From 303696c3b47e6719e983e93da5896ddc4a2e0dbb Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 3 Sep 2010 01:34:55 +0000 Subject: [PATCH] Install a data-type-based solution for protecting pg_get_expr(). Since the code underlying pg_get_expr() is not secure against malformed input, and can't practically be made so, we need to prevent miscreants from feeding arbitrary data to it. We can do this securely by declaring pg_get_expr() to take a new datatype "pg_node_tree" and declaring the system catalog columns that hold nodeToString output to be of that type. There is no way at SQL level to create a non-null value of type pg_node_tree. Since the backend-internal operations that fill those catalog columns operate below the SQL level, they are oblivious to the datatype relabeling and don't need any changes. --- doc/src/sgml/catalogs.sgml | 25 +++++----- doc/src/sgml/func.sgml | 6 +-- src/backend/bootstrap/bootstrap.c | 7 ++- src/backend/utils/adt/pseudotypes.c | 57 ++++++++++++++++++++++- src/include/catalog/catversion.h | 4 +- src/include/catalog/genbki.h | 5 +- src/include/catalog/pg_attrdef.h | 10 ++-- src/include/catalog/pg_cast.h | 5 +- src/include/catalog/pg_constraint.h | 4 +- src/include/catalog/pg_index.h | 6 +-- src/include/catalog/pg_proc.h | 19 ++++++-- src/include/catalog/pg_rewrite.h | 6 +-- src/include/catalog/pg_trigger.h | 4 +- src/include/catalog/pg_type.h | 8 +++- src/include/utils/builtins.h | 6 ++- src/test/regress/expected/opr_sanity.out | 23 +++++---- src/test/regress/expected/type_sanity.out | 9 ++-- src/test/regress/sql/opr_sanity.sql | 5 +- src/test/regress/sql/type_sanity.sql | 2 +- 19 files changed, 149 insertions(+), 62 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index d287e84866..d53477ca47 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,4 +1,4 @@ - + @@ -797,7 +797,7 @@ adbin - text + pg_node_tree The internal representation of the column default value @@ -1917,7 +1917,7 @@ conbin - text + pg_node_tree If a check constraint, an internal representation of the expression @@ -2915,7 +2915,7 @@ indexprs - text + pg_node_tree Expression trees (in nodeToString() @@ -2928,7 +2928,7 @@ indpred - text + pg_node_tree Expression tree (in nodeToString() @@ -3980,7 +3980,7 @@ proargdefaults - text + pg_node_tree Expression trees (in nodeToString() representation) @@ -4129,7 +4129,7 @@ ev_qual - text + pg_node_tree Expression tree (in the form of a @@ -4140,7 +4140,7 @@ ev_action - text + pg_node_tree Query tree (in the form of a @@ -4839,7 +4839,7 @@ tgqual - text + pg_node_tree Expression tree (in nodeToString() representation) for the trigger's WHEN condition, or null @@ -5622,10 +5622,11 @@ typdefaultbin - text + pg_node_tree - If typdefaultbin is not null, it is the nodeToString() + If typdefaultbin is not null, it is the + nodeToString() representation of a default expression for the type. This is only used for domains. @@ -5642,7 +5643,7 @@ default expression represented by typdefaultbin. If typdefaultbin is null and typdefault is not, then typdefault is the external representation of - the type's default value, which might be fed to the type's input + the type's default value, which can be fed to the type's input converter to produce a constant. diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 01fbd315b9..8d1015b9f8 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,4 +1,4 @@ - + Functions and Operators @@ -12746,13 +12746,13 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); get definition of a constraint - pg_get_expr(expr_text, relation_oid) + pg_get_expr(pg_node_tree, relation_oid) text decompile internal form of an expression, assuming that any Vars in it refer to the relation indicated by the second parameter - pg_get_expr(expr_text, relation_oid, pretty_bool) + pg_get_expr(pg_node_tree, relation_oid, pretty_bool) text decompile internal form of an expression, assuming that any Vars in it refer to the relation indicated by the second parameter diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 080d80e296..c4744966ca 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.261 2010/04/20 01:38:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.262 2010/09/03 01:34:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -72,7 +72,8 @@ int numattr; /* number of attributes for cur. rel */ /* * Basic information associated with each type. This is used before - * pg_type is created. + * pg_type is filled, so it has to cover the datatypes used as column types + * in the core "bootstrapped" catalogs. * * XXX several of these input/output functions do catalog scans * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some @@ -122,6 +123,8 @@ static const struct typinfo TypInfo[] = { F_XIDIN, F_XIDOUT}, {"cid", CIDOID, 0, 4, true, 'i', 'p', F_CIDIN, F_CIDOUT}, + {"pg_node_tree", PGNODETREEOID, 0, -1, false, 'i', 'x', + F_PG_NODE_TREE_IN, F_PG_NODE_TREE_OUT}, {"int2vector", INT2VECTOROID, INT2OID, -1, false, 'i', 'p', F_INT2VECTORIN, F_INT2VECTOROUT}, {"oidvector", OIDVECTOROID, OIDOID, -1, false, 'i', 'p', diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index 6a56129e97..8986e06904 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -16,7 +16,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.23 2010/01/02 16:57:55 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.24 2010/09/03 01:34:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -398,3 +398,58 @@ shell_out(PG_FUNCTION_ARGS) 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 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 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); +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index f5a96c81f5..fef5e686a0 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.597 2010/08/24 06:30:43 itagaki Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.598 2010/09/03 01:34:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201008241 +#define CATALOG_VERSION_NO 201009021 #endif diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h index 0fe9b74e71..9d92ca7b31 100644 --- a/src/include/catalog/genbki.h +++ b/src/include/catalog/genbki.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/genbki.h,v 1.6 2010/01/05 01:06:56 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/genbki.h,v 1.7 2010/09/03 01:34:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,7 +35,8 @@ #define DESCR(x) extern int no_such_variable #define SHDESCR(x) extern int no_such_variable -/* PHONY type definition for use in catalog structure definitions only */ +/* PHONY type definitions for use in catalog structure definitions only */ typedef int aclitem; +typedef int pg_node_tree; #endif /* GENBKI_H */ diff --git a/src/include/catalog/pg_attrdef.h b/src/include/catalog/pg_attrdef.h index 81da20a502..1b3153a7e7 100644 --- a/src/include/catalog/pg_attrdef.h +++ b/src/include/catalog/pg_attrdef.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_attrdef.h,v 1.26 2010/01/05 01:06:56 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_attrdef.h,v 1.27 2010/09/03 01:34:55 tgl Exp $ * * NOTES * the genbki.pl script reads this file and generates .bki @@ -30,10 +30,10 @@ CATALOG(pg_attrdef,2604) { - Oid adrelid; - int2 adnum; - text adbin; - text adsrc; + Oid adrelid; /* OID of table containing attribute */ + int2 adnum; /* attnum of attribute */ + pg_node_tree adbin; /* nodeToString representation of default */ + text adsrc; /* human-readable representation of default */ } FormData_pg_attrdef; /* ---------------- diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index ca8b0b921b..db2333d4d9 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -10,7 +10,7 @@ * * Copyright (c) 2002-2010, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.45 2010/07/16 02:15:54 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.46 2010/09/03 01:34:55 tgl Exp $ * * NOTES * the genbki.pl script reads this file and generates .bki @@ -235,6 +235,9 @@ DATA(insert ( 1043 19 1400 i f )); DATA(insert ( 18 23 77 e f )); DATA(insert ( 23 18 78 e f )); +/* pg_node_tree can be coerced to, but not from, text */ +DATA(insert ( 194 25 0 i b )); + /* * Datetime category */ diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index 63fddc697b..bbfd576733 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.41 2010/08/07 02:44:07 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.42 2010/09/03 01:34:55 tgl Exp $ * * NOTES * the genbki.pl script reads this file and generates .bki @@ -129,7 +129,7 @@ CATALOG(pg_constraint,2606) /* * If a check constraint, nodeToString representation of expression */ - text conbin; + pg_node_tree conbin; /* * If a check constraint, source-text representation of expression diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h index 685fae3c0e..c6a1a22c02 100644 --- a/src/include/catalog/pg_index.h +++ b/src/include/catalog/pg_index.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_index.h,v 1.50 2010/01/05 01:06:56 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_index.h,v 1.51 2010/09/03 01:34:55 tgl Exp $ * * NOTES * the genbki.pl script reads this file and generates .bki @@ -45,10 +45,10 @@ CATALOG(pg_index,2610) BKI_WITHOUT_OIDS BKI_SCHEMA_MACRO int2vector indkey; /* column numbers of indexed cols, or 0 */ oidvector indclass; /* opclass identifiers */ int2vector indoption; /* per-column flags (AM-specific meanings) */ - text indexprs; /* expression trees for index attributes that + pg_node_tree indexprs; /* expression trees for index attributes that * are not simple column references; one for * each zero entry in indkey[] */ - text indpred; /* expression tree for predicate, if a partial + pg_node_tree indpred; /* expression tree for predicate, if a partial * index; else NULL */ } FormData_pg_index; diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index b3f1e14fd3..33f5c218e3 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.581 2010/08/24 06:30:43 itagaki Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.582 2010/09/03 01:34:55 tgl Exp $ * * NOTES * The script catalog/genbki.pl reads this file and generates .bki @@ -57,8 +57,8 @@ CATALOG(pg_proc,1255) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81) BKI_SCHEMA_MACRO Oid proallargtypes[1]; /* all param types (NULL if IN only) */ char proargmodes[1]; /* parameter modes (NULL if IN only) */ text proargnames[1]; /* parameter names (NULL if no names) */ - text proargdefaults; /* list of expression trees for argument - * defaults (NULL if none) */ + pg_node_tree proargdefaults; /* list of expression trees for argument + * defaults (NULL if none) */ text prosrc; /* procedure source text */ text probin; /* secondary procedure info (can be NULL) */ text proconfig[1]; /* procedure-local GUC settings */ @@ -399,6 +399,15 @@ DESCR("is contained by?"); DATA(insert OID = 193 ( box_contain_pt PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "603 600" _null_ _null_ _null_ _null_ box_contain_pt _null_ _null_ _null_ )); DESCR("contains?"); +DATA(insert OID = 195 ( pg_node_tree_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 194 "2275" _null_ _null_ _null_ _null_ pg_node_tree_in _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 196 ( pg_node_tree_out PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2275 "194" _null_ _null_ _null_ _null_ pg_node_tree_out _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 197 ( pg_node_tree_recv PGNSP PGUID 12 1 0 0 f f f t f s 1 0 194 "2281" _null_ _null_ _null_ _null_ pg_node_tree_recv _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 198 ( pg_node_tree_send PGNSP PGUID 12 1 0 0 f f f t f s 1 0 17 "194" _null_ _null_ _null_ _null_ pg_node_tree_send _null_ _null_ _null_ )); +DESCR("I/O"); + /* OIDS 200 - 299 */ DATA(insert OID = 200 ( float4in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 700 "2275" _null_ _null_ _null_ _null_ float4in _null_ _null_ _null_ )); @@ -2317,7 +2326,7 @@ DATA(insert OID = 1662 ( pg_get_triggerdef PGNSP PGUID 12 1 0 0 f f f t f s DESCR("trigger description"); DATA(insert OID = 1387 ( pg_get_constraintdef PGNSP PGUID 12 1 0 0 f f f t f s 1 0 25 "26" _null_ _null_ _null_ _null_ pg_get_constraintdef _null_ _null_ _null_ )); DESCR("constraint description"); -DATA(insert OID = 1716 ( pg_get_expr PGNSP PGUID 12 1 0 0 f f f t f s 2 0 25 "25 26" _null_ _null_ _null_ _null_ pg_get_expr _null_ _null_ _null_ )); +DATA(insert OID = 1716 ( pg_get_expr PGNSP PGUID 12 1 0 0 f f f t f s 2 0 25 "194 26" _null_ _null_ _null_ _null_ pg_get_expr _null_ _null_ _null_ )); DESCR("deparse an encoded expression"); DATA(insert OID = 1665 ( pg_get_serial_sequence PGNSP PGUID 12 1 0 0 f f f t f s 2 0 25 "25 25" _null_ _null_ _null_ _null_ pg_get_serial_sequence _null_ _null_ _null_ )); DESCR("name of sequence for a serial column"); @@ -4170,7 +4179,7 @@ DATA(insert OID = 2507 ( pg_get_indexdef PGNSP PGUID 12 1 0 0 f f f t f s 3 DESCR("index description (full create statement or single expression) with pretty-print option"); DATA(insert OID = 2508 ( pg_get_constraintdef PGNSP PGUID 12 1 0 0 f f f t f s 2 0 25 "26 16" _null_ _null_ _null_ _null_ pg_get_constraintdef_ext _null_ _null_ _null_ )); DESCR("constraint description with pretty-print option"); -DATA(insert OID = 2509 ( pg_get_expr PGNSP PGUID 12 1 0 0 f f f t f s 3 0 25 "25 26 16" _null_ _null_ _null_ _null_ pg_get_expr_ext _null_ _null_ _null_ )); +DATA(insert OID = 2509 ( pg_get_expr PGNSP PGUID 12 1 0 0 f f f t f s 3 0 25 "194 26 16" _null_ _null_ _null_ _null_ pg_get_expr_ext _null_ _null_ _null_ )); DESCR("deparse an encoded expression with pretty-print option"); DATA(insert OID = 2510 ( pg_prepared_statement PGNSP PGUID 12 1 1000 0 f f f t t s 0 0 2249 "" "{25,25,1184,2211,16}" "{o,o,o,o,o}" "{name,statement,prepare_time,parameter_types,from_sql}" _null_ pg_prepared_statement _null_ _null_ _null_ )); DESCR("get the prepared statements for this session"); diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h index 20d4e00c43..acb3e83b05 100644 --- a/src/include/catalog/pg_rewrite.h +++ b/src/include/catalog/pg_rewrite.h @@ -11,7 +11,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_rewrite.h,v 1.35 2010/01/05 01:06:57 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_rewrite.h,v 1.36 2010/09/03 01:34:55 tgl Exp $ * * NOTES * the genbki.pl script reads this file and generates .bki @@ -41,8 +41,8 @@ CATALOG(pg_rewrite,2618) bool is_instead; /* NB: remaining fields must be accessed via heap_getattr */ - text ev_qual; - text ev_action; + pg_node_tree ev_qual; + pg_node_tree ev_action; } FormData_pg_rewrite; /* ---------------- diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h index 7c95475043..9a548dca86 100644 --- a/src/include/catalog/pg_trigger.h +++ b/src/include/catalog/pg_trigger.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_trigger.h,v 1.39 2010/01/17 22:56:23 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_trigger.h,v 1.40 2010/09/03 01:34:55 tgl Exp $ * * NOTES * the genbki.pl script reads this file and generates .bki @@ -53,7 +53,7 @@ CATALOG(pg_trigger,2620) /* VARIABLE LENGTH FIELDS (note: tgattr and tgargs must not be null) */ int2vector tgattr; /* column numbers, if trigger is on columns */ bytea tgargs; /* first\000second\000tgnargs\000 */ - text tgqual; /* WHEN expression, or NULL if none */ + pg_node_tree tgqual; /* WHEN expression, or NULL if none */ } FormData_pg_trigger; /* ---------------- diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 3a10da25c3..5d997dc731 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.212 2010/01/05 01:06:57 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.213 2010/09/03 01:34:55 tgl Exp $ * * NOTES * the genbki.pl script reads this file and generates .bki @@ -199,7 +199,7 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO * a default expression for the type. Currently this is only used for * domains. */ - text typdefaultbin; /* VARIABLE LENGTH FIELD */ + pg_node_tree typdefaultbin; /* VARIABLE LENGTH FIELD */ /* * typdefault is NULL if the type has no associated default value. If @@ -343,6 +343,10 @@ DESCR("XML content"); #define XMLOID 142 DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b A f t \054 0 142 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 194 ( pg_node_tree PGNSP PGUID -1 f b S f t \054 0 0 0 pg_node_tree_in pg_node_tree_out pg_node_tree_recv pg_node_tree_send - - - i x f 0 -1 0 _null_ _null_ )); +DESCR("string representing an internal node tree"); +#define PGNODETREEOID 194 + /* OIDS 200 - 299 */ DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f 0 -1 0 _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 4612cb3543..c7e50d2512 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.355 2010/08/24 06:30:44 itagaki Exp $ + * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.356 2010/09/03 01:34:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -510,6 +510,10 @@ extern Datum anyelement_in(PG_FUNCTION_ARGS); extern Datum anyelement_out(PG_FUNCTION_ARGS); extern Datum shell_in(PG_FUNCTION_ARGS); extern Datum shell_out(PG_FUNCTION_ARGS); +extern Datum pg_node_tree_in(PG_FUNCTION_ARGS); +extern Datum pg_node_tree_out(PG_FUNCTION_ARGS); +extern Datum pg_node_tree_recv(PG_FUNCTION_ARGS); +extern Datum pg_node_tree_send(PG_FUNCTION_ARGS); /* regexp.c */ extern Datum nameregexeq(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index f6fee25de5..4703d497c1 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -400,22 +400,25 @@ WHERE c.castfunc = p.oid AND -- As of 8.3, this finds the casts from xml to text, varchar, and bpchar, -- because those are binary-compatible while the reverse goes through -- texttoxml(), which does an XML syntax check. -SELECT * +-- As of 9.1, this finds the cast from pg_node_tree to text, which we +-- intentionally do not provide a reverse pathway for. +SELECT castsource::regtype, casttarget::regtype, castfunc, castcontext FROM pg_cast c WHERE c.castmethod = 'b' AND NOT EXISTS (SELECT 1 FROM pg_cast k WHERE k.castmethod = 'b' AND k.castsource = c.casttarget AND k.casttarget = c.castsource); - castsource | casttarget | castfunc | castcontext | castmethod -------------+------------+----------+-------------+------------ - 25 | 1042 | 0 | i | b - 1043 | 1042 | 0 | i | b - 650 | 869 | 0 | i | b - 142 | 25 | 0 | a | b - 142 | 1043 | 0 | a | b - 142 | 1042 | 0 | a | b -(6 rows) + castsource | casttarget | castfunc | castcontext +-------------------+-------------------+----------+------------- + text | character | 0 | i + character varying | character | 0 | i + pg_node_tree | text | 0 | i + cidr | inet | 0 | i + xml | text | 0 | a + xml | character varying | 0 | a + xml | character | 0 | a +(7 rows) -- **************** pg_operator **************** -- Look for illegal values in pg_operator fields. diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index be86ee313b..b7433653d1 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -57,18 +57,19 @@ WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR (0 rows) -- Look for basic or enum types that don't have an array type. --- NOTE: as of 8.0, this check finds smgr and unknown. +-- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown. SELECT p1.oid, p1.typname FROM pg_type as p1 WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS (SELECT 1 FROM pg_type as p2 WHERE p2.typname = ('_' || p1.typname)::name AND p2.typelem = p1.oid and p1.typarray = p2.oid); - oid | typname ------+--------- + oid | typname +-----+-------------- + 194 | pg_node_tree 210 | smgr 705 | unknown -(2 rows) +(3 rows) -- Make sure typarray points to a varlena array type of our own base SELECT p1.oid, p1.typname as basetype, p2.typname as arraytype, diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 46ec24cca6..0d084a1f7a 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -318,7 +318,10 @@ WHERE c.castfunc = p.oid AND -- because those are binary-compatible while the reverse goes through -- texttoxml(), which does an XML syntax check. -SELECT * +-- As of 9.1, this finds the cast from pg_node_tree to text, which we +-- intentionally do not provide a reverse pathway for. + +SELECT castsource::regtype, casttarget::regtype, castfunc, castcontext FROM pg_cast c WHERE c.castmethod = 'b' AND NOT EXISTS (SELECT 1 FROM pg_cast k diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index 265ef5e26e..479bf8542a 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -51,7 +51,7 @@ WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR (p1.typtype != 'c' AND p1.typrelid != 0); -- Look for basic or enum types that don't have an array type. --- NOTE: as of 8.0, this check finds smgr and unknown. +-- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown. SELECT p1.oid, p1.typname FROM pg_type as p1