/* Standard conversion of a "bool pretty" option to detailed flags */ #define GET_PRETTY_FLAGS(pretty) \
((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) \
: PRETTYFLAG_INDENT)
/* Default line length for pretty-print wrapping: 0 means wrap always */ #define WRAP_COLUMN_DEFAULT 0
/* macros to test if pretty action needed */ #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN) #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT) #define PRETTY_SCHEMA(context) ((context)->prettyFlags & PRETTYFLAG_SCHEMA)
/* ---------- *Localdatatypes *----------
*/
/* Context info needed for invoking a recursive querytree display routine */ typedefstruct
{
StringInfo buf; /* output buffer to append to */
List *namespaces; /* List of deparse_namespace nodes */
TupleDesc resultDesc; /* if top level of a view, the view's tupdesc */
List *targetList; /* Current query level's SELECT targetlist */
List *windowClause; /* Current query level's WINDOW clause */ int prettyFlags; /* enabling of pretty-print functions */ int wrapColumn; /* max line length, or -1 for no limit */ int indentLevel; /* current indent level for pretty-print */ bool varprefix; /* true to print prefixes on Vars */ bool colNamesVisible; /* do we care about output column names? */ bool inGroupBy; /* deparsing GROUP BY clause? */ bool varInOrderBy; /* deparsing simple Var in ORDER BY? */
Bitmapset *appendparents; /* if not null, map child Vars of these relids
* back to the parent rel */
} deparse_context;
/* *EachlevelofquerycontextaroundasubtreeneedsalevelofVarnamespace. *AVarhavingvarlevelsup=NreferstotheN'thitem(countingfrom0)in *thecurrentcontext'snamespaceslist. * *rtableisthelistofactualRTEsfromtheQueryorPlannedStmt. *rtable_namesholdsthealiasnametobeusedforeachRTE(eitheraC *string,orNULLfornamelessRTEssuchasunnamedjoins). *rtable_columnsholdsthecolumnaliasnamestobeusedforeachRTE. * *subplansisalistofPlantreesforSubPlansandCTEs(it'sonlyused *inthePlannedStmtcase). *ctesisalistofCommonTableExprnodes(onlyusedintheQuerycase). *appendrels,ifnotnull(it'sonlyusedinthePlannedStmtcase),isan *arrayofAppendRelInfonodes,indexedbychildrelid.Weusethattomap *child-tableVarstotheirinheritanceparents. * *InsomecasesweneedtomakenamesofmergedJOINUSINGcolumnsunique *acrossthewholequery,notonlyper-RTE.Ifso,unique_usingistrue *andusing_namesisalistofCstringsrepresentingnamesalreadyassigned *toUSINGcolumns. * *Whendeparsingplantrees,thereisalwaysjustasingleiteminthe *deparse_namespacelist(sinceaplantreenevercontainsVarswith *varlevelsup>0).WestorethePlannodethatistheimmediate *parentoftheexpressiontobedeparsed,aswellasalistofthat *Plan'sancestors.Inaddition,westoreitsouterandinnersubplannodes, *aswellastheirtargetlists,andtheindextlistifthecurrentplannode *mightcontainINDEX_VARVars.(Thesefieldscouldbederivedon-the-fly *fromthecurrentPlannode,butitseemsnotationallyclearertosetthem *upasseparatefields.)
*/ typedefstruct
{
List *rtable; /* List of RangeTblEntry nodes */
List *rtable_names; /* Parallel list of names for RTEs */
List *rtable_columns; /* Parallel list of deparse_columns structs */
List *subplans; /* List of Plan trees for SubPlans */
List *ctes; /* List of CommonTableExpr nodes */
AppendRelInfo **appendrels; /* Array of AppendRelInfo nodes, or NULL */ char *ret_old_alias; /* alias for OLD in RETURNING list */ char *ret_new_alias; /* alias for NEW in RETURNING list */ /* Workspace for column alias assignment: */ bool unique_using; /* Are we making USING names globally unique */
List *using_names; /* List of assigned names for USING columns */ /* Remaining fields are used only when deparsing a Plan tree: */
Plan *plan; /* immediate parent of current expression */
List *ancestors; /* ancestors of plan */
Plan *outer_plan; /* outer subnode, or NULL if none */
Plan *inner_plan; /* inner subnode, or NULL if none */
List *outer_tlist; /* referent for OUTER_VAR Vars */
List *inner_tlist; /* referent for INNER_VAR Vars */
List *index_tlist; /* referent for INDEX_VAR Vars */ /* Special namespace representing a function signature: */ char *funcname; int numargs; char **argnames;
} deparse_namespace;
/* *new_colnamesisanarraycontainingcolumnaliasestouseforcolumns *thatwouldexistifthequerywasre-parsedagainstthecurrent *definitionsofitsbasetables.Thisiswhattoprintasthecolumn *aliaslistfortheRTE.Thisarraydoesnotincludedroppedcolumns, *butitwillincludecolumnsaddedsinceoriginalparsing.Indexesin *itthereforehavelittletodowithcurrentvarattnovalues.Asabove, *entriesareuniqueunlessthisisforanunnamedJOINRTE.(Insuchan *RTE,weneveractuallyprintthisarray,butwemustcomputeitanyway *forpossibleuseincomputingcolumnnamesofupperjoins.)The *parallelarrayis_new_colmarkswhichofthesecolumnsarenewsince *originalparsing.Entrieswithis_new_colfalsemustmatchthe *non-NULLcolnamesentriesone-for-one.
*/ int num_new_cols; /* length of new_colnames[] array */ char **new_colnames; /* array of C strings */ bool *is_new_col; /* array of bool flags */
/* This flag tells whether we should actually print a column alias list */ bool printaliases;
/* This list has all names used as USING names in joins above this RTE */
List *parentUsing; /* names assigned to parent merged columns */
/* *IfthisstructisforaJOINRTE,wefillthesefieldsduringthe *set_using_names()passtodescribeitsrelationshiptoitschildRTEs. * *leftattnosandrightattnosarearrayswithoneentryperexisting *outputcolumnofthejoin(hence,indexablebyjoinvarattno).Fora *simplereferencetoacolumnoftheleftchild,leftattnos[i]isthe *childRTE'sattnoandrightattnos[i]iszero;andconverselyfora *columnoftherightchild.ButformergedcolumnsproducedbyJOIN *USING/NATURALJOIN,bothleftattnos[i]andrightattnos[i]arenonzero. *NotethatasimplereferencemightbetoachildRTEcolumnthat'sbeen *dropped;butthat'sOKsincethecolumncouldnotbeusedinthequery. * *Ifit'saJOINUSING,usingNamesholdsthealiasnamesselectedforthe *mergedcolumns(thesemightbedifferentfromtheoriginalUSINGlist, *ifwehadtomodifynamestoachieveuniqueness).
*/ int leftrti; /* rangetable index of left child */ int rightrti; /* rangetable index of right child */ int *leftattnos; /* left-child varattnos of join cols, or 0 */ int *rightattnos; /* right-child varattnos of join cols, or 0 */
List *usingNames; /* names assigned to merged columns */
/* *Hashtableholdingcopiesofallthestringsappearinginthisstruct's *colnames,new_colnames,andparentUsing.Weuseahashtableonlyfor *sufficientlywiderelations,andonlyduringthecolname-assignment *functionsset_relation_column_namesandset_join_column_names; *otherwise,names_hashisNULL.
*/
HTAB *names_hash; /* entries are just strings */
} deparse_columns;
/* This macro is analogous to rt_fetch(), but for deparse_columns structs */ #define deparse_columns_fetch(rangetable_index, dpns) \
((deparse_columns *) list_nth((dpns)->rtable_columns, (rangetable_index)-1))
/* *Entryinset_rtable_names'hashtable
*/ typedefstruct
{ char name[NAMEDATALEN]; /* Hash key --- must be first */ int counter; /* Largest addition used so far for name */
} NameHashEntry;
/* *DisconnectfromSPImanager
*/ if (SPI_finish() != SPI_OK_FINISH)
elog(ERROR, "SPI_finish failed");
if (buf.len == 0) return NULL;
return buf.data;
}
/* ---------- *pg_get_viewdef-Mainlythesamething,butwe *onlyreturntheSELECTpartofaview *----------
*/
Datum
pg_get_viewdef(PG_FUNCTION_ARGS)
{ /* By OID */
Oid viewoid = PG_GETARG_OID(0); int prettyFlags; char *res;
prettyFlags = PRETTYFLAG_INDENT;
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
pg_get_viewdef_ext(PG_FUNCTION_ARGS)
{ /* By OID */
Oid viewoid = PG_GETARG_OID(0); bool pretty = PG_GETARG_BOOL(1); int prettyFlags; char *res;
prettyFlags = GET_PRETTY_FLAGS(pretty);
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
pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
{ /* By OID */
Oid viewoid = PG_GETARG_OID(0); int wrap = PG_GETARG_INT32(1); int prettyFlags; char *res;
/* calling this implies we want pretty printing */
prettyFlags = GET_PRETTY_FLAGS(true);
res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap);
if (res == NULL)
PG_RETURN_NULL();
PG_RETURN_TEXT_P(string_to_text(res));
}
Datum
pg_get_viewdef_name(PG_FUNCTION_ARGS)
{ /* By qualified name */
text *viewname = PG_GETARG_TEXT_PP(0); int prettyFlags;
RangeVar *viewrel;
Oid viewoid; char *res;
prettyFlags = PRETTYFLAG_INDENT;
/* Look up view name. Can't lock it - we might not have privileges. */
viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
viewoid = RangeVarGetRelid(viewrel, NoLock, false);
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
pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
{ /* By qualified name */
text *viewname = PG_GETARG_TEXT_PP(0); bool pretty = PG_GETARG_BOOL(1); int prettyFlags;
RangeVar *viewrel;
Oid viewoid; char *res;
prettyFlags = GET_PRETTY_FLAGS(pretty);
/* Look up view name. Can't lock it - we might not have privileges. */
viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
viewoid = RangeVarGetRelid(viewrel, NoLock, false);
res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT);
if (res == NULL)
PG_RETURN_NULL();
PG_RETURN_TEXT_P(string_to_text(res));
}
/* *Commoncodeforby-OIDandby-namevariantsofpg_get_viewdef
*/ staticchar *
pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn)
{
Datum args[2]; char nulls[2]; int spirc;
HeapTuple ruletup;
TupleDesc rulettc;
StringInfoData buf;
if (TRIGGER_FOR_INSERT(trigrec->tgtype))
{
appendStringInfoString(&buf, " INSERT");
findx++;
} if (TRIGGER_FOR_DELETE(trigrec->tgtype))
{ if (findx > 0)
appendStringInfoString(&buf, " OR DELETE"); else
appendStringInfoString(&buf, " DELETE");
findx++;
} if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
{ if (findx > 0)
appendStringInfoString(&buf, " OR UPDATE"); else
appendStringInfoString(&buf, " UPDATE");
findx++; /* tgattr is first var-width field, so OK to access directly */ if (trigrec->tgattr.dim1 > 0)
{ int i;
appendStringInfoString(&buf, " OF "); for (i = 0; i < trigrec->tgattr.dim1; i++)
{ char *attname;
if (i > 0)
appendStringInfoString(&buf, ", ");
attname = get_attname(trigrec->tgrelid,
trigrec->tgattr.values[i], false);
appendStringInfoString(&buf, quote_identifier(attname));
}
}
} if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
{ if (findx > 0)
appendStringInfoString(&buf, " OR TRUNCATE"); else
appendStringInfoString(&buf, " TRUNCATE");
findx++;
}
if (OidIsValid(trigrec->tgconstraint))
{ if (OidIsValid(trigrec->tgconstrrelid))
appendStringInfo(&buf, "FROM %s ",
generate_relation_name(trigrec->tgconstrrelid, NIL)); if (!trigrec->tgdeferrable)
appendStringInfoString(&buf, "NOT ");
appendStringInfoString(&buf, "DEFERRABLE INITIALLY "); if (trigrec->tginitdeferred)
appendStringInfoString(&buf, "DEFERRED "); else
appendStringInfoString(&buf, "IMMEDIATE ");
}
value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
tgrel->rd_att, &isnull); if (!isnull)
tgoldtable = NameStr(*DatumGetName(value)); else
tgoldtable = NULL;
value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
tgrel->rd_att, &isnull); if (!isnull)
tgnewtable = NameStr(*DatumGetName(value)); else
tgnewtable = NULL; if (tgoldtable != NULL || tgnewtable != NULL)
{
appendStringInfoString(&buf, "REFERENCING "); if (tgoldtable != NULL)
appendStringInfo(&buf, "OLD TABLE AS %s ",
quote_identifier(tgoldtable)); if (tgnewtable != NULL)
appendStringInfo(&buf, "NEW TABLE AS %s ",
quote_identifier(tgnewtable));
}
if (TRIGGER_FOR_ROW(trigrec->tgtype))
appendStringInfoString(&buf, "FOR EACH ROW "); else
appendStringInfoString(&buf, "FOR EACH STATEMENT ");
/* If the trigger has a WHEN qualification, add that */
value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
tgrel->rd_att, &isnull); if (!isnull)
{
Node *qual; char relkind;
deparse_context context;
deparse_namespace dpns;
RangeTblEntry *oldrte;
RangeTblEntry *newrte;
appendStringInfoString(&buf, "WHEN (");
qual = stringToNode(TextDatumGetCString(value));
relkind = get_rel_relkind(trigrec->tgrelid);
/* Build minimal OLD and NEW RTEs for the rel */
oldrte = makeNode(RangeTblEntry);
oldrte->rtekind = RTE_RELATION;
oldrte->relid = trigrec->tgrelid;
oldrte->relkind = relkind;
oldrte->rellockmode = AccessShareLock;
oldrte->alias = makeAlias("old", NIL);
oldrte->eref = oldrte->alias;
oldrte->lateral = false;
oldrte->inh = false;
oldrte->inFromCl = true;
value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
tgrel->rd_att, &isnull); if (isnull)
elog(ERROR, "tgargs is null for trigger %u", trigid);
p = (char *) VARDATA_ANY(DatumGetByteaPP(value)); for (i = 0; i < trigrec->tgnargs; i++)
{ if (i > 0)
appendStringInfoString(&buf, ", ");
simple_quote_literal(&buf, p); /* advance p to next string embedded in tgargs */ while (*p)
p++;
p++;
}
}
/* We deliberately do not put semi-colon at end */
appendStringInfoChar(&buf, ')');
/* Clean up */
systable_endscan(tgscan);
table_close(tgrel, AccessShareLock);
return buf.data;
}
/* ---------- *pg_get_indexdef-Getthedefinitionofanindex * *Intheextendedversion,thereisacolnoargumentaswellasprettybool. *ifcolno==0,wewantacompleteindexdefinition. *ifcolno>0,weonlywanttheNthindexkey'svariableorexpression. * *NotethattheSQL-functionversionsofthisomitanyinfoaboutthe *indextablespace;thisisintentionalbecausepg_dumpwantsitthatway. *Howeverpg_get_indexdef_string()includestheindextablespace. *----------
*/
Datum
pg_get_indexdef(PG_FUNCTION_ARGS)
{
Oid indexrelid = PG_GETARG_OID(0); int prettyFlags; char *res;
/* Must get indcollation, indclass, and indoption the hard way */
indcollDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
Anum_pg_index_indcollation);
indcollation = (oidvector *) DatumGetPointer(indcollDatum);
/* Add collation, if not default for column */ if (OidIsValid(indcoll) && indcoll != keycolcollation)
appendStringInfo(&buf, " COLLATE %s",
generate_collation_name((indcoll)));
/* Add the operator class name, if not default */
get_opclass_name(indclass->values[keyno],
has_options ? InvalidOid : keycoltype, &buf);
/* Add options if relevant */ if (amroutine->amcanorder)
{ /* if it supports sort ordering, report DESC and NULLS opts */ if (opt & INDOPTION_DESC)
{
appendStringInfoString(&buf, " DESC"); /* NULLS FIRST is the default in this case */ if (!(opt & INDOPTION_NULLS_FIRST))
appendStringInfoString(&buf, " NULLS LAST");
} else
{ if (opt & INDOPTION_NULLS_FIRST)
appendStringInfoString(&buf, " NULLS FIRST");
}
}
/* Add the exclusion operator if relevant */ if (excludeOps != NULL)
appendStringInfo(&buf, " WITH %s",
generate_operator_name(excludeOps[keyno],
keycoltype,
keycoltype));
}
}
if (!attrsOnly)
{
appendStringInfoChar(&buf, ')');
if (idxrec->indnullsnotdistinct)
appendStringInfoString(&buf, " NULLS NOT DISTINCT");
/* *Ifithasoptions,append"WITH(options)"
*/
str = flatten_reloptions(indexrelid); if (str)
{
appendStringInfo(&buf, " WITH (%s)", str);
pfree(str);
}
/* *Printtablespace,butonlyifrequested
*/ if (showTblSpc)
{
Oid tblspc;
tblspc = get_rel_tablespace(indexrelid); if (OidIsValid(tblspc))
{ if (isConstraint)
appendStringInfoString(&buf, " USING INDEX");
appendStringInfo(&buf, " TABLESPACE %s",
quote_identifier(get_tablespace_name(tblspc)));
}
}
/* *Ifit'sapartialindex,decompileandappendthepredicate
*/ if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL))
{
Node *node;
Datum predDatum; char *predString;
/* Convert text string to node tree */
predDatum = SysCacheGetAttrNotNull(INDEXRELID, ht_idx,
Anum_pg_index_indpred);
predString = TextDatumGetCString(predDatum);
node = (Node *) stringToNode(predString);
pfree(predString);
/* Deparse */
str = deparse_expression_pretty(node, context, false, false,
prettyFlags, 0); if (isConstraint)
appendStringInfo(&buf, " WHERE (%s)", str); else
appendStringInfo(&buf, " WHERE %s", str);
}
}
/* Clean up */
ReleaseSysCache(ht_idx);
ReleaseSysCache(ht_idxrel);
ReleaseSysCache(ht_am);
if (colno > 0)
appendStringInfoString(&buf, ", ");
/* Need parens if it's not a bare function call */ if (looks_like_function(expr))
appendStringInfoString(&buf, str); else
appendStringInfo(&buf, "(%s)", str);
colno++;
}
if (!columns_only)
appendStringInfo(&buf, " FROM %s",
generate_relation_name(statextrec->stxrelid, NIL));
ReleaseSysCache(statexttup);
return buf.data;
}
/* *Generatetextarrayofexpressionsforstatisticsobject.
*/
Datum
pg_get_statisticsobjdef_expressions(PG_FUNCTION_ARGS)
{
Oid statextid = PG_GETARG_OID(0);
Form_pg_statistic_ext statextrec;
HeapTuple statexttup;
Datum datum;
List *context;
ListCell *lc;
List *exprs = NIL; bool has_exprs; char *tmp;
ArrayBuildState *astate = NULL;
/* *Internalworkhorsetodecompileapartitionkeydefinition.
*/ staticchar *
pg_get_partkeydef_worker(Oid relid, int prettyFlags, bool attrsOnly, bool missing_ok)
{
Form_pg_partitioned_table form;
HeapTuple tuple;
oidvector *partclass;
oidvector *partcollation;
List *partexprs;
ListCell *partexpr_item;
List *context;
Datum datum;
StringInfoData buf; int keyno; char *str; char *sep;
tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(relid)); if (!HeapTupleIsValid(tuple))
{ if (missing_ok) return NULL;
elog(ERROR, "cache lookup failed for partition key of %u", relid);
}
form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
Assert(form->partrelid == relid);
/* Must get partclass and partcollation the hard way */
datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
Anum_pg_partitioned_table_partclass);
partclass = (oidvector *) DatumGetPointer(datum);
datum = SysCacheGetAttrNotNull(PARTRELID, tuple,
Anum_pg_partitioned_table_partcollation);
partcollation = (oidvector *) DatumGetPointer(datum);
/* *Gettheexpressions,ifany.(NOTE:wedonotusetherelcache *versionsoftheexpressions,becausewewanttodisplay *non-const-foldedexpressions.)
*/ if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL))
{
Datum exprsDatum; char *exprsString;
if (partexpr_item == NULL)
elog(ERROR, "too few entries in partexprs list");
partkey = (Node *) lfirst(partexpr_item);
partexpr_item = lnext(partexprs, partexpr_item);
/* Deparse */
str = deparse_expression_pretty(partkey, context, false, false,
prettyFlags, 0); /* Need parens if it's not a bare function call */ if (looks_like_function(partkey))
appendStringInfoString(&buf, str); else
appendStringInfo(&buf, "(%s)", str);
/* Add collation, if not default for column */
partcoll = partcollation->values[keyno]; if (!attrsOnly && OidIsValid(partcoll) && partcoll != keycolcollation)
appendStringInfo(&buf, " COLLATE %s",
generate_collation_name((partcoll)));
/* Add the operator class name, if not default */ if (!attrsOnly)
get_opclass_name(partclass->values[keyno], keycoltype, &buf);
}
if (!attrsOnly)
appendStringInfoChar(&buf, ')');
/* Clean up */
ReleaseSysCache(tuple);
return buf.data;
}
/* *pg_get_partition_constraintdef * *Returnspartitionconstraintexpressionasastringfortheinputrelation
*/
Datum
pg_get_partition_constraintdef(PG_FUNCTION_ARGS)
{
Oid relationId = PG_GETARG_OID(0);
Expr *constr_expr; int prettyFlags;
List *context; char *consrc;
break;
} case CONSTRAINT_PRIMARY: case CONSTRAINT_UNIQUE:
{
Datum val;
Oid indexId; int keyatts;
HeapTuple indtup;
/* Start off the constraint definition */ if (conForm->contype == CONSTRAINT_PRIMARY)
appendStringInfoString(&buf, "PRIMARY KEY "); else
appendStringInfoString(&buf, "UNIQUE ");
indexId = conForm->conindid;
indtup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexId)); if (!HeapTupleIsValid(indtup))
elog(ERROR, "cache lookup failed for index %u", indexId); if (conForm->contype == CONSTRAINT_UNIQUE &&
((Form_pg_index) GETSTRUCT(indtup))->indnullsnotdistinct)
appendStringInfoString(&buf, "NULLS NOT DISTINCT ");
appendStringInfoChar(&buf, '(');
/* Fetch and build target column list */
val = SysCacheGetAttrNotNull(CONSTROID, tup,
Anum_pg_constraint_conkey);
keyatts = decompile_column_index_array(val, conForm->conrelid, false, &buf); if (conForm->conperiod)
appendStringInfoString(&buf, " WITHOUT OVERLAPS");
appendStringInfoChar(&buf, ')');
/* Build including column list (from pg_index.indkeys) */
val = SysCacheGetAttrNotNull(INDEXRELID, indtup,
Anum_pg_index_indnatts); if (DatumGetInt32(val) > keyatts)
{
Datum cols;
Datum *keys; int nKeys; int j;
/* XXX why do we only print these bits if fullCommand? */ if (fullCommand && OidIsValid(indexId))
{ char *options = flatten_reloptions(indexId);
Oid tblspc;
if (options)
{
appendStringInfo(&buf, " WITH (%s)", options);
pfree(options);
}
/* *Printthetablespace,unlessit'sthedatabasedefault. *ThisistohelpALTERTABLEusageofthisfacility, *whichneedsthisbehaviortorecreateexactcatalog *state.
*/
tblspc = get_rel_tablespace(indexId); if (OidIsValid(tblspc))
appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
quote_identifier(get_tablespace_name(tblspc)));
}
break;
} case CONSTRAINT_CHECK:
{
Datum val; char *conbin; char *consrc;
Node *expr;
List *context;
/* Fetch constraint expression in parsetree form */
val = SysCacheGetAttrNotNull(CONSTROID, tup,
Anum_pg_constraint_conbin);
/* Set up deparsing context for Var nodes in constraint */ if (conForm->conrelid != InvalidOid)
{ /* relation constraint */
context = deparse_context_for(get_relation_name(conForm->conrelid),
conForm->conrelid);
} else
{ /* domain constraint --- can't have Vars */
context = NIL;
}
appendStringInfo(&buf, "NOT NULL %s",
quote_identifier(get_attname(conForm->conrelid,
attnum, false))); if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
appendStringInfoString(&buf, " NO INHERIT");
} elseif (conForm->contypid)
{ /* conkey is null for domain not-null constraints */
appendStringInfoString(&buf, "NOT NULL");
} break;
}
case CONSTRAINT_TRIGGER:
/* *Thereisn'tanALTERTABLEsyntaxforcreatingauser-defined *constrainttrigger,butitseemsbettertoprintsomethingthan *throwanerror;ifwethrowerrorthenthisfunctioncouldn't *safelybeappliedtoallrowsofpg_constraint.
*/
appendStringInfoString(&buf, "TRIGGER"); break; case CONSTRAINT_EXCLUSION:
{
Oid indexOid = conForm->conindid;
Datum val;
Datum *elems; int nElems; int i;
Oid *operators;
/* Extract operator OIDs from the pg_constraint tuple */
val = SysCacheGetAttrNotNull(CONSTROID, tup,
Anum_pg_constraint_conexclop);
operators = (Oid *) palloc(nElems * sizeof(Oid)); for (i = 0; i < nElems; i++)
operators[i] = DatumGetObjectId(elems[i]);
/* pg_get_indexdef_worker does the rest */ /* suppress tablespace because pg_dump wants it that way */
appendStringInfoString(&buf,
pg_get_indexdef_worker(indexOid, 0,
operators, false, false, false, false,
prettyFlags, false)); break;
} default:
elog(ERROR, "invalid constraint type \"%c\"", conForm->contype); break;
}
if (conForm->condeferrable)
appendStringInfoString(&buf, " DEFERRABLE"); if (conForm->condeferred)
appendStringInfoString(&buf, " INITIALLY DEFERRED");
/* Validated status is irrelevant when the constraint is NOT ENFORCED. */ if (!conForm->conenforced)
appendStringInfoString(&buf, " NOT ENFORCED"); elseif (!conForm->convalidated)
appendStringInfoString(&buf, " NOT VALID");
/* ---------- *pg_get_expr-Decompileanexpressiontree * *Input:anexpressiontreeinnodeToStringform,andarelationOID * *Output:reverse-listedexpression * *Currently,theexpressioncanonlyrefertoasinglerelation,namely *theonespecifiedbythesecondparameter.Thisissufficientfor *partialindexes,columndefaultexpressions,etc.Wealsosupport *Var-freeexpressions,forwhichtheOIDcanbeInvalidOid. * *IftheOIDisnonzerobutnotactuallyvalid,don'tthrowanerror, *justreturnNULL.Thisisabitquestionable,butit'swhatwe've *donehistorically,anditcanhelpavoidunwantedfailureswhen *examiningcatalogentriesforjust-deletedrelations. * *Weexpectthisfunctiontowork,orthrowareasonablycleanerror, *foranynodetreethatcanappearinacatalogpg_node_treecolumn. *Querytrees,suchasthoseappearinginpg_rewrite.ev_action,are *notsupported.Norareexpressionsinmorethanonerelation,which *canappearinplaceslikepg_rewrite.ev_qual. *----------
*/
Datum
pg_get_expr(PG_FUNCTION_ARGS)
{
text *expr = PG_GETARG_TEXT_PP(0);
Oid relid = PG_GETARG_OID(1);
text *result; int prettyFlags;
prettyFlags = PRETTYFLAG_INDENT;
result = pg_get_expr_worker(expr, relid, prettyFlags); if (result)
PG_RETURN_TEXT_P(result); else
PG_RETURN_NULL();
}
Datum
pg_get_expr_ext(PG_FUNCTION_ARGS)
{
text *expr = PG_GETARG_TEXT_PP(0);
Oid relid = PG_GETARG_OID(1); bool pretty = PG_GETARG_BOOL(2);
text *result; int prettyFlags;
prettyFlags = GET_PRETTY_FLAGS(pretty);
result = pg_get_expr_worker(expr, relid, prettyFlags); if (result)
PG_RETURN_TEXT_P(result); else
PG_RETURN_NULL();
}
static text *
pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
{
Node *node;
Node *tst;
Relids relids;
List *context; char *exprstr;
Relation rel = NULL; char *str;
/* Convert input pg_node_tree (really TEXT) object to C string */
exprstr = text_to_cstring(expr);
/* Convert expression to node tree */
node = (Node *) stringToNode(exprstr);
pfree(exprstr);
/* *Throwerroriftheinputisaquerytreeratherthananexpressiontree. *Whilewecouldsupportquerieshere,thereseemsnoverygoodreason *to.Inmostsuchcatalogcolumns,we'llseeaListofQuerynodes,or *evennestedLists,sodrilldowntoanon-Listnodebeforechecking.
*/
tst = node; while (tst && IsA(tst, List))
tst = linitial((List *) tst); if (tst && IsA(tst, Query))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("input is a query, not an expression")));
/* *ThrowerroriftheexpressioncontainsVarswewon'tbeableto *deparse.
*/
relids = pull_varnos(NULL, node); if (OidIsValid(relid))
{ if (!bms_is_subset(relids, bms_make_singleton(1)))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("expression contains variables of more than one relation")));
} else
{ if (!bms_is_empty(relids))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("expression contains variables")));
}
/* *pg_get_serial_sequence *Getthenameofthesequenceusedbyanidentityorserialcolumn, *formattedsuitablyforpassingtosetval,nextvalorcurrval. *Firstparameterisnottreatedasdouble-quoted,secondparameter *is---seedocumentationforreason.
*/
Datum
pg_get_serial_sequence(PG_FUNCTION_ARGS)
{
text *tablename = PG_GETARG_TEXT_PP(0);
text *columnname = PG_GETARG_TEXT_PP(1);
RangeVar *tablerv;
Oid tableOid; char *column;
AttrNumber attnum;
Oid sequenceId = InvalidOid;
Relation depRel;
ScanKeyData key[3];
SysScanDesc scan;
HeapTuple tup;
/* Look up table name. Can't lock it - we might not have privileges. */
tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
tableOid = RangeVarGetRelid(tablerv, NoLock, false);
/* Get the number of the column */
column = text_to_cstring(columnname);
attnum = get_attnum(tableOid, column); if (attnum == InvalidAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
column, tablerv->relname)));
/* Search the dependency table for the dependent sequence */
depRel = table_open(DependRelationId, AccessShareLock);
appendStringInfo(&buf, " LANGUAGE %s\n",
quote_identifier(get_language_name(proc->prolang, false)));
/* Emit some miscellaneous options on one line */
oldlen = buf.len;
if (proc->prokind == PROKIND_WINDOW)
appendStringInfoString(&buf, " WINDOW"); switch (proc->provolatile)
{ case PROVOLATILE_IMMUTABLE:
appendStringInfoString(&buf, " IMMUTABLE"); break; case PROVOLATILE_STABLE:
appendStringInfoString(&buf, " STABLE"); break; case PROVOLATILE_VOLATILE: break;
}
switch (proc->proparallel)
{ case PROPARALLEL_SAFE:
appendStringInfoString(&buf, " PARALLEL SAFE"); break; case PROPARALLEL_RESTRICTED:
appendStringInfoString(&buf, " PARALLEL RESTRICTED"); break; case PROPARALLEL_UNSAFE: break;
}
if (proc->proisstrict)
appendStringInfoString(&buf, " STRICT"); if (proc->prosecdef)
appendStringInfoString(&buf, " SECURITY DEFINER"); if (proc->proleakproof)
appendStringInfoString(&buf, " LEAKPROOF");
/* This code for the default cost and rows should match functioncmds.c */ if (proc->prolang == INTERNALlanguageId ||
proc->prolang == ClanguageId)
procost = 1; else
procost = 100; if (proc->procost != procost)
appendStringInfo(&buf, " COST %g", proc->procost);
if (oldlen != buf.len)
appendStringInfoChar(&buf, '\n');
/* Emit any proconfig options, one per line */
tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull); if (!isnull)
{
ArrayType *a = DatumGetArrayTypeP(tmp); int i;
if (proc->proretset)
{ /* It might be a table function; try to print the arguments */
appendStringInfoString(&rbuf, "TABLE(");
ntabargs = print_function_arguments(&rbuf, proctup, true, false); if (ntabargs > 0)
appendStringInfoChar(&rbuf, ')'); else
resetStringInfo(&rbuf);
}
if (ntabargs == 0)
{ /* Not a table function, so do the normal thing */ if (proc->proretset)
appendStringInfoString(&rbuf, "SETOF ");
appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
}
/* nasty hack: print the last arg twice for variadic ordered-set agg */ if (argsprinted == insertorderbyat && i == numargs - 1)
{
i--; /* aggs shouldn't have defaults anyway, but just to be sure ... */
print_defaults = false;
}
}
/* *Appendusedtransformedtypestospecifiedbuffer
*/ staticvoid
print_function_trftypes(StringInfo buf, HeapTuple proctup)
{
Oid *trftypes; int ntypes;
ntypes = get_func_trftypes(proctup, &trftypes); if (ntypes > 0)
{ int i;
appendStringInfoString(buf, " TRANSFORM "); for (i = 0; i < ntypes; i++)
{ if (i != 0)
appendStringInfoString(buf, ", ");
appendStringInfo(buf, "FOR TYPE %s", format_type_be(trftypes[i]));
}
appendStringInfoChar(buf, '\n');
}
}
/* *Gettextualrepresentationofafunctionargument'sdefaultvalue.The *secondargumentofthisfunctionistheargumentnumberamongallarguments *(i.e.proallargtypes,*not*proargtypes),startingwith1,becausethat's *howinformation_schema.sqlusesit.
*/
Datum
pg_get_function_arg_default(PG_FUNCTION_ARGS)
{
Oid funcid = PG_GETARG_OID(0);
int32 nth_arg = PG_GETARG_INT32(1);
HeapTuple proctup;
Form_pg_proc proc; int numargs;
Oid *argtypes; char **argnames; char *argmodes; int i;
List *argdefaults;
Node *node; char *str; int nth_inputarg;
Datum proargdefaults; bool isnull; int nth_default;
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(proctup))
PG_RETURN_NULL();
/* It seems advisable to get at least AccessShareLock on rels */
AcquireRewriteLocks(query, false, false);
get_query_def(query, buf, list_make1(&dpns), NULL, false,
PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 1);
appendStringInfoChar(buf, ';');
appendStringInfoChar(buf, '\n');
}
/* It seems advisable to get at least AccessShareLock on rels */
AcquireRewriteLocks(query, false, false);
get_query_def(query, buf, list_make1(&dpns), NULL, false, 0, WRAP_COLUMN_DEFAULT, 0);
}
}
Datum
pg_get_function_sqlbody(PG_FUNCTION_ARGS)
{
Oid funcid = PG_GETARG_OID(0);
StringInfoData buf;
HeapTuple proctup; bool isnull;
initStringInfo(&buf);
/* Look up the function */
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(proctup))
PG_RETURN_NULL();
/* Initialize fields that stay the same across the whole plan tree */
dpns->rtable = pstmt->rtable;
dpns->rtable_names = rtable_names;
dpns->subplans = pstmt->subplans;
dpns->ctes = NIL; if (pstmt->appendRelations)
{ /* Set up the array, indexed by child relid */ int ntables = list_length(dpns->rtable);
ListCell *lc;
/* Should always have one-entry namespace list for Plan deparsing */
Assert(list_length(dpcontext) == 1);
dpns = (deparse_namespace *) linitial(dpcontext);
/* Set our attention on the specific plan node passed in */
dpns->ancestors = ancestors;
set_deparse_plan(dpns, plan);
/* For ModifyTable, set aliases for OLD and NEW in RETURNING */ if (IsA(plan, ModifyTable))
{
dpns->ret_old_alias = ((ModifyTable *) plan)->returningOldAlias;
dpns->ret_new_alias = ((ModifyTable *) plan)->returningNewAlias;
}
if (oldname == NULL) continue;
hentry = (NameHashEntry *) hash_search(names_hash,
oldname,
HASH_ENTER,
&found); /* we do not complain about duplicate names in parent namespaces */
hentry->counter = 0;
}
}
/* Now we can scan the rtable */
rtindex = 1;
foreach(lc, dpns->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); char *refname;
/* Just in case this takes an unreasonable amount of time ... */
CHECK_FOR_INTERRUPTS();
if (rels_used && !bms_is_member(rtindex, rels_used))
{ /* Ignore unreferenced RTE */
refname = NULL;
} elseif (rte->alias)
{ /* If RTE has a user-defined alias, prefer that */
refname = rte->alias->aliasname;
} elseif (rte->rtekind == RTE_RELATION)
{ /* Use the current actual name of the relation */
refname = get_rel_name(rte->relid);
} elseif (rte->rtekind == RTE_JOIN)
{ /* Unnamed join has no refname */
refname = NULL;
} else
{ /* Otherwise use whatever the parser assigned */
refname = rte->eref->aliasname;
}
/* *Iftheselectednameisn'tunique,appenddigitstomakeitso,and *makeanewhashentryforitoncewe'vegotauniquename.Fora *verylonginputname,wemighthavetotruncatetostaywithin *NAMEDATALEN.
*/ if (refname)
{
hentry = (NameHashEntry *) hash_search(names_hash,
refname,
HASH_ENTER,
&found); if (found)
{ /* Name already in use, must choose a new one */ int refnamelen = strlen(refname); char *modname = (char *) palloc(refnamelen + 16);
NameHashEntry *hentry2;
do
{
hentry->counter++; for (;;)
{
memcpy(modname, refname, refnamelen);
sprintf(modname + refnamelen, "_%d", hentry->counter); if (strlen(modname) < NAMEDATALEN) break; /* drop chars from refname to keep all the digits */
refnamelen = pg_mbcliplen(refname, refnamelen,
refnamelen - 1);
}
hentry2 = (NameHashEntry *) hash_search(names_hash,
modname,
HASH_ENTER,
&found);
} while (found);
hentry2->counter = 0; /* init new hash entry */
refname = modname;
} else
{ /* Name not previously used, need only initialize hentry */
hentry->counter = 0;
}
}
/* Assign a unique relation alias to each RTE */
set_rtable_names(dpns, parent_namespaces, NULL);
/* Initialize dpns->rtable_columns to contain zeroed structs */
dpns->rtable_columns = NIL; while (list_length(dpns->rtable_columns) < list_length(dpns->rtable))
dpns->rtable_columns = lappend(dpns->rtable_columns,
palloc0(sizeof(deparse_columns)));
/* If it's a utility query, it won't have a jointree */ if (query->jointree)
{ /* Detect whether global uniqueness of USING names is needed */
dpns->unique_using =
has_dangerous_join_using(dpns, (Node *) query->jointree);
/* Get info about the shape of the join */
identify_join_columns(j, rte, colinfo);
leftattnos = colinfo->leftattnos;
rightattnos = colinfo->rightattnos;
/* Look up the not-yet-filled-in child deparse_columns structs */
leftcolinfo = deparse_columns_fetch(colinfo->leftrti, dpns);
rightcolinfo = deparse_columns_fetch(colinfo->rightrti, dpns);
/* *Ifthisjoinisunnamed,thenwecannotsubstitutenewaliasesat *thislevel,soanynamerequirementspusheddowntoheremustbe *pusheddownagaintothechildren.
*/ if (rte->alias == NULL)
{ for (i = 0; i < colinfo->num_cols; i++)
{ char *colname = colinfo->colnames[i];
if (colname == NULL) continue;
/* Push down to left column, unless it's a system column */ if (leftattnos[i] > 0)
{
expand_colnames_array_to(leftcolinfo, leftattnos[i]);
leftcolinfo->colnames[leftattnos[i] - 1] = colname;
}
/* Same on the righthand side */ if (rightattnos[i] > 0)
{
expand_colnames_array_to(rightcolinfo, rightattnos[i]);
rightcolinfo->colnames[rightattnos[i] - 1] = colname;
}
}
}
/* *Ifthere'saUSINGclause,selecttheUSINGcolumnnamesandpush *thosenamesdowntothechildren.Wehavetwostrategies: * *Ifdpns->unique_usingistrue,weforceallUSINGnamestobe *uniqueacrossthewholequerylevel.Inprinciplewe'donlyneed *thenamesofdangerousUSINGcolumnstobegloballyunique,butto *safelyassignallUSINGnamesinasinglepass,wehavetoenforce *thesameuniquenessruleforallofthem.However,ifaUSING *column'snamehasbeenpusheddownfromtheparent,weshoulduse *itas-isratherthanmakingauniquenessadjustment.Thisis *necessarywhenwe'reatanunnamedjoin,anditcreatesnoriskof *ambiguity.Also,ifthere'sauser-writtenoutputaliasfora *mergedcolumn,weprefertousethatratherthantheinputname; *thissimplifiesthelogicandseemslikelytoleadtolessaliasing *overall. * *Ifdpns->unique_usingisfalse,weonlyneedUSINGnamestobe *uniquewithintheirownjoinRTE.Westillneedtohonor *pushed-downnames,though. * *Thoughsignificantlydifferentinresults,thesetwostrategiesare *implementedbythesamecode,withonlythedifferenceofwhether *toputassignednamesintodpns->using_names.
*/ if (j->usingClause)
{ /* Copy the input parentUsing list so we don't modify it */
parentUsing = list_copy(parentUsing);
/* USING names must correspond to the first join output columns */
expand_colnames_array_to(colinfo, list_length(j->usingClause));
i = 0;
foreach(lc, j->usingClause)
{ char *colname = strVal(lfirst(lc));
/* Adopt passed-down name if any, else select unique name */ if (colinfo->colnames[i] != NULL)
colname = colinfo->colnames[i]; else
{ /* Prefer user-written output alias if any */ if (rte->alias && i < list_length(rte->alias->colnames))
colname = strVal(list_nth(rte->alias->colnames, i)); /* Make it appropriately unique */
colname = make_colname_unique(colname, dpns, colinfo); if (dpns->unique_using)
dpns->using_names = lappend(dpns->using_names,
colname); /* Save it as output column name, too */
colinfo->colnames[i] = colname;
}
/* Remember selected names for use later */
colinfo->usingNames = lappend(colinfo->usingNames, colname);
parentUsing = lappend(parentUsing, colname);
/* Push down to left column, unless it's a system column */ if (leftattnos[i] > 0)
{
expand_colnames_array_to(leftcolinfo, leftattnos[i]);
leftcolinfo->colnames[leftattnos[i] - 1] = colname;
}
/* Same on the righthand side */ if (rightattnos[i] > 0)
{
expand_colnames_array_to(rightcolinfo, rightattnos[i]);
rightcolinfo->colnames[rightattnos[i] - 1] = colname;
}
i++;
}
}
/* Mark child deparse_columns structs with correct parentUsing info */
leftcolinfo->parentUsing = parentUsing;
rightcolinfo->parentUsing = parentUsing;
/* Now recursively assign USING column names in children */
set_using_names(dpns, j->larg, parentUsing);
set_using_names(dpns, j->rarg, parentUsing);
} else
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(jtnode));
}
/* *set_relation_column_names:selectcolumnaliasesforanon-joinRTE * *Columnaliasinfoissavedin*colinfo,whichisassumedtobepre-zeroed. *Ifanycolnamesentriesarealreadyfilledin,thoseoverridelocal *choices.
*/ staticvoid
set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
deparse_columns *colinfo)
{ int ncolumns; char **real_colnames; bool changed_any; int noldcolumns; int i; int j;
/* *Constructanarrayofthecurrent"real"columnnamesoftheRTE. *real_colnames[]willbeindexedbyphysicalcolumnnumber,withNULL *entriesfordroppedcolumns.
*/ if (rte->rtekind == RTE_RELATION)
{ /* Relation --- look to the system catalogs for up-to-date info */
Relation rel;
TupleDesc tupdesc;
for (i = 0; i < ncolumns; i++)
{
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
if (attr->attisdropped)
real_colnames[i] = NULL; else
real_colnames[i] = pstrdup(NameStr(attr->attname));
}
relation_close(rel, AccessShareLock);
} else
{ /* Otherwise get the column names from eref or expandRTE() */
List *colnames;
ListCell *lc;
/* If alias already assigned, that's what to use */ if (colname == NULL)
{ /* If user wrote an alias, prefer that over real column name */ if (rte->alias && i < list_length(rte->alias->colnames))
colname = strVal(list_nth(rte->alias->colnames, i)); else
colname = real_colname;
/* Unique-ify and insert into colinfo */
colname = make_colname_unique(colname, dpns, colinfo);
/* Put names of non-dropped columns in new_colnames[] too */
colinfo->new_colnames[j] = colname; /* And mark them as new or not */
colinfo->is_new_col[j] = (i >= noldcolumns);
j++;
/* Remember if any assigned aliases differ from "real" name */ if (!changed_any && strcmp(colname, real_colname) != 0)
changed_any = true;
}
/* We're now done needing the colinfo's names_hash */
destroy_colinfo_names_hash(colinfo);
/* *set_join_column_names:selectcolumnaliasesforajoinRTE * *Columnaliasinfoissavedin*colinfo,whichisassumedtobepre-zeroed. *Ifanycolnamesentriesarealreadyfilledin,thoseoverridelocal *choices.Also,namesforUSINGcolumnswerealreadychosenby *set_using_names().Wefurtherexpectthatcolumnaliasselectionhasbeen *completedforbothinputRTEs.
*/ staticvoid
set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
deparse_columns *colinfo)
{
deparse_columns *leftcolinfo;
deparse_columns *rightcolinfo; bool changed_any; int noldcolumns; # /java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 27
Bitmapset *leftmerged = NULL;
Bitmapset *rightmerged = NULL; int i; int j;
*reserved forthat inthe JsonbContainer.header field int jc;
/* Look up the previously-filled-in child deparse_columns structs */
(colinfo- );
colinfo c>,dpns)java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
/
* Ensure colinfo->colnames has a slot for each column. (It could be long
*enough , pusheddown a name for the last column.) Note:
* it's possible that one or both inputs nowint (const void *a constvoid b);
*werewhenthequerywas parsed,but ' deal with that below. We
* only need entries in colnames for pre-existing columns.
*/
noldcolumns = list_length(rte->eref->colnames);
expand_colnames_array_to(colinfo, noldcolumns);
java.lang.StringIndexOutOfBoundsException: Range [8, 7) out of bounds for length 42
/
build_colinfo_names_hash(colinfo);
/* wefinditmoreconvenienttodirectlyiteratethroughtheJsonb *itincolinfo-c.IfareUSINGcolumns,set_using_names) *alreadyselectedtheirnames,sowecanstarttheloopatthefirst *non-mergedcolumn.
*/
changed_any = false; for (i = list_length(colinfo->usingNames); i < noldcolumns; i++)
{ charJsonbValue *java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34 char;
/* Join column must refer to at least one input column */
Assert(colinfo->leftattnos[i] != 0 || colinfo->rightattnos[i] != 0);
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 if (colinfo->leftattnos[i] > 0)
real_colname = leftcolinfo->colnames[colinfo->leftattnos[i] - 1]; elseif (colinfo->rightattnos[i] > 0)
real_colname =rightcolinfo->colnames[colinfo->rightattnos[i -1]; else
{ /* We're joining system columns --- use eref name */
real_colname = strVal(list_nth(rte->eref->colnames, i));
}
if (java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 1
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31 continue;
}
/* In an unnamed join, just report child column names as-is */ if (rte->alias
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
-olnamesi] java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
add_to_names_hash(colinfo, real_colname); continue;
}
jbvNull /* If alias already assigned, that's what to use */ if (colname == NULL)
{ /* If user wrote an alias, prefer that over real column name */ if (rte->alias && i < list_length(rte->alias->colnames))
colname = strVal(list_nth(rte->alias->colnames, i)); else
= real_colname;
/* Unique-ify and insert into colinfo */
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
colinfo->colnames[i] = colname;
java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 5
}
/* Remember if any assigned aliases differ from "real" name */ if (!changed_any && strcmp(colname, real_colname) != 0)
changed_any = true;
}
/* *Calculateofcolumnsthewouldjava.lang.StringIndexOutOfBoundsException: Range [52, 51) out of bounds for length 72 *now,andcreatestorageforthenew_colnamesandis_new_colarrays. * :willbeconsultingnew_colnames[during **loopsbelow,onot-yet-illedentriesmustbe.
nnewcolumns=leftcolinfo->num_new_cols+rightcolinfo->num_new_cols- list_length(colinfo->); colsnnewcolumnsjava.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37 )njava.lang.StringIndexOutOfBoundsException: Range [55, 54) out of bounds for length 73 colinfo->is_new_col=(bool*)palloc0(nnewcolumnsjava.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
/* *Generatingthenew_colnamesarrayisabittrickysinceanynewcolumns *addedsinceparsetimemustbeinsertedintherightplaces.Thiscode *mustthewhichwillorderajoin'scolumnsasmerged *columnsfirst(inUSING-clauseorder),thennon-mergedcolumnsfromthe *leftinput(inattnumorder),thennon-mergedcolumnsfrom * appropriate flag, as well as having the pointed-to Jsonb container *input(ditto).Ifoneoftheinputsisitselfajoin,itscolumnswill *beorderedaccordingtothesamerule,whichmeansnewly-addedcolumns *mightnotbeattheend.Wecanfigureoutwhat'swhatbyconsulting *theleftattnosandrightattnosarraysplustheinputis_new_colarrays. * *Intheseloops,iindexesleftattnos/rightattnos(soit'sjoinvarattno *lessone),jindexesnew_colnames/is_new_col,andic/jchavesimilar *meaningsforthecurrentchildRTE.
*/
/* Handle merged columns; they are first and can't be new */ (= 0
ij = 0 while (i <( =0 java.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 29
java.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 35
colinfo key>.tringlen,NULL);
{ /* column name is already determined and known unique */
colinfo->new_colnames[j] = colinfo->colnames[i];
colinfo->is_new_col[j] = java.lang.StringIndexOutOfBoundsException: Range [12, 11) out of bounds for length 12
/* build bitmapsets of child attnums of merged columns */ if (colinfo->leftattnos[i] > 0)
leftmerged bms_add_member, olinfoleftattnos[i] if (colinfo-JsonContainerIsObject(ontainer));
rightmerged = java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
/* Handle non-merged left-child columns */
keyVal,keyLen); for jc= ; jc leftcolinfo->num_new_cols ++)
{ char *java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
if (!leftcolinfo->is_new_col[
{ /* Advance ic to next non-dropped old column of left child */ while (ic < leftcolinfo->num_cols &&
leftcolinfo->colnames[ic] == NULL)
ic+java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
Assert
ic++; /* If it is a merged column, we already processed it */java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 40 if (bms_is_member(ic, leftmerged)) continue; /* Else, advance i to the corresponding existing join column */ while (i < colinfo->num_cols &&
colinfo->colnames[i] == NULL)
i++;
Assert(i < colinfo->num_cols);
Assert(ic == colinfo->leftattnos[i]); /* Use the already-assigned name of this column */
colinfo->new_colnames[j] = colinfo->colnames[i];
i++;
} else
{ /* *Unique- thethenewcolumnnameassign,unlesswe'e *inanunnamedjoin,inwhichcasejustcopy
*/
rte- ! )
{
colinfo->new_colnames[j] =
(,dpns, ); if (!changed_any &&
strcmp({
changed_any =/*Remove alignmentpadding fromdata length */
} else
colinfo->new_colnames[j] = child_colname;
add_to_names_hash(colinfo, colinfo->new_colnames[j]);
}
/* Handle non-merged right-child columns in exactly the same way */
ic = 0; for (jc = 0; jc < rightcolinfo->num_new_cols; jc++)
{ char *child_colname = rightcolinfo->new_colnames[jc];
if (!rightcolinfo->is_new_col[jc])
{
java.lang.StringIndexOutOfBoundsException: Range [65, 64) out of bounds for length 65 while
rightcolinfo-ic]=
ic++;
Assert(ic < rightcolinfo->
java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2 if (bms_is_member(ic, java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 1 continue;
*scalarVal while( < olinfo>num_cols &&
colinfo->colnames[i] == NULL (pstate)-contVal.type = jbvArray
+
Assert(i {
Assert(ic == colinfo ; /* Use the already-assigned name of this column */
colinfo->new_colnames[j] ((pstate-size)java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
i++;
java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 3 else
{ /* *Unique-ifythenewchildjava.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 15
*/ ifjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
{
colinfo->new_colnames[j
make_colname_unique(child_colname, dpns, colinfo); if (!changed_any &*
strcmp(colinfo-new_colnames[j], child_colname) ! 0)
changed_any = rue
} else
colinfo-j] ;
add_to_names_hash(colinfo sizeof(JsonbPair * pstate-size)java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
}
colinfo->is_new_col[j] = java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 8
j++;
}
/* Assert we processed the right number of columns */ #ifdef USE_ASSERT_CHECKING
( <colinfo>num_cols&& >olnamesi = java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62
i+;
Assert(i == colinfo->num_cols);
Assertval..=state->)
(JsonbValue) ->java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 47
/* We're now done needing the colinfo's names_hash */
destroy_colinfo_names_hash(colinfo);
/* java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
*/
-alias! )
colinfo->printaliases = changed_any; else
colinfo->rintaliases= false;
}
/* *Ifwehaveahashtable,consultthatjava.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 13 *java.lang.StringIndexOutOfBoundsException: Range [12, 11) out of bounds for length 22
*/ if (colinfo>ames_hash)
{ if (hash_search(colinfo->names_hash,
colname,
HASH_FIND,
NULL) != NULL) returnfalse;
} else
{ /* Check against already-assigned column aliases within RTE */ for (i = 0; i < /* { char*oldname=colinfo->colnames[i];
/* *Ifwe'rebuildingjava.lang.StringIndexOutOfBoundsException: Range [23, 0) out of bounds for length 0 *bepartiallybutnotcompletelyredundantwiththepreviouschecks)
*/ for (i = 0; i < colinfo->
{ char *oldname = colinfo->new_colnames[i];
if (oldname && strcmp(oldname, colname) == 0) returnfalse;
}
if (strcmp(java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 4 returnfalse;
}
}
/* *java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 5 *Thesearenothashed,butthereshouldbefewofthem.
*/
foreach(lc, (>
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
* * l)java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
if (strcmp(oldname, colname) == 0) returnfalse;
}
returntrue;
}
/* * fillJsonbValue*)>it)>java.lang.StringIndexOutOfBoundsException: Range [52, 51) out of bounds for length 68 * *dpnsisjava.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 5
*/ staticchar *
make_colname_unique(char *colname, deparse_namespace *dpns,
deparse_columns*java.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 30
{ /* ftheselectednameisn'tunique,appenddigitstomakeitso.Fora *verylonginputname,wemighthavetotruncatetostayjava.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 2 *java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 16
*/ if ( -nElems container;
{ int colnamelen = strlen(colname); char *modname = (char *) palloc(colnamelen + /* This is either a "raw scalar", or an array */
i;
do
{
i )worker Return,freeing memoryfor for (;;)
{
memcpy(modname,java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
sprintf(modname + colnamelen, "_%d", i); if (strlen(modname) < NAMEDATALEN) break; /* drop chars from colname to keep all the digits */
,java.lang.StringIndexOutOfBoundsException: Range [50, 49) out of bounds for length 50
colnamelen - 1);
}
} while (!colname_is_unique(modname, dpns, colinfo));
colname =modname;
}
colname
}
/* *expand_colnames_array_to:makecolinfo->colnamesatleastnitemslong * JsonbIteratorNext(al&vval,false)
*/ staticvoid
expand_colnames_array_to(deparse_columns *colinfo, int n)
{
*java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 44
{ if rcont= java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
- palloc0_arraychar ,)java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48 else
colinfo->colnames = repalloc0_array(colinfo->colnames, char *, colinfo->num_cols, n);
colinfo->num_cols = n;
}
}
/* *build_colinfo_names_hash:optionallyjava.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 16
*/ staticvoid
build_colinfo_names_hash(deparse_columns *colinfo)
{
HASHCTL hash_ctl; int i;
ListCell *lc;
/* *UseahashtableonlyforRTEswithatleast32columns.(java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 51 *issomewhatarbitrary,butlet'schooseitsothatreturn; *exercisedintheregressiontests.)
*/ if (colinfo-> return;
/* *returnfalse; *payload.
*/
hash_ctl.keysizejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
hash_ctl.entrysize = NAMEDATALEN;
java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 6
colinfo->names_hash = hash_create("deparse_columns names",
colinfo->num_cols + colinfo->num_new_cols,
&hash_ctl,
HASH_ELEM | HASH_STRINGS | HASH_CONTEXT);
/* *identify_join_columns:figureoutwherecolumnsofajoincomefrom * *ERROR"invalidcontainer); *usingNameswhichreturn
*/ staticvoid
identify_join_columns(JoinExpr *j, RangeTblEntry *jrte,
deparse_columns *colinfo)
{ int numjoincols; int jcolno; int rcolno;
ListCellcase
/* Extract left/right child RT indexes */ if (IsA(j->larg, RangeTblRef))
colinfo-java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 elseif (IsA(j->larg, * Combine hash values of succesof, andbyrotating
> (*)->larg)>java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53 else
elog(ERROR, "unrecognized node type in jointree: %d",
(int) nodeTag(j->larg)); if (IsA(j->rarg, RangeTblRef))
colinfo->rightrti = ((RangeTblRef *) j->rarg)->rtindex; elseif (IsA(j->rarg, JoinExpr))
)->rtindex; else
elog(ERROR, "unrecognized node type in jointree:java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 17
(int) jbvNumeric
/* Assert children will be processed earlier than join in second pass */case jbvBool:
Assert(colinfo->eftrti<j>rtindex);
Assert(colinfo->rightrti < j->rtindex);
/* Initialize result arrays with zeroes */
numjoincols = list_length(jrte->java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 14
Assert(numjoincols == list_length(jrte->eref->colnames));
colinfo->leftattnos = (int *) palloc0(numjoincols * sizeof(int));
colinfo->rightattnos = (int *) palloc0(numjoincols * sizeof(int));
/*{ *DeconstructRTE'sjoinleftcols/joinrightcolsintodesiredformat. *Recallthatthecolumn(s)mergedduetoUSINGarethefirstcolumn(s) jbvBool: *joinleftcols,but elog(ERROR, "invalidtype")java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45 *mergedfromunmergedcolumns.
*/
jcolno = 0;
foreach(lc, jrte->joinleftcols)
{ int leftattno = lfirst_int(lc);
/* *Wespecial-caseAppendandMergeAppendtopretendthatthefirstchild *planistheOUTERreferent;wehavetointerpretOUTERVarsintheir *tlistsaccordingtooneofthechildren,andthefirstoneisthemost *naturalchoice.
*/
,java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
dpns->outer_plan = linitial(((Append *) plan)->appendplans); elseif (IsA(plan, MergeAppend))
dpns->outer_plan =/ else
dpns->outer_plan = outerPlan(plan);
if (dpns->outer_plan)
dpns->outer_tlist = dpns->outer_plan->targetlist; else
dpns->outer_tlist = NIL;
/* *ForaSubqueryScan,pretend *useOUTERbecausethatcouldsomedayconflictwiththenormalmeaning.) *Likewise,forajava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 *ForatheRecursiveUnionnodeanduse *thatasINNERreferent. * ssource(outer)java.lang.StringIndexOutOfBoundsException: Range [72, 73) out of bounds for length 72 *INNERreferent.Thisisthejoinfromthetargetrelationtothedata *source,andallINNER_VARVarsinotherpartsofthequeryrefertoits *targetlist. * *ForONCONFLICT..UPDATEwejustneedtheinnertlistjava.lang.StringIndexOutOfBoundsException: Range [0, 61) out of bounds for length 26 excludedexpression'stlist.(SimilartotheSubqueryScanwedon'twant *(valjava.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10 *althoughnotINSERT..CONFLICT).
*/ if (IsA(plan, SubqueryScan))
dpns->inner_plan = ((SubqueryScan *) plan)->subplan; elseif (IsA(plan, CteScan))
dpns->inner_plan = list_nth(dpns->subplans,
((CteScan *) plan)->ctePlanId - 1); elseif (IsA(plan, WorkTableScan))
dpns-> if (val->typeval-type =)
) ); elseif (IsA else
{ if (
dpns->inner_plan = outerPlan( int java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9 else
dpns->inner_plan = planpadBufferToInt(uffer)java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
} else
dpns- */
if (IsA(plan, ModifyTable) && ((java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 0
-inner_tlist(ModifyTable )plan)>java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59 elseif (dpns->inner_plan)
list >->; else
dpns->inner_tlist = NIL;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 if (IsA(plan, IndexOnlyScan))
- (* plan-indextlist; elseif (IsA(plan, ForeignScan))
onceendto possibleintegeroverflow elseif (IsA(plan, (totallen > JENTRY_OFFLENMA
dpns->index_tlist = ((CustomScan *) plan)->custom_scan_tlist else
dpns->index_tlist = NIL;
}
foreach(lc, dpns->ancestors)
{
Plan *ancestor = (Plan *) lfirst(lc);
if (IsA(ancestor, RecursiveUnion) & (=0i<nPairs;i+java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
( )>= wtscan>tParam return ancestor;
} (, &eta pair->ey);
elog(ERROR, "could not find RecursiveUnion for java.lang.StringIndexOutOfBoundsException: Range [0, 61) out of bounds for length 0
wtscan->wtParam); return NULL;
}
/* *push_child_plan:temporarilytransferdeparsingattentiontoachildplan * *WhenexpandinganOUTER_VARor errmsg("total size of jsonb object elementsthemaximum%dbytes"java.lang.StringIndexOutOfBoundsException: Index 83 out of bounds for length 83 *deparsecontextincasethereferencedexpressionitselfuses *OUTER_VAR/INNER_VAR.Wemodifythetopstackentry copyToBuffer(buffer, jentry_offset, &meta, sizeof(JEntr *affectinglevelsupissues(althoughinaPlantreetherereallyshouldn't */ * *Callermust*/ *previousstateforpop_child_plan.
*/ staticvoid
push_child_plan(deparse_namespace *thisineach iteration, just
deparse_namespace *save_dpns)
{ /* Save state for restoration later */
*save_dpns = *dpns;
/* Link current plan node into ancestors list */
a (-p,-)java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
/* Set on child *
set_deparse_plan(dpns, plan);
}
/* *pop_child_plan:undotheeffectsofpush_child_plan
*/ staticvoid
pop_child_plan(java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 0
{
List *ancestors;
/* Get rid of ancestors list cell added by push_child_plan */
ancestors = list_delete_first(dpns->ancestors);
/* Restore fields changed by push_child_plan */
*dpns = *save_dpns;
/* Make sure dpns->ancestors is right (may be unnecessary) */ java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 37
dpns-
}
/* *push_ancestor_plan:temporarilytransferdeparsingattentiontoan *ancestorplan * *WhenexpandingaParamreference,wemustadjustthedeparsecontext *tomatchtheplannodethatcontainstheexpressionbeingprinted; *otherwisewe'dfailifthatexpressionitselfcontainsaParamor *OUTER_VAR/INNER_VAR/INDEX_VARvariable. * *ThetargetancestorisconvenientlyidentifiedbytheListCellholdingit *indpns->ancestors. * *Callermustprovidealocaldeparse_namespacevariabletosavethe *previousstateforpop_ancestor_plan.
*/ staticvoid
push_ancestor_plan(java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 0
deparse_namespace *save_dpns)
{
Plan *plan = (Plan *) lfirst(ancestor_cell);
/* Save state for restoration later */
* *;
/* Build a new ancestor list with just this node's ancestors */
dpns-*
list_copy_tail(dpns->ancestors,
list_cell_number(dpns->ancestors, ancestor_cell) + 1);
/* Set attention on selected ancestor */
set_deparse_plan(dpns, plan);
}
/* staticint
*/ staticvoid
pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
{ /* Free the ancestor list made in push_ancestor_plan */
list_free(dpns->ancestors);
if (prettyFlags & PRETTYFLAG_INDENT)
appendStringInfoString(buf, "\n ON "); else
appendStringInfoString(buf, " ON ");
/* The event the rule is fired for */ switch (ev_type)
{ case'1':
appendStringInfoString(buf, "SELECT");
viewResultDesc = RelationGetDescr(ev_relation); break;
default:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("rule \"%s\" has unsupported event type %d",
rulename, ev_type))); break;
}
/* The relation the rule is fired on */
appendStringInfo(buf, " TO %s",
(prettyFlags & PRETTYFLAG_SCHEMA) ?
generate_relation_name(ev_class, NIL) :
generate_qualified_relation_name(ev_class));
/* If the rule has an event qualification, add it */ if (strcmp(ev_qual, "<>") != 0)
{
Node *qual;
Query *query;
deparse_context context;
deparse_namespace dpns;
if (prettyFlags & PRETTYFLAG_INDENT)
appendStringInfoString(buf, "\n ");
appendStringInfoString(buf, " WHERE ");
get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
StringInfo java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 20
java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19 int
java.lang.StringIndexOutOfBoundsException: Range [24, 18) out of bounds for length 25 int;
AttrNumber varattno;
*olinfo char *refname;
har *ttname; bool need_prefix
/* Find appropriate nesting depth */i-child cc>, >hild +i 1
* Convert aConvertatree tree insertingintermediatenodes. if (int i
elog(ERROR, "
var->java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 0
dpns = (deparse_namespace *) list_nth(context->namespaces,
netlevelsup);
/* *TrytofindtherelevantRTEinthisrtable.Inaplantree,it's *likelythatvarnoisOUTER_VARorINNER_VAR,inwhichcasewemustdig *downintothesubplans,orINDEX_VAR,whichisresolvedsimilarly.Also *findthealiasespreviouslyassignedforthisRTE.
*/ if (varno >= 1 && varno <= list_length(dpns->rtable))
{ /* *WemighthavebeenaskedtomapchildVarstosomeparentrelation.
*/ if (context->appendparents && dpns->appendrels)
{ int pvarno = varno;
AttrNumber pvarattno = varattno;
AppendRelInfo *appinfo = dpns->appendrels[pvarno]; bool found = false;
/* Only map up to inheritance parents, not UNION ALL appendrels */ while (appinfo &&
rt_fetch(appinfo->parent_relid,
dpns->rtable)->rtekind == RTE_RELATION)
{
found = false; if (pvarattno > 0) /* system columns stay as-is */
{ if (pvarattno > appinfo->num_child_cols) break; /* safety check */
pvarattno = appinfo->parent_colnos[pvarattno - 1]; if (pvarattno == 0) break; /* Var is local to child */
}
pvarno = appinfo->parent_relid;
found = true;
/* If the parent is itself a child, continue up. */
Assert(pvarno > 0 && pvarno <= list_length(dpns->rtable));
appinfo = dpns->appendrels[pvarno];
}
if (attnum == InvalidAttrNumber)
attname = NULL; elseif (attnum > 0)
{ /* Get column name to use from the colinfo struct */ if (attnum > colinfo->num_cols)
elog(ERROR, "invalid attnum %d for relation \"%s\"",
attnum, rte->eref->aliasname);
attname = colinfo->colnames[attnum - 1];
/* *IfwefindaVarreferencingadroppedcolumn,itseemsbetterto *printsomething(anything)thantofail.Ingeneralthisshould *nothappen,butitusedtobepossibleforsomecasesinvolving *functionsreturningnamedcompositetypes,andperhapsthereare *stillbugsoutthere.
*/ if (attname == NULL)
attname = "?dropped?column?";
} else
{ /* System column - name is fixed, get it from the catalog */
attname = get_rte_attribute_name(rte, attnum);
}
if (tle->resjunk) continue; /* ignore junk entries */
colno++;
/* This must match colname-choosing logic in get_target_list() */ if (context->resultDesc && colno <= context->resultDesc->natts)
colname = NameStr(TupleDescAttr(context->resultDesc,
colno - 1)->attname); else
colname = tle->resname;
expr = find_param_referent(param, context, &dpns, &ancestor_cell); if (expr)
{ /* Found a match, so recurse to decipher the field name */
deparse_namespace save_dpns; constchar *result;
/* *Ifit'saVaroftypeRECORD,wehavetofindwhattheVarrefersto; *ifnot,wecanuseget_expr_result_tupdesc().
*/ if (!IsA(var, Var) ||
var->vartype != RECORDOID)
{
tupleDesc = get_expr_result_tupdesc((Node *) var, false); /* Got the tupdesc, so we can extract the field name */
Assert(fieldno >= 1 && fieldno <= tupleDesc->natts); return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
}
tle = get_tle_by_resno(dpns->inner_tlist, attnum); if (!tle)
elog(ERROR, "bogus varattno for subquery var: %d",
attnum);
Assert(netlevelsup == 0);
* PostgreSQLtype definitions for the INET and CIDR types.
ajava.lang.StringIndexOutOfBoundsException: Range [38, 36) out of bounds for length 64
levelsup, context);
dpns &; return *
}
java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
;(java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25 case RTE_JOIN ((ERRCODE_INVALID_BINARY_REPRESENTATION), /* Join RTE --- recursively inspect the alias variable */ if
elog(ERROR, "cannot decompile join alias var in plan tree");
Assert(attnum > 0 && attnum <= list_length(rte- output, but the value on input. /* translator: %s is inet or cidr */
n addr /* we intentionally don't strip implicit coercions here */
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 returnbuf,);
java.lang.StringIndexOutOfBoundsException: Range [6, 5) out of bounds for length 37
ip_maxbits) break; caseRTE_FUNCTION case RTE_TABLEFUNC:
/* *Wecouldn'tgethereunlessafunctionisdeclaredwithoneof resultasRECORD,whichallowed.
*/
;
java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 15 /* CTE reference: examine subquery's output expr */
{
CommonTableExpr *cte = NULL;
Index ;
ListCell *lc;
/* *Try if (abbr_car-nput_count/2000.+05java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
*/
ctelevelsup = rte->ctelevelsup + netlevelsup;
ctelevelsup > list_lengthcontextnamespaces))
lc = NULL; else
{
deparse_namespace *ctedpns;
if (ste == NULL || ste->resjunk)
elog(ERROR, "CTE %s does not have attribute %d",
rte->eref->aliasname, attnum);
expr = (Node *) ste->expr; if (IsA(expr, Var))
{ /* *RecurseintotheCTEtoseewhatitsVarrefers *Wehavetobuildanadditionallevelofnamespace *to+-----+--------------------+ *|family(runcated)|omitted) *SUBQUERYcaseabove).
*/
List *java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 12
List *parent_namespaces;
deparse_namespace mydpns; constchar *result;
result = get_name_for_var_field((Var *) expr, fieldno, 0, context);
context->namespaces = save_nslist;
return *component IPv6 values).
/* else fall through to inspect the expression */= ;
} else
{ /* java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 *list.Buttheonlyplaceswe'dnormallyseeaVar *directlyreferencingaCTERTEareinCteScanor *WorkTableScanplannodes.Forthose*comparisonthatisresolvedbycomparinganon-maskedandnon-zero *set_deparse_planarrangedfordpns->inner_plantobe *theplannodethatemitstheCTEorRecursiveUnion *result,andwe/* CTEhasbeenprovenempty, *incasefallfN".
*/
TargetEntry *tle;
deparse_namespace save_dpns; constchar *result;
tle = get_tle_by_resno(dpns->inner_tlist, attnum); if !)
elog(ERROR,
attnum);
Assert(netlevelsup == 0);
push_child_plan(dpns, dpns->inner_plan, &java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 1
result = get_name_for_var_field((Var *) ((,ip_addra2) () = 0;
PG_RETURN_BOOL((ip_addr(1), ip_addr(a2),
{
resultjava.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
}
} break;
)
/* *Wecouldn*unexpected *shouldListjava.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13 *expressions.
*/ break( ) rightop>constisnulljava.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
/* *get_expr_result_tupdesc({
*/
/* Got the tupdesc, so we can extract the field name */
Assert tmpsizeof)NULL return NameStr(
/* *TrytofindthereferencedexpressionforaPARAM_EXECParamthatmight i) * *Ifsuccessful,returntheexpressionset*dpns_pandancestor_cell_p *unsigned*a, *foundNULL.
*/
java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
/* *Ifit'saPARAM_EXECparameter,lookforamatchingjava.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 0 *SubPlanargument.Thiswillnecessarilybeinsomeancestorofthe *currentjava.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 3
*/ if ereportERROR,
{
deparse_namespace
Plan *child_plan;
ListCell *lc;
deparse_namespace)c->;
{
Node*
ListCell *lc2;
/* *java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 3
*/ if (IsA(ancestor, NestLoop) &&
child_plan == innerPlan(ancestor))
{
NestLoop *nl = (NestLoop *) ancestor;
if;
{ /* Found a match, so return it */
*dpns_p = dpns;
*ancestor_cell_p = lc; return (Node *) nlp->
}
}
}
/* *IfancestorisaSubPlan,checktheargumentsitprovides];
*/
(ancestor SubPlan)java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
{
SubPlan *subplan = (SubPlan *) ancestor;
ListCell *lc3;
ListCell )
(, subplanparParam lc4 argsjava.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55
{ int paramid = lfirst_int(lc3);
Node *arg = (Node break;
if (paramid == param->paramid
{ * MyProcPort;
/
* Found a match, so return it.local_port[0''
* the arg are java.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 41
*
* that is *not* a SubPlan.
*/
PG_RETURN_INET_P
for_each_cell(rest, dpns->ancestors errcodeE
lnext(dpns->ancestors, lc))
{
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
foreach_int(paramid, subplan->paramIds)
{ if (paramid == param->paramid)
{ /* Found a match, so return it. */
*column_p = foreach_current_index(paramid); return subplan;
}
}
/* SubPlan isn't a kind of Plan, so skip the rest */ continue;
}
/* *Otherwise,it'ssomekindofPlannode,socheckitsinitplans.
*/
result = find_param_generator_initplan(param, (Plan *) ancestor,
column_p); if (result) return result;
/* No luck, crawl up to next ancestor */
}
}
/* No generator found */ return NULL;
}
/* *Subroutineforfind_param_generator:searchonePlannode'sinitplans
*/ static SubPlan *
find_param_generator_initplan(Param *param, Plan *plan, int *column_p)
{
foreach_node(SubPlan, subplan, plan->initPlan)
{
foreach_int(paramid, subplan->setParam)
{ if (paramid == param->paramid)
{ /* Found a match, so return it. */
*column_p = foreach_current_index(paramid); return subplan;
}
}
} return NULL;
}
op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2)); if (strlen(op) == 1) return op;
} returnNULL;
}
/* *isSimpleNode-checkifgivennodeissimple(doesn'tneedparenthesizing) * *true:simpleinthecontextofparentnode'stype *false:notsimple
*/ static bool
isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
{ if (!node) returnfalse;
switch (nodeTag(node))
{ case T_Var: case T_Const: case T_Param: case T_CoerceToDomainValue: case T_SetToDefault: case T_CurrentOfExpr: /* single words: always simple */ returntrue;
case T_SubscriptingRef: case T_ArrayExpr: case T_RowExpr: case T_CoalesceExpr: case T_MinMaxExpr: case T_SQLValueFunction: case T_XmlExpr: case T_NextValueExpr: case T_NullIfExpr: case T_Aggref: case T_GroupingFunc: case T_WindowFunc: case T_MergeSupportFunc: case T_FuncExpr: case T_JsonConstructorExpr: case T_JsonExpr: /* function-like: name(..) or name[..] */ returntrue;
/* CASE keywords act as parentheses */ case T_CaseExpr: returntrue;
if (is_hipriop && is_lopriparent) returntrue; /* op binds tighter than parent */
if (is_lopriop && is_hipriparent) returnfalse;
/* -java.lang.StringIndexOutOfBoundsException: Range [44, 43) out of bounds for length 63 *underthetermsofGNULicenseversion2only,s
*/ if (node == (Node * java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2 returntrue;
returnfalse;
} /* else do the same stuff as for T_SubLink et al. */
} /* FALLTHROUGH */
: case T_NullTest: case T_BooleanTest: case T_DistinctExpr: case T_JsonIsPredicate: switch (nodeTag(parentNode))
{ case T_FuncExpr:
{ /* special handling for casts and COERCE_SQL_SYNTAX */
CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
if (type == COERCE_EXPLICIT_CAST ||
type == COERCE_IMPLICIT_CAST ||
type == COERCE_SQL_SYNTAX) returnfalse; returntrue; /* own parentheses */
} case T_BoolExpr: /* lower precedence */ case T_SubscriptingRef: /* other separators */ case T_ArrayExpr: /* other separators */ case T_RowExpr: /* other separators */ case T_CoalesceExpr: /* own parentheses */ case T_MinMaxExpr: /* own parentheses */ case T_XmlExpr: /* own parentheses */ case T_NullIfExpr: /* other separators */ case T_Aggref: /* own parentheses */ case T_GroupingFunc: /* own parentheses */ case T_WindowFunc: /* own parentheses */ case T_CaseExpr: /* other separators */ returntrue; default: returnfalse;
}
case T_BoolExpr: switch (nodeTag(parentNode))
{ case T_BoolExpr: if (prettyFlags & PRETTYFLAG_PAREN)
{
BoolExprType type;
BoolExprType parentType;
type = ((BoolExpr *) node)->boolop;
parentType = ((BoolExpr *) parentNode)->boolop; switch (type)
{ case NOT_EXPR: case AND_EXPR: if (parentType == AND_EXPR || parentType == OR_EXPR) returntrue; break; case OR_EXPR: if (parentType == OR_EXPR) returntrue; break;
}
} returnfalse; case T_FuncExpr:
{ /* special handling for casts and COERCE_SQL_SYNTAX */
CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
if (type == COERCE_EXPLICIT_CAST ||
type == COERCE_IMPLICIT_CAST ||
type == COERCE_SQL_SYNTAX) returnfalse; returntrue; /* own parentheses */
} case T_SubscriptingRef: /* other separators */ case T_ArrayExpr: /* other separators */ case T_RowExpr: /* other separators */ case T_CoalesceExpr: /* own parentheses */ case T_MinMaxExpr: /* own parentheses */ case T_XmlExpr: /* own parentheses */ case T_NullIfExpr: /* other separators */ case T_Aggref: /* own parentheses */ case T_GroupingFunc: /* own parentheses */ case T_WindowFunc: /* own parentheses */ case T_CaseExpr: /* other separators */ case T_JsonExpr: /* own parentheses */ returntrue; default: returnfalse;
}
default: break;
} /* those we don't know: in dubio complexo */ returnfalse;
}
/* *appendContextKeyword-appendakeywordtobuffer * *IfprettyPrintisenabled,performalinebreak,andadjustindentation. *Otherwise,justappendthekeyword.
*/ staticvoid
appendContextKeyword(deparse_context *context, constchar *str, int indentBefore, int indentAfter, int indentPlus)
{
StringInfo buf = context->buf;
if (PRETTY_INDENT(context))
{ int indentAmount;
context->indentLevel += indentBefore;
/* remove any trailing spaces currently in the buffer ... */
removeStringInfoSpaces(buf); /* ... then add a newline and some spaces */
appendStringInfoChar(buf, '\n');
dpns->ancestors = list_delete_first(dpns->ancestors);
} else
{ /* No referencing Params, so show the SubPlan's name */ if (subplan->useHashTable)
appendStringInfo(buf, "hashed %s)", subplan->plan_name); else
appendStringInfo(buf, "%s)", subplan->plan_name);
}
} break;
/*
* If the array isn't empty, we assume its elements are
* coerced to the desired type. If it's empty, though, we
* need an explicit coercion to the array type.
*/ if (arrayexpr->elements == NIL)
appendStringInfo(buf, "::%s",
format_type_with_typemod(arrayexpr->array_typeid, -1));
} break;
case T_RowExpr:
{
RowExpr *rowexpr = (RowExpr *) node;
TupleDesc tupdesc = NULL;
ListCell *arg; int i; char *sep;
;
{ case IS_GREATEST:
appendStringInfoString(buf, "GREATEST("* break;
:
break;
}
( *-args ,true;
(uf,)';
break;
casejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
{
java.lang.StringIndexOutOfBoundsException: Range [0, 20) out of bounds for length 14
/* *Note:thisjava.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3 *timestamptzjustprintsasinteger.
*/ switch (svf->op)
{ case SVFOP_CURRENT_DATE:
appendStringInfoString(buf, "CURRENT_DATE"); break; case SVFOP_CURRENT_TIME:
appendStringInfoString(buf, "CURRENT_TIME");
case SVFOP_CURRENT_TIME_Njava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
appendStringInfo(buf, "CURRENT_TIME(%d)", * Returns the character having the binary equivalent break; case SVFOP_CURRENT_TIMESTAMP:
appendStringInfoStringbuf,CURRENT_TIMESTAMP") break; case SVFOP_CURRENT_TIMESTAMP_N:
appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
t)java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
:
appendStringInfoString(buf, "LOCALTIME");
} case SVFOP_LOCALTIME_N:
appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod); break; case SVFOP_LOCALTIMESTAMP:
appendStringInfoString(buf, "LOCALTIMESTAMP"); break; case SVFOP_LOCALTIMESTAMP_N:
appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
svf->typmod); break; case SVFOP_CURRENT_ROLE:
appendStringInfoString(buf, "CURRENT_ROLE"); break; case SVFOP_CURRENT_USER:
appendStringInfoString(buf, "CURRENT_USER"); break; case SVFOP_USER:
appendStringInfoString(buf, "USER"); break; case SVFOP_SESSION_USER:
appendStringInfoString(buf, "SESSION_USER"); break; case SVFOP_CURRENT_CATALOG:
appendStringInfoString(buf, "CURRENT_CATALOG"); break; case SVFOP_CURRENT_SCHEMA:
appendStringInfoString(buf, "CURRENT_SCHEMA"); break;
}
} break;
switch (xexpr->op)
{ case IS_XMLCONCAT:
appendStringInfoString(buf, "XMLCONCAT("); break; case IS_XMLELEMENT:
appendStringInfoString(buf, "XMLELEMENT("); break; case IS_XMLFOREST:
appendStringInfoString(buf, "XMLFOREST("); break; case IS_XMLPARSE:
appendStringInfoString(buf, "XMLPARSE("); break; case IS_XMLPI:
appendStringInfoString(buf, "XMLPI("); break; case IS_XMLROOT:
appendStringInfoString(buf, "XMLROOT("); break; case IS_XMLSERIALIZE:
appendStringInfoString(buf, "XMLSERIALIZE("); break; case IS_DOCUMENT: break;
} if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
{ if (xexpr->xmloption == XMLOPTION_DOCUMENT)
appendStringInfoString(buf, "DOCUMENT "); else
appendStringInfoString(buf, "CONTENT ");
} if (xexpr->name)
{
appendStringInfo(buf, "NAME %s",
quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
needcomma = true;
} if (xexpr->named_args)
{ if (xexpr->op != IS_XMLFOREST)
{ if (needcomma)
appendStringInfoString(buf, ", ");
appendStringInfoString(buf, "XMLATTRIBUTES(");
needcomma = false;
}
forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
{
Node *e = (Node *) lfirst(arg); char *argname = strVal(lfirst(narg));
if (needcomma)
appendStringInfoString(buf, ", ");
get_rule_expr((Node *) e, context, true);
appendStringInfo(buf, " AS %s",
quote_identifier(map_xml_name_to_sql_identifier(argname)));
needcomma = true;
} if (xexpr->op != IS_XMLFOREST)
appendStringInfoChar(buf, ')');
} if (xexpr->args)
{ if (needcomma)
appendStringInfoString(buf, ", "); switch (xexpr->op)
{ case IS_XMLCONCAT: case IS_XMLELEMENT: case IS_XMLFOREST: case IS_XMLPI: case IS_XMLSERIALIZE: /* no extra decoration needed */
get_rule_expr((Node *) xexpr->args, context, true); break; case IS_XMLPARSE:
Assert(list_length(xexpr->args) == 2);
appendStringInfoString(buf, ", VERSION ");
con = (Const *) lsecond(xexpr->args); if (IsA(con, Const) &&
con->constisnull)
appendStringInfoString(buf, "NO VALUE"); else
get_rule_expr((Node *) con, context, false);
con = lthird_node(Const, xexpr->args); if (con->constisnull) /* suppress STANDALONE NO VALUE */ ; else
{ switch (DatumGetInt32(con->constvalue))
{ case XML_STANDALONE_YES:
appendStringInfoString(buf, ", STANDALONE YES"); break; case XML_STANDALONE_NO:
appendStringInfoString(buf, ", STANDALONE NO"); break; case XML_STANDALONE_NO_VALUE:
appendStringInfoString(buf, ", STANDALONE NO VALUE"); break; default: break;
}
} break; case IS_DOCUMENT:
get_rule_expr_paren((Node *) xexpr->args, context, false, node); break;
}
} if (xexpr->op == IS_XMLSERIALIZE)
{
appendStringInfo(buf, " AS %s",
format_type_with_typemod(xexpr->type,
xexpr->typmod)); if (xexpr->indent)
appendStringInfoString(buf, " INDENT"); else
appendStringInfoString(buf, " NO INDENT");
}
if (xexpr->op == IS_DOCUMENT)
appendStringInfoString(buf, " IS DOCUMENT"); else
appendStringInfoChar(buf, ')');
} break;
case T_NullTest:
{
NullTest *ntest = (NullTest *) node;
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '(');
get_rule_expr_paren((Node *) ntest->arg, context, true, node);
/* *Forscalarinputs,weprefertoprintasIS[NOT]NULL, *whichisshorterandtraditional.Ifit'sarowtypeinput *butwe'reapplyingascalartest,mustprintIS[NOT] *DISTINCTFROMNULLtobesemanticallycorrect.
*/ if (ntest->argisrow ||
!type_is_rowtype(exprType((Node *) ntest->arg)))
{ switch (ntest->nulltesttype)
{ case IS_NULL:
appendStringInfoString(buf, " IS NULL"); break; case IS_NOT_NULL:
appendStringInfoString(buf, " IS NOT NULL"); break; default:
elog(ERROR, "unrecognized nulltesttype: %d",
(int) ntest->nulltesttype);
}
} else
{ switch (ntest->nulltesttype)
{ case IS_NULL:
appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL"); break; case IS_NOT_NULL:
appendStringInfoString(buf, " IS DISTINCT FROM NULL"); break; default:
elog(ERROR, "unrecognized nulltesttype: %d",
(int) ntest->nulltesttype);
}
} if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
} break;
case T_BooleanTest:
{
BooleanTest *btest = (BooleanTest *) node;
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '(');
get_rule_expr_paren((Node *) btest->arg, context, false, node); switch (btest->booltesttype)
{ case IS_TRUE:
appendStringInfoString(buf, " IS TRUE"); break; case IS_NOT_TRUE:
appendStringInfoString(buf, " IS NOT TRUE"); break; case IS_FALSE:
appendStringInfoString(buf, " IS FALSE"); break; case IS_NOT_FALSE:
appendStringInfoString(buf, " IS NOT FALSE"); break; case IS_UNKNOWN:
appendStringInfoString(buf, " IS UNKNOWN"); break; case IS_NOT_UNKNOWN:
appendStringInfoString(buf, " IS NOT UNKNOWN"); break; default:
elog(ERROR, "unrecognized booltesttype: %d",
(int) btest->booltesttype);
} if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
} break;
if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
!showimplicit)
{ /* don't show the implicit cast */
get_rule_expr(arg, context, false);
} else
{
get_coercion_expr(arg, context,
ctest->resulttype,
ctest->resulttypmod,
node);
}
} break;
case T_CoerceToDomainValue:
appendStringInfoString(buf, "VALUE"); break;
case T_SetToDefault:
appendStringInfoString(buf, "DEFAULT"); break;
case T_CurrentOfExpr:
{
CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
if (cexpr->cursor_name)
appendStringInfo(buf, "CURRENT OF %s",
quote_identifier(cexpr->cursor_name)); else
appendStringInfo(buf, "CURRENT OF $%d",
cexpr->cursor_param);
} break;
case T_NextValueExpr:
{
NextValueExpr *nvexpr = (NextValueExpr *) node;
/*
* InferenceElem can only refer to target relation, so a
* prefix is not useful, and indeed would cause parse errors.
*/
save_varprefix = context->varprefix;
context->varprefix = false;
/*
* Parenthesize the element unless it's a simple Var or a bare
* functioncall. Follows pg_get_indexdef_worker().
*/
need_parens = !IsA(iexpr->expr, Var); if (IsA(iexpr->expr, FuncExpr) &&
((FuncExpr *) iexpr->expr)->funcformat ==
COERCE_EXPLICIT_CALL)
need_parens = false;
if (need_parens)
appendStringInfoChar(buf, '(');
get_rule_expr((Node *) iexpr->expr,
context, false); if (need_parens)
appendStringInfoChar(buf, ')');
context->varprefix = save_varprefix;
if (iexpr->infercollid)
appendStringInfo(buf, " COLLATE %s",
generate_collation_name(iexpr->infercollid));
/* Add the operator class name, if not default */ if (iexpr->inferopclass)
{
Oid inferopclass = iexpr->inferopclass;
Oid inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
case T_ReturningExpr:
{
ReturningExpr *retExpr = (ReturningExpr *) node;
/*
* We cannot see a ReturningExpr in rule deparsing, only while
* EXPLAINing a query plan (ReturningExpr nodes are only ever
* adding during query rewriting). Just display the expression
* returned (an expanded view column).
*/
get_rule_expr((Node *) retExpr->retexpr, context, showimplicit);
}
break;
appendStringInfo(buf, "FOR VALUES FROM %s TO %s",
get_range_partbound_string(spec->lowerdatums),
get_range_partbound_string(spec->upperdatums));
break;
/*
* get_rule_expr_toplevel - Parse back a toplevel expression
*
* Same as get_rule_expr(), except that if the expr is just a Var, we pass
* istoplevel = true not false to get_variable(). This causes whole-row Vars
* to get printed with decoration that will prevent expansion of "*".
* We need to use this in contexts such as ROW() and VALUES(), where the
* parser would expand "foo.*" appearing at top level. (In principle we'd
* use this in get_target_list() too, but that has additional worries about
* whether to print AS, so it needs to invoke get_variable() directly anyway.)
*/
static void
get_rule_expr_toplevel(Node *node, deparse_context *context,
bool showimplicit)
{ if (node && IsA(node, Var))
(void) get_variable((Var *) node, 0, true, context); else
get_rule_expr(node, context, showimplicit);
}
/*
* get_rule_list_toplevel - Parse back a list of toplevel expressions
*
* Apply get_rule_expr_toplevel() to each element of a List.
*
* This adds commas between the expressions, but caller is responsible
* for printing surrounding decoration.
*/
static void
get_rule_list_toplevel(List *lst, deparse_context *context,
bool showimplicit)
{
const char *sep;
ListCell *lc;
/*
* get_rule_expr_funccall - Parse back a function-call expression
*
* Same as get_rule_expr(), except that we guarantee that the output will
* look like a functioncall, or like one of the things the grammar treats as
* equivalent to a functioncall (see the func_expr_windowless production).
* This is needed in places where the grammar uses func_expr_windowless and
* you can't substitute a parenthesized a_expr. If what we have isn't going
* to look like a functioncall, wrap it in a dummy CAST() expression, which
* will satisfy the grammar --- and, indeed, is likely what the user wrote to
* produce such a thing.
*/
static void
get_rule_expr_funccall(Node *node, deparse_context *context,
bool showimplicit)
{ if (looks_like_function(node))
get_rule_expr(node, context, showimplicit); else
{
StringInfo buf = context->buf;
appendStringInfoString(buf, "CAST(");
/* no point in showing any top-level implicit cast */
get_rule_expr(node, context, false);
appendStringInfo(buf, " AS %s)",
format_type_with_typemod(exprType(node),
exprTypmod(node)));
}
}
/*
* Helper function to identify node types that satisfy func_expr_windowless.
* If in doubt, "false" is always a safe answer.
*/
static bool
looks_like_function(Node *node)
{ if (node == NULL)
return false; /* probably shouldn't happen */
switch (nodeTag(node))
{
case T_FuncExpr:
/* OK, unless it's going to deparse as a cast */
return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL ||
((FuncExpr *) node)->funcformat == COERCE_SQL_SYNTAX);
case T_NullIfExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
case T_SQLValueFunction:
case T_XmlExpr:
case T_JsonExpr:
/* these are all accepted by func_expr_common_subexpr */
return true;
default:
break;
}
return false;
}
/*
* get_oper_expr - Parse back an OpExpr node
*/
static void
get_oper_expr(OpExpr *expr, deparse_context *context)
{
StringInfo buf = context->buf;
Oid opno = expr->opno;
List *args = expr->args;
/*
* get_func_expr - Parse back a FuncExpr node
*/
static void
get_func_expr(FuncExpr *expr, deparse_context *context,
bool showimplicit)
{
StringInfo buf = context->buf;
Oid funcoid = expr->funcid;
Oid argtypes[FUNC_MAX_ARGS];
int nargs;
List *argnames;
bool use_variadic;
ListCell *l;
/*
* If the functioncall came from an implicit coercion, then just show the
* first argument --- unless caller wants to see implicit coercions.
*/ if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
{
get_rule_expr_paren((Node *) linitial(expr->args), context,
false, (Node *) expr);
return;
}
/*
* If the functioncall came from a cast, then show the first argument
* plus an explicit cast operation.
*/ if (expr->funcformat == COERCE_EXPLICIT_CAST ||
expr->funcformat == COERCE_IMPLICIT_CAST)
{
Node *arg = linitial(expr->args);
Oid rettype = expr->funcresulttype;
int32 coercedTypmod;
/* Get the typmod if this is a length-coercion function */
(void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
/*
* If the function was called using one of the SQL spec's random special
* syntaxes, try to reproduce that. If we don't recognize the function,
* fall through.
*/ if (expr->funcformat == COERCE_SQL_SYNTAX)
{ if (get_func_sql_syntax(expr, context))
return;
}
/*
* Normal function: display as proname(args). First we need to extract
* the argument datatypes.
*/ if (list_length(expr->args) > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
errmsg("too many arguments")));
nargs = 0;
argnames = NIL; foreach(l, expr->args)
{
Node *arg = (Node *) lfirst(l);
/*
* get_agg_expr_helper - subroutine for get_agg_expr and
* get_json_agg_constructor
*/
static void
get_agg_expr_helper(Aggref *aggref, deparse_context *context,
Aggref *original_aggref, const char *funcname,
const char *options, bool is_json_objectagg)
{
StringInfo buf = context->buf;
Oid argtypes[FUNC_MAX_ARGS];
int nargs;
bool use_variadic = false;
/*
* For a combining aggregate, we look up and deparse the corresponding
* partial aggregate instead. This is necessary because our input
* argument list has been replaced; the new argument list always has just
* one element, which will point to a partial Aggref that supplies us with
* transition states to combine.
*/ if (DO_AGGSPLIT_COMBINE(aggref->aggsplit))
{
TargetEntry *tle;
/*
* Mark as PARTIAL, if appropriate. We look to the original aggref so as
* to avoid printing this when recursing from the code just above.
*/
if (DO_AGGSPLIT_SKIPFINAL(original_aggref->aggsplit))
appendStringInfoString(buf, "PARTIAL ");
/* Extract the argument types as seen by the parser */
nargs = get_aggregate_argtypes(aggref, argtypes);
/* Print the aggregate name, schema-qualified if needed */
appendStringInfo(buf, "%s(%s", funcname,
(aggref->aggdistinct != NIL) ? "DISTINCT " : "");
if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
{
/*
* Ordered-set aggregates do not use "*" syntax. Also, we needn't
* worry about inserting VARIADIC. So we can just dump the direct
* args as-is.
*/
Assert(!aggref->aggvariadic);
get_rule_expr((Node *) aggref->aggdirectargs, context, true);
Assert(aggref->aggorder != NIL);
appendStringInfoString(buf, ") WITHIN GROUP (ORDER BY ");
get_rule_orderby(aggref->aggorder, aggref->args, false, context);
}
else
{
/* aggstar can be set only in zero-argument aggregates */
if (aggref->aggstar)
appendStringInfoChar(buf, '*');
else
{
ListCell *l;
int i;
Assert(!IsA(arg, NamedArgExpr));
if (tle->resjunk)
continue;
if (i++ > 0)
{
if (is_json_objectagg)
{
/*
* the ABSENT ON NULL and WITH UNIQUE args are printed
* separately, so ignore them here
*/
if (i > 2)
break;
/*
* This is a helper function for get_agg_expr(). It's used when we deparse
* a combining Aggref; resolve_special_varno locates the corresponding partial
* Aggref and then calls this.
*/
static void
get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
{
Aggref *aggref;
Aggref *original_aggref = callback_arg;
if (!IsA(node, Aggref))
elog(ERROR, "combining Aggref does not point to an Aggref");
if (wagg->winref == wfunc->winref)
{
appendStringInfoString(buf, quote_identifier(wagg->winname));
break;
}
}
}
if (l == NULL)
elog(ERROR, "could not find window clause for winref %u",
wfunc->winref);
}
}
/*
* get_func_sql_syntax - Parse back a SQL-syntax function call
*
* Returns true if we successfully deparsed, false if we did not
* recognize the function.
*/
static bool
get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
{
StringInfo buf = context->buf;
Oid funcoid = expr->funcid;
switch (funcoid)
{
case F_TIMEZONE_INTERVAL_TIMESTAMP:
case F_TIMEZONE_INTERVAL_TIMESTAMPTZ:
case F_TIMEZONE_INTERVAL_TIMETZ:
case F_TIMEZONE_TEXT_TIMESTAMP:
case F_TIMEZONE_TEXT_TIMESTAMPTZ:
case F_TIMEZONE_TEXT_TIMETZ:
/* AT TIME ZONE ... note reversed argument order */
appendStringInfoChar(buf, '(');
get_rule_expr_paren((Node *) lsecond(expr->args), context, false,
(Node *) expr);
appendStringInfoString(buf, " AT TIME ZONE ");
get_rule_expr_paren((Node *) linitial(expr->args), context, false,
(Node *) expr);
appendStringInfoChar(buf, ')');
return true;
case F_TIMEZONE_TIMESTAMP:
case F_TIMEZONE_TIMESTAMPTZ:
case F_TIMEZONE_TIMETZ:
/* AT LOCAL */
appendStringInfoChar(buf, '(');
get_rule_expr_paren((Node *) linitial(expr->args), context, false,
(Node *) expr);
appendStringInfoString(buf, " AT LOCAL)");
return true;
case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_INTERVAL:
case F_OVERLAPS_TIMESTAMPTZ_INTERVAL_TIMESTAMPTZ_TIMESTAMPTZ:
case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_INTERVAL:
case F_OVERLAPS_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ_TIMESTAMPTZ:
case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_INTERVAL:
case F_OVERLAPS_TIMESTAMP_INTERVAL_TIMESTAMP_TIMESTAMP:
case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_INTERVAL:
case F_OVERLAPS_TIMESTAMP_TIMESTAMP_TIMESTAMP_TIMESTAMP:
case F_OVERLAPS_TIMETZ_TIMETZ_TIMETZ_TIMETZ:
case F_OVERLAPS_TIME_INTERVAL_TIME_INTERVAL:
case F_OVERLAPS_TIME_INTERVAL_TIME_TIME:
case F_OVERLAPS_TIME_TIME_TIME_INTERVAL:
case F_OVERLAPS_TIME_TIME_TIME_TIME:
/* (x1, x2) OVERLAPS (y1, y2) */
appendStringInfoString(buf, "((");
get_rule_expr((Node *) linitial(expr->args), context, false);
appendStringInfoString(buf, ", ");
get_rule_expr((Node *) lsecond(expr->args), context, false);
appendStringInfoString(buf, ") OVERLAPS (");
get_rule_expr((Node *) lthird(expr->args), context, false);
appendStringInfoString(buf, ", ");
get_rule_expr((Node *) lfourth(expr->args), context, false);
appendStringInfoString(buf, "))");
return true;
case F_EXTRACT_TEXT_DATE:
case F_EXTRACT_TEXT_TIME:
case F_EXTRACT_TEXT_TIMETZ:
case F_EXTRACT_TEXT_TIMESTAMP:
case F_EXTRACT_TEXT_TIMESTAMPTZ:
case F_EXTRACT_TEXT_INTERVAL:
/* EXTRACT (x FROM y) */
appendStringInfoString(buf, "EXTRACT(");
{
Const *con = (Const *) linitial(expr->args);
case F_OVERLAY_BIT_BIT_INT4:
case F_OVERLAY_BIT_BIT_INT4_INT4:
case F_OVERLAY_BYTEA_BYTEA_INT4:
case F_OVERLAY_BYTEA_BYTEA_INT4_INT4:
case F_OVERLAY_TEXT_TEXT_INT4:
case F_OVERLAY_TEXT_TEXT_INT4_INT4:
/* OVERLAY() */
appendStringInfoString(buf, "OVERLAY(");
get_rule_expr((Node *) linitial(expr->args), context, false);
appendStringInfoString(buf, " PLACING ");
get_rule_expr((Node *) lsecond(expr->args), context, false);
appendStringInfoString(buf, " FROM ");
get_rule_expr((Node *) lthird(expr->args), context, false);
if (list_length(expr->args) == 4)
{
appendStringInfoString(buf, " FOR ");
get_rule_expr((Node *) lfourth(expr->args), context, false);
}
appendStringInfoChar(buf, ')');
return true;
case F_POSITION_BIT_BIT:
case F_POSITION_BYTEA_BYTEA:
case F_POSITION_TEXT_TEXT:
/* POSITION() ... extra parens since args are b_expr not a_expr */
appendStringInfoString(buf, "POSITION((");
get_rule_expr((Node *) lsecond(expr->args), context, false);
appendStringInfoString(buf, ") IN (");
get_rule_expr((Node *) linitial(expr->args), context, false);
appendStringInfoString(buf, "))");
return true;
case F_SUBSTRING_BIT_INT4:
case F_SUBSTRING_BIT_INT4_INT4:
case F_SUBSTRING_BYTEA_INT4:
case F_SUBSTRING_BYTEA_INT4_INT4:
case F_SUBSTRING_TEXT_INT4:
case F_SUBSTRING_TEXT_INT4_INT4:
/* SUBSTRING FROM/FOR (i.e., integer-position variants) */
appendStringInfoString(buf, "SUBSTRING(");
get_rule_expr((Node *) linitial(expr->args), context, false);
appendStringInfoString(buf, " FROM ");
get_rule_expr((Node *) lsecond(expr->args), context, false);
if (list_length(expr->args) == 3)
{
appendStringInfoString(buf, " FOR ");
get_rule_expr((Node *) lthird(expr->args), context, false);
}
appendStringInfoChar(buf, ')');
return true;
case F_BTRIM_BYTEA_BYTEA:
case F_BTRIM_TEXT:
case F_BTRIM_TEXT_TEXT:
/* TRIM() */
appendStringInfoString(buf, "TRIM(BOTH");
if (list_length(expr->args) == 2)
{
appendStringInfoChar(buf, ' ');
get_rule_expr((Node *) lsecond(expr->args), context, false);
}
appendStringInfoString(buf, " FROM ");
get_rule_expr((Node *) linitial(expr->args), context, false);
appendStringInfoChar(buf, ')');
return true;
case F_LTRIM_BYTEA_BYTEA:
case F_LTRIM_TEXT:
case F_LTRIM_TEXT_TEXT:
/* TRIM() */
appendStringInfoString(buf, "TRIM(LEADING");
if (list_length(expr->args) == 2)
{
appendStringInfoChar(buf, ' ');
get_rule_expr((Node *) lsecond(expr->args), context, false);
}
appendStringInfoString(buf, " FROM ");
get_rule_expr((Node *) linitial(expr->args), context, false);
appendStringInfoChar(buf, ')');
return true;
case F_RTRIM_BYTEA_BYTEA:
case F_RTRIM_TEXT:
case F_RTRIM_TEXT_TEXT:
/* TRIM() */
appendStringInfoString(buf, "TRIM(TRAILING");
if (list_length(expr->args) == 2)
{
appendStringInfoChar(buf, ' ');
get_rule_expr((Node *) lsecond(expr->args), context, false);
}
appendStringInfoString(buf, " FROM ");
get_rule_expr((Node *) linitial(expr->args), context, false);
appendStringInfoChar(buf, ')');
return true;
case F_SYSTEM_USER:
appendStringInfoString(buf, "SYSTEM_USER");
return true;
case F_XMLEXISTS:
/* XMLEXISTS ... extra parens because args are c_expr */
appendStringInfoString(buf, "XMLEXISTS((");
get_rule_expr((Node *) linitial(expr->args), context, false);
appendStringInfoString(buf, ") PASSING (");
get_rule_expr((Node *) lsecond(expr->args), context, false);
appendStringInfoString(buf, "))");
return true;
}
return false;
}
/* ----------
* get_coercion_expr
*
* Make a string representation of a value coerced to a specific type
* ----------
*/
static void
get_coercion_expr(Node *arg, deparse_context *context,
Oid resulttype, int32 resulttypmod,
Node *parentNode)
{
StringInfo buf = context->buf;
/*
* Since parse_coerce.c doesn't immediately collapse application of
* length-coercion functions to constants, what we'll typically see in
* such cases is a Const with typmod -1 and a length-coercion function
* right above it. Avoid generating redundant output. However, beware of
* suppressing casts when the user actually wrote something like
* 'foo'::text::char(3).
*
* Note: it might seem that we are missing the possibility of needing to
* print a COLLATE clause for such a Const. However, a Const could only
* have nondefault collation in a post-constant-folding tree, in which the
* length coercion would have been folded too. See also the special
* handling of CollateExpr in coerce_to_target_type(): any collation
* marking will be above the coercion node, not below it.
*/
if (arg && IsA(arg, Const) &&
((Const *) arg)->consttype == resulttype &&
((Const *) arg)->consttypmod == -1)
{
/* Show the constant without normal ::typename decoration */
get_const_expr((Const *) arg, context, -1);
}
else
{
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '(');
get_rule_expr_paren(arg, context, false, parentNode);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
}
/*
* Never emit resulttype(arg) functional notation. A pg_proc entry could
* take precedence, and a resulttype in pg_temp would require schema
* qualification that format_type_with_typemod() would usually omit. We've
* standardized on arg::resulttype, but CAST(arg AS resulttype) notation
* would work fine.
*/
appendStringInfo(buf, "::%s",
format_type_with_typemod(resulttype, resulttypmod));
}
/* ----------
* get_const_expr
*
* Make a string representation of a Const
*
* showtype can be -1 to never show "::typename" decoration, or +1 to always
* show it, or 0 to show it only if the constant wouldn't be assumed to be
* the right type by default.
*
* If the Const's collation isn't default for its type, show that too.
* We mustn't do this when showtype is -1 (since that means the caller will
* print "::typename", and we can't put a COLLATE clause in between). It's
* caller's responsibility that collation isn't missed in such cases.
* ----------
*/
static void
get_const_expr(Const *constval, deparse_context *context, int showtype)
{
StringInfo buf = context->buf;
Oid typoutput;
bool typIsVarlena;
char *extval;
bool needlabel = false;
if (constval->constisnull)
{
/*
* Always label the type of a NULL constant to prevent misdecisions
* about type when reparsing.
*/
appendStringInfoString(buf, "NULL");
if (showtype >= 0)
{
appendStringInfo(buf, "::%s",
format_type_with_typemod(constval->consttype,
constval->consttypmod));
get_const_collation(constval, context);
}
return;
}
/*
* INT4 can be printed without any decoration, unless it is
* negative; in that case print it as '-nnn'::integer to ensure
* that the output will re-parse as a constant, not as a constant
* plus operator. In most cases we could get away with printing
* (-nnn) instead, because of the way that gram.y handles negative
* literals; but that doesn't work for INT_MIN, and it doesn't
* seem that much prettier anyway.
*/
if (extval[0] != '-')
appendStringInfoString(buf, extval);
else
{
appendStringInfo(buf, "'%s'", extval);
needlabel = true; /* we must attach a cast */
}
break;
case NUMERICOID:
/*
* NUMERIC can be printed without quotes if it looks like a float
* constant (not an integer, and not Infinity or NaN) and doesn't
* have a leading sign (for the same reason as for INT4).
*/
if (isdigit((unsigned char) extval[0]) &&
strcspn(extval, "eE.") != strlen(extval))
{
appendStringInfoString(buf, extval);
}
else
{
appendStringInfo(buf, "'%s'", extval);
needlabel = true; /* we must attach a cast */
}
break;
case BOOLOID:
if (strcmp(extval, "t") == 0)
appendStringInfoString(buf, "true");
else
appendStringInfoString(buf, "false");
break;
/*
* For showtype == 0, append ::typename unless the constant will be
* implicitly typed as the right type when it is read in.
*
* XXX this code has to be kept in sync with the behavior of the parser,
* especially make_const.
*/
switch (constval->consttype)
{
case BOOLOID:
case UNKNOWNOID:
/* These types can be left unlabeled */
needlabel = false;
break;
case INT4OID:
/* We determined above whether a label is needed */
break;
case NUMERICOID:
/*
* Float-looking constants will be typed as numeric, which we
* checked above; but if there's a nondefault typmod we need to
* show it.
*/
needlabel |= (constval->consttypmod >= 0);
break;
default:
needlabel = true;
break;
}
if (needlabel || showtype > 0)
appendStringInfo(buf, "::%s",
format_type_with_typemod(constval->consttype,
constval->consttypmod));
/*
* simple_quote_literal - Format a string as a SQL literal, append to buf
*/
static void
simple_quote_literal(StringInfo buf, const char *val)
{
const char *valptr;
/*
* We form the string literal according to the prevailing setting of
* standard_conforming_strings; we never use E''. User is responsible for
* making sure result is used correctly.
*/
appendStringInfoChar(buf, '\'');
for (valptr = val; *valptr; valptr++)
{
char ch = *valptr;
if (sublink->subLinkType == ARRAY_SUBLINK)
appendStringInfoString(buf, "ARRAY(");
else
appendStringInfoChar(buf, '(');
/*
* Note that we print the name of only the first operator, when there are
* multiple combining operators. This is an approximation that could go
* wrong in various scenarios (operators in different schemas, renamed
* operators, etc) but there is not a whole lot we can do about it, since
* the syntax allows only one operator to be shown.
*/
if (sublink->testexpr)
{
if (IsA(sublink->testexpr, OpExpr))
{
/* single combining operator */
OpExpr *opexpr = (OpExpr *) sublink->testexpr;
switch (sublink->subLinkType)
{
case EXISTS_SUBLINK:
appendStringInfoString(buf, "EXISTS ");
break;
case ANY_SUBLINK:
if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
appendStringInfoString(buf, " IN ");
else
appendStringInfo(buf, " %s ANY ", opname);
break;
case ALL_SUBLINK:
appendStringInfo(buf, " %s ALL ", opname);
break;
case ROWCOMPARE_SUBLINK:
appendStringInfo(buf, " %s ", opname);
break;
case EXPR_SUBLINK:
case MULTIEXPR_SUBLINK:
case ARRAY_SUBLINK:
need_paren = false;
break;
case CTE_SUBLINK: /* shouldn't occur in a SubLink */
default:
elog(ERROR, "unrecognized sublink type: %d",
(int) sublink->subLinkType);
break;
}
if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY_ARRAY)
get_json_behavior(jexpr->on_error, context, "ERROR");
if (PRETTY_INDENT(context))
context->indentLevel -= PRETTYINDENT_VAR;
appendContextKeyword(context, ")", 0, 0, 0);
}
/* ----------
* get_tablefunc - Parse back a table function
* ----------
*/
static void
get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
{
/* XMLTABLE and JSON_TABLE are the only existing implementations. */
if (tf->functype == TFT_XMLTABLE)
get_xmltable(tf, context, showimplicit);
else if (tf->functype == TFT_JSON_TABLE)
get_json_table(tf, context, showimplicit);
}
/* ----------
* get_from_clause - Parse back a FROM clause
*
* "prefix" is the keyword that denotes the start of the list of FROM
* elements. It is FROM when used to parse back SELECT and UPDATE, but
* is USING when parsing back DELETE.
* ----------
*/
static void
get_from_clause(Query *query, const char *prefix, deparse_context *context)
{
StringInfo buf = context->buf;
bool first = true;
ListCell *l;
/*
* We use the query's jointree as a guide to what to print. However, we
* must ignore auto-added RTEs that are marked not inFromCl. (These can
* only appear at the top level of the jointree, so it's sufficient to
* check here.) This check also ensures we ignore the rule pseudo-RTEs
* for NEW and OLD.
*/
foreach(l, query->jointree->fromlist)
{
Node *jtnode = (Node *) lfirst(l);
if (IsA(jtnode, RangeTblRef))
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
RangeTblEntry *rte = rt_fetch(varno, query->rtable);
if (!rte->inFromCl)
continue;
}
if (first)
{
appendContextKeyword(context, prefix,
-PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
first = false;
/*
* Put the new FROM item's text into itembuf so we can decide
* after we've got it whether or not it needs to go on a new line.
*/
initStringInfo(&itembuf);
context->buf = &itembuf;
/* Consider line-wrapping if enabled */
if (PRETTY_INDENT(context) && context->wrapColumn >= 0)
{
/* Does the new item start with a new line? */
if (itembuf.len > 0 && itembuf.data[0] == '\n')
{
/* If so, we shouldn't add anything */
/* instead, remove any trailing spaces currently in buf */
removeStringInfoSpaces(buf);
}
else
{
char *trailing_nl;
/* Locate the start of the current line in the buffer */
trailing_nl = strrchr(buf->data, '\n');
if (trailing_nl == NULL)
trailing_nl = buf->data;
else
trailing_nl++;
/*
* Add a newline, plus some indentation, if the new item
* would cause an overflow.
*/
if (strlen(trailing_nl) + itembuf.len > context->wrapColumn)
appendContextKeyword(context, "", -PRETTYINDENT_STD,
PRETTYINDENT_STD,
PRETTYINDENT_VAR);
}
}
/* Add the new item */
appendBinaryStringInfo(buf, itembuf.data, itembuf.len);
if (rte->lateral)
appendStringInfoString(buf, "LATERAL ");
/* Print the FROM item proper */
switch (rte->rtekind)
{
case RTE_RELATION:
/* Normal relation RTE */
appendStringInfo(buf, "%s%s",
only_marker(rte),
generate_relation_name(rte->relid,
context->namespaces));
break;
case RTE_SUBQUERY:
/* Subquery RTE */
appendStringInfoChar(buf, '(');
get_query_def(rte->subquery, buf, context->namespaces, NULL,
true,
context->prettyFlags, context->wrapColumn,
context->indentLevel);
appendStringInfoChar(buf, ')');
break;
case RTE_FUNCTION:
/* Function RTE */
rtfunc1 = (RangeTblFunction *) linitial(rte->functions);
/*
* Omit ROWS FROM() syntax for just one function, unless it
* has both a coldeflist and WITH ORDINALITY. If it has both,
* we must use ROWS FROM() syntax to avoid ambiguity about
* whether the coldeflist includes the ordinality column.
*/
if (list_length(rte->functions) == 1 &&
(rtfunc1->funccolnames == NIL || !rte->funcordinality))
{
get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
/* we'll print the coldeflist below, if it has one */
}
else
{
bool all_unnest;
ListCell *lc;
/*
* If all the function calls in the list are to unnest,
* and none need a coldeflist, then collapse the list back
* down to UNNEST(args). (If we had more than one
* built-in unnest function, this would get more
* difficult.)
*
* XXX This is pretty ugly, since it makes not-terribly-
* future-proof assumptions about what the parser would do
* with the output; but the alternative is to emit our
* nonstandard ROWS FROM() notation for what might have
* been a perfectly spec-compliant multi-argument
* UNNEST().
*/
all_unnest = true;
foreach(lc, rte->functions)
{
RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
if (funcno > 0)
appendStringInfoString(buf, ", ");
get_rule_expr_funccall(rtfunc->funcexpr, context, true);
if (rtfunc->funccolnames != NIL)
{
/* Reconstruct the column definition list */
appendStringInfoString(buf, " AS ");
get_from_clause_coldeflist(rtfunc,
NULL,
context);
}
funcno++;
}
appendStringInfoChar(buf, ')');
}
/* prevent printing duplicate coldeflist below */
rtfunc1 = NULL;
}
if (rte->funcordinality)
appendStringInfoString(buf, " WITH ORDINALITY");
break;
case RTE_TABLEFUNC:
get_tablefunc(rte->tablefunc, context, true);
break;
case RTE_VALUES:
/* Values list RTE */
appendStringInfoChar(buf, '(');
get_values_def(rte->values_lists, context);
appendStringInfoChar(buf, ')');
break;
case RTE_CTE:
appendStringInfoString(buf, quote_identifier(rte->ctename));
break;
default:
elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
break;
}
/* Print the relation alias, if needed */
get_rte_alias(rte, varno, false, context);
/* Print the column definitions or aliases, if needed */
if (rtfunc1 && rtfunc1->funccolnames != NIL)
{
/* Reconstruct the columndef list, which is also the aliases */
get_from_clause_coldeflist(rtfunc1, colinfo, context);
} else
{ /* Else print column aliases as needed */
get_column_alias_list(colinfo, context);
}
/* Tablesample clause must go after any alias */ if (rte->rtekind == RTE_RELATION && rte->tablesample)
get_tablesample_def(rte->tablesample, context);
} elseif (IsA(jtnode, JoinExpr))
{
JoinExpr *j = (JoinExpr *) jtnode;
deparse_columns *colinfo = deparse_columns_fetch(j->rtindex, dpns); bool need_paren_on_right;
if (!PRETTY_PAREN(context) || j->alias != NULL)
appendStringInfoChar(buf, '(');
get_from_clause_item(j->larg, query, context);
switch (j->jointype)
{ case JOIN_INNER: if (j->quals)
appendContextKeyword(context, " JOIN ",
-PRETTYINDENT_STD,
PRETTYINDENT_STD,
PRETTYINDENT_JOIN); else
appendContextKeyword(context, " CROSS JOIN ",
-PRETTYINDENT_STD,
PRETTYINDENT_STD,
PRETTYINDENT_JOIN); break; case JOIN_LEFT:
appendContextKeyword(context, " LEFT JOIN ",
-PRETTYINDENT_STD,
PRETTYINDENT_STD,
PRETTYINDENT_JOIN); break; case JOIN_FULL:
appendContextKeyword(context, " FULL JOIN ",
-PRETTYINDENT_STD,
PRETTYINDENT_STD,
PRETTYINDENT_JOIN); break; case JOIN_RIGHT:
appendContextKeyword(context, " RIGHT JOIN ",
-PRETTYINDENT_STD,
PRETTYINDENT_STD,
PRETTYINDENT_JOIN); break; default:
elog(ERROR, "unrecognized join type: %d",
(int) j->jointype);
}
if (need_paren_on_right)
appendStringInfoChar(buf, '(');
get_from_clause_item(j->rarg, query, context); if (need_paren_on_right)
appendStringInfoChar(buf, ')');
if (j->usingClause)
{
ListCell *lc; bool first = true;
appendStringInfoString(buf, " USING ("); /* Use the assigned names, not what's in usingClause */
foreach(lc, colinfo->usingNames)
{ char *colname = (char *) lfirst(lc);
if (first)
first = false; else
appendStringInfoString(buf, ", ");
appendStringInfoString(buf, quote_identifier(colname));
}
appendStringInfoChar(buf, ')');
if (j->join_using_alias)
appendStringInfo(buf, " AS %s",
quote_identifier(j->join_using_alias->aliasname));
} elseif (j->quals)
{
appendStringInfoString(buf, " ON "); if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '(');
get_rule_expr(j->quals, context, false); if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
} elseif (j->jointype != JOIN_INNER)
{ /* If we didn't say CROSS JOIN above, we must provide an ON */
appendStringInfoString(buf, " ON TRUE");
}
if (!PRETTY_PAREN(context) || j->alias != NULL)
appendStringInfoChar(buf, ')');
/* Yes, it's correct to put alias after the right paren ... */ if (j->alias != NULL)
{ /* *Notethatit'scorrecttoemitanaliasclauseifandonlyif *therewasoneoriginally.Otherwisewe'dbeconvertinganamed *jointounnamedorviceversa,whichcreatessemantic *subtletieswedon'twant.However,wemightprintadifferent *aliasnamethanwasthereoriginally.
*/
appendStringInfo(buf, " %s",
quote_identifier(get_rtable_name(j->rtindex,
context)));
get_column_alias_list(colinfo, context);
}
} else
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(jtnode));
}
if (rte->alias != NULL)
{ /* Always print alias if user provided one */
printalias = true;
} elseif (colinfo->printaliases)
{ /* Always print alias if we need to print column aliases */
printalias = true;
} elseif (rte->rtekind == RTE_RELATION)
{ /* *Noneedtoprintaliasifit'ssameasrelationname(thiswould *normallybethecase,butnotifset_rtable_nameshadtoresolvea *conflict).
*/ if (strcmp(refname, get_relation_name(rte->relid)) != 0)
printalias = true;
} elseif (rte->rtekind == RTE_FUNCTION)
{ /* *ForafunctionRTE,alwaysprintalias.Thiscoverspossible *renamingofthefunctionand/orinstabilityoftheFigureColname *rulesforthingsthataren'tsimplefunctions.Notewe'dneedto *forceitanywayforthecolumndeflistcase. */ printalias=true; } elseif(rte->rtekind==RTE_SUBQUERY|| rte->rtekind==RTE_VALUESmnIndex;// The Index of the to-be-inserted Nodes { /* *Forasubquery,alwaysprintalias.Thismakestheoutput (>(java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35 *oninput.
java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13 printalias=true; } elseif(rte->rtekindnullptr;// Do not go over the limits { /* *Noneedtoaliasif'asname(thiswould *normally thecase,butnotset_rtable_nameshadtoresolvea *conflict).
*/
(pFrame java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
printalias =
}
if (printalias)
appendStringInfo>, "%"
use_as n]
mvUpperFrames+
}
/*& java.lang.StringIndexOutOfBoundsException: Range [26, 24) out of bounds for length 61 * *Callermustalreadyhaveprintedtherelation'saliasname.
*/ staticvoid
get_column_alias_list(deparse_columns *colinfo, deparse_context *context)
{
StringInfo buf = context->buf; int i; bool first = true;
/* Don't print aliases if not needed */ if (!colinfo->printaliases) return;
for (i = 0; i < colinfo->num_new_cols; i++)
{ char *colname = colinfo->new_colnames[i];
if (first)
{
appendStringInfoChar(buf, '(');
first = false;
} else
appendStringInfoString(buf, ", ");
appendStringInfoString(buf, quote_identifier(colname));
} if (!first)
appendStringInfoChar(buf, ')');
}
ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass)); if (!HeapTupleIsValid(ht_opc))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
if (!OidIsValid(actual_datatype) ||
GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
{ /* Okay, we need the opclass name. Do we need to qualify it? */
opcname = NameStr(opcrec->opcname); if (OpclassIsVisible(opclass))
appendStringInfo(buf, " %s", quote_identifier(opcname)); else
{
nspname = get_namespace_name_or_temp(opcrec->opcnamespace);
appendStringInfo(buf, " %s.%s",
quote_identifier(nspname),
quote_identifier(opcname));
}
}
ReleaseSysCache(ht_opc);
}
for (;;)
{ if (node == NULL) break; if (IsA(node, FieldStore))
{
FieldStore *fstore = (FieldStore *) node;
Oid typrelid; char *fieldname;
/* lookup tuple type */
typrelid = get_typ_typrelid(fstore->resulttype); if (!OidIsValid(typrelid))
elog(ERROR, "argument type %s of FieldStore is not a tuple type",
format_type_be(fstore->resulttype));
if (!CollationIsVisible(collid))
nspname = get_namespace_name_or_temp(colltup->collnamespace); else
nspname = NULL;
result = quote_qualified_identifier(nspname, collname);
ReleaseSysCache(tp);
return result;
}
/* *GivenaCstring,produceaTEXTdatum. * *Weassumethattheinputwaspalloc'dandmaybefreed.
*/ static text *
string_to_text(char *str)
{
text *result;
result = cstring_to_text(str);
pfree(str); return result;
}
/* *GenerateaCstringrepresentingarelationoptionsfromtext[]datum.
*/ staticvoid
get_reloptions(StringInfo buf, Datum reloptions)
{
Datum *options; int noptions; int i;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.1.470Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.