diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/analyze.c | 12 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 259 | ||||
-rw-r--r-- | src/backend/parser/parse_clause.c | 25 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 28 | ||||
-rw-r--r-- | src/backend/parser/parse_node.c | 17 | ||||
-rw-r--r-- | src/backend/parser/parse_oper.c | 534 |
6 files changed, 430 insertions, 445 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index f71f40829c6..6a68adfff37 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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); } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3488fb0762f..26b1be11d82 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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; @@ -6244,17 +6268,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 diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 4177e7887e1..452f66284d8 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -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)) diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 916c1da4a68..a3525487485 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -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); diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 0868f3f0bb8..8a3dc4d5573 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -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 */ diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 028bfab4319..52ae39cccd5 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -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]; - - *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 == '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++; - } - } - - systable_endscan(pg_operator_scan); - heap_close(pg_operator_desc, AccessShareLock); - - return ncandidates; -} /* binary_oper_get_candidates() */ + /* 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; -/* 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))) + while (candidates != NULL) { - 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++; - } + 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; -} /* 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)); } } |