📄 rewritehandler.c
字号:
/*------------------------------------------------------------------------- * * rewriteHandler.c * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.48 1999/07/11 17:54:30 tgl Exp $ * *------------------------------------------------------------------------- */#include <string.h>#include "postgres.h"#include "miscadmin.h"#include "utils/palloc.h"#include "utils/elog.h"#include "utils/rel.h"#include "nodes/pg_list.h"#include "nodes/primnodes.h"#include "nodes/relation.h"#include "parser/parsetree.h" /* for parsetree manipulation */#include "parser/parse_relation.h"#include "nodes/parsenodes.h"/***S*I***/#include "parser/parse_node.h"#include "parser/parse_target.h"#include "parser/analyze.h"#include "optimizer/clauses.h"#include "optimizer/prep.h"#include "rewrite/rewriteSupport.h"#include "rewrite/rewriteHandler.h"#include "rewrite/rewriteManip.h"#include "rewrite/locks.h"#include "commands/creatinh.h"#include "access/heapam.h"#include "utils/lsyscache.h"#include "utils/syscache.h"#include "utils/acl.h"#include "catalog/pg_shadow.h"#include "catalog/pg_type.h"static RewriteInfo *gatherRewriteMeta(Query *parsetree, Query *rule_action, Node *rule_qual, int rt_index, CmdType event, bool *instead_flag);static bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up);static bool attribute_used(Node *node, int rt_index, int attno, int sublevels_up);static void modifyAggrefUplevel(Node *node);static void modifyAggrefChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int sublevels_up);static void modifyAggrefDropQual(Node **nodePtr, Node *orignode, Expr *expr);static SubLink *modifyAggrefMakeSublink(Expr *origexp, Query *parsetree);static void modifyAggrefQual(Node **nodePtr, Query *parsetree);static bool checkQueryHasAggs(Node *node);static bool checkQueryHasAggs_walker(Node *node, void *context);static bool checkQueryHasSubLink(Node *node);static bool checkQueryHasSubLink_walker(Node *node, void *context);static Query *fireRIRrules(Query *parsetree);static Query *Except_Intersect_Rewrite(Query *parsetree);static void check_targetlists_are_compatible(List *prev_target, List *current_target);static void create_intersect_list(Node *ptr, List **intersect_list);static Node *intersect_tree_analyze(Node *tree, Node *first_select, Node *parsetree);/* * gatherRewriteMeta - * Gather meta information about parsetree, and rule. Fix rule body * and qualifier so that they can be mixed with the parsetree and * maintain semantic validity */static RewriteInfo *gatherRewriteMeta(Query *parsetree, Query *rule_action, Node *rule_qual, int rt_index, CmdType event, bool *instead_flag){ RewriteInfo *info; int rt_length; int result_reln; info = (RewriteInfo *) palloc(sizeof(RewriteInfo)); info->rt_index = rt_index; info->event = event; info->instead_flag = *instead_flag; info->rule_action = (Query *) copyObject(rule_action); info->rule_qual = (Node *) copyObject(rule_qual); if (info->rule_action == NULL) info->nothing = TRUE; else { info->nothing = FALSE; info->action = info->rule_action->commandType; info->current_varno = rt_index; info->rt = parsetree->rtable; rt_length = length(info->rt); info->rt = nconc(info->rt, copyObject(info->rule_action->rtable)); info->new_varno = PRS2_NEW_VARNO + rt_length; OffsetVarNodes(info->rule_action->qual, rt_length, 0); OffsetVarNodes((Node *) info->rule_action->targetList, rt_length, 0); OffsetVarNodes(info->rule_qual, rt_length, 0); ChangeVarNodes((Node *) info->rule_action->qual, PRS2_CURRENT_VARNO + rt_length, rt_index, 0); ChangeVarNodes((Node *) info->rule_action->targetList, PRS2_CURRENT_VARNO + rt_length, rt_index, 0); ChangeVarNodes(info->rule_qual, PRS2_CURRENT_VARNO + rt_length, rt_index, 0); /* * bug here about replace CURRENT -- sort of replace current is * deprecated now so this code shouldn't really need to be so * clutzy but..... */ if (info->action != CMD_SELECT) { /* i.e update XXXXX */ int new_result_reln = 0; result_reln = info->rule_action->resultRelation; switch (result_reln) { case PRS2_CURRENT_VARNO: new_result_reln = rt_index; break; case PRS2_NEW_VARNO: /* XXX */ default: new_result_reln = result_reln + rt_length; break; } info->rule_action->resultRelation = new_result_reln; } } return info;}/* * rangeTableEntry_used - * we need to process a RTE for RIR rules only if it is * referenced somewhere in var nodes of the query. */static boolrangeTableEntry_used(Node *node, int rt_index, int sublevels_up){ if (node == NULL) return FALSE; switch (nodeTag(node)) { case T_TargetEntry: { TargetEntry *tle = (TargetEntry *) node; return rangeTableEntry_used( (Node *) (tle->expr), rt_index, sublevels_up); } break; case T_Aggref: { Aggref *aggref = (Aggref *) node; return rangeTableEntry_used( (Node *) (aggref->target), rt_index, sublevels_up); } break; case T_GroupClause: return FALSE; case T_Expr: { Expr *exp = (Expr *) node; return rangeTableEntry_used( (Node *) (exp->args), rt_index, sublevels_up); } break; case T_Iter: { Iter *iter = (Iter *) node; return rangeTableEntry_used( (Node *) (iter->iterexpr), rt_index, sublevels_up); } break; case T_ArrayRef: { ArrayRef *ref = (ArrayRef *) node; if (rangeTableEntry_used( (Node *) (ref->refupperindexpr), rt_index, sublevels_up)) return TRUE; if (rangeTableEntry_used( (Node *) (ref->reflowerindexpr), rt_index, sublevels_up)) return TRUE; if (rangeTableEntry_used( (Node *) (ref->refexpr), rt_index, sublevels_up)) return TRUE; if (rangeTableEntry_used( (Node *) (ref->refassgnexpr), rt_index, sublevels_up)) return TRUE; return FALSE; } break; case T_Var: { Var *var = (Var *) node; if (var->varlevelsup == sublevels_up) return var->varno == rt_index; else return FALSE; } break; case T_Param: return FALSE; case T_Const: return FALSE; case T_List: { List *l; foreach(l, (List *) node) { if (rangeTableEntry_used( (Node *) lfirst(l), rt_index, sublevels_up)) return TRUE; } return FALSE; } break; case T_SubLink: { SubLink *sub = (SubLink *) node; if (rangeTableEntry_used( (Node *) (sub->lefthand), rt_index, sublevels_up)) return TRUE; if (rangeTableEntry_used( (Node *) (sub->subselect), rt_index, sublevels_up + 1)) return TRUE; return FALSE; } break; case T_CaseExpr: { CaseExpr *exp = (CaseExpr *) node; if (rangeTableEntry_used( (Node *) (exp->args), rt_index, sublevels_up)) return TRUE; if (rangeTableEntry_used( (Node *) (exp->defresult), rt_index, sublevels_up)) return TRUE; return FALSE; } break; case T_CaseWhen: { CaseWhen *when = (CaseWhen *) node; if (rangeTableEntry_used( (Node *) (when->expr), rt_index, sublevels_up)) return TRUE; if (rangeTableEntry_used( (Node *) (when->result), rt_index, sublevels_up)) return TRUE; return FALSE; } break; case T_Query: { Query *qry = (Query *) node; if (rangeTableEntry_used( (Node *) (qry->targetList), rt_index, sublevels_up)) return TRUE; if (rangeTableEntry_used( (Node *) (qry->qual), rt_index, sublevels_up)) return TRUE; if (rangeTableEntry_used( (Node *) (qry->havingQual), rt_index, sublevels_up)) return TRUE; return FALSE; } break; default: elog(NOTICE, "unknown node tag %d in rangeTableEntry_used()", nodeTag(node)); elog(NOTICE, "Node is: %s", nodeToString(node)); break; } return FALSE;}/* * attribute_used - * Check if a specific attribute number of a RTE is used * somewhere in the query */static boolattribute_used(Node *node, int rt_index, int attno, int sublevels_up){ if (node == NULL) return FALSE; switch (nodeTag(node)) { case T_TargetEntry: { TargetEntry *tle = (TargetEntry *) node; return attribute_used( (Node *) (tle->expr), rt_index, attno, sublevels_up); } break; case T_Aggref: { Aggref *aggref = (Aggref *) node; return attribute_used( (Node *) (aggref->target), rt_index, attno, sublevels_up); } break; case T_GroupClause: return FALSE; case T_Expr: { Expr *exp = (Expr *) node; return attribute_used( (Node *) (exp->args), rt_index, attno, sublevels_up); } break; case T_Iter: { Iter *iter = (Iter *) node; return attribute_used( (Node *) (iter->iterexpr), rt_index, attno, sublevels_up); } break; case T_ArrayRef: { ArrayRef *ref = (ArrayRef *) node; if (attribute_used( (Node *) (ref->refupperindexpr), rt_index, attno, sublevels_up)) return TRUE; if (attribute_used( (Node *) (ref->reflowerindexpr), rt_index, attno, sublevels_up)) return TRUE; if (attribute_used( (Node *) (ref->refexpr), rt_index, attno, sublevels_up)) return TRUE; if (attribute_used( (Node *) (ref->refassgnexpr), rt_index, attno, sublevels_up)) return TRUE; return FALSE; } break; case T_Var: { Var *var = (Var *) node; if (var->varlevelsup == sublevels_up) return var->varno == rt_index; else return FALSE; } break; case T_Param: return FALSE; case T_Const: return FALSE; case T_List: { List *l; foreach(l, (List *) node) { if (attribute_used( (Node *) lfirst(l), rt_index, attno, sublevels_up)) return TRUE; } return FALSE; } break; case T_SubLink: { SubLink *sub = (SubLink *) node; if (attribute_used( (Node *) (sub->lefthand), rt_index, attno, sublevels_up)) return TRUE; if (attribute_used( (Node *) (sub->subselect), rt_index, attno, sublevels_up + 1)) return TRUE; return FALSE; } break; case T_Query: { Query *qry = (Query *) node; if (attribute_used( (Node *) (qry->targetList), rt_index, attno, sublevels_up)) return TRUE; if (attribute_used( (Node *) (qry->qual), rt_index, attno, sublevels_up)) return TRUE; if (attribute_used( (Node *) (qry->havingQual), rt_index, attno, sublevels_up)) return TRUE; return FALSE; } break; default: elog(NOTICE, "unknown node tag %d in attribute_used()", nodeTag(node)); elog(NOTICE, "Node is: %s", nodeToString(node)); break; } return FALSE;}/* * modifyAggrefUplevel - * In the newly created sublink for an aggregate column used in * the qualification, we must adjust the varlevelsup in all the * var nodes. */static voidmodifyAggrefUplevel(Node *node){ if (node == NULL) return; switch (nodeTag(node)) { case T_TargetEntry: { TargetEntry *tle = (TargetEntry *) node; modifyAggrefUplevel( (Node *) (tle->expr)); } break; case T_Aggref: { Aggref *aggref = (Aggref *) node; modifyAggrefUplevel( (Node *) (aggref->target)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -