7
7
*
8
8
*
9
9
* 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 $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
14
14
15
15
#include <stdio.h>
16
16
#include <stdlib.h>
17
+ #include <stdarg.h>
17
18
#include <string.h>
18
19
19
20
#include "postgres.h"
@@ -39,7 +40,9 @@ static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
39
40
static Query * transformSelectStmt (ParseState * pstate , RetrieveStmt * stmt );
40
41
static Query * transformUpdateStmt (ParseState * pstate , ReplaceStmt * stmt );
41
42
static Query * transformCursorStmt (ParseState * pstate , CursorStmt * stmt );
43
+ static Query * transformCreateStmt (ParseState * pstate , CreateStmt * stmt );
42
44
45
+ List * extras = NIL ;
43
46
44
47
/*
45
48
* parse_analyze -
@@ -65,6 +68,17 @@ parse_analyze(List *pl)
65
68
{
66
69
pstate = make_parsestate ();
67
70
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 ;
68
82
pl = lnext (pl );
69
83
if (pstate -> p_target_relation != NULL )
70
84
heap_close (pstate -> p_target_relation );
@@ -90,6 +104,10 @@ transformStmt(ParseState *pstate, Node *parseTree)
90
104
* Non-optimizable statements
91
105
*------------------------
92
106
*/
107
+ case T_CreateStmt :
108
+ result = transformCreateStmt (pstate , (CreateStmt * ) parseTree );
109
+ break ;
110
+
93
111
case T_IndexStmt :
94
112
result = transformIndexStmt (pstate , (IndexStmt * ) parseTree );
95
113
break ;
@@ -309,6 +327,316 @@ transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
309
327
return (Query * ) qry ;
310
328
}
311
329
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
+
312
640
/*
313
641
* transformIndexStmt -
314
642
* transforms the qualification of the index statement
0 commit comments