Commit a341a96c authored by Neil Conway's avatar Neil Conway

Refactor transformExpr() by creating separate functions for most of the

expression types.
parent a73198ac
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.179 2005/01/12 17:32:36 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.180 2005/01/19 23:45:24 neilc Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -37,9 +37,27 @@
bool Transform_null_equals = false;
static Node *transformParamRef(ParseState *pstate, ParamRef *pref);
static Node *transformAExprOp(ParseState *pstate, A_Expr *a);
static Node *transformAExprAnd(ParseState *pstate, A_Expr *a);
static Node *transformAExprOr(ParseState *pstate, A_Expr *a);
static Node *transformAExprNot(ParseState *pstate, A_Expr *a);
static Node *transformAExprOpAny(ParseState *pstate, A_Expr *a);
static Node *transformAExprOpAll(ParseState *pstate, A_Expr *a);
static Node *transformAExprDistinct(ParseState *pstate, A_Expr *a);
static Node *transformAExprNullIf(ParseState *pstate, A_Expr *a);
static Node *transformAExprOf(ParseState *pstate, A_Expr *a);
static Node *transformFuncCall(ParseState *pstate, FuncCall *fn);
static Node *transformCaseExpr(ParseState *pstate, CaseExpr *c);
static Node *transformSubLink(ParseState *pstate, SubLink *sublink);
static Node *transformArrayExpr(ParseState *pstate, ArrayExpr *a);
static Node *transformRowExpr(ParseState *pstate, RowExpr *r);
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
char *relname);
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection);
static Node *typecast_expression(ParseState *pstate, Node *expr,
......@@ -90,65 +108,13 @@ transformExpr(ParseState *pstate, Node *expr)
switch (nodeTag(expr))
{
case T_ColumnRef:
{
result = transformColumnRef(pstate, (ColumnRef *) expr);
break;
}
case T_ParamRef:
{
ParamRef *pref = (ParamRef *) expr;
int paramno = pref->number;
ParseState *toppstate;
Param *param;
/*
* Find topmost ParseState, which is where paramtype info
* lives.
*/
toppstate = pstate;
while (toppstate->parentParseState != NULL)
toppstate = toppstate->parentParseState;
result = transformColumnRef(pstate, (ColumnRef *) expr);
break;
/* Check parameter number is in range */
if (paramno <= 0) /* probably can't happen? */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_PARAMETER),
errmsg("there is no parameter $%d", paramno)));
if (paramno > toppstate->p_numparams)
{
if (!toppstate->p_variableparams)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_PARAMETER),
errmsg("there is no parameter $%d",
paramno)));
/* Okay to enlarge param array */
if (toppstate->p_paramtypes)
toppstate->p_paramtypes =
(Oid *) repalloc(toppstate->p_paramtypes,
paramno * sizeof(Oid));
else
toppstate->p_paramtypes =
(Oid *) palloc(paramno * sizeof(Oid));
/* Zero out the previously-unreferenced slots */
MemSet(toppstate->p_paramtypes + toppstate->p_numparams,
0,
(paramno - toppstate->p_numparams) * sizeof(Oid));
toppstate->p_numparams = paramno;
}
if (toppstate->p_variableparams)
{
/* If not seen before, initialize to UNKNOWN type */
if (toppstate->p_paramtypes[paramno - 1] == InvalidOid)
toppstate->p_paramtypes[paramno - 1] = UNKNOWNOID;
}
case T_ParamRef:
result = transformParamRef(pstate, (ParamRef *) expr);
break;
param = makeNode(Param);
param->paramkind = PARAM_NUM;
param->paramid = (AttrNumber) paramno;
param->paramtype = toppstate->p_paramtypes[paramno - 1];
result = (Node *) param;
break;
}
case T_A_Const:
{
A_Const *con = (A_Const *) expr;
......@@ -160,6 +126,7 @@ transformExpr(ParseState *pstate, Node *expr)
con->typename);
break;
}
case T_A_Indirection:
{
A_Indirection *ind = (A_Indirection *) expr;
......@@ -169,6 +136,7 @@ transformExpr(ParseState *pstate, Node *expr)
ind->indirection);
break;
}
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
......@@ -177,6 +145,7 @@ transformExpr(ParseState *pstate, Node *expr)
result = typecast_expression(pstate, arg, tc->typename);
break;
}
case T_A_Expr:
{
A_Expr *a = (A_Expr *) expr;
......@@ -184,701 +153,61 @@ transformExpr(ParseState *pstate, Node *expr)
switch (a->kind)
{
case AEXPR_OP:
{
Node *lexpr = a->lexpr;
Node *rexpr = a->rexpr;
/*
* Special-case "foo = NULL" and "NULL = foo"
* for compatibility with standards-broken
* products (like Microsoft's). Turn these
* into IS NULL exprs.
*/
if (Transform_null_equals &&
list_length(a->name) == 1 &&
strcmp(strVal(linitial(a->name)), "=") == 0 &&
(exprIsNullConstant(lexpr) ||
exprIsNullConstant(rexpr)))
{
NullTest *n = makeNode(NullTest);
n->nulltesttype = IS_NULL;
if (exprIsNullConstant(lexpr))
n->arg = (Expr *) rexpr;
else
n->arg = (Expr *) lexpr;
result = transformExpr(pstate,
(Node *) n);
}
else if (lexpr && IsA(lexpr, RowExpr) &&
rexpr && IsA(rexpr, SubLink) &&
((SubLink *) rexpr)->subLinkType == EXPR_SUBLINK)
{
/*
* Convert "row op subselect" into a
* MULTIEXPR sublink. Formerly the
* grammar did this, but now that a row
* construct is allowed anywhere in
* expressions, it's easier to do it here.
*/
SubLink *s = (SubLink *) rexpr;
s->subLinkType = MULTIEXPR_SUBLINK;
s->lefthand = ((RowExpr *) lexpr)->args;
s->operName = a->name;
result = transformExpr(pstate, (Node *) s);
}
else if (lexpr && IsA(lexpr, RowExpr) &&
rexpr && IsA(rexpr, RowExpr))
{
/* "row op row" */
result = make_row_op(pstate, a->name,
lexpr, rexpr);
}
else
{
/* Ordinary scalar operator */
lexpr = transformExpr(pstate, lexpr);
rexpr = transformExpr(pstate, rexpr);
result = (Node *) make_op(pstate,
a->name,
lexpr,
rexpr);
}
}
result = transformAExprOp(pstate, a);
break;
case AEXPR_AND:
{
Node *lexpr = transformExpr(pstate,
a->lexpr);
Node *rexpr = transformExpr(pstate,
a->rexpr);
lexpr = coerce_to_boolean(pstate, lexpr, "AND");
rexpr = coerce_to_boolean(pstate, rexpr, "AND");
result = (Node *) makeBoolExpr(AND_EXPR,
list_make2(lexpr,
rexpr));
}
result = transformAExprAnd(pstate, a);
break;
case AEXPR_OR:
{
Node *lexpr = transformExpr(pstate,
a->lexpr);
Node *rexpr = transformExpr(pstate,
a->rexpr);
lexpr = coerce_to_boolean(pstate, lexpr, "OR");
rexpr = coerce_to_boolean(pstate, rexpr, "OR");
result = (Node *) makeBoolExpr(OR_EXPR,
list_make2(lexpr,
rexpr));
}
result = transformAExprOr(pstate, a);
break;
case AEXPR_NOT:
{
Node *rexpr = transformExpr(pstate,
a->rexpr);
rexpr = coerce_to_boolean(pstate, rexpr, "NOT");
result = (Node *) makeBoolExpr(NOT_EXPR,
list_make1(rexpr));
}
result = transformAExprNot(pstate, a);
break;
case AEXPR_OP_ANY:
{
Node *lexpr = transformExpr(pstate,
a->lexpr);
Node *rexpr = transformExpr(pstate,
a->rexpr);
result = (Node *) make_scalar_array_op(pstate,
a->name,
true,
lexpr,
rexpr);
}
result = transformAExprOpAny(pstate, a);
break;
case AEXPR_OP_ALL:
{
Node *lexpr = transformExpr(pstate,
a->lexpr);
Node *rexpr = transformExpr(pstate,
a->rexpr);
result = (Node *) make_scalar_array_op(pstate,
a->name,
false,
lexpr,
rexpr);
}
result = transformAExprOpAll(pstate, a);
break;
case AEXPR_DISTINCT:
{
Node *lexpr = a->lexpr;
Node *rexpr = a->rexpr;
if (lexpr && IsA(lexpr, RowExpr) &&
rexpr && IsA(rexpr, RowExpr))
{
/* "row op row" */
result = make_row_distinct_op(pstate, a->name,
lexpr, rexpr);
}
else
{
/* Ordinary scalar operator */
lexpr = transformExpr(pstate, lexpr);
rexpr = transformExpr(pstate, rexpr);
result = (Node *) make_distinct_op(pstate,
a->name,
lexpr,
rexpr);
}
}
result = transformAExprDistinct(pstate, a);
break;
case AEXPR_NULLIF:
{
Node *lexpr = transformExpr(pstate,
a->lexpr);
Node *rexpr = transformExpr(pstate,
a->rexpr);
result = (Node *) make_op(pstate,
a->name,
lexpr,
rexpr);
if (((OpExpr *) result)->opresulttype != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("NULLIF requires = operator to yield boolean")));
/*
* We rely on NullIfExpr and OpExpr being same
* struct
*/
NodeSetTag(result, T_NullIfExpr);
}
result = transformAExprNullIf(pstate, a);
break;
case AEXPR_OF:
{
/*
* Checking an expression for match to type.
* Will result in a boolean constant node.
*/
ListCell *telem;
A_Const *n;
Oid ltype,
rtype;
bool matched = FALSE;
Node *lexpr = transformExpr(pstate,
a->lexpr);
ltype = exprType(lexpr);
foreach(telem, (List *) a->rexpr)
{
rtype = LookupTypeName(lfirst(telem));
matched = (rtype == ltype);
if (matched)
break;
}
/*
* Expect two forms: equals or not equals.
* Flip the sense of the result for not
* equals.
*/
if (strcmp(strVal(linitial(a->name)), "!=") == 0)
matched = (!matched);
n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = (matched ? "t" : "f");
n->typename = SystemTypeName("bool");
result = transformExpr(pstate, (Node *) n);
}
result = transformAExprOf(pstate, a);
break;
default:
elog(ERROR, "unrecognized A_Expr kind: %d", a->kind);
}
break;
}
case T_FuncCall:
{
FuncCall *fn = (FuncCall *) expr;
List *targs;
ListCell *args;
result = transformFuncCall(pstate, (FuncCall *) expr);
break;
/*
* Transform the list of arguments. We use a shallow list
* copy and then transform-in-place to avoid O(N^2)
* behavior from repeated lappend's.
*
* XXX: repeated lappend() would no longer result in O(n^2)
* behavior; worth reconsidering this design?
*/
targs = list_copy(fn->args);
foreach(args, targs)
{
lfirst(args) = transformExpr(pstate,
(Node *) lfirst(args));
}
result = ParseFuncOrColumn(pstate,
fn->funcname,
targs,
fn->agg_star,
fn->agg_distinct,
false);
break;
}
case T_SubLink:
{
SubLink *sublink = (SubLink *) expr;
List *qtrees;
Query *qtree;
/* If we already transformed this node, do nothing */
if (IsA(sublink->subselect, Query))
{
result = expr;
break;
}
pstate->p_hasSubLinks = true;
qtrees = parse_sub_analyze(sublink->subselect, pstate);
if (list_length(qtrees) != 1)
elog(ERROR, "bad query in sub-select");
qtree = (Query *) linitial(qtrees);
if (qtree->commandType != CMD_SELECT ||
qtree->resultRelation != 0)
elog(ERROR, "bad query in sub-select");
sublink->subselect = (Node *) qtree;
if (sublink->subLinkType == EXISTS_SUBLINK)
{
/*
* EXISTS needs no lefthand or combining operator.
* These fields should be NIL already, but make sure.
*/
sublink->lefthand = NIL;
sublink->operName = NIL;
sublink->operOids = NIL;
sublink->useOr = FALSE;
}
else if (sublink->subLinkType == EXPR_SUBLINK ||
sublink->subLinkType == ARRAY_SUBLINK)
{
ListCell *tlist_item = list_head(qtree->targetList);
/*
* Make sure the subselect delivers a single column
* (ignoring resjunk targets).
*/
if (tlist_item == NULL ||
((TargetEntry *) lfirst(tlist_item))->resdom->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery must return a column")));
while ((tlist_item = lnext(tlist_item)) != NULL)
{
if (!((TargetEntry *) lfirst(tlist_item))->resdom->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery must return only one column")));
}
/*
* EXPR and ARRAY need no lefthand or combining
* operator. These fields should be NIL already, but
* make sure.
*/
sublink->lefthand = NIL;
sublink->operName = NIL;
sublink->operOids = NIL;
sublink->useOr = FALSE;
}
else
{
/* ALL, ANY, or MULTIEXPR: generate operator list */
List *left_list = sublink->lefthand;
List *right_list = qtree->targetList;
int row_length = list_length(left_list);
bool needNot = false;
List *op = sublink->operName;
char *opname = strVal(llast(op));
ListCell *l;
ListCell *ll_item;
/* transform lefthand expressions */
foreach(l, left_list)
lfirst(l) = transformExpr(pstate, lfirst(l));
/*
* If the expression is "<> ALL" (with unqualified
* opname) then convert it to "NOT IN". This is a
* hack to improve efficiency of expressions output by
* pre-7.4 Postgres.
*/
if (sublink->subLinkType == ALL_SUBLINK &&
list_length(op) == 1 && strcmp(opname, "<>") == 0)
{
sublink->subLinkType = ANY_SUBLINK;
opname = pstrdup("=");
op = list_make1(makeString(opname));
sublink->operName = op;
needNot = true;
}
/* Set useOr if op is "<>" (possibly qualified) */
if (strcmp(opname, "<>") == 0)
sublink->useOr = TRUE;
else
sublink->useOr = FALSE;
/* Combining operators other than =/<> is dubious... */
if (row_length != 1 &&
strcmp(opname, "=") != 0 &&
strcmp(opname, "<>") != 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("row comparison cannot use operator %s",
opname)));
/*
* To build the list of combining operator OIDs, we
* must scan subquery's targetlist to find values that
* will be matched against lefthand values. We need
* to ignore resjunk targets, so doing the outer
* iteration over right_list is easier than doing it
* over left_list.
*/
sublink->operOids = NIL;
ll_item = list_head(left_list);
foreach(l, right_list)
{
TargetEntry *tent = (TargetEntry *) lfirst(l);
Node *lexpr;
Operator optup;
Form_pg_operator opform;
if (tent->resdom->resjunk)
continue;
if (ll_item == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery has too many columns")));
lexpr = lfirst(ll_item);
ll_item = lnext(ll_item);
/*
* It's OK to use oper() not compatible_oper()
* here, because make_subplan() will insert type
* coercion calls if needed.
*/
optup = oper(op,
exprType(lexpr),
exprType((Node *) tent->expr),
false);
opform = (Form_pg_operator) GETSTRUCT(optup);
if (opform->oprresult != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("operator %s must return type boolean, not type %s",
opname,
format_type_be(opform->oprresult)),
errhint("The operator of a quantified predicate subquery must return type boolean.")));
if (get_func_retset(opform->oprcode))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("operator %s must not return a set",
opname),
errhint("The operator of a quantified predicate subquery must return type boolean.")));
sublink->operOids = lappend_oid(sublink->operOids,
oprid(optup));
ReleaseSysCache(optup);
}
if (ll_item != NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery has too few columns")));
if (needNot)
{
expr = coerce_to_boolean(pstate, expr, "NOT");
expr = (Node *) makeBoolExpr(NOT_EXPR,
list_make1(expr));
}
}
result = (Node *) expr;
break;
}
result = transformSubLink(pstate, (SubLink *) expr);
break;
case T_CaseExpr:
{
CaseExpr *c = (CaseExpr *) expr;
CaseExpr *newc;
Node *arg;
CaseTestExpr *placeholder;
List *newargs;
List *typeids;
ListCell *l;
Node *defresult;
Oid ptype;
/* If we already transformed this node, do nothing */
if (OidIsValid(c->casetype))
{
result = expr;
break;
}
newc = makeNode(CaseExpr);
/* transform the test expression, if any */
arg = transformExpr(pstate, (Node *) c->arg);
/* generate placeholder for test expression */
if (arg)
{
/*
* If test expression is an untyped literal, force it to
* text. We have to do something now because we won't be
* able to do this coercion on the placeholder. This is
* not as flexible as what was done in 7.4 and before,
* but it's good enough to handle the sort of silly
* coding commonly seen.
*/
if (exprType(arg) == UNKNOWNOID)
arg = coerce_to_common_type(pstate, arg,
TEXTOID, "CASE");
placeholder = makeNode(CaseTestExpr);
placeholder->typeId = exprType(arg);
placeholder->typeMod = exprTypmod(arg);
}
else
placeholder = NULL;
newc->arg = (Expr *) arg;
/* transform the list of arguments */
newargs = NIL;
typeids = NIL;
foreach(l, c->args)
{
CaseWhen *w = (CaseWhen *) lfirst(l);
CaseWhen *neww = makeNode(CaseWhen);
Node *warg;
Assert(IsA(w, CaseWhen));
warg = (Node *) w->expr;
if (placeholder)
{
/* shorthand form was specified, so expand... */
warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
(Node *) placeholder,
warg);
}
neww->expr = (Expr *) transformExpr(pstate, warg);
neww->expr = (Expr *) coerce_to_boolean(pstate,
(Node *) neww->expr,
"CASE/WHEN");
warg = (Node *) w->result;
neww->result = (Expr *) transformExpr(pstate, warg);
newargs = lappend(newargs, neww);
typeids = lappend_oid(typeids, exprType((Node *) neww->result));
}
newc->args = newargs;
/* transform the default clause */
defresult = (Node *) c->defresult;
if (defresult == NULL)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
defresult = (Node *) n;
}
newc->defresult = (Expr *) transformExpr(pstate, defresult);
/*
* Note: default result is considered the most significant
* type in determining preferred type. This is how the
* code worked before, but it seems a little bogus to me
* --- tgl
*/
typeids = lcons_oid(exprType((Node *) newc->defresult), typeids);
ptype = select_common_type(typeids, "CASE");
Assert(OidIsValid(ptype));
newc->casetype = ptype;
/* Convert default result clause, if necessary */
newc->defresult = (Expr *)
coerce_to_common_type(pstate,
(Node *) newc->defresult,
ptype,
"CASE/ELSE");
/* Convert when-clause results, if necessary */
foreach(l, newc->args)
{
CaseWhen *w = (CaseWhen *) lfirst(l);
w->result = (Expr *)
coerce_to_common_type(pstate,
(Node *) w->result,
ptype,
"CASE/WHEN");
}
result = (Node *) newc;
break;
}
result = transformCaseExpr(pstate, (CaseExpr *) expr);
break;
case T_ArrayExpr:
{
ArrayExpr *a = (ArrayExpr *) expr;
ArrayExpr *newa = makeNode(ArrayExpr);
List *newelems = NIL;
List *newcoercedelems = NIL;
List *typeids = NIL;
ListCell *element;
Oid array_type;
Oid element_type;
/* Transform the element expressions */
foreach(element, a->elements)
{
Node *e = (Node *) lfirst(element);
Node *newe;
newe = transformExpr(pstate, e);
newelems = lappend(newelems, newe);
typeids = lappend_oid(typeids, exprType(newe));
}
/* Select a common type for the elements */
element_type = select_common_type(typeids, "ARRAY");
/* Coerce arguments to common type if necessary */
foreach(element, newelems)
{
Node *e = (Node *) lfirst(element);
Node *newe;
newe = coerce_to_common_type(pstate, e,
element_type,
"ARRAY");
newcoercedelems = lappend(newcoercedelems, newe);
}
/* Do we have an array type to use? */
array_type = get_array_type(element_type);
if (array_type != InvalidOid)
{
/* Elements are presumably of scalar type */
newa->multidims = false;
}
else
{
/* Must be nested array expressions */
newa->multidims = true;
array_type = element_type;
element_type = get_element_type(array_type);
if (!OidIsValid(element_type))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("could not find array type for data type %s",
format_type_be(array_type))));
}
newa->array_typeid = array_type;
newa->element_typeid = element_type;
newa->elements = newcoercedelems;
result = (Node *) newa;
break;
}
result = transformArrayExpr(pstate, (ArrayExpr *) expr);
break;
case T_RowExpr:
{
RowExpr *r = (RowExpr *) expr;
RowExpr *newr = makeNode(RowExpr);
List *newargs = NIL;
ListCell *arg;
/* Transform the field expressions */
foreach(arg, r->args)
{
Node *e = (Node *) lfirst(arg);
Node *newe;
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
}
newr->args = newargs;
/* Barring later casting, we consider the type RECORD */
newr->row_typeid = RECORDOID;
newr->row_format = COERCE_IMPLICIT_CAST;
result = (Node *) newr;
break;
}
result = transformRowExpr(pstate, (RowExpr *) expr);
break;
case T_CoalesceExpr:
{
CoalesceExpr *c = (CoalesceExpr *) expr;
CoalesceExpr *newc = makeNode(CoalesceExpr);
List *newargs = NIL;
List *newcoercedargs = NIL;
List *typeids = NIL;
ListCell *args;
foreach(args, c->args)
{
Node *e = (Node *) lfirst(args);
Node *newe;
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
typeids = lappend_oid(typeids, exprType(newe));
}
newc->coalescetype = select_common_type(typeids, "COALESCE");
/* Convert arguments if necessary */
foreach(args, newargs)
{
Node *e = (Node *) lfirst(args);
Node *newe;
newe = coerce_to_common_type(pstate, e,
newc->coalescetype,
"COALESCE");
newcoercedargs = lappend(newcoercedargs, newe);
}
newc->args = newcoercedargs;
result = (Node *) newc;
break;
}
result = transformCoalesceExpr(pstate, (CoalesceExpr *) expr);
break;
case T_NullTest:
{
......@@ -891,45 +220,8 @@ transformExpr(ParseState *pstate, Node *expr)
}
case T_BooleanTest:
{
BooleanTest *b = (BooleanTest *) expr;
const char *clausename;
switch (b->booltesttype)
{
case IS_TRUE:
clausename = "IS TRUE";
break;
case IS_NOT_TRUE:
clausename = "IS NOT TRUE";
break;
case IS_FALSE:
clausename = "IS FALSE";
break;
case IS_NOT_FALSE:
clausename = "IS NOT FALSE";
break;
case IS_UNKNOWN:
clausename = "IS UNKNOWN";
break;
case IS_NOT_UNKNOWN:
clausename = "IS NOT UNKNOWN";
break;
default:
elog(ERROR, "unrecognized booltesttype: %d",
(int) b->booltesttype);
clausename = NULL; /* keep compiler quiet */
}
b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg);
b->arg = (Expr *) coerce_to_boolean(pstate,
(Node *) b->arg,
clausename);
result = expr;
break;
}
result = transformBooleanTest(pstate, (BooleanTest *) expr);
break;
/*********************************************
* Quietly accept node types that may be presented when we are
......@@ -1203,6 +495,780 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
return node;
}
static Node *
transformParamRef(ParseState *pstate, ParamRef *pref)
{
int paramno = pref->number;
ParseState *toppstate;
Param *param;
/*
* Find topmost ParseState, which is where paramtype info lives.
*/
toppstate = pstate;
while (toppstate->parentParseState != NULL)
toppstate = toppstate->parentParseState;
/* Check parameter number is in range */
if (paramno <= 0) /* probably can't happen? */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_PARAMETER),
errmsg("there is no parameter $%d", paramno)));
if (paramno > toppstate->p_numparams)
{
if (!toppstate->p_variableparams)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_PARAMETER),
errmsg("there is no parameter $%d",
paramno)));
/* Okay to enlarge param array */
if (toppstate->p_paramtypes)
toppstate->p_paramtypes =
(Oid *) repalloc(toppstate->p_paramtypes,
paramno * sizeof(Oid));
else
toppstate->p_paramtypes =
(Oid *) palloc(paramno * sizeof(Oid));
/* Zero out the previously-unreferenced slots */
MemSet(toppstate->p_paramtypes + toppstate->p_numparams,
0,
(paramno - toppstate->p_numparams) * sizeof(Oid));
toppstate->p_numparams = paramno;
}
if (toppstate->p_variableparams)
{
/* If not seen before, initialize to UNKNOWN type */
if (toppstate->p_paramtypes[paramno - 1] == InvalidOid)
toppstate->p_paramtypes[paramno - 1] = UNKNOWNOID;
}
param = makeNode(Param);
param->paramkind = PARAM_NUM;
param->paramid = (AttrNumber) paramno;
param->paramtype = toppstate->p_paramtypes[paramno - 1];
return (Node *) param;
}
static Node *
transformAExprOp(ParseState *pstate, A_Expr *a)
{
Node *lexpr = a->lexpr;
Node *rexpr = a->rexpr;
Node *result;
/*
* Special-case "foo = NULL" and "NULL = foo" for compatibility
* with standards-broken products (like Microsoft's). Turn these
* into IS NULL exprs.
*/
if (Transform_null_equals &&
list_length(a->name) == 1 &&
strcmp(strVal(linitial(a->name)), "=") == 0 &&
(exprIsNullConstant(lexpr) || exprIsNullConstant(rexpr)))
{
NullTest *n = makeNode(NullTest);
n->nulltesttype = IS_NULL;
if (exprIsNullConstant(lexpr))
n->arg = (Expr *) rexpr;
else
n->arg = (Expr *) lexpr;
result = transformExpr(pstate, (Node *) n);
}
else if (lexpr && IsA(lexpr, RowExpr) &&
rexpr && IsA(rexpr, SubLink) &&
((SubLink *) rexpr)->subLinkType == EXPR_SUBLINK)
{
/*
* Convert "row op subselect" into a MULTIEXPR sublink.
* Formerly the grammar did this, but now that a row construct
* is allowed anywhere in expressions, it's easier to do it
* here.
*/
SubLink *s = (SubLink *) rexpr;
s->subLinkType = MULTIEXPR_SUBLINK;
s->lefthand = ((RowExpr *) lexpr)->args;
s->operName = a->name;
result = transformExpr(pstate, (Node *) s);
}
else if (lexpr && IsA(lexpr, RowExpr) &&
rexpr && IsA(rexpr, RowExpr))
{
/* "row op row" */
result = make_row_op(pstate, a->name, lexpr, rexpr);
}
else
{
/* Ordinary scalar operator */
lexpr = transformExpr(pstate, lexpr);
rexpr = transformExpr(pstate, rexpr);
result = (Node *) make_op(pstate,
a->name,
lexpr,
rexpr);
}
return result;
}
static Node *
transformAExprAnd(ParseState *pstate, A_Expr *a)
{
Node *lexpr = transformExpr(pstate, a->lexpr);
Node *rexpr = transformExpr(pstate, a->rexpr);
lexpr = coerce_to_boolean(pstate, lexpr, "AND");
rexpr = coerce_to_boolean(pstate, rexpr, "AND");
return (Node *) makeBoolExpr(AND_EXPR,
list_make2(lexpr, rexpr));
}
static Node *
transformAExprOr(ParseState *pstate, A_Expr *a)
{
Node *lexpr = transformExpr(pstate, a->lexpr);
Node *rexpr = transformExpr(pstate, a->rexpr);
lexpr = coerce_to_boolean(pstate, lexpr, "OR");
rexpr = coerce_to_boolean(pstate, rexpr, "OR");
return (Node *) makeBoolExpr(OR_EXPR,
list_make2(lexpr, rexpr));
}
static Node *
transformAExprNot(ParseState *pstate, A_Expr *a)
{
Node *rexpr = transformExpr(pstate, a->rexpr);
rexpr = coerce_to_boolean(pstate, rexpr, "NOT");
return (Node *) makeBoolExpr(NOT_EXPR,
list_make1(rexpr));
}
static Node *
transformAExprOpAny(ParseState *pstate, A_Expr *a)
{
Node *lexpr = transformExpr(pstate, a->lexpr);
Node *rexpr = transformExpr(pstate, a->rexpr);
return (Node *) make_scalar_array_op(pstate,
a->name,
true,
lexpr,
rexpr);
}
static Node *
transformAExprOpAll(ParseState *pstate, A_Expr *a)
{
Node *lexpr = transformExpr(pstate, a->lexpr);
Node *rexpr = transformExpr(pstate, a->rexpr);
return (Node *) make_scalar_array_op(pstate,
a->name,
false,
lexpr,
rexpr);
}
static Node *
transformAExprDistinct(ParseState *pstate, A_Expr *a)
{
Node *lexpr = a->lexpr;
Node *rexpr = a->rexpr;
if (lexpr && IsA(lexpr, RowExpr) &&
rexpr && IsA(rexpr, RowExpr))
{
/* "row op row" */
return make_row_distinct_op(pstate, a->name,
lexpr, rexpr);
}
else
{
/* Ordinary scalar operator */
lexpr = transformExpr(pstate, lexpr);
rexpr = transformExpr(pstate, rexpr);
return (Node *) make_distinct_op(pstate,
a->name,
lexpr,
rexpr);
}
}
static Node *
transformAExprNullIf(ParseState *pstate, A_Expr *a)
{
Node *lexpr = transformExpr(pstate, a->lexpr);
Node *rexpr = transformExpr(pstate, a->rexpr);
Node *result;
result = (Node *) make_op(pstate,
a->name,
lexpr,
rexpr);
if (((OpExpr *) result)->opresulttype != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("NULLIF requires = operator to yield boolean")));
/*
* We rely on NullIfExpr and OpExpr being the same struct
*/
NodeSetTag(result, T_NullIfExpr);
return result;
}
static Node *
transformAExprOf(ParseState *pstate, A_Expr *a)
{
/*
* Checking an expression for match to type. Will result in a
* boolean constant node.
*/
ListCell *telem;
A_Const *n;
Oid ltype,
rtype;
bool matched = false;
Node *lexpr = transformExpr(pstate, a->lexpr);
ltype = exprType(lexpr);
foreach(telem, (List *) a->rexpr)
{
rtype = LookupTypeName(lfirst(telem));
matched = (rtype == ltype);
if (matched)
break;
}
/*
* Expect two forms: equals or not equals. Flip the sense of the
* result for not equals.
*/
if (strcmp(strVal(linitial(a->name)), "!=") == 0)
matched = (!matched);
n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = (matched ? "t" : "f");
n->typename = SystemTypeName("bool");
return transformExpr(pstate, (Node *) n);
}
static Node *
transformFuncCall(ParseState *pstate, FuncCall *fn)
{
List *targs;
ListCell *args;
/*
* Transform the list of arguments. We use a shallow list copy
* and then transform-in-place to avoid O(N^2) behavior from
* repeated lappend's.
*
* XXX: repeated lappend() would no longer result in O(n^2)
* behavior; worth reconsidering this design?
*/
targs = list_copy(fn->args);
foreach(args, targs)
{
lfirst(args) = transformExpr(pstate,
(Node *) lfirst(args));
}
return ParseFuncOrColumn(pstate,
fn->funcname,
targs,
fn->agg_star,
fn->agg_distinct,
false);
}
static Node *
transformCaseExpr(ParseState *pstate, CaseExpr *c)
{
CaseExpr *newc;
Node *arg;
CaseTestExpr *placeholder;
List *newargs;
List *typeids;
ListCell *l;
Node *defresult;
Oid ptype;
/* If we already transformed this node, do nothing */
if (OidIsValid(c->casetype))
return (Node *) c;
newc = makeNode(CaseExpr);
/* transform the test expression, if any */
arg = transformExpr(pstate, (Node *) c->arg);
/* generate placeholder for test expression */
if (arg)
{
/*
* If test expression is an untyped literal, force it to text.
* We have to do something now because we won't be able to do
* this coercion on the placeholder. This is not as flexible
* as what was done in 7.4 and before, but it's good enough to
* handle the sort of silly coding commonly seen.
*/
if (exprType(arg) == UNKNOWNOID)
arg = coerce_to_common_type(pstate, arg, TEXTOID, "CASE");
placeholder = makeNode(CaseTestExpr);
placeholder->typeId = exprType(arg);
placeholder->typeMod = exprTypmod(arg);
}
else
placeholder = NULL;
newc->arg = (Expr *) arg;
/* transform the list of arguments */
newargs = NIL;
typeids = NIL;
foreach(l, c->args)
{
CaseWhen *w = (CaseWhen *) lfirst(l);
CaseWhen *neww = makeNode(CaseWhen);
Node *warg;
Assert(IsA(w, CaseWhen));
warg = (Node *) w->expr;
if (placeholder)
{
/* shorthand form was specified, so expand... */
warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
(Node *) placeholder,
warg);
}
neww->expr = (Expr *) transformExpr(pstate, warg);
neww->expr = (Expr *) coerce_to_boolean(pstate,
(Node *) neww->expr,
"CASE/WHEN");
warg = (Node *) w->result;
neww->result = (Expr *) transformExpr(pstate, warg);
newargs = lappend(newargs, neww);
typeids = lappend_oid(typeids, exprType((Node *) neww->result));
}
newc->args = newargs;
/* transform the default clause */
defresult = (Node *) c->defresult;
if (defresult == NULL)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
defresult = (Node *) n;
}
newc->defresult = (Expr *) transformExpr(pstate, defresult);
/*
* Note: default result is considered the most significant type in
* determining preferred type. This is how the code worked before,
* but it seems a little bogus to me
* --- tgl
*/
typeids = lcons_oid(exprType((Node *) newc->defresult), typeids);
ptype = select_common_type(typeids, "CASE");
Assert(OidIsValid(ptype));
newc->casetype = ptype;
/* Convert default result clause, if necessary */
newc->defresult = (Expr *)
coerce_to_common_type(pstate,
(Node *) newc->defresult,
ptype,
"CASE/ELSE");
/* Convert when-clause results, if necessary */
foreach(l, newc->args)
{
CaseWhen *w = (CaseWhen *) lfirst(l);
w->result = (Expr *)
coerce_to_common_type(pstate,
(Node *) w->result,
ptype,
"CASE/WHEN");
}
return (Node *) newc;
}
static Node *
transformSubLink(ParseState *pstate, SubLink *sublink)
{
List *qtrees;
Query *qtree;
Node *result = (Node *) sublink;
/* If we already transformed this node, do nothing */
if (IsA(sublink->subselect, Query))
return result;
pstate->p_hasSubLinks = true;
qtrees = parse_sub_analyze(sublink->subselect, pstate);
if (list_length(qtrees) != 1)
elog(ERROR, "bad query in sub-select");
qtree = (Query *) linitial(qtrees);
if (qtree->commandType != CMD_SELECT ||
qtree->resultRelation != 0)
elog(ERROR, "bad query in sub-select");
sublink->subselect = (Node *) qtree;
if (sublink->subLinkType == EXISTS_SUBLINK)
{
/*
* EXISTS needs no lefthand or combining operator. These
* fields should be NIL already, but make sure.
*/
sublink->lefthand = NIL;
sublink->operName = NIL;
sublink->operOids = NIL;
sublink->useOr = FALSE;
}
else if (sublink->subLinkType == EXPR_SUBLINK ||
sublink->subLinkType == ARRAY_SUBLINK)
{
ListCell *tlist_item = list_head(qtree->targetList);
/*
* Make sure the subselect delivers a single column (ignoring
* resjunk targets).
*/
if (tlist_item == NULL ||
((TargetEntry *) lfirst(tlist_item))->resdom->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery must return a column")));
while ((tlist_item = lnext(tlist_item)) != NULL)
{
if (!((TargetEntry *) lfirst(tlist_item))->resdom->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery must return only one column")));
}
/*
* EXPR and ARRAY need no lefthand or combining
* operator. These fields should be NIL already, but make
* sure.
*/
sublink->lefthand = NIL;
sublink->operName = NIL;
sublink->operOids = NIL;
sublink->useOr = FALSE;
}
else
{
/* ALL, ANY, or MULTIEXPR: generate operator list */
List *left_list = sublink->lefthand;
List *right_list = qtree->targetList;
int row_length = list_length(left_list);
bool needNot = false;
List *op = sublink->operName;
char *opname = strVal(llast(op));
ListCell *l;
ListCell *ll_item;
/* transform lefthand expressions */
foreach(l, left_list)
lfirst(l) = transformExpr(pstate, lfirst(l));
/*
* If the expression is "<> ALL" (with unqualified opname)
* then convert it to "NOT IN". This is a hack to improve
* efficiency of expressions output by pre-7.4 Postgres.
*/
if (sublink->subLinkType == ALL_SUBLINK &&
list_length(op) == 1 && strcmp(opname, "<>") == 0)
{
sublink->subLinkType = ANY_SUBLINK;
opname = pstrdup("=");
op = list_make1(makeString(opname));
sublink->operName = op;
needNot = true;
}
/* Set useOr if op is "<>" (possibly qualified) */
if (strcmp(opname, "<>") == 0)
sublink->useOr = TRUE;
else
sublink->useOr = FALSE;
/* Combining operators other than =/<> is dubious... */
if (row_length != 1 &&
strcmp(opname, "=") != 0 &&
strcmp(opname, "<>") != 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("row comparison cannot use operator %s",
opname)));
/*
* To build the list of combining operator OIDs, we must scan
* subquery's targetlist to find values that will be matched
* against lefthand values. We need to ignore resjunk
* targets, so doing the outer iteration over right_list is
* easier than doing it over left_list.
*/
sublink->operOids = NIL;
ll_item = list_head(left_list);
foreach(l, right_list)
{
TargetEntry *tent = (TargetEntry *) lfirst(l);
Node *lexpr;
Operator optup;
Form_pg_operator opform;
if (tent->resdom->resjunk)
continue;
if (ll_item == NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery has too many columns")));
lexpr = lfirst(ll_item);
ll_item = lnext(ll_item);
/*
* It's OK to use oper() not compatible_oper() here,
* because make_subplan() will insert type coercion calls
* if needed.
*/
optup = oper(op,
exprType(lexpr),
exprType((Node *) tent->expr),
false);
opform = (Form_pg_operator) GETSTRUCT(optup);
if (opform->oprresult != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("operator %s must return type boolean, not type %s",
opname,
format_type_be(opform->oprresult)),
errhint("The operator of a quantified predicate subquery must return type boolean.")));
if (get_func_retset(opform->oprcode))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("operator %s must not return a set",
opname),
errhint("The operator of a quantified predicate subquery must return type boolean.")));
sublink->operOids = lappend_oid(sublink->operOids,
oprid(optup));
ReleaseSysCache(optup);
}
if (ll_item != NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery has too few columns")));
if (needNot)
{
result = coerce_to_boolean(pstate, result, "NOT");
result = (Node *) makeBoolExpr(NOT_EXPR,
list_make1(result));
}
}
return result;
}
static Node *
transformArrayExpr(ParseState *pstate, ArrayExpr *a)
{
ArrayExpr *newa = makeNode(ArrayExpr);
List *newelems = NIL;
List *newcoercedelems = NIL;
List *typeids = NIL;
ListCell *element;
Oid array_type;
Oid element_type;
/* Transform the element expressions */
foreach(element, a->elements)
{
Node *e = (Node *) lfirst(element);
Node *newe;
newe = transformExpr(pstate, e);
newelems = lappend(newelems, newe);
typeids = lappend_oid(typeids, exprType(newe));
}
/* Select a common type for the elements */
element_type = select_common_type(typeids, "ARRAY");
/* Coerce arguments to common type if necessary */
foreach(element, newelems)
{
Node *e = (Node *) lfirst(element);
Node *newe;
newe = coerce_to_common_type(pstate, e,
element_type,
"ARRAY");
newcoercedelems = lappend(newcoercedelems, newe);
}
/* Do we have an array type to use? */
array_type = get_array_type(element_type);
if (array_type != InvalidOid)
{
/* Elements are presumably of scalar type */
newa->multidims = false;
}
else
{
/* Must be nested array expressions */
newa->multidims = true;
array_type = element_type;
element_type = get_element_type(array_type);
if (!OidIsValid(element_type))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("could not find array type for data type %s",
format_type_be(array_type))));
}
newa->array_typeid = array_type;
newa->element_typeid = element_type;
newa->elements = newcoercedelems;
return (Node *) newa;
}
static Node *
transformRowExpr(ParseState *pstate, RowExpr *r)
{
RowExpr *newr = makeNode(RowExpr);
List *newargs = NIL;
ListCell *arg;
/* Transform the field expressions */
foreach(arg, r->args)
{
Node *e = (Node *) lfirst(arg);
Node *newe;
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
}
newr->args = newargs;
/* Barring later casting, we consider the type RECORD */
newr->row_typeid = RECORDOID;
newr->row_format = COERCE_IMPLICIT_CAST;
return (Node *) newr;
}
static Node *
transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
{
CoalesceExpr *newc = makeNode(CoalesceExpr);
List *newargs = NIL;
List *newcoercedargs = NIL;
List *typeids = NIL;
ListCell *args;
foreach(args, c->args)
{
Node *e = (Node *) lfirst(args);
Node *newe;
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
typeids = lappend_oid(typeids, exprType(newe));
}
newc->coalescetype = select_common_type(typeids, "COALESCE");
/* Convert arguments if necessary */
foreach(args, newargs)
{
Node *e = (Node *) lfirst(args);
Node *newe;
newe = coerce_to_common_type(pstate, e,
newc->coalescetype,
"COALESCE");
newcoercedargs = lappend(newcoercedargs, newe);
}
newc->args = newcoercedargs;
return (Node *) newc;
}
static Node *
transformBooleanTest(ParseState *pstate, BooleanTest *b)
{
const char *clausename;
switch (b->booltesttype)
{
case IS_TRUE:
clausename = "IS TRUE";
break;
case IS_NOT_TRUE:
clausename = "IS NOT TRUE";
break;
case IS_FALSE:
clausename = "IS FALSE";
break;
case IS_NOT_FALSE:
clausename = "IS NOT FALSE";
break;
case IS_UNKNOWN:
clausename = "IS UNKNOWN";
break;
case IS_NOT_UNKNOWN:
clausename = "IS NOT UNKNOWN";
break;
default:
elog(ERROR, "unrecognized booltesttype: %d",
(int) b->booltesttype);
clausename = NULL; /* keep compiler quiet */
}
b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg);
b->arg = (Expr *) coerce_to_boolean(pstate,
(Node *) b->arg,
clausename);
return (Node *) b;
}
/*
* Construct a whole-row reference to represent the notation "relation.*".
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment