|
|
|
|
@ -11,35 +11,20 @@ |
|
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
|
#include "postgres.h" |
|
|
|
|
#include "nodes/pg_list.h" |
|
|
|
|
#include "nodes/parsenodes.h" |
|
|
|
|
#include "utils/elog.h" |
|
|
|
|
|
|
|
|
|
#include "nodes/nodes.h" |
|
|
|
|
#include "nodes/execnodes.h" |
|
|
|
|
#include "nodes/plannodes.h" |
|
|
|
|
#include "nodes/primnodes.h" |
|
|
|
|
#include "nodes/relation.h" |
|
|
|
|
|
|
|
|
|
#include "catalog/pg_type.h" |
|
|
|
|
#include "lib/stringinfo.h" |
|
|
|
|
#include "optimizer/planmain.h" |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Node_Copy-- |
|
|
|
|
* a macro to simplify calling of copyObject on the specified field |
|
|
|
|
*/ |
|
|
|
|
#define Node_Copy(from, newnode, field) newnode->field = copyObject(from->field) |
|
|
|
|
|
|
|
|
|
/***** DEBUG stuff
|
|
|
|
|
#define TABS {int i; printf("\n"); for (i = 0; i<level; i++) printf("\t"); } |
|
|
|
|
static int level = 0; |
|
|
|
|
******/ |
|
|
|
|
|
|
|
|
|
bool _use_keyset_query_optimizer = FALSE; |
|
|
|
|
|
|
|
|
|
static int inspectOpNode(Expr *expr); |
|
|
|
|
static int inspectAndNode(Expr *expr); |
|
|
|
|
static int inspectOrNode(Expr *expr); |
|
|
|
|
static int TotalExpr; |
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* This routine transforms query trees with the following form: |
|
|
|
|
@ -73,8 +58,7 @@ static int inspectOrNode(Expr *expr); |
|
|
|
|
* |
|
|
|
|
* daveh@insightdist.com 1998-08-31 |
|
|
|
|
* |
|
|
|
|
* Needs to better identify the signeture WHERE clause. |
|
|
|
|
* May want to also prune out duplicate where clauses. |
|
|
|
|
* May want to also prune out duplicate terms. |
|
|
|
|
**********************************************************************/ |
|
|
|
|
void |
|
|
|
|
transformKeySetQuery(Query *origNode) |
|
|
|
|
@ -92,18 +76,20 @@ transformKeySetQuery(Query *origNode) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
/* Qualify single table query */ |
|
|
|
|
|
|
|
|
|
if (length(origNode->rtable) != 1) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
/* Sorry about the global, not worth passing around */ |
|
|
|
|
/* 9 expressions seems like a good number. More than 9 */ |
|
|
|
|
/* and it starts to slow down quite a bit */ |
|
|
|
|
TotalExpr = 0;
|
|
|
|
|
/*************************/ |
|
|
|
|
/* Qualify where clause */ |
|
|
|
|
if ( ! inspectOrNode((Expr*)origNode->qual)) { |
|
|
|
|
/*************************/ |
|
|
|
|
if ( ! inspectOrNode((Expr*)origNode->qual) || TotalExpr < 9) |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Copy essential elements into a union node */ |
|
|
|
|
/*
|
|
|
|
|
elog(NOTICE, "OR_EXPR=%d, OP_EXPR=%d, AND_EXPR=%d", OR_EXPR, OP_EXPR, AND_EXPR); |
|
|
|
|
elog(NOTICE, "T_List=%d, T_Expr=%d, T_Var=%d, T_Const=%d", T_List, T_Expr, T_Var, T_Const); |
|
|
|
|
elog(NOTICE, "opType=%d", ((Expr*)origNode->qual)->opType); |
|
|
|
|
*/ |
|
|
|
|
while (((Expr*)origNode->qual)->opType == OR_EXPR) { |
|
|
|
|
Query *unionNode = makeNode(Query); |
|
|
|
|
|
|
|
|
|
@ -113,11 +99,6 @@ transformKeySetQuery(Query *origNode) |
|
|
|
|
/* Pull up balance of tree */ |
|
|
|
|
origNode->qual = lfirst(((Expr*)origNode->qual)->args);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
elog(NOTICE, "origNode: opType=%d, nodeTag=%d", ((Expr*)origNode->qual)->opType, nodeTag(origNode->qual)); |
|
|
|
|
elog(NOTICE, "unionNode: opType=%d, nodeTag=%d", ((Expr*)unionNode->qual)->opType, nodeTag(unionNode->qual)); |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
unionNode->commandType = origNode->commandType; |
|
|
|
|
unionNode->resultRelation = origNode->resultRelation; |
|
|
|
|
unionNode->isPortal = origNode->isPortal; |
|
|
|
|
@ -139,9 +120,14 @@ transformKeySetQuery(Query *origNode) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
/**********************************************************************
|
|
|
|
|
* Checks for 1 or more OR terms w/ 1 or more AND terms. |
|
|
|
|
* AND terms must be equal in size. |
|
|
|
|
* Returns the number of each AND term. |
|
|
|
|
**********************************************************************/ |
|
|
|
|
inspectOrNode(Expr *expr) |
|
|
|
|
{ |
|
|
|
|
int fr = 0, sr = 0; |
|
|
|
|
int rc; |
|
|
|
|
Expr *firstExpr, *secondExpr; |
|
|
|
|
|
|
|
|
|
if ( ! (expr && nodeTag(expr) == T_Expr && expr->opType == OR_EXPR)) |
|
|
|
|
@ -152,27 +138,35 @@ inspectOrNode(Expr *expr) |
|
|
|
|
if (nodeTag(firstExpr) != T_Expr || nodeTag(secondExpr) != T_Expr)
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
if (firstExpr->opType == OR_EXPR) |
|
|
|
|
fr = inspectOrNode(firstExpr); |
|
|
|
|
else if (firstExpr->opType == OP_EXPR) /* Need to make sure it is last */ |
|
|
|
|
fr = inspectOpNode(firstExpr); |
|
|
|
|
else if (firstExpr->opType == AND_EXPR) /* Need to make sure it is last */ |
|
|
|
|
fr = inspectAndNode(firstExpr); |
|
|
|
|
|
|
|
|
|
if (firstExpr->opType == OR_EXPR && secondExpr->opType == AND_EXPR) |
|
|
|
|
{ |
|
|
|
|
if ((rc = inspectOrNode(firstExpr)) == 0)
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
if (secondExpr->opType == AND_EXPR) |
|
|
|
|
sr = inspectAndNode(secondExpr); |
|
|
|
|
else if (secondExpr->opType == OP_EXPR) |
|
|
|
|
sr = inspectOpNode(secondExpr); |
|
|
|
|
return (rc == inspectAndNode(secondExpr)) ? rc : 0;
|
|
|
|
|
} |
|
|
|
|
else if (firstExpr->opType == AND_EXPR && secondExpr->opType == AND_EXPR) |
|
|
|
|
{ |
|
|
|
|
if ((rc = inspectAndNode(firstExpr)) == 0)
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
return (rc == inspectAndNode(secondExpr)) ? rc : 0;
|
|
|
|
|
|
|
|
|
|
return (fr && sr);
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
/**********************************************************************
|
|
|
|
|
* Check for one or more AND terms. Each sub-term must be a T_Const |
|
|
|
|
* T_Var expression.
|
|
|
|
|
* Returns the number of AND terms. |
|
|
|
|
**********************************************************************/ |
|
|
|
|
inspectAndNode(Expr *expr) |
|
|
|
|
{ |
|
|
|
|
int fr = 0, sr = 0; |
|
|
|
|
int rc; |
|
|
|
|
Expr *firstExpr, *secondExpr; |
|
|
|
|
|
|
|
|
|
if ( ! (expr && nodeTag(expr) == T_Expr && expr->opType == AND_EXPR)) |
|
|
|
|
@ -183,15 +177,19 @@ inspectAndNode(Expr *expr) |
|
|
|
|
if (nodeTag(firstExpr) != T_Expr || nodeTag(secondExpr) != T_Expr)
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
if (firstExpr->opType == AND_EXPR) |
|
|
|
|
fr = inspectAndNode(firstExpr); |
|
|
|
|
else if (firstExpr->opType == OP_EXPR) |
|
|
|
|
fr = inspectOpNode(firstExpr); |
|
|
|
|
if (firstExpr->opType == AND_EXPR && |
|
|
|
|
secondExpr->opType == OP_EXPR && inspectOpNode(secondExpr)) |
|
|
|
|
{ |
|
|
|
|
rc = inspectAndNode(firstExpr); |
|
|
|
|
return ((rc) ? (rc + 1) : 0); /* Add up the AND nodes */ |
|
|
|
|
} |
|
|
|
|
else if (firstExpr->opType == OP_EXPR && inspectOpNode(firstExpr) &&
|
|
|
|
|
secondExpr->opType == OP_EXPR && inspectOpNode(secondExpr)) |
|
|
|
|
{ |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (secondExpr->opType == OP_EXPR) |
|
|
|
|
sr = inspectOpNode(secondExpr); |
|
|
|
|
|
|
|
|
|
return (fr && sr);
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -205,7 +203,9 @@ inspectOpNode(Expr *expr) |
|
|
|
|
Expr *firstExpr, *secondExpr; |
|
|
|
|
|
|
|
|
|
if (nodeTag(expr) != T_Expr || expr->opType != OP_EXPR) |
|
|
|
|
return 0; |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
TotalExpr++; |
|
|
|
|
|
|
|
|
|
firstExpr = lfirst(expr->args); |
|
|
|
|
secondExpr = lsecond(expr->args); |
|
|
|
|
|