aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-03-21 16:02:16 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-03-21 16:02:16 +0000
commit95ef6a344821655ce4d0a74999ac49dd6af6d342 (patch)
treedf484a4c9dde9827894ab707917c001a1f376749 /src/backend/parser/parse_expr.c
parent8c9c8ca2b57e4edef218245ccdc9eef7c06425d8 (diff)
downloadpostgresql-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.c322
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));