diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-03-21 16:02:16 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-03-21 16:02:16 +0000 |
commit | 95ef6a344821655ce4d0a74999ac49dd6af6d342 (patch) | |
tree | df484a4c9dde9827894ab707917c001a1f376749 /src/backend/parser/parse_expr.c | |
parent | 8c9c8ca2b57e4edef218245ccdc9eef7c06425d8 (diff) | |
download | postgresql-95ef6a344821655ce4d0a74999ac49dd6af6d342.tar.gz postgresql-95ef6a344821655ce4d0a74999ac49dd6af6d342.zip |
First phase of SCHEMA changes, concentrating on fixing the grammar and
the parsetree representation. As yet we don't *do* anything with schema
names, just drop 'em on the floor; but you can enter schema-compatible
command syntax, and there's even a primitive CREATE SCHEMA command.
No doc updates yet, except to note that you can now extract a field
from a function-returning-row's result with (foo(...)).fieldname.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 322 |
1 files changed, 232 insertions, 90 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 6409ef3226a..73cd89fd3d8 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.110 2002/03/20 19:44:25 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.111 2002/03/21 16:01:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" +#include "miscadmin.h" #include "nodes/makefuncs.h" #include "nodes/params.h" #include "parser/analyze.h" @@ -41,8 +42,7 @@ bool Transform_null_equals = false; static Node *parser_typecast_constant(Value *expr, TypeName *typename); static Node *parser_typecast_expression(ParseState *pstate, Node *expr, TypeName *typename); -static Node *transformAttr(ParseState *pstate, Attr *att, int precedence); -static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence); +static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref); static Node *transformIndirection(ParseState *pstate, Node *basenode, List *indirection); @@ -85,7 +85,7 @@ parse_expr_init(void) * input and output of transformExpr; see SubLink for example. */ Node * -transformExpr(ParseState *pstate, Node *expr, int precedence) +transformExpr(ParseState *pstate, Node *expr) { Node *result = NULL; @@ -105,9 +105,37 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) switch (nodeTag(expr)) { - case T_Attr: + case T_ColumnRef: { - result = transformAttr(pstate, (Attr *) expr, precedence); + result = transformColumnRef(pstate, (ColumnRef *) expr); + break; + } + case T_ParamRef: + { + ParamRef *pref = (ParamRef *) expr; + int paramno = pref->number; + Oid paramtyp = param_type(paramno); + Param *param; + List *fields; + + if (!OidIsValid(paramtyp)) + elog(ERROR, "Parameter '$%d' is out of range", paramno); + param = makeNode(Param); + param->paramkind = PARAM_NUM; + param->paramid = (AttrNumber) paramno; + param->paramname = "<unnamed>"; + param->paramtype = paramtyp; + result = (Node *) param; + /* handle qualification, if any */ + foreach(fields, pref->fields) + { + result = ParseFuncOrColumn(pstate, strVal(lfirst(fields)), + makeList1(result), + false, false, true); + } + /* handle subscripts, if any */ + result = transformIndirection(pstate, result, + pref->indirection); break; } case T_A_Const: @@ -121,31 +149,28 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) result = (Node *) make_const(val); break; } - case T_ParamNo: + case T_ExprFieldSelect: { - ParamNo *pno = (ParamNo *) expr; - int paramno = pno->number; - Oid toid = param_type(paramno); - Param *param = makeNode(Param); + ExprFieldSelect *efs = (ExprFieldSelect *) expr; + List *fields; - if (!OidIsValid(toid)) - elog(ERROR, "Parameter '$%d' is out of range", paramno); - param->paramkind = PARAM_NUM; - param->paramid = (AttrNumber) paramno; - param->paramname = "<unnamed>"; - param->paramtype = toid; - result = transformIndirection(pstate, (Node *) param, - pno->indirection); - /* cope with typecast applied to param */ - if (pno->typename != NULL) - result = parser_typecast_expression(pstate, result, - pno->typename); + result = transformExpr(pstate, efs->arg); + /* handle qualification, if any */ + foreach(fields, efs->fields) + { + result = ParseFuncOrColumn(pstate, strVal(lfirst(fields)), + makeList1(result), + false, false, true); + } + /* handle subscripts, if any */ + result = transformIndirection(pstate, result, + efs->indirection); break; } case T_TypeCast: { TypeCast *tc = (TypeCast *) expr; - Node *arg = transformExpr(pstate, tc->arg, precedence); + Node *arg = transformExpr(pstate, tc->arg); result = parser_typecast_expression(pstate, arg, tc->typename); break; @@ -179,17 +204,14 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) n->arg = a->lexpr; result = transformExpr(pstate, - (Node *) n, - precedence); + (Node *) n); } else { Node *lexpr = transformExpr(pstate, - a->lexpr, - precedence); + a->lexpr); Node *rexpr = transformExpr(pstate, - a->rexpr, - precedence); + a->rexpr); result = (Node *) make_op(a->opname, lexpr, @@ -200,11 +222,9 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) case AND: { Node *lexpr = transformExpr(pstate, - a->lexpr, - precedence); + a->lexpr); Node *rexpr = transformExpr(pstate, - a->rexpr, - precedence); + a->rexpr); Expr *expr = makeNode(Expr); if (!coerce_to_boolean(pstate, &lexpr)) @@ -226,11 +246,9 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) case OR: { Node *lexpr = transformExpr(pstate, - a->lexpr, - precedence); + a->lexpr); Node *rexpr = transformExpr(pstate, - a->rexpr, - precedence); + a->rexpr); Expr *expr = makeNode(Expr); if (!coerce_to_boolean(pstate, &lexpr)) @@ -252,8 +270,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) case NOT: { Node *rexpr = transformExpr(pstate, - a->rexpr, - precedence); + a->rexpr); Expr *expr = makeNode(Expr); if (!coerce_to_boolean(pstate, &rexpr)) @@ -270,11 +287,6 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) } break; } - case T_Ident: - { - result = transformIdent(pstate, (Ident *) expr, precedence); - break; - } case T_FuncCall: { FuncCall *fn = (FuncCall *) expr; @@ -283,14 +295,13 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) /* transform the list of arguments */ foreach(args, fn->args) lfirst(args) = transformExpr(pstate, - (Node *) lfirst(args), - precedence); + (Node *) lfirst(args)); result = ParseFuncOrColumn(pstate, fn->funcname, fn->args, fn->agg_star, fn->agg_distinct, - precedence); + false); break; } case T_SubLink: @@ -357,8 +368,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) List *elist; foreach(elist, left_list) - lfirst(elist) = transformExpr(pstate, lfirst(elist), - precedence); + lfirst(elist) = transformExpr(pstate, lfirst(elist)); Assert(IsA(sublink->oper, A_Expr)); op = ((A_Expr *) sublink->oper)->opname; @@ -455,7 +465,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) a->rexpr = warg; warg = (Node *) a; } - neww->expr = transformExpr(pstate, warg, precedence); + neww->expr = transformExpr(pstate, warg); if (!coerce_to_boolean(pstate, &neww->expr)) elog(ERROR, "WHEN clause must have a boolean result"); @@ -472,7 +482,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) n->val.type = T_Null; warg = (Node *) n; } - neww->result = transformExpr(pstate, warg, precedence); + neww->result = transformExpr(pstate, warg); newargs = lappend(newargs, neww); typeids = lappendi(typeids, exprType(neww->result)); @@ -496,7 +506,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) n->val.type = T_Null; defresult = (Node *) n; } - newc->defresult = transformExpr(pstate, defresult, precedence); + newc->defresult = transformExpr(pstate, defresult); /* * Note: default result is considered the most significant @@ -534,7 +544,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) { NullTest *n = (NullTest *) expr; - n->arg = transformExpr(pstate, n->arg, precedence); + n->arg = transformExpr(pstate, n->arg); /* the argument can be any type, so don't coerce it */ result = expr; break; @@ -544,7 +554,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) { BooleanTest *b = (BooleanTest *) expr; - b->arg = transformExpr(pstate, b->arg, precedence); + b->arg = transformExpr(pstate, b->arg); if (!coerce_to_boolean(pstate, &b->arg)) { @@ -627,47 +637,183 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection) } static Node * -transformAttr(ParseState *pstate, Attr *att, int precedence) +transformColumnRef(ParseState *pstate, ColumnRef *cref) { - Node *basenode; + int numnames = length(cref->fields); + Node *node; + RangeVar *rv; + + /*---------- + * The allowed syntaxes are: + * + * A First try to resolve as unqualified column name; + * if no luck, try to resolve as unqual. table name (A.*). + * A.B A is an unqual. table name; B is either a + * column or function name (trying column name first). + * A.B.C schema A, table B, col or func name C. + * A.B.C.D catalog A, schema B, table C, col or func D. + * A.* A is an unqual. table name; means whole-row value. + * A.B.* whole-row value of table B in schema A. + * A.B.C.* whole-row value of table C in schema B in catalog A. + * + * We do not need to cope with bare "*"; that will only be accepted by + * the grammar at the top level of a SELECT list, and transformTargetList + * will take care of it before it ever gets here. + * + * Currently, if a catalog name is given then it must equal the current + * database name; we check it here and then discard it. + * + * For whole-row references, the result is an untransformed RangeVar, + * which will work as the argument to a function call, but not in any + * other context at present. (We could instead coerce to a whole-row Var, + * but that will fail for subselect and join RTEs, because there is no + * pg_type entry for their rowtypes.) + *---------- + */ + switch (numnames) + { + case 1: + { + char *name = strVal(lfirst(cref->fields)); - basenode = ParseNestedFuncOrColumn(pstate, att, precedence); - return transformIndirection(pstate, basenode, att->indirection); -} + /* Try to identify as an unqualified column */ + node = colnameToVar(pstate, name); + if (node == NULL) + { + /* + * Not known as a column of any range-table entry, so + * try to find the name as a relation ... but not if + * subscripts appear. Note also that only relations + * already entered into the rangetable will be recognized. + */ + int levels_up; -static Node * -transformIdent(ParseState *pstate, Ident *ident, int precedence) -{ - Node *result = NULL; - int sublevels_up; + if (cref->indirection == NIL && + refnameRangeTblEntry(pstate, name, &levels_up) != NULL) + { + rv = makeNode(RangeVar); + rv->relname = name; + rv->inhOpt = INH_DEFAULT; + node = (Node *) rv; + } + else + elog(ERROR, "Attribute \"%s\" not found", name); + } + break; + } + case 2: + { + char *name1 = strVal(lfirst(cref->fields)); + char *name2 = strVal(lsecond(cref->fields)); - /* - * try to find the ident as a relation ... but not if subscripts - * appear - */ - if (ident->indirection == NIL && - refnameRangeTblEntry(pstate, ident->name, &sublevels_up) != NULL) - { - ident->isRel = TRUE; - result = (Node *) ident; - } + /* Whole-row reference? */ + if (strcmp(name2, "*") == 0) + { + rv = makeNode(RangeVar); + rv->relname = name1; + rv->inhOpt = INH_DEFAULT; + node = (Node *) rv; + break; + } - if (result == NULL || precedence == EXPR_COLUMN_FIRST) - { - /* try to find the ident as a column */ - Node *var = colnameToVar(pstate, ident->name); + /* Try to identify as a once-qualified column */ + node = qualifiedNameToVar(pstate, name1, name2, true); + if (node == NULL) + { + /* + * Not known as a column of any range-table entry, so + * try it as a function call. Here, we will create an + * implicit RTE for tables not already entered. + */ + rv = makeNode(RangeVar); + rv->relname = name1; + rv->inhOpt = INH_DEFAULT; + node = ParseFuncOrColumn(pstate, name2, + makeList1(rv), + false, false, true); + } + break; + } + case 3: + { + char *name1 = strVal(lfirst(cref->fields)); + char *name2 = strVal(lsecond(cref->fields)); + char *name3 = strVal(lfirst(lnext(lnext(cref->fields)))); - if (var != NULL) + /* Whole-row reference? */ + if (strcmp(name3, "*") == 0) + { + rv = makeNode(RangeVar); + rv->schemaname = name1; + rv->relname = name2; + rv->inhOpt = INH_DEFAULT; + node = (Node *) rv; + break; + } + + /* Try to identify as a twice-qualified column */ + /* XXX do something with schema name here */ + node = qualifiedNameToVar(pstate, name2, name3, true); + if (node == NULL) + { + /* Try it as a function call */ + rv = makeNode(RangeVar); + rv->schemaname = name1; + rv->relname = name2; + rv->inhOpt = INH_DEFAULT; + node = ParseFuncOrColumn(pstate, name3, + makeList1(rv), + false, false, true); + } + break; + } + case 4: { - ident->isRel = FALSE; - result = transformIndirection(pstate, var, ident->indirection); + char *name1 = strVal(lfirst(cref->fields)); + char *name2 = strVal(lsecond(cref->fields)); + char *name3 = strVal(lfirst(lnext(lnext(cref->fields)))); + char *name4 = strVal(lfirst(lnext(lnext(lnext(cref->fields))))); + + /* + * We check the catalog name and then ignore it. + */ + if (strcmp(name1, DatabaseName) != 0) + elog(ERROR, "Cross-database references are not implemented"); + + /* Whole-row reference? */ + if (strcmp(name4, "*") == 0) + { + rv = makeNode(RangeVar); + rv->schemaname = name2; + rv->relname = name3; + rv->inhOpt = INH_DEFAULT; + node = (Node *) rv; + break; + } + + /* Try to identify as a twice-qualified column */ + /* XXX do something with schema name here */ + node = qualifiedNameToVar(pstate, name3, name4, true); + if (node == NULL) + { + /* Try it as a function call */ + rv = makeNode(RangeVar); + rv->schemaname = name2; + rv->relname = name3; + rv->inhOpt = INH_DEFAULT; + node = ParseFuncOrColumn(pstate, name4, + makeList1(rv), + false, false, true); + } + break; } + default: + elog(ERROR, "Invalid qualified name syntax (too many names)"); + node = NULL; /* keep compiler quiet */ + break; } - if (result == NULL) - elog(ERROR, "Attribute '%s' not found", ident->name); - - return result; + return transformIndirection(pstate, node, cref->indirection); } /* @@ -748,10 +894,6 @@ exprType(Node *expr) case T_BooleanTest: type = BOOLOID; break; - case T_Ident: - /* XXX is this right? */ - type = UNKNOWNOID; - break; default: elog(ERROR, "Do not know how to get type for %d node", nodeTag(expr)); |