|
|
|
@ -39,53 +39,8 @@
|
|
|
|
|
#include "utils/xml.h"
|
|
|
|
|
|
|
|
|
|
/* GUC parameters */
|
|
|
|
|
bool operator_precedence_warning = false;
|
|
|
|
|
bool Transform_null_equals = false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Node-type groups for operator precedence warnings
|
|
|
|
|
* We use zero for everything not otherwise classified
|
|
|
|
|
*/
|
|
|
|
|
#define PREC_GROUP_POSTFIX_IS 1 /* postfix IS tests (NullTest, etc) */
|
|
|
|
|
#define PREC_GROUP_INFIX_IS 2 /* infix IS (IS DISTINCT FROM, etc) */
|
|
|
|
|
#define PREC_GROUP_LESS 3 /* < > */
|
|
|
|
|
#define PREC_GROUP_EQUAL 4 /* = */
|
|
|
|
|
#define PREC_GROUP_LESS_EQUAL 5 /* <= >= <> */
|
|
|
|
|
#define PREC_GROUP_LIKE 6 /* LIKE ILIKE SIMILAR */
|
|
|
|
|
#define PREC_GROUP_BETWEEN 7 /* BETWEEN */
|
|
|
|
|
#define PREC_GROUP_IN 8 /* IN */
|
|
|
|
|
#define PREC_GROUP_NOT_LIKE 9 /* NOT LIKE/ILIKE/SIMILAR */
|
|
|
|
|
#define PREC_GROUP_NOT_BETWEEN 10 /* NOT BETWEEN */
|
|
|
|
|
#define PREC_GROUP_NOT_IN 11 /* NOT IN */
|
|
|
|
|
#define PREC_GROUP_ANY_ALL 12 /* ANY/ALL */
|
|
|
|
|
#define PREC_GROUP_INFIX_OP 13 /* generic infix operators */
|
|
|
|
|
#define PREC_GROUP_PREFIX_OP 14 /* generic prefix operators */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Map precedence groupings to old precedence ordering
|
|
|
|
|
*
|
|
|
|
|
* Old precedence order:
|
|
|
|
|
* 1. NOT
|
|
|
|
|
* 2. =
|
|
|
|
|
* 3. < >
|
|
|
|
|
* 4. LIKE ILIKE SIMILAR
|
|
|
|
|
* 5. BETWEEN
|
|
|
|
|
* 6. IN
|
|
|
|
|
* 7. ANY ALL
|
|
|
|
|
* 8. generic Op, including <= => <>
|
|
|
|
|
* 9. generic prefix Op
|
|
|
|
|
* 10. IS tests (NullTest, BooleanTest, etc)
|
|
|
|
|
*
|
|
|
|
|
* NOT BETWEEN etc map to BETWEEN etc when considered as being on the left,
|
|
|
|
|
* but to NOT when considered as being on the right, because of the buggy
|
|
|
|
|
* precedence handling of those productions in the old grammar.
|
|
|
|
|
*/
|
|
|
|
|
static const int oldprecedence_l[] = {
|
|
|
|
|
0, 10, 10, 3, 2, 8, 4, 5, 6, 4, 5, 6, 7, 8, 9
|
|
|
|
|
};
|
|
|
|
|
static const int oldprecedence_r[] = {
|
|
|
|
|
0, 10, 10, 3, 2, 8, 4, 5, 6, 1, 1, 1, 7, 8, 9
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static Node *transformExprRecurse(ParseState *pstate, Node *expr);
|
|
|
|
|
static Node *transformParamRef(ParseState *pstate, ParamRef *pref);
|
|
|
|
@ -127,11 +82,6 @@ static Expr *make_distinct_op(ParseState *pstate, List *opname,
|
|
|
|
|
Node *ltree, Node *rtree, int location);
|
|
|
|
|
static Node *make_nulltest_from_distinct(ParseState *pstate,
|
|
|
|
|
A_Expr *distincta, Node *arg);
|
|
|
|
|
static int operator_precedence_group(Node *node, const char **nodename);
|
|
|
|
|
static void emit_precedence_warnings(ParseState *pstate,
|
|
|
|
|
int opgroup, const char *opname,
|
|
|
|
|
Node *lchild, Node *rchild,
|
|
|
|
|
int location);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -242,9 +192,6 @@ transformExprRecurse(ParseState *pstate, Node *expr)
|
|
|
|
|
case AEXPR_NOT_BETWEEN_SYM:
|
|
|
|
|
result = transformAExprBetween(pstate, a);
|
|
|
|
|
break;
|
|
|
|
|
case AEXPR_PAREN:
|
|
|
|
|
result = transformExprRecurse(pstate, a->lexpr);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
elog(ERROR, "unrecognized A_Expr kind: %d", a->kind);
|
|
|
|
|
result = NULL; /* keep compiler quiet */
|
|
|
|
@ -315,11 +262,6 @@ transformExprRecurse(ParseState *pstate, Node *expr)
|
|
|
|
|
{
|
|
|
|
|
NullTest *n = (NullTest *) expr;
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning)
|
|
|
|
|
emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_IS, "IS",
|
|
|
|
|
(Node *) n->arg, NULL,
|
|
|
|
|
n->location);
|
|
|
|
|
|
|
|
|
|
n->arg = (Expr *) transformExprRecurse(pstate, (Node *) n->arg);
|
|
|
|
|
/* the argument can be any type, so don't coerce it */
|
|
|
|
|
n->argisrow = type_is_rowtype(exprType((Node *) n->arg));
|
|
|
|
@ -926,26 +868,6 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
|
|
|
|
|
Node *rexpr = a->rexpr;
|
|
|
|
|
Node *result;
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning)
|
|
|
|
|
{
|
|
|
|
|
int opgroup;
|
|
|
|
|
const char *opname;
|
|
|
|
|
|
|
|
|
|
opgroup = operator_precedence_group((Node *) a, &opname);
|
|
|
|
|
if (opgroup > 0)
|
|
|
|
|
emit_precedence_warnings(pstate, opgroup, opname,
|
|
|
|
|
lexpr, rexpr,
|
|
|
|
|
a->location);
|
|
|
|
|
|
|
|
|
|
/* Look through AEXPR_PAREN nodes so they don't affect tests below */
|
|
|
|
|
while (lexpr && IsA(lexpr, A_Expr) &&
|
|
|
|
|
((A_Expr *) lexpr)->kind == AEXPR_PAREN)
|
|
|
|
|
lexpr = ((A_Expr *) lexpr)->lexpr;
|
|
|
|
|
while (rexpr && IsA(rexpr, A_Expr) &&
|
|
|
|
|
((A_Expr *) rexpr)->kind == AEXPR_PAREN)
|
|
|
|
|
rexpr = ((A_Expr *) rexpr)->lexpr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Special-case "foo = NULL" and "NULL = foo" for compatibility with
|
|
|
|
|
* standards-broken products (like Microsoft's). Turn these into IS NULL
|
|
|
|
@ -1023,17 +945,8 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
|
|
|
|
|
static Node *
|
|
|
|
|
transformAExprOpAny(ParseState *pstate, A_Expr *a)
|
|
|
|
|
{
|
|
|
|
|
Node *lexpr = a->lexpr;
|
|
|
|
|
Node *rexpr = a->rexpr;
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning)
|
|
|
|
|
emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
|
|
|
|
|
strVal(llast(a->name)),
|
|
|
|
|
lexpr, NULL,
|
|
|
|
|
a->location);
|
|
|
|
|
|
|
|
|
|
lexpr = transformExprRecurse(pstate, lexpr);
|
|
|
|
|
rexpr = transformExprRecurse(pstate, rexpr);
|
|
|
|
|
Node *lexpr = transformExprRecurse(pstate, a->lexpr);
|
|
|
|
|
Node *rexpr = transformExprRecurse(pstate, a->rexpr);
|
|
|
|
|
|
|
|
|
|
return (Node *) make_scalar_array_op(pstate,
|
|
|
|
|
a->name,
|
|
|
|
@ -1046,17 +959,8 @@ transformAExprOpAny(ParseState *pstate, A_Expr *a)
|
|
|
|
|
static Node *
|
|
|
|
|
transformAExprOpAll(ParseState *pstate, A_Expr *a)
|
|
|
|
|
{
|
|
|
|
|
Node *lexpr = a->lexpr;
|
|
|
|
|
Node *rexpr = a->rexpr;
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning)
|
|
|
|
|
emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
|
|
|
|
|
strVal(llast(a->name)),
|
|
|
|
|
lexpr, NULL,
|
|
|
|
|
a->location);
|
|
|
|
|
|
|
|
|
|
lexpr = transformExprRecurse(pstate, lexpr);
|
|
|
|
|
rexpr = transformExprRecurse(pstate, rexpr);
|
|
|
|
|
Node *lexpr = transformExprRecurse(pstate, a->lexpr);
|
|
|
|
|
Node *rexpr = transformExprRecurse(pstate, a->rexpr);
|
|
|
|
|
|
|
|
|
|
return (Node *) make_scalar_array_op(pstate,
|
|
|
|
|
a->name,
|
|
|
|
@ -1073,11 +977,6 @@ transformAExprDistinct(ParseState *pstate, A_Expr *a)
|
|
|
|
|
Node *rexpr = a->rexpr;
|
|
|
|
|
Node *result;
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning)
|
|
|
|
|
emit_precedence_warnings(pstate, PREC_GROUP_INFIX_IS, "IS",
|
|
|
|
|
lexpr, rexpr,
|
|
|
|
|
a->location);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If either input is an undecorated NULL literal, transform to a NullTest
|
|
|
|
|
* on the other input. That's simpler to process than a full DistinctExpr,
|
|
|
|
@ -1183,13 +1082,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
|
|
|
|
else
|
|
|
|
|
useOr = true;
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning)
|
|
|
|
|
emit_precedence_warnings(pstate,
|
|
|
|
|
useOr ? PREC_GROUP_IN : PREC_GROUP_NOT_IN,
|
|
|
|
|
"IN",
|
|
|
|
|
a->lexpr, NULL,
|
|
|
|
|
a->location);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We try to generate a ScalarArrayOpExpr from IN/NOT IN, but this is only
|
|
|
|
|
* possible if there is a suitable array type available. If not, we fall
|
|
|
|
@ -1342,22 +1234,6 @@ transformAExprBetween(ParseState *pstate, A_Expr *a)
|
|
|
|
|
bexpr = (Node *) linitial(args);
|
|
|
|
|
cexpr = (Node *) lsecond(args);
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning)
|
|
|
|
|
{
|
|
|
|
|
int opgroup;
|
|
|
|
|
const char *opname;
|
|
|
|
|
|
|
|
|
|
opgroup = operator_precedence_group((Node *) a, &opname);
|
|
|
|
|
emit_precedence_warnings(pstate, opgroup, opname,
|
|
|
|
|
aexpr, cexpr,
|
|
|
|
|
a->location);
|
|
|
|
|
/* We can ignore bexpr thanks to syntactic restrictions */
|
|
|
|
|
/* Wrap subexpressions to prevent extra warnings */
|
|
|
|
|
aexpr = (Node *) makeA_Expr(AEXPR_PAREN, NIL, aexpr, NULL, -1);
|
|
|
|
|
bexpr = (Node *) makeA_Expr(AEXPR_PAREN, NIL, bexpr, NULL, -1);
|
|
|
|
|
cexpr = (Node *) makeA_Expr(AEXPR_PAREN, NIL, cexpr, NULL, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Build the equivalent comparison expression. Make copies of
|
|
|
|
|
* multiply-referenced subexpressions for safety. (XXX this is really
|
|
|
|
@ -1964,19 +1840,6 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
|
|
|
|
|
List *right_list;
|
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning)
|
|
|
|
|
{
|
|
|
|
|
if (sublink->operName == NIL)
|
|
|
|
|
emit_precedence_warnings(pstate, PREC_GROUP_IN, "IN",
|
|
|
|
|
sublink->testexpr, NULL,
|
|
|
|
|
sublink->location);
|
|
|
|
|
else
|
|
|
|
|
emit_precedence_warnings(pstate, PREC_GROUP_ANY_ALL,
|
|
|
|
|
strVal(llast(sublink->operName)),
|
|
|
|
|
sublink->testexpr, NULL,
|
|
|
|
|
sublink->location);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the source was "x IN (select)", convert to "x = ANY (select)".
|
|
|
|
|
*/
|
|
|
|
@ -2076,11 +1939,6 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
|
|
|
|
|
Node *e = (Node *) lfirst(element);
|
|
|
|
|
Node *newe;
|
|
|
|
|
|
|
|
|
|
/* Look through AEXPR_PAREN nodes so they don't affect test below */
|
|
|
|
|
while (e && IsA(e, A_Expr) &&
|
|
|
|
|
((A_Expr *) e)->kind == AEXPR_PAREN)
|
|
|
|
|
e = ((A_Expr *) e)->lexpr;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If an element is itself an A_ArrayExpr, recurse directly so that we
|
|
|
|
|
* can pass down any target type we were given.
|
|
|
|
@ -2389,11 +2247,6 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
|
|
|
|
|
ListCell *lc;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning && x->op == IS_DOCUMENT)
|
|
|
|
|
emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_IS, "IS",
|
|
|
|
|
(Node *) linitial(x->args), NULL,
|
|
|
|
|
x->location);
|
|
|
|
|
|
|
|
|
|
newx = makeNode(XmlExpr);
|
|
|
|
|
newx->op = x->op;
|
|
|
|
|
if (x->name)
|
|
|
|
@ -2564,11 +2417,6 @@ transformBooleanTest(ParseState *pstate, BooleanTest *b)
|
|
|
|
|
{
|
|
|
|
|
const char *clausename;
|
|
|
|
|
|
|
|
|
|
if (operator_precedence_warning)
|
|
|
|
|
emit_precedence_warnings(pstate, PREC_GROUP_POSTFIX_IS, "IS",
|
|
|
|
|
(Node *) b->arg, NULL,
|
|
|
|
|
b->location);
|
|
|
|
|
|
|
|
|
|
switch (b->booltesttype)
|
|
|
|
|
{
|
|
|
|
|
case IS_TRUE:
|
|
|
|
@ -2702,15 +2550,6 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
|
|
|
|
|
/* Look up the type name first */
|
|
|
|
|
typenameTypeIdAndMod(pstate, tc->typeName, &targetType, &targetTypmod);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Look through any AEXPR_PAREN nodes that may have been inserted thanks
|
|
|
|
|
* to operator_precedence_warning. Otherwise, ARRAY[]::foo[] behaves
|
|
|
|
|
* differently from (ARRAY[])::foo[].
|
|
|
|
|
*/
|
|
|
|
|
while (arg && IsA(arg, A_Expr) &&
|
|
|
|
|
((A_Expr *) arg)->kind == AEXPR_PAREN)
|
|
|
|
|
arg = ((A_Expr *) arg)->lexpr;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the subject of the typecast is an ARRAY[] construct and the target
|
|
|
|
|
* type is an array type, we invoke transformArrayExpr() directly so that
|
|
|
|
@ -3117,287 +2956,6 @@ make_nulltest_from_distinct(ParseState *pstate, A_Expr *distincta, Node *arg)
|
|
|
|
|
return (Node *) nt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Identify node's group for operator precedence warnings
|
|
|
|
|
*
|
|
|
|
|
* For items in nonzero groups, also return a suitable node name into *nodename
|
|
|
|
|
*
|
|
|
|
|
* Note: group zero is used for nodes that are higher or lower precedence
|
|
|
|
|
* than everything that changed precedence; we need never issue warnings
|
|
|
|
|
* related to such nodes.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
operator_precedence_group(Node *node, const char **nodename)
|
|
|
|
|
{
|
|
|
|
|
int group = 0;
|
|
|
|
|
|
|
|
|
|
*nodename = NULL;
|
|
|
|
|
if (node == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (IsA(node, A_Expr))
|
|
|
|
|
{
|
|
|
|
|
A_Expr *aexpr = (A_Expr *) node;
|
|
|
|
|
|
|
|
|
|
if (aexpr->kind == AEXPR_OP &&
|
|
|
|
|
aexpr->lexpr != NULL &&
|
|
|
|
|
aexpr->rexpr != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* binary operator */
|
|
|
|
|
if (list_length(aexpr->name) == 1)
|
|
|
|
|
{
|
|
|
|
|
*nodename = strVal(linitial(aexpr->name));
|
|
|
|
|
/* Ignore if op was always higher priority than IS-tests */
|
|
|
|
|
if (strcmp(*nodename, "+") == 0 ||
|
|
|
|
|
strcmp(*nodename, "-") == 0 ||
|
|
|
|
|
strcmp(*nodename, "*") == 0 ||
|
|
|
|
|
strcmp(*nodename, "/") == 0 ||
|
|
|
|
|
strcmp(*nodename, "%") == 0 ||
|
|
|
|
|
strcmp(*nodename, "^") == 0)
|
|
|
|
|
group = 0;
|
|
|
|
|
else if (strcmp(*nodename, "<") == 0 ||
|
|
|
|
|
strcmp(*nodename, ">") == 0)
|
|
|
|
|
group = PREC_GROUP_LESS;
|
|
|
|
|
else if (strcmp(*nodename, "=") == 0)
|
|
|
|
|
group = PREC_GROUP_EQUAL;
|
|
|
|
|
else if (strcmp(*nodename, "<=") == 0 ||
|
|
|
|
|
strcmp(*nodename, ">=") == 0 ||
|
|
|
|
|
strcmp(*nodename, "<>") == 0)
|
|
|
|
|
group = PREC_GROUP_LESS_EQUAL;
|
|
|
|
|
else
|
|
|
|
|
group = PREC_GROUP_INFIX_OP;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* schema-qualified operator syntax */
|
|
|
|
|
*nodename = "OPERATOR()";
|
|
|
|
|
group = PREC_GROUP_INFIX_OP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (aexpr->kind == AEXPR_OP &&
|
|
|
|
|
aexpr->lexpr == NULL &&
|
|
|
|
|
aexpr->rexpr != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* prefix operator */
|
|
|
|
|
if (list_length(aexpr->name) == 1)
|
|
|
|
|
{
|
|
|
|
|
*nodename = strVal(linitial(aexpr->name));
|
|
|
|
|
/* Ignore if op was always higher priority than IS-tests */
|
|
|
|
|
if (strcmp(*nodename, "+") == 0 ||
|
|
|
|
|
strcmp(*nodename, "-") == 0)
|
|
|
|
|
group = 0;
|
|
|
|
|
else
|
|
|
|
|
group = PREC_GROUP_PREFIX_OP;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* schema-qualified operator syntax */
|
|
|
|
|
*nodename = "OPERATOR()";
|
|
|
|
|
group = PREC_GROUP_PREFIX_OP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (aexpr->kind == AEXPR_OP_ANY ||
|
|
|
|
|
aexpr->kind == AEXPR_OP_ALL)
|
|
|
|
|
{
|
|
|
|
|
*nodename = strVal(llast(aexpr->name));
|
|
|
|
|
group = PREC_GROUP_ANY_ALL;
|
|
|
|
|
}
|
|
|
|
|
else if (aexpr->kind == AEXPR_DISTINCT ||
|
|
|
|
|
aexpr->kind == AEXPR_NOT_DISTINCT)
|
|
|
|
|
{
|
|
|
|
|
*nodename = "IS";
|
|
|
|
|
group = PREC_GROUP_INFIX_IS;
|
|
|
|
|
}
|
|
|
|
|
else if (aexpr->kind == AEXPR_IN)
|
|
|
|
|
{
|
|
|
|
|
*nodename = "IN";
|
|
|
|
|
if (strcmp(strVal(linitial(aexpr->name)), "=") == 0)
|
|
|
|
|
group = PREC_GROUP_IN;
|
|
|
|
|
else
|
|
|
|
|
group = PREC_GROUP_NOT_IN;
|
|
|
|
|
}
|
|
|
|
|
else if (aexpr->kind == AEXPR_LIKE)
|
|
|
|
|
{
|
|
|
|
|
*nodename = "LIKE";
|
|
|
|
|
if (strcmp(strVal(linitial(aexpr->name)), "~~") == 0)
|
|
|
|
|
group = PREC_GROUP_LIKE;
|
|
|
|
|
else
|
|
|
|
|
group = PREC_GROUP_NOT_LIKE;
|
|
|
|
|
}
|
|
|
|
|
else if (aexpr->kind == AEXPR_ILIKE)
|
|
|
|
|
{
|
|
|
|
|
*nodename = "ILIKE";
|
|
|
|
|
if (strcmp(strVal(linitial(aexpr->name)), "~~*") == 0)
|
|
|
|
|
group = PREC_GROUP_LIKE;
|
|
|
|
|
else
|
|
|
|
|
group = PREC_GROUP_NOT_LIKE;
|
|
|
|
|
}
|
|
|
|
|
else if (aexpr->kind == AEXPR_SIMILAR)
|
|
|
|
|
{
|
|
|
|
|
*nodename = "SIMILAR";
|
|
|
|
|
if (strcmp(strVal(linitial(aexpr->name)), "~") == 0)
|
|
|
|
|
group = PREC_GROUP_LIKE;
|
|
|
|
|
else
|
|
|
|
|
group = PREC_GROUP_NOT_LIKE;
|
|
|
|
|
}
|
|
|
|
|
else if (aexpr->kind == AEXPR_BETWEEN ||
|
|
|
|
|
aexpr->kind == AEXPR_BETWEEN_SYM)
|
|
|
|
|
{
|
|
|
|
|
Assert(list_length(aexpr->name) == 1);
|
|
|
|
|
*nodename = strVal(linitial(aexpr->name));
|
|
|
|
|
group = PREC_GROUP_BETWEEN;
|
|
|
|
|
}
|
|
|
|
|
else if (aexpr->kind == AEXPR_NOT_BETWEEN ||
|
|
|
|
|
aexpr->kind == AEXPR_NOT_BETWEEN_SYM)
|
|
|
|
|
{
|
|
|
|
|
Assert(list_length(aexpr->name) == 1);
|
|
|
|
|
*nodename = strVal(linitial(aexpr->name));
|
|
|
|
|
group = PREC_GROUP_NOT_BETWEEN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (IsA(node, NullTest) ||
|
|
|
|
|
IsA(node, BooleanTest))
|
|
|
|
|
{
|
|
|
|
|
*nodename = "IS";
|
|
|
|
|
group = PREC_GROUP_POSTFIX_IS;
|
|
|
|
|
}
|
|
|
|
|
else if (IsA(node, XmlExpr))
|
|
|
|
|
{
|
|
|
|
|
XmlExpr *x = (XmlExpr *) node;
|
|
|
|
|
|
|
|
|
|
if (x->op == IS_DOCUMENT)
|
|
|
|
|
{
|
|
|
|
|
*nodename = "IS";
|
|
|
|
|
group = PREC_GROUP_POSTFIX_IS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (IsA(node, SubLink))
|
|
|
|
|
{
|
|
|
|
|
SubLink *s = (SubLink *) node;
|
|
|
|
|
|
|
|
|
|
if (s->subLinkType == ANY_SUBLINK ||
|
|
|
|
|
s->subLinkType == ALL_SUBLINK)
|
|
|
|
|
{
|
|
|
|
|
if (s->operName == NIL)
|
|
|
|
|
{
|
|
|
|
|
*nodename = "IN";
|
|
|
|
|
group = PREC_GROUP_IN;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*nodename = strVal(llast(s->operName));
|
|
|
|
|
group = PREC_GROUP_ANY_ALL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (IsA(node, BoolExpr))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Must dig into NOTs to see if it's IS NOT DOCUMENT or NOT IN. This
|
|
|
|
|
* opens us to possibly misrecognizing, eg, NOT (x IS DOCUMENT) as a
|
|
|
|
|
* problematic construct. We can tell the difference by checking
|
|
|
|
|
* whether the parse locations of the two nodes are identical.
|
|
|
|
|
*
|
|
|
|
|
* Note that when we are comparing the child node to its own children,
|
|
|
|
|
* we will not know that it was a NOT. Fortunately, that doesn't
|
|
|
|
|
* matter for these cases.
|
|
|
|
|
*/
|
|
|
|
|
BoolExpr *b = (BoolExpr *) node;
|
|
|
|
|
|
|
|
|
|
if (b->boolop == NOT_EXPR)
|
|
|
|
|
{
|
|
|
|
|
Node *child = (Node *) linitial(b->args);
|
|
|
|
|
|
|
|
|
|
if (IsA(child, XmlExpr))
|
|
|
|
|
{
|
|
|
|
|
XmlExpr *x = (XmlExpr *) child;
|
|
|
|
|
|
|
|
|
|
if (x->op == IS_DOCUMENT &&
|
|
|
|
|
x->location == b->location)
|
|
|
|
|
{
|
|
|
|
|
*nodename = "IS";
|
|
|
|
|
group = PREC_GROUP_POSTFIX_IS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (IsA(child, SubLink))
|
|
|
|
|
{
|
|
|
|
|
SubLink *s = (SubLink *) child;
|
|
|
|
|
|
|
|
|
|
if (s->subLinkType == ANY_SUBLINK && s->operName == NIL &&
|
|
|
|
|
s->location == b->location)
|
|
|
|
|
{
|
|
|
|
|
*nodename = "IN";
|
|
|
|
|
group = PREC_GROUP_NOT_IN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return group;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* helper routine for delivering 9.4-to-9.5 operator precedence warnings
|
|
|
|
|
*
|
|
|
|
|
* opgroup/opname/location represent some parent node
|
|
|
|
|
* lchild, rchild are its left and right children (either could be NULL)
|
|
|
|
|
*
|
|
|
|
|
* This should be called before transforming the child nodes, since if a
|
|
|
|
|
* precedence-driven parsing change has occurred in a query that used to work,
|
|
|
|
|
* it's quite possible that we'll get a semantic failure while analyzing the
|
|
|
|
|
* child expression. We want to produce the warning before that happens.
|
|
|
|
|
* In any case, operator_precedence_group() expects untransformed input.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
emit_precedence_warnings(ParseState *pstate,
|
|
|
|
|
int opgroup, const char *opname,
|
|
|
|
|
Node *lchild, Node *rchild,
|
|
|
|
|
int location)
|
|
|
|
|
{
|
|
|
|
|
int cgroup;
|
|
|
|
|
const char *copname;
|
|
|
|
|
|
|
|
|
|
Assert(opgroup > 0);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Complain if left child, which should be same or higher precedence
|
|
|
|
|
* according to current rules, used to be lower precedence.
|
|
|
|
|
*
|
|
|
|
|
* Exception to precedence rules: if left child is IN or NOT IN the
|
|
|
|
|
* grouping is syntactically forced regardless of precedence.
|
|
|
|
|
*/
|
|
|
|
|
cgroup = operator_precedence_group(lchild, &copname);
|
|
|
|
|
if (cgroup > 0)
|
|
|
|
|
{
|
|
|
|
|
if (oldprecedence_l[cgroup] < oldprecedence_r[opgroup] &&
|
|
|
|
|
cgroup != PREC_GROUP_IN &&
|
|
|
|
|
cgroup != PREC_GROUP_NOT_IN &&
|
|
|
|
|
cgroup != PREC_GROUP_ANY_ALL &&
|
|
|
|
|
cgroup != PREC_GROUP_POSTFIX_IS)
|
|
|
|
|
ereport(WARNING,
|
|
|
|
|
(errmsg("operator precedence change: %s is now lower precedence than %s",
|
|
|
|
|
opname, copname),
|
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Complain if right child, which should be higher precedence according to
|
|
|
|
|
* current rules, used to be same or lower precedence.
|
|
|
|
|
*
|
|
|
|
|
* Exception to precedence rules: if right child is a prefix operator, the
|
|
|
|
|
* grouping is syntactically forced regardless of precedence.
|
|
|
|
|
*/
|
|
|
|
|
cgroup = operator_precedence_group(rchild, &copname);
|
|
|
|
|
if (cgroup > 0)
|
|
|
|
|
{
|
|
|
|
|
if (oldprecedence_r[cgroup] <= oldprecedence_l[opgroup] &&
|
|
|
|
|
cgroup != PREC_GROUP_PREFIX_OP)
|
|
|
|
|
ereport(WARNING,
|
|
|
|
|
(errmsg("operator precedence change: %s is now lower precedence than %s",
|
|
|
|
|
opname, copname),
|
|
|
|
|
parser_errposition(pstate, location)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Produce a string identifying an expression by kind.
|
|
|
|
|
*
|
|
|
|
|