mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Rearrange pseudotypes.c to get rid of duplicative code.
Commit a5954de10 replaced a lot of manually-coded stub I/O routines
with code generated by macros.  That was a good idea but it didn't
go far enough, because there were still manually-coded stub input
routines for types that had live output routines.  Refactor the
macro so that we can generate just a stub input routine at need.
Also create similar macros to generate stub binary I/O routines,
since we have some of those now.  The only stub functions that remain
hand-coded are shell_in() and shell_out(), which need to be separate
because they use different error messages.
While here, rearrange the commentary to discuss each type not each
function.  This provides a better way to explain the *why* of which
types need which support, rather than just duplicatively annotating
the functions.
Discussion: https://postgr.es/m/24137.1584139352@sss.pgh.pa.us
			
			
This commit is contained in:
		@@ -29,362 +29,11 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * cstring_in		- input routine for pseudo-type CSTRING.
 | 
			
		||||
 *
 | 
			
		||||
 * We might as well allow this to support constructs like "foo_in('blah')".
 | 
			
		||||
 * These macros generate input and output functions for a pseudo-type that
 | 
			
		||||
 * will reject all input and output attempts.  (But for some types, only
 | 
			
		||||
 * the input function need be dummy.)
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
cstring_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	char	   *str = PG_GETARG_CSTRING(0);
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_CSTRING(pstrdup(str));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * cstring_out		- output routine for pseudo-type CSTRING.
 | 
			
		||||
 *
 | 
			
		||||
 * We allow this mainly so that "SELECT some_output_function(...)" does
 | 
			
		||||
 * what the user will expect.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
cstring_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	char	   *str = PG_GETARG_CSTRING(0);
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_CSTRING(pstrdup(str));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * cstring_recv		- binary input routine for pseudo-type CSTRING.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
cstring_recv(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 | 
			
		||||
	char	   *str;
 | 
			
		||||
	int			nbytes;
 | 
			
		||||
 | 
			
		||||
	str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
 | 
			
		||||
	PG_RETURN_CSTRING(str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * cstring_send		- binary output routine for pseudo-type CSTRING.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
cstring_send(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	char	   *str = PG_GETARG_CSTRING(0);
 | 
			
		||||
	StringInfoData buf;
 | 
			
		||||
 | 
			
		||||
	pq_begintypsend(&buf);
 | 
			
		||||
	pq_sendtext(&buf, str, strlen(str));
 | 
			
		||||
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyarray_in		- input routine for pseudo-type ANYARRAY.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
anyarray_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of type %s", "anyarray")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyarray_out		- output routine for pseudo-type ANYARRAY.
 | 
			
		||||
 *
 | 
			
		||||
 * We may as well allow this, since array_out will in fact work.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
anyarray_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return array_out(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyarray_recv		- binary input routine for pseudo-type ANYARRAY.
 | 
			
		||||
 *
 | 
			
		||||
 * XXX this could actually be made to work, since the incoming array
 | 
			
		||||
 * data will contain the element type OID.  Need to think through
 | 
			
		||||
 * type-safety issues before allowing it, however.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
anyarray_recv(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of type %s", "anyarray")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyarray_send		- binary output routine for pseudo-type ANYARRAY.
 | 
			
		||||
 *
 | 
			
		||||
 * We may as well allow this, since array_send will in fact work.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
anyarray_send(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return array_send(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyenum_in		- input routine for pseudo-type ANYENUM.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
anyenum_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of type %s", "anyenum")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyenum_out		- output routine for pseudo-type ANYENUM.
 | 
			
		||||
 *
 | 
			
		||||
 * We may as well allow this, since enum_out will in fact work.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
anyenum_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return enum_out(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyrange_in		- input routine for pseudo-type ANYRANGE.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
anyrange_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of type %s", "anyrange")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyrange_out		- output routine for pseudo-type ANYRANGE.
 | 
			
		||||
 *
 | 
			
		||||
 * We may as well allow this, since range_out will in fact work.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
anyrange_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return range_out(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * void_in		- input routine for pseudo-type VOID.
 | 
			
		||||
 *
 | 
			
		||||
 * We allow this so that PL functions can return VOID without any special
 | 
			
		||||
 * hack in the PL handler.  Whatever value the PL thinks it's returning
 | 
			
		||||
 * will just be ignored.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
void_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	PG_RETURN_VOID();			/* you were expecting something different? */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * void_out		- output routine for pseudo-type VOID.
 | 
			
		||||
 *
 | 
			
		||||
 * We allow this so that "SELECT function_returning_void(...)" works.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
void_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	PG_RETURN_CSTRING(pstrdup(""));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * void_recv	- binary input routine for pseudo-type VOID.
 | 
			
		||||
 *
 | 
			
		||||
 * Note that since we consume no bytes, an attempt to send anything but
 | 
			
		||||
 * an empty string will result in an "invalid message format" error.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
void_recv(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	PG_RETURN_VOID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * void_send	- binary output routine for pseudo-type VOID.
 | 
			
		||||
 *
 | 
			
		||||
 * We allow this so that "SELECT function_returning_void(...)" works
 | 
			
		||||
 * even when binary output is requested.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
void_send(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	StringInfoData buf;
 | 
			
		||||
 | 
			
		||||
	/* send an empty string */
 | 
			
		||||
	pq_begintypsend(&buf);
 | 
			
		||||
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * shell_in		- input routine for "shell" types (those not yet filled in).
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
shell_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of a shell type")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * shell_out		- output routine for "shell" types.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
shell_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot display a value of a shell type")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_node_tree_in		- input routine for type PG_NODE_TREE.
 | 
			
		||||
 *
 | 
			
		||||
 * pg_node_tree isn't really a pseudotype --- it's real enough to be a table
 | 
			
		||||
 * column --- but it presently has no operations of its own, and disallows
 | 
			
		||||
 * input too, so its I/O functions seem to fit here as much as anywhere.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
pg_node_tree_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * We disallow input of pg_node_tree values because the SQL functions that
 | 
			
		||||
	 * operate on the type are not secure against malformed input.
 | 
			
		||||
	 */
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of type %s", "pg_node_tree")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_node_tree_out		- output routine for type PG_NODE_TREE.
 | 
			
		||||
 *
 | 
			
		||||
 * The internal representation is the same as TEXT, so just pass it off.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
pg_node_tree_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return textout(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_node_tree_recv		- binary input routine for type PG_NODE_TREE.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
pg_node_tree_recv(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of type %s", "pg_node_tree")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_node_tree_send		- binary output routine for type PG_NODE_TREE.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
pg_node_tree_send(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return textsend(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_ddl_command_in	- input routine for type PG_DDL_COMMAND.
 | 
			
		||||
 *
 | 
			
		||||
 * Like pg_node_tree, pg_ddl_command isn't really a pseudotype; it's here for
 | 
			
		||||
 * the same reasons as that one.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
pg_ddl_command_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * Disallow input of pg_ddl_command value.
 | 
			
		||||
	 */
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of type %s", "pg_ddl_command")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_ddl_command_out		- output routine for type PG_DDL_COMMAND.
 | 
			
		||||
 *
 | 
			
		||||
 * We don't have any good way to output this type directly, so punt.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
pg_ddl_command_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot output a value of type %s", "pg_ddl_command")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_ddl_command_recv		- binary input routine for type PG_DDL_COMMAND.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
pg_ddl_command_recv(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of type %s", "pg_ddl_command")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_ddl_command_send		- binary output routine for type PG_DDL_COMMAND.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
pg_ddl_command_send(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot output a value of type %s", "pg_ddl_command")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Generate input and output functions for a pseudotype that will reject all
 | 
			
		||||
 * input and output attempts.
 | 
			
		||||
 */
 | 
			
		||||
#define PSEUDOTYPE_DUMMY_IO_FUNCS(typname) \
 | 
			
		||||
\
 | 
			
		||||
#define PSEUDOTYPE_DUMMY_INPUT_FUNC(typname) \
 | 
			
		||||
Datum \
 | 
			
		||||
typname##_in(PG_FUNCTION_ARGS) \
 | 
			
		||||
{ \
 | 
			
		||||
@@ -395,6 +44,11 @@ typname##_in(PG_FUNCTION_ARGS) \
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */ \
 | 
			
		||||
} \
 | 
			
		||||
\
 | 
			
		||||
extern int no_such_variable
 | 
			
		||||
 | 
			
		||||
#define PSEUDOTYPE_DUMMY_IO_FUNCS(typname) \
 | 
			
		||||
PSEUDOTYPE_DUMMY_INPUT_FUNC(typname); \
 | 
			
		||||
\
 | 
			
		||||
Datum \
 | 
			
		||||
typname##_out(PG_FUNCTION_ARGS) \
 | 
			
		||||
{ \
 | 
			
		||||
@@ -407,14 +61,258 @@ typname##_out(PG_FUNCTION_ARGS) \
 | 
			
		||||
\
 | 
			
		||||
extern int no_such_variable
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Likewise for binary send/receive functions.  We don't bother with these
 | 
			
		||||
 * at all for many pseudotypes, but some have them.  (By convention, if
 | 
			
		||||
 * a type has a send function it should have a receive function, even if
 | 
			
		||||
 * that's only dummy.)
 | 
			
		||||
 */
 | 
			
		||||
#define PSEUDOTYPE_DUMMY_RECEIVE_FUNC(typname) \
 | 
			
		||||
Datum \
 | 
			
		||||
typname##_recv(PG_FUNCTION_ARGS) \
 | 
			
		||||
{ \
 | 
			
		||||
	ereport(ERROR, \
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
 | 
			
		||||
			 errmsg("cannot accept a value of type %s", #typname))); \
 | 
			
		||||
\
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */ \
 | 
			
		||||
} \
 | 
			
		||||
\
 | 
			
		||||
extern int no_such_variable
 | 
			
		||||
 | 
			
		||||
#define PSEUDOTYPE_DUMMY_BINARY_IO_FUNCS(typname) \
 | 
			
		||||
PSEUDOTYPE_DUMMY_RECEIVE_FUNC(typname); \
 | 
			
		||||
\
 | 
			
		||||
Datum \
 | 
			
		||||
typname##_send(PG_FUNCTION_ARGS) \
 | 
			
		||||
{ \
 | 
			
		||||
	ereport(ERROR, \
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
 | 
			
		||||
			 errmsg("cannot display a value of type %s", #typname))); \
 | 
			
		||||
\
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */ \
 | 
			
		||||
} \
 | 
			
		||||
\
 | 
			
		||||
extern int no_such_variable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * cstring
 | 
			
		||||
 *
 | 
			
		||||
 * cstring is marked as a pseudo-type because we don't want people using it
 | 
			
		||||
 * in tables.  But it's really a perfectly functional type, so provide
 | 
			
		||||
 * a full set of working I/O functions for it.  Among other things, this
 | 
			
		||||
 * allows manual invocation of datatype I/O functions, along the lines of
 | 
			
		||||
 * "SELECT foo_in('blah')" or "SELECT foo_out(some-foo-value)".
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
cstring_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	char	   *str = PG_GETARG_CSTRING(0);
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_CSTRING(pstrdup(str));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
cstring_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	char	   *str = PG_GETARG_CSTRING(0);
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_CSTRING(pstrdup(str));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
cstring_recv(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 | 
			
		||||
	char	   *str;
 | 
			
		||||
	int			nbytes;
 | 
			
		||||
 | 
			
		||||
	str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
 | 
			
		||||
	PG_RETURN_CSTRING(str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
cstring_send(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	char	   *str = PG_GETARG_CSTRING(0);
 | 
			
		||||
	StringInfoData buf;
 | 
			
		||||
 | 
			
		||||
	pq_begintypsend(&buf);
 | 
			
		||||
	pq_sendtext(&buf, str, strlen(str));
 | 
			
		||||
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyarray
 | 
			
		||||
 *
 | 
			
		||||
 * We need to allow output of anyarray so that, e.g., pg_statistic columns
 | 
			
		||||
 * can be printed.  Input has to be disallowed, however.
 | 
			
		||||
 *
 | 
			
		||||
 * XXX anyarray_recv could actually be made to work, since the incoming
 | 
			
		||||
 * array data would contain the element type OID.  It seems unlikely that
 | 
			
		||||
 * it'd be sufficiently type-safe, though.
 | 
			
		||||
 */
 | 
			
		||||
PSEUDOTYPE_DUMMY_INPUT_FUNC(anyarray);
 | 
			
		||||
PSEUDOTYPE_DUMMY_RECEIVE_FUNC(anyarray);
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
anyarray_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return array_out(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
anyarray_send(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return array_send(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyenum
 | 
			
		||||
 *
 | 
			
		||||
 * We may as well allow output, since enum_out will in fact work.
 | 
			
		||||
 */
 | 
			
		||||
PSEUDOTYPE_DUMMY_INPUT_FUNC(anyenum);
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
anyenum_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return enum_out(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * anyrange
 | 
			
		||||
 *
 | 
			
		||||
 * We may as well allow output, since range_out will in fact work.
 | 
			
		||||
 */
 | 
			
		||||
PSEUDOTYPE_DUMMY_INPUT_FUNC(anyrange);
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
anyrange_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return range_out(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * void
 | 
			
		||||
 *
 | 
			
		||||
 * We support void_in so that PL functions can return VOID without any
 | 
			
		||||
 * special hack in the PL handler.  Whatever value the PL thinks it's
 | 
			
		||||
 * returning will just be ignored.  Conversely, void_out and void_send
 | 
			
		||||
 * are needed so that "SELECT function_returning_void(...)" works.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
void_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	PG_RETURN_VOID();			/* you were expecting something different? */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
void_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	PG_RETURN_CSTRING(pstrdup(""));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
void_recv(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * Note that since we consume no bytes, an attempt to send anything but an
 | 
			
		||||
	 * empty string will result in an "invalid message format" error.
 | 
			
		||||
	 */
 | 
			
		||||
	PG_RETURN_VOID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
void_send(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	StringInfoData buf;
 | 
			
		||||
 | 
			
		||||
	/* send an empty string */
 | 
			
		||||
	pq_begintypsend(&buf);
 | 
			
		||||
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * shell
 | 
			
		||||
 *
 | 
			
		||||
 * shell_in and shell_out are entered in pg_type for "shell" types
 | 
			
		||||
 * (those not yet filled in).  They should be unreachable, but we
 | 
			
		||||
 * set them up just in case some code path tries to do I/O without
 | 
			
		||||
 * having checked pg_type.typisdefined anywhere along the way.
 | 
			
		||||
 */
 | 
			
		||||
Datum
 | 
			
		||||
shell_in(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot accept a value of a shell type")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
shell_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	ereport(ERROR,
 | 
			
		||||
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 | 
			
		||||
			 errmsg("cannot display a value of a shell type")));
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();			/* keep compiler quiet */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_node_tree
 | 
			
		||||
 *
 | 
			
		||||
 * pg_node_tree isn't really a pseudotype --- it's real enough to be a table
 | 
			
		||||
 * column --- but it presently has no operations of its own, and disallows
 | 
			
		||||
 * input too, so its I/O functions seem to fit here as much as anywhere.
 | 
			
		||||
 *
 | 
			
		||||
 * We must disallow input of pg_node_tree values because the SQL functions
 | 
			
		||||
 * that operate on the type are not secure against malformed input.
 | 
			
		||||
 * We do want to allow output, though.
 | 
			
		||||
 */
 | 
			
		||||
PSEUDOTYPE_DUMMY_INPUT_FUNC(pg_node_tree);
 | 
			
		||||
PSEUDOTYPE_DUMMY_RECEIVE_FUNC(pg_node_tree);
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
pg_node_tree_out(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return textout(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Datum
 | 
			
		||||
pg_node_tree_send(PG_FUNCTION_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	return textsend(fcinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_ddl_command
 | 
			
		||||
 *
 | 
			
		||||
 * Like pg_node_tree, pg_ddl_command isn't really a pseudotype; it's here
 | 
			
		||||
 * for the same reasons as that one.
 | 
			
		||||
 *
 | 
			
		||||
 * We don't have any good way to output this type directly, so punt
 | 
			
		||||
 * for output as well as input.
 | 
			
		||||
 */
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(pg_ddl_command);
 | 
			
		||||
PSEUDOTYPE_DUMMY_BINARY_IO_FUNCS(pg_ddl_command);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Dummy I/O functions for various other pseudotypes.
 | 
			
		||||
 */
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(any);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(trigger);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(event_trigger);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(language_handler);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(fdw_handler);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(table_am_handler);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(index_am_handler);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(internal);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray);
 | 
			
		||||
PSEUDOTYPE_DUMMY_IO_FUNCS(table_am_handler);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user