Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 162 additions & 20 deletions src/query.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,39 @@

void extractClauseFromOpExpr(
#if PG_VERSION_NUM >= 140000
PlannerInfo *root,
PlannerInfo *root,
#endif
Relids base_relids,
OpExpr *node,
List **quals);
Relids base_relids,
OpExpr *node,
List **quals);

void extractClauseFromNullTest(Relids base_relids,
NullTest *node,
List **quals);

void extractClauseFromScalarArrayOpExpr(
#if PG_VERSION_NUM >= 140000
PlannerInfo *root,
PlannerInfo *root,
#endif
Relids base_relids,
ScalarArrayOpExpr *node,
List **quals);
Relids base_relids,
ScalarArrayOpExpr *node,
List **quals);

char *getOperatorString(Oid opoid);
void extractClauseFromBooleanTest(Relids base_relids, BooleanTest *node, List **quals);

void extractClauseFromBoolExpr(
#if PG_VERSION_NUM >= 140000
PlannerInfo *root,
#endif
Relids base_relids, BoolExpr *node, List **quals);

void extractClauseFromVar(
#if PG_VERSION_NUM >= 140000
PlannerInfo *root,
#endif
Relids base_relids, Var *node, List **quals);

char *getOperatorString(Oid opoid);

MulticornBaseQual *makeQual(AttrNumber varattno, char *opname, Expr *value,
bool isarray,
Expand Down Expand Up @@ -319,6 +333,26 @@ extractRestrictions(
#endif
base_relids, (ScalarArrayOpExpr *) node, quals);
break;

case T_BooleanTest:
extractClauseFromBooleanTest(base_relids, (BooleanTest *) node, quals);
break;

case T_Var:
extractClauseFromVar(
#if PG_VERSION_NUM >= 140000
(PlannerInfo *) root,
#endif
base_relids, (Var *) node, quals);
break;

case T_BoolExpr:
extractClauseFromBoolExpr(
#if PG_VERSION_NUM >= 140000
root,
#endif
base_relids, (BoolExpr *) node, quals);
break;
default:
{
ereport(WARNING,
Expand All @@ -343,9 +377,9 @@ extractRestrictions(
void
extractClauseFromOpExpr(
#if PG_VERSION_NUM >= 140000
PlannerInfo *root,
PlannerInfo *root,
#endif
Relids base_relids, OpExpr *op, List **quals)
Relids base_relids, OpExpr *op, List **quals)
{
Var *left;
Expr *right;
Expand Down Expand Up @@ -378,11 +412,11 @@ extractClauseFromOpExpr(
void
extractClauseFromScalarArrayOpExpr(
#if PG_VERSION_NUM >= 140000
PlannerInfo *root,
PlannerInfo *root,
#endif
Relids base_relids,
ScalarArrayOpExpr *op,
List **quals)
Relids base_relids,
ScalarArrayOpExpr *op,
List **quals)
{
Var *left;
Expr *right;
Expand All @@ -396,9 +430,9 @@ extractClauseFromScalarArrayOpExpr(
if (!(contain_volatile_functions((Node *) right) ||
bms_is_subset(base_relids, pull_varnos(
#if PG_VERSION_NUM >= 140000
root,
root,
#endif
(Node *) right))))
(Node *) right))))

{
*quals = lappend(*quals, makeQual(left->varattno,
Expand Down Expand Up @@ -446,7 +480,115 @@ extractClauseFromNullTest(Relids base_relids,
}
}

/*
* Convert a "BooleanTest" (IS TRUE, IS FALSE, IS NOT TRUE, IS NOT FALSE)
* to the corresponding qualifier.
*/
void extractClauseFromBooleanTest(Relids base_relids, BooleanTest *node, List **quals)
{
elog(DEBUG3, "entering extractClauseFromBooleanTest()");
if (IsA(node->arg, Var))
{
Var *var = (Var *) node->arg;
MulticornBaseQual *result;
char *opname = NULL;
Expr *val;

if (var->varattno < 1)
{
return;
}
switch (node->booltesttype)
{
case IS_TRUE:
opname = "IS";
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
break;
case IS_FALSE:
opname = "IS";
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(false), false, true);
break;
case IS_NOT_TRUE:
opname = "IS NOT";
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
break;
case IS_NOT_FALSE:
opname = "IS NOT";
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
break;
case IS_UNKNOWN:
opname = "IS";
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), (Datum)0, true, true);
break;
case IS_NOT_UNKNOWN:
opname = "IS NOT";
val = (Expr *) makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), (Datum)0, true, true);
break;
default:
elog(ERROR, "unsupported boolean test type %d", node->booltesttype);
}
result = makeQual(var->varattno, opname,
(Expr *) val, false, false);
*quals = lappend(*quals, result);
}
}

void extractClauseFromVar(
#if PG_VERSION_NUM >= 140000
PlannerInfo *root,
#endif
Relids base_relids, Var *var, List **quals)
{
MulticornBaseQual *result;
Expr *true_expr;
if (!bms_is_subset(pull_varnos(
#if PG_VERSION_NUM >= 140000
root,
#endif
(Node *) var), base_relids)) {
return;
}

true_expr = (Expr *) makeConst(BOOLOID, // Type OID for boolean
-1, // typmod
InvalidOid, // collation
sizeof(bool), // constlen
BoolGetDatum(true), // the actual value
false, // isnull
true); // constbyval

result = makeQual(var->varattno, "=", true_expr, false, false);
*quals = lappend(*quals, result);
}

void extractClauseFromBoolExpr(
#if PG_VERSION_NUM >= 140000
PlannerInfo *root,
#endif
Relids base_relids, BoolExpr *bexpr, List **quals)
{
if (!bms_is_subset(pull_varnos(
#if PG_VERSION_NUM >= 140000
root,
#endif
(Node *) bexpr), base_relids)) {
return;
}

if (bexpr->boolop == NOT_EXPR &&
list_length(bexpr->args) == 1 &&
IsA(linitial(bexpr->args), Var)) {

Var *var = (Var *) linitial(bexpr->args);
Expr *true_expr = (Expr *) makeConst(
BOOLOID, -1, InvalidOid, sizeof(bool),
BoolGetDatum(true), false, true);

MulticornBaseQual *result = makeQual(
var->varattno, "<>", true_expr, false, false);

*quals = lappend(*quals, result);
}}

/*
* Returns a "Value" node containing the string name of the column from a var.
Expand Down Expand Up @@ -484,21 +626,21 @@ makeQual(AttrNumber varattno, char *opname, Expr *value, bool isarray,
switch (value->type)
{
case T_Const:
elog(DEBUG3, "T_Const");
elog(DEBUG3, "T_Const");
qual = palloc0(sizeof(MulticornConstQual));
qual->right_type = T_Const;
qual->typeoid = ((Const *) value)->consttype;
((MulticornConstQual *) qual)->value = ((Const *) value)->constvalue;
((MulticornConstQual *) qual)->isnull = ((Const *) value)->constisnull;
break;
case T_Var:
elog(DEBUG3, "T_Var");
elog(DEBUG3, "T_Var");
qual = palloc0(sizeof(MulticornVarQual));
qual->right_type = T_Var;
((MulticornVarQual *) qual)->rightvarattno = ((Var *) value)->varattno;
break;
default:
elog(DEBUG3, "default");
elog(DEBUG3, "default");
qual = palloc0(sizeof(MulticornParamQual));
qual->right_type = T_Param;
((MulticornParamQual *) qual)->expr = value;
Expand Down
60 changes: 60 additions & 0 deletions test-3.9/expected/multicorn_regression_test.out
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,66 @@ NOTICE: ['test1', 'test2', 'test3']
-------+-------+-------
(0 rows)

-- Test boolean operation pushdown
ALTER FOREIGN TABLE testmulticorn alter test1 type bool;
select * from testmulticorn where test1;
NOTICE: [('option1', 'option1'), ('test_type', 'iter_none'), ('usermapping', 'test')]
NOTICE: [('test1', 'boolean'), ('test2', 'bytea'), ('test3', 'money')]
NOTICE: [test1 = t]
NOTICE: ['test1', 'test2', 'test3']
test1 | test2 | test3
-------+-------+-------
(0 rows)

select * from testmulticorn where NOT test1;
NOTICE: [test1 <> t]
NOTICE: ['test1', 'test2', 'test3']
test1 | test2 | test3
-------+-------+-------
(0 rows)

select * from testmulticorn where test1 = TRUE;
NOTICE: [test1 = t]
NOTICE: ['test1', 'test2', 'test3']
test1 | test2 | test3
-------+-------+-------
(0 rows)

select * from testmulticorn where test1 = FALSE;
NOTICE: [test1 <> t]
NOTICE: ['test1', 'test2', 'test3']
test1 | test2 | test3
-------+-------+-------
(0 rows)

select * from testmulticorn where test1 IS TRUE;
NOTICE: [test1 IS t]
NOTICE: ['test1', 'test2', 'test3']
test1 | test2 | test3
-------+-------+-------
(0 rows)

select * from testmulticorn where test1 IS FALSE;
NOTICE: [test1 IS f]
NOTICE: ['test1', 'test2', 'test3']
test1 | test2 | test3
-------+-------+-------
(0 rows)

select * from testmulticorn where test1 IS UNKNOWN;
NOTICE: [test1 IS None]
NOTICE: ['test1', 'test2', 'test3']
test1 | test2 | test3
-------+-------+-------
(0 rows)

select * from testmulticorn where test1 IS NOT UNKNOWN;
NOTICE: [test1 IS NOT None]
NOTICE: ['test1', 'test2', 'test3']
test1 | test2 | test3
-------+-------+-------
(0 rows)

DROP USER MAPPING FOR current_user SERVER multicorn_srv;
DROP EXTENSION multicorn cascade;
NOTICE: drop cascades to 3 other objects
Expand Down
11 changes: 11 additions & 0 deletions test-3.9/sql/multicorn_regression_test.sql
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,16 @@ ALTER FOREIGN TABLE testmulticorn add test3 money;
SELECT * from testmulticorn where test3 = 12::money;
SELECT * from testmulticorn where test1 = '12 €';

-- Test boolean operation pushdown
ALTER FOREIGN TABLE testmulticorn alter test1 type bool;
select * from testmulticorn where test1;
select * from testmulticorn where NOT test1;
select * from testmulticorn where test1 = TRUE;
select * from testmulticorn where test1 = FALSE;
select * from testmulticorn where test1 IS TRUE;
select * from testmulticorn where test1 IS FALSE;
select * from testmulticorn where test1 IS UNKNOWN;
select * from testmulticorn where test1 IS NOT UNKNOWN;

DROP USER MAPPING FOR current_user SERVER multicorn_srv;
DROP EXTENSION multicorn cascade;