analyze.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,222 行 · 第 1/5 页
C
2,222 行
/*------------------------------------------------------------------------- * * analyze.c * transform the parse tree into a query tree * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.326.2.1 2005/11/22 18:23:12 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/heap.h"#include "catalog/index.h"#include "catalog/namespace.h"#include "catalog/pg_index.h"#include "catalog/pg_type.h"#include "commands/defrem.h"#include "commands/prepare.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/var.h"#include "parser/analyze.h"#include "parser/gramparse.h"#include "parser/parsetree.h"#include "parser/parse_agg.h"#include "parser/parse_clause.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_oper.h"#include "parser/parse_relation.h"#include "parser/parse_target.h"#include "parser/parse_type.h"#include "parser/parse_expr.h"#include "rewrite/rewriteManip.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/guc.h"#include "utils/lsyscache.h"#include "utils/relcache.h"#include "utils/syscache.h"/* State shared by transformCreateSchemaStmt and its subroutines */typedef struct{ const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */ char *schemaname; /* name of schema */ char *authid; /* owner of schema */ List *sequences; /* CREATE SEQUENCE items */ List *tables; /* CREATE TABLE items */ List *views; /* CREATE VIEW items */ List *indexes; /* CREATE INDEX items */ List *triggers; /* CREATE TRIGGER items */ List *grants; /* GRANT items */ List *fwconstraints; /* Forward referencing FOREIGN KEY constraints */ List *alters; /* Generated ALTER items (from the above) */ List *ixconstraints; /* index-creating constraints */ List *blist; /* "before list" of things to do before * creating the schema */ List *alist; /* "after list" of things to do after creating * the schema */} CreateSchemaStmtContext;/* State shared by transformCreateStmt and its subroutines */typedef struct{ const char *stmtType; /* "CREATE TABLE" or "ALTER TABLE" */ RangeVar *relation; /* relation to create */ List *inhRelations; /* relations to inherit from */ bool hasoids; /* does relation have an OID column? */ bool isalter; /* true if altering existing table */ List *columns; /* ColumnDef items */ List *ckconstraints; /* CHECK constraints */ List *fkconstraints; /* FOREIGN KEY constraints */ List *ixconstraints; /* index-creating constraints */ List *blist; /* "before list" of things to do before * creating the table */ List *alist; /* "after list" of things to do after creating * the table */ IndexStmt *pkey; /* PRIMARY KEY index, if any */} CreateStmtContext;typedef struct{ Oid *paramTypes; int numParams;} check_parameter_resolution_context;static List *do_parse_analyze(Node *parseTree, ParseState *pstate);static Query *transformStmt(ParseState *pstate, Node *stmt, List **extras_before, List **extras_after);static Query *transformViewStmt(ParseState *pstate, ViewStmt *stmt, List **extras_before, List **extras_after);static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt, List **extras_before, List **extras_after);static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt, List **extras_before, List **extras_after);static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);static Query *transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt);static Query *transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt);static Query *transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt);static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt, List **extras_before, List **extras_after);static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt, List **extras_before, List **extras_after);static void transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, ColumnDef *column);static void transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt, Constraint *constraint);static void transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, InhRelation *inhrelation);static void transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt);static void transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt, bool skipValidation, bool isAddConstraint);static void applyColumnNames(List *dst, List *src);static List *getSetColTypes(ParseState *pstate, Node *node);static void transformLockingClause(Query *qry, LockingClause *lc);static void transformConstraintAttrs(List *constraintList);static void transformColumnType(ParseState *pstate, ColumnDef *column);static void release_pstate_resources(ParseState *pstate);static FromExpr *makeFromExpr(List *fromlist, Node *quals);static bool check_parameter_resolution_walker(Node *node, check_parameter_resolution_context *context);/* * parse_analyze * Analyze a raw parse tree and transform it to Query form. * * Optionally, information about $n parameter types can be supplied. * References to $n indexes not defined by paramTypes[] are disallowed. * * The result is a List of Query nodes (we need a list since some commands * produce multiple Queries). Optimizable statements require considerable * transformation, while many utility-type statements are simply hung off * a dummy CMD_UTILITY Query node. */List *parse_analyze(Node *parseTree, Oid *paramTypes, int numParams){ ParseState *pstate = make_parsestate(NULL); List *result; pstate->p_paramtypes = paramTypes; pstate->p_numparams = numParams; pstate->p_variableparams = false; result = do_parse_analyze(parseTree, pstate); pfree(pstate); return result;}/* * parse_analyze_varparams * * This variant is used when it's okay to deduce information about $n * symbol datatypes from context. The passed-in paramTypes[] array can * be modified or enlarged (via repalloc). */List *parse_analyze_varparams(Node *parseTree, Oid **paramTypes, int *numParams){ ParseState *pstate = make_parsestate(NULL); List *result; pstate->p_paramtypes = *paramTypes; pstate->p_numparams = *numParams; pstate->p_variableparams = true; result = do_parse_analyze(parseTree, pstate); *paramTypes = pstate->p_paramtypes; *numParams = pstate->p_numparams; pfree(pstate); /* make sure all is well with parameter types */ if (*numParams > 0) { check_parameter_resolution_context context; context.paramTypes = *paramTypes; context.numParams = *numParams; check_parameter_resolution_walker((Node *) result, &context); } return result;}/* * parse_sub_analyze * Entry point for recursively analyzing a sub-statement. */List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState){ ParseState *pstate = make_parsestate(parentParseState); List *result; result = do_parse_analyze(parseTree, pstate); pfree(pstate); return result;}/* * do_parse_analyze * Workhorse code shared by the above variants of parse_analyze. */static List *do_parse_analyze(Node *parseTree, ParseState *pstate){ List *result = NIL; /* Lists to return extra commands from transformation */ List *extras_before = NIL; List *extras_after = NIL; Query *query; ListCell *l; query = transformStmt(pstate, parseTree, &extras_before, &extras_after); /* don't need to access result relation any more */ release_pstate_resources(pstate); foreach(l, extras_before) result = list_concat(result, parse_sub_analyze(lfirst(l), pstate)); result = lappend(result, query); foreach(l, extras_after) result = list_concat(result, parse_sub_analyze(lfirst(l), pstate)); /* * Make sure that only the original query is marked original. We have to * do this explicitly since recursive calls of do_parse_analyze will have * marked some of the added-on queries as "original". Also mark only the * original query as allowed to set the command-result tag. */ foreach(l, result) { Query *q = lfirst(l); if (q == query) { q->querySource = QSRC_ORIGINAL; q->canSetTag = true; } else { q->querySource = QSRC_PARSER; q->canSetTag = false; } } return result;}static voidrelease_pstate_resources(ParseState *pstate){ if (pstate->p_target_relation != NULL) heap_close(pstate->p_target_relation, NoLock); pstate->p_target_relation = NULL; pstate->p_target_rangetblentry = NULL;}/* * transformStmt - * transform a Parse tree into a Query tree. */static Query *transformStmt(ParseState *pstate, Node *parseTree, List **extras_before, List **extras_after){ Query *result = NULL; switch (nodeTag(parseTree)) { /* * Non-optimizable statements */ case T_CreateStmt: result = transformCreateStmt(pstate, (CreateStmt *) parseTree, extras_before, extras_after); break; case T_IndexStmt: result = transformIndexStmt(pstate, (IndexStmt *) parseTree); break; case T_RuleStmt: result = transformRuleStmt(pstate, (RuleStmt *) parseTree, extras_before, extras_after); break; case T_ViewStmt: result = transformViewStmt(pstate, (ViewStmt *) parseTree, extras_before, extras_after); break; case T_ExplainStmt: { ExplainStmt *n = (ExplainStmt *) parseTree; result = makeNode(Query); result->commandType = CMD_UTILITY; n->query = transformStmt(pstate, (Node *) n->query, extras_before, extras_after); result->utilityStmt = (Node *) parseTree; } break; case T_AlterTableStmt: result = transformAlterTableStmt(pstate, (AlterTableStmt *) parseTree, extras_before, extras_after); break; case T_PrepareStmt: result = transformPrepareStmt(pstate, (PrepareStmt *) parseTree); break; case T_ExecuteStmt: result = transformExecuteStmt(pstate, (ExecuteStmt *) parseTree); break; /* * Optimizable statements */ case T_InsertStmt: result = transformInsertStmt(pstate, (InsertStmt *) parseTree, extras_before, extras_after); break; case T_DeleteStmt: result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree); break; case T_UpdateStmt: result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree); break; case T_SelectStmt: if (((SelectStmt *) parseTree)->op == SETOP_NONE) result = transformSelectStmt(pstate, (SelectStmt *) parseTree); else result = transformSetOperationStmt(pstate, (SelectStmt *) parseTree); break; case T_DeclareCursorStmt: result = transformDeclareCursorStmt(pstate, (DeclareCursorStmt *) parseTree); break; default: /* * other statements don't require any transformation-- just return * the original parsetree, yea! */ result = makeNode(Query); result->commandType = CMD_UTILITY; result->utilityStmt = (Node *) parseTree; break; } /* Mark as original query until we learn differently */ result->querySource = QSRC_ORIGINAL; result->canSetTag = true; /* * Check that we did not produce too many resnos; at the very least we * cannot allow more than 2^16, since that would exceed the range of a * AttrNumber. It seems safest to use MaxTupleAttributeNumber. */ if (pstate->p_next_resno - 1 > MaxTupleAttributeNumber) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("target lists can have at most %d entries", MaxTupleAttributeNumber))); return result;}static Query *transformViewStmt(ParseState *pstate, ViewStmt *stmt, List **extras_before, List **extras_after){ Query *result = makeNode(Query); result->commandType = CMD_UTILITY; result->utilityStmt = (Node *) stmt; stmt->query = transformStmt(pstate, (Node *) stmt->query, extras_before, extras_after); /* * If a list of column names was given, run through and insert these into * the actual query tree. - thomas 2000-03-08 * * Outer loop is over targetlist to make it easier to skip junk targetlist * entries. */ if (stmt->aliases != NIL) { ListCell *alist_item = list_head(stmt->aliases); ListCell *targetList; foreach(targetList, stmt->query->targetList) { TargetEntry *te = (TargetEntry *) lfirst(targetList); Assert(IsA(te, TargetEntry)); /* junk columns don't get aliases */ if (te->resjunk) continue; te->resname = pstrdup(strVal(lfirst(alist_item))); alist_item = lnext(alist_item); if (alist_item == NULL) break; /* done assigning aliases */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?