/* *ENRshidetablesofthesamename,soweneedtocheckforthemfirst. *Incontrast,CTEsdon'thidetables(forthispurpose).
*/ if (relation->schemaname == NULL &&
scanNameSpaceForENR(pstate, relation->relname))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("relation \"%s\" cannot be the target of a modifying statement",
relation->relname)));
/* Close old target; this could only happen for multi-action rules */ if (pstate->p_target_relation != NULL)
table_close(pstate->p_target_relation, NoLock);
/* Require read access to the join variables */
markVarForSelectPriv(pstate, lvar);
markVarForSelectPriv(pstate, rvar);
/* Now create the lvar = rvar join condition */
e = makeSimpleA_Expr(AEXPR_OP, "=",
(Node *) copyObject(lvar), (Node *) copyObject(rvar),
-1);
/* Prepare to combine into an AND clause, if multiple join columns */
andargs = lappend(andargs, e);
}
/* Only need an AND if there's more than one join column */ if (list_length(andargs) == 1)
result = (Node *) linitial(andargs); else
result = (Node *) makeBoolExpr(AND_EXPR, andargs, -1);
/* nodeFunctionscan.c requires SRFs to be at top level */ if (pstate->p_last_srf != last_srf &&
pstate->p_last_srf != newfexpr)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-returning functions must appear at top level of FROM"),
parser_errposition(pstate,
exprLocation(pstate->p_last_srf))));
/* nodeFunctionscan.c requires SRFs to be at top level */ if (pstate->p_last_srf != last_srf &&
pstate->p_last_srf != newfexpr)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-returning functions must appear at top level of FROM"),
parser_errposition(pstate,
exprLocation(pstate->p_last_srf))));
if (coldeflist && r->coldeflist)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple column definition lists are not allowed for the same function"),
parser_errposition(pstate,
exprLocation((Node *) r->coldeflist))));
/* *Installthetop-levelcoldeflistiftherewasone(wealreadychecked *thattherewasnoconflictingper-functioncoldeflist). * *Weonlyallowthiswhenthere'sasinglefunction(evenafterUNNEST *expansion)andnoWITHORDINALITY.Thereasonforthelatter *restrictionisthatit'snotrealclearwhethertheordinalitycolumn *shouldbeinthecoldeflist,andusersaretoolikelytomakemistakes *inonedirectionortheother.PuttingthecoldeflistinsideROWS *FROM()ismuchclearerinthiscase.
*/ if (r->coldeflist)
{ if (list_length(funcexprs) != 1)
{ if (r->is_rowsfrom)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("ROWS FROM() with multiple functions cannot have a column definition list"),
errhint("Put a separate column definition list for each function inside ROWS FROM()."),
parser_errposition(pstate,
exprLocation((Node *) r->coldeflist)))); else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("UNNEST() with multiple arguments cannot have a column definition list"),
errhint("Use separate UNNEST() calls inside ROWS FROM(), and attach a column definition list to each one."),
parser_errposition(pstate,
exprLocation((Node *) r->coldeflist))));
} if (r->ordinality)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("WITH ORDINALITY cannot be used with a column definition list"),
errhint("Put the column definition list inside ROWS FROM()."),
parser_errposition(pstate,
exprLocation((Node *) r->coldeflist))));
/* *Determinethetypeandtypmodforthenewcolumn.FORORDINALITY *columnsareINTEGERperspec;theothersareuser-specified.
*/ if (rawc->for_ordinality)
{ if (tf->ordinalitycol != -1)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("only one FOR ORDINALITY column is allowed"),
parser_errposition(pstate, rawc->location)));
if (rawc->is_not_null)
tf->notnulls = bms_add_member(tf->notnulls, colno);
/* make sure column names are unique */ for (j = 0; j < colno; j++) if (strcmp(names[j], rawc->colname) == 0)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("column name \"%s\" is not unique",
rawc->colname),
parser_errposition(pstate, rawc->location)));
names[colno] = rawc->colname;
colno++;
}
pfree(names);
/* Namespaces, if any, also need to be transformed */ if (rtf->namespaces != NIL)
{
ListCell *ns;
ListCell *lc2;
List *ns_uris = NIL;
List *ns_names = NIL; bool default_ns_seen = false;
/* Verify consistency of name list: no dupes, only one DEFAULT */ if (r->name != NULL)
{
foreach(lc2, ns_names)
{
String *ns_node = lfirst_node(String, lc2);
if (ns_node == NULL) continue; if (strcmp(strVal(ns_node), r->name) == 0)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("namespace name \"%s\" is not unique",
r->name),
parser_errposition(pstate, r->location)));
}
} else
{ if (default_ns_seen)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("only one default namespace is allowed"),
parser_errposition(pstate, r->location)));
default_ns_seen = true;
}
/* We represent DEFAULT by a null pointer */
ns_names = lappend(ns_names,
r->name ? makeString(r->name) : NULL);
}
/* we want error to complain about no-such-method, not no-such-function */ if (!OidIsValid(handlerOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablesample method %s does not exist",
NameListToString(rts->method)),
parser_errposition(pstate, rts->location)));
/* check that handler has correct return type */ if (get_func_rettype(handlerOid) != TSM_HANDLEROID)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("function %s must return type %s",
NameListToString(rts->method), "tsm_handler"),
parser_errposition(pstate, rts->location)));
/* OK, run the handler to get TsmRoutine, for argument type info */
tsm = GetTsmRoutine(handlerOid);
/* Process REPEATABLE (seed) */ if (rts->repeatable != NULL)
{
Node *arg;
if (!tsm->repeatable_across_queries)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("tablesample method %s does not support REPEATABLE",
NameListToString(rts->method)),
parser_errposition(pstate, rts->location)));
/* Recursively transform the contained relation */
rel = transformFromClauseItem(pstate, rts->relation,
top_nsitem, namespace);
rte = (*top_nsitem)->p_rte; /* We only support this on plain relations and matviews */ if (rte->rtekind != RTE_RELATION ||
(rte->relkind != RELKIND_RELATION &&
rte->relkind != RELKIND_MATVIEW &&
rte->relkind != RELKIND_PARTITIONED_TABLE))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("TABLESAMPLE clause can only be applied to tables and materialized views"),
parser_errposition(pstate, exprLocation(rts->relation))));
/* Transform TABLESAMPLE details and attach to the RTE */
rte->tablesample = transformRangeTableSample(pstate, rts); return rel;
} elseif (IsA(n, JoinExpr))
{ /* A newfangled join expression */
JoinExpr *j = (JoinExpr *) n;
ParseNamespaceItem *nsitem;
ParseNamespaceItem *l_nsitem;
ParseNamespaceItem *r_nsitem;
List *l_namespace,
*r_namespace,
*my_namespace,
*l_colnames,
*r_colnames,
*res_colnames,
*l_colnos,
*r_colnos,
*res_colvars;
ParseNamespaceColumn *l_nscolumns,
*r_nscolumns,
*res_nscolumns; int res_colindex; bool lateral_ok; int sv_namespace_length; int k;
/* this may be larger than needed, but it's not worth being exact */
res_nscolumns = (ParseNamespaceColumn *)
palloc0((list_length(l_colnames) + list_length(r_colnames)) * sizeof(ParseNamespaceColumn));
res_colindex = 0;
if (j->usingClause)
{ /* *JOIN/USING(orNATURALJOIN,astransformedabove).Transform *thelistintoanexplicitON-condition.
*/
List *ucols = j->usingClause;
List *l_usingvars = NIL;
List *r_usingvars = NIL;
ListCell *ucol;
Assert(j->quals == NULL); /* shouldn't have ON() too */
foreach(ucol, ucols)
{ char *u_colname = strVal(lfirst(ucol));
ListCell *col; int ndx; int l_index = -1; int r_index = -1;
Var *l_colvar,
*r_colvar;
if (strcmp(res_colname, u_colname) == 0)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column name \"%s\" appears more than once in USING clause",
u_colname)));
}
/* Find it in left input */
ndx = 0;
foreach(col, l_colnames)
{ char *l_colname = strVal(lfirst(col));
if (strcmp(l_colname, u_colname) == 0)
{ if (l_index >= 0)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
errmsg("common column name \"%s\" appears more than once in left table",
u_colname)));
l_index = ndx;
}
ndx++;
} if (l_index < 0)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" specified in USING clause does not exist in left table",
u_colname)));
l_colnos = lappend_int(l_colnos, l_index + 1);
/* Find it in right input */
ndx = 0;
foreach(col, r_colnames)
{ char *r_colname = strVal(lfirst(col));
if (strcmp(r_colname, u_colname) == 0)
{ if (r_index >= 0)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
errmsg("common column name \"%s\" appears more than once in right table",
u_colname)));
r_index = ndx;
}
ndx++;
} if (r_index < 0)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" specified in USING clause does not exist in right table",
u_colname)));
r_colnos = lappend_int(r_colnos, r_index + 1);
/* Build Vars to use in the generated JOIN ON clause */
l_colvar = buildVarFromNSColumn(pstate, l_nscolumns + l_index);
l_usingvars = lappend(l_usingvars, l_colvar);
r_colvar = buildVarFromNSColumn(pstate, r_nscolumns + r_index);
r_usingvars = lappend(r_usingvars, r_colvar);
switch (j->jointype)
{ case JOIN_INNER: break; case JOIN_LEFT:
markRelsAsNulledBy(pstate, j->rarg, j->rtindex); break; case JOIN_FULL:
markRelsAsNulledBy(pstate, j->larg, j->rtindex);
markRelsAsNulledBy(pstate, j->rarg, j->rtindex); break; case JOIN_RIGHT:
markRelsAsNulledBy(pstate, j->larg, j->rtindex); break; default: /* shouldn't see any other types here */
elog(ERROR, "unrecognized join type: %d",
(int) j->jointype); break;
}
/* *NowwecanconstructjoinaliasexpressionsfortheUSINGcolumns.
*/ if (j->usingClause)
{
ListCell *lc1,
*lc2;
/* Scan the colnos lists to recover info from the previous loop */
forboth(lc1, l_colnos, lc2, r_colnos)
{ int l_index = lfirst_int(lc1) - 1; int r_index = lfirst_int(lc2) - 1;
Var *l_colvar,
*r_colvar;
Node *u_colvar;
ParseNamespaceColumn *res_nscolumn;
/* Construct the join alias Var for this column */
u_colvar = buildMergedJoinVar(pstate,
j->jointype,
l_colvar,
r_colvar);
res_colvars = lappend(res_colvars, u_colvar);
/* Add remaining columns from each side to the output columns */
res_colindex +=
extractRemainingColumns(pstate,
l_nscolumns, l_colnames, &l_colnos,
&res_colnames, &res_colvars,
res_nscolumns + res_colindex);
res_colindex +=
extractRemainingColumns(pstate,
r_nscolumns, r_colnames, &r_colnos,
&res_colnames, &res_colvars,
res_nscolumns + res_colindex);
/* If join has an alias, it syntactically hides all inputs */ if (j->alias)
{ for (k = 0; k < res_colindex; k++)
{
ParseNamespaceColumn *nscol = res_nscolumns + k;
nscol->p_varnosyn = j->rtindex;
nscol->p_varattnosyn = k + 1;
}
}
/* Verify that we correctly predicted the join's RT index */
Assert(j->rtindex == nsitem->p_rtindex); /* Cross-check number of columns, too */
Assert(res_colindex == list_length(nsitem->p_names->colnames));
/* *IfthejoinhasaUSINGalias,buildaParseNamespaceItemforthat *andaddittothelistofnsitemsinthejoin'sinput.
*/ if (j->join_using_alias)
{
ParseNamespaceItem *jnsitem;
jnsitem = (ParseNamespaceItem *) palloc(sizeof(ParseNamespaceItem));
jnsitem->p_names = j->join_using_alias;
jnsitem->p_rte = nsitem->p_rte;
jnsitem->p_rtindex = nsitem->p_rtindex;
jnsitem->p_perminfo = NULL; /* no need to copy the first N columns, just use res_nscolumns */
jnsitem->p_nscolumns = res_nscolumns; /* set default visibility flags; might get changed later */
jnsitem->p_rel_visible = true;
jnsitem->p_cols_visible = true;
jnsitem->p_lateral_only = false;
jnsitem->p_lateral_ok = true;
jnsitem->p_returning_type = VAR_RETURNING_DEFAULT; /* Per SQL, we must check for alias conflicts */
checkNameSpaceConflicts(pstate, list_make1(jnsitem), my_namespace);
my_namespace = lappend(my_namespace, jnsitem);
}
qual = coerce_to_specific_type(pstate, qual, INT8OID, constructName);
/* LIMIT can't refer to any variables of the current query */
checkExprIsVarFree(pstate, qual, constructName);
/* *Don'tallowNULLsinFETCHFIRST..WITHTIES.Thistestisuglyand *extremelysimplistic,inthatyoucanpassaNULLanywaybyhidingit *insideanexpression--butthisprotectsruleutilsagainstemittingan *unadornedNULLthat'snotacceptedbackbythegrammar.
*/ if (exprKind == EXPR_KIND_LIMIT && limitOption == LIMIT_OPTION_WITH_TIES &&
IsA(clause, A_Const) && castNode(A_Const, clause)->isnull)
ereport(ERROR,
(errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),
errmsg("row count cannot be null in FETCH FIRST ... WITH TIES clause")));
return qual;
}
/* *checkExprIsVarFree *CheckthatgivenexprhasnoVarsofthecurrentquerylevel *(aggregatesandwindowfunctionsshouldhavebeenrejectedalready). * *Thisisusedtocheckexpressionsthathavetohaveaconsistentvalue *acrossallrowsofthequery,suchasaLIMIT.Arguablyitshouldreject *volatilefunctions,too,butwedon'tdothat---whatevervaluethe *functiongivesonfirstexecutioniswhatyouget. * *constructNamedoesnotaffectthesemantics,butisusedinerrormessages
*/ staticvoid
checkExprIsVarFree(ParseState *pstate, Node *n, constchar *constructName)
{ if (contain_vars_of_level(n, 0))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE), /* translator: %s is name of a SQL construct, eg LIMIT */
errmsg("argument of %s must not contain variables",
constructName),
parser_errposition(pstate,
locate_var_of_level(n, 0))));
}
}
/* *checkTargetlistEntrySQL92- *ValidateatargetlistentryfoundbyfindTargetlistEntrySQL92 * *Whenweselectapre-existingtlistentryasaresultofsyntaxsuch *as"GROUPBY1",wehavetomakesureitisacceptableforuseinthe *indicatedclausetype;transformExpr()willhavetreateditasaregular *targetlistitem.
*/ staticvoid
checkTargetlistEntrySQL92(ParseState *pstate, TargetEntry *tle,
ParseExprKind exprKind)
{ switch (exprKind)
{ case EXPR_KIND_GROUP_BY: /* reject aggregates and window functions */ if (pstate->p_hasAggs &&
contain_aggs_of_level((Node *) tle->expr, 0))
ereport(ERROR,
(errcode(ERRCODE_GROUPING_ERROR), /* translator: %s is name of a SQL construct, eg GROUP BY */
errmsg("aggregate functions are not allowed in %s",
ParseExprKindName(exprKind)),
parser_errposition(pstate,
locate_agg_of_level((Node *) tle->expr, 0)))); if (pstate->p_hasWindowFuncs &&
contain_windowfuncs((Node *) tle->expr))
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR), /* translator: %s is name of a SQL construct, eg GROUP BY */
errmsg("window functions are not allowed in %s",
ParseExprKindName(exprKind)),
parser_errposition(pstate,
locate_windowfunc((Node *) tle->expr)))); break; case EXPR_KIND_ORDER_BY: /* no extra checks needed */ break; case EXPR_KIND_DISTINCT_ON: /* no extra checks needed */ break; default:
elog(ERROR, "unexpected exprKind in checkTargetlistEntrySQL92"); break;
}
}
if (!tle->resjunk &&
strcmp(tle->resname, name) == 0)
{ if (target_result != NULL)
{ if (!equal(target_result->expr, tle->expr))
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
/*------
translator: first %s is name of a SQL construct, eg ORDER BY */
errmsg("%s \"%s\" is ambiguous",
ParseExprKindName(exprKind),
name),
parser_errposition(pstate, location)));
} else
target_result = tle; /* Stay in loop to check for ambiguity */
}
} if (target_result != NULL)
{ /* return the first match, after suitable validation */
checkTargetlistEntrySQL92(pstate, target_result, exprKind); return target_result;
}
}
} if (IsA(node, A_Const))
{
A_Const *aconst = castNode(A_Const, node); int targetlist_pos = 0; int target_pos;
if (!IsA(&aconst->val, Integer))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), /* translator: %s is name of a SQL construct, eg ORDER BY */
errmsg("non-integer constant in %s",
ParseExprKindName(exprKind)),
parser_errposition(pstate, aconst->location)));
if (!tle->resjunk)
{ if (++targetlist_pos == target_pos)
{ /* return the unique match, after suitable validation */
checkTargetlistEntrySQL92(pstate, tle, exprKind); return tle;
}
}
}
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE), /* translator: %s is name of a SQL construct, eg ORDER BY */
errmsg("%s position %d is not in select list",
ParseExprKindName(exprKind), target_pos),
parser_errposition(pstate, aconst->location)));
}
if (useSQL99)
tle = findTargetlistEntrySQL99(pstate, gexpr,
targetlist, exprKind); else
tle = findTargetlistEntrySQL92(pstate, gexpr,
targetlist, exprKind);
/* Arbitrarily cap the size of CUBE, which has exponential growth */ if (gset->kind == GROUPING_SET_CUBE)
{ if (list_length(content) > 12)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
errmsg("CUBE is limited to 12 elements"),
parser_errposition(pstate, gset->location)));
}
if (useSQL99)
tle = findTargetlistEntrySQL99(pstate, sortby->node,
targetlist, exprKind); else
tle = findTargetlistEntrySQL92(pstate, sortby->node,
targetlist, exprKind);
/* *transformWindowDefinitions- *transformwindowdefinitions(WindowDeftoWindowClause)
*/
List *
transformWindowDefinitions(ParseState *pstate,
List *windowdefs,
List **targetlist)
{
List *result = NIL;
Index winref = 0;
ListCell *lc;
foreach(lc, windowdefs)
{
WindowDef *windef = (WindowDef *) lfirst(lc);
WindowClause *refwc = NULL;
List *partitionClause;
List *orderClause;
Oid rangeopfamily = InvalidOid;
Oid rangeopcintype = InvalidOid;
WindowClause *wc;
winref++;
/* *Checkforduplicatewindownames.
*/ if (windef->name &&
findWindowClause(result, windef->name) != NULL)
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("window \"%s\" is already defined", windef->name),
parser_errposition(pstate, windef->location)));
/* *Ifitreferencesapreviouswindow,lookthatup.
*/ if (windef->refname)
{
refwc = findWindowClause(result, windef->refname); if (refwc == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("window \"%s\" does not exist",
windef->refname),
parser_errposition(pstate, windef->location)));
}
if (list_length(wc->orderClause) != 1)
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("RANGE with offset PRECEDING/FOLLOWING requires exactly one ORDER BY column"),
parser_errposition(pstate, windef->location)));
sortcl = linitial_node(SortGroupClause, wc->orderClause);
sortkey = get_sortgroupclause_expr(sortcl, *targetlist); /* Find the sort operator in pg_amop */ if (!get_ordering_op_properties(sortcl->sortop,
&rangeopfamily,
&rangeopcintype,
&rangecmptype))
elog(ERROR, "operator %u is not a valid ordering operator",
sortcl->sortop); /* Record properties of sort ordering */
wc->inRangeColl = exprCollation(sortkey);
wc->inRangeAsc = !sortcl->reverse_sort;
wc->inRangeNullsFirst = sortcl->nulls_first;
}
/* Per spec, GROUPS mode requires an ORDER BY clause */ if (wc->frameOptions & FRAMEOPTION_GROUPS)
{ if (wc->orderClause == NIL)
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("GROUPS mode requires an ORDER BY clause"),
parser_errposition(pstate, windef->location)));
}
if (tle->resjunk)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
is_agg ?
errmsg("in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list") :
errmsg("for SELECT DISTINCT, ORDER BY expressions must appear in select list"),
parser_errposition(pstate,
exprLocation((Node *) tle->expr))));
result = lappend(result, copyObject(scl));
}
if (tle->resjunk) continue; /* ignore junk */
result = addTargetToGroupList(pstate, tle,
result, *targetlist,
exprLocation((Node *) tle->expr));
}
/* *ComplainifwefoundnothingtomakeDISTINCT.Returninganemptylist *wouldcausetheparsedQuerytolooklikeitdidn'thaveDISTINCT,with *resultsthatwouldprobablysurprisetheuser.Note:thiscaseis *presentlyimpossibleforaggregatesbecauseofgrammarrestrictions, *butwecheckanyway.
*/ if (result == NIL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
is_agg ?
errmsg("an aggregate with DISTINCT must have at least one argument") :
errmsg("SELECT DISTINCT must have at least one column")));
return result;
}
/* *transformDistinctOnClause- *transformaDISTINCTONclause * *Sincewemayneedtoadditemstothequery'stargetlist,thatlist *ispassedbyreference. * *AswithGROUPBY,weabsorbthesortingsemanticsofORDERBYasmuchas *possibleintothedistinctClause.Thisavoidsapossibleneedtore-sort, *andallowstheusertochoosetheequalitysemanticsusedbyDISTINCT, *shouldshebeworkingwithadatatypethathasmorethanoneequality *operator.
*/
List *
transformDistinctOnClause(ParseState *pstate, List *distinctlist,
List **targetlist, List *sortClause)
{
List *result = NIL;
List *sortgrouprefs = NIL; bool skipped_sortitem;
ListCell *lc;
ListCell *lc2;
if (list_member_int(sortgrouprefs, scl->tleSortGroupRef))
{ if (skipped_sortitem)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions"),
parser_errposition(pstate,
get_matching_location(scl->tleSortGroupRef,
sortgrouprefs,
distinctlist)))); else
result = lappend(result, copyObject(scl));
} else
skipped_sortitem = true;
}
if (targetIsInSortList(tle, InvalidOid, result)) continue; /* already in list (with some semantics) */ if (skipped_sortitem)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions"),
parser_errposition(pstate, exprLocation(dexpr))));
result = addTargetToGroupList(pstate, tle,
result, *targetlist,
exprLocation(dexpr));
}
/* *Rawgrammarre-usesCREATEINDEXinfrastructureforuniqueindex *inferenceclause,andsowillacceptopclassesbynameandsoon. * *MakenoattempttomatchASCorDESCorderingorNULLSFIRST/NULLS *LASTordering,sincethosearenotsignificantforinference *purposes(anyuniqueindexmatchingtheinferencespecificationin *otherregardsisacceptedindifferently).Activelyrejectthisas *wrong-headed.
*/ if (ielem->ordering != SORTBY_DEFAULT)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("ASC/DESC is not allowed in ON CONFLICT clause"),
parser_errposition(pstate,
exprLocation((Node *) infer)))); if (ielem->nulls_ordering != SORTBY_NULLS_DEFAULT)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("NULLS FIRST/LAST is not allowed in ON CONFLICT clause"),
parser_errposition(pstate,
exprLocation((Node *) infer))));
if (!ielem->expr)
{ /* Simple index attribute */
ColumnRef *n;
/* *Grammarwon'thavebuiltrawexpressionforusineventof *plaincolumnreference.Createonedirectly,andperform *expressiontransformation.Plannerexpectsthis,andperforms *itsownnormalizationforthepurposesofmatchingagainst *pg_index.
*/
n = makeNode(ColumnRef);
n->fields = list_make1(makeString(ielem->name)); /* Location is approximately that of inference specification */
n->location = infer->location;
parse = (Node *) n;
} else
{ /* Do parse transformation of the raw expression */
parse = (Node *) ielem->expr;
}
/* Perform lookup of collation and operator class as required */ if (!ielem->collation)
pInfer->infercollid = InvalidOid; else
pInfer->infercollid = LookupCollation(pstate, ielem->collation,
exprLocation(pInfer->expr));
if (onConflictClause->action == ONCONFLICT_UPDATE && !infer)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("ON CONFLICT DO UPDATE requires inference specification or constraint name"),
errhint("For example, ON CONFLICT (column_name)."),
parser_errposition(pstate,
exprLocation((Node *) onConflictClause))));
/* *Tosimplifycertainaspectsofitsdesign,speculativeinsertioninto *systemcatalogsisdisallowed
*/ if (IsCatalogRelation(pstate->p_target_relation))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("ON CONFLICT is not supported with system catalog tables"),
parser_errposition(pstate,
exprLocation((Node *) onConflictClause))));
/* Same applies to table used by logical decoding as catalog table */ if (RelationIsUsedAsCatalogTable(pstate->p_target_relation))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("ON CONFLICT is not supported on table \"%s\" used as a catalog table",
RelationGetRelationName(pstate->p_target_relation)),
parser_errposition(pstate,
exprLocation((Node *) onConflictClause))));
/* ON CONFLICT DO NOTHING does not require an inference clause */ if (infer)
{ if (infer->indexElems)
*arbiterExpr = resolve_unique_index_expr(pstate, infer,
pstate->p_target_relation);
/* Make sure the rel as a whole is marked for SELECT access */
perminfo->requiredPerms |= ACL_SELECT; /* Mark the constrained columns as requiring SELECT access */
perminfo->selectedCols = bms_add_members(perminfo->selectedCols,
conattnos);
}
}
/* determine the sortop, eqop, and directionality */ switch (sortby->sortby_dir)
{ case SORTBY_DEFAULT: case SORTBY_ASC:
get_sort_group_operators(restype, true, true, false,
&sortop, &eqop, NULL,
&hashable);
reverse = false; break; case SORTBY_DESC:
get_sort_group_operators(restype, false, true, true,
NULL, &eqop, &sortop,
&hashable);
reverse = true; break; case SORTBY_USING:
Assert(sortby->useOp != NIL);
sortop = compatible_oper_opid(sortby->useOp,
restype,
restype, false);
/* *Verifyit'savalidorderingoperator,fetchthecorresponding *equalityoperator,anddeterminewhethertoconsideritlike *ASCorDESC.
*/
eqop = get_equality_op_for_ordering_op(sortop, &reverse); if (!OidIsValid(eqop))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("operator %s is not a valid ordering operator",
strVal(llast(sortby->useOp))),
errhint("Ordering operators must be \"<\" or \">\" members of btree operator families.")));
switch (sortby->sortby_nulls)
{ case SORTBY_NULLS_DEFAULT: /* NULLS FIRST is default for DESC; other way for ASC */
sortcl->nulls_first = reverse; break; case SORTBY_NULLS_FIRST:
sortcl->nulls_first = true; break; case SORTBY_NULLS_LAST:
sortcl->nulls_first = false; break; default:
elog(ERROR, "unrecognized sortby_nulls: %d",
sortby->sortby_nulls); break;
}
sortlist = lappend(sortlist, sortcl);
}
return sortlist;
}
/* *addTargetToGroupList *Ifthegiventargetlistentryisn'talreadyintheSortGroupClause *list,addittotheendofthelist,usingdefaultsort/group *semantics. * *ThisisverysimilartoaddTargetToSortList,exceptthatweallowthe *casewhereonlyagrouping(equality)operatorcanbefound,andthat *theTLEisconsidered"alreadyinthelist"ifitappearstherewithany *sortingsemantics. * *locationistheparselocationtobefingeredineventoftrouble.Note *thatwecan'trelyonexprLocation(tle->expr),becausethatmightpoint *toaSELECTitemthatmatchestheGROUPBYitem;it'dbeprettyconfusing *toreportsuchalocation. * *ReturnstheupdatedSortGroupClauselist.
*/ static List *
addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
List *grouplist, List *targetlist, int location)
{
Oid restype = exprType((Node *) tle->expr);
/* if tlist item is an UNKNOWN literal, change it to TEXT */ if (restype == UNKNOWNOID)
{
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST,
-1);
restype = TEXTOID;
}
/* avoid making duplicate grouplist entries */ if (!targetIsInSortList(tle, InvalidOid, grouplist))
{
SortGroupClause *grpcl = makeNode(SortGroupClause);
Oid sortop;
Oid eqop; bool hashable;
ParseCallbackState pcbstate;
/* Find the in_range support functions applicable to this case */
proclist = SearchSysCacheList2(AMPROCNUM,
ObjectIdGetDatum(rangeopfamily),
ObjectIdGetDatum(rangeopcintype)); for (i = 0; i < proclist->n_members; i++)
{
HeapTuple proctup = &proclist->members[i]->tuple;
Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
/* The search will find all support proc types; ignore others */ if (procform->amprocnum != BTINRANGE_PROC) continue;
nfuncs++;
/* Ignore function if given value can't be coerced to that type */ if (!can_coerce_type(1, &nodeType, &procform->amprocrighttype,
COERCION_IMPLICIT)) continue;
nmatches++;
/* Remember preferred match, or any match if didn't find that */ if (selectedType != preferredType)
{
selectedType = procform->amprocrighttype;
selectedFunc = procform->amproc;
}
}
ReleaseCatCacheList(proclist);
/* *Throwerrorifneeded.Itseemsworthtakingthetroubleto *distinguish"nosupportatall"from"youdidn'tmatchany *availableoffsettype".
*/ if (nfuncs == 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("RANGE with offset PRECEDING/FOLLOWING is not supported for column type %s",
format_type_be(rangeopcintype)),
parser_errposition(pstate, exprLocation(node)))); if (nmatches == 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("RANGE with offset PRECEDING/FOLLOWING is not supported for column type %s and offset type %s",
format_type_be(rangeopcintype),
format_type_be(nodeType)),
errhint("Cast the offset value to an appropriate type."),
parser_errposition(pstate, exprLocation(node)))); if (nmatches != 1 && selectedType != preferredType)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("RANGE with offset PRECEDING/FOLLOWING has multiple interpretations for column type %s and offset type %s",
format_type_be(rangeopcintype),
format_type_be(nodeType)),
errhint("Cast the offset value to the exact intended type."),
parser_errposition(pstate, exprLocation(node))));
/* OK, coerce the offset to the right type */
constructName = "RANGE";
node = coerce_to_specific_type(pstate, node,
selectedType, constructName);
*inRangeFunc = selectedFunc;
} elseif (frameOptions & FRAMEOPTION_GROUPS)
{ /* Transform the raw expression tree */
node = transformExpr(pstate, clause, EXPR_KIND_WINDOW_FRAME_GROUPS);
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.