|
27 | 27 | #include "miscadmin.h" |
28 | 28 | #include "catalog/pg_type_d.h" |
29 | 29 | #include "nodes/nodeFuncs.h" |
| 30 | +#include "optimizer/var.h" |
30 | 31 | #include "parser/parse_coerce.h" |
31 | 32 | #include "parser/parse_collate.h" |
32 | 33 | #include "parser/parse_func.h" |
@@ -483,26 +484,153 @@ static Node *transform_cypher_comparison_aexpr_OP(cypher_parsestate *cpstate, |
483 | 484 | return (Node *)transform_AEXPR_OP(cpstate, n); |
484 | 485 | } |
485 | 486 |
|
| 487 | +/* copied over from PostgreSQL version 13 function of the same name */ |
| 488 | +static bool verify_common_type(Oid common_type, List *exprs) |
| 489 | +{ |
| 490 | + ListCell *lc; |
| 491 | + |
| 492 | + foreach(lc, exprs) |
| 493 | + { |
| 494 | + Node *nexpr = (Node *) lfirst(lc); |
| 495 | + Oid ntype = exprType(nexpr); |
| 496 | + |
| 497 | + if (!can_coerce_type(1, &ntype, &common_type, COERCION_IMPLICIT)) |
| 498 | + { |
| 499 | + return false; |
| 500 | + } |
| 501 | + } |
| 502 | + return true; |
| 503 | +} |
486 | 504 |
|
487 | 505 | static Node *transform_AEXPR_IN(cypher_parsestate *cpstate, A_Expr *a) |
488 | 506 | { |
489 | | - Oid func_in_oid; |
490 | | - FuncExpr *result; |
491 | | - List *args = NIL; |
| 507 | + ParseState *pstate = (ParseState *)cpstate; |
| 508 | + cypher_list *rexpr; |
| 509 | + Node *result = NULL; |
| 510 | + Node *lexpr; |
| 511 | + List *rexprs; |
| 512 | + List *rvars; |
| 513 | + List *rnonvars; |
| 514 | + bool useOr; |
| 515 | + ListCell *l; |
| 516 | + |
| 517 | + /* Check for null arguments in the list to return NULL*/ |
| 518 | + if (!is_ag_node(a->rexpr, cypher_list)) |
| 519 | + { |
| 520 | + if (nodeTag(a->rexpr) == T_A_Const) |
| 521 | + { |
| 522 | + A_Const *r_a_const = (A_Const*)a->rexpr; |
| 523 | + if (r_a_const->val.type == T_Null) |
| 524 | + { |
| 525 | + return (Node *)makeConst(AGTYPEOID, -1, InvalidOid, -1, |
| 526 | + (Datum)NULL, true, false); |
| 527 | + } |
| 528 | + } |
492 | 529 |
|
493 | | - args = lappend(args, transform_cypher_expr_recurse(cpstate, a->rexpr)); |
494 | | - args = lappend(args, transform_cypher_expr_recurse(cpstate, a->lexpr)); |
| 530 | + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 531 | + errmsg("object of IN must be a list"))); |
| 532 | + } |
495 | 533 |
|
496 | | - /* get the agtype_access_slice function */ |
497 | | - func_in_oid = get_ag_func_oid("agtype_in_operator", 2, AGTYPEOID, |
498 | | - AGTYPEOID); |
| 534 | + Assert(is_ag_node(a->rexpr, cypher_list)); |
| 535 | + |
| 536 | + // If the operator is <>, combine with AND not OR. |
| 537 | + if (strcmp(strVal(linitial(a->name)), "<>") == 0) |
| 538 | + { |
| 539 | + useOr = false; |
| 540 | + } |
| 541 | + else |
| 542 | + { |
| 543 | + useOr = true; |
| 544 | + } |
| 545 | + |
| 546 | + lexpr = transform_cypher_expr_recurse(cpstate, a->lexpr); |
| 547 | + |
| 548 | + rexprs = rvars = rnonvars = NIL; |
| 549 | + |
| 550 | + rexpr = (cypher_list *)a->rexpr; |
| 551 | + |
| 552 | + foreach(l, (List *) rexpr->elems) |
| 553 | + { |
| 554 | + Node *rexpr = transform_cypher_expr_recurse(cpstate, lfirst(l)); |
| 555 | + |
| 556 | + rexprs = lappend(rexprs, rexpr); |
| 557 | + if (contain_vars_of_level(rexpr, 0)) |
| 558 | + { |
| 559 | + rvars = lappend(rvars, rexpr); |
| 560 | + } |
| 561 | + else |
| 562 | + { |
| 563 | + rnonvars = lappend(rnonvars, rexpr); |
| 564 | + } |
| 565 | + } |
499 | 566 |
|
500 | | - result = makeFuncExpr(func_in_oid, AGTYPEOID, args, InvalidOid, InvalidOid, |
501 | | - COERCE_EXPLICIT_CALL); |
| 567 | + /* |
| 568 | + * ScalarArrayOpExpr is only going to be useful if there's more than one |
| 569 | + * non-Var righthand item. |
| 570 | + */ |
| 571 | + if (list_length(rnonvars) > 1) |
| 572 | + { |
| 573 | + List *allexprs; |
| 574 | + Oid scalar_type; |
| 575 | + List *aexprs; |
| 576 | + ArrayExpr *newa; |
| 577 | + |
| 578 | + allexprs = list_concat(list_make1(lexpr), rnonvars); |
502 | 579 |
|
503 | | - result->location = exprLocation(a->lexpr); |
| 580 | + scalar_type = AGTYPEOID; |
| 581 | + |
| 582 | + Assert(verify_common_type(scalar_type, allexprs)); |
| 583 | + /* |
| 584 | + * coerce all the right-hand non-Var inputs to the common type |
| 585 | + * and build an ArrayExpr for them. |
| 586 | + */ |
| 587 | + |
| 588 | + aexprs = NIL; |
| 589 | + foreach(l, rnonvars) |
| 590 | + { |
| 591 | + Node *rexpr = (Node *) lfirst(l); |
504 | 592 |
|
505 | | - return (Node *)result; |
| 593 | + rexpr = coerce_to_common_type(pstate, rexpr, AGTYPEOID, "IN"); |
| 594 | + aexprs = lappend(aexprs, rexpr); |
| 595 | + } |
| 596 | + newa = makeNode(ArrayExpr); |
| 597 | + newa->array_typeid = get_array_type(AGTYPEOID); |
| 598 | + /* array_collid will be set by parse_collate.c */ |
| 599 | + newa->element_typeid = AGTYPEOID; |
| 600 | + newa->elements = aexprs; |
| 601 | + newa->multidims = false; |
| 602 | + result = (Node *) make_scalar_array_op(pstate, a->name, useOr, |
| 603 | + lexpr, (Node *) newa, |
| 604 | + a->location); |
| 605 | + |
| 606 | + /* Consider only the Vars (if any) in the loop below */ |
| 607 | + rexprs = rvars; |
| 608 | + } |
| 609 | + |
| 610 | + // Must do it the hard way, with a boolean expression tree. |
| 611 | + foreach(l, rexprs) |
| 612 | + { |
| 613 | + Node *rexpr = (Node *) lfirst(l); |
| 614 | + Node *cmp; |
| 615 | + |
| 616 | + // Ordinary scalar operator |
| 617 | + cmp = (Node *) make_op(pstate, a->name, copyObject(lexpr), rexpr, |
| 618 | + pstate->p_last_srf, a->location); |
| 619 | + |
| 620 | + cmp = coerce_to_boolean(pstate, cmp, "IN"); |
| 621 | + if (result == NULL) |
| 622 | + { |
| 623 | + result = cmp; |
| 624 | + } |
| 625 | + else |
| 626 | + { |
| 627 | + result = (Node *) makeBoolExpr(useOr ? OR_EXPR : AND_EXPR, |
| 628 | + list_make2(result, cmp), |
| 629 | + a->location); |
| 630 | + } |
| 631 | + } |
| 632 | + |
| 633 | + return result; |
506 | 634 | } |
507 | 635 |
|
508 | 636 | static Node *transform_BoolExpr(cypher_parsestate *cpstate, BoolExpr *expr) |
|
0 commit comments