mirror of
https://github.com/postgres/postgres.git
synced 2025-08-24 09:27:52 +03:00
Operators live in namespaces. CREATE/DROP/COMMENT ON OPERATOR take
qualified operator names directly, for example CREATE OPERATOR myschema.+ ( ... ). To qualify an operator name in an expression you need to write OPERATOR(myschema.+) (thanks to Peter for suggesting an escape hatch). I also took advantage of having to reformat pg_operator to fix something that'd been bugging me for a while: mergejoinable operators should have explicit links to the associated cross-data-type comparison operators, rather than hardwiring an assumption that they are named < and >.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.229 2002/04/12 19:11:49 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.230 2002/04/16 23:08:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1460,11 +1460,13 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
|
||||
{
|
||||
/*
|
||||
* fktypoid[i] is the foreign key table's i'th element's type
|
||||
* oid pktypoid[i] is the primary key table's i'th element's
|
||||
* type oid We let oper() do our work for us, including
|
||||
* elog(ERROR) if the types don't compare with =
|
||||
* pktypoid[i] is the primary key table's i'th element's type
|
||||
*
|
||||
* We let oper() do our work for us, including elog(ERROR) if
|
||||
* the types don't compare with =
|
||||
*/
|
||||
Operator o = oper("=", fktypoid[i], pktypoid[i], false);
|
||||
Operator o = oper(makeList1(makeString("=")),
|
||||
fktypoid[i], pktypoid[i], false);
|
||||
|
||||
ReleaseSysCache(o);
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.301 2002/04/09 20:35:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.302 2002/04/16 23:08:11 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -82,11 +82,10 @@ static int pfunc_num_args;
|
||||
*/
|
||||
/*#define __YYSCLASS*/
|
||||
|
||||
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
|
||||
static Node *makeTypeCast(Node *arg, TypeName *typename);
|
||||
static Node *makeStringConst(char *str, TypeName *typename);
|
||||
static Node *makeFloatConst(char *str);
|
||||
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
|
||||
static Node *makeRowExpr(List *opr, List *largs, List *rargs);
|
||||
static SelectStmt *findLeftmostSelect(SelectStmt *node);
|
||||
static void insertSelectOptions(SelectStmt *stmt,
|
||||
List *sortClause, List *forUpdate,
|
||||
@@ -177,13 +176,13 @@ static bool set_name_needs_quotes(const char *name);
|
||||
database_name, access_method_clause, access_method, attr_name,
|
||||
class, index_name, name, function_name, file_name
|
||||
|
||||
%type <list> func_name, handler_name
|
||||
%type <list> func_name, handler_name, qual_Op, qual_all_Op, OptUseOp
|
||||
|
||||
%type <range> qualified_name, OptConstrFromTable
|
||||
|
||||
%type <str> opt_id,
|
||||
all_Op, MathOp, opt_name,
|
||||
OptUseOp, opt_class, SpecialRuleRelation
|
||||
opt_class, SpecialRuleRelation
|
||||
|
||||
%type <str> opt_level, opt_encoding
|
||||
%type <node> grantee
|
||||
@@ -202,7 +201,7 @@ static bool set_name_needs_quotes(const char *name);
|
||||
opt_column_list, columnList, opt_name_list,
|
||||
sort_clause, sortby_list, index_params, index_list, name_list,
|
||||
from_clause, from_list, opt_array_bounds, qualified_name_list,
|
||||
any_name, any_name_list, expr_list, dotted_name, attrs,
|
||||
any_name, any_name_list, any_operator, expr_list, dotted_name, attrs,
|
||||
target_list, update_target_list, insert_column_list,
|
||||
insert_target_list,
|
||||
def_list, opt_indirection, group_clause, TriggerFuncArgs,
|
||||
@@ -404,7 +403,7 @@ static bool set_name_needs_quotes(const char *name);
|
||||
%nonassoc BETWEEN
|
||||
%nonassoc IN
|
||||
%left POSTFIXOP /* dummy for postfix Op rules */
|
||||
%left Op /* multi-character ops and user-defined operators */
|
||||
%left Op OPERATOR /* multi-character ops and user-defined operators */
|
||||
%nonassoc NOTNULL
|
||||
%nonassoc ISNULL
|
||||
%nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN /* sets precedence for IS NULL, etc */
|
||||
@@ -2086,11 +2085,11 @@ DefineStmt: CREATE AGGREGATE func_name definition
|
||||
n->definition = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE OPERATOR all_Op definition
|
||||
| CREATE OPERATOR any_operator definition
|
||||
{
|
||||
DefineStmt *n = makeNode(DefineStmt);
|
||||
n->defType = OPERATOR;
|
||||
n->defnames = makeList1(makeString($3)); /* XXX */
|
||||
n->defnames = $3;
|
||||
n->definition = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
@@ -2227,11 +2226,11 @@ CommentStmt: COMMENT ON comment_type any_name IS comment_text
|
||||
n->comment = $7;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| COMMENT ON OPERATOR all_Op '(' oper_argtypes ')' IS comment_text
|
||||
| COMMENT ON OPERATOR any_operator '(' oper_argtypes ')' IS comment_text
|
||||
{
|
||||
CommentStmt *n = makeNode(CommentStmt);
|
||||
n->objtype = OPERATOR;
|
||||
n->objname = makeList1(makeString($4)); /* XXX */
|
||||
n->objname = $4;
|
||||
n->objargs = $6;
|
||||
n->comment = $9;
|
||||
$$ = (Node *) n;
|
||||
@@ -2812,7 +2811,7 @@ aggr_argtype: Typename { $$ = $1; }
|
||||
| '*' { $$ = NULL; }
|
||||
;
|
||||
|
||||
RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')'
|
||||
RemoveOperStmt: DROP OPERATOR any_operator '(' oper_argtypes ')'
|
||||
{
|
||||
RemoveOperStmt *n = makeNode(RemoveOperStmt);
|
||||
n->opname = $3;
|
||||
@@ -2833,6 +2832,12 @@ oper_argtypes: Typename
|
||||
{ $$ = makeList2($1, NULL); }
|
||||
;
|
||||
|
||||
any_operator: all_Op
|
||||
{ $$ = makeList1(makeString($1)); }
|
||||
| ColId '.' any_operator
|
||||
{ $$ = lcons(makeString($1), $3); }
|
||||
;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
@@ -3831,10 +3836,14 @@ sortby: a_expr OptUseOp
|
||||
}
|
||||
;
|
||||
|
||||
OptUseOp: USING all_Op { $$ = $2; }
|
||||
| ASC { $$ = "<"; }
|
||||
| DESC { $$ = ">"; }
|
||||
| /*EMPTY*/ { $$ = "<"; /*default*/ }
|
||||
OptUseOp: USING qual_all_Op
|
||||
{ $$ = $2; }
|
||||
| ASC
|
||||
{ $$ = makeList1(makeString("<")); }
|
||||
| DESC
|
||||
{ $$ = makeList1(makeString(">")); }
|
||||
| /*EMPTY*/
|
||||
{ $$ = makeList1(makeString("<")); /*default*/ }
|
||||
;
|
||||
|
||||
|
||||
@@ -4593,7 +4602,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = $2;
|
||||
n->oper = (List *) makeA_Expr(OP, "=", NULL, NULL);
|
||||
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
|
||||
n->useor = FALSE;
|
||||
n->subLinkType = ANY_SUBLINK;
|
||||
n->subselect = $5;
|
||||
@@ -4603,18 +4612,18 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = $2;
|
||||
n->oper = (List *) makeA_Expr(OP, "<>", NULL, NULL);
|
||||
n->oper = (List *) makeSimpleA_Expr(OP, "<>", NULL, NULL);
|
||||
n->useor = TRUE;
|
||||
n->subLinkType = ALL_SUBLINK;
|
||||
n->subselect = $6;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| '(' row_descriptor ')' all_Op sub_type select_with_parens
|
||||
| '(' row_descriptor ')' qual_all_Op sub_type select_with_parens %prec Op
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = $2;
|
||||
n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL);
|
||||
if (strcmp($4, "<>") == 0)
|
||||
if (strcmp(strVal(llast($4)), "<>") == 0)
|
||||
n->useor = TRUE;
|
||||
else
|
||||
n->useor = FALSE;
|
||||
@@ -4622,12 +4631,12 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
|
||||
n->subselect = $6;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| '(' row_descriptor ')' all_Op select_with_parens
|
||||
| '(' row_descriptor ')' qual_all_Op select_with_parens %prec Op
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = $2;
|
||||
n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL);
|
||||
if (strcmp($4, "<>") == 0)
|
||||
if (strcmp(strVal(llast($4)), "<>") == 0)
|
||||
n->useor = TRUE;
|
||||
else
|
||||
n->useor = FALSE;
|
||||
@@ -4635,7 +4644,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
|
||||
n->subselect = $5;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| '(' row_descriptor ')' all_Op '(' row_descriptor ')'
|
||||
| '(' row_descriptor ')' qual_all_Op '(' row_descriptor ')' %prec Op
|
||||
{
|
||||
$$ = makeRowExpr($4, $2, $6);
|
||||
}
|
||||
@@ -4696,6 +4705,18 @@ MathOp: '+' { $$ = "+"; }
|
||||
| '=' { $$ = "="; }
|
||||
;
|
||||
|
||||
qual_Op: Op
|
||||
{ $$ = makeList1(makeString($1)); }
|
||||
| OPERATOR '(' any_operator ')'
|
||||
{ $$ = $3; }
|
||||
;
|
||||
|
||||
qual_all_Op: all_Op
|
||||
{ $$ = makeList1(makeString($1)); }
|
||||
| OPERATOR '(' any_operator ')'
|
||||
{ $$ = $3; }
|
||||
;
|
||||
|
||||
/*
|
||||
* General expressions
|
||||
* This is the heart of the expression syntax.
|
||||
@@ -4735,52 +4756,52 @@ a_expr: c_expr
|
||||
* also to b_expr and to the MathOp list above.
|
||||
*/
|
||||
| '+' a_expr %prec UMINUS
|
||||
{ $$ = makeA_Expr(OP, "+", NULL, $2); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "+", NULL, $2); }
|
||||
| '-' a_expr %prec UMINUS
|
||||
{ $$ = doNegate($2); }
|
||||
| '%' a_expr
|
||||
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", NULL, $2); }
|
||||
| '^' a_expr
|
||||
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", NULL, $2); }
|
||||
| a_expr '%'
|
||||
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, NULL); }
|
||||
| a_expr '^'
|
||||
{ $$ = makeA_Expr(OP, "^", $1, NULL); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, NULL); }
|
||||
| a_expr '+' a_expr
|
||||
{ $$ = makeA_Expr(OP, "+", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "+", $1, $3); }
|
||||
| a_expr '-' a_expr
|
||||
{ $$ = makeA_Expr(OP, "-", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "-", $1, $3); }
|
||||
| a_expr '*' a_expr
|
||||
{ $$ = makeA_Expr(OP, "*", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "*", $1, $3); }
|
||||
| a_expr '/' a_expr
|
||||
{ $$ = makeA_Expr(OP, "/", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "/", $1, $3); }
|
||||
| a_expr '%' a_expr
|
||||
{ $$ = makeA_Expr(OP, "%", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, $3); }
|
||||
| a_expr '^' a_expr
|
||||
{ $$ = makeA_Expr(OP, "^", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, $3); }
|
||||
| a_expr '<' a_expr
|
||||
{ $$ = makeA_Expr(OP, "<", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "<", $1, $3); }
|
||||
| a_expr '>' a_expr
|
||||
{ $$ = makeA_Expr(OP, ">", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, ">", $1, $3); }
|
||||
| a_expr '=' a_expr
|
||||
{ $$ = makeA_Expr(OP, "=", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "=", $1, $3); }
|
||||
|
||||
| a_expr Op a_expr
|
||||
{ $$ = makeA_Expr(OP, $2, $1, $3); }
|
||||
| Op a_expr
|
||||
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
|
||||
| a_expr Op %prec POSTFIXOP
|
||||
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
|
||||
| a_expr qual_Op a_expr %prec Op
|
||||
{ $$ = (Node *) makeA_Expr(OP, $2, $1, $3); }
|
||||
| qual_Op a_expr %prec Op
|
||||
{ $$ = (Node *) makeA_Expr(OP, $1, NULL, $2); }
|
||||
| a_expr qual_Op %prec POSTFIXOP
|
||||
{ $$ = (Node *) makeA_Expr(OP, $2, $1, NULL); }
|
||||
|
||||
| a_expr AND a_expr
|
||||
{ $$ = makeA_Expr(AND, NULL, $1, $3); }
|
||||
{ $$ = (Node *) makeA_Expr(AND, NIL, $1, $3); }
|
||||
| a_expr OR a_expr
|
||||
{ $$ = makeA_Expr(OR, NULL, $1, $3); }
|
||||
{ $$ = (Node *) makeA_Expr(OR, NIL, $1, $3); }
|
||||
| NOT a_expr
|
||||
{ $$ = makeA_Expr(NOT, NULL, NULL, $2); }
|
||||
{ $$ = (Node *) makeA_Expr(NOT, NIL, NULL, $2); }
|
||||
|
||||
| a_expr LIKE a_expr
|
||||
{ $$ = makeA_Expr(OP, "~~", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "~~", $1, $3); }
|
||||
| a_expr LIKE a_expr ESCAPE a_expr
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
@@ -4788,10 +4809,10 @@ a_expr: c_expr
|
||||
n->args = makeList2($3, $5);
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = makeA_Expr(OP, "~~", $1, (Node *) n);
|
||||
$$ = (Node *) makeSimpleA_Expr(OP, "~~", $1, (Node *) n);
|
||||
}
|
||||
| a_expr NOT LIKE a_expr
|
||||
{ $$ = makeA_Expr(OP, "!~~", $1, $4); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "!~~", $1, $4); }
|
||||
| a_expr NOT LIKE a_expr ESCAPE a_expr
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
@@ -4799,10 +4820,10 @@ a_expr: c_expr
|
||||
n->args = makeList2($4, $6);
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = makeA_Expr(OP, "!~~", $1, (Node *) n);
|
||||
$$ = (Node *) makeSimpleA_Expr(OP, "!~~", $1, (Node *) n);
|
||||
}
|
||||
| a_expr ILIKE a_expr
|
||||
{ $$ = makeA_Expr(OP, "~~*", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "~~*", $1, $3); }
|
||||
| a_expr ILIKE a_expr ESCAPE a_expr
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
@@ -4810,10 +4831,10 @@ a_expr: c_expr
|
||||
n->args = makeList2($3, $5);
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = makeA_Expr(OP, "~~*", $1, (Node *) n);
|
||||
$$ = (Node *) makeSimpleA_Expr(OP, "~~*", $1, (Node *) n);
|
||||
}
|
||||
| a_expr NOT ILIKE a_expr
|
||||
{ $$ = makeA_Expr(OP, "!~~*", $1, $4); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, $4); }
|
||||
| a_expr NOT ILIKE a_expr ESCAPE a_expr
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
@@ -4821,7 +4842,7 @@ a_expr: c_expr
|
||||
n->args = makeList2($4, $6);
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = makeA_Expr(OP, "!~~*", $1, (Node *) n);
|
||||
$$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, (Node *) n);
|
||||
}
|
||||
/* NullTest clause
|
||||
* Define SQL92-style Null test clause.
|
||||
@@ -4915,15 +4936,15 @@ a_expr: c_expr
|
||||
}
|
||||
| a_expr BETWEEN b_expr AND b_expr %prec BETWEEN
|
||||
{
|
||||
$$ = makeA_Expr(AND, NULL,
|
||||
makeA_Expr(OP, ">=", $1, $3),
|
||||
makeA_Expr(OP, "<=", $1, $5));
|
||||
$$ = (Node *) makeA_Expr(AND, NIL,
|
||||
(Node *) makeSimpleA_Expr(OP, ">=", $1, $3),
|
||||
(Node *) makeSimpleA_Expr(OP, "<=", $1, $5));
|
||||
}
|
||||
| a_expr NOT BETWEEN b_expr AND b_expr %prec BETWEEN
|
||||
{
|
||||
$$ = makeA_Expr(OR, NULL,
|
||||
makeA_Expr(OP, "<", $1, $4),
|
||||
makeA_Expr(OP, ">", $1, $6));
|
||||
$$ = (Node *) makeA_Expr(OR, NIL,
|
||||
(Node *) makeSimpleA_Expr(OP, "<", $1, $4),
|
||||
(Node *) makeSimpleA_Expr(OP, ">", $1, $6));
|
||||
}
|
||||
| a_expr IN in_expr
|
||||
{
|
||||
@@ -4932,7 +4953,8 @@ a_expr: c_expr
|
||||
{
|
||||
SubLink *n = (SubLink *)$3;
|
||||
n->lefthand = makeList1($1);
|
||||
n->oper = (List *) makeA_Expr(OP, "=", NULL, NULL);
|
||||
n->oper = (List *) makeSimpleA_Expr(OP, "=",
|
||||
NULL, NULL);
|
||||
n->useor = FALSE;
|
||||
n->subLinkType = ANY_SUBLINK;
|
||||
$$ = (Node *)n;
|
||||
@@ -4943,11 +4965,13 @@ a_expr: c_expr
|
||||
List *l;
|
||||
foreach(l, (List *) $3)
|
||||
{
|
||||
Node *cmp = makeA_Expr(OP, "=", $1, lfirst(l));
|
||||
Node *cmp;
|
||||
cmp = (Node *) makeSimpleA_Expr(OP, "=",
|
||||
$1, lfirst(l));
|
||||
if (n == NULL)
|
||||
n = cmp;
|
||||
else
|
||||
n = makeA_Expr(OR, NULL, n, cmp);
|
||||
n = (Node *) makeA_Expr(OR, NIL, n, cmp);
|
||||
}
|
||||
$$ = n;
|
||||
}
|
||||
@@ -4959,7 +4983,8 @@ a_expr: c_expr
|
||||
{
|
||||
SubLink *n = (SubLink *)$4;
|
||||
n->lefthand = makeList1($1);
|
||||
n->oper = (List *) makeA_Expr(OP, "<>", NULL, NULL);
|
||||
n->oper = (List *) makeSimpleA_Expr(OP, "<>",
|
||||
NULL, NULL);
|
||||
n->useor = FALSE;
|
||||
n->subLinkType = ALL_SUBLINK;
|
||||
$$ = (Node *)n;
|
||||
@@ -4970,16 +4995,18 @@ a_expr: c_expr
|
||||
List *l;
|
||||
foreach(l, (List *) $4)
|
||||
{
|
||||
Node *cmp = makeA_Expr(OP, "<>", $1, lfirst(l));
|
||||
Node *cmp;
|
||||
cmp = (Node *) makeSimpleA_Expr(OP, "<>",
|
||||
$1, lfirst(l));
|
||||
if (n == NULL)
|
||||
n = cmp;
|
||||
else
|
||||
n = makeA_Expr(AND, NULL, n, cmp);
|
||||
n = (Node *) makeA_Expr(AND, NIL, n, cmp);
|
||||
}
|
||||
$$ = n;
|
||||
}
|
||||
}
|
||||
| a_expr all_Op sub_type select_with_parens %prec Op
|
||||
| a_expr qual_all_Op sub_type select_with_parens %prec Op
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = makeList1($1);
|
||||
@@ -5007,42 +5034,42 @@ b_expr: c_expr
|
||||
| b_expr TYPECAST Typename
|
||||
{ $$ = makeTypeCast($1, $3); }
|
||||
| '+' b_expr %prec UMINUS
|
||||
{ $$ = makeA_Expr(OP, "+", NULL, $2); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "+", NULL, $2); }
|
||||
| '-' b_expr %prec UMINUS
|
||||
{ $$ = doNegate($2); }
|
||||
| '%' b_expr
|
||||
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", NULL, $2); }
|
||||
| '^' b_expr
|
||||
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", NULL, $2); }
|
||||
| b_expr '%'
|
||||
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, NULL); }
|
||||
| b_expr '^'
|
||||
{ $$ = makeA_Expr(OP, "^", $1, NULL); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, NULL); }
|
||||
| b_expr '+' b_expr
|
||||
{ $$ = makeA_Expr(OP, "+", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "+", $1, $3); }
|
||||
| b_expr '-' b_expr
|
||||
{ $$ = makeA_Expr(OP, "-", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "-", $1, $3); }
|
||||
| b_expr '*' b_expr
|
||||
{ $$ = makeA_Expr(OP, "*", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "*", $1, $3); }
|
||||
| b_expr '/' b_expr
|
||||
{ $$ = makeA_Expr(OP, "/", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "/", $1, $3); }
|
||||
| b_expr '%' b_expr
|
||||
{ $$ = makeA_Expr(OP, "%", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, $3); }
|
||||
| b_expr '^' b_expr
|
||||
{ $$ = makeA_Expr(OP, "^", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, $3); }
|
||||
| b_expr '<' b_expr
|
||||
{ $$ = makeA_Expr(OP, "<", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "<", $1, $3); }
|
||||
| b_expr '>' b_expr
|
||||
{ $$ = makeA_Expr(OP, ">", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, ">", $1, $3); }
|
||||
| b_expr '=' b_expr
|
||||
{ $$ = makeA_Expr(OP, "=", $1, $3); }
|
||||
{ $$ = (Node *) makeSimpleA_Expr(OP, "=", $1, $3); }
|
||||
|
||||
| b_expr Op b_expr
|
||||
{ $$ = makeA_Expr(OP, $2, $1, $3); }
|
||||
| Op b_expr
|
||||
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
|
||||
| b_expr Op %prec POSTFIXOP
|
||||
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
|
||||
| b_expr qual_Op b_expr %prec Op
|
||||
{ $$ = (Node *) makeA_Expr(OP, $2, $1, $3); }
|
||||
| qual_Op b_expr %prec Op
|
||||
{ $$ = (Node *) makeA_Expr(OP, $1, NULL, $2); }
|
||||
| b_expr qual_Op %prec POSTFIXOP
|
||||
{ $$ = (Node *) makeA_Expr(OP, $2, $1, NULL); }
|
||||
;
|
||||
|
||||
/*
|
||||
@@ -5539,12 +5566,9 @@ case_expr: CASE case_arg when_clause_list case_default END_TRANS
|
||||
{
|
||||
CaseExpr *c = makeNode(CaseExpr);
|
||||
CaseWhen *w = makeNode(CaseWhen);
|
||||
/*
|
||||
A_Const *n = makeNode(A_Const);
|
||||
n->val.type = T_Null;
|
||||
w->result = (Node *)n;
|
||||
*/
|
||||
w->expr = makeA_Expr(OP, "=", $3, $5);
|
||||
|
||||
w->expr = (Node *) makeSimpleA_Expr(OP, "=", $3, $5);
|
||||
/* w->result is left NULL */
|
||||
c->args = makeList1(w);
|
||||
c->defresult = $3;
|
||||
$$ = (Node *)c;
|
||||
@@ -6243,17 +6267,6 @@ SpecialRuleRelation: OLD
|
||||
|
||||
%%
|
||||
|
||||
static Node *
|
||||
makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)
|
||||
{
|
||||
A_Expr *a = makeNode(A_Expr);
|
||||
a->oper = oper;
|
||||
a->opname = opname;
|
||||
a->lexpr = lexpr;
|
||||
a->rexpr = rexpr;
|
||||
return (Node *)a;
|
||||
}
|
||||
|
||||
static Node *
|
||||
makeTypeCast(Node *arg, TypeName *typename)
|
||||
{
|
||||
@@ -6308,41 +6321,49 @@ makeFloatConst(char *str)
|
||||
* - thomas 1997-12-22
|
||||
*/
|
||||
static Node *
|
||||
makeRowExpr(char *opr, List *largs, List *rargs)
|
||||
makeRowExpr(List *opr, List *largs, List *rargs)
|
||||
{
|
||||
Node *expr = NULL;
|
||||
Node *larg, *rarg;
|
||||
char *oprname;
|
||||
|
||||
if (length(largs) != length(rargs))
|
||||
elog(ERROR,"Unequal number of entries in row expression");
|
||||
elog(ERROR, "Unequal number of entries in row expression");
|
||||
|
||||
if (lnext(largs) != NIL)
|
||||
expr = makeRowExpr(opr,lnext(largs),lnext(rargs));
|
||||
expr = makeRowExpr(opr, lnext(largs), lnext(rargs));
|
||||
|
||||
larg = lfirst(largs);
|
||||
rarg = lfirst(rargs);
|
||||
|
||||
if ((strcmp(opr, "=") == 0)
|
||||
|| (strcmp(opr, "<") == 0)
|
||||
|| (strcmp(opr, "<=") == 0)
|
||||
|| (strcmp(opr, ">") == 0)
|
||||
|| (strcmp(opr, ">=") == 0))
|
||||
oprname = strVal(llast(opr));
|
||||
|
||||
if ((strcmp(oprname, "=") == 0) ||
|
||||
(strcmp(oprname, "<") == 0) ||
|
||||
(strcmp(oprname, "<=") == 0) ||
|
||||
(strcmp(oprname, ">") == 0) ||
|
||||
(strcmp(oprname, ">=") == 0))
|
||||
{
|
||||
if (expr == NULL)
|
||||
expr = makeA_Expr(OP, opr, larg, rarg);
|
||||
expr = (Node *) makeA_Expr(OP, opr, larg, rarg);
|
||||
else
|
||||
expr = makeA_Expr(AND, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
|
||||
expr = (Node *) makeA_Expr(AND, NIL, expr,
|
||||
(Node *) makeA_Expr(OP, opr,
|
||||
larg, rarg));
|
||||
}
|
||||
else if (strcmp(opr, "<>") == 0)
|
||||
else if (strcmp(oprname, "<>") == 0)
|
||||
{
|
||||
if (expr == NULL)
|
||||
expr = makeA_Expr(OP, opr, larg, rarg);
|
||||
expr = (Node *) makeA_Expr(OP, opr, larg, rarg);
|
||||
else
|
||||
expr = makeA_Expr(OR, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
|
||||
expr = (Node *) makeA_Expr(OR, NIL, expr,
|
||||
(Node *) makeA_Expr(OP, opr,
|
||||
larg, rarg));
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR,"Operator '%s' not implemented for row expressions",opr);
|
||||
elog(ERROR, "Operator '%s' not implemented for row expressions",
|
||||
oprname);
|
||||
}
|
||||
|
||||
return expr;
|
||||
@@ -6557,7 +6578,7 @@ doNegate(Node *n)
|
||||
}
|
||||
}
|
||||
|
||||
return makeA_Expr(OP, "-", NULL, n);
|
||||
return (Node *) makeSimpleA_Expr(OP, "-", NULL, n);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.88 2002/04/15 06:05:49 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.89 2002/04/16 23:08:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -54,7 +54,7 @@ static Node *transformFromClauseItem(ParseState *pstate, Node *n,
|
||||
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
|
||||
List *tlist, int clause);
|
||||
static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
|
||||
List *targetlist, char *opname);
|
||||
List *targetlist, List *opname);
|
||||
static bool exprIsInSortList(Node *expr, List *sortList, List *targetList);
|
||||
|
||||
|
||||
@@ -257,22 +257,15 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
|
||||
Node *rvar = (Node *) lfirst(rvars);
|
||||
A_Expr *e;
|
||||
|
||||
e = makeNode(A_Expr);
|
||||
e->oper = OP;
|
||||
e->opname = "=";
|
||||
e->lexpr = copyObject(lvar);
|
||||
e->rexpr = copyObject(rvar);
|
||||
e = makeSimpleA_Expr(OP, "=", copyObject(lvar), copyObject(rvar));
|
||||
|
||||
if (result == NULL)
|
||||
result = (Node *) e;
|
||||
else
|
||||
{
|
||||
A_Expr *a = makeNode(A_Expr);
|
||||
A_Expr *a;
|
||||
|
||||
a->oper = AND;
|
||||
a->opname = NULL;
|
||||
a->lexpr = result;
|
||||
a->rexpr = (Node *) e;
|
||||
a = makeA_Expr(AND, NIL, result, (Node *) e);
|
||||
result = (Node *) a;
|
||||
}
|
||||
|
||||
@@ -1117,7 +1110,7 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
|
||||
else
|
||||
{
|
||||
*sortClause = addTargetToSortList(tle, *sortClause,
|
||||
targetlist, NULL);
|
||||
targetlist, NIL);
|
||||
|
||||
/*
|
||||
* Probably, the tle should always have been added at the
|
||||
@@ -1160,7 +1153,7 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
|
||||
TargetEntry *tle = (TargetEntry *) lfirst(i);
|
||||
|
||||
if (!tle->resdom->resjunk)
|
||||
sortlist = addTargetToSortList(tle, sortlist, targetlist, NULL);
|
||||
sortlist = addTargetToSortList(tle, sortlist, targetlist, NIL);
|
||||
}
|
||||
return sortlist;
|
||||
}
|
||||
@@ -1169,13 +1162,13 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
|
||||
* addTargetToSortList
|
||||
* If the given targetlist entry isn't already in the ORDER BY list,
|
||||
* add it to the end of the list, using the sortop with given name
|
||||
* or any available sort operator if opname == NULL.
|
||||
* or any available sort operator if opname == NIL.
|
||||
*
|
||||
* Returns the updated ORDER BY list.
|
||||
*/
|
||||
static List *
|
||||
addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist,
|
||||
char *opname)
|
||||
List *opname)
|
||||
{
|
||||
/* avoid making duplicate sortlist entries */
|
||||
if (!exprIsInSortList(tle->expr, sortlist, targetlist))
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.114 2002/04/11 20:00:00 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.115 2002/04/16 23:08:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -192,7 +192,8 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
* into IS NULL exprs.
|
||||
*/
|
||||
if (Transform_null_equals &&
|
||||
strcmp(a->opname, "=") == 0 &&
|
||||
length(a->name) == 1 &&
|
||||
strcmp(strVal(lfirst(a->name)), "=") == 0 &&
|
||||
(exprIsNullConstant(a->lexpr) ||
|
||||
exprIsNullConstant(a->rexpr)))
|
||||
{
|
||||
@@ -215,7 +216,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
Node *rexpr = transformExpr(pstate,
|
||||
a->rexpr);
|
||||
|
||||
result = (Node *) make_op(a->opname,
|
||||
result = (Node *) make_op(a->name,
|
||||
lexpr,
|
||||
rexpr);
|
||||
}
|
||||
@@ -366,21 +367,23 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
/* ALL, ANY, or MULTIEXPR: generate operator list */
|
||||
List *left_list = sublink->lefthand;
|
||||
List *right_list = qtree->targetList;
|
||||
char *op;
|
||||
List *op;
|
||||
char *opname;
|
||||
List *elist;
|
||||
|
||||
foreach(elist, left_list)
|
||||
lfirst(elist) = transformExpr(pstate, lfirst(elist));
|
||||
|
||||
Assert(IsA(sublink->oper, A_Expr));
|
||||
op = ((A_Expr *) sublink->oper)->opname;
|
||||
op = ((A_Expr *) sublink->oper)->name;
|
||||
opname = strVal(llast(op));
|
||||
sublink->oper = NIL;
|
||||
|
||||
/* Combining operators other than =/<> is dubious... */
|
||||
if (length(left_list) != 1 &&
|
||||
strcmp(op, "=") != 0 && strcmp(op, "<>") != 0)
|
||||
strcmp(opname, "=") != 0 && strcmp(opname, "<>") != 0)
|
||||
elog(ERROR, "Row comparison cannot use '%s'",
|
||||
op);
|
||||
opname);
|
||||
|
||||
/*
|
||||
* Scan subquery's targetlist to find values that will
|
||||
@@ -420,7 +423,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
if (opform->oprresult != BOOLOID)
|
||||
elog(ERROR, "'%s' result type of '%s' must return '%s'"
|
||||
" to be used with quantified predicate subquery",
|
||||
op, typeidTypeName(opform->oprresult),
|
||||
opname, typeidTypeName(opform->oprresult),
|
||||
typeidTypeName(BOOLOID));
|
||||
|
||||
newop = makeOper(oprid(optup), /* opno */
|
||||
@@ -459,13 +462,8 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
if (c->arg != NULL)
|
||||
{
|
||||
/* shorthand form was specified, so expand... */
|
||||
A_Expr *a = makeNode(A_Expr);
|
||||
|
||||
a->oper = OP;
|
||||
a->opname = "=";
|
||||
a->lexpr = c->arg;
|
||||
a->rexpr = warg;
|
||||
warg = (Node *) a;
|
||||
warg = (Node *) makeSimpleA_Expr(OP, "=",
|
||||
c->arg, warg);
|
||||
}
|
||||
neww->expr = transformExpr(pstate, warg);
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.61 2002/04/11 20:00:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.62 2002/04/16 23:08:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -62,10 +62,7 @@ make_parsestate(ParseState *parentParseState)
|
||||
* Ensure argument type match by forcing conversion of constants.
|
||||
*/
|
||||
Node *
|
||||
make_operand(char *opname,
|
||||
Node *tree,
|
||||
Oid orig_typeId,
|
||||
Oid target_typeId)
|
||||
make_operand(Node *tree, Oid orig_typeId, Oid target_typeId)
|
||||
{
|
||||
Node *result;
|
||||
|
||||
@@ -95,7 +92,7 @@ make_operand(char *opname,
|
||||
* This is where some type conversion happens.
|
||||
*/
|
||||
Expr *
|
||||
make_op(char *opname, Node *ltree, Node *rtree)
|
||||
make_op(List *opname, Node *ltree, Node *rtree)
|
||||
{
|
||||
Oid ltypeId,
|
||||
rtypeId;
|
||||
@@ -114,7 +111,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
|
||||
{
|
||||
tup = right_oper(opname, ltypeId);
|
||||
opform = (Form_pg_operator) GETSTRUCT(tup);
|
||||
left = make_operand(opname, ltree, ltypeId, opform->oprleft);
|
||||
left = make_operand(ltree, ltypeId, opform->oprleft);
|
||||
right = NULL;
|
||||
}
|
||||
|
||||
@@ -123,7 +120,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
|
||||
{
|
||||
tup = left_oper(opname, rtypeId);
|
||||
opform = (Form_pg_operator) GETSTRUCT(tup);
|
||||
right = make_operand(opname, rtree, rtypeId, opform->oprright);
|
||||
right = make_operand(rtree, rtypeId, opform->oprright);
|
||||
left = NULL;
|
||||
}
|
||||
|
||||
@@ -132,8 +129,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
|
||||
{
|
||||
tup = oper(opname, ltypeId, rtypeId, false);
|
||||
opform = (Form_pg_operator) GETSTRUCT(tup);
|
||||
left = make_operand(opname, ltree, ltypeId, opform->oprleft);
|
||||
right = make_operand(opname, rtree, rtypeId, opform->oprright);
|
||||
left = make_operand(ltree, ltypeId, opform->oprleft);
|
||||
right = make_operand(rtree, rtypeId, opform->oprright);
|
||||
}
|
||||
|
||||
newop = makeOper(oprid(tup), /* opno */
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.54 2002/04/11 20:00:02 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.55 2002/04/16 23:08:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
#include "parser/parse_func.h"
|
||||
@@ -28,17 +29,106 @@
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
static Oid *oper_select_candidate(int nargs, Oid *input_typeids,
|
||||
CandidateList candidates);
|
||||
static Operator oper_exact(char *op, Oid arg1, Oid arg2);
|
||||
static Operator oper_inexact(char *op, Oid arg1, Oid arg2);
|
||||
static int binary_oper_get_candidates(char *opname,
|
||||
CandidateList *candidates);
|
||||
static int unary_oper_get_candidates(char *opname,
|
||||
CandidateList *candidates,
|
||||
char rightleft);
|
||||
static void op_error(char *op, Oid arg1, Oid arg2);
|
||||
static void unary_op_error(char *op, Oid arg, bool is_left_op);
|
||||
static Oid binary_oper_exact(Oid arg1, Oid arg2,
|
||||
FuncCandidateList candidates);
|
||||
static Oid oper_select_candidate(int nargs, Oid *input_typeids,
|
||||
FuncCandidateList candidates);
|
||||
static void op_error(List *op, Oid arg1, Oid arg2);
|
||||
static void unary_op_error(List *op, Oid arg, bool is_left_op);
|
||||
|
||||
|
||||
/*
|
||||
* LookupOperName
|
||||
* Given a possibly-qualified operator name and exact input datatypes,
|
||||
* look up the operator. Returns InvalidOid if no such operator.
|
||||
*
|
||||
* Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
|
||||
* a postfix op.
|
||||
*
|
||||
* If the operator name is not schema-qualified, it is sought in the current
|
||||
* namespace search path.
|
||||
*/
|
||||
Oid
|
||||
LookupOperName(List *opername, Oid oprleft, Oid oprright)
|
||||
{
|
||||
FuncCandidateList clist;
|
||||
char oprkind;
|
||||
|
||||
if (!OidIsValid(oprleft))
|
||||
oprkind = 'l';
|
||||
else if (!OidIsValid(oprright))
|
||||
oprkind = 'r';
|
||||
else
|
||||
oprkind = 'b';
|
||||
|
||||
clist = OpernameGetCandidates(opername, oprkind);
|
||||
|
||||
while (clist)
|
||||
{
|
||||
if (clist->args[0] == oprleft && clist->args[1] == oprright)
|
||||
return clist->oid;
|
||||
clist = clist->next;
|
||||
}
|
||||
|
||||
return InvalidOid;
|
||||
}
|
||||
|
||||
/*
|
||||
* LookupOperNameTypeNames
|
||||
* Like LookupOperName, but the argument types are specified by
|
||||
* TypeName nodes. Also, if we fail to find the operator
|
||||
* and caller is not NULL, then an error is reported.
|
||||
*
|
||||
* Pass oprleft = NULL for a prefix op, oprright = NULL for a postfix op.
|
||||
*/
|
||||
Oid
|
||||
LookupOperNameTypeNames(List *opername, TypeName *oprleft,
|
||||
TypeName *oprright, const char *caller)
|
||||
{
|
||||
Oid operoid;
|
||||
Oid leftoid,
|
||||
rightoid;
|
||||
|
||||
if (oprleft == NULL)
|
||||
leftoid = InvalidOid;
|
||||
else
|
||||
{
|
||||
leftoid = LookupTypeName(oprleft);
|
||||
if (!OidIsValid(leftoid))
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(oprleft));
|
||||
}
|
||||
if (oprright == NULL)
|
||||
rightoid = InvalidOid;
|
||||
else
|
||||
{
|
||||
rightoid = LookupTypeName(oprright);
|
||||
if (!OidIsValid(rightoid))
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(oprright));
|
||||
}
|
||||
|
||||
operoid = LookupOperName(opername, leftoid, rightoid);
|
||||
|
||||
if (!OidIsValid(operoid) && caller != NULL)
|
||||
{
|
||||
if (oprleft == NULL)
|
||||
elog(ERROR, "%s: Prefix operator '%s' for type '%s' does not exist",
|
||||
caller, NameListToString(opername),
|
||||
TypeNameToString(oprright));
|
||||
else if (oprright == NULL)
|
||||
elog(ERROR, "%s: Postfix operator '%s' for type '%s' does not exist",
|
||||
caller, NameListToString(opername),
|
||||
TypeNameToString(oprleft));
|
||||
else
|
||||
elog(ERROR, "%s: Operator '%s' for types '%s' and '%s' does not exist",
|
||||
caller, NameListToString(opername),
|
||||
TypeNameToString(oprleft),
|
||||
TypeNameToString(oprright));
|
||||
}
|
||||
|
||||
return operoid;
|
||||
}
|
||||
|
||||
|
||||
/* Select an ordering operator for the given datatype */
|
||||
@@ -47,7 +137,8 @@ any_ordering_op(Oid argtype)
|
||||
{
|
||||
Oid order_opid;
|
||||
|
||||
order_opid = compatible_oper_opid("<", argtype, argtype, true);
|
||||
order_opid = compatible_oper_opid(makeList1(makeString("<")),
|
||||
argtype, argtype, true);
|
||||
if (!OidIsValid(order_opid))
|
||||
elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'"
|
||||
"\n\tUse an explicit ordering operator or modify the query",
|
||||
@@ -72,116 +163,32 @@ oprfuncid(Operator op)
|
||||
}
|
||||
|
||||
|
||||
/* binary_oper_get_candidates()
|
||||
* given opname, find all possible input type pairs for which an operator
|
||||
* named opname exists.
|
||||
* Build a list of the candidate input types.
|
||||
* Returns number of candidates found.
|
||||
/* binary_oper_exact()
|
||||
* Check for an "exact" match to the specified operand types.
|
||||
*
|
||||
* If one operand is an unknown literal, assume it should be taken to be
|
||||
* the same type as the other operand for this purpose.
|
||||
*/
|
||||
static int
|
||||
binary_oper_get_candidates(char *opname,
|
||||
CandidateList *candidates)
|
||||
static Oid
|
||||
binary_oper_exact(Oid arg1, Oid arg2,
|
||||
FuncCandidateList candidates)
|
||||
{
|
||||
Relation pg_operator_desc;
|
||||
SysScanDesc pg_operator_scan;
|
||||
HeapTuple tup;
|
||||
int ncandidates = 0;
|
||||
ScanKeyData opKey[1];
|
||||
/* Unspecified type for one of the arguments? then use the other */
|
||||
if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
|
||||
arg1 = arg2;
|
||||
else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
|
||||
arg2 = arg1;
|
||||
|
||||
*candidates = NULL;
|
||||
|
||||
ScanKeyEntryInitialize(&opKey[0], 0,
|
||||
Anum_pg_operator_oprname,
|
||||
F_NAMEEQ,
|
||||
NameGetDatum(opname));
|
||||
|
||||
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
|
||||
pg_operator_scan = systable_beginscan(pg_operator_desc,
|
||||
OperatorNameIndex, true,
|
||||
SnapshotNow,
|
||||
1, opKey);
|
||||
|
||||
while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan)))
|
||||
while (candidates != NULL)
|
||||
{
|
||||
Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup);
|
||||
|
||||
if (oper->oprkind == 'b')
|
||||
{
|
||||
CandidateList current_candidate;
|
||||
|
||||
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
|
||||
current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
|
||||
|
||||
current_candidate->args[0] = oper->oprleft;
|
||||
current_candidate->args[1] = oper->oprright;
|
||||
current_candidate->next = *candidates;
|
||||
*candidates = current_candidate;
|
||||
ncandidates++;
|
||||
}
|
||||
if (arg1 == candidates->args[0] &&
|
||||
arg2 == candidates->args[1])
|
||||
return candidates->oid;
|
||||
candidates = candidates->next;
|
||||
}
|
||||
|
||||
systable_endscan(pg_operator_scan);
|
||||
heap_close(pg_operator_desc, AccessShareLock);
|
||||
|
||||
return ncandidates;
|
||||
} /* binary_oper_get_candidates() */
|
||||
|
||||
/* unary_oper_get_candidates()
|
||||
* given opname, find all possible types for which
|
||||
* a right/left unary operator named opname exists.
|
||||
* Build a list of the candidate input types.
|
||||
* Returns number of candidates found.
|
||||
*/
|
||||
static int
|
||||
unary_oper_get_candidates(char *opname,
|
||||
CandidateList *candidates,
|
||||
char rightleft)
|
||||
{
|
||||
Relation pg_operator_desc;
|
||||
SysScanDesc pg_operator_scan;
|
||||
HeapTuple tup;
|
||||
int ncandidates = 0;
|
||||
ScanKeyData opKey[1];
|
||||
|
||||
*candidates = NULL;
|
||||
|
||||
ScanKeyEntryInitialize(&opKey[0], 0,
|
||||
Anum_pg_operator_oprname,
|
||||
F_NAMEEQ,
|
||||
NameGetDatum(opname));
|
||||
|
||||
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
|
||||
pg_operator_scan = systable_beginscan(pg_operator_desc,
|
||||
OperatorNameIndex, true,
|
||||
SnapshotNow,
|
||||
1, opKey);
|
||||
|
||||
while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan)))
|
||||
{
|
||||
Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup);
|
||||
|
||||
if (oper->oprkind == rightleft)
|
||||
{
|
||||
CandidateList current_candidate;
|
||||
|
||||
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
|
||||
current_candidate->args = (Oid *) palloc(sizeof(Oid));
|
||||
|
||||
if (rightleft == 'r')
|
||||
current_candidate->args[0] = oper->oprleft;
|
||||
else
|
||||
current_candidate->args[0] = oper->oprright;
|
||||
current_candidate->next = *candidates;
|
||||
*candidates = current_candidate;
|
||||
ncandidates++;
|
||||
}
|
||||
}
|
||||
|
||||
systable_endscan(pg_operator_scan);
|
||||
heap_close(pg_operator_desc, AccessShareLock);
|
||||
|
||||
return ncandidates;
|
||||
} /* unary_oper_get_candidates() */
|
||||
return InvalidOid;
|
||||
}
|
||||
|
||||
|
||||
/* oper_select_candidate()
|
||||
@@ -234,13 +241,13 @@ unary_oper_get_candidates(char *opname,
|
||||
* some sense. (see equivalentOpersAfterPromotion for details.)
|
||||
* - ay 6/95
|
||||
*/
|
||||
static Oid *
|
||||
static Oid
|
||||
oper_select_candidate(int nargs,
|
||||
Oid *input_typeids,
|
||||
CandidateList candidates)
|
||||
FuncCandidateList candidates)
|
||||
{
|
||||
CandidateList current_candidate;
|
||||
CandidateList last_candidate;
|
||||
FuncCandidateList current_candidate;
|
||||
FuncCandidateList last_candidate;
|
||||
Oid *current_typeids;
|
||||
Oid current_type;
|
||||
int unknownOids;
|
||||
@@ -289,9 +296,9 @@ oper_select_candidate(int nargs,
|
||||
|
||||
/* Done if no candidate or only one candidate survives */
|
||||
if (ncandidates == 0)
|
||||
return NULL;
|
||||
return InvalidOid;
|
||||
if (ncandidates == 1)
|
||||
return candidates->args;
|
||||
return candidates->oid;
|
||||
|
||||
/*
|
||||
* Run through all candidates and keep those with the most matches on
|
||||
@@ -335,7 +342,7 @@ oper_select_candidate(int nargs,
|
||||
last_candidate->next = NULL;
|
||||
|
||||
if (ncandidates == 1)
|
||||
return candidates->args;
|
||||
return candidates->oid;
|
||||
|
||||
/*
|
||||
* Still too many candidates? Run through all candidates and keep
|
||||
@@ -382,7 +389,7 @@ oper_select_candidate(int nargs,
|
||||
last_candidate->next = NULL;
|
||||
|
||||
if (ncandidates == 1)
|
||||
return candidates->args;
|
||||
return candidates->oid;
|
||||
|
||||
/*
|
||||
* Still too many candidates? Now look for candidates which are
|
||||
@@ -428,7 +435,7 @@ oper_select_candidate(int nargs,
|
||||
last_candidate->next = NULL;
|
||||
|
||||
if (ncandidates == 1)
|
||||
return candidates->args;
|
||||
return candidates->oid;
|
||||
|
||||
/*
|
||||
* Still too many candidates? Try assigning types for the unknown
|
||||
@@ -467,7 +474,7 @@ oper_select_candidate(int nargs,
|
||||
nmatch++;
|
||||
}
|
||||
if (nmatch == nargs)
|
||||
return current_typeids;
|
||||
return current_candidate->oid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,87 +609,12 @@ oper_select_candidate(int nargs,
|
||||
}
|
||||
|
||||
if (ncandidates == 1)
|
||||
return candidates->args;
|
||||
return candidates->oid;
|
||||
|
||||
return NULL; /* failed to determine a unique candidate */
|
||||
return InvalidOid; /* failed to determine a unique candidate */
|
||||
} /* oper_select_candidate() */
|
||||
|
||||
|
||||
/* oper_exact()
|
||||
* Given operator, types of arg1 and arg2, return oper struct or NULL.
|
||||
*
|
||||
* NOTE: on success, the returned object is a syscache entry. The caller
|
||||
* must ReleaseSysCache() the entry when done with it.
|
||||
*/
|
||||
static Operator
|
||||
oper_exact(char *op, Oid arg1, Oid arg2)
|
||||
{
|
||||
HeapTuple tup;
|
||||
|
||||
/* Unspecified type for one of the arguments? then use the other */
|
||||
if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
|
||||
arg1 = arg2;
|
||||
else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
|
||||
arg2 = arg1;
|
||||
|
||||
tup = SearchSysCache(OPERNAME,
|
||||
PointerGetDatum(op),
|
||||
ObjectIdGetDatum(arg1),
|
||||
ObjectIdGetDatum(arg2),
|
||||
CharGetDatum('b'));
|
||||
|
||||
return (Operator) tup;
|
||||
}
|
||||
|
||||
|
||||
/* oper_inexact()
|
||||
* Given operator, types of arg1 and arg2, return oper struct or NULL.
|
||||
*
|
||||
* NOTE: on success, the returned object is a syscache entry. The caller
|
||||
* must ReleaseSysCache() the entry when done with it.
|
||||
*/
|
||||
static Operator
|
||||
oper_inexact(char *op, Oid arg1, Oid arg2)
|
||||
{
|
||||
HeapTuple tup;
|
||||
CandidateList candidates;
|
||||
int ncandidates;
|
||||
Oid *targetOids;
|
||||
Oid inputOids[2];
|
||||
|
||||
/* Unspecified type for one of the arguments? then use the other */
|
||||
if (arg2 == InvalidOid)
|
||||
arg2 = arg1;
|
||||
if (arg1 == InvalidOid)
|
||||
arg1 = arg2;
|
||||
|
||||
ncandidates = binary_oper_get_candidates(op, &candidates);
|
||||
|
||||
/* No operators found? Then return null... */
|
||||
if (ncandidates == 0)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Otherwise, check for compatible datatypes, and then try to resolve
|
||||
* the conflict if more than one candidate remains.
|
||||
*/
|
||||
inputOids[0] = arg1;
|
||||
inputOids[1] = arg2;
|
||||
targetOids = oper_select_candidate(2, inputOids, candidates);
|
||||
if (targetOids != NULL)
|
||||
{
|
||||
tup = SearchSysCache(OPERNAME,
|
||||
PointerGetDatum(op),
|
||||
ObjectIdGetDatum(targetOids[0]),
|
||||
ObjectIdGetDatum(targetOids[1]),
|
||||
CharGetDatum('b'));
|
||||
}
|
||||
else
|
||||
tup = NULL;
|
||||
return (Operator) tup;
|
||||
}
|
||||
|
||||
|
||||
/* oper() -- search for a binary operator
|
||||
* Given operator name, types of arg1 and arg2, return oper struct.
|
||||
*
|
||||
@@ -697,22 +629,48 @@ oper_inexact(char *op, Oid arg1, Oid arg2)
|
||||
* must ReleaseSysCache() the entry when done with it.
|
||||
*/
|
||||
Operator
|
||||
oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError)
|
||||
oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError)
|
||||
{
|
||||
HeapTuple tup;
|
||||
FuncCandidateList clist;
|
||||
Oid operOid;
|
||||
Oid inputOids[2];
|
||||
HeapTuple tup = NULL;
|
||||
|
||||
/* check for exact match on this operator... */
|
||||
if (HeapTupleIsValid(tup = oper_exact(opname, ltypeId, rtypeId)))
|
||||
return (Operator) tup;
|
||||
/* Get binary operators of given name */
|
||||
clist = OpernameGetCandidates(opname, 'b');
|
||||
|
||||
/* try to find a match on likely candidates... */
|
||||
if (HeapTupleIsValid(tup = oper_inexact(opname, ltypeId, rtypeId)))
|
||||
return (Operator) tup;
|
||||
/* No operators found? Then fail... */
|
||||
if (clist != NULL)
|
||||
{
|
||||
/*
|
||||
* Check for an "exact" match.
|
||||
*/
|
||||
operOid = binary_oper_exact(ltypeId, rtypeId, clist);
|
||||
if (!OidIsValid(operOid))
|
||||
{
|
||||
/*
|
||||
* Otherwise, search for the most suitable candidate.
|
||||
*/
|
||||
|
||||
if (!noError)
|
||||
/* Unspecified type for one of the arguments? then use the other */
|
||||
if (rtypeId == InvalidOid)
|
||||
rtypeId = ltypeId;
|
||||
else if (ltypeId == InvalidOid)
|
||||
ltypeId = rtypeId;
|
||||
inputOids[0] = ltypeId;
|
||||
inputOids[1] = rtypeId;
|
||||
operOid = oper_select_candidate(2, inputOids, clist);
|
||||
}
|
||||
if (OidIsValid(operOid))
|
||||
tup = SearchSysCache(OPEROID,
|
||||
ObjectIdGetDatum(operOid),
|
||||
0, 0, 0);
|
||||
}
|
||||
|
||||
if (!HeapTupleIsValid(tup) && !noError)
|
||||
op_error(opname, ltypeId, rtypeId);
|
||||
|
||||
return (Operator) NULL;
|
||||
return (Operator) tup;
|
||||
}
|
||||
|
||||
/* compatible_oper()
|
||||
@@ -723,7 +681,7 @@ oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError)
|
||||
* are accepted). Otherwise, the semantics are the same.
|
||||
*/
|
||||
Operator
|
||||
compatible_oper(char *op, Oid arg1, Oid arg2, bool noError)
|
||||
compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
|
||||
{
|
||||
Operator optup;
|
||||
Form_pg_operator opform;
|
||||
@@ -755,7 +713,7 @@ compatible_oper(char *op, Oid arg1, Oid arg2, bool noError)
|
||||
* lookup fails and noError is true.
|
||||
*/
|
||||
Oid
|
||||
compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError)
|
||||
compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
|
||||
{
|
||||
Operator optup;
|
||||
Oid result;
|
||||
@@ -777,7 +735,7 @@ compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError)
|
||||
* lookup fails and noError is true.
|
||||
*/
|
||||
Oid
|
||||
compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError)
|
||||
compatible_oper_funcid(List *op, Oid arg1, Oid arg2, bool noError)
|
||||
{
|
||||
Operator optup;
|
||||
Oid result;
|
||||
@@ -805,46 +763,50 @@ compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError)
|
||||
* must ReleaseSysCache() the entry when done with it.
|
||||
*/
|
||||
Operator
|
||||
right_oper(char *op, Oid arg)
|
||||
right_oper(List *op, Oid arg)
|
||||
{
|
||||
HeapTuple tup;
|
||||
CandidateList candidates;
|
||||
int ncandidates;
|
||||
Oid *targetOid;
|
||||
FuncCandidateList clist;
|
||||
Oid operOid = InvalidOid;
|
||||
HeapTuple tup = NULL;
|
||||
|
||||
/* Try for exact match */
|
||||
tup = SearchSysCache(OPERNAME,
|
||||
PointerGetDatum(op),
|
||||
ObjectIdGetDatum(arg),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
CharGetDatum('r'));
|
||||
/* Find candidates */
|
||||
clist = OpernameGetCandidates(op, 'r');
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
if (clist != NULL)
|
||||
{
|
||||
/* Try for inexact matches */
|
||||
ncandidates = unary_oper_get_candidates(op, &candidates, 'r');
|
||||
if (ncandidates == 0)
|
||||
unary_op_error(op, arg, FALSE);
|
||||
else
|
||||
/*
|
||||
* First, quickly check to see if there is an exactly matching
|
||||
* operator (there can be only one such entry in the list).
|
||||
*/
|
||||
FuncCandidateList clisti;
|
||||
|
||||
for (clisti = clist; clisti != NULL; clisti = clisti->next)
|
||||
{
|
||||
if (arg == clisti->args[0])
|
||||
{
|
||||
operOid = clisti->oid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!OidIsValid(operOid))
|
||||
{
|
||||
/*
|
||||
* We must run oper_select_candidate even if only one
|
||||
* candidate, otherwise we may falsely return a
|
||||
* non-type-compatible operator.
|
||||
*/
|
||||
targetOid = oper_select_candidate(1, &arg, candidates);
|
||||
if (targetOid != NULL)
|
||||
tup = SearchSysCache(OPERNAME,
|
||||
PointerGetDatum(op),
|
||||
ObjectIdGetDatum(targetOid[0]),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
CharGetDatum('r'));
|
||||
operOid = oper_select_candidate(1, &arg, clist);
|
||||
}
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
unary_op_error(op, arg, FALSE);
|
||||
if (OidIsValid(operOid))
|
||||
tup = SearchSysCache(OPEROID,
|
||||
ObjectIdGetDatum(operOid),
|
||||
0, 0, 0);
|
||||
}
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
unary_op_error(op, arg, FALSE);
|
||||
|
||||
return (Operator) tup;
|
||||
} /* right_oper() */
|
||||
|
||||
@@ -861,46 +823,55 @@ right_oper(char *op, Oid arg)
|
||||
* must ReleaseSysCache() the entry when done with it.
|
||||
*/
|
||||
Operator
|
||||
left_oper(char *op, Oid arg)
|
||||
left_oper(List *op, Oid arg)
|
||||
{
|
||||
HeapTuple tup;
|
||||
CandidateList candidates;
|
||||
int ncandidates;
|
||||
Oid *targetOid;
|
||||
FuncCandidateList clist;
|
||||
Oid operOid = InvalidOid;
|
||||
HeapTuple tup = NULL;
|
||||
|
||||
/* Try for exact match */
|
||||
tup = SearchSysCache(OPERNAME,
|
||||
PointerGetDatum(op),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
ObjectIdGetDatum(arg),
|
||||
CharGetDatum('l'));
|
||||
/* Find candidates */
|
||||
clist = OpernameGetCandidates(op, 'l');
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
if (clist != NULL)
|
||||
{
|
||||
/* Try for inexact matches */
|
||||
ncandidates = unary_oper_get_candidates(op, &candidates, 'l');
|
||||
if (ncandidates == 0)
|
||||
unary_op_error(op, arg, TRUE);
|
||||
else
|
||||
/*
|
||||
* First, quickly check to see if there is an exactly matching
|
||||
* operator (there can be only one such entry in the list).
|
||||
*
|
||||
* The returned list has args in the form (0, oprright). Move the
|
||||
* useful data into args[0] to keep oper_select_candidate simple.
|
||||
* XXX we are assuming here that we may scribble on the list!
|
||||
*/
|
||||
FuncCandidateList clisti;
|
||||
|
||||
for (clisti = clist; clisti != NULL; clisti = clisti->next)
|
||||
{
|
||||
clisti->args[0] = clisti->args[1];
|
||||
if (arg == clisti->args[0])
|
||||
{
|
||||
operOid = clisti->oid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!OidIsValid(operOid))
|
||||
{
|
||||
/*
|
||||
* We must run oper_select_candidate even if only one
|
||||
* candidate, otherwise we may falsely return a
|
||||
* non-type-compatible operator.
|
||||
*/
|
||||
targetOid = oper_select_candidate(1, &arg, candidates);
|
||||
if (targetOid != NULL)
|
||||
tup = SearchSysCache(OPERNAME,
|
||||
PointerGetDatum(op),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
ObjectIdGetDatum(targetOid[0]),
|
||||
CharGetDatum('l'));
|
||||
operOid = oper_select_candidate(1, &arg, clist);
|
||||
}
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
unary_op_error(op, arg, TRUE);
|
||||
if (OidIsValid(operOid))
|
||||
tup = SearchSysCache(OPEROID,
|
||||
ObjectIdGetDatum(operOid),
|
||||
0, 0, 0);
|
||||
}
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
unary_op_error(op, arg, TRUE);
|
||||
|
||||
return (Operator) tup;
|
||||
} /* left_oper() */
|
||||
|
||||
@@ -910,19 +881,22 @@ left_oper(char *op, Oid arg)
|
||||
* is not found.
|
||||
*/
|
||||
static void
|
||||
op_error(char *op, Oid arg1, Oid arg2)
|
||||
op_error(List *op, Oid arg1, Oid arg2)
|
||||
{
|
||||
if (!typeidIsValid(arg1))
|
||||
elog(ERROR, "Left hand side of operator '%s' has an unknown type"
|
||||
"\n\tProbably a bad attribute name", op);
|
||||
"\n\tProbably a bad attribute name",
|
||||
NameListToString(op));
|
||||
|
||||
if (!typeidIsValid(arg2))
|
||||
elog(ERROR, "Right hand side of operator %s has an unknown type"
|
||||
"\n\tProbably a bad attribute name", op);
|
||||
"\n\tProbably a bad attribute name",
|
||||
NameListToString(op));
|
||||
|
||||
elog(ERROR, "Unable to identify an operator '%s' for types '%s' and '%s'"
|
||||
"\n\tYou will have to retype this query using an explicit cast",
|
||||
op, format_type_be(arg1), format_type_be(arg2));
|
||||
NameListToString(op),
|
||||
format_type_be(arg1), format_type_be(arg2));
|
||||
}
|
||||
|
||||
/* unary_op_error()
|
||||
@@ -930,28 +904,28 @@ op_error(char *op, Oid arg1, Oid arg2)
|
||||
* is not found.
|
||||
*/
|
||||
static void
|
||||
unary_op_error(char *op, Oid arg, bool is_left_op)
|
||||
unary_op_error(List *op, Oid arg, bool is_left_op)
|
||||
{
|
||||
if (!typeidIsValid(arg))
|
||||
{
|
||||
if (is_left_op)
|
||||
elog(ERROR, "operand of prefix operator '%s' has an unknown type"
|
||||
"\n\t(probably an invalid column reference)",
|
||||
op);
|
||||
NameListToString(op));
|
||||
else
|
||||
elog(ERROR, "operand of postfix operator '%s' has an unknown type"
|
||||
"\n\t(probably an invalid column reference)",
|
||||
op);
|
||||
NameListToString(op));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_left_op)
|
||||
elog(ERROR, "Unable to identify a prefix operator '%s' for type '%s'"
|
||||
"\n\tYou may need to add parentheses or an explicit cast",
|
||||
op, format_type_be(arg));
|
||||
NameListToString(op), format_type_be(arg));
|
||||
else
|
||||
elog(ERROR, "Unable to identify a postfix operator '%s' for type '%s'"
|
||||
"\n\tYou may need to add parentheses or an explicit cast",
|
||||
op, format_type_be(arg));
|
||||
NameListToString(op), format_type_be(arg));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user