analyze.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,222 行 · 第 1/5 页
C
2,222 行
*/ 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'). We cannot reduce the raw tree to cooked * form until after the sequence is created, but there's no need to do * so. */ qstring = quote_qualified_identifier(snamespace, sname); snamenode = makeNode(A_Const); snamenode->val.type = T_String; snamenode->val.val.str = qstring; snamenode->typename = SystemTypeName("regclass"); funccallnode = makeNode(FuncCall); funccallnode->funcname = SystemFuncName("nextval"); funccallnode->args = list_make1(snamenode); funccallnode->agg_star = false; funccallnode->agg_distinct = false; constraint = makeNode(Constraint); constraint->contype = CONSTR_DEFAULT; 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 = list_make1(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: case CONSTR_UNIQUE: if (constraint->keys == NIL) constraint->keys = list_make1(makeString(column->colname)); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break; case CONSTR_CHECK: 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: 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){ IndexStmt *index; List *indexlist = NIL; ListCell *listptr; ListCell *l; /* * 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); ListCell *keys; IndexElem *iparam; 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) { if (cxt->pkey != NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("multiple primary keys for table \"%s\" are not allowed", cxt->relation->relname))); cxt->pkey = index; /* * In ALTER TABLE case, a primary index might already exist, but * DefineIndex will check for it. */ } index->isconstraint = true; if (constraint->name != NULL) index->idxname = pstrdup(constraint->name); else index->idxname = NULL; /* DefineIndex will choose name */ index->relation = cxt->relation; index->accessMethod = DEFAULT_INDEX_TYPE; index->tableSpace = constraint->indexspace; 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; ColumnDef *column = NULL; ListCell *columns; foreach(columns, cxt->columns) { column = (ColumnDef *) lfirst(columns); Assert(IsA(column, ColumnDef)); if (strcmp(column->colname, key) == 0) { found = true; break; } } if (found) { /* found column in the new table; force it to be NOT NULL */ if (constraint->contype == CONSTR_PRIMARY) column->is_not_null = TRUE; } else if (SystemAttributeByName(key, cxt->hasoids) != NULL) { /* * column will be a system column in the new table, so accept * it. System columns can't ever be null, so no need to worry * about PRIMARY/NOT NULL constraint. */ found = true; } else if (cxt->inhRelations) { /* try inherited tables */ ListCell *inher; foreach(inher, cxt->inhRelations) { RangeVar *inh = (RangeVar *) lfirst(inher); Relation rel; int count; Assert(IsA(inh, RangeVar)); rel = heap_openrv(inh, AccessShareLock); if (rel->rd_rel->relkind != RELKIND_RELATION) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("inherited relation \"%s\" is not a table", inh->relname))); for (count = 0; count < rel->rd_att->natts; count++) { Form_pg_attribute inhattr = rel->rd_att->attrs[count]; char *inhname = NameStr(inhattr->attname); if (inhattr->attisdropped) continue; if (strcmp(key, inhname) == 0) { found = true; /* * We currently have no easy way to force an * inherited column to be NOT NULL at creation, if * its parent wasn't so already. We leave it to * DefineIndex to fix things up in this case. */ break; } } heap_close(rel, NoLock); if (found) break; } } /* * In the ALTER TABLE case, don't complain about index keys not * created in the command; they may well exist already. * DefineIndex will complain about them if not, and will also take * care of marking them NOT NULL. */ if (!found && !cxt->isalter) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" named in key does not exist", key))); /* Check for PRIMARY KEY(foo, foo) */ foreach(columns, index->indexParams) { iparam = (IndexElem *) lfirst(columns); if (iparam->name && strcmp(key, iparam->name) == 0) { if (index->primary) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column \"%s\" appears twice in primary key constraint", key))); else ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column \"%s\" appears twice in unique constraint", key)));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?