diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index faf0e30b157e5a591c6dc34719bf0f9f9ea66c1d..a594a12ed7b11a4b15685b667968344ed7c6feb2 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.480 2009/05/18 08:59:29 petere Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.481 2009/05/26 17:36:05 tgl Exp $ --> <chapter id="functions"> <title>Functions and Operators</title> @@ -12367,7 +12367,9 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); is a decompiled reconstruction, not the original text of the command.) <function>pg_get_expr</function> decompiles the internal form of an individual expression, such as the default value for a column. It can be - useful when examining the contents of system catalogs. + useful when examining the contents of system catalogs. If the expression + might contain Vars, specify the OID of the relation they refer to as the + second parameter; if no Vars are expected, zero is sufficient. <function>pg_get_viewdef</function> reconstructs the <command>SELECT</> query that defines a view. Most of these functions come in two variants, one of which can optionally <quote>pretty-print</> the result. The diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 8d06f54e479d46b32eae5ab7a471a498ca068a5a..8e031fd5027074de7aa8a8e77d4e61226f9df1e9 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.297 2009/04/05 19:59:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.298 2009/05/26 17:36:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -146,7 +146,7 @@ static char *pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc, int prettyFlags); static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, int prettyFlags); -static char *pg_get_expr_worker(text *expr, Oid relid, char *relname, +static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags); static int print_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults); @@ -1198,7 +1198,8 @@ decompile_column_index_array(Datum column_index_array, Oid relId, * * Currently, the expression can only refer to a single relation, namely * the one specified by the second parameter. This is sufficient for - * partial indexes, column default expressions, etc. + * partial indexes, column default expressions, etc. We also support + * Var-free expressions, for which the OID can be InvalidOid. * ---------- */ Datum @@ -1208,12 +1209,24 @@ pg_get_expr(PG_FUNCTION_ARGS) Oid relid = PG_GETARG_OID(1); char *relname; - /* Get the name for the relation */ - relname = get_rel_name(relid); - if (relname == NULL) - PG_RETURN_NULL(); /* should we raise an error? */ + if (OidIsValid(relid)) + { + /* Get the name for the relation */ + relname = get_rel_name(relid); - PG_RETURN_TEXT_P(string_to_text(pg_get_expr_worker(expr, relid, relname, 0))); + /* + * If the OID isn't actually valid, don't throw an error, just return + * NULL. This is a bit questionable, but it's what we've done + * historically, and it can help avoid unwanted failures when + * examining catalog entries for just-deleted relations. + */ + if (relname == NULL) + PG_RETURN_NULL(); + } + else + relname = NULL; + + PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, 0)); } Datum @@ -1227,16 +1240,22 @@ pg_get_expr_ext(PG_FUNCTION_ARGS) prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0; - /* Get the name for the relation */ - relname = get_rel_name(relid); - if (relname == NULL) - PG_RETURN_NULL(); /* should we raise an error? */ + if (OidIsValid(relid)) + { + /* Get the name for the relation */ + relname = get_rel_name(relid); + /* See notes above */ + if (relname == NULL) + PG_RETURN_NULL(); + } + else + relname = NULL; - PG_RETURN_TEXT_P(string_to_text(pg_get_expr_worker(expr, relid, relname, prettyFlags))); + PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags)); } -static char * -pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags) +static text * +pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags) { Node *node; List *context; @@ -1249,14 +1268,19 @@ pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags) /* Convert expression to node tree */ node = (Node *) stringToNode(exprstr); + pfree(exprstr); + + /* Prepare deparse context if needed */ + if (OidIsValid(relid)) + context = deparse_context_for(relname, relid); + else + context = NIL; + /* Deparse */ - context = deparse_context_for(relname, relid); str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0); - pfree(exprstr); - - return str; + return string_to_text(str); } diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 814c8228545607beb94b0069b0e12e62d8159a53..ccb54e5929daedf5581a0f8286633de5aa8bd478 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -12,7 +12,7 @@ * by PostgreSQL * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.536 2009/05/21 01:08:43 petere Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.537 2009/05/26 17:36:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -6186,13 +6186,14 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) "typanalyze::pg_catalog.oid AS typanalyzeoid, " "typcategory, typispreferred, " "typdelim, typbyval, typalign, typstorage, " - "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault " + "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault " "FROM pg_catalog.pg_type " "WHERE oid = '%u'::pg_catalog.oid", tinfo->dobj.catId.oid); } else if (fout->remoteVersion >= 80300) { + /* Before 8.4, pg_get_expr does not allow 0 for its second arg */ appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, typreceive, typsend, " "typmodin, typmodout, typanalyze, "