将rownum优化的处理模块独立开来。

This commit is contained in:
zhouxiongjia
2020-10-30 11:58:55 +08:00
parent 1b439d8718
commit 68518a58ee
3 changed files with 377 additions and 348 deletions

View File

@ -16,6 +16,6 @@ ifneq "$(MAKECMDGOALS)" "clean"
endif
endif
endif
OBJS = prepjointree.o prepnonjointree.o prepqual.o preptlist.o prepunion.o
OBJS = prepjointree.o prepnonjointree.o prepqual.o preprownum.o preptlist.o prepunion.o
include $(top_srcdir)/src/gausskernel/common.mk

View File

@ -92,16 +92,6 @@ static Node* find_jointree_node_for_rel(Node* jtnode, int relid);
static Node* deleteRelatedNullTest(Node* node, PlannerInfo* root);
static Node* reduce_inequality_fulljoins_jointree_recurse(PlannerInfo* root, Node* jtnode);
static bool find_rownum_in_quals(PlannerInfo *root);
static Node* preprocess_rownum_opexpr(PlannerInfo* root, Query* parse, OpExpr* expr, bool isOrExpr);
static Node* process_rownum_boolexpr(PlannerInfo *root, Query* parse, BoolExpr* quals);
static Node* process_rownum_lt(Query *parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_le(Query* parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_eq(Query* parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_gt(Query* parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_ge(Query* parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_ne(Query* parse, OpExpr* qual, bool isOrExpr);
static int64 extract_rownum_limit(OpExpr *expr);
/*
* pull_up_sublinks
@ -2949,340 +2939,4 @@ static bool find_rownum_in_quals(PlannerInfo *root)
}
return hasRownum;
}
/*
* preprocess_rownum
* rewrite ROWNUM to LIMIT in parse tree if possible
*/
void preprocess_rownum(PlannerInfo *root, Query *parse)
{
Node* quals = parse->jointree->quals;
if (quals == NULL) {
return;
}
/* If it includes {order by} or {group by}, can not be rewrited */
if ((parse->sortClause != NULL) || (parse->groupClause != NULL)) {
return;
}
if (parse->limitCount != NULL) {
parse->limitCount = eval_const_expressions(root, parse->limitCount);
if (!IsA(parse->limitCount, Const)) {
/* can not estimate */
return;
}
}
quals = (Node*)canonicalize_qual((Expr*)quals);
switch (nodeTag(quals)) {
case T_OpExpr: {
quals = preprocess_rownum_opexpr(root, parse, (OpExpr*)quals, false);
break;
}
case T_BoolExpr: {
quals = process_rownum_boolexpr(root, parse, (BoolExpr*)quals);
break;
}
default: {
break;
}
}
parse->jointree->quals = quals;
}
static Node* process_rownum_boolexpr(PlannerInfo* root, Query* parse, BoolExpr* quals)
{
ListCell *lc = NULL;
if (quals->boolop == AND_EXPR) {
foreach(lc, quals->args)
{
Node* clause = (Node*)lfirst(lc);
if (!IsA(clause, OpExpr)) {
continue;
}
clause = preprocess_rownum_opexpr(root, parse, (OpExpr*)clause, false);
if (IsA(clause, Const) && !DatumGetBool(((Const*)clause)->constvalue)) {
/* if FALSE constant in AND expr, directly return FALSE qual */
return clause;
}
lfirst(lc) = clause;
}
} else if (quals->boolop == OR_EXPR) {
foreach(lc, quals->args)
{
Node* clause = (Node*)lfirst(lc);
if (!IsA(clause, OpExpr)) {
continue;
}
clause = preprocess_rownum_opexpr(root, parse, (OpExpr*)clause, true);
if (IsA(clause, Const) && DatumGetBool(((Const*)clause)->constvalue)) {
/* if TRUE constant in OR expr, directly return TRUE qual */
return clause;
}
lfirst(lc) = clause;
}
}
return (Node*)quals;
}
static void rewrite_rownum_to_limit(Query *parse, int64 num)
{
Const* limitCount = (Const*)parse->limitCount;
Assert(limitCount == NULL || IsA(limitCount, Const));
if (limitCount == NULL || limitCount->constisnull) {
/* limitCount->constisnull indicates LIMIT ALL, ie, no limit */
parse->limitCount =
(Node*)makeConst(INT8OID, -1, InvalidOid, sizeof(int64), Int64GetDatum(num), false, true);
return;
}
if (DatumGetInt64(limitCount->constvalue) > num) {
limitCount->constvalue = Int64GetDatum(num);
}
}
static bool is_optimizable_rownum_opexpr(PlannerInfo* root, OpExpr* expr)
{
Node* leftArg = (Node*)linitial(expr->args);
if (!IsA(leftArg, Rownum)) {
return false;
}
Node* rightArg = (Node*)llast(expr->args);
rightArg = eval_const_expressions(root, rightArg);
if (!IsA(rightArg, Const)) {
return false;
}
/* now, only constant integer types are supported to rewrite */
Oid consttype = ((Const*)rightArg)->consttype;
if (consttype == INT8OID || consttype == INT4OID ||
consttype == INT2OID || consttype == INT1OID) {
return true;
}
return false;
}
static Node* preprocess_rownum_opexpr(PlannerInfo* root, Query* parse, OpExpr* expr, bool isOrExpr)
{
/* Currently, only {ROWNUM op Const} can be optimizable */
if (!is_optimizable_rownum_opexpr(root, expr)) {
return (Node*)expr;
}
switch (expr->opno) {
case INT8LTOID:
case INT84LTOID:
case INT82LTOID:
/* operator '<' */
return process_rownum_lt(parse, expr, isOrExpr);
case INT8LEOID:
case INT84LEOID:
case INT82LEOID:
/* operator '<=' */
return process_rownum_le(parse, expr, isOrExpr);
case INT8EQOID:
case INT84EQOID:
case INT82EQOID:
/* operator '=' */
return process_rownum_eq(parse, expr, isOrExpr);
case INT8GTOID:
case INT84GTOID:
case INT82GTOID:
/* operator '>' */
return process_rownum_gt(parse, expr, isOrExpr);
case INT8GEOID:
case INT84GEOID:
case INT82GEOID:
/* operator '>=' */
return process_rownum_ge(parse, expr, isOrExpr);
case INT8NEOID:
case INT84NEOID:
case INT82NEOID:
/* operator '!=' */
return process_rownum_ne(parse, expr, isOrExpr);
default:
return (Node*)expr;
}
}
/* extract const value from OpExpr like {rownum op Const} */
static int64 extract_rownum_limit(OpExpr *expr)
{
Const* con = (Const *)llast(expr->args);
Oid type = con->consttype;
Datum value = con->constvalue;
if (type == INT8OID) {
return DatumGetInt64(value);
} else if (type == INT4OID) {
return (int64)DatumGetInt32(value);
} else if (type == INT2OID) {
return (int64)DatumGetInt16(value);
} else if (type == INT1OID) {
return (int64)DatumGetInt8(value);
} else {
ereport(ERROR,
((errmodule(MOD_OPT),
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unsupported data type %u for ROWNUM limit", type))));
return -1;
}
}
/* process operator '<' in rownum expr like {rownum < 5}
* if the OpExpr is rewritten, the original OpExpr can be
* substituted by a bool constant expr. */
static Node* process_rownum_lt(Query *parse, OpExpr *rnxpr, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(rnxpr);
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
if (limitValue <= 1) {
return makeBoolConst(false, false);
}
return (Node*)rnxpr;
}
/* ROWNUM OpExpr in AndExpr */
if (limitValue <= 1) {
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
} else {
rewrite_rownum_to_limit(parse, limitValue - 1);
return makeBoolConst(true, false);
}
}
/* process operator '<=' in rownum expr like {rownum <= 5}
* if the OpExpr is rewritten, the original OpExpr can be
* substituted by a bool constant expr. */
static Node* process_rownum_le(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
if (limitValue < 1) {
return makeBoolConst(false, false);
}
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr */
if (limitValue < 1) {
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
} else {
rewrite_rownum_to_limit(parse, limitValue);
return makeBoolConst(true, false);
}
}
/* process operator '=' in rownum expr like {rownum = 5} */
static Node* process_rownum_eq(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
if (limitValue < 1) {
return makeBoolConst(false, false);
}
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr */
if (limitValue == 1) {
rewrite_rownum_to_limit(parse, 1);
return makeBoolConst(true, false);
} else {
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
}
}
/* process operator '>' in rownum expr like {rcoerceownum > 5} */
static Node* process_rownum_gt(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
if (limitValue < 1) {
return makeBoolConst(true, false);
}
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr,
* here limitValue >= 1, so ROWNUM > limitValue is always false. */
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
}
/* process operator '>=' in rownum expr like {rownum >= 5}
* if the OpExpr is rewritten, the original OpExpr can be
* substituted by a bool constant expr. */
static Node* process_rownum_ge(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
if (limitValue <= 1) {
return makeBoolConst(true, false);
}
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr */
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
}
/* process operator '!=' in rownum expr, e.g. rewrite {rownum != 5} to LIMIT 4
* if it can be rewrited to LIMIT, return TRUE
*/
static Node* process_rownum_ne(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
if (limitValue < 1) {
return makeBoolConst(true, false);
}
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr */
if (limitValue == 1) {
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
} else { /* for limitValue > 1 */
rewrite_rownum_to_limit(parse, limitValue - 1);
return makeBoolConst(true, false);
}
}
}

View File

@ -0,0 +1,375 @@
/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* preprownum.cpp
* Planner preprocessing for ROWNUM
* The main function is to rewrite ROWNUM to LIMIT in parse tree if possible.
* For example,
* {select * from table_name where rownum < 5;}
* can be rewrited to
* {select * from table_name limit 4;}
*
* IDENTIFICATION
* src/gausskernel/optimizer/prep/preprownum.cpp
*
* -------------------------------------------------------------------------
*/
#include "optimizer/prep.h"
#include "nodes/makefuncs.h"
static Node* preprocess_rownum_opexpr(PlannerInfo* root, Query* parse, OpExpr* expr, bool isOrExpr);
static Node* process_rownum_boolexpr(PlannerInfo *root, Query* parse, BoolExpr* quals);
static Node* process_rownum_lt(Query *parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_le(Query* parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_eq(Query* parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_gt(Query* parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_ge(Query* parse, OpExpr* qual, bool isOrExpr);
static Node* process_rownum_ne(Query* parse, OpExpr* qual, bool isOrExpr);
static int64 extract_rownum_limit(OpExpr *expr);
/*
* preprocess_rownum
* rewrite ROWNUM to LIMIT in parse tree if possible
*/
void preprocess_rownum(PlannerInfo *root, Query *parse)
{
Node* quals = parse->jointree->quals;
if (quals == NULL) {
return;
}
/* If it includes {order by} or {group by}, can not be rewrited */
if ((parse->sortClause != NULL) || (parse->groupClause != NULL)) {
return;
}
if (parse->limitCount != NULL) {
parse->limitCount = eval_const_expressions(root, parse->limitCount);
if (!IsA(parse->limitCount, Const)) {
/* can not estimate */
return;
}
}
quals = (Node*)canonicalize_qual((Expr*)quals);
switch (nodeTag(quals)) {
case T_OpExpr: {
quals = preprocess_rownum_opexpr(root, parse, (OpExpr*)quals, false);
break;
}
case T_BoolExpr: {
quals = process_rownum_boolexpr(root, parse, (BoolExpr*)quals);
break;
}
default: {
break;
}
}
parse->jointree->quals = quals;
}
static Node* process_rownum_boolexpr(PlannerInfo* root, Query* parse, BoolExpr* quals)
{
ListCell *lc = NULL;
if (quals->boolop == AND_EXPR) {
foreach(lc, quals->args)
{
Node* clause = (Node*)lfirst(lc);
if (!IsA(clause, OpExpr)) {
continue;
}
clause = preprocess_rownum_opexpr(root, parse, (OpExpr*)clause, false);
if (IsA(clause, Const) && !DatumGetBool(((Const*)clause)->constvalue)) {
/* if FALSE constant in AND expr, directly return FALSE qual */
return clause;
}
lfirst(lc) = clause;
}
} else if (quals->boolop == OR_EXPR) {
foreach(lc, quals->args)
{
Node* clause = (Node*)lfirst(lc);
if (!IsA(clause, OpExpr)) {
continue;
}
clause = preprocess_rownum_opexpr(root, parse, (OpExpr*)clause, true);
if (IsA(clause, Const) && DatumGetBool(((Const*)clause)->constvalue)) {
/* if TRUE constant in OR expr, directly return TRUE qual */
return clause;
}
lfirst(lc) = clause;
}
}
return (Node*)quals;
}
static void rewrite_rownum_to_limit(Query *parse, int64 num)
{
Const* limitCount = (Const*)parse->limitCount;
Assert(limitCount == NULL || IsA(limitCount, Const));
if (limitCount == NULL || limitCount->constisnull) {
/* limitCount->constisnull indicates LIMIT ALL, ie, no limit */
parse->limitCount =
(Node*)makeConst(INT8OID, -1, InvalidOid, sizeof(int64), Int64GetDatum(num), false, true);
return;
}
if (DatumGetInt64(limitCount->constvalue) > num) {
limitCount->constvalue = Int64GetDatum(num);
}
}
static bool is_optimizable_rownum_opexpr(PlannerInfo* root, OpExpr* expr)
{
Node* leftArg = (Node*)linitial(expr->args);
if (!IsA(leftArg, Rownum)) {
return false;
}
Node* rightArg = (Node*)llast(expr->args);
rightArg = eval_const_expressions(root, rightArg);
if (!IsA(rightArg, Const)) {
return false;
}
/* now, only constant integer types are supported to rewrite */
Oid consttype = ((Const*)rightArg)->consttype;
if (consttype == INT8OID || consttype == INT4OID ||
consttype == INT2OID || consttype == INT1OID) {
return true;
}
return false;
}
static Node* preprocess_rownum_opexpr(PlannerInfo* root, Query* parse, OpExpr* expr, bool isOrExpr)
{
/* Currently, only {ROWNUM op Const} can be optimizable */
if (!is_optimizable_rownum_opexpr(root, expr)) {
return (Node*)expr;
}
switch (expr->opno) {
case INT8LTOID:
case INT84LTOID:
case INT82LTOID:
/* operator '<' */
return process_rownum_lt(parse, expr, isOrExpr);
case INT8LEOID:
case INT84LEOID:
case INT82LEOID:
/* operator '<=' */
return process_rownum_le(parse, expr, isOrExpr);
case INT8EQOID:
case INT84EQOID:
case INT82EQOID:
/* operator '=' */
return process_rownum_eq(parse, expr, isOrExpr);
case INT8GTOID:
case INT84GTOID:
case INT82GTOID:
/* operator '>' */
return process_rownum_gt(parse, expr, isOrExpr);
case INT8GEOID:
case INT84GEOID:
case INT82GEOID:
/* operator '>=' */
return process_rownum_ge(parse, expr, isOrExpr);
case INT8NEOID:
case INT84NEOID:
case INT82NEOID:
/* operator '!=' */
return process_rownum_ne(parse, expr, isOrExpr);
default:
return (Node*)expr;
}
}
/* extract const value from OpExpr like {rownum op Const} */
static int64 extract_rownum_limit(OpExpr *expr)
{
Const* con = (Const *)llast(expr->args);
Oid type = con->consttype;
Datum value = con->constvalue;
if (type == INT8OID) {
return DatumGetInt64(value);
} else if (type == INT4OID) {
return (int64)DatumGetInt32(value);
} else if (type == INT2OID) {
return (int64)DatumGetInt16(value);
} else if (type == INT1OID) {
return (int64)DatumGetInt8(value);
} else {
ereport(ERROR,
((errmodule(MOD_OPT),
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unsupported data type %u for ROWNUM limit", type))));
return -1;
}
}
/* process operator '<' in rownum expr like {rownum < 5}
* if the OpExpr is rewritten, the original OpExpr can be
* substituted by a bool constant expr. */
static Node* process_rownum_lt(Query *parse, OpExpr *rnxpr, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(rnxpr);
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
if (limitValue <= 1) {
return makeBoolConst(false, false);
}
return (Node*)rnxpr;
}
/* ROWNUM OpExpr in AndExpr */
if (limitValue <= 1) {
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
} else {
rewrite_rownum_to_limit(parse, limitValue - 1);
return makeBoolConst(true, false);
}
}
/* process operator '<=' in rownum expr like {rownum <= 5}
* if the OpExpr is rewritten, the original OpExpr can be
* substituted by a bool constant expr. */
static Node* process_rownum_le(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
if (limitValue < 1) {
return makeBoolConst(false, false);
}
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr */
if (limitValue < 1) {
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
} else {
rewrite_rownum_to_limit(parse, limitValue);
return makeBoolConst(true, false);
}
}
/* process operator '=' in rownum expr like {rownum = 5} */
static Node* process_rownum_eq(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
if (limitValue < 1) {
return makeBoolConst(false, false);
}
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr */
if (limitValue == 1) {
rewrite_rownum_to_limit(parse, 1);
return makeBoolConst(true, false);
} else {
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
}
}
/* process operator '>' in rownum expr like {rcoerceownum > 5} */
static Node* process_rownum_gt(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
if (limitValue < 1) {
return makeBoolConst(true, false);
}
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr,
* here limitValue >= 1, so ROWNUM > limitValue is always false. */
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
}
/* process operator '>=' in rownum expr like {rownum >= 5}
* if the OpExpr is rewritten, the original OpExpr can be
* substituted by a bool constant expr. */
static Node* process_rownum_ge(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
if (limitValue <= 1) {
return makeBoolConst(true, false);
}
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr */
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
}
/* process operator '!=' in rownum expr, e.g. rewrite {rownum != 5} to LIMIT 4
* if it can be rewrited to LIMIT, return TRUE
*/
static Node* process_rownum_ne(Query* parse, OpExpr* qual, bool isOrExpr)
{
int64 limitValue = extract_rownum_limit(qual);
if (limitValue < 1) {
return makeBoolConst(true, false);
}
/* ROWNUM OpExpr in OrExpr */
if (isOrExpr) {
return (Node*)qual;
}
/* ROWNUM OpExpr in AndExpr */
if (limitValue == 1) {
rewrite_rownum_to_limit(parse, 0);
return makeBoolConst(false, false);
} else { /* for limitValue > 1 */
rewrite_rownum_to_limit(parse, limitValue - 1);
return makeBoolConst(true, false);
}
}