1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

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.
This commit is contained in:
Tom Lane
2002-03-21 16:02:16 +00:00
parent 8c9c8ca2b5
commit 95ef6a3448
52 changed files with 2039 additions and 1535 deletions

View File

@ -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;
basenode = ParseNestedFuncOrColumn(pstate, att, precedence);
return transformIndirection(pstate, basenode, att->indirection);
}
static Node *
transformIdent(ParseState *pstate, Ident *ident, int precedence)
{
Node *result = NULL;
int sublevels_up;
/*
* try to find the ident as a relation ... but not if subscripts
* appear
/*----------
* 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.)
*----------
*/
if (ident->indirection == NIL &&
refnameRangeTblEntry(pstate, ident->name, &sublevels_up) != NULL)
switch (numnames)
{
ident->isRel = TRUE;
result = (Node *) ident;
}
if (result == NULL || precedence == EXPR_COLUMN_FIRST)
{
/* try to find the ident as a column */
Node *var = colnameToVar(pstate, ident->name);
if (var != NULL)
case 1:
{
ident->isRel = FALSE;
result = transformIndirection(pstate, var, ident->indirection);
char *name = strVal(lfirst(cref->fields));
/* 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;
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));
/* Whole-row reference? */
if (strcmp(name2, "*") == 0)
{
rv = makeNode(RangeVar);
rv->relname = name1;
rv->inhOpt = INH_DEFAULT;
node = (Node *) rv;
break;
}
/* 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))));
/* 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:
{
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));