summaryrefslogtreecommitdiff
path: root/src/backend/parser/analyze.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/analyze.c')
-rw-r--r--src/backend/parser/analyze.c330
1 files changed, 329 insertions, 1 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 30bdd9c0627..63b990aa747 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -7,13 +7,14 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.51 1997/11/26 01:11:03 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.52 1997/12/04 23:07:18 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
#include "postgres.h"
@@ -39,7 +40,9 @@ static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
static Query *transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt);
static Query *transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt);
static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
+static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
+List *extras = NIL;
/*
* parse_analyze -
@@ -65,6 +68,17 @@ parse_analyze(List *pl)
{
pstate = make_parsestate();
result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
+ if (extras != NIL)
+ {
+ result->len += length(extras);
+ result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
+ while (extras != NIL)
+ {
+ result->qtrees[i++] = transformStmt(pstate, lfirst(extras));
+ extras = lnext(extras);
+ }
+ }
+ extras = NIL;
pl = lnext(pl);
if (pstate->p_target_relation != NULL)
heap_close(pstate->p_target_relation);
@@ -90,6 +104,10 @@ transformStmt(ParseState *pstate, Node *parseTree)
* Non-optimizable statements
*------------------------
*/
+ case T_CreateStmt:
+ result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
+ break;
+
case T_IndexStmt:
result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
break;
@@ -309,6 +327,316 @@ transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
return (Query *) qry;
}
+/* makeTableName()
+ * Create a table name from a list of fields.
+ */
+static char *
+makeTableName(void *elem,...);
+
+static char *
+makeTableName(void *elem,...)
+{
+ va_list args;
+
+ char *name;
+ char buf[NAMEDATALEN+1];
+
+ strcpy(buf,"");
+
+ va_start(args,elem);
+
+ name = elem;
+ while (name != NULL)
+ {
+ /* not enough room for next part? then return nothing */
+ if ((strlen(buf)+strlen(name)) >= (sizeof(buf)-1))
+ return (NULL);
+
+ if (strlen(buf) > 0) strcat(buf,"_");
+ strcat(buf,name);
+
+ name = va_arg(args,void *);
+ }
+
+ va_end(args);
+
+ name = palloc(strlen(buf)+1);
+ strcpy(name,buf);
+
+ return (name);
+} /* makeTableName() */
+
+/*
+ * 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 *ilist;
+ IndexStmt *index;
+ IndexElem *iparam;
+
+ q = makeNode(Query);
+ q->commandType = CMD_UTILITY;
+
+ elements = stmt->tableElts;
+ constraints = stmt->constraints;
+ columns = NIL;
+ dlist = NIL;
+
+ while (elements != NIL)
+ {
+ element = lfirst(elements);
+ switch (nodeTag(element))
+ {
+ case T_ColumnDef:
+ column = (ColumnDef *) element;
+#if PARSEDEBUG
+printf("transformCreateStmt- found column %s\n",column->colname);
+#endif
+ columns = lappend(columns,column);
+ if (column->constraints != NIL)
+ {
+#if PARSEDEBUG
+printf("transformCreateStmt- found constraint(s) on column %s\n",column->colname);
+#endif
+ clist = column->constraints;
+ while (clist != NIL)
+ {
+ constraint = lfirst(clist);
+ switch (constraint->contype)
+ {
+ case CONSTR_NOTNULL:
+#if PARSEDEBUG
+printf("transformCreateStmt- found NOT NULL constraint on column %s\n",column->colname);
+#endif
+ if (column->is_not_null)
+ elog(WARN,"CREATE TABLE/NOT NULL already specified"
+ " for %s.%s", stmt->relname, column->colname);
+ column->is_not_null = TRUE;
+ break;
+
+ case CONSTR_DEFAULT:
+#if PARSEDEBUG
+printf("transformCreateStmt- found DEFAULT clause on column %s\n",column->colname);
+#endif
+ if (column->defval != NULL)
+ elog(WARN,"CREATE TABLE/DEFAULT multiple values specified"
+ " for %s.%s", stmt->relname, column->colname);
+ column->defval = constraint->def;
+ break;
+
+ case CONSTR_PRIMARY:
+#if PARSEDEBUG
+printf("transformCreateStmt- found PRIMARY KEY clause on column %s\n",column->colname);
+#endif
+ if (constraint->name == NULL)
+ constraint->name = makeTableName(stmt->relname, "pkey", NULL);
+ if (constraint->keys == NIL)
+ constraint->keys = lappend(constraint->keys, column);
+ dlist = lappend(dlist, constraint);
+ break;
+
+ case CONSTR_UNIQUE:
+#if PARSEDEBUG
+printf("transformCreateStmt- found UNIQUE clause on column %s\n",column->colname);
+#endif
+ if (constraint->name == NULL)
+ constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
+ if (constraint->keys == NIL)
+ constraint->keys = lappend(constraint->keys, column);
+ dlist = lappend(dlist, constraint);
+ break;
+
+ case CONSTR_CHECK:
+#if PARSEDEBUG
+printf("transformCreateStmt- found CHECK clause on column %s\n",column->colname);
+#endif
+ constraints = lappend(constraints, constraint);
+ if (constraint->name == NULL)
+ constraint->name = makeTableName(stmt->relname, ".", column->colname, NULL);
+ break;
+
+ default:
+ elog(WARN,"parser: internal error; unrecognized constraint",NULL);
+ break;
+ }
+ clist = lnext(clist);
+ }
+ }
+ break;
+
+ case T_Constraint:
+ constraint = (Constraint *) element;
+#if PARSEDEBUG
+printf("transformCreateStmt- found constraint %s\n", ((constraint->name != NULL)? constraint->name: "(unknown)"));
+#endif
+ switch (constraint->contype)
+ {
+ case CONSTR_PRIMARY:
+#if PARSEDEBUG
+printf("transformCreateStmt- found PRIMARY KEY clause\n");
+#endif
+ if (constraint->name == NULL)
+ constraint->name = makeTableName(stmt->relname, "pkey", NULL);
+ dlist = lappend(dlist, constraint);
+ break;
+
+ case CONSTR_UNIQUE:
+#if PARSEDEBUG
+printf("transformCreateStmt- found UNIQUE clause\n");
+#endif
+#if FALSE
+ if (constraint->name == NULL)
+ constraint->name = makeTableName(stmt->relname, "key", NULL);
+#endif
+ dlist = lappend(dlist, constraint);
+ break;
+
+ case CONSTR_CHECK:
+#if PARSEDEBUG
+printf("transformCreateStmt- found CHECK clause\n");
+#endif
+ constraints = lappend(constraints, constraint);
+ break;
+
+ case CONSTR_NOTNULL:
+ case CONSTR_DEFAULT:
+ elog(WARN,"parser: internal error; illegal context for constraint",NULL);
+ break;
+ default:
+ elog(WARN,"parser: internal error; unrecognized constraint",NULL);
+ break;
+ }
+ break;
+
+ default:
+ elog(WARN,"parser: internal error; unrecognized node",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 will fail later when
+ * names for indices turn out to be redundant, or a user might just find
+ * extra useless indices which might kill performance. - thomas 1997-12-04
+ */
+ ilist = NIL;
+ while (dlist != NIL)
+ {
+ constraint = lfirst(dlist);
+ if (nodeTag(constraint) != T_Constraint)
+ elog(WARN,"parser: internal error; unrecognized deferred node",NULL);
+
+ if ((constraint->contype != CONSTR_PRIMARY)
+ && (constraint->contype != CONSTR_UNIQUE))
+ elog(WARN,"parser: internal error; illegal deferred constraint",NULL);
+
+#if PARSEDEBUG
+printf("transformCreateStmt- found deferred constraint %s\n",
+ ((constraint->name != NULL)? constraint->name: "(unknown)"));
+#endif
+
+#if PARSEDEBUG
+printf("transformCreateStmt- found deferred %s clause\n",
+ (constraint->contype == CONSTR_PRIMARY? "PRIMARY KEY": "UNIQUE"));
+#endif
+ index = makeNode(IndexStmt);
+ ilist = lappend(ilist, index);
+
+ index->unique = TRUE;
+ if (constraint->name != NULL)
+ index->idxname = constraint->name;
+ else if (constraint->contype == CONSTR_PRIMARY)
+ index->idxname = makeTableName(stmt->relname, "pkey", NULL);
+ 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);
+#if PARSEDEBUG
+printf("transformCreateStmt- check key %s for column match\n", key->name);
+#endif
+ columns = stmt->tableElts;
+ column = NULL;
+ while (columns != NIL)
+ {
+ column = lfirst(columns);
+#if PARSEDEBUG
+printf("transformCreateStmt- check column %s for key match\n", column->colname);
+#endif
+ if (strcasecmp(column->colname,key->name) == 0) break;
+ else column = NULL;
+ columns = lnext(columns);
+ }
+ if (column == NULL)
+ elog(WARN,"parser: column '%s' in key does not exist",key->name);
+
+ if (constraint->contype == CONSTR_PRIMARY)
+ {
+#if PARSEDEBUG
+printf("transformCreateStmt- mark column %s as NOT NULL\n", column->colname);
+#endif
+ column->is_not_null = TRUE;
+ }
+ iparam = makeNode(IndexElem);
+ iparam->name = strcpy(palloc(strlen(column->colname)+1), column->colname);
+ iparam->args = NIL;
+ iparam->class = NULL;
+ iparam->tname = NULL;
+ index->indexParams = lappend(index->indexParams, iparam);
+
+ if (index->idxname == NULL)
+ index->idxname = makeTableName(stmt->relname, iparam->name, "key", NULL);
+
+ keys = lnext(keys);
+ }
+
+ if (index->idxname == NULL)
+ elog(WARN,"parser: unable to construct implicit index for table %s"
+ "; name too long", stmt->relname);
+
+ dlist = lnext(dlist);
+ }
+
+ q->utilityStmt = (Node *) stmt;
+ extras = ilist;
+
+ return q;
+} /* transformCreateStmt() */
+
/*
* transformIndexStmt -
* transforms the qualification of the index statement