DROP TABLE IF EXISTS test \;
DROP FUNCTION PLUS_ONE(INTEGER);
NOTICE: table "test" does not exist, skipping
+-- This DROP query uses two different strings, still they count as one entry.
DROP TABLE IF EXISTS test \;
-DROP TABLE IF EXISTS test \;
+Drop Table If Exists test \;
DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER);
NOTICE: table "test" does not exist, skipping
NOTICE: table "test" does not exist, skipping
DROP TABLE test \;
DROP TABLE IF EXISTS test \;
DROP FUNCTION PLUS_ONE(INTEGER);
+-- This DROP query uses two different strings, still they count as one entry.
DROP TABLE IF EXISTS test \;
-DROP TABLE IF EXISTS test \;
+Drop Table If Exists test \;
DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER);
DROP FUNCTION PLUS_TWO(INTEGER);
readfuncs.c - convert text representation back to a node tree (*)
makefuncs.c - creator functions for some common node types
nodeFuncs.c - some other general-purpose manipulation functions
+ queryjumblefuncs.c - compute a node tree for query jumbling (*)
(*) - Most functions in these files are generated by
gen_node_support.pl and #include'd there.
my @no_copy;
# node types we don't want equal support for
my @no_equal;
+# node types we don't want jumble support for
+my @no_query_jumble;
# node types we don't want read support for
my @no_read;
# node types we don't want read/write support for
# This is a regular node, but we skip parsing it from its header file
# since we won't use its internal structure here anyway.
push @node_types, qw(List);
-# Lists are specially treated in all four support files, too.
+# Lists are specially treated in all five support files, too.
# (Ideally we'd mark List as "special copy/equal" not "no copy/equal".
# But until there's other use-cases for that, just hot-wire the tests
# that would need to distinguish.)
push @no_copy, qw(List);
push @no_equal, qw(List);
+push @no_query_jumble, qw(List);
push @special_read_write, qw(List);
# Nodes with custom copy/equal implementations are skipped from
# Similarly for custom read/write implementations.
my @custom_read_write;
+# Similarly for custom query jumble implementation.
+my @custom_query_jumble;
+
# Track node types with manually assigned NodeTag numbers.
my %manual_nodetag_number;
{
push @custom_read_write, $in_struct;
}
+ elsif ($attr eq 'custom_query_jumble')
+ {
+ push @custom_query_jumble, $in_struct;
+ }
elsif ($attr eq 'no_copy')
{
push @no_copy, $in_struct;
push @no_copy, $in_struct;
push @no_equal, $in_struct;
}
+ elsif ($attr eq 'no_query_jumble')
+ {
+ push @no_query_jumble, $in_struct;
+ }
elsif ($attr eq 'no_read')
{
push @no_read, $in_struct;
equal_as_scalar
equal_ignore
equal_ignore_if_zero
+ query_jumble_ignore
+ query_jumble_location
read_write_ignore
write_only_relids
write_only_nondefault_pathtarget
close $rfs;
+# queryjumblefuncs.c
+
+push @output_files, 'queryjumblefuncs.funcs.c';
+open my $jff, '>', "$output_path/queryjumblefuncs.funcs.c$tmpext" or die $!;
+push @output_files, 'queryjumblefuncs.switch.c';
+open my $jfs, '>', "$output_path/queryjumblefuncs.switch.c$tmpext" or die $!;
+
+printf $jff $header_comment, 'queryjumblefuncs.funcs.c';
+printf $jfs $header_comment, 'queryjumblefuncs.switch.c';
+
+print $jff $node_includes;
+
+foreach my $n (@node_types)
+{
+ next if elem $n, @abstract_types;
+ next if elem $n, @nodetag_only;
+ my $struct_no_query_jumble = (elem $n, @no_query_jumble);
+
+ print $jfs "\t\t\tcase T_${n}:\n"
+ . "\t\t\t\t_jumble${n}(jstate, expr);\n"
+ . "\t\t\t\tbreak;\n"
+ unless $struct_no_query_jumble;
+
+ next if elem $n, @custom_query_jumble;
+
+ print $jff "
+static void
+_jumble${n}(JumbleState *jstate, Node *node)
+{
+\t${n} *expr = (${n} *) node;\n
+" unless $struct_no_query_jumble;
+
+ # print instructions for each field
+ foreach my $f (@{ $node_type_info{$n}->{fields} })
+ {
+ my $t = $node_type_info{$n}->{field_types}{$f};
+ my @a = @{ $node_type_info{$n}->{field_attrs}{$f} };
+ my $query_jumble_ignore = $struct_no_query_jumble;
+ my $query_jumble_location = 0;
+
+ # extract per-field attributes
+ foreach my $a (@a)
+ {
+ if ($a eq 'query_jumble_ignore')
+ {
+ $query_jumble_ignore = 1;
+ }
+ elsif ($a eq 'query_jumble_location')
+ {
+ $query_jumble_location = 1;
+ }
+ }
+
+ # node type
+ if (($t =~ /^(\w+)\*$/ or $t =~ /^struct\s+(\w+)\*$/)
+ and elem $1, @node_types)
+ {
+ print $jff "\tJUMBLE_NODE($f);\n"
+ unless $query_jumble_ignore;
+ }
+ elsif ($t eq 'int' && $f =~ 'location$')
+ {
+ # Track the node's location only if directly requested.
+ if ($query_jumble_location)
+ {
+ print $jff "\tJUMBLE_LOCATION($f);\n"
+ unless $query_jumble_ignore;
+ }
+ }
+ elsif ($t eq 'char*')
+ {
+ print $jff "\tJUMBLE_STRING($f);\n"
+ unless $query_jumble_ignore;
+ }
+ else
+ {
+ print $jff "\tJUMBLE_FIELD($f);\n"
+ unless $query_jumble_ignore;
+ }
+ }
+
+ # Some nodes have no attributes like CheckPointStmt,
+ # so tweak things for empty contents.
+ if (scalar(@{ $node_type_info{$n}->{fields} }) == 0)
+ {
+ print $jff "\t(void) expr;\n"
+ unless $struct_no_query_jumble;
+ }
+
+ print $jff "}
+" unless $struct_no_query_jumble;
+}
+
+close $jff;
+close $jfs;
+
# now rename the temporary files to their final names
foreach my $file (@output_files)
{
'nodes.c',
'params.c',
'print.c',
- 'queryjumblefuncs.c',
'read.c',
'tidbitmap.c',
'value.c',
nodefunc_sources = files(
'copyfuncs.c',
'equalfuncs.c',
+ 'queryjumblefuncs.c',
'outfuncs.c',
'readfuncs.c',
)
/* True when compute_query_id is ON, or AUTO and a module requests them */
bool query_id_enabled = false;
-static uint64 compute_utility_query_id(const char *query_text,
- int query_location, int query_len);
static void AppendJumble(JumbleState *jstate,
const unsigned char *item, Size size);
-static void JumbleQueryInternal(JumbleState *jstate, Query *query);
-static void JumbleRangeTable(JumbleState *jstate, List *rtable);
-static void JumbleRowMarks(JumbleState *jstate, List *rowMarks);
-static void JumbleExpr(JumbleState *jstate, Node *node);
static void RecordConstLocation(JumbleState *jstate, int location);
+static void _jumbleNode(JumbleState *jstate, Node *node);
+static void _jumbleList(JumbleState *jstate, Node *node);
+static void _jumbleRangeTblEntry(JumbleState *jstate, Node *node);
/*
* Given a possibly multi-statement source string, confine our attention to the
Assert(IsQueryIdEnabled());
- if (query->utilityStmt)
- {
- query->queryId = compute_utility_query_id(querytext,
- query->stmt_location,
- query->stmt_len);
- }
- else
+ jstate = (JumbleState *) palloc(sizeof(JumbleState));
+
+ /* Set up workspace for query jumbling */
+ jstate->jumble = (unsigned char *) palloc(JUMBLE_SIZE);
+ jstate->jumble_len = 0;
+ jstate->clocations_buf_size = 32;
+ jstate->clocations = (LocationLen *)
+ palloc(jstate->clocations_buf_size * sizeof(LocationLen));
+ jstate->clocations_count = 0;
+ jstate->highest_extern_param_id = 0;
+
+ /* Compute query ID and mark the Query node with it */
+ _jumbleNode(jstate, (Node *) query);
+ query->queryId = DatumGetUInt64(hash_any_extended(jstate->jumble,
+ jstate->jumble_len,
+ 0));
+
+ /*
+ * If we are unlucky enough to get a hash of zero, use 1 instead for
+ * normal statements and 2 for utility queries.
+ */
+ if (query->queryId == UINT64CONST(0))
{
- jstate = (JumbleState *) palloc(sizeof(JumbleState));
-
- /* Set up workspace for query jumbling */
- jstate->jumble = (unsigned char *) palloc(JUMBLE_SIZE);
- jstate->jumble_len = 0;
- jstate->clocations_buf_size = 32;
- jstate->clocations = (LocationLen *)
- palloc(jstate->clocations_buf_size * sizeof(LocationLen));
- jstate->clocations_count = 0;
- jstate->highest_extern_param_id = 0;
-
- /* Compute query ID and mark the Query node with it */
- JumbleQueryInternal(jstate, query);
- query->queryId = DatumGetUInt64(hash_any_extended(jstate->jumble,
- jstate->jumble_len,
- 0));
-
- /*
- * If we are unlucky enough to get a hash of zero, use 1 instead, to
- * prevent confusion with the utility-statement case.
- */
- if (query->queryId == UINT64CONST(0))
+ if (query->utilityStmt)
+ query->queryId = UINT64CONST(2);
+ else
query->queryId = UINT64CONST(1);
}
query_id_enabled = true;
}
-/*
- * Compute a query identifier for the given utility query string.
- */
-static uint64
-compute_utility_query_id(const char *query_text, int query_location, int query_len)
-{
- uint64 queryId;
- const char *sql;
-
- /*
- * Confine our attention to the relevant part of the string, if the query
- * is a portion of a multi-statement source string.
- */
- sql = CleanQuerytext(query_text, &query_location, &query_len);
-
- queryId = DatumGetUInt64(hash_any_extended((const unsigned char *) sql,
- query_len, 0));
-
- /*
- * If we are unlucky enough to get a hash of zero(invalid), use queryID as
- * 2 instead, queryID 1 is already in use for normal statements.
- */
- if (queryId == UINT64CONST(0))
- queryId = UINT64CONST(2);
-
- return queryId;
-}
-
/*
* AppendJumble: Append a value that is substantive in a given query to
* the current jumble.
}
/*
- * Wrappers around AppendJumble to encapsulate details of serialization
- * of individual local variable elements.
- */
-#define APP_JUMB(item) \
- AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item))
-#define APP_JUMB_STRING(str) \
- AppendJumble(jstate, (const unsigned char *) (str), strlen(str) + 1)
-
-/*
- * JumbleQueryInternal: Selectively serialize the query tree, appending
- * significant data to the "query jumble" while ignoring nonsignificant data.
- *
- * Rule of thumb for what to include is that we should ignore anything not
- * semantically significant (such as alias names) as well as anything that can
- * be deduced from child nodes (else we'd just be double-hashing that piece
- * of information).
- */
-static void
-JumbleQueryInternal(JumbleState *jstate, Query *query)
-{
- Assert(IsA(query, Query));
- Assert(query->utilityStmt == NULL);
-
- APP_JUMB(query->commandType);
- /* resultRelation is usually predictable from commandType */
- JumbleExpr(jstate, (Node *) query->cteList);
- JumbleRangeTable(jstate, query->rtable);
- JumbleExpr(jstate, (Node *) query->jointree);
- JumbleExpr(jstate, (Node *) query->mergeActionList);
- JumbleExpr(jstate, (Node *) query->targetList);
- JumbleExpr(jstate, (Node *) query->onConflict);
- JumbleExpr(jstate, (Node *) query->returningList);
- JumbleExpr(jstate, (Node *) query->groupClause);
- APP_JUMB(query->groupDistinct);
- JumbleExpr(jstate, (Node *) query->groupingSets);
- JumbleExpr(jstate, query->havingQual);
- JumbleExpr(jstate, (Node *) query->windowClause);
- JumbleExpr(jstate, (Node *) query->distinctClause);
- JumbleExpr(jstate, (Node *) query->sortClause);
- JumbleExpr(jstate, query->limitOffset);
- JumbleExpr(jstate, query->limitCount);
- APP_JUMB(query->limitOption);
- JumbleRowMarks(jstate, query->rowMarks);
- JumbleExpr(jstate, query->setOperations);
-}
-
-/*
- * Jumble a range table
+ * Record location of constant within query string of query tree
+ * that is currently being walked.
*/
static void
-JumbleRangeTable(JumbleState *jstate, List *rtable)
+RecordConstLocation(JumbleState *jstate, int location)
{
- ListCell *lc;
-
- foreach(lc, rtable)
+ /* -1 indicates unknown or undefined location */
+ if (location >= 0)
{
- RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc);
-
- APP_JUMB(rte->rtekind);
- switch (rte->rtekind)
+ /* enlarge array if needed */
+ if (jstate->clocations_count >= jstate->clocations_buf_size)
{
- case RTE_RELATION:
- APP_JUMB(rte->relid);
- JumbleExpr(jstate, (Node *) rte->tablesample);
- APP_JUMB(rte->inh);
- break;
- case RTE_SUBQUERY:
- JumbleQueryInternal(jstate, rte->subquery);
- break;
- case RTE_JOIN:
- APP_JUMB(rte->jointype);
- break;
- case RTE_FUNCTION:
- JumbleExpr(jstate, (Node *) rte->functions);
- break;
- case RTE_TABLEFUNC:
- JumbleExpr(jstate, (Node *) rte->tablefunc);
- break;
- case RTE_VALUES:
- JumbleExpr(jstate, (Node *) rte->values_lists);
- break;
- case RTE_CTE:
-
- /*
- * Depending on the CTE name here isn't ideal, but it's the
- * only info we have to identify the referenced WITH item.
- */
- APP_JUMB_STRING(rte->ctename);
- APP_JUMB(rte->ctelevelsup);
- break;
- case RTE_NAMEDTUPLESTORE:
- APP_JUMB_STRING(rte->enrname);
- break;
- case RTE_RESULT:
- break;
- default:
- elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
- break;
+ jstate->clocations_buf_size *= 2;
+ jstate->clocations = (LocationLen *)
+ repalloc(jstate->clocations,
+ jstate->clocations_buf_size *
+ sizeof(LocationLen));
}
+ jstate->clocations[jstate->clocations_count].location = location;
+ /* initialize lengths to -1 to simplify third-party module usage */
+ jstate->clocations[jstate->clocations_count].length = -1;
+ jstate->clocations_count++;
}
}
-/*
- * Jumble a rowMarks list
- */
-static void
-JumbleRowMarks(JumbleState *jstate, List *rowMarks)
-{
- ListCell *lc;
-
- foreach(lc, rowMarks)
- {
- RowMarkClause *rowmark = lfirst_node(RowMarkClause, lc);
+#define JUMBLE_NODE(item) \
+ _jumbleNode(jstate, (Node *) expr->item)
+#define JUMBLE_LOCATION(location) \
+ RecordConstLocation(jstate, expr->location)
+#define JUMBLE_FIELD(item) \
+ AppendJumble(jstate, (const unsigned char *) &(expr->item), sizeof(expr->item))
+#define JUMBLE_FIELD_SINGLE(item) \
+ AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item))
+#define JUMBLE_STRING(str) \
+do { \
+ if (expr->str) \
+ AppendJumble(jstate, (const unsigned char *) (expr->str), strlen(expr->str) + 1); \
+} while(0)
- if (!rowmark->pushedDown)
- {
- APP_JUMB(rowmark->rti);
- APP_JUMB(rowmark->strength);
- APP_JUMB(rowmark->waitPolicy);
- }
- }
-}
+#include "queryjumblefuncs.funcs.c"
-/*
- * Jumble an expression tree
- *
- * In general this function should handle all the same node types that
- * expression_tree_walker() does, and therefore it's coded to be as parallel
- * to that function as possible. However, since we are only invoked on
- * queries immediately post-parse-analysis, we need not handle node types
- * that only appear in planning.
- *
- * Note: the reason we don't simply use expression_tree_walker() is that the
- * point of that function is to support tree walkers that don't care about
- * most tree node types, but here we care about all types. We should complain
- * about any unrecognized node type.
- */
static void
-JumbleExpr(JumbleState *jstate, Node *node)
+_jumbleNode(JumbleState *jstate, Node *node)
{
- ListCell *temp;
+ Node *expr = node;
- if (node == NULL)
+ if (expr == NULL)
return;
/* Guard against stack overflow due to overly complex expressions */
* We always emit the node's NodeTag, then any additional fields that are
* considered significant, and then we recurse to any child nodes.
*/
- APP_JUMB(node->type);
+ JUMBLE_FIELD(type);
- switch (nodeTag(node))
+ switch (nodeTag(expr))
{
- case T_Var:
- {
- Var *var = (Var *) node;
+#include "queryjumblefuncs.switch.c"
- APP_JUMB(var->varno);
- APP_JUMB(var->varattno);
- APP_JUMB(var->varlevelsup);
-
- /*
- * We can omit varnullingrels, because it's fully determined
- * by varno/varlevelsup plus the Var's query location.
- */
- }
+ case T_List:
+ case T_IntList:
+ case T_OidList:
+ case T_XidList:
+ _jumbleList(jstate, expr);
break;
- case T_Const:
- {
- Const *c = (Const *) node;
- /* We jumble only the constant's type, not its value */
- APP_JUMB(c->consttype);
- /* Also, record its parse location for query normalization */
- RecordConstLocation(jstate, c->location);
- }
+ default:
+ /* Only a warning, since we can stumble along anyway */
+ elog(WARNING, "unrecognized node type: %d",
+ (int) nodeTag(expr));
break;
+ }
+
+ /* Special cases to handle outside the automated code */
+ switch (nodeTag(expr))
+ {
case T_Param:
{
Param *p = (Param *) node;
- APP_JUMB(p->paramkind);
- APP_JUMB(p->paramid);
- APP_JUMB(p->paramtype);
- /* Also, track the highest external Param id */
+ /*
+ * Update the highest Param id seen, in order to start
+ * normalization correctly.
+ */
if (p->paramkind == PARAM_EXTERN &&
p->paramid > jstate->highest_extern_param_id)
jstate->highest_extern_param_id = p->paramid;
}
break;
- case T_Aggref:
- {
- Aggref *expr = (Aggref *) node;
-
- APP_JUMB(expr->aggfnoid);
- JumbleExpr(jstate, (Node *) expr->aggdirectargs);
- JumbleExpr(jstate, (Node *) expr->args);
- JumbleExpr(jstate, (Node *) expr->aggorder);
- JumbleExpr(jstate, (Node *) expr->aggdistinct);
- JumbleExpr(jstate, (Node *) expr->aggfilter);
- }
- break;
- case T_GroupingFunc:
- {
- GroupingFunc *grpnode = (GroupingFunc *) node;
-
- JumbleExpr(jstate, (Node *) grpnode->refs);
- APP_JUMB(grpnode->agglevelsup);
- }
- break;
- case T_WindowFunc:
- {
- WindowFunc *expr = (WindowFunc *) node;
-
- APP_JUMB(expr->winfnoid);
- APP_JUMB(expr->winref);
- JumbleExpr(jstate, (Node *) expr->args);
- JumbleExpr(jstate, (Node *) expr->aggfilter);
- }
- break;
- case T_SubscriptingRef:
- {
- SubscriptingRef *sbsref = (SubscriptingRef *) node;
-
- JumbleExpr(jstate, (Node *) sbsref->refupperindexpr);
- JumbleExpr(jstate, (Node *) sbsref->reflowerindexpr);
- JumbleExpr(jstate, (Node *) sbsref->refexpr);
- JumbleExpr(jstate, (Node *) sbsref->refassgnexpr);
- }
- break;
- case T_FuncExpr:
- {
- FuncExpr *expr = (FuncExpr *) node;
-
- APP_JUMB(expr->funcid);
- JumbleExpr(jstate, (Node *) expr->args);
- }
- break;
- case T_NamedArgExpr:
- {
- NamedArgExpr *nae = (NamedArgExpr *) node;
-
- APP_JUMB(nae->argnumber);
- JumbleExpr(jstate, (Node *) nae->arg);
- }
- break;
- case T_OpExpr:
- case T_DistinctExpr: /* struct-equivalent to OpExpr */
- case T_NullIfExpr: /* struct-equivalent to OpExpr */
- {
- OpExpr *expr = (OpExpr *) node;
-
- APP_JUMB(expr->opno);
- JumbleExpr(jstate, (Node *) expr->args);
- }
- break;
- case T_ScalarArrayOpExpr:
- {
- ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
-
- APP_JUMB(expr->opno);
- APP_JUMB(expr->useOr);
- JumbleExpr(jstate, (Node *) expr->args);
- }
- break;
- case T_BoolExpr:
- {
- BoolExpr *expr = (BoolExpr *) node;
-
- APP_JUMB(expr->boolop);
- JumbleExpr(jstate, (Node *) expr->args);
- }
- break;
- case T_SubLink:
- {
- SubLink *sublink = (SubLink *) node;
-
- APP_JUMB(sublink->subLinkType);
- APP_JUMB(sublink->subLinkId);
- JumbleExpr(jstate, (Node *) sublink->testexpr);
- JumbleQueryInternal(jstate, castNode(Query, sublink->subselect));
- }
- break;
- case T_FieldSelect:
- {
- FieldSelect *fs = (FieldSelect *) node;
-
- APP_JUMB(fs->fieldnum);
- JumbleExpr(jstate, (Node *) fs->arg);
- }
- break;
- case T_FieldStore:
- {
- FieldStore *fstore = (FieldStore *) node;
-
- JumbleExpr(jstate, (Node *) fstore->arg);
- JumbleExpr(jstate, (Node *) fstore->newvals);
- }
- break;
- case T_RelabelType:
- {
- RelabelType *rt = (RelabelType *) node;
-
- APP_JUMB(rt->resulttype);
- JumbleExpr(jstate, (Node *) rt->arg);
- }
- break;
- case T_CoerceViaIO:
- {
- CoerceViaIO *cio = (CoerceViaIO *) node;
-
- APP_JUMB(cio->resulttype);
- JumbleExpr(jstate, (Node *) cio->arg);
- }
- break;
- case T_ArrayCoerceExpr:
- {
- ArrayCoerceExpr *acexpr = (ArrayCoerceExpr *) node;
-
- APP_JUMB(acexpr->resulttype);
- JumbleExpr(jstate, (Node *) acexpr->arg);
- JumbleExpr(jstate, (Node *) acexpr->elemexpr);
- }
- break;
- case T_ConvertRowtypeExpr:
- {
- ConvertRowtypeExpr *crexpr = (ConvertRowtypeExpr *) node;
-
- APP_JUMB(crexpr->resulttype);
- JumbleExpr(jstate, (Node *) crexpr->arg);
- }
- break;
- case T_CollateExpr:
- {
- CollateExpr *ce = (CollateExpr *) node;
-
- APP_JUMB(ce->collOid);
- JumbleExpr(jstate, (Node *) ce->arg);
- }
- break;
- case T_CaseExpr:
- {
- CaseExpr *caseexpr = (CaseExpr *) node;
-
- JumbleExpr(jstate, (Node *) caseexpr->arg);
- foreach(temp, caseexpr->args)
- {
- CaseWhen *when = lfirst_node(CaseWhen, temp);
-
- JumbleExpr(jstate, (Node *) when->expr);
- JumbleExpr(jstate, (Node *) when->result);
- }
- JumbleExpr(jstate, (Node *) caseexpr->defresult);
- }
- break;
- case T_CaseTestExpr:
- {
- CaseTestExpr *ct = (CaseTestExpr *) node;
-
- APP_JUMB(ct->typeId);
- }
- break;
- case T_ArrayExpr:
- JumbleExpr(jstate, (Node *) ((ArrayExpr *) node)->elements);
- break;
- case T_RowExpr:
- JumbleExpr(jstate, (Node *) ((RowExpr *) node)->args);
- break;
- case T_RowCompareExpr:
- {
- RowCompareExpr *rcexpr = (RowCompareExpr *) node;
-
- APP_JUMB(rcexpr->rctype);
- JumbleExpr(jstate, (Node *) rcexpr->largs);
- JumbleExpr(jstate, (Node *) rcexpr->rargs);
- }
- break;
- case T_CoalesceExpr:
- JumbleExpr(jstate, (Node *) ((CoalesceExpr *) node)->args);
- break;
- case T_MinMaxExpr:
- {
- MinMaxExpr *mmexpr = (MinMaxExpr *) node;
-
- APP_JUMB(mmexpr->op);
- JumbleExpr(jstate, (Node *) mmexpr->args);
- }
- break;
- case T_XmlExpr:
- {
- XmlExpr *xexpr = (XmlExpr *) node;
-
- APP_JUMB(xexpr->op);
- JumbleExpr(jstate, (Node *) xexpr->named_args);
- JumbleExpr(jstate, (Node *) xexpr->args);
- }
- break;
- case T_NullTest:
- {
- NullTest *nt = (NullTest *) node;
-
- APP_JUMB(nt->nulltesttype);
- JumbleExpr(jstate, (Node *) nt->arg);
- }
- break;
- case T_BooleanTest:
- {
- BooleanTest *bt = (BooleanTest *) node;
-
- APP_JUMB(bt->booltesttype);
- JumbleExpr(jstate, (Node *) bt->arg);
- }
- break;
- case T_CoerceToDomain:
- {
- CoerceToDomain *cd = (CoerceToDomain *) node;
-
- APP_JUMB(cd->resulttype);
- JumbleExpr(jstate, (Node *) cd->arg);
- }
- break;
- case T_CoerceToDomainValue:
- {
- CoerceToDomainValue *cdv = (CoerceToDomainValue *) node;
-
- APP_JUMB(cdv->typeId);
- }
- break;
- case T_SetToDefault:
- {
- SetToDefault *sd = (SetToDefault *) node;
-
- APP_JUMB(sd->typeId);
- }
- break;
- case T_CurrentOfExpr:
- {
- CurrentOfExpr *ce = (CurrentOfExpr *) node;
-
- APP_JUMB(ce->cvarno);
- if (ce->cursor_name)
- APP_JUMB_STRING(ce->cursor_name);
- APP_JUMB(ce->cursor_param);
- }
+ default:
break;
- case T_NextValueExpr:
- {
- NextValueExpr *nve = (NextValueExpr *) node;
+ }
+}
- APP_JUMB(nve->seqid);
- APP_JUMB(nve->typeId);
- }
- break;
- case T_InferenceElem:
- {
- InferenceElem *ie = (InferenceElem *) node;
+static void
+_jumbleList(JumbleState *jstate, Node *node)
+{
+ List *expr = (List *) node;
+ ListCell *l;
- APP_JUMB(ie->infercollid);
- APP_JUMB(ie->inferopclass);
- JumbleExpr(jstate, ie->expr);
- }
+ switch (expr->type)
+ {
+ case T_List:
+ foreach(l, expr)
+ _jumbleNode(jstate, lfirst(l));
break;
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *) node;
-
- APP_JUMB(tle->resno);
- APP_JUMB(tle->ressortgroupref);
- JumbleExpr(jstate, (Node *) tle->expr);
- }
+ case T_IntList:
+ foreach(l, expr)
+ JUMBLE_FIELD_SINGLE(lfirst_int(l));
break;
- case T_RangeTblRef:
- {
- RangeTblRef *rtr = (RangeTblRef *) node;
-
- APP_JUMB(rtr->rtindex);
- }
+ case T_OidList:
+ foreach(l, expr)
+ JUMBLE_FIELD_SINGLE(lfirst_oid(l));
break;
- case T_JoinExpr:
- {
- JoinExpr *join = (JoinExpr *) node;
-
- APP_JUMB(join->jointype);
- APP_JUMB(join->isNatural);
- APP_JUMB(join->rtindex);
- JumbleExpr(jstate, join->larg);
- JumbleExpr(jstate, join->rarg);
- JumbleExpr(jstate, join->quals);
- }
+ case T_XidList:
+ foreach(l, expr)
+ JUMBLE_FIELD_SINGLE(lfirst_xid(l));
break;
- case T_FromExpr:
- {
- FromExpr *from = (FromExpr *) node;
+ default:
+ elog(ERROR, "unrecognized list node type: %d",
+ (int) expr->type);
+ return;
+ }
+}
- JumbleExpr(jstate, (Node *) from->fromlist);
- JumbleExpr(jstate, from->quals);
- }
- break;
- case T_OnConflictExpr:
- {
- OnConflictExpr *conf = (OnConflictExpr *) node;
-
- APP_JUMB(conf->action);
- JumbleExpr(jstate, (Node *) conf->arbiterElems);
- JumbleExpr(jstate, conf->arbiterWhere);
- JumbleExpr(jstate, (Node *) conf->onConflictSet);
- JumbleExpr(jstate, conf->onConflictWhere);
- APP_JUMB(conf->constraint);
- APP_JUMB(conf->exclRelIndex);
- JumbleExpr(jstate, (Node *) conf->exclRelTlist);
- }
- break;
- case T_MergeAction:
- {
- MergeAction *mergeaction = (MergeAction *) node;
+static void
+_jumbleRangeTblEntry(JumbleState *jstate, Node *node)
+{
+ RangeTblEntry *expr = (RangeTblEntry *) node;
- APP_JUMB(mergeaction->matched);
- APP_JUMB(mergeaction->commandType);
- JumbleExpr(jstate, mergeaction->qual);
- JumbleExpr(jstate, (Node *) mergeaction->targetList);
- }
+ JUMBLE_FIELD(rtekind);
+ switch (expr->rtekind)
+ {
+ case RTE_RELATION:
+ JUMBLE_FIELD(relid);
+ JUMBLE_NODE(tablesample);
+ JUMBLE_FIELD(inh);
break;
- case T_List:
- foreach(temp, (List *) node)
- {
- JumbleExpr(jstate, (Node *) lfirst(temp));
- }
+ case RTE_SUBQUERY:
+ JUMBLE_NODE(subquery);
break;
- case T_IntList:
- foreach(temp, (List *) node)
- {
- APP_JUMB(lfirst_int(temp));
- }
+ case RTE_JOIN:
+ JUMBLE_FIELD(jointype);
break;
- case T_SortGroupClause:
- {
- SortGroupClause *sgc = (SortGroupClause *) node;
-
- APP_JUMB(sgc->tleSortGroupRef);
- APP_JUMB(sgc->eqop);
- APP_JUMB(sgc->sortop);
- APP_JUMB(sgc->nulls_first);
- }
+ case RTE_FUNCTION:
+ JUMBLE_NODE(functions);
break;
- case T_GroupingSet:
- {
- GroupingSet *gsnode = (GroupingSet *) node;
-
- JumbleExpr(jstate, (Node *) gsnode->content);
- }
+ case RTE_TABLEFUNC:
+ JUMBLE_NODE(tablefunc);
break;
- case T_WindowClause:
- {
- WindowClause *wc = (WindowClause *) node;
-
- APP_JUMB(wc->winref);
- APP_JUMB(wc->frameOptions);
- JumbleExpr(jstate, (Node *) wc->partitionClause);
- JumbleExpr(jstate, (Node *) wc->orderClause);
- JumbleExpr(jstate, wc->startOffset);
- JumbleExpr(jstate, wc->endOffset);
- }
+ case RTE_VALUES:
+ JUMBLE_NODE(values_lists);
break;
- case T_CommonTableExpr:
- {
- CommonTableExpr *cte = (CommonTableExpr *) node;
+ case RTE_CTE:
- /* we store the string name because RTE_CTE RTEs need it */
- APP_JUMB_STRING(cte->ctename);
- APP_JUMB(cte->ctematerialized);
- JumbleQueryInternal(jstate, castNode(Query, cte->ctequery));
- }
+ /*
+ * Depending on the CTE name here isn't ideal, but it's the only
+ * info we have to identify the referenced WITH item.
+ */
+ JUMBLE_STRING(ctename);
+ JUMBLE_FIELD(ctelevelsup);
break;
- case T_SetOperationStmt:
- {
- SetOperationStmt *setop = (SetOperationStmt *) node;
-
- APP_JUMB(setop->op);
- APP_JUMB(setop->all);
- JumbleExpr(jstate, setop->larg);
- JumbleExpr(jstate, setop->rarg);
- }
+ case RTE_NAMEDTUPLESTORE:
+ JUMBLE_STRING(enrname);
break;
- case T_RangeTblFunction:
- {
- RangeTblFunction *rtfunc = (RangeTblFunction *) node;
-
- JumbleExpr(jstate, rtfunc->funcexpr);
- }
- break;
- case T_TableFunc:
- {
- TableFunc *tablefunc = (TableFunc *) node;
-
- JumbleExpr(jstate, tablefunc->docexpr);
- JumbleExpr(jstate, tablefunc->rowexpr);
- JumbleExpr(jstate, (Node *) tablefunc->colexprs);
- }
- break;
- case T_TableSampleClause:
- {
- TableSampleClause *tsc = (TableSampleClause *) node;
-
- APP_JUMB(tsc->tsmhandler);
- JumbleExpr(jstate, (Node *) tsc->args);
- JumbleExpr(jstate, (Node *) tsc->repeatable);
- }
+ case RTE_RESULT:
break;
default:
- /* Only a warning, since we can stumble along anyway */
- elog(WARNING, "unrecognized node type: %d",
- (int) nodeTag(node));
+ elog(ERROR, "unrecognized RTE kind: %d", (int) expr->rtekind);
break;
}
}
-
-/*
- * Record location of constant within query string of query tree
- * that is currently being walked.
- */
-static void
-RecordConstLocation(JumbleState *jstate, int location)
-{
- /* -1 indicates unknown or undefined location */
- if (location >= 0)
- {
- /* enlarge array if needed */
- if (jstate->clocations_count >= jstate->clocations_buf_size)
- {
- jstate->clocations_buf_size *= 2;
- jstate->clocations = (LocationLen *)
- repalloc(jstate->clocations,
- jstate->clocations_buf_size *
- sizeof(LocationLen));
- }
- jstate->clocations[jstate->clocations_count].location = location;
- /* initialize lengths to -1 to simplify third-party module usage */
- jstate->clocations[jstate->clocations_count].length = -1;
- jstate->clocations_count++;
- }
-}
typedef struct Bitmapset
{
- pg_node_attr(custom_copy_equal, special_read_write)
+ pg_node_attr(custom_copy_equal, special_read_write, no_query_jumble)
NodeTag type;
int nwords; /* number of words in array */
* - custom_read_write: Has custom implementations in outfuncs.c and
* readfuncs.c.
*
+ * - custom_query_jumble: Has custom implementation in queryjumblefuncs.c.
+ *
* - no_copy: Does not support copyObject() at all.
*
* - no_equal: Does not support equal() at all.
*
* - no_copy_equal: Shorthand for both no_copy and no_equal.
*
+ * - no_query_jumble: Does not support JumbleQuery() at all.
+ *
* - no_read: Does not support nodeRead() at all.
*
- * - nodetag_only: Does not support copyObject(), equal(), outNode(),
- * or nodeRead().
+ * - nodetag_only: Does not support copyObject(), equal(), jumbleQuery()
+ * outNode() or nodeRead().
*
* - special_read_write: Has special treatment in outNode() and nodeRead().
*
* - equal_ignore_if_zero: Ignore the field for equality if it is zero.
* (Otherwise, compare normally.)
*
+ * - query_jumble_ignore: Ignore the field for the query jumbling. Note
+ * that typmod and collation information are usually irrelevant for the
+ * query jumbling.
+ *
+ * - query_jumble_location: Mark the field as a location to track. This is
+ * only allowed for integer fields that include "location" in their name.
+ *
* - read_as(VALUE): In nodeRead(), replace the field's value with VALUE.
*
* - read_write_ignore: Ignore the field for read/write. This is only allowed
*
* Planning converts a Query tree into a Plan tree headed by a PlannedStmt
* node --- the Query structure is not used by the executor.
+ *
+ * All the fields ignored for the query jumbling are not semantically
+ * significant (such as alias names), as is ignored anything that can
+ * be deduced from child nodes (else we'd just be double-hashing that
+ * piece of information).
*/
typedef struct Query
{
CmdType commandType; /* select|insert|update|delete|merge|utility */
/* where did I come from? */
- QuerySource querySource;
+ QuerySource querySource pg_node_attr(query_jumble_ignore);
/*
* query identifier (can be set by plugins); ignored for equal, as it
- * might not be set; also not stored
+ * might not be set; also not stored. This is the result of the query
+ * jumble, hence ignored.
*/
- uint64 queryId pg_node_attr(equal_ignore, read_write_ignore, read_as(0));
+ uint64 queryId pg_node_attr(equal_ignore, query_jumble_ignore, read_write_ignore, read_as(0));
/* do I set the command result tag? */
- bool canSetTag;
+ bool canSetTag pg_node_attr(query_jumble_ignore);
Node *utilityStmt; /* non-null if commandType == CMD_UTILITY */
/*
* rtable index of target relation for INSERT/UPDATE/DELETE/MERGE; 0 for
- * SELECT.
+ * SELECT. This is ignored in the query jumble as unrelated to the
+ * compilation of the query ID.
*/
- int resultRelation;
+ int resultRelation pg_node_attr(query_jumble_ignore);
/* has aggregates in tlist or havingQual */
- bool hasAggs;
+ bool hasAggs pg_node_attr(query_jumble_ignore);
/* has window functions in tlist */
- bool hasWindowFuncs;
+ bool hasWindowFuncs pg_node_attr(query_jumble_ignore);
/* has set-returning functions in tlist */
- bool hasTargetSRFs;
+ bool hasTargetSRFs pg_node_attr(query_jumble_ignore);
/* has subquery SubLink */
- bool hasSubLinks;
+ bool hasSubLinks pg_node_attr(query_jumble_ignore);
/* distinctClause is from DISTINCT ON */
- bool hasDistinctOn;
+ bool hasDistinctOn pg_node_attr(query_jumble_ignore);
/* WITH RECURSIVE was specified */
- bool hasRecursive;
+ bool hasRecursive pg_node_attr(query_jumble_ignore);
/* has INSERT/UPDATE/DELETE in WITH */
- bool hasModifyingCTE;
+ bool hasModifyingCTE pg_node_attr(query_jumble_ignore);
/* FOR [KEY] UPDATE/SHARE was specified */
- bool hasForUpdate;
+ bool hasForUpdate pg_node_attr(query_jumble_ignore);
/* rewriter has applied some RLS policy */
- bool hasRowSecurity;
+ bool hasRowSecurity pg_node_attr(query_jumble_ignore);
/* is a RETURN statement */
- bool isReturn;
+ bool isReturn pg_node_attr(query_jumble_ignore);
List *cteList; /* WITH list (of CommonTableExpr's) */
* list of RTEPermissionInfo nodes for the rtable entries having
* perminfoindex > 0
*/
- List *rteperminfos;
+ List *rteperminfos pg_node_attr(query_jumble_ignore);
FromExpr *jointree; /* table join tree (FROM and WHERE clauses);
* also USING clause for MERGE */
List *mergeActionList; /* list of actions for MERGE (only) */
/* whether to use outer join */
- bool mergeUseOuterJoin;
+ bool mergeUseOuterJoin pg_node_attr(query_jumble_ignore);
List *targetList; /* target list (of TargetEntry) */
/* OVERRIDING clause */
- OverridingKind override;
+ OverridingKind override pg_node_attr(query_jumble_ignore);
OnConflictExpr *onConflict; /* ON CONFLICT DO [NOTHING | UPDATE] */
* A list of pg_constraint OIDs that the query depends on to be
* semantically valid
*/
- List *constraintDeps;
+ List *constraintDeps pg_node_attr(query_jumble_ignore);
/* a list of WithCheckOption's (added during rewrite) */
- List *withCheckOptions;
+ List *withCheckOptions pg_node_attr(query_jumble_ignore);
/*
* The following two fields identify the portion of the source text string
/* start location, or -1 if unknown */
int stmt_location;
/* length in bytes; 0 means "rest of string" */
- int stmt_len;
+ int stmt_len pg_node_attr(query_jumble_ignore);
} Query;
typedef struct RangeTblEntry
{
- pg_node_attr(custom_read_write)
+ pg_node_attr(custom_read_write, custom_query_jumble)
NodeTag type;
* time. We do however remember how many columns we thought the type had
* (including dropped columns!), so that we can successfully ignore any
* columns added after the query was parsed.
+ *
+ * The query jumbling only needs to track the function expression.
*/
typedef struct RangeTblFunction
{
Node *funcexpr; /* expression tree for func call */
/* number of columns it contributes to RTE */
- int funccolcount;
+ int funccolcount pg_node_attr(query_jumble_ignore);
/* These fields record the contents of a column definition list, if any: */
/* column names (list of String) */
- List *funccolnames;
+ List *funccolnames pg_node_attr(query_jumble_ignore);
/* OID list of column type OIDs */
- List *funccoltypes;
+ List *funccoltypes pg_node_attr(query_jumble_ignore);
/* integer list of column typmods */
- List *funccoltypmods;
+ List *funccoltypmods pg_node_attr(query_jumble_ignore);
/* OID list of column collation OIDs */
- List *funccolcollations;
+ List *funccolcollations pg_node_attr(query_jumble_ignore);
/* This is set during planning for use by the executor: */
/* PARAM_EXEC Param IDs affecting this func */
- Bitmapset *funcparams;
+ Bitmapset *funcparams pg_node_attr(query_jumble_ignore);
} RangeTblFunction;
/*
Oid sortop; /* the ordering operator ('<' op), or 0 */
bool nulls_first; /* do NULLs come before normal values? */
/* can eqop be implemented by hashing? */
- bool hashable;
+ bool hashable pg_node_attr(query_jumble_ignore);
} SortGroupClause;
/*
typedef struct GroupingSet
{
NodeTag type;
- GroupingSetKind kind;
+ GroupingSetKind kind pg_node_attr(query_jumble_ignore);
List *content;
int location;
} GroupingSet;
* When refname isn't null, the partitionClause is always copied from there;
* the orderClause might or might not be copied (see copiedOrder); the framing
* options are never copied, per spec.
+ *
+ * The information relevant for the query jumbling is the partition clause
+ * type and its bounds.
*/
typedef struct WindowClause
{
NodeTag type;
/* window name (NULL in an OVER clause) */
- char *name;
+ char *name pg_node_attr(query_jumble_ignore);
/* referenced window name, if any */
- char *refname;
+ char *refname pg_node_attr(query_jumble_ignore);
List *partitionClause; /* PARTITION BY list */
/* ORDER BY list */
List *orderClause;
Node *startOffset; /* expression for starting bound, if any */
Node *endOffset; /* expression for ending bound, if any */
/* qual to help short-circuit execution */
- List *runCondition;
+ List *runCondition pg_node_attr(query_jumble_ignore);
/* in_range function for startOffset */
- Oid startInRangeFunc;
+ Oid startInRangeFunc pg_node_attr(query_jumble_ignore);
/* in_range function for endOffset */
- Oid endInRangeFunc;
+ Oid endInRangeFunc pg_node_attr(query_jumble_ignore);
/* collation for in_range tests */
- Oid inRangeColl;
+ Oid inRangeColl pg_node_attr(query_jumble_ignore);
/* use ASC sort order for in_range tests? */
- bool inRangeAsc;
+ bool inRangeAsc pg_node_attr(query_jumble_ignore);
/* nulls sort first for in_range tests? */
- bool inRangeNullsFirst;
+ bool inRangeNullsFirst pg_node_attr(query_jumble_ignore);
Index winref; /* ID referenced by window functions */
/* did we copy orderClause from refname? */
- bool copiedOrder;
+ bool copiedOrder pg_node_attr(query_jumble_ignore);
} WindowClause;
/*
typedef struct CommonTableExpr
{
NodeTag type;
- char *ctename; /* query name (never qualified) */
- List *aliascolnames; /* optional list of column names */
+
+ /*
+ * Query name (never qualified). The string name is included in the query
+ * jumbling because RTE_CTE RTEs need it.
+ */
+ char *ctename;
+ /* optional list of column names */
+ List *aliascolnames pg_node_attr(query_jumble_ignore);
CTEMaterialize ctematerialized; /* is this an optimization fence? */
/* SelectStmt/InsertStmt/etc before parse analysis, Query afterwards: */
Node *ctequery; /* the CTE's subquery */
- CTESearchClause *search_clause;
- CTECycleClause *cycle_clause;
+ CTESearchClause *search_clause pg_node_attr(query_jumble_ignore);
+ CTECycleClause *cycle_clause pg_node_attr(query_jumble_ignore);
int location; /* token location, or -1 if unknown */
/* These fields are set during parse analysis: */
/* is this CTE actually recursive? */
- bool cterecursive;
+ bool cterecursive pg_node_attr(query_jumble_ignore);
/*
* Number of RTEs referencing this CTE (excluding internal
- * self-references)
+ * self-references), irrelevant for query jumbling.
*/
- int cterefcount;
+ int cterefcount pg_node_attr(query_jumble_ignore);
/* list of output column names */
- List *ctecolnames;
+ List *ctecolnames pg_node_attr(query_jumble_ignore);
/* OID list of output column type OIDs */
- List *ctecoltypes;
+ List *ctecoltypes pg_node_attr(query_jumble_ignore);
/* integer list of output column typmods */
- List *ctecoltypmods;
+ List *ctecoltypmods pg_node_attr(query_jumble_ignore);
/* OID list of column collation OIDs */
- List *ctecolcollations;
+ List *ctecolcollations pg_node_attr(query_jumble_ignore);
} CommonTableExpr;
/* Convenience macro to get the output tlist of a CTE's query */
bool matched; /* true=MATCHED, false=NOT MATCHED */
CmdType commandType; /* INSERT/UPDATE/DELETE/DO NOTHING */
/* OVERRIDING clause */
- OverridingKind override;
+ OverridingKind override pg_node_attr(query_jumble_ignore);
Node *qual; /* transformed WHEN conditions */
List *targetList; /* the target list (of TargetEntry) */
/* target attribute numbers of an UPDATE */
- List *updateColnos;
+ List *updateColnos pg_node_attr(query_jumble_ignore);
} MergeAction;
/*
Node *rarg; /* right child */
/* Eventually add fields for CORRESPONDING spec here */
- /* Fields derived during parse analysis: */
+ /* Fields derived during parse analysis (irrelevant for query jumbling): */
/* OID list of output column type OIDs */
- List *colTypes;
+ List *colTypes pg_node_attr(query_jumble_ignore);
/* integer list of output column typmods */
- List *colTypmods;
+ List *colTypmods pg_node_attr(query_jumble_ignore);
/* OID list of output column collation OIDs */
- List *colCollations;
+ List *colCollations pg_node_attr(query_jumble_ignore);
/* a list of SortGroupClause's */
- List *groupClauses;
+ List *groupClauses pg_node_attr(query_jumble_ignore);
/* groupClauses is NIL if UNION ALL, but must be set otherwise */
} SetOperationStmt;
{
NodeTag type;
/* list of namespace URI expressions */
- List *ns_uris;
+ List *ns_uris pg_node_attr(query_jumble_ignore);
/* list of namespace names or NULL */
- List *ns_names;
+ List *ns_names pg_node_attr(query_jumble_ignore);
/* input document expression */
Node *docexpr;
/* row filter expression */
Node *rowexpr;
/* column names (list of String) */
- List *colnames;
+ List *colnames pg_node_attr(query_jumble_ignore);
/* OID list of column type OIDs */
- List *coltypes;
+ List *coltypes pg_node_attr(query_jumble_ignore);
/* integer list of column typmods */
- List *coltypmods;
+ List *coltypmods pg_node_attr(query_jumble_ignore);
/* OID list of column collation OIDs */
- List *colcollations;
+ List *colcollations pg_node_attr(query_jumble_ignore);
/* list of column filter expressions */
List *colexprs;
/* list of column default expressions */
- List *coldefexprs;
+ List *coldefexprs pg_node_attr(query_jumble_ignore);
/* nullability flag for each output column */
- Bitmapset *notnulls;
+ Bitmapset *notnulls pg_node_attr(query_jumble_ignore);
/* counts from 0; -1 if none specified */
- int ordinalitycol;
+ int ordinalitycol pg_node_attr(query_jumble_ignore);
/* token location, or -1 if unknown */
int location;
} TableFunc;
AttrNumber varattno;
/* pg_type OID for the type of this var */
- Oid vartype;
+ Oid vartype pg_node_attr(query_jumble_ignore);
/* pg_attribute typmod value */
- int32 vartypmod;
+ int32 vartypmod pg_node_attr(query_jumble_ignore);
/* OID of collation, or InvalidOid if none */
- Oid varcollid;
- /* RT indexes of outer joins that can replace the Var's value with null */
- Bitmapset *varnullingrels;
+ Oid varcollid pg_node_attr(query_jumble_ignore);
+
+ /*
+ * RT indexes of outer joins that can replace the Var's value with null.
+ * We can omit varnullingrels in the query jumble, because it's fully
+ * determined by varno/varlevelsup plus the Var's query location.
+ */
+ Bitmapset *varnullingrels pg_node_attr(query_jumble_ignore);
/*
* for subquery variables referencing outer relations; 0 in a normal var,
* their varno/varattno match.
*/
/* syntactic relation index (0 if unknown) */
- Index varnosyn pg_node_attr(equal_ignore);
+ Index varnosyn pg_node_attr(equal_ignore, query_jumble_ignore);
/* syntactic attribute number */
- AttrNumber varattnosyn pg_node_attr(equal_ignore);
+ AttrNumber varattnosyn pg_node_attr(equal_ignore, query_jumble_ignore);
/* token location, or -1 if unknown */
int location;
* must be in non-extended form (4-byte header, no compression or external
* references). This ensures that the Const node is self-contained and makes
* it more likely that equal() will see logically identical values as equal.
+ *
+ * Only the constant type OID is relevant for the query jumbling.
*/
typedef struct Const
{
/* pg_type OID of the constant's datatype */
Oid consttype;
/* typmod value, if any */
- int32 consttypmod;
+ int32 consttypmod pg_node_attr(query_jumble_ignore);
/* OID of collation, or InvalidOid if none */
- Oid constcollid;
+ Oid constcollid pg_node_attr(query_jumble_ignore);
/* typlen of the constant's datatype */
- int constlen;
+ int constlen pg_node_attr(query_jumble_ignore);
/* the constant's value */
- Datum constvalue;
+ Datum constvalue pg_node_attr(query_jumble_ignore);
/* whether the constant is null (if true, constvalue is undefined) */
- bool constisnull;
+ bool constisnull pg_node_attr(query_jumble_ignore);
/*
* Whether this datatype is passed by value. If true, then all the
* information is stored in the Datum. If false, then the Datum contains
* a pointer to the information.
*/
- bool constbyval;
- /* token location, or -1 if unknown */
- int location;
+ bool constbyval pg_node_attr(query_jumble_ignore);
+
+ /*
+ * token location, or -1 if unknown. All constants are tracked as
+ * locations in query jumbling, to be marked as parameters.
+ */
+ int location pg_node_attr(query_jumble_location);
} Const;
/*
int paramid; /* numeric ID for parameter */
Oid paramtype; /* pg_type OID of parameter's datatype */
/* typmod value, if known */
- int32 paramtypmod;
+ int32 paramtypmod pg_node_attr(query_jumble_ignore);
/* OID of collation, or InvalidOid if none */
- Oid paramcollid;
+ Oid paramcollid pg_node_attr(query_jumble_ignore);
/* token location, or -1 if unknown */
int location;
} Param;
* and can share the result. Aggregates with same 'transno' but different
* 'aggno' can share the same transition state, only the final function needs
* to be called separately.
+ *
+ * Information related to collations, transition types and internal states
+ * are irrelevant for the query jumbling.
*/
typedef struct Aggref
{
Oid aggfnoid;
/* type Oid of result of the aggregate */
- Oid aggtype;
+ Oid aggtype pg_node_attr(query_jumble_ignore);
/* OID of collation of result */
- Oid aggcollid;
+ Oid aggcollid pg_node_attr(query_jumble_ignore);
/* OID of collation that function should use */
- Oid inputcollid;
+ Oid inputcollid pg_node_attr(query_jumble_ignore);
/*
* type Oid of aggregate's transition value; ignored for equal since it
* might not be set yet
*/
- Oid aggtranstype pg_node_attr(equal_ignore);
+ Oid aggtranstype pg_node_attr(equal_ignore, query_jumble_ignore);
/* type Oids of direct and aggregated args */
- List *aggargtypes;
+ List *aggargtypes pg_node_attr(query_jumble_ignore);
/* direct arguments, if an ordered-set agg */
List *aggdirectargs;
Expr *aggfilter;
/* true if argument list was really '*' */
- bool aggstar;
+ bool aggstar pg_node_attr(query_jumble_ignore);
/*
* true if variadic arguments have been combined into an array last
* argument
*/
- bool aggvariadic;
+ bool aggvariadic pg_node_attr(query_jumble_ignore);
/* aggregate kind (see pg_aggregate.h) */
- char aggkind;
+ char aggkind pg_node_attr(query_jumble_ignore);
/* aggregate input already sorted */
- bool aggpresorted pg_node_attr(equal_ignore);
+ bool aggpresorted pg_node_attr(equal_ignore, query_jumble_ignore);
/* > 0 if agg belongs to outer query */
- Index agglevelsup;
+ Index agglevelsup pg_node_attr(query_jumble_ignore);
/* expected agg-splitting mode of parent Agg */
- AggSplit aggsplit;
+ AggSplit aggsplit pg_node_attr(query_jumble_ignore);
/* unique ID within the Agg node */
- int aggno;
+ int aggno pg_node_attr(query_jumble_ignore);
/* unique ID of transition state in the Agg */
- int aggtransno;
+ int aggtransno pg_node_attr(query_jumble_ignore);
/* token location, or -1 if unknown */
int location;
*
* In raw parse output we have only the args list; parse analysis fills in the
* refs list, and the planner fills in the cols list.
+ *
+ * All the fields used as information for an internal state are irrelevant
+ * for the query jumbling.
*/
typedef struct GroupingFunc
{
Expr xpr;
/* arguments, not evaluated but kept for benefit of EXPLAIN etc. */
- List *args;
+ List *args pg_node_attr(query_jumble_ignore);
/* ressortgrouprefs of arguments */
List *refs pg_node_attr(equal_ignore);
/* actual column positions set by planner */
- List *cols pg_node_attr(equal_ignore);
+ List *cols pg_node_attr(equal_ignore, query_jumble_ignore);
/* same as Aggref.agglevelsup */
Index agglevelsup;
/*
* WindowFunc
+ *
+ * Collation information is irrelevant for the query jumbling, as is the
+ * internal state information of the node like "winstar" and "winagg".
*/
typedef struct WindowFunc
{
/* pg_proc Oid of the function */
Oid winfnoid;
/* type Oid of result of the window function */
- Oid wintype;
+ Oid wintype pg_node_attr(query_jumble_ignore);
/* OID of collation of result */
- Oid wincollid;
+ Oid wincollid pg_node_attr(query_jumble_ignore);
/* OID of collation that function should use */
- Oid inputcollid;
+ Oid inputcollid pg_node_attr(query_jumble_ignore);
/* arguments to the window function */
List *args;
/* FILTER expression, if any */
/* index of associated WindowClause */
Index winref;
/* true if argument list was really '*' */
- bool winstar;
+ bool winstar pg_node_attr(query_jumble_ignore);
/* is function a simple aggregate? */
- bool winagg;
+ bool winagg pg_node_attr(query_jumble_ignore);
/* token location, or -1 if unknown */
int location;
} WindowFunc;
* subscripting logic. Likewise, reftypmod and refcollid will match the
* container's properties in a store, but could be different in a fetch.
*
+ * Any internal state data is ignored for the query jumbling.
+ *
* Note: for the cases where a container is returned, if refexpr yields a R/W
* expanded container, then the implementation is allowed to modify that
* object in-place and return the same object.
{
Expr xpr;
/* type of the container proper */
- Oid refcontainertype;
+ Oid refcontainertype pg_node_attr(query_jumble_ignore);
/* the container type's pg_type.typelem */
- Oid refelemtype;
+ Oid refelemtype pg_node_attr(query_jumble_ignore);
/* type of the SubscriptingRef's result */
- Oid refrestype;
+ Oid refrestype pg_node_attr(query_jumble_ignore);
/* typmod of the result */
- int32 reftypmod;
+ int32 reftypmod pg_node_attr(query_jumble_ignore);
/* collation of result, or InvalidOid if none */
- Oid refcollid;
+ Oid refcollid pg_node_attr(query_jumble_ignore);
/* expressions that evaluate to upper container indexes */
List *refupperindexpr;
/*
* FuncExpr - expression node for a function call
+ *
+ * Collation information is irrelevant for the query jumbling, only the
+ * arguments and the function OID matter.
*/
typedef struct FuncExpr
{
/* PG_PROC OID of the function */
Oid funcid;
/* PG_TYPE OID of result value */
- Oid funcresulttype;
+ Oid funcresulttype pg_node_attr(query_jumble_ignore);
/* true if function returns set */
- bool funcretset;
+ bool funcretset pg_node_attr(query_jumble_ignore);
/*
* true if variadic arguments have been combined into an array last
* argument
*/
- bool funcvariadic;
+ bool funcvariadic pg_node_attr(query_jumble_ignore);
/* how to display this function call */
- CoercionForm funcformat;
+ CoercionForm funcformat pg_node_attr(query_jumble_ignore);
/* OID of collation of result */
- Oid funccollid;
+ Oid funccollid pg_node_attr(query_jumble_ignore);
/* OID of collation that function should use */
- Oid inputcollid;
+ Oid inputcollid pg_node_attr(query_jumble_ignore);
/* arguments to the function */
List *args;
/* token location, or -1 if unknown */
/* the argument expression */
Expr *arg;
/* the name */
- char *name;
+ char *name pg_node_attr(query_jumble_ignore);
/* argument's number in positional notation */
int argnumber;
/* argument name location, or -1 if unknown */
* of the node. The planner makes sure it is valid before passing the node
* tree to the executor, but during parsing/planning opfuncid can be 0.
* Therefore, equal() will accept a zero value as being equal to other values.
+ *
+ * Internal state information and collation data is irrelevant for the query
+ * jumbling.
*/
typedef struct OpExpr
{
Oid opno;
/* PG_PROC OID of underlying function */
- Oid opfuncid pg_node_attr(equal_ignore_if_zero);
+ Oid opfuncid pg_node_attr(equal_ignore_if_zero, query_jumble_ignore);
/* PG_TYPE OID of result value */
- Oid opresulttype;
+ Oid opresulttype pg_node_attr(query_jumble_ignore);
/* true if operator returns set */
- bool opretset;
+ bool opretset pg_node_attr(query_jumble_ignore);
/* OID of collation of result */
- Oid opcollid;
+ Oid opcollid pg_node_attr(query_jumble_ignore);
/* OID of collation that operator should use */
- Oid inputcollid;
+ Oid inputcollid pg_node_attr(query_jumble_ignore);
/* arguments to the operator (1 or 2) */
List *args;
* Similar to OpExpr, opfuncid, hashfuncid, and negfuncid are not necessarily
* filled in right away, so will be ignored for equality if they are not set
* yet.
+ *
+ * OID entries of the internal function types are irrelevant for the query
+ * jumbling, but the operator OID and the arguments are.
*/
typedef struct ScalarArrayOpExpr
{
Oid opno;
/* PG_PROC OID of comparison function */
- Oid opfuncid pg_node_attr(equal_ignore_if_zero);
+ Oid opfuncid pg_node_attr(equal_ignore_if_zero, query_jumble_ignore);
/* PG_PROC OID of hash func or InvalidOid */
- Oid hashfuncid pg_node_attr(equal_ignore_if_zero);
+ Oid hashfuncid pg_node_attr(equal_ignore_if_zero, query_jumble_ignore);
/* PG_PROC OID of negator of opfuncid function or InvalidOid. See above */
- Oid negfuncid pg_node_attr(equal_ignore_if_zero);
+ Oid negfuncid pg_node_attr(equal_ignore_if_zero, query_jumble_ignore);
/* true for ANY, false for ALL */
bool useOr;
/* OID of collation that operator should use */
- Oid inputcollid;
+ Oid inputcollid pg_node_attr(query_jumble_ignore);
/* the scalar and array operands */
List *args;
int subLinkId; /* ID (1..n); 0 if not MULTIEXPR */
Node *testexpr; /* outer-query test for ALL/ANY/ROWCOMPARE */
/* originally specified operator name */
- List *operName;
+ List *operName pg_node_attr(query_jumble_ignore);
/* subselect as Query* or raw parsetree */
Node *subselect;
int location; /* token location, or -1 if unknown */
Expr *arg; /* input expression */
AttrNumber fieldnum; /* attribute number of field to extract */
/* type of the field (result type of this node) */
- Oid resulttype;
+ Oid resulttype pg_node_attr(query_jumble_ignore);
/* output typmod (usually -1) */
- int32 resulttypmod;
+ int32 resulttypmod pg_node_attr(query_jumble_ignore);
/* OID of collation of the field */
- Oid resultcollid;
+ Oid resultcollid pg_node_attr(query_jumble_ignore);
} FieldSelect;
/* ----------------
Expr *arg; /* input tuple value */
List *newvals; /* new value(s) for field(s) */
/* integer list of field attnums */
- List *fieldnums;
+ List *fieldnums pg_node_attr(query_jumble_ignore);
/* type of result (same as type of arg) */
- Oid resulttype;
+ Oid resulttype pg_node_attr(query_jumble_ignore);
/* Like RowExpr, we deliberately omit a typmod and collation here */
} FieldStore;
Expr *arg; /* input expression */
Oid resulttype; /* output type of coercion expression */
/* output typmod (usually -1) */
- int32 resulttypmod;
+ int32 resulttypmod pg_node_attr(query_jumble_ignore);
/* OID of collation, or InvalidOid if none */
- Oid resultcollid;
+ Oid resultcollid pg_node_attr(query_jumble_ignore);
/* how to display this node */
- CoercionForm relabelformat;
+ CoercionForm relabelformat pg_node_attr(query_jumble_ignore);
int location; /* token location, or -1 if unknown */
} RelabelType;
Oid resulttype; /* output type of coercion */
/* output typmod is not stored, but is presumed -1 */
/* OID of collation, or InvalidOid if none */
- Oid resultcollid;
+ Oid resultcollid pg_node_attr(query_jumble_ignore);
/* how to display this node */
- CoercionForm coerceformat;
+ CoercionForm coerceformat pg_node_attr(query_jumble_ignore);
int location; /* token location, or -1 if unknown */
} CoerceViaIO;
Expr *elemexpr; /* expression representing per-element work */
Oid resulttype; /* output type of coercion (an array type) */
/* output typmod (also element typmod) */
- int32 resulttypmod;
+ int32 resulttypmod pg_node_attr(query_jumble_ignore);
/* OID of collation, or InvalidOid if none */
- Oid resultcollid;
+ Oid resultcollid pg_node_attr(query_jumble_ignore);
/* how to display this node */
- CoercionForm coerceformat;
+ CoercionForm coerceformat pg_node_attr(query_jumble_ignore);
int location; /* token location, or -1 if unknown */
} ArrayCoerceExpr;
Oid resulttype; /* output type (always a composite type) */
/* Like RowExpr, we deliberately omit a typmod and collation here */
/* how to display this node */
- CoercionForm convertformat;
+ CoercionForm convertformat pg_node_attr(query_jumble_ignore);
int location; /* token location, or -1 if unknown */
} ConvertRowtypeExpr;
{
Expr xpr;
/* type of expression result */
- Oid casetype;
+ Oid casetype pg_node_attr(query_jumble_ignore);
/* OID of collation, or InvalidOid if none */
- Oid casecollid;
+ Oid casecollid pg_node_attr(query_jumble_ignore);
Expr *arg; /* implicit equality comparison argument */
List *args; /* the arguments (list of WHEN clauses) */
Expr *defresult; /* the default result (ELSE clause) */
Expr xpr;
Oid typeId; /* type for substituted value */
/* typemod for substituted value */
- int32 typeMod;
+ int32 typeMod pg_node_attr(query_jumble_ignore);
/* collation for the substituted value */
- Oid collation;
+ Oid collation pg_node_attr(query_jumble_ignore);
} CaseTestExpr;
/*
{
Expr xpr;
/* type of expression result */
- Oid array_typeid;
+ Oid array_typeid pg_node_attr(query_jumble_ignore);
/* OID of collation, or InvalidOid if none */
- Oid array_collid;
+ Oid array_collid pg_node_attr(query_jumble_ignore);
/* common type of array elements */
- Oid element_typeid;
+ Oid element_typeid pg_node_attr(query_jumble_ignore);
/* the array elements or sub-arrays */
List *elements;
/* true if elements are sub-arrays */
- bool multidims;
+ bool multidims pg_node_attr(query_jumble_ignore);
/* token location, or -1 if unknown */
int location;
} ArrayExpr;
List *args; /* the fields */
/* RECORDOID or a composite type's ID */
- Oid row_typeid;
+ Oid row_typeid pg_node_attr(query_jumble_ignore);
/*
* row_typeid cannot be a domain over composite, only plain composite. To
*/
/* how to display this node */
- CoercionForm row_format;
+ CoercionForm row_format pg_node_attr(query_jumble_ignore);
/* list of String, or NIL */
- List *colnames;
+ List *colnames pg_node_attr(query_jumble_ignore);
int location; /* token location, or -1 if unknown */
} RowExpr;
/* LT LE GE or GT, never EQ or NE */
RowCompareType rctype;
/* OID list of pairwise comparison ops */
- List *opnos;
+ List *opnos pg_node_attr(query_jumble_ignore);
/* OID list of containing operator families */
- List *opfamilies;
+ List *opfamilies pg_node_attr(query_jumble_ignore);
/* OID list of collations for comparisons */
- List *inputcollids;
+ List *inputcollids pg_node_attr(query_jumble_ignore);
/* the left-hand input arguments */
List *largs;
/* the right-hand input arguments */
{
Expr xpr;
/* type of expression result */
- Oid coalescetype;
+ Oid coalescetype pg_node_attr(query_jumble_ignore);
/* OID of collation, or InvalidOid if none */
- Oid coalescecollid;
+ Oid coalescecollid pg_node_attr(query_jumble_ignore);
/* the arguments */
List *args;
/* token location, or -1 if unknown */
{
Expr xpr;
/* common type of arguments and result */
- Oid minmaxtype;
+ Oid minmaxtype pg_node_attr(query_jumble_ignore);
/* OID of collation of result */
- Oid minmaxcollid;
+ Oid minmaxcollid pg_node_attr(query_jumble_ignore);
/* OID of collation that function should use */
- Oid inputcollid;
+ Oid inputcollid pg_node_attr(query_jumble_ignore);
/* function to execute */
MinMaxOp op;
/* the arguments */
/* xml function ID */
XmlExprOp op;
/* name in xml(NAME foo ...) syntaxes */
- char *name;
+ char *name pg_node_attr(query_jumble_ignore);
/* non-XML expressions for xml_attributes */
List *named_args;
/* parallel list of String values */
- List *arg_names;
+ List *arg_names pg_node_attr(query_jumble_ignore);
/* list of expressions */
List *args;
/* DOCUMENT or CONTENT */
- XmlOptionType xmloption;
+ XmlOptionType xmloption pg_node_attr(query_jumble_ignore);
/* target type/typmod for XMLSERIALIZE */
- Oid type;
- int32 typmod;
+ Oid type pg_node_attr(query_jumble_ignore);
+ int32 typmod pg_node_attr(query_jumble_ignore);
/* token location, or -1 if unknown */
int location;
} XmlExpr;
Expr *arg; /* input expression */
NullTestType nulltesttype; /* IS NULL, IS NOT NULL */
/* T to perform field-by-field null checks */
- bool argisrow;
+ bool argisrow pg_node_attr(query_jumble_ignore);
int location; /* token location, or -1 if unknown */
} NullTest;
Expr *arg; /* input expression */
Oid resulttype; /* domain type ID (result type) */
/* output typmod (currently always -1) */
- int32 resulttypmod;
+ int32 resulttypmod pg_node_attr(query_jumble_ignore);
/* OID of collation, or InvalidOid if none */
- Oid resultcollid;
+ Oid resultcollid pg_node_attr(query_jumble_ignore);
/* how to display this node */
- CoercionForm coercionformat;
+ CoercionForm coercionformat pg_node_attr(query_jumble_ignore);
int location; /* token location, or -1 if unknown */
} CoerceToDomain;
/* type for substituted value */
Oid typeId;
/* typemod for substituted value */
- int32 typeMod;
+ int32 typeMod pg_node_attr(query_jumble_ignore);
/* collation for the substituted value */
- Oid collation;
+ Oid collation pg_node_attr(query_jumble_ignore);
/* token location, or -1 if unknown */
int location;
} CoerceToDomainValue;
/* type for substituted value */
Oid typeId;
/* typemod for substituted value */
- int32 typeMod;
+ int32 typeMod pg_node_attr(query_jumble_ignore);
/* collation for the substituted value */
- Oid collation;
+ Oid collation pg_node_attr(query_jumble_ignore);
/* token location, or -1 if unknown */
int location;
} SetToDefault;
/* attribute number (see notes above) */
AttrNumber resno;
/* name of the column (could be NULL) */
- char *resname;
+ char *resname pg_node_attr(query_jumble_ignore);
/* nonzero if referenced by a sort/group clause */
Index ressortgroupref;
/* OID of column's source table */
- Oid resorigtbl;
+ Oid resorigtbl pg_node_attr(query_jumble_ignore);
/* column's number in source table */
- AttrNumber resorigcol;
+ AttrNumber resorigcol pg_node_attr(query_jumble_ignore);
/* set to true to eliminate the attribute from final target list */
- bool resjunk;
+ bool resjunk pg_node_attr(query_jumble_ignore);
} TargetEntry;
Node *larg; /* left subtree */
Node *rarg; /* right subtree */
/* USING clause, if any (list of String) */
- List *usingClause;
+ List *usingClause pg_node_attr(query_jumble_ignore);
/* alias attached to USING clause, if any */
- Alias *join_using_alias;
+ Alias *join_using_alias pg_node_attr(query_jumble_ignore);
/* qualifiers on join, if any */
Node *quals;
/* user-written alias clause, if any */
- Alias *alias;
+ Alias *alias pg_node_attr(query_jumble_ignore);
/* RT index assigned for join, or 0 */
int rtindex;
} JoinExpr;