analyze.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,258 行 · 第 1/5 页
C
2,258 行
/* * Output results. */ q = makeNode(Query); q->commandType = CMD_UTILITY; q->utilityStmt = (Node *) stmt; stmt->tableElts = cxt.columns; stmt->constraints = cxt.ckconstraints; *extras_before = nconc(*extras_before, cxt.blist); *extras_after = nconc(cxt.alist, *extras_after); return q;}static voidtransformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, ColumnDef *column){ bool is_serial; bool saw_nullable; Constraint *constraint; List *clist; cxt->columns = lappend(cxt->columns, column); /* Check for SERIAL pseudo-types */ is_serial = false; if (length(column->typename->names) == 1) { char *typname = strVal(lfirst(column->typename->names)); if (strcmp(typname, "serial") == 0 || strcmp(typname, "serial4") == 0) { is_serial = true; column->typename->names = NIL; column->typename->typeid = INT4OID; } else if (strcmp(typname, "bigserial") == 0 || strcmp(typname, "serial8") == 0) { is_serial = true; column->typename->names = NIL; column->typename->typeid = INT8OID; } } /* Do necessary work on the column type declaration */ transformColumnType(pstate, column); /* Special actions for SERIAL pseudo-types */ if (is_serial) { char *sname; char *snamespace; char *qstring; A_Const *snamenode; FuncCall *funccallnode; CreateSeqStmt *seqstmt; /* * Determine name and namespace to use for the sequence. */ sname = makeObjectName(cxt->relation->relname, column->colname, "seq"); snamespace = get_namespace_name(RangeVarGetCreationNamespace(cxt->relation)); ereport(NOTICE, (errmsg("%s will create implicit sequence \"%s\" for \"serial\" column \"%s.%s\"", cxt->stmtType, sname, cxt->relation->relname, column->colname))); /* * Build a CREATE SEQUENCE command to create the sequence object, * and add it to the list of things to be done before this * CREATE/ALTER TABLE. */ seqstmt = makeNode(CreateSeqStmt); seqstmt->sequence = makeRangeVar(snamespace, sname); seqstmt->options = NIL; cxt->blist = lappend(cxt->blist, seqstmt); /* * Mark the ColumnDef so that during execution, an appropriate * dependency will be added from the sequence to the column. */ column->support = makeRangeVar(snamespace, sname); /* * Create appropriate constraints for SERIAL. We do this in full, * rather than shortcutting, so that we will detect any * conflicting constraints the user wrote (like a different * DEFAULT). * * Create an expression tree representing the function call * nextval('"sequencename"') */ qstring = quote_qualified_identifier(snamespace, sname); snamenode = makeNode(A_Const); snamenode->val.type = T_String; snamenode->val.val.str = qstring; funccallnode = makeNode(FuncCall); funccallnode->funcname = SystemFuncName("nextval"); funccallnode->args = makeList1(snamenode); funccallnode->agg_star = false; funccallnode->agg_distinct = false; constraint = makeNode(Constraint); constraint->contype = CONSTR_DEFAULT; constraint->name = sname; constraint->raw_expr = (Node *) funccallnode; constraint->cooked_expr = NULL; constraint->keys = NIL; column->constraints = lappend(column->constraints, constraint); constraint = makeNode(Constraint); constraint->contype = CONSTR_NOTNULL; column->constraints = lappend(column->constraints, constraint); } /* Process column constraints, if any... */ transformConstraintAttrs(column->constraints); saw_nullable = false; foreach(clist, column->constraints) { constraint = lfirst(clist); /* * If this column constraint is a FOREIGN KEY constraint, then we * fill in the current attribute's name and throw it into the list * of FK constraints to be processed later. */ if (IsA(constraint, FkConstraint)) { FkConstraint *fkconstraint = (FkConstraint *) constraint; fkconstraint->fk_attrs = makeList1(makeString(column->colname)); cxt->fkconstraints = lappend(cxt->fkconstraints, fkconstraint); continue; } Assert(IsA(constraint, Constraint)); switch (constraint->contype) { case CONSTR_NULL: if (saw_nullable && column->is_not_null) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"", column->colname, cxt->relation->relname))); column->is_not_null = FALSE; saw_nullable = true; break; case CONSTR_NOTNULL: if (saw_nullable && !column->is_not_null) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"", column->colname, cxt->relation->relname))); column->is_not_null = TRUE; saw_nullable = true; break; case CONSTR_DEFAULT: if (column->raw_default != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple default values specified for column \"%s\" of table \"%s\"", column->colname, cxt->relation->relname))); column->raw_default = constraint->raw_expr; Assert(constraint->cooked_expr == NULL); break; case CONSTR_PRIMARY: if (constraint->name == NULL) constraint->name = makeObjectName(cxt->relation->relname, NULL, "pkey"); if (constraint->keys == NIL) constraint->keys = makeList1(makeString(column->colname)); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break; case CONSTR_UNIQUE: if (constraint->name == NULL) constraint->name = makeObjectName(cxt->relation->relname, column->colname, "key"); if (constraint->keys == NIL) constraint->keys = makeList1(makeString(column->colname)); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break; case CONSTR_CHECK: if (constraint->name == NULL) constraint->name = makeObjectName(cxt->relation->relname, column->colname, NULL); cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); break; case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: case CONSTR_ATTR_IMMEDIATE: /* transformConstraintAttrs took care of these */ break; default: elog(ERROR, "unrecognized constraint type: %d", constraint->contype); break; } }}static voidtransformTableConstraint(ParseState *pstate, CreateStmtContext *cxt, Constraint *constraint){ switch (constraint->contype) { case CONSTR_PRIMARY: if (constraint->name == NULL) constraint->name = makeObjectName(cxt->relation->relname, NULL, "pkey"); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break; case CONSTR_UNIQUE: cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break; case CONSTR_CHECK: cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); break; case CONSTR_NULL: case CONSTR_NOTNULL: case CONSTR_DEFAULT: case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: case CONSTR_ATTR_IMMEDIATE: elog(ERROR, "invalid context for constraint type %d", constraint->contype); break; default: elog(ERROR, "unrecognized constraint type: %d", constraint->contype); break; }}/* * transformInhRelation * * Change the LIKE <subtable> portion of a CREATE TABLE statement into the * column definitions which recreate the user defined column portions of <subtable>. */static voidtransformInhRelation(ParseState *pstate, CreateStmtContext *cxt, InhRelation *inhRelation){ AttrNumber parent_attno; Relation relation; TupleDesc tupleDesc; TupleConstr *constr; AclResult aclresult; relation = heap_openrv(inhRelation->relation, AccessShareLock); if (relation->rd_rel->relkind != RELKIND_RELATION) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("inherited relation \"%s\" is not a table", inhRelation->relation->relname))); /* * Check for SELECT privilages */ aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(), ACL_SELECT); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, RelationGetRelationName(relation)); tupleDesc = RelationGetDescr(relation); constr = tupleDesc->constr; /* * Insert the inherited attributes into the cxt for the new table * definition. */ for (parent_attno = 1; parent_attno <= tupleDesc->natts; parent_attno++) { Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1]; char *attributeName = NameStr(attribute->attname); ColumnDef *def; TypeName *typename; /* * Ignore dropped columns in the parent. */ if (attribute->attisdropped) continue; /* * Create a new inherited column. * * For constraints, ONLY the NOT NULL constraint is inherited by the * new column definition per SQL99. */ def = makeNode(ColumnDef); def->colname = pstrdup(attributeName); typename = makeNode(TypeName); typename->typeid = attribute->atttypid; typename->typmod = attribute->atttypmod; def->typename = typename; def->inhcount = 0; def->is_local = false; def->is_not_null = attribute->attnotnull; def->raw_default = NULL; def->cooked_default = NULL; def->constraints = NIL; def->support = NULL; /* * Add to column list */ cxt->columns = lappend(cxt->columns, def); /* * Copy default if any, and the default has been requested */ if (attribute->atthasdef && inhRelation->including_defaults) { char *this_default = NULL; AttrDefault *attrdef; int i; /* Find default in constraint structure */ Assert(constr != NULL); attrdef = constr->defval; for (i = 0; i < constr->num_defval; i++) { if (attrdef[i].adnum == parent_attno) { this_default = attrdef[i].adbin; break; } } Assert(this_default != NULL); /* * If default expr could contain any vars, we'd need to fix * 'em, but it can't; so default is ready to apply to child. */ def->cooked_default = pstrdup(this_default); } } /* * Close the parent rel, but keep our AccessShareLock on it until xact * commit. That will prevent someone else from deleting or ALTERing * the parent before the child is committed. */ heap_close(relation, NoLock);}static voidtransformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt){ List *listptr; List *keys; IndexStmt *index; IndexElem *iparam; ColumnDef *column; List *columns; List *indexlist = NIL; /* * Run through the constraints that need to generate an index. For * PRIMARY KEY, mark each column as NOT NULL and create an index. For * UNIQUE, create an index as for PRIMARY KEY, but do not insist on * NOT NULL. */ foreach(listptr, cxt->ixconstraints) { Constraint *constraint = lfirst(listptr); Assert(IsA(constraint, Constraint)); Assert((constraint->contype == CONSTR_PRIMARY) || (constraint->contype == CONSTR_UNIQUE)); index = makeNode(IndexStmt); index->unique = true; index->primary = (constraint->contype == CONSTR_PRIMARY); if (index->primary) { /* In ALTER TABLE case, a primary index might already exist */ if (cxt->pkey != NULL || (OidIsValid(cxt->relOid) && relationHasPrimaryKey(cxt->relOid))) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("multiple primary keys for table \"%s\" are not allowed", cxt->relation->relname))); cxt->pkey = index; } index->isconstraint = true; if (constraint->name != NULL) index->idxname = pstrdup(constraint->name); else if (constraint->contype == CONSTR_PRIMARY) index->idxname = makeObjectName(cxt->relation->relname, NULL, "pkey"); else index->idxname = NULL; /* will set it later */ index->relation = cxt->relation; index->accessMethod = DEFAULT_INDEX_TYPE; index->indexParams = NIL; index->whereClause = NULL; /* * Make sure referenced keys exist. If we are making a PRIMARY * KEY index, also make sure they are NOT NULL, if possible. * (Although we could leave it to DefineIndex to mark the columns * NOT NULL, it's more efficient to get it right the first time.) */ foreach(keys, constraint->keys) { char *key = strVal(lfirst(keys)); bool found = false; column = NULL; foreach(columns, cxt->columns) { column = lfirst(columns); Assert(IsA(column, ColumnDef)); if (strcmp(column->colname, key) == 0)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?