diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 8fb5fbbab794eba3ff2f70aae81f61994bdb15e5..b30cee931d7d047a4993be3e0d70dfa7267e76e6 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -318,9 +318,9 @@ static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags); static char *pg_get_indexdef_worker(Oid indexrelid, int colno, const Oid *excludeOps, bool attrsOnly, bool showTblSpc, - int prettyFlags); + int prettyFlags, bool missing_ok); static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, - int prettyFlags); + int prettyFlags, bool missing_ok); static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags); static int print_function_arguments(StringInfo buf, HeapTuple proctup, @@ -466,9 +466,16 @@ pg_get_ruledef(PG_FUNCTION_ARGS) { Oid ruleoid = PG_GETARG_OID(0); int prettyFlags; + char *res; prettyFlags = PRETTYFLAG_INDENT; - PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags))); + + res = pg_get_ruledef_worker(ruleoid, prettyFlags); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } @@ -478,10 +485,16 @@ pg_get_ruledef_ext(PG_FUNCTION_ARGS) Oid ruleoid = PG_GETARG_OID(0); bool pretty = PG_GETARG_BOOL(1); int prettyFlags; + char *res; prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; - PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags))); + res = pg_get_ruledef_worker(ruleoid, prettyFlags); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } @@ -533,7 +546,12 @@ pg_get_ruledef_worker(Oid ruleoid, int prettyFlags) if (spirc != SPI_OK_SELECT) elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid); if (SPI_processed != 1) - appendStringInfoChar(&buf, '-'); + { + /* + * There is no tuple data available here, just keep the output buffer + * empty. + */ + } else { /* @@ -550,6 +568,9 @@ pg_get_ruledef_worker(Oid ruleoid, int prettyFlags) if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed"); + if (buf.len == 0) + return NULL; + return buf.data; } @@ -565,9 +586,16 @@ pg_get_viewdef(PG_FUNCTION_ARGS) /* By OID */ Oid viewoid = PG_GETARG_OID(0); int prettyFlags; + char *res; prettyFlags = PRETTYFLAG_INDENT; - PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT))); + + res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } @@ -578,10 +606,16 @@ pg_get_viewdef_ext(PG_FUNCTION_ARGS) Oid viewoid = PG_GETARG_OID(0); bool pretty = PG_GETARG_BOOL(1); int prettyFlags; + char *res; prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; - PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT))); + res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } Datum @@ -591,11 +625,17 @@ pg_get_viewdef_wrap(PG_FUNCTION_ARGS) Oid viewoid = PG_GETARG_OID(0); int wrap = PG_GETARG_INT32(1); int prettyFlags; + char *res; /* calling this implies we want pretty printing */ prettyFlags = PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA; - PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags, wrap))); + res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } Datum @@ -606,6 +646,7 @@ pg_get_viewdef_name(PG_FUNCTION_ARGS) int prettyFlags; RangeVar *viewrel; Oid viewoid; + char *res; prettyFlags = PRETTYFLAG_INDENT; @@ -613,7 +654,12 @@ pg_get_viewdef_name(PG_FUNCTION_ARGS) viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname)); viewoid = RangeVarGetRelid(viewrel, NoLock, false); - PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT))); + res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } @@ -690,7 +736,12 @@ pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn) if (spirc != SPI_OK_SELECT) elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid); if (SPI_processed != 1) - appendStringInfoString(&buf, "Not a view"); + { + /* + * There is no tuple data available here, just keep the output buffer + * empty. + */ + } else { /* @@ -707,6 +758,9 @@ pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn) if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed"); + if (buf.len == 0) + return NULL; + return buf.data; } @@ -718,8 +772,14 @@ Datum pg_get_triggerdef(PG_FUNCTION_ARGS) { Oid trigid = PG_GETARG_OID(0); + char *res; - PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, false))); + res = pg_get_triggerdef_worker(trigid, false); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } Datum @@ -727,8 +787,14 @@ pg_get_triggerdef_ext(PG_FUNCTION_ARGS) { Oid trigid = PG_GETARG_OID(0); bool pretty = PG_GETARG_BOOL(1); + char *res; - PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, pretty))); + res = pg_get_triggerdef_worker(trigid, pretty); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } static char * @@ -761,7 +827,11 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) ht_trig = systable_getnext(tgscan); if (!HeapTupleIsValid(ht_trig)) - elog(ERROR, "could not find tuple for trigger %u", trigid); + { + systable_endscan(tgscan); + heap_close(tgrel, AccessShareLock); + return NULL; + } trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig); @@ -976,12 +1046,17 @@ pg_get_indexdef(PG_FUNCTION_ARGS) { Oid indexrelid = PG_GETARG_OID(0); int prettyFlags; + char *res; prettyFlags = PRETTYFLAG_INDENT; - PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0, - NULL, - false, false, - prettyFlags))); + + res = pg_get_indexdef_worker(indexrelid, 0, NULL, false, false, + prettyFlags, true); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } Datum @@ -991,14 +1066,17 @@ pg_get_indexdef_ext(PG_FUNCTION_ARGS) int32 colno = PG_GETARG_INT32(1); bool pretty = PG_GETARG_BOOL(2); int prettyFlags; + char *res; prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; - PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno, - NULL, - colno != 0, - false, - prettyFlags))); + res = pg_get_indexdef_worker(indexrelid, colno, NULL, colno != 0, false, + prettyFlags, true); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } /* @@ -1009,7 +1087,7 @@ pg_get_indexdef_ext(PG_FUNCTION_ARGS) char * pg_get_indexdef_string(Oid indexrelid) { - return pg_get_indexdef_worker(indexrelid, 0, NULL, false, true, 0); + return pg_get_indexdef_worker(indexrelid, 0, NULL, false, true, 0, false); } /* Internal version that just reports the column definitions */ @@ -1019,8 +1097,8 @@ pg_get_indexdef_columns(Oid indexrelid, bool pretty) int prettyFlags; prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; - - return pg_get_indexdef_worker(indexrelid, 0, NULL, true, false, prettyFlags); + return pg_get_indexdef_worker(indexrelid, 0, NULL, true, false, + prettyFlags, false); } /* @@ -1033,7 +1111,7 @@ static char * pg_get_indexdef_worker(Oid indexrelid, int colno, const Oid *excludeOps, bool attrsOnly, bool showTblSpc, - int prettyFlags) + int prettyFlags, bool missing_ok) { /* might want a separate isConstraint parameter later */ bool isConstraint = (excludeOps != NULL); @@ -1065,9 +1143,9 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid)); if (!HeapTupleIsValid(ht_idx)) { - /* Was: elog(ERROR, "cache lookup failed for index %u", indexrelid); */ - /* See: MPP-10387. */ - return pstrdup("Not an index"); + if (missing_ok) + return NULL; + elog(ERROR, "cache lookup failed for index %u", indexrelid); } idxrec = (Form_pg_index) GETSTRUCT(ht_idx); @@ -1324,11 +1402,16 @@ pg_get_constraintdef(PG_FUNCTION_ARGS) { Oid constraintId = PG_GETARG_OID(0); int prettyFlags; + char *res; prettyFlags = PRETTYFLAG_INDENT; - PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId, - false, - prettyFlags))); + + res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } Datum @@ -1337,12 +1420,16 @@ pg_get_constraintdef_ext(PG_FUNCTION_ARGS) Oid constraintId = PG_GETARG_OID(0); bool pretty = PG_GETARG_BOOL(1); int prettyFlags; + char *res; prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; - PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId, - false, - prettyFlags))); + res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true); + + if (res == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(string_to_text(res)); } /* @@ -1351,14 +1438,14 @@ pg_get_constraintdef_ext(PG_FUNCTION_ARGS) char * pg_get_constraintdef_string(Oid constraintId) { - return pg_get_constraintdef_worker(constraintId, true, 0); + return pg_get_constraintdef_worker(constraintId, true, 0, false); } /* Internal version that returns a palloc'd C string */ char * pg_get_constraintexpr_string(Oid constraintId) { - return pg_get_constraintdef_worker(constraintId, false, 0); + return pg_get_constraintdef_worker(constraintId, false, 0, false); } /* @@ -1366,7 +1453,7 @@ pg_get_constraintexpr_string(Oid constraintId) */ static char * pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, - int prettyFlags) + int prettyFlags, bool missing_ok) { HeapTuple tup; Form_pg_constraint conForm; @@ -1396,8 +1483,16 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, UnregisterSnapshot(snapshot); - if (!HeapTupleIsValid(tup)) /* should not happen */ + if (!HeapTupleIsValid(tup)) + { + if (missing_ok) + { + systable_endscan(scandesc); + heap_close(relation, AccessShareLock); + return NULL; + } elog(ERROR, "cache lookup failed for constraint %u", constraintId); + } conForm = (Form_pg_constraint) GETSTRUCT(tup); @@ -1669,7 +1764,8 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, operators, false, false, - prettyFlags)); + prettyFlags, + false)); break; } default: @@ -2024,7 +2120,8 @@ pg_get_functiondef(PG_FUNCTION_ARGS) /* Look up the function */ proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(proctup)) - elog(ERROR, "cache lookup failed for function %u", funcid); + PG_RETURN_NULL(); + proc = (Form_pg_proc) GETSTRUCT(proctup); name = NameStr(proc->proname); @@ -4396,7 +4493,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, if (list_length(actions) != 1) { - appendStringInfoString(buf, "Not a view"); + /* keep output buffer empty and leave */ return; } @@ -4405,7 +4502,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, if (ev_type != '1' || !is_instead || strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT) { - appendStringInfoString(buf, "Not a view"); + /* keep output buffer empty and leave */ return; } diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 15d8c586544615268bfcea40de8998b92027a834..c53a60274d7c8b7ece7340c1c1ad0708000fe3f6 100755 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2735,6 +2735,43 @@ SELECT pg_get_functiondef('func_with_set_params()'::regprocedure); (1 row) +-- tests for pg_get_*def with invalid objects +SELECT pg_get_constraintdef(0); + pg_get_constraintdef +---------------------- + +(1 row) + +SELECT pg_get_functiondef(0); + pg_get_functiondef +-------------------- + +(1 row) + +SELECT pg_get_indexdef(0); + pg_get_indexdef +----------------- + +(1 row) + +SELECT pg_get_ruledef(0); + pg_get_ruledef +---------------- + +(1 row) + +SELECT pg_get_triggerdef(0); + pg_get_triggerdef +------------------- + +(1 row) + +SELECT pg_get_viewdef(0); + pg_get_viewdef +---------------- + +(1 row) + -- test rule for select-for-update create table t_test_rules_select_for_update (c int) distributed randomly; create rule myrule as on insert to t_test_rules_select_for_update diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql index d055c7562e8ee940b876a98814fdb26fd51c47d3..887a2b17990b608cb11b6d654dc21f883f91b739 100644 --- a/src/test/regress/sql/rules.sql +++ b/src/test/regress/sql/rules.sql @@ -1036,6 +1036,14 @@ CREATE FUNCTION func_with_set_params() RETURNS integer IMMUTABLE STRICT; SELECT pg_get_functiondef('func_with_set_params()'::regprocedure); +-- tests for pg_get_*def with invalid objects +SELECT pg_get_constraintdef(0); +SELECT pg_get_functiondef(0); +SELECT pg_get_indexdef(0); +SELECT pg_get_ruledef(0); +SELECT pg_get_triggerdef(0); +SELECT pg_get_viewdef(0); + -- test rule for select-for-update create table t_test_rules_select_for_update (c int) distributed randomly; create rule myrule as on insert to t_test_rules_select_for_update