Rearrange pseudotypes.c to get rid of duplicative code.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 14 Mar 2020 19:31:44 +0000 (15:31 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 14 Mar 2020 19:31:44 +0000 (15:31 -0400)
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

src/backend/utils/adt/pseudotypes.c

index 4653fc33e6d848fe995e6fd5dedfefbcf28f251b..9eee03c143a156aacc6e5390e0b35b8979e3d505 100644 (file)
 
 
 /*
- * cstring_in      - input routine for pseudo-type CSTRING.
+ * 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.)
+ */
+#define PSEUDOTYPE_DUMMY_INPUT_FUNC(typname) \
+Datum \
+typname##_in(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_IO_FUNCS(typname) \
+PSEUDOTYPE_DUMMY_INPUT_FUNC(typname); \
+\
+Datum \
+typname##_out(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
+
+/*
+ * 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
  *
- * We might as well allow this to support constructs like "foo_in('blah')".
+ * 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)
@@ -41,12 +113,6 @@ cstring_in(PG_FUNCTION_ARGS)
    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)
 {
@@ -55,9 +121,6 @@ cstring_out(PG_FUNCTION_ARGS)
    PG_RETURN_CSTRING(pstrdup(str));
 }
 
-/*
- * cstring_recv        - binary input routine for pseudo-type CSTRING.
- */
 Datum
 cstring_recv(PG_FUNCTION_ARGS)
 {
@@ -69,9 +132,6 @@ cstring_recv(PG_FUNCTION_ARGS)
    PG_RETURN_CSTRING(str);
 }
 
-/*
- * cstring_send        - binary output routine for pseudo-type CSTRING.
- */
 Datum
 cstring_send(PG_FUNCTION_ARGS)
 {
@@ -84,76 +144,37 @@ cstring_send(PG_FUNCTION_ARGS)
 }
 
 /*
- * 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.
+ * anyarray
+ *
+ * We need to allow output of anyarray so that, e.g., pg_statistic columns
+ * can be printed.  Input has to be disallowed, however.
  *
- * We may as well allow this, since array_out will in fact work.
+ * 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);
 }
 
-/*
- * 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.
+ * anyenum
  *
- * We may as well allow this, since enum_out will in fact work.
+ * We may as well allow output, since enum_out will in fact work.
  */
+PSEUDOTYPE_DUMMY_INPUT_FUNC(anyenum);
+
 Datum
 anyenum_out(PG_FUNCTION_ARGS)
 {
@@ -161,23 +182,12 @@ anyenum_out(PG_FUNCTION_ARGS)
 }
 
 /*
- * 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.
+ * anyrange
  *
- * We may as well allow this, since range_out will in fact work.
+ * We may as well allow output, since range_out will in fact work.
  */
+PSEUDOTYPE_DUMMY_INPUT_FUNC(anyrange);
+
 Datum
 anyrange_out(PG_FUNCTION_ARGS)
 {
@@ -185,11 +195,12 @@ anyrange_out(PG_FUNCTION_ARGS)
 }
 
 /*
- * void_in     - input routine for pseudo-type VOID.
+ * 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.
+ * 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)
@@ -197,35 +208,22 @@ 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)
 {
+   /*
+    * 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();
 }
 
-/*
- * 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)
 {
@@ -237,7 +235,12 @@ void_send(PG_FUNCTION_ARGS)
 }
 
 /*
- * shell_in        - input routine for "shell" types (those not yet filled in).
+ * 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)
@@ -249,9 +252,6 @@ shell_in(PG_FUNCTION_ARGS)
    PG_RETURN_VOID();           /* keep compiler quiet */
 }
 
-/*
- * shell_out       - output routine for "shell" types.
- */
 Datum
 shell_out(PG_FUNCTION_ARGS)
 {
@@ -264,54 +264,25 @@ shell_out(PG_FUNCTION_ARGS)
 
 
 /*
- * pg_node_tree_in     - input routine for type PG_NODE_TREE.
+ * 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.
+ * 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);
 }
 
-/*
- * 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)
 {
@@ -319,102 +290,29 @@ pg_node_tree_send(PG_FUNCTION_ARGS)
 }
 
 /*
- * pg_ddl_command_in   - input routine for type PG_DDL_COMMAND.
+ * 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.
+ * 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.
+ * We don't have any good way to output this type directly, so punt
+ * for output as well as input.
  */
-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();
-}
+PSEUDOTYPE_DUMMY_IO_FUNCS(pg_ddl_command);
+PSEUDOTYPE_DUMMY_BINARY_IO_FUNCS(pg_ddl_command);
 
 
 /*
- * Generate input and output functions for a pseudotype that will reject all
- * input and output attempts.
+ * Dummy I/O functions for various other pseudotypes.
  */
-#define PSEUDOTYPE_DUMMY_IO_FUNCS(typname) \
-\
-Datum \
-typname##_in(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 */ \
-} \
-\
-Datum \
-typname##_out(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
-
 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);