Skip to content

Commit aca6514

Browse files
authored
Support boolean operation push-down (#78)
1 parent a39224d commit aca6514

File tree

3 files changed

+233
-20
lines changed

3 files changed

+233
-20
lines changed

src/query.c

Lines changed: 162 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,39 @@
1616

1717
void extractClauseFromOpExpr(
1818
#if PG_VERSION_NUM >= 140000
19-
PlannerInfo *root,
19+
PlannerInfo *root,
2020
#endif
21-
Relids base_relids,
22-
OpExpr *node,
23-
List **quals);
21+
Relids base_relids,
22+
OpExpr *node,
23+
List **quals);
2424

2525
void extractClauseFromNullTest(Relids base_relids,
2626
NullTest *node,
2727
List **quals);
2828

2929
void extractClauseFromScalarArrayOpExpr(
3030
#if PG_VERSION_NUM >= 140000
31-
PlannerInfo *root,
31+
PlannerInfo *root,
3232
#endif
33-
Relids base_relids,
34-
ScalarArrayOpExpr *node,
35-
List **quals);
33+
Relids base_relids,
34+
ScalarArrayOpExpr *node,
35+
List **quals);
3636

37-
char *getOperatorString(Oid opoid);
37+
void extractClauseFromBooleanTest(Relids base_relids, BooleanTest *node, List **quals);
38+
39+
void extractClauseFromBoolExpr(
40+
#if PG_VERSION_NUM >= 140000
41+
PlannerInfo *root,
42+
#endif
43+
Relids base_relids, BoolExpr *node, List **quals);
44+
45+
void extractClauseFromVar(
46+
#if PG_VERSION_NUM >= 140000
47+
PlannerInfo *root,
48+
#endif
49+
Relids base_relids, Var *node, List **quals);
50+
51+
char *getOperatorString(Oid opoid);
3852

3953
MulticornBaseQual *makeQual(AttrNumber varattno, char *opname, Expr *value,
4054
bool isarray,
@@ -319,6 +333,26 @@ extractRestrictions(
319333
#endif
320334
base_relids, (ScalarArrayOpExpr *) node, quals);
321335
break;
336+
337+
case T_BooleanTest:
338+
extractClauseFromBooleanTest(base_relids, (BooleanTest *) node, quals);
339+
break;
340+
341+
case T_Var:
342+
extractClauseFromVar(
343+
#if PG_VERSION_NUM >= 140000
344+
(PlannerInfo *) root,
345+
#endif
346+
base_relids, (Var *) node, quals);
347+
break;
348+
349+
case T_BoolExpr:
350+
extractClauseFromBoolExpr(
351+
#if PG_VERSION_NUM >= 140000
352+
root,
353+
#endif
354+
base_relids, (BoolExpr *) node, quals);
355+
break;
322356
default:
323357
{
324358
ereport(WARNING,
@@ -343,9 +377,9 @@ extractRestrictions(
343377
void
344378
extractClauseFromOpExpr(
345379
#if PG_VERSION_NUM >= 140000
346-
PlannerInfo *root,
380+
PlannerInfo *root,
347381
#endif
348-
Relids base_relids, OpExpr *op, List **quals)
382+
Relids base_relids, OpExpr *op, List **quals)
349383
{
350384
Var *left;
351385
Expr *right;
@@ -378,11 +412,11 @@ extractClauseFromOpExpr(
378412
void
379413
extractClauseFromScalarArrayOpExpr(
380414
#if PG_VERSION_NUM >= 140000
381-
PlannerInfo *root,
415+
PlannerInfo *root,
382416
#endif
383-
Relids base_relids,
384-
ScalarArrayOpExpr *op,
385-
List **quals)
417+
Relids base_relids,
418+
ScalarArrayOpExpr *op,
419+
List **quals)
386420
{
387421
Var *left;
388422
Expr *right;
@@ -396,9 +430,9 @@ extractClauseFromScalarArrayOpExpr(
396430
if (!(contain_volatile_functions((Node *) right) ||
397431
bms_is_subset(base_relids, pull_varnos(
398432
#if PG_VERSION_NUM >= 140000
399-
root,
433+
root,
400434
#endif
401-
(Node *) right))))
435+
(Node *) right))))
402436

403437
{
404438
*quals = lappend(*quals, makeQual(left->varattno,
@@ -446,7 +480,115 @@ extractClauseFromNullTest(Relids base_relids,
446480
}
447481
}
448482

483+
/*
484+
* Convert a "BooleanTest" (IS TRUE, IS FALSE, IS NOT TRUE, IS NOT FALSE)
485+
* to the corresponding qualifier.
486+
*/
487+
void extractClauseFromBooleanTest(Relids base_relids, BooleanTest *node, List **quals)
488+
{
489+
elog(DEBUG3, "entering extractClauseFromBooleanTest()");
490+
if (IsA(node->arg, Var))
491+
{
492+
Var *var = (Var *) node->arg;
493+
MulticornBaseQual *result;
494+
char *opname = NULL;
495+
Expr *val;
496+
497+
if (var->varattno < 1)
498+
{
499+
return;
500+
}
501+
switch (node->booltesttype)
502+
{
503+
case IS_TRUE:
504+
opname = "IS";
505+
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
506+
break;
507+
case IS_FALSE:
508+
opname = "IS";
509+
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(false), false, true);
510+
break;
511+
case IS_NOT_TRUE:
512+
opname = "IS NOT";
513+
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
514+
break;
515+
case IS_NOT_FALSE:
516+
opname = "IS NOT";
517+
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
518+
break;
519+
case IS_UNKNOWN:
520+
opname = "IS";
521+
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), (Datum)0, true, true);
522+
break;
523+
case IS_NOT_UNKNOWN:
524+
opname = "IS NOT";
525+
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), (Datum)0, true, true);
526+
break;
527+
default:
528+
elog(ERROR, "unsupported boolean test type %d", node->booltesttype);
529+
}
530+
result = makeQual(var->varattno, opname,
531+
(Expr *) val, false, false);
532+
*quals = lappend(*quals, result);
533+
}
534+
}
535+
536+
void extractClauseFromVar(
537+
#if PG_VERSION_NUM >= 140000
538+
PlannerInfo *root,
539+
#endif
540+
Relids base_relids, Var *var, List **quals)
541+
{
542+
MulticornBaseQual *result;
543+
Expr *true_expr;
544+
if (!bms_is_subset(pull_varnos(
545+
#if PG_VERSION_NUM >= 140000
546+
root,
547+
#endif
548+
(Node *) var), base_relids)) {
549+
return;
550+
}
551+
552+
true_expr = (Expr *) makeConst(BOOLOID, // Type OID for boolean
553+
-1, // typmod
554+
InvalidOid, // collation
555+
sizeof(bool), // constlen
556+
BoolGetDatum(true), // the actual value
557+
false, // isnull
558+
true); // constbyval
559+
560+
result = makeQual(var->varattno, "=", true_expr, false, false);
561+
*quals = lappend(*quals, result);
562+
}
563+
564+
void extractClauseFromBoolExpr(
565+
#if PG_VERSION_NUM >= 140000
566+
PlannerInfo *root,
567+
#endif
568+
Relids base_relids, BoolExpr *bexpr, List **quals)
569+
{
570+
if (!bms_is_subset(pull_varnos(
571+
#if PG_VERSION_NUM >= 140000
572+
root,
573+
#endif
574+
(Node *) bexpr), base_relids)) {
575+
return;
576+
}
449577

578+
if (bexpr->boolop == NOT_EXPR &&
579+
list_length(bexpr->args) == 1 &&
580+
IsA(linitial(bexpr->args), Var)) {
581+
582+
Var *var = (Var *) linitial(bexpr->args);
583+
Expr *true_expr = (Expr *) makeConst(
584+
BOOLOID, -1, InvalidOid, sizeof(bool),
585+
BoolGetDatum(true), false, true);
586+
587+
MulticornBaseQual *result = makeQual(
588+
var->varattno, "<>", true_expr, false, false);
589+
590+
*quals = lappend(*quals, result);
591+
}}
450592

451593
/*
452594
* Returns a "Value" node containing the string name of the column from a var.
@@ -484,21 +626,21 @@ makeQual(AttrNumber varattno, char *opname, Expr *value, bool isarray,
484626
switch (value->type)
485627
{
486628
case T_Const:
487-
elog(DEBUG3, "T_Const");
629+
elog(DEBUG3, "T_Const");
488630
qual = palloc0(sizeof(MulticornConstQual));
489631
qual->right_type = T_Const;
490632
qual->typeoid = ((Const *) value)->consttype;
491633
((MulticornConstQual *) qual)->value = ((Const *) value)->constvalue;
492634
((MulticornConstQual *) qual)->isnull = ((Const *) value)->constisnull;
493635
break;
494636
case T_Var:
495-
elog(DEBUG3, "T_Var");
637+
elog(DEBUG3, "T_Var");
496638
qual = palloc0(sizeof(MulticornVarQual));
497639
qual->right_type = T_Var;
498640
((MulticornVarQual *) qual)->rightvarattno = ((Var *) value)->varattno;
499641
break;
500642
default:
501-
elog(DEBUG3, "default");
643+
elog(DEBUG3, "default");
502644
qual = palloc0(sizeof(MulticornParamQual));
503645
qual->right_type = T_Param;
504646
((MulticornParamQual *) qual)->expr = value;

test-3.9/expected/multicorn_regression_test.out

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,66 @@ NOTICE: ['test1', 'test2', 'test3']
473473
-------+-------+-------
474474
(0 rows)
475475

476+
-- Test boolean operation pushdown
477+
ALTER FOREIGN TABLE testmulticorn alter test1 type bool;
478+
select * from testmulticorn where test1;
479+
NOTICE: [('option1', 'option1'), ('test_type', 'iter_none'), ('usermapping', 'test')]
480+
NOTICE: [('test1', 'boolean'), ('test2', 'bytea'), ('test3', 'money')]
481+
NOTICE: [test1 = t]
482+
NOTICE: ['test1', 'test2', 'test3']
483+
test1 | test2 | test3
484+
-------+-------+-------
485+
(0 rows)
486+
487+
select * from testmulticorn where NOT test1;
488+
NOTICE: [test1 <> t]
489+
NOTICE: ['test1', 'test2', 'test3']
490+
test1 | test2 | test3
491+
-------+-------+-------
492+
(0 rows)
493+
494+
select * from testmulticorn where test1 = TRUE;
495+
NOTICE: [test1 = t]
496+
NOTICE: ['test1', 'test2', 'test3']
497+
test1 | test2 | test3
498+
-------+-------+-------
499+
(0 rows)
500+
501+
select * from testmulticorn where test1 = FALSE;
502+
NOTICE: [test1 <> t]
503+
NOTICE: ['test1', 'test2', 'test3']
504+
test1 | test2 | test3
505+
-------+-------+-------
506+
(0 rows)
507+
508+
select * from testmulticorn where test1 IS TRUE;
509+
NOTICE: [test1 IS t]
510+
NOTICE: ['test1', 'test2', 'test3']
511+
test1 | test2 | test3
512+
-------+-------+-------
513+
(0 rows)
514+
515+
select * from testmulticorn where test1 IS FALSE;
516+
NOTICE: [test1 IS f]
517+
NOTICE: ['test1', 'test2', 'test3']
518+
test1 | test2 | test3
519+
-------+-------+-------
520+
(0 rows)
521+
522+
select * from testmulticorn where test1 IS UNKNOWN;
523+
NOTICE: [test1 IS None]
524+
NOTICE: ['test1', 'test2', 'test3']
525+
test1 | test2 | test3
526+
-------+-------+-------
527+
(0 rows)
528+
529+
select * from testmulticorn where test1 IS NOT UNKNOWN;
530+
NOTICE: [test1 IS NOT None]
531+
NOTICE: ['test1', 'test2', 'test3']
532+
test1 | test2 | test3
533+
-------+-------+-------
534+
(0 rows)
535+
476536
DROP USER MAPPING FOR current_user SERVER multicorn_srv;
477537
DROP EXTENSION multicorn cascade;
478538
NOTICE: drop cascades to 3 other objects

test-3.9/sql/multicorn_regression_test.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,16 @@ ALTER FOREIGN TABLE testmulticorn add test3 money;
107107
SELECT * from testmulticorn where test3 = 12::money;
108108
SELECT * from testmulticorn where test1 = '12 €';
109109

110+
-- Test boolean operation pushdown
111+
ALTER FOREIGN TABLE testmulticorn alter test1 type bool;
112+
select * from testmulticorn where test1;
113+
select * from testmulticorn where NOT test1;
114+
select * from testmulticorn where test1 = TRUE;
115+
select * from testmulticorn where test1 = FALSE;
116+
select * from testmulticorn where test1 IS TRUE;
117+
select * from testmulticorn where test1 IS FALSE;
118+
select * from testmulticorn where test1 IS UNKNOWN;
119+
select * from testmulticorn where test1 IS NOT UNKNOWN;
120+
110121
DROP USER MAPPING FOR current_user SERVER multicorn_srv;
111122
DROP EXTENSION multicorn cascade;

0 commit comments

Comments
 (0)