Commit 55000398 authored by Tom Lane's avatar Tom Lane

Fix optimizer coredump with unary-operator WHERE clauses.

A test case is:
create table linetab (x line);
select * from linetab where ?| x;
which coredumps in 6.4.2 and current sources.
parent d8b482be
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.29 1999/02/13 23:16:42 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.30 1999/02/14 22:24:25 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -101,7 +101,10 @@ make_opclause(Oper *op, Var *leftop, Var *rightop) ...@@ -101,7 +101,10 @@ make_opclause(Oper *op, Var *leftop, Var *rightop)
expr->typeOid = InvalidOid; /* assume type checking done */ expr->typeOid = InvalidOid; /* assume type checking done */
expr->opType = OP_EXPR; expr->opType = OP_EXPR;
expr->oper = (Node *) op; expr->oper = (Node *) op;
expr->args = makeList(leftop, rightop, -1); if (rightop)
expr->args = lcons(leftop, lcons(rightop, NIL));
else
expr->args = lcons(leftop, NIL);
return expr; return expr;
} }
...@@ -125,7 +128,7 @@ get_leftop(Expr *clause) ...@@ -125,7 +128,7 @@ get_leftop(Expr *clause)
* get_rightop * get_rightop
* *
* Returns the right operand in a clause of the form (op expr expr). * Returns the right operand in a clause of the form (op expr expr).
* * NB: result will be NULL if applied to a unary op clause.
*/ */
Var * Var *
get_rightop(Expr *clause) get_rightop(Expr *clause)
...@@ -470,6 +473,9 @@ is_joinable(Node *clause) ...@@ -470,6 +473,9 @@ is_joinable(Node *clause)
leftop = (Node *) get_leftop((Expr *) clause); leftop = (Node *) get_leftop((Expr *) clause);
rightop = (Node *) get_rightop((Expr *) clause); rightop = (Node *) get_rightop((Expr *) clause);
if (!rightop)
return false; /* unary opclauses need not apply */
/* /*
* One side of the clause (i.e. left or right operands) must either be * One side of the clause (i.e. left or right operands) must either be
* a var node ... * a var node ...
...@@ -491,19 +497,27 @@ is_joinable(Node *clause) ...@@ -491,19 +497,27 @@ is_joinable(Node *clause)
* *
* Returns t iff 'clause' is a valid qualification clause. * Returns t iff 'clause' is a valid qualification clause.
* *
* For now we accept only "var op const" or "const op var".
*/ */
bool bool
qual_clause_p(Node *clause) qual_clause_p(Node *clause)
{ {
Node *leftop,
*rightop;
if (!is_opclause(clause)) if (!is_opclause(clause))
return false; return false;
leftop = (Node *) get_leftop((Expr *) clause);
rightop = (Node *) get_rightop((Expr *) clause);
if (!rightop)
return false; /* unary opclauses need not apply */
/* How about Param-s ? - vadim 02/03/98 */ /* How about Param-s ? - vadim 02/03/98 */
if (IsA(get_leftop((Expr *) clause), Var) && if (IsA(leftop, Var) && IsA(rightop, Const))
IsA(get_rightop((Expr *) clause), Const))
return true; return true;
else if (IsA(get_rightop((Expr *) clause), Var) && if (IsA(rightop, Var) && IsA(leftop, Const))
IsA(get_leftop((Expr *) clause), Const))
return true; return true;
return false; return false;
} }
...@@ -618,42 +632,35 @@ get_relattval(Node *clause, ...@@ -618,42 +632,35 @@ get_relattval(Node *clause,
Datum *constval, Datum *constval,
int *flag) int *flag)
{ {
Var *left = get_leftop((Expr *) clause); Var *left,
Var *right = get_rightop((Expr *) clause); *right;
if (is_opclause(clause) && IsA(left, Var) && /* Careful; the passed clause might not be a binary operator at all */
IsA(right, Const))
{
if (right != NULL) if (!is_opclause(clause))
{ goto default_results;
*relid = left->varno; left = get_leftop((Expr *) clause);
*attno = left->varattno; right = get_rightop((Expr *) clause);
*constval = ((Const *) right)->constvalue;
*flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
} if (!right)
else goto default_results;
{
if (IsA(left, Var) && IsA(right, Const))
{
*relid = left->varno; *relid = left->varno;
*attno = left->varattno; *attno = left->varattno;
*constval = 0; *constval = ((Const *) right)->constvalue;
*flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_NOT_CONSTANT_); *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
}
} }
else if (is_opclause(clause) && IsA(left, Var) &&IsA(right, Param)) else if (IsA(left, Var) && IsA(right, Param))
{ {
*relid = left->varno; *relid = left->varno;
*attno = left->varattno; *attno = left->varattno;
*constval = 0; *constval = 0;
*flag = (_SELEC_NOT_CONSTANT_); *flag = (_SELEC_NOT_CONSTANT_);
} }
else if (is_opclause(clause) && else if (is_funcclause((Node *) left) && IsA(right, Const))
is_funcclause((Node *) left) &&
IsA(right, Const))
{ {
List *vars = pull_var_clause((Node *) left); List *vars = pull_var_clause((Node *) left);
...@@ -662,52 +669,33 @@ get_relattval(Node *clause, ...@@ -662,52 +669,33 @@ get_relattval(Node *clause,
*constval = ((Const *) right)->constvalue; *constval = ((Const *) right)->constvalue;
*flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_); *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
} }
else if (is_opclause(clause) && else if (IsA(right, Var) && IsA(left, Const))
is_funcclause((Node *) right) &&
IsA(left, Const))
{
List *vars = pull_var_clause((Node *) right);
*relid = ((Var *) lfirst(vars))->varno;
*attno = InvalidAttrNumber;
*constval = ((Const *) left)->constvalue;
*flag = (_SELEC_IS_CONSTANT_);
}
else if (is_opclause(clause) && IsA(right, Var) &&
IsA(left, Const))
{
if (left != NULL)
{ {
*relid = right->varno; *relid = right->varno;
*attno = right->varattno; *attno = right->varattno;
*constval = ((Const *) left)->constvalue; *constval = ((Const *) left)->constvalue;
*flag = (_SELEC_IS_CONSTANT_); *flag = (_SELEC_IS_CONSTANT_);
} }
else else if (IsA(right, Var) &&IsA(left, Param))
{ {
*relid = right->varno; *relid = right->varno;
*attno = right->varattno; *attno = right->varattno;
*constval = 0; *constval = 0;
*flag = (_SELEC_NOT_CONSTANT_); *flag = (_SELEC_NOT_CONSTANT_);
} }
} else if (is_funcclause((Node *) right) && IsA(left, Const))
else if (is_opclause(clause) && IsA(right, Var) &&IsA(left, Param))
{ {
*relid = right->varno; List *vars = pull_var_clause((Node *) right);
*attno = right->varattno;
*constval = 0; *relid = ((Var *) lfirst(vars))->varno;
*flag = (_SELEC_NOT_CONSTANT_); *attno = InvalidAttrNumber;
*constval = ((Const *) left)->constvalue;
*flag = (_SELEC_IS_CONSTANT_);
} }
else else
{ {
/* Duh, it's too complicated for me... */
/* default_results:
* One or more of the operands are expressions (e.g., oper
* clauses)
*/
*relid = _SELEC_VALUE_UNKNOWN_; *relid = _SELEC_VALUE_UNKNOWN_;
*attno = _SELEC_VALUE_UNKNOWN_; *attno = _SELEC_VALUE_UNKNOWN_;
*constval = 0; *constval = 0;
...@@ -733,17 +721,20 @@ get_rels_atts(Node *clause, ...@@ -733,17 +721,20 @@ get_rels_atts(Node *clause,
int *relid2, int *relid2,
AttrNumber *attno2) AttrNumber *attno2)
{ {
if (is_opclause(clause))
{
Var *left = get_leftop((Expr *) clause); Var *left = get_leftop((Expr *) clause);
Var *right = get_rightop((Expr *) clause); Var *right = get_rightop((Expr *) clause);
bool var_left = (IsA(left, Var));
bool var_right = (IsA(right, Var)); if (left && right)
bool varexpr_left = (bool) ((IsA(left, Func) ||IsA(left, Oper)) && {
bool var_left = IsA(left, Var);
bool var_right = IsA(right, Var);
bool varexpr_left = (bool) ((IsA(left, Func) || IsA(left, Oper)) &&
contain_var_clause((Node *) left)); contain_var_clause((Node *) left));
bool varexpr_right = (bool) ((IsA(right, Func) ||IsA(right, Oper)) && bool varexpr_right = (bool) ((IsA(right, Func) || IsA(right, Oper)) &&
contain_var_clause((Node *) right)); contain_var_clause((Node *) right));
if (is_opclause(clause))
{
if (var_left && var_right) if (var_left && var_right)
{ {
...@@ -753,7 +744,7 @@ get_rels_atts(Node *clause, ...@@ -753,7 +744,7 @@ get_rels_atts(Node *clause,
*attno2 = right->varoattno; *attno2 = right->varoattno;
return; return;
} }
else if (var_left && varexpr_right) if (var_left && varexpr_right)
{ {
*relid1 = left->varno; *relid1 = left->varno;
...@@ -762,7 +753,7 @@ get_rels_atts(Node *clause, ...@@ -762,7 +753,7 @@ get_rels_atts(Node *clause,
*attno2 = _SELEC_VALUE_UNKNOWN_; *attno2 = _SELEC_VALUE_UNKNOWN_;
return; return;
} }
else if (varexpr_left && var_right) if (varexpr_left && var_right)
{ {
*relid1 = _SELEC_VALUE_UNKNOWN_; *relid1 = _SELEC_VALUE_UNKNOWN_;
...@@ -772,12 +763,12 @@ get_rels_atts(Node *clause, ...@@ -772,12 +763,12 @@ get_rels_atts(Node *clause,
return; return;
} }
} }
}
*relid1 = _SELEC_VALUE_UNKNOWN_; *relid1 = _SELEC_VALUE_UNKNOWN_;
*attno1 = _SELEC_VALUE_UNKNOWN_; *attno1 = _SELEC_VALUE_UNKNOWN_;
*relid2 = _SELEC_VALUE_UNKNOWN_; *relid2 = _SELEC_VALUE_UNKNOWN_;
*attno2 = _SELEC_VALUE_UNKNOWN_; *attno2 = _SELEC_VALUE_UNKNOWN_;
return;
} }
void void
...@@ -813,4 +804,3 @@ CommuteClause(Node *clause) ...@@ -813,4 +804,3 @@ CommuteClause(Node *clause)
lfirst(((Expr *) clause)->args) = lsecond(((Expr *) clause)->args); lfirst(((Expr *) clause)->args) = lsecond(((Expr *) clause)->args);
lsecond(((Expr *) clause)->args) = temp; lsecond(((Expr *) clause)->args) = temp;
} }
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