diff options
author | Bruce Momjian <bruce@momjian.us> | 2002-06-16 00:09:12 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 2002-06-16 00:09:12 +0000 |
commit | 0dbfea39f313fbd24a1754a701a85815229fe262 (patch) | |
tree | 8cd4ee381d1e1f4d39b32dfd396a29957903da90 /src/backend/optimizer/prep/_deadcode/prepkeyset.c | |
parent | b50cbbd66b8835682982d553b348d017a850f76a (diff) |
Remove KSQO from GUC and move file to _deadcode.
Diffstat (limited to 'src/backend/optimizer/prep/_deadcode/prepkeyset.c')
-rw-r--r-- | src/backend/optimizer/prep/_deadcode/prepkeyset.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/backend/optimizer/prep/_deadcode/prepkeyset.c b/src/backend/optimizer/prep/_deadcode/prepkeyset.c new file mode 100644 index 00000000000..b7f7ca169e8 --- /dev/null +++ b/src/backend/optimizer/prep/_deadcode/prepkeyset.c @@ -0,0 +1,222 @@ +/*------------------------------------------------------------------------- + * + * prepkeyset.c + * Special preperation for keyset queries. + * + * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + *------------------------------------------------------------------------- + */ + +/* THIS FILE WAS USED FOR KSQO, WHICH IS DISABLED NOW. bjm 2002-06-15 */ + +#include "postgres.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) + +bool _use_keyset_query_optimizer = FALSE; + +#ifdef ENABLE_KEY_SET_QUERY + +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: + * SELECT a,b, ... FROM one_table WHERE + * (v1 = const1 AND v2 = const2 [ vn = constn ]) OR + * (v1 = const3 AND v2 = const4 [ vn = constn ]) OR + * (v1 = const5 AND v2 = const6 [ vn = constn ]) OR + * ... + * [(v1 = constn AND v2 = constn [ vn = constn ])] + * + * into + * + * SELECT a,b, ... FROM one_table WHERE + * (v1 = const1 AND v2 = const2 [ vn = constn ]) UNION + * SELECT a,b, ... FROM one_table WHERE + * (v1 = const3 AND v2 = const4 [ vn = constn ]) UNION + * SELECT a,b, ... FROM one_table WHERE + * (v1 = const5 AND v2 = const6 [ vn = constn ]) UNION + * ... + * SELECT a,b, ... FROM one_table WHERE + * [(v1 = constn AND v2 = constn [ vn = constn ])] + * + * + * To qualify for transformation the query must not be a sub select, + * a HAVING, or a GROUP BY. It must be a single table and have KSQO + * set to 'on'. + * + * The primary use of this transformation is to avoid the exponrntial + * memory consumption of cnfify() and to make use of index access + * methods. + * + * daveh@insightdist.com 1998-08-31 + * + * May want to also prune out duplicate terms. + **********************************************************************/ +void +transformKeySetQuery(Query *origNode) +{ + /* Qualify as a key set query candidate */ + if (_use_keyset_query_optimizer == FALSE || + origNode->groupClause || + origNode->havingQual || + origNode->hasAggs || + origNode->utilityStmt || + origNode->unionClause || + origNode->unionall || + origNode->hasSubLinks || + origNode->commandType != CMD_SELECT) + 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->jointree->quals) || TotalExpr < 9) + return; + + /* Copy essential elements into a union node */ + while (((Expr *) origNode->jointree->quals)->opType == OR_EXPR) + { + Query *unionNode = makeNode(Query); + List *qualargs = ((Expr *) origNode->jointree->quals)->args; + + unionNode->commandType = origNode->commandType; + unionNode->resultRelation = origNode->resultRelation; + unionNode->isPortal = origNode->isPortal; + unionNode->isBinary = origNode->isBinary; + + Node_Copy(origNode, unionNode, distinctClause); + Node_Copy(origNode, unionNode, sortClause); + Node_Copy(origNode, unionNode, rtable); + origNode->jointree->quals = NULL; /* avoid unnecessary + * copying */ + Node_Copy(origNode, unionNode, jointree); + Node_Copy(origNode, unionNode, targetList); + + /* Pull up Expr = */ + unionNode->jointree->quals = lsecond(qualargs); + + /* Pull up balance of tree */ + origNode->jointree->quals = lfirst(qualargs); + + origNode->unionClause = lappend(origNode->unionClause, unionNode); + } + return; +} + + + + +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 rc; + Expr *firstExpr, + *secondExpr; + + if (!(expr && nodeTag(expr) == T_Expr && expr->opType == OR_EXPR)) + return 0; + + firstExpr = lfirst(expr->args); + secondExpr = lsecond(expr->args); + if (nodeTag(firstExpr) != T_Expr || nodeTag(secondExpr) != T_Expr) + return 0; + + if (firstExpr->opType == OR_EXPR && secondExpr->opType == AND_EXPR) + { + if ((rc = inspectOrNode(firstExpr)) == 0) + return 0; + + 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 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 rc; + Expr *firstExpr, + *secondExpr; + + if (!(expr && nodeTag(expr) == T_Expr && expr->opType == AND_EXPR)) + return 0; + + firstExpr = lfirst(expr->args); + secondExpr = lsecond(expr->args); + if (nodeTag(firstExpr) != T_Expr || nodeTag(secondExpr) != T_Expr) + return 0; + + 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; + + return 0; +} + + +static int +/****************************************************************** + * Return TRUE if T_Var = T_Const, else FALSE + * Actually it does not test for =. Need to do this! + ******************************************************************/ +inspectOpNode(Expr *expr) +{ + Expr *firstExpr, + *secondExpr; + + if (nodeTag(expr) != T_Expr || expr->opType != OP_EXPR) + return FALSE; + + TotalExpr++; + + firstExpr = lfirst(expr->args); + secondExpr = lsecond(expr->args); + return (firstExpr && secondExpr && nodeTag(firstExpr) == T_Var && nodeTag(secondExpr) == T_Const); +} + +#endif /* ENABLE_KEY_SET_QUERY */ |