should be it

This commit is contained in:
2025-10-24 19:21:19 -05:00
parent a4b23fc57c
commit f09560c7b1
14047 changed files with 3161551 additions and 1 deletions

View File

@@ -0,0 +1,756 @@
/*
* The signature of this function is required by bison. However, we
* ignore the passed yylloc and instead use the last token position
* available from the scanner.
*/
static void
base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg)
{
parser_yyerror(msg);
}
static PGRawStmt *
makeRawStmt(PGNode *stmt, int stmt_location)
{
PGRawStmt *rs = makeNode(PGRawStmt);
rs->stmt = stmt;
rs->stmt_location = stmt_location;
rs->stmt_len = 0; /* might get changed later */
return rs;
}
/* Adjust a PGRawStmt to reflect that it doesn't run to the end of the string */
static void
updateRawStmtEnd(PGRawStmt *rs, int end_location)
{
/*
* If we already set the length, don't change it. This is for situations
* like "select foo ;; select bar" where the same statement will be last
* in the string for more than one semicolon.
*/
if (rs->stmt_len > 0)
return;
/* OK, update length of PGRawStmt */
rs->stmt_len = end_location - rs->stmt_location;
}
static PGNode *
makeColumnRef(char *colname, PGList *indirection,
int location, core_yyscan_t yyscanner)
{
/*
* Generate a PGColumnRef node, with an PGAIndirection node added if there
* is any subscripting in the specified indirection list. However,
* any field selection at the start of the indirection list must be
* transposed into the "fields" part of the PGColumnRef node.
*/
PGColumnRef *c = makeNode(PGColumnRef);
int nfields = 0;
PGListCell *l;
c->location = location;
foreach(l, indirection)
{
if (IsA(lfirst(l), PGAIndices))
{
PGAIndirection *i = makeNode(PGAIndirection);
if (nfields == 0)
{
/* easy case - all indirection goes to PGAIndirection */
c->fields = list_make1(makeString(colname));
i->indirection = check_indirection(indirection, yyscanner);
}
else
{
/* got to split the list in two */
i->indirection = check_indirection(list_copy_tail(indirection,
nfields),
yyscanner);
indirection = list_truncate(indirection, nfields);
c->fields = lcons(makeString(colname), indirection);
}
i->arg = (PGNode *) c;
return (PGNode *) i;
}
else if (IsA(lfirst(l), PGAStar))
{
/* We only allow '*' at the end of a PGColumnRef */
if (lnext(l) != NULL)
parser_yyerror("improper use of \"*\"");
}
nfields++;
}
/* No subscripting, so all indirection gets added to field list */
c->fields = lcons(makeString(colname), indirection);
return (PGNode *) c;
}
static PGNode *
makeTypeCast(PGNode *arg, PGTypeName *tpname, int trycast, int location)
{
PGTypeCast *n = makeNode(PGTypeCast);
n->arg = arg;
n->typeName = tpname;
n->tryCast = trycast;
n->location = location;
return (PGNode *) n;
}
static PGNode *
makeStringConst(const char *str, int location)
{
PGAConst *n = makeNode(PGAConst);
n->val.type = T_PGString;
n->val.val.str = (char *) str;
n->location = location;
return (PGNode *)n;
}
static PGNode *
makeStringConstCast(const char *str, int location, PGTypeName *tpname)
{
PGNode *s = makeStringConst(str, location);
return makeTypeCast(s, tpname, 0, -1);
}
static PGNode *
makeIntervalNode(char *str, int location, PGList *typmods) {
PGIntervalConstant *n = makeNode(PGIntervalConstant);
n->val_type = T_PGString;
n->sval = str;
n->location = location;
n->typmods = typmods;
return (PGNode *)n;
}
static PGNode *
makeIntervalNode(int val, int location, PGList *typmods) {
PGIntervalConstant *n = makeNode(PGIntervalConstant);
n->val_type = T_PGInteger;
n->ival = val;
n->location = location;
n->typmods = typmods;
return (PGNode *)n;
}
static PGNode *
makeIntervalNode(PGNode *arg, int location, PGList *typmods) {
PGIntervalConstant *n = makeNode(PGIntervalConstant);
n->val_type = T_PGAExpr;
n->eval = arg;
n->location = location;
n->typmods = typmods;
return (PGNode *)n;
}
static PGNode *
makeSampleSize(PGNode *sample_size, bool is_percentage) {
PGSampleSize *n = makeNode(PGSampleSize);
n->sample_size = sample_size;
n->is_percentage = is_percentage;
return (PGNode *)n;
}
static PGNode *
makeSampleOptions(PGNode *sample_size, char *method, int *seed, int location) {
PGSampleOptions *n = makeNode(PGSampleOptions);
n->sample_size = sample_size;
n->method = method;
if (seed) {
n->has_seed = true;
n->seed = *seed;
}
n->location = location;
return (PGNode *)n;
}
/* makeLimitPercent()
* Make limit percent node
*/
static PGNode *
makeLimitPercent(PGNode *limit_percent) {
PGLimitPercent *n = makeNode(PGLimitPercent);
n->limit_percent = limit_percent;
return (PGNode *)n;
}
static PGNode *
makeIntConst(int val, int location)
{
PGAConst *n = makeNode(PGAConst);
n->val.type = T_PGInteger;
n->val.val.ival = val;
n->location = location;
return (PGNode *)n;
}
static PGNode *
makeFloatConst(char *str, int location)
{
PGAConst *n = makeNode(PGAConst);
n->val.type = T_PGFloat;
n->val.val.str = str;
n->location = location;
return (PGNode *)n;
}
static PGNode *
makeBitStringConst(char *str, int location)
{
PGAConst *n = makeNode(PGAConst);
n->val.type = T_PGBitString;
n->val.val.str = str;
n->location = location;
return (PGNode *)n;
}
static PGNode *
makeNullAConst(int location)
{
PGAConst *n = makeNode(PGAConst);
n->val.type = T_PGNull;
n->location = location;
return (PGNode *)n;
}
static PGNode *
makeAConst(PGValue *v, int location)
{
PGNode *n;
switch (v->type)
{
case T_PGFloat:
n = makeFloatConst(v->val.str, location);
break;
case T_PGInteger:
n = makeIntConst(v->val.ival, location);
break;
case T_PGString:
default:
n = makeStringConst(v->val.str, location);
break;
}
return n;
}
/* makeBoolAConst()
* Create an PGAConst string node and put it inside a boolean cast.
*/
static PGNode *
makeBoolAConst(bool state, int location)
{
PGAConst *n = makeNode(PGAConst);
n->val.type = T_PGString;
n->val.val.str = (state ? (char*) "t" : (char*) "f");
n->location = location;
return makeTypeCast((PGNode *)n, SystemTypeName("bool"), 0, -1);
}
/* check_qualified_name --- check the result of qualified_name production
*
* It's easiest to let the grammar production for qualified_name allow
* subscripts and '*', which we then must reject here.
*/
static void
check_qualified_name(PGList *names, core_yyscan_t yyscanner)
{
PGListCell *i;
foreach(i, names)
{
if (!IsA(lfirst(i), PGString))
parser_yyerror("syntax error");
}
}
/* check_func_name --- check the result of func_name production
*
* It's easiest to let the grammar production for func_name allow subscripts
* and '*', which we then must reject here.
*/
static PGList *
check_func_name(PGList *names, core_yyscan_t yyscanner)
{
PGListCell *i;
foreach(i, names)
{
if (!IsA(lfirst(i), PGString))
parser_yyerror("syntax error");
}
return names;
}
/* check_indirection --- check the result of indirection production
*
* We only allow '*' at the end of the list, but it's hard to enforce that
* in the grammar, so do it here.
*/
static PGList *
check_indirection(PGList *indirection, core_yyscan_t yyscanner)
{
PGListCell *l;
foreach(l, indirection)
{
if (IsA(lfirst(l), PGAStar))
{
if (lnext(l) != NULL)
parser_yyerror("improper use of \"*\"");
}
}
return indirection;
}
/* makeParamRef
* Creates a new PGParamRef node
*/
static PGNode* makeParamRef(int number, int location)
{
PGParamRef *p = makeNode(PGParamRef);
p->number = number;
p->location = location;
p->name = NULL;
return (PGNode *) p;
}
/* makeNamedParamRef
* Creates a new PGParamRef node
*/
static PGNode* makeNamedParamRef(char *name, int location)
{
PGParamRef *p = (PGParamRef *)makeParamRef(0, location);
p->name = name;
return (PGNode *) p;
}
/* insertSelectOptions()
* Insert ORDER BY, etc into an already-constructed SelectStmt.
*
* This routine is just to avoid duplicating code in PGSelectStmt productions.
*/
static void
insertSelectOptions(PGSelectStmt *stmt,
PGList *sortClause, PGList *lockingClause,
PGNode *limitOffset, PGNode *limitCount, PGNode *isLimitOffsetFirst,
PGWithClause *withClause,
core_yyscan_t yyscanner)
{
if (stmt->type != T_PGSelectStmt) {
ereport(ERROR,
(errcode(PG_ERRCODE_SYNTAX_ERROR),
errmsg("DESCRIBE/SHOW/SUMMARIZE with CTE/ORDER BY/... not allowed - wrap the statement in a subquery instead"),
parser_errposition(exprLocation((PGNode *) stmt))));
}
Assert(IsA(stmt, PGSelectStmt));
/*
* Tests here are to reject constructs like
* (SELECT foo ORDER BY bar) ORDER BY baz
*/
if (sortClause)
{
if (stmt->sortClause)
ereport(ERROR,
(errcode(PG_ERRCODE_SYNTAX_ERROR),
errmsg("multiple ORDER BY clauses not allowed"),
parser_errposition(exprLocation((PGNode *) sortClause))));
stmt->sortClause = sortClause;
}
/* We can handle multiple locking clauses, though */
stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause);
if (limitOffset)
{
if (stmt->limitOffset)
ereport(ERROR,
(errcode(PG_ERRCODE_SYNTAX_ERROR),
errmsg("multiple OFFSET clauses not allowed"),
parser_errposition(exprLocation(limitOffset))));
stmt->limitOffset = limitOffset;
}
if (limitCount)
{
if (stmt->limitCount)
ereport(ERROR,
(errcode(PG_ERRCODE_SYNTAX_ERROR),
errmsg("multiple LIMIT clauses not allowed"),
parser_errposition(exprLocation(limitCount))));
stmt->limitCount = limitCount;
}
if (limitOffset == isLimitOffsetFirst) {
stmt->offset_first = true;
}
if (withClause)
{
if (stmt->withClause)
ereport(ERROR,
(errcode(PG_ERRCODE_SYNTAX_ERROR),
errmsg("multiple WITH clauses not allowed"),
parser_errposition(exprLocation((PGNode *) withClause))));
stmt->withClause = withClause;
}
}
static PGNode *
makeSetOp(PGSetOperation op, bool all, PGNode *larg, PGNode *rarg)
{
PGSelectStmt *n = makeNode(PGSelectStmt);
n->op = op;
n->all = all;
n->larg = larg;
n->rarg = rarg;
return (PGNode *) n;
}
/* SystemFuncName()
* Build a properly-qualified reference to a built-in function.
*/
PGList *
SystemFuncName(const char *name)
{
return list_make2(makeString(DEFAULT_SCHEMA), makeString(name));
}
/* SystemTypeName()
* Build a properly-qualified reference to a built-in type.
*
* typmod is defaulted, but may be changed afterwards by caller.
* Likewise for the location.
*/
PGTypeName *
SystemTypeName(const char *name)
{
return makeTypeNameFromNameList(list_make1(makeString(name)));
}
/* doNegate()
* Handle negation of a numeric constant.
*
* Formerly, we did this here because the optimizer couldn't cope with
* indexquals that looked like "var = -4" --- it wants "var = const"
* and a unary minus operator applied to a constant didn't qualify.
* As of Postgres 7.0, that problem doesn't exist anymore because there
* is a constant-subexpression simplifier in the optimizer. However,
* there's still a good reason for doing this here, which is that we can
* postpone committing to a particular internal representation for simple
* negative constants. It's better to leave "-123.456" in string form
* until we know what the desired type is.
*/
static PGNode *
doNegate(PGNode *n, int location)
{
if (IsA(n, PGAConst))
{
PGAConst *con = (PGAConst *)n;
/* report the constant's location as that of the '-' sign */
con->location = location;
if (con->val.type == T_PGInteger)
{
con->val.val.ival = -con->val.val.ival;
return n;
}
if (con->val.type == T_PGFloat)
{
doNegateFloat(&con->val);
return n;
}
}
return (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "-", NULL, n, location);
}
static void
doNegateFloat(PGValue *v)
{
char *oldval = v->val.str;
Assert(IsA(v, PGFloat));
if (*oldval == '+')
oldval++;
if (*oldval == '-')
v->val.str = oldval+1; /* just strip the '-' */
else
v->val.str = psprintf("-%s", oldval);
}
static PGNode *
makeAndExpr(PGNode *lexpr, PGNode *rexpr, int location)
{
PGNode *lexp = lexpr;
/* Look through AEXPR_PAREN nodes so they don't affect flattening */
while (IsA(lexp, PGAExpr) &&
((PGAExpr *) lexp)->kind == AEXPR_PAREN)
lexp = ((PGAExpr *) lexp)->lexpr;
/* Flatten "a AND b AND c ..." to a single PGBoolExpr on sight */
if (IsA(lexp, PGBoolExpr))
{
PGBoolExpr *blexpr = (PGBoolExpr *) lexp;
if (blexpr->boolop == PG_AND_EXPR)
{
blexpr->args = lappend(blexpr->args, rexpr);
return (PGNode *) blexpr;
}
}
return (PGNode *) makeBoolExpr(PG_AND_EXPR, list_make2(lexpr, rexpr), location);
}
static PGNode *
makeOrExpr(PGNode *lexpr, PGNode *rexpr, int location)
{
PGNode *lexp = lexpr;
/* Look through AEXPR_PAREN nodes so they don't affect flattening */
while (IsA(lexp, PGAExpr) &&
((PGAExpr *) lexp)->kind == AEXPR_PAREN)
lexp = ((PGAExpr *) lexp)->lexpr;
/* Flatten "a OR b OR c ..." to a single PGBoolExpr on sight */
if (IsA(lexp, PGBoolExpr))
{
PGBoolExpr *blexpr = (PGBoolExpr *) lexp;
if (blexpr->boolop == PG_OR_EXPR)
{
blexpr->args = lappend(blexpr->args, rexpr);
return (PGNode *) blexpr;
}
}
return (PGNode *) makeBoolExpr(PG_OR_EXPR, list_make2(lexpr, rexpr), location);
}
static PGNode *
makeNotExpr(PGNode *expr, int location)
{
return (PGNode *) makeBoolExpr(PG_NOT_EXPR, list_make1(expr), location);
}
/* Separate PGConstraint nodes from COLLATE clauses in a */
static void
SplitColQualList(PGList *qualList,
PGList **constraintList, PGCollateClause **collClause,
core_yyscan_t yyscanner)
{
PGListCell *cell;
PGListCell *prev;
PGListCell *next;
*collClause = NULL;
prev = NULL;
for (cell = list_head(qualList); cell; cell = next)
{
PGNode *n = (PGNode *) lfirst(cell);
next = lnext(cell);
if (IsA(n, PGConstraint))
{
/* keep it in list */
prev = cell;
continue;
}
if (IsA(n, PGCollateClause))
{
PGCollateClause *c = (PGCollateClause *) n;
if (*collClause)
ereport(ERROR,
(errcode(PG_ERRCODE_SYNTAX_ERROR),
errmsg("multiple COLLATE clauses not allowed"),
parser_errposition(c->location)));
*collClause = c;
}
else
elog(ERROR, "unexpected node type %d", (int) n->type);
/* remove non-Constraint nodes from qualList */
qualList = list_delete_cell(qualList, cell, prev);
}
*constraintList = qualList;
}
/*
* Process result of ConstraintAttributeSpec, and set appropriate bool flags
* in the output command node. Pass NULL for any flags the particular
* command doesn't support.
*/
static void
processCASbits(int cas_bits, int location, const char *constrType,
bool *deferrable, bool *initdeferred, bool *not_valid,
bool *no_inherit, core_yyscan_t yyscanner)
{
/* defaults */
if (deferrable)
*deferrable = false;
if (initdeferred)
*initdeferred = false;
if (not_valid)
*not_valid = false;
if (cas_bits & (CAS_DEFERRABLE | CAS_INITIALLY_DEFERRED))
{
if (deferrable)
*deferrable = true;
else
ereport(ERROR,
(errcode(PG_ERRCODE_FEATURE_NOT_SUPPORTED),
/* translator: %s is CHECK, UNIQUE, or similar */
errmsg("%s constraints cannot be marked DEFERRABLE",
constrType),
parser_errposition(location)));
}
if (cas_bits & CAS_INITIALLY_DEFERRED)
{
if (initdeferred)
*initdeferred = true;
else
ereport(ERROR,
(errcode(PG_ERRCODE_FEATURE_NOT_SUPPORTED),
/* translator: %s is CHECK, UNIQUE, or similar */
errmsg("%s constraints cannot be marked DEFERRABLE",
constrType),
parser_errposition(location)));
}
if (cas_bits & CAS_NOT_VALID)
{
if (not_valid)
*not_valid = true;
else
ereport(ERROR,
(errcode(PG_ERRCODE_FEATURE_NOT_SUPPORTED),
/* translator: %s is CHECK, UNIQUE, or similar */
errmsg("%s constraints cannot be marked NOT VALID",
constrType),
parser_errposition(location)));
}
if (cas_bits & CAS_NO_INHERIT)
{
if (no_inherit)
*no_inherit = true;
else
ereport(ERROR,
(errcode(PG_ERRCODE_FEATURE_NOT_SUPPORTED),
/* translator: %s is CHECK, UNIQUE, or similar */
errmsg("%s constraints cannot be marked NO INHERIT",
constrType),
parser_errposition(location)));
}
}
/*----------
* Recursive view transformation
*
* Convert
*
* CREATE RECURSIVE VIEW relname (aliases) AS query
*
* to
*
* CREATE VIEW relname (aliases) AS
* WITH RECURSIVE relname (aliases) AS (query)
* SELECT aliases FROM relname
*
* Actually, just the WITH ... part, which is then inserted into the original
* view as the query.
* ----------
*/
static PGNode *
makeRecursiveViewSelect(char *relname, PGList *aliases, PGNode *query)
{
PGSelectStmt *s = makeNode(PGSelectStmt);
PGWithClause *w = makeNode(PGWithClause);
PGCommonTableExpr *cte = makeNode(PGCommonTableExpr);
PGList *tl = NIL;
PGListCell *lc;
/* create common table expression */
cte->ctename = relname;
cte->aliascolnames = aliases;
cte->ctequery = query;
cte->location = -1;
/* create WITH clause and attach CTE */
w->recursive = true;
w->ctes = list_make1(cte);
w->location = -1;
/* create target list for the new SELECT from the alias list of the
* recursive view specification */
foreach (lc, aliases)
{
PGResTarget *rt = makeNode(PGResTarget);
rt->name = NULL;
rt->indirection = NIL;
rt->val = makeColumnRef(strVal(lfirst(lc)), NIL, -1, 0);
rt->location = -1;
tl = lappend(tl, rt);
}
/* create new SELECT combining WITH clause, target list, and fake FROM
* clause */
s->withClause = w;
s->targetList = tl;
s->fromClause = list_make1(makeRangeVar(NULL, relname, -1));
return (PGNode *) s;
}
/* parser_init()
* Initialize to parse one query string
*/
void
parser_init(base_yy_extra_type *yyext)
{
yyext->parsetree = NIL; /* in case grammar forgets to set it */
}
#undef yyparse
#undef yylex
#undef yyerror
#undef yylval
#undef yychar
#undef yydebug
#undef yynerrs
#undef yylloc
} // namespace duckdb_libpgquery