📄 analyze.c
字号:
* so that the generated names are easily predictable by a person. */static char *makeObjectName(char *name1, char *name2, char *typename){ char *name; int overhead = 0; /* chars needed for type and underscores */ int availchars; /* chars available for name(s) */ int name1chars; /* chars allocated to name1 */ int name2chars; /* chars allocated to name2 */ int ndx; name1chars = strlen(name1); if (name2) { name2chars = strlen(name2); overhead++; /* allow for separating underscore */ } else name2chars = 0; if (typename) overhead += strlen(typename) + 1; availchars = NAMEDATALEN-1 - overhead; /* If we must truncate, preferentially truncate the longer name. * This logic could be expressed without a loop, but it's simple and * obvious as a loop. */ while (name1chars + name2chars > availchars) { if (name1chars > name2chars) name1chars--; else name2chars--; } /* Now construct the string using the chosen lengths */ name = palloc(name1chars + name2chars + overhead + 1); strncpy(name, name1, name1chars); ndx = name1chars; if (name2) { name[ndx++] = '_'; strncpy(name+ndx, name2, name2chars); ndx += name2chars; } if (typename) { name[ndx++] = '_'; strcpy(name+ndx, typename); } else name[ndx] = '\0'; return name;}static char *CreateIndexName(char *table_name, char *column_name, char *label, List *indices){ int pass = 0; char *iname = NULL; List *ilist; char typename[NAMEDATALEN]; /* The type name for makeObjectName is label, or labelN if that's * necessary to prevent collisions among multiple indexes for the same * table. Note there is no check for collisions with already-existing * indexes; this ought to be rethought someday. */ strcpy(typename, label); for (;;) { iname = makeObjectName(table_name, column_name, typename); foreach(ilist, indices) { IndexStmt *index = lfirst(ilist); if (strcasecmp(iname, index->idxname) == 0) break; } /* ran through entire list? then no name conflict found so done */ if (ilist == NIL) break; /* the last one conflicted, so try a new name component */ pfree(iname); sprintf(typename, "%s%d", label, ++pass); } return iname;}/* * transformCreateStmt - * transforms the "create table" statement * SQL92 allows constraints to be scattered all over, so thumb through * the columns and collect all constraints into one place. * If there are any implied indices (e.g. UNIQUE or PRIMARY KEY) * then expand those into multiple IndexStmt blocks. * - thomas 1997-12-02 */static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt){ Query *q; List *elements; Node *element; List *columns; List *dlist; ColumnDef *column; List *constraints, *clist; Constraint *constraint; List *keys; Ident *key; List *blist = NIL; /* "before list" of things to do before * creating the table */ List *ilist = NIL; /* "index list" of things to do after * creating the table */ IndexStmt *index, *pkey = NULL; IndexElem *iparam; q = makeNode(Query); q->commandType = CMD_UTILITY; elements = stmt->tableElts; constraints = stmt->constraints; columns = NIL; dlist = NIL; /* * Run through each primary element in the table creation clause */ while (elements != NIL) { element = lfirst(elements); switch (nodeTag(element)) { case T_ColumnDef: column = (ColumnDef *) element; columns = lappend(columns, column); /* Special case SERIAL type? */ if (column->is_sequence) { char *sname; char *cstring; CreateSeqStmt *sequence; sname = makeObjectName(stmt->relname, column->colname, "seq"); constraint = makeNode(Constraint); constraint->contype = CONSTR_DEFAULT; constraint->name = sname; cstring = palloc(10 + strlen(constraint->name) + 3 + 1); strcpy(cstring, "nextval('\""); strcat(cstring, constraint->name); strcat(cstring, "\"')"); constraint->def = cstring; constraint->keys = NULL; column->constraints = lappend(column->constraints, constraint); constraint = makeNode(Constraint); constraint->contype = CONSTR_UNIQUE; constraint->name = makeObjectName(stmt->relname, column->colname, "key"); column->constraints = lappend(column->constraints, constraint); sequence = makeNode(CreateSeqStmt); sequence->seqname = pstrdup(sname); sequence->options = NIL; elog(NOTICE, "CREATE TABLE will create implicit sequence '%s' for SERIAL column '%s.%s'", sequence->seqname, stmt->relname, column->colname); blist = lcons(sequence, NIL); } /* Check for column constraints, if any... */ if (column->constraints != NIL) { clist = column->constraints; while (clist != NIL) { constraint = lfirst(clist); switch (constraint->contype) { case CONSTR_NULL: /* * We should mark this explicitly, so we * can tell if NULL and NOT NULL are both * specified */ if (column->is_not_null) elog(ERROR, "CREATE TABLE/(NOT) NULL conflicting declaration" " for '%s.%s'", stmt->relname, column->colname); column->is_not_null = FALSE; break; case CONSTR_NOTNULL: if (column->is_not_null) elog(ERROR, "CREATE TABLE/NOT NULL already specified" " for '%s.%s'", stmt->relname, column->colname); column->is_not_null = TRUE; break; case CONSTR_DEFAULT: if (column->defval != NULL) elog(ERROR, "CREATE TABLE/DEFAULT multiple values specified" " for '%s.%s'", stmt->relname, column->colname); column->defval = constraint->def; break; case CONSTR_PRIMARY: if (constraint->name == NULL) constraint->name = makeObjectName(stmt->relname, NULL, "pkey"); if (constraint->keys == NIL) constraint->keys = lappend(constraint->keys, column); dlist = lappend(dlist, constraint); break; case CONSTR_UNIQUE: if (constraint->name == NULL) constraint->name = makeObjectName(stmt->relname, column->colname, "key"); if (constraint->keys == NIL) constraint->keys = lappend(constraint->keys, column); dlist = lappend(dlist, constraint); break; case CONSTR_CHECK: constraints = lappend(constraints, constraint); if (constraint->name == NULL) constraint->name = makeObjectName(stmt->relname, column->colname, NULL); break; default: elog(ERROR, "parser: unrecognized constraint (internal error)", NULL); break; } clist = lnext(clist); } } break; case T_Constraint: constraint = (Constraint *) element; switch (constraint->contype) { case CONSTR_PRIMARY: if (constraint->name == NULL) constraint->name = makeObjectName(stmt->relname, NULL, "pkey"); dlist = lappend(dlist, constraint); break; case CONSTR_UNIQUE: dlist = lappend(dlist, constraint); break; case CONSTR_CHECK: constraints = lappend(constraints, constraint); break; case CONSTR_NOTNULL: case CONSTR_DEFAULT: elog(ERROR, "parser: illegal context for constraint (internal error)", NULL); break; default: elog(ERROR, "parser: unrecognized constraint (internal error)", NULL); break; } break; default: elog(ERROR, "parser: unrecognized node (internal error)", NULL); } elements = lnext(elements); } stmt->tableElts = columns; stmt->constraints = constraints;/* Now run through the "deferred list" to complete the query transformation. * For PRIMARY KEYs, mark each column as NOT NULL and create an index. * For UNIQUE, create an index as for PRIMARY KEYS, but do not insist on NOT NULL. * * Note that this code does not currently look for all possible redundant cases * and either ignore or stop with warning. The create might fail later when * names for indices turn out to be duplicated, or a user might have specified * extra useless indices which might hurt performance. - thomas 1997-12-08 */ while (dlist != NIL) { constraint = lfirst(dlist); Assert(nodeTag(constraint) == T_Constraint); Assert((constraint->contype == CONSTR_PRIMARY) || (constraint->contype == CONSTR_UNIQUE)); index = makeNode(IndexStmt); index->unique = TRUE; index->primary = (constraint->contype == CONSTR_PRIMARY ? TRUE : FALSE); if (index->primary) { if (pkey != NULL) elog(ERROR, "CREATE TABLE/PRIMARY KEY multiple primary keys" " for table '%s' are not allowed", stmt->relname); pkey = (IndexStmt *) index; } if (constraint->name != NULL) index->idxname = pstrdup(constraint->name); else if (constraint->contype == CONSTR_PRIMARY) index->idxname = makeObjectName(stmt->relname, NULL, "pkey"); else index->idxname = NULL; index->relname = stmt->relname; index->accessMethod = "btree"; index->indexParams = NIL; index->withClause = NIL; index->whereClause = NULL; keys = constraint->keys; while (keys != NIL) { key = lfirst(keys); columns = stmt->tableElts; column = NULL; while (columns != NIL) { column = lfirst(columns); if (strcasecmp(column->colname, key->name) == 0) break; else column = NULL; columns = lnext(columns); } if (column == NULL) elog(ERROR, "CREATE TABLE column '%s' in key does not exist", key->name); if (constraint->contype == CONSTR_PRIMARY) column->is_not_null = TRUE; iparam = makeNode(IndexElem); iparam->name = pstrdup(column->colname); iparam->args = NIL; iparam->class = NULL; iparam->typename = NULL; index->indexParams = lappend(index->indexParams, iparam); if (index->idxname == NULL) index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist); keys = lnext(keys); } if (index->idxname == NULL) /* should not happen */ elog(ERROR, "CREATE TABLE: failed to make implicit index name"); ilist = lappend(ilist, index); dlist = lnext(dlist); }/* OK, now finally, if there is a primary key, then make sure that there aren't any redundant * unique indices defined on columns. This can arise if someone specifies UNIQUE explicitly * or if a SERIAL column was defined along with a table PRIMARY KEY constraint. * - thomas 1999-05-11 */ if (pkey != NULL) { dlist = ilist; ilist = NIL; while (dlist != NIL) { List *pcols, *icols; int plen, ilen; int keep = TRUE; index = lfirst(dlist); pcols = pkey->indexParams; icols = index->indexParams; plen = length(pcols); ilen = length(icols); /* Not the same as the primary key? Then we should look... */ if ((index != pkey) && (ilen == plen)) { keep = FALSE; while ((pcols != NIL) && (icols != NIL)) { IndexElem *pcol = lfirst(pcols); IndexElem *icol = lfirst(icols); char *pname = pcol->name; char *iname = icol->name; /* different names? then no match... */ if (strcmp(iname, pname) != 0) { keep = TRUE; break; } pcols = lnext(pcols); icols = lnext(icols); } } if (keep) ilist = lappend(ilist, index); dlist = lnext(dlist); } } dlist = ilist; while (dlist != NIL) { index = lfirst(dlist); elog(NOTICE, "CREATE TABLE/%s will create implicit index '%s' for table '%s'", (index->primary ? "PRIMARY KEY" : "UNIQUE"), index->idxname, stmt->relname); dlist = lnext(dlist); } q->utilityStmt = (Node *) stmt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -