Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1ac4ae4

Browse files
author
Thomas G. Lockhart
committed
Add SQL92-compliant syntax for constraints.
Implement PRIMARY KEY and UNIQUE clauses using indices.
1 parent 7b06d99 commit 1ac4ae4

File tree

2 files changed

+601
-209
lines changed

2 files changed

+601
-209
lines changed

src/backend/parser/analyze.c

+329-1
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.51 1997/11/26 01:11:03 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.52 1997/12/04 23:07:18 thomas Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
1414

1515
#include <stdio.h>
1616
#include <stdlib.h>
17+
#include <stdarg.h>
1718
#include <string.h>
1819

1920
#include "postgres.h"
@@ -39,7 +40,9 @@ static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
3940
static Query *transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt);
4041
static Query *transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt);
4142
static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
43+
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
4244

45+
List *extras = NIL;
4346

4447
/*
4548
* parse_analyze -
@@ -65,6 +68,17 @@ parse_analyze(List *pl)
6568
{
6669
pstate = make_parsestate();
6770
result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
71+
if (extras != NIL)
72+
{
73+
result->len += length(extras);
74+
result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
75+
while (extras != NIL)
76+
{
77+
result->qtrees[i++] = transformStmt(pstate, lfirst(extras));
78+
extras = lnext(extras);
79+
}
80+
}
81+
extras = NIL;
6882
pl = lnext(pl);
6983
if (pstate->p_target_relation != NULL)
7084
heap_close(pstate->p_target_relation);
@@ -90,6 +104,10 @@ transformStmt(ParseState *pstate, Node *parseTree)
90104
* Non-optimizable statements
91105
*------------------------
92106
*/
107+
case T_CreateStmt:
108+
result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
109+
break;
110+
93111
case T_IndexStmt:
94112
result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
95113
break;
@@ -309,6 +327,316 @@ transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
309327
return (Query *) qry;
310328
}
311329

330+
/* makeTableName()
331+
* Create a table name from a list of fields.
332+
*/
333+
static char *
334+
makeTableName(void *elem,...);
335+
336+
static char *
337+
makeTableName(void *elem,...)
338+
{
339+
va_list args;
340+
341+
char *name;
342+
char buf[NAMEDATALEN+1];
343+
344+
strcpy(buf,"");
345+
346+
va_start(args,elem);
347+
348+
name = elem;
349+
while (name != NULL)
350+
{
351+
/* not enough room for next part? then return nothing */
352+
if ((strlen(buf)+strlen(name)) >= (sizeof(buf)-1))
353+
return (NULL);
354+
355+
if (strlen(buf) > 0) strcat(buf,"_");
356+
strcat(buf,name);
357+
358+
name = va_arg(args,void *);
359+
}
360+
361+
va_end(args);
362+
363+
name = palloc(strlen(buf)+1);
364+
strcpy(name,buf);
365+
366+
return (name);
367+
} /* makeTableName() */
368+
369+
/*
370+
* transformCreateStmt -
371+
* transforms the "create table" statement
372+
* SQL92 allows constraints to be scattered all over, so thumb through
373+
* the columns and collect all constraints into one place.
374+
* If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
375+
* then expand those into multiple IndexStmt blocks.
376+
* - thomas 1997-12-02
377+
*/
378+
static Query *
379+
transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
380+
{
381+
Query *q;
382+
List *elements;
383+
Node *element;
384+
List *columns;
385+
List *dlist;
386+
ColumnDef *column;
387+
List *constraints, *clist;
388+
Constraint *constraint;
389+
List *keys;
390+
Ident *key;
391+
List *ilist;
392+
IndexStmt *index;
393+
IndexElem *iparam;
394+
395+
q = makeNode(Query);
396+
q->commandType = CMD_UTILITY;
397+
398+
elements = stmt->tableElts;
399+
constraints = stmt->constraints;
400+
columns = NIL;
401+
dlist = NIL;
402+
403+
while (elements != NIL)
404+
{
405+
element = lfirst(elements);
406+
switch (nodeTag(element))
407+
{
408+
case T_ColumnDef:
409+
column = (ColumnDef *) element;
410+
#if PARSEDEBUG
411+
printf("transformCreateStmt- found column %s\n",column->colname);
412+
#endif
413+
columns = lappend(columns,column);
414+
if (column->constraints != NIL)
415+
{
416+
#if PARSEDEBUG
417+
printf("transformCreateStmt- found constraint(s) on column %s\n",column->colname);
418+
#endif
419+
clist = column->constraints;
420+
while (clist != NIL)
421+
{
422+
constraint = lfirst(clist);
423+
switch (constraint->contype)
424+
{
425+
case CONSTR_NOTNULL:
426+
#if PARSEDEBUG
427+
printf("transformCreateStmt- found NOT NULL constraint on column %s\n",column->colname);
428+
#endif
429+
if (column->is_not_null)
430+
elog(WARN,"CREATE TABLE/NOT NULL already specified"
431+
" for %s.%s", stmt->relname, column->colname);
432+
column->is_not_null = TRUE;
433+
break;
434+
435+
case CONSTR_DEFAULT:
436+
#if PARSEDEBUG
437+
printf("transformCreateStmt- found DEFAULT clause on column %s\n",column->colname);
438+
#endif
439+
if (column->defval != NULL)
440+
elog(WARN,"CREATE TABLE/DEFAULT multiple values specified"
441+
" for %s.%s", stmt->relname, column->colname);
442+
column->defval = constraint->def;
443+
break;
444+
445+
case CONSTR_PRIMARY:
446+
#if PARSEDEBUG
447+
printf("transformCreateStmt- found PRIMARY KEY clause on column %s\n",column->colname);
448+
#endif
449+
if (constraint->name == NULL)
450+
constraint->name = makeTableName(stmt->relname, "pkey", NULL);
451+
if (constraint->keys == NIL)
452+
constraint->keys = lappend(constraint->keys, column);
453+
dlist = lappend(dlist, constraint);
454+
break;
455+
456+
case CONSTR_UNIQUE:
457+
#if PARSEDEBUG
458+
printf("transformCreateStmt- found UNIQUE clause on column %s\n",column->colname);
459+
#endif
460+
if (constraint->name == NULL)
461+
constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
462+
if (constraint->keys == NIL)
463+
constraint->keys = lappend(constraint->keys, column);
464+
dlist = lappend(dlist, constraint);
465+
break;
466+
467+
case CONSTR_CHECK:
468+
#if PARSEDEBUG
469+
printf("transformCreateStmt- found CHECK clause on column %s\n",column->colname);
470+
#endif
471+
constraints = lappend(constraints, constraint);
472+
if (constraint->name == NULL)
473+
constraint->name = makeTableName(stmt->relname, ".", column->colname, NULL);
474+
break;
475+
476+
default:
477+
elog(WARN,"parser: internal error; unrecognized constraint",NULL);
478+
break;
479+
}
480+
clist = lnext(clist);
481+
}
482+
}
483+
break;
484+
485+
case T_Constraint:
486+
constraint = (Constraint *) element;
487+
#if PARSEDEBUG
488+
printf("transformCreateStmt- found constraint %s\n", ((constraint->name != NULL)? constraint->name: "(unknown)"));
489+
#endif
490+
switch (constraint->contype)
491+
{
492+
case CONSTR_PRIMARY:
493+
#if PARSEDEBUG
494+
printf("transformCreateStmt- found PRIMARY KEY clause\n");
495+
#endif
496+
if (constraint->name == NULL)
497+
constraint->name = makeTableName(stmt->relname, "pkey", NULL);
498+
dlist = lappend(dlist, constraint);
499+
break;
500+
501+
case CONSTR_UNIQUE:
502+
#if PARSEDEBUG
503+
printf("transformCreateStmt- found UNIQUE clause\n");
504+
#endif
505+
#if FALSE
506+
if (constraint->name == NULL)
507+
constraint->name = makeTableName(stmt->relname, "key", NULL);
508+
#endif
509+
dlist = lappend(dlist, constraint);
510+
break;
511+
512+
case CONSTR_CHECK:
513+
#if PARSEDEBUG
514+
printf("transformCreateStmt- found CHECK clause\n");
515+
#endif
516+
constraints = lappend(constraints, constraint);
517+
break;
518+
519+
case CONSTR_NOTNULL:
520+
case CONSTR_DEFAULT:
521+
elog(WARN,"parser: internal error; illegal context for constraint",NULL);
522+
break;
523+
default:
524+
elog(WARN,"parser: internal error; unrecognized constraint",NULL);
525+
break;
526+
}
527+
break;
528+
529+
default:
530+
elog(WARN,"parser: internal error; unrecognized node",NULL);
531+
}
532+
533+
elements = lnext(elements);
534+
}
535+
536+
stmt->tableElts = columns;
537+
stmt->constraints = constraints;
538+
539+
/* Now run through the "deferred list" to complete the query transformation.
540+
* For PRIMARY KEYs, mark each column as NOT NULL and create an index.
541+
* For UNIQUE, create an index as for PRIMARY KEYS, but do not insist on NOT NULL.
542+
*
543+
* Note that this code does not currently look for all possible redundant cases
544+
* and either ignore or stop with warning. The create will fail later when
545+
* names for indices turn out to be redundant, or a user might just find
546+
* extra useless indices which might kill performance. - thomas 1997-12-04
547+
*/
548+
ilist = NIL;
549+
while (dlist != NIL)
550+
{
551+
constraint = lfirst(dlist);
552+
if (nodeTag(constraint) != T_Constraint)
553+
elog(WARN,"parser: internal error; unrecognized deferred node",NULL);
554+
555+
if ((constraint->contype != CONSTR_PRIMARY)
556+
&& (constraint->contype != CONSTR_UNIQUE))
557+
elog(WARN,"parser: internal error; illegal deferred constraint",NULL);
558+
559+
#if PARSEDEBUG
560+
printf("transformCreateStmt- found deferred constraint %s\n",
561+
((constraint->name != NULL)? constraint->name: "(unknown)"));
562+
#endif
563+
564+
#if PARSEDEBUG
565+
printf("transformCreateStmt- found deferred %s clause\n",
566+
(constraint->contype == CONSTR_PRIMARY? "PRIMARY KEY": "UNIQUE"));
567+
#endif
568+
index = makeNode(IndexStmt);
569+
ilist = lappend(ilist, index);
570+
571+
index->unique = TRUE;
572+
if (constraint->name != NULL)
573+
index->idxname = constraint->name;
574+
else if (constraint->contype == CONSTR_PRIMARY)
575+
index->idxname = makeTableName(stmt->relname, "pkey", NULL);
576+
else
577+
index->idxname = NULL;
578+
579+
index->relname = stmt->relname;
580+
index->accessMethod = "btree";
581+
index->indexParams = NIL;
582+
index->withClause = NIL;
583+
index->whereClause = NULL;
584+
585+
keys = constraint->keys;
586+
while (keys != NIL)
587+
{
588+
key = lfirst(keys);
589+
#if PARSEDEBUG
590+
printf("transformCreateStmt- check key %s for column match\n", key->name);
591+
#endif
592+
columns = stmt->tableElts;
593+
column = NULL;
594+
while (columns != NIL)
595+
{
596+
column = lfirst(columns);
597+
#if PARSEDEBUG
598+
printf("transformCreateStmt- check column %s for key match\n", column->colname);
599+
#endif
600+
if (strcasecmp(column->colname,key->name) == 0) break;
601+
else column = NULL;
602+
columns = lnext(columns);
603+
}
604+
if (column == NULL)
605+
elog(WARN,"parser: column '%s' in key does not exist",key->name);
606+
607+
if (constraint->contype == CONSTR_PRIMARY)
608+
{
609+
#if PARSEDEBUG
610+
printf("transformCreateStmt- mark column %s as NOT NULL\n", column->colname);
611+
#endif
612+
column->is_not_null = TRUE;
613+
}
614+
iparam = makeNode(IndexElem);
615+
iparam->name = strcpy(palloc(strlen(column->colname)+1), column->colname);
616+
iparam->args = NIL;
617+
iparam->class = NULL;
618+
iparam->tname = NULL;
619+
index->indexParams = lappend(index->indexParams, iparam);
620+
621+
if (index->idxname == NULL)
622+
index->idxname = makeTableName(stmt->relname, iparam->name, "key", NULL);
623+
624+
keys = lnext(keys);
625+
}
626+
627+
if (index->idxname == NULL)
628+
elog(WARN,"parser: unable to construct implicit index for table %s"
629+
"; name too long", stmt->relname);
630+
631+
dlist = lnext(dlist);
632+
}
633+
634+
q->utilityStmt = (Node *) stmt;
635+
extras = ilist;
636+
637+
return q;
638+
} /* transformCreateStmt() */
639+
312640
/*
313641
* transformIndexStmt -
314642
* transforms the qualification of the index statement

0 commit comments

Comments
 (0)