📄 analyze.c
字号:
extras_before = blist; extras_after = ilist; return q;} /* transformCreateStmt() *//* * transformIndexStmt - * transforms the qualification of the index statement */static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt){ Query *qry; qry = makeNode(Query); qry->commandType = CMD_UTILITY; /* take care of the where clause */ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL); qry->hasSubLinks = pstate->p_hasSubLinks; stmt->rangetable = pstate->p_rtable; qry->utilityStmt = (Node *) stmt; return qry;}/* * transformExtendStmt - * transform the qualifications of the Extend Index Statement * */static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt){ Query *qry; qry = makeNode(Query); qry->commandType = CMD_UTILITY; /* take care of the where clause */ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL); qry->hasSubLinks = pstate->p_hasSubLinks; stmt->rangetable = pstate->p_rtable; qry->utilityStmt = (Node *) stmt; return qry;}/* * transformRuleStmt - * transform a Create Rule Statement. The actions is a list of parse * trees which is transformed into a list of query trees. */static Query *transformRuleStmt(ParseState *pstate, RuleStmt *stmt){ Query *qry; Query *action; List *actions; qry = makeNode(Query); qry->commandType = CMD_UTILITY; /* * 'instead nothing' rules with a qualification need a query a * rangetable so the rewrite handler can add the negated rule * qualification to the original query. We create a query with the new * command type CMD_NOTHING here that is treated special by the * rewrite system. */ if (stmt->actions == NIL) { Query *nothing_qry = makeNode(Query); nothing_qry->commandType = CMD_NOTHING; addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*", FALSE, FALSE); addRangeTableEntry(pstate, stmt->object->relname, "*NEW*", FALSE, FALSE); nothing_qry->rtable = pstate->p_rtable; stmt->actions = lappend(NIL, nothing_qry); } actions = stmt->actions; /* * transform each statment, like parse_analyze() */ while (actions != NIL) { /* * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW' * equal to 2. */ addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*", FALSE, FALSE); addRangeTableEntry(pstate, stmt->object->relname, "*NEW*", FALSE, FALSE); pstate->p_last_resno = 1; pstate->p_is_rule = true; /* for expand all */ pstate->p_hasAggs = false; action = (Query *) lfirst(actions); if (action->commandType != CMD_NOTHING) lfirst(actions) = transformStmt(pstate, lfirst(actions)); actions = lnext(actions); } /* take care of the where clause */ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL); qry->hasSubLinks = pstate->p_hasSubLinks; qry->utilityStmt = (Node *) stmt; return qry;}/* * transformSelectStmt - * transforms a Select Statement * */static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt){ Query *qry = makeNode(Query); Node *qual; qry->commandType = CMD_SELECT; /* set up a range table */ makeRangeTable(pstate, NULL, stmt->fromClause, &qual); qry->uniqueFlag = stmt->unique; qry->into = stmt->into; qry->isTemp = stmt->istemp; qry->isPortal = FALSE; qry->targetList = transformTargetList(pstate, stmt->targetList); qry->qual = transformWhereClause(pstate, stmt->whereClause, qual); /* * The havingQual has a similar meaning as "qual" in the where * statement. So we can easily use the code from the "where clause" * with some additional traversals done in optimizer/plan/planner.c */ qry->havingQual = transformWhereClause(pstate, stmt->havingClause, NULL); qry->hasSubLinks = pstate->p_hasSubLinks; qry->sortClause = transformSortClause(pstate, stmt->sortClause, NIL, qry->targetList, qry->uniqueFlag); qry->groupClause = transformGroupClause(pstate, stmt->groupClause, qry->targetList); qry->rtable = pstate->p_rtable; qry->hasAggs = pstate->p_hasAggs; if (pstate->p_hasAggs || qry->groupClause) parseCheckAggregates(pstate, qry); /* * The INSERT INTO ... SELECT ... could have a UNION in child, so * unionClause may be false */ qry->unionall = stmt->unionall; /***S*I***/ /* * Just hand through the unionClause and intersectClause. We will * handle it in the function Except_Intersect_Rewrite() */ qry->unionClause = stmt->unionClause; qry->intersectClause = stmt->intersectClause; /* * If there is a havingQual but there are no aggregates, then there is * something wrong with the query because having must contain * aggregates in its expressions! Otherwise the query could have been * formulated using the where clause. */ if ((qry->hasAggs == false) && (qry->havingQual != NULL)) { elog(ERROR, "SELECT/HAVING requires aggregates to be valid"); return (Query *) NIL; } if (stmt->forUpdate != NULL) transformForUpdate(qry, stmt->forUpdate); return (Query *) qry;}/* * transformUpdateStmt - * transforms an update statement * */static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt){ Query *qry = makeNode(Query); qry->commandType = CMD_UPDATE; pstate->p_is_update = true; /* * the FROM clause is non-standard SQL syntax. We used to be able to * do this with REPLACE in POSTQUEL so we keep the feature. */ makeRangeTable(pstate, stmt->relname, stmt->fromClause, NULL); qry->targetList = transformTargetList(pstate, stmt->targetList); qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL); qry->hasSubLinks = pstate->p_hasSubLinks; qry->rtable = pstate->p_rtable; qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL); qry->hasAggs = pstate->p_hasAggs; if (pstate->p_hasAggs) parseCheckAggregates(pstate, qry); return (Query *) qry;}/* * transformCursorStmt - * transform a Create Cursor Statement * */static Query *transformCursorStmt(ParseState *pstate, SelectStmt *stmt){ Query *qry; qry = transformSelectStmt(pstate, stmt); qry->into = stmt->portalname; qry->isTemp = stmt->istemp; qry->isPortal = TRUE; qry->isBinary = stmt->binary; /* internal portal */ return qry;}/***S*I***//* This function steps through the tree * built up by the select_w_o_sort rule * and builds a list of all SelectStmt Nodes found * The built up list is handed back in **select_list. * If one of the SelectStmt Nodes has the 'unionall' flag * set to true *unionall_present hands back 'true' */voidcreate_select_list(Node *ptr, List **select_list, bool *unionall_present){ if (IsA(ptr, SelectStmt)) { *select_list = lappend(*select_list, ptr); if (((SelectStmt *) ptr)->unionall == TRUE) *unionall_present = TRUE; return; } /* Recursively call for all arguments. A NOT expr has no lexpr! */ if (((A_Expr *) ptr)->lexpr != NULL) create_select_list(((A_Expr *) ptr)->lexpr, select_list, unionall_present); create_select_list(((A_Expr *) ptr)->rexpr, select_list, unionall_present);}/* Changes the A_Expr Nodes to Expr Nodes and exchanges ANDs and ORs. * The reason for the exchange is easy: We implement INTERSECTs and EXCEPTs * by rewriting these queries to semantically equivalent queries that use * IN and NOT IN subselects. To be able to use all three operations * (UNIONs INTERSECTs and EXCEPTs) in one complex query we have to * translate the queries into Disjunctive Normal Form (DNF). Unfortunately * there is no function 'dnfify' but there is a function 'cnfify' * which produces DNF when we exchange ANDs and ORs before calling * 'cnfify' and exchange them back in the result. * * If an EXCEPT or INTERSECT is present *intersect_present * hands back 'true' */Node *A_Expr_to_Expr(Node *ptr, bool *intersect_present){ Node *result = NULL; switch (nodeTag(ptr)) { case T_A_Expr: { A_Expr *a = (A_Expr *) ptr; switch (a->oper) { case AND: { Expr *expr = makeNode(Expr); Node *lexpr = A_Expr_to_Expr(((A_Expr *) ptr)->lexpr, intersect_present); Node *rexpr = A_Expr_to_Expr(((A_Expr *) ptr)->rexpr, intersect_present); *intersect_present = TRUE; expr->typeOid = BOOLOID; expr->opType = OR_EXPR; expr->args = makeList(lexpr, rexpr, -1); result = (Node *) expr; break; } case OR: { Expr *expr = makeNode(Expr); Node *lexpr = A_Expr_to_Expr(((A_Expr *) ptr)->lexpr, intersect_present); Node *rexpr = A_Expr_to_Expr(((A_Expr *) ptr)->rexpr, intersect_present); expr->typeOid = BOOLOID; expr->opType = AND_EXPR; expr->args = makeList(lexpr, rexpr, -1); result = (Node *) expr; break; } case NOT: { Expr *expr = makeNode(Expr); Node *rexpr = A_Expr_to_Expr(((A_Expr *) ptr)->rexpr, intersect_present); expr->typeOid = BOOLOID; expr->opType = NOT_EXPR; expr->args = makeList(rexpr, -1); result = (Node *) expr; break; } } break; } default: result = ptr; } return result;}voidCheckSelectForUpdate(Query *qry){ if (qry->unionClause != NULL) elog(ERROR, "SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT clause"); if (qry->uniqueFlag != NULL) elog(ERROR, "SELECT FOR UPDATE is not allowed with DISTINCT clause"); if (qry->groupClause != NULL) elog(ERROR, "SELECT FOR UPDATE is not allowed with GROUP BY clause"); if (qry->hasAggs) elog(ERROR, "SELECT FOR UPDATE is not allowed with AGGREGATE");}static voidtransformForUpdate(Query *qry, List *forUpdate){ List *rowMark = NULL; RowMark *newrm; List *l; Index i; CheckSelectForUpdate(qry); if (lfirst(forUpdate) == NULL) /* all tables */ { i = 1; foreach(l, qry->rtable) { newrm = makeNode(RowMark); newrm->rti = i++; newrm->info = ROW_MARK_FOR_UPDATE | ROW_ACL_FOR_UPDATE; rowMark = lappend(rowMark, newrm); } qry->rowMark = nconc(qry->rowMark, rowMark); return; } foreach(l, forUpdate) { List *l2; List *l3; i = 1; foreach(l2, qry->rtable) { if (strcmp(((RangeTblEntry *) lfirst(l2))->refname, lfirst(l)) == 0) { foreach(l3, rowMark) { if (((RowMark *) lfirst(l3))->rti == i) /* duplicate */ break; } if (l3 == NULL) { newrm = makeNode(RowMark); newrm->rti = i; newrm->info = ROW_MARK_FOR_UPDATE | ROW_ACL_FOR_UPDATE; rowMark = lappend(rowMark, newrm); } break; } i++; } if (l2 == NULL) elog(ERROR, "FOR UPDATE: relation %s not found in FROM clause", lfirst(l)); } qry->rowMark = rowMark; return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -