1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 
27 #include <vdb/extern.h>
28 
29 #include "schema-priv.h"
30 #include "schema-parse.h"
31 #include "schema-expr.h"
32 #include "schema-dump.h"
33 #include "dbmgr-priv.h"
34 
35 #include <klib/symbol.h>
36 #include <klib/log.h>
37 #include <klib/debug.h>
38 #include <klib/rc.h>
39 #include <klib/namelist.h>
40 #include <sysalloc.h>
41 
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <assert.h>
46 
47 
48 /* if non-zero, accept a typeset or a typedecl
49    for column. otherwise, only allow a typedecl */
50 #define ALLOW_COLUMN_TYPESET 1
51 
52 /* make implicit physical expressions explicit on output */
53 #define DUMP_EXPLICIT_PHYS_MEMBERS 0
54 
55 /* temporary v1 schema modification */
56 #define ALLOW_DEFAULT_VIEW_DECL 1
57 
58 
59 /*--------------------------------------------------------------------------
60  * SColumn
61  *  column declaration
62  */
63 
64 #if SLVL >= 8
65 
66 /* Whack
67  */
SColumnWhack(void * item,void * ignore)68 void CC SColumnWhack ( void *item, void *ignore )
69 {
70     SColumn *self = item;
71     SExpressionWhack ( self -> read );
72     SExpressionWhack ( self -> validate );
73     SExpressionWhack ( self -> limit );
74     SExpressionWhack ( self -> ptype );
75     free ( self );
76 }
77 
78 /* Cmp
79  * Sort
80  */
SColumnCmp(const void * item,const void * n)81 int64_t CC SColumnCmp ( const void *item, const void *n )
82 {
83     const VTypedecl *a = item;
84     const SColumn *b = n;
85 
86     if ( a -> type_id != b -> td . type_id )
87         return ( int64_t ) a -> type_id - ( int64_t ) b -> td . type_id;
88     return ( int64_t ) a -> dim - ( int64_t ) b -> td . dim;
89 }
90 
SColumnSort(const void * item,const void * n)91 int64_t CC SColumnSort ( const void *item, const void *n )
92 {
93     const SColumn *a = item;
94     const SColumn *b = n;
95 
96     if ( a -> td . type_id != b -> td . type_id )
97         return ( int64_t ) a -> td . type_id - ( int64_t ) b -> td . type_id;
98     return ( int64_t ) a -> td . dim - ( int64_t ) b -> td . dim;
99 }
100 
101 /* Mark
102  */
103 static
SColumnMark(void * item,void * data)104 void CC SColumnMark ( void * item, void * data )
105 {
106     const SColumn *self = item;
107     VSchema * schema = data;
108     if ( self != NULL )
109     {
110         SExpressionMark ( ( void * )self -> read, data );
111         SExpressionMark ( ( void * )self -> validate, data );
112         SExpressionMark ( ( void * )self -> limit, data );
113         VSchemaTypeMark ( schema, self -> td . type_id );
114     }
115 }
116 
117 /* Dump
118  */
SColumnDump(const SColumn * self,SDumper * d)119 rc_t SColumnDump ( const SColumn *self, SDumper *d )
120 {
121     return KSymbolDump ( self != NULL ? self -> name : NULL, d );
122 }
123 
124 static
SColumnDumpExpr(SDumper * d,const SExpression * e)125 rc_t SColumnDumpExpr ( SDumper *d, const SExpression *e )
126 {
127     rc_t rc;
128     const SBinExpr *c;
129     bool compact = SDumperMode ( d ) == sdmCompact ? true : false;
130 
131     if ( e -> var != eCondExpr )
132         return SDumperPrint ( d, compact ? "=%E;" : " = %E;\n", e );
133 
134     c = ( const SBinExpr* ) e;
135 
136     if ( ! compact )
137         SDumperIncIndentLevel ( d );
138 
139     rc = SDumperPrint ( d, compact ? "=%E" : "\n\t= %E", c -> left );
140     while ( rc == 0 )
141     {
142         if ( c -> right -> var != eCondExpr )
143             break;
144         c = ( const SBinExpr* ) c -> right;
145         rc = SDumperPrint ( d, compact ? "|%E" : "\n\t| %E", c -> left );
146     }
147 
148     rc = SDumperPrint ( d, compact ? "|%E;" : "\n\t| %E\n\t;\n", c -> right );
149     if ( ! compact )
150         SDumperDecIndentLevel ( d );
151     return rc;
152 }
153 
SColumnDefDump(void * item,void * data)154 bool CC SColumnDefDump ( void *item, void *data )
155 {
156     SDumper *b = data;
157     const SColumn *self = ( const void* ) item;
158     bool compact = SDumperMode ( b ) == sdmCompact ? true : false;
159 
160     /* handle simple cases first */
161     if ( self -> validate == NULL && self -> limit == NULL )
162     {
163         /* simple */
164 #if ! DUMP_EXPLICIT_PHYS_MEMBERS
165         if ( self -> simple )
166         {
167             if ( self -> ptype != NULL )
168             {
169                 b -> rc = SDumperPrint ( b, compact ? "column %E %N;" : "\tcolumn %E %N;\n"
170                                          , self -> ptype
171                                          , self -> name
172                     );
173             }
174             else
175             {
176                 b -> rc = SDumperPrint ( b, compact ? "column %T %N;" : "\tcolumn %T %N;\n"
177                                          , & self -> td
178                                          , self -> name
179                     );
180             }
181         }
182         else
183 #endif
184         {
185             assert ( self -> read != NULL );
186             b -> rc = SDumperPrint ( b, compact ? "%s%scolumn %T %N = %E;" : "\t%s%scolumn %T %N = %E;\n"
187                                      , self -> dflt ? "default " : ""
188                                      , self -> read_only ? "readonly " : ""
189                                      , & self -> td
190                                      , self -> name
191                                      , self -> read
192                 );
193         }
194     }
195 
196     /* canonical representation */
197     else
198     {
199 #if ! DUMP_EXPLICIT_PHYS_MEMBERS
200         if ( self -> ptype != NULL )
201         {
202             b -> rc = SDumperPrint ( b, compact ? "%scolumn %E %N{" : "\t%scolumn %E %N\n\t{\n"
203                                      , self -> dflt ? "default " : ""
204                                      , self -> ptype
205                                      , self -> name
206                 );
207         }
208         else
209 #endif
210         {
211             b -> rc = SDumperPrint ( b, compact ? "%s%scolumn %T %N{" : "\t%s%scolumn %T %N\n\t{\n"
212                                      , self -> dflt ? "default " : ""
213                                      , self -> read_only ? "readonly " : ""
214                                      , & self -> td
215                                      , self -> name
216                 );
217         }
218         if ( b -> rc == 0 )
219         {
220             if ( ! compact )
221                 SDumperIncIndentLevel ( b );
222 
223 #if DUMP_EXPLICIT_PHYS_MEMBERS
224             if ( self -> read != NULL )
225 #else
226             if ( ! self -> simple && self -> read != NULL )
227 #endif
228             {
229                 b -> rc = SDumperPrint ( b, compact ? "read" : "\tread" );
230                 if ( b -> rc == 0 )
231                     b -> rc = SColumnDumpExpr ( b, self -> read );
232             }
233 
234             if ( b -> rc == 0 && self -> validate != NULL )
235             {
236                 b -> rc = SDumperPrint ( b, compact ? "validate" : "\tvalidate" );
237                 if ( b -> rc == 0 )
238                     b -> rc = SColumnDumpExpr ( b, self -> validate );
239             }
240 
241             if ( b -> rc == 0 && self -> limit != NULL )
242                 b -> rc = SDumperPrint ( b, compact ? "limit = %E;" : "\tlimit = %E;\n", self -> limit );
243 
244             if ( ! compact )
245                 SDumperDecIndentLevel ( b );
246         }
247         if ( b -> rc == 0 )
248             b -> rc = SDumperPrint ( b, compact ? "}" : "\t}\n" );
249     }
250 
251     return ( b -> rc != 0 ) ? true : false;
252 }
253 
254 #endif
255 
256 
257 /*--------------------------------------------------------------------------
258  * SPhysMember
259  *  column declaration
260  */
261 
262 #if SLVL >= 7
263 
264 /* Whack
265  */
SPhysMemberWhack(void * item,void * ignore)266 void CC SPhysMemberWhack ( void *item, void *ignore )
267 {
268     SPhysMember *self = item;
269 
270     SExpressionWhack ( self -> type );
271     SExpressionWhack ( self -> expr );
272     free ( self );
273 }
274 
275 /* Mark
276  */
SPhysMemberMark(void * item,void * data)277 void CC SPhysMemberMark ( void * item, void * data )
278 {
279     const SPhysMember * self = item;
280     const VSchema * schema = data;
281     if ( self != NULL )
282     {
283         SExpressionMark ( ( void * )self -> type, data );
284         SExpressionMark ( ( void * )self -> expr, data );
285         VSchemaTypeMark ( schema, self -> td . type_id );
286     }
287 }
288 
289 /* Dump
290  */
SPhysMemberDump(const SPhysMember * self,struct SDumper * d)291 rc_t SPhysMemberDump ( const SPhysMember *self, struct SDumper *d )
292 {
293     return FQNDump ( self != NULL ? self -> name : NULL, d );
294 }
295 
SPhysMemberDefDump(void * item,void * data)296 bool CC SPhysMemberDefDump ( void *item, void *data )
297 {
298     SDumper *b = data;
299     const SPhysMember *self = ( const void* ) item;
300     bool compact = SDumperMode ( b ) == sdmCompact ? true : false;
301 
302 #if ! DUMP_EXPLICIT_PHYS_MEMBERS
303     if ( self -> simple )
304         return false;
305 #endif
306 
307     b -> rc = SDumperPrint ( b, compact ? "%s column " : "\t%s column "
308                              , self -> stat ? "static" : "physical"
309         );
310     if ( b -> rc == 0 )
311     {
312         if ( self -> type != NULL )
313             b -> rc = SExpressionDump ( self -> type, b );
314         else
315             b -> rc = SDumperPrint ( b, "%T", & self -> td );
316     }
317     if ( b -> rc == 0 )
318     {
319         if ( compact )
320         {
321             if ( self -> expr == NULL )
322                 b -> rc = SDumperPrint ( b, " %N;", self -> name );
323             else
324                 b -> rc = SDumperPrint ( b, " %N=%E;", self -> name, self -> expr );
325         }
326         else
327         {
328             if ( self -> expr == NULL )
329                 b -> rc = SDumperPrint ( b, " %N;\n", self -> name );
330             else
331                 b -> rc = SDumperPrint ( b, " %N = %E;\n", self -> name, self -> expr );
332         }
333     }
334 
335     return ( b -> rc != 0 ) ? true : false;
336 }
337 
338 #endif
339 
340 /*--------------------------------------------------------------------------
341  * STableOverrides
342  *  describes extended parent
343  */
344 
345 #if SLVL >= 6
346 
347 /* Cmp
348  * Sort
349  */
STableOverridesCmp(const void * item,const void * n)350 int64_t CC STableOverridesCmp ( const void *item, const void *n )
351 {
352     const uint32_t *a = item;
353     const STableOverrides *b = n;
354 
355     return ( int64_t ) * a - ( int64_t ) b -> ctx;
356 }
357 
358 static
STableOverridesSort(const void * item,const void * n)359 int64_t CC STableOverridesSort ( const void *item, const void *n )
360 {
361     const STableOverrides *a = item;
362     const STableOverrides *b = n;
363 
364     return ( int64_t ) a -> ctx - ( int64_t ) b -> ctx;
365 }
366 
367 static
STableOverridesKSort(const void ** item,const void ** n,void * ignore)368 int64_t CC STableOverridesKSort ( const void **item, const void **n, void *ignore )
369 {
370     return STableOverridesSort ( * item, * n );
371 }
372 
373 /* Whack
374  */
375 static
STableOverridesWhack(void * item,void * ignore)376 void CC STableOverridesWhack ( void *item, void *ignore )
377 {
378     STableOverrides *self = item;
379     VectorWhack ( & self -> by_parent, NULL, NULL );
380     free ( self );
381 }
382 
383 /* Make
384  */
STableOverridesMake(Vector * parents,const STable * dad,const Vector * overrides)385 rc_t STableOverridesMake ( Vector *parents, const STable *dad, const Vector *overrides )
386 {
387     rc_t rc;
388     STableOverrides *to;
389 
390     /* first question is whether parent exists */
391     if ( VectorFind ( parents, & dad -> id, NULL, STableOverridesCmp ) != NULL )
392         return SILENT_RC ( rcVDB, rcSchema, rcParsing, rcTable, rcExists );
393 
394     /* create a new override object */
395     to = malloc ( sizeof * to );
396     if ( to == NULL )
397         return RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
398 
399     /* shallow clone */
400     rc = VectorCopy ( overrides, & to -> by_parent );
401     if ( rc != 0 )
402     {
403         free ( to );
404         return rc;
405     }
406     to -> dad = dad;
407     to -> ctx = dad -> id;
408 
409     /* insert into parent override vector */
410     rc = VectorInsert ( parents, to, NULL, STableOverridesSort );
411     if ( rc != 0 )
412     {
413         STableOverridesWhack ( to, NULL );
414         return rc;
415     }
416 
417     return 0;
418 }
419 
420 static
STableOverridesClone(void * item,void * data)421 bool CC STableOverridesClone ( void *item, void *data )
422 {
423     const STableOverrides *self = ( const void* ) item;
424     rc_t rc = STableOverridesMake ( data, self -> dad, & self -> by_parent );
425     return ( rc != 0 && GetRCState ( rc ) != rcExists ) ? true : false;
426 }
427 
428 #endif
429 
430 /*--------------------------------------------------------------------------
431  * STable
432  *  table declaration
433  */
434 
435 #if SLVL >= 6
436 
437 /* Whack
438  */
STableWhack(void * item,void * ignore)439 void CC STableWhack ( void *item, void *ignore )
440 {
441     STable *self = item;
442 
443     if ( self -> dflt_view != NULL )
444         StringWhack ( self -> dflt_view );
445 
446 #if SLVL >= 8
447     VectorWhack ( & self -> col, SColumnWhack, NULL );
448     VectorWhack ( & self -> cname, SNameOverloadWhack, NULL );
449 #endif
450 #if SLVL >= 7
451     VectorWhack ( & self -> phys, SPhysMemberWhack, NULL );
452 #endif
453     VectorWhack ( & self -> prod, SProductionWhack, NULL );
454     VectorWhack ( & self -> vprods, NULL, NULL );
455     VectorWhack ( & self -> syms, ( void ( CC * ) ( void*, void* ) ) KSymbolWhack, NULL );
456 
457     VectorWhack ( & self -> parents, NULL, NULL );
458     VectorWhack ( & self -> overrides, STableOverridesWhack, NULL );
459 
460     SExpressionWhack ( self -> limit );
461 
462     BSTreeWhack ( & self -> scope, KSymbolWhack, NULL );
463 
464     free ( self );
465 }
466 
467 /* Cmp
468  * Sort
469  */
STableCmp(const void * item,const void * n)470 int64_t CC STableCmp ( const void *item, const void *n )
471 {
472     const uint32_t *a = item;
473     const STable *b = n;
474 
475     if ( * a > b -> version )
476         return 1;
477     return ( int64_t ) ( * a >> 24 ) - ( int64_t ) ( b -> version >> 24 );
478 }
479 
STableSort(const void * item,const void * n)480 int64_t CC STableSort ( const void *item, const void *n )
481 {
482     const STable *a = item;
483     const STable *b = n;
484 
485     return ( int64_t ) ( a -> version >> 24 ) - ( int64_t ) ( b -> version >> 24 );
486 }
487 
488 
489 /* Find
490  *  generic object find within table scope
491  *
492  *  "td" [ OUT, NULL OKAY ] - returns cast type expression
493  *  if given or "any" if not
494  *
495  *  "name" [ OUT ] - returns list of overloaded objects if found
496  *
497  *  "type" [ OUT ] - returns object type id, e.g.:
498  *    eDatatype, eTypeset, eFormat, eFunction, ePhysical, eTable, ...
499  *
500  *  "expr" [ IN ] - NUL terminated name expression identifying object
501  *
502  *  "ctx" [ IN ] - NUL terminated context string for evaluation,
503  *  substitutes for filename in logging reports
504  *
505  *  "dflt" [ IN ] - if true, resolve default value
506  *
507  *  returns principal object identified. if NULL but "name" is not
508  *  NULL, then the object was only partially identified.
509  */
STableFind(const STable * self,const VSchema * schema,VTypedecl * td,const SNameOverload ** name,uint32_t * type,const char * expr,const char * ctx,bool dflt)510 const void * CC STableFind ( const STable *self,
511     const VSchema *schema, VTypedecl *td, const SNameOverload **name,
512     uint32_t *type, const char *expr, const char *ctx, bool dflt )
513 {
514     rc_t rc;
515     KSymTable tbl;
516 
517     /* initialize to not-found */
518     const void *obj = NULL;
519     * name = NULL;
520     * type = 0;
521 
522     /* build a symbol table for table */
523     rc = init_tbl_symtab ( & tbl, schema, self );
524     if ( rc == 0 )
525     {
526         obj = resolve_object ( & tbl, schema, td, name, type, expr, ctx, dflt );
527         KSymTableWhack ( & tbl );
528     }
529 
530     return obj;
531 }
532 
533 
534 /* FindOverride
535  *  finds an inherited or introduced overridden symbol
536  */
STableFindOverride(const STable * self,const VCtxId * cid)537 KSymbol * CC STableFindOverride ( const STable *self, const VCtxId *cid )
538 {
539     const STableOverrides *to;
540 
541     /* it may be on the existing table */
542     if ( cid -> ctx == self -> id )
543         return VectorGet ( & self -> vprods, cid -> id );
544 
545     to = ( const void* ) VectorFind ( & self -> overrides,
546         & cid -> ctx, NULL, STableOverridesCmp );
547     if ( to == NULL )
548         return NULL;
549 
550     return VectorGet ( & to -> by_parent, cid -> id );
551 }
552 
553 /* FindOrdAncestor
554  *  finds a parent or grandparent by order
555  */
STableFindOrdAncestor(const STable * self,uint32_t i)556 const STable * CC STableFindOrdAncestor ( const STable *self, uint32_t i )
557 {
558     const STableOverrides *to = ( const void* ) VectorGet ( & self -> overrides, i );
559     if ( to == NULL )
560         return NULL;
561     return to -> dad;
562 }
563 
564 
565 /* Extend
566  */
567 static
STableHasDad(void * item,void * data)568 bool CC STableHasDad ( void *item, void *data )
569 {
570     if ( item == data )
571         return true;
572     return false;
573 }
574 
575 /* OverloadTestForTypeCollision
576  * used for tables and views
577 */
SOverloadTestForTypeCollision(const SNameOverload * a,const SNameOverload * b)578 bool CC SOverloadTestForTypeCollision ( const SNameOverload *a, const SNameOverload *b )
579 {
580     uint32_t ax, bx, ctx;
581 
582     uint32_t aend = VectorLength ( & a -> items );
583     uint32_t bend = VectorLength ( & b -> items );
584 
585     if ( aend == 0 || bend == 0 )
586         return false;
587 
588     ctx = a -> cid . ctx;
589     ax = VectorStart ( & a -> items );
590     bx = VectorStart ( & b -> items );
591 
592     for ( aend += ax, bend += bx; ax < aend && bx < bend; )
593     {
594         int64_t diff;
595         const SColumn *acol = ( const void* ) VectorGet ( & a -> items, ax );
596         const SColumn *bcol = ( const void* ) VectorGet ( & b -> items, bx );
597         assert ( acol != NULL && bcol != NULL );
598 
599         /* if they are both from some other shared parent
600            maybe they are even the same column */
601         if ( acol == bcol || acol -> cid . ctx == bcol -> cid . ctx )
602         {
603             ++ ax;
604             ++ bx;
605             continue;
606         }
607 
608         /* don't bother comparing if either is from
609            originating table, as they are required
610            to appear in both lists */
611         if ( acol -> cid . ctx == ctx )
612         {
613             ++ ax;
614             continue;
615         }
616 
617         if ( bcol -> cid . ctx == ctx )
618         {
619             ++ bx;
620             continue;
621         }
622 
623         /* test the column types */
624         diff = SColumnSort ( acol, bcol );
625 
626         /* if they are the same type, this is a collision */
627         if ( diff == 0 )
628             return true;
629 
630         /* let it slide */
631         if ( diff < 0 )
632             ++ ax;
633         else
634             ++ bx;
635     }
636 
637     return false;
638 }
639 
640 static
STableTestForSymCollision(const KSymbol * sym,void * data)641 bool STableTestForSymCollision ( const KSymbol *sym, void *data )
642 {
643     const KSymTable *tbl = ( const void* ) data;
644     const KSymbol *found = KSymTableFindSymbol ( tbl, sym );
645     if ( found != NULL && found != sym ) switch ( found -> type )
646     {
647     case eColumn:
648         if ( sym -> type == eColumn )
649         {
650             /* when colliding columns originated in the same
651                table, consider them to be compatible extensions */
652             const SNameOverload *found_col, *sym_col;
653             sym_col = sym -> u . obj;
654             found_col = found -> u . obj;
655             assert ( sym_col != NULL && found_col != NULL );
656             if ( sym_col -> cid . ctx == found_col -> cid . ctx )
657                 return SOverloadTestForTypeCollision ( sym_col, found_col );
658         }
659     case eProduction:
660     case ePhysMember:
661         PLOGMSG ( klogErr, ( klogErr, "duplicate symbol '$(sym)' in parent table hierarchy"
662                              , "sym=%S"
663                              , & sym -> name
664                       ));
665         return true;
666     }
667     return false;
668 }
669 
670 static
STableTestColCollisions(void * item,void * data)671 bool CC STableTestColCollisions ( void *item, void *data )
672 {
673     const SNameOverload *no = ( const void* ) item;
674     return STableTestForSymCollision ( no -> name, data );
675 }
676 
677 static
STableTestPhysCollisions(void * item,void * data)678 bool CC STableTestPhysCollisions ( void *item, void *data )
679 {
680     const SPhysMember *phys = ( const void* ) item;
681     return STableTestForSymCollision ( phys -> name, data );
682 }
683 
684 static
STableTestProdCollisions(void * item,void * data)685 bool CC STableTestProdCollisions ( void *item, void *data )
686 {
687     const SProduction *prod = ( const void* ) item;
688     return STableTestForSymCollision ( prod -> name, data );
689 }
690 
691 static
STableTestForCollisions(void * item,void * data)692 bool STableTestForCollisions ( void *item, void *data )
693 {
694     const STable *self = ( const void* ) item;
695 
696     /* test column names */
697     if ( VectorDoUntil ( & self -> cname, false, STableTestColCollisions, data ) )
698         return true;
699 
700     /* test physical names */
701     if ( VectorDoUntil ( & self -> phys, false, STableTestPhysCollisions, data ) )
702         return true;
703 
704     /* test production names */
705     if ( VectorDoUntil ( & self -> prod, false, STableTestProdCollisions, data ) )
706         return true;
707 
708     return false;
709 }
710 
711 static
STableOverridesTestForCollisions(void * item,void * data)712 bool CC STableOverridesTestForCollisions ( void *item, void *data )
713 {
714     const STableOverrides *to = ( const void* ) item;
715     return STableTestForCollisions ( ( void* ) to -> dad, data );
716 }
717 
718 static
STableCopyColumnNames(void * item,void * data)719 bool CC STableCopyColumnNames ( void *item, void *data )
720 {
721     rc_t rc;
722     STable *self= data;
723     SNameOverload *copy;
724     const SNameOverload *orig = ( const void* ) item;
725     const KSymbol *sym = ( const KSymbol* )
726         BSTreeFind ( & self -> scope, & orig -> name -> name, KSymbolCmp );
727     if ( sym == NULL )
728     {
729         rc = SNameOverloadCopy ( & self -> scope, & copy, orig );
730         if ( rc == 0 )
731         {
732             rc = VectorAppend ( & self -> cname, & copy -> cid . id, copy );
733             if ( rc != 0 )
734                 SNameOverloadWhack ( copy, NULL );
735         }
736     }
737     else
738     {
739         copy = ( void* ) sym -> u . obj;
740         assert ( copy -> cid . ctx == orig -> cid . ctx );
741         rc = VectorMerge ( & copy -> items, true, & orig -> items, SColumnSort );
742     }
743 
744     return ( rc != 0 ) ? true : false;
745 }
746 
STableScanVirtuals(void * item,void * data)747 bool CC STableScanVirtuals ( void *item, void *data )
748 {
749     KSymTable *tbl = data;
750     STableOverrides *to = item;
751     BSTree *scope = VectorLast ( & tbl -> stack );
752     uint32_t i = VectorStart ( & to -> by_parent );
753     uint32_t end = VectorLength ( & to -> by_parent );
754     for ( end += i; i < end; ++ i )
755     {
756         const KSymbol *orig = ( const void* ) VectorGet ( & to -> by_parent, i );
757         assert ( orig != NULL );
758         if ( orig -> type == eVirtual )
759         {
760             void *ignore;
761 
762             /* since the virtual productions in one parent could be
763                defined by another parent, test for the possibility */
764             const KSymbol *def = KSymTableFindSymbol ( tbl, orig );
765             if ( def != NULL )
766             {
767                 if ( def -> type == eProduction || def -> type == eVirtual )
768                 {
769                     VectorSwap ( & to -> by_parent, i, def, & ignore );
770                 }
771                 else
772                 {
773                     PLOGMSG ( klogErr, ( klogErr, "a virtual production from one parent defined as non-production in another: '$(sym)'"
774                         , "sym=%S"
775                         , & def -> name
776                     ));
777                     return true;
778                 }
779             }
780             else
781             {
782                 /* copy the original */
783                 const KSymbol *copy;
784                 rc_t rc = KSymbolCopy ( scope, & copy, orig );
785                 if ( rc != 0 )
786                     return true;
787 
788                 /* replace the parent virtual with an updatable copy */
789                 VectorSwap ( & to -> by_parent, i, copy, & ignore );
790             }
791         }
792     }
793     return false;
794 }
795 
STableExtend(KSymTable * tbl,STable * self,const STable * dad)796 rc_t CC STableExtend ( KSymTable *tbl, STable *self, const STable *dad )
797 {
798     rc_t rc;
799 
800     /* reject if direct parent already there */
801     if ( VectorDoUntil ( & self -> parents, false, STableHasDad, ( void* ) dad ) )
802         return RC ( rcVDB, rcSchema, rcParsing, rcTable, rcExists );
803 
804     /* if parent is already in ancestry, treat as redundant */
805     if ( VectorFind ( & self -> overrides, & dad -> id, NULL, STableOverridesCmp ) != NULL )
806         return VectorAppend ( & self -> parents, NULL, dad );
807 
808     /* enter scope for this table */
809     rc = push_tbl_scope ( tbl, self );
810     if ( rc != 0 )
811         return rc;
812 
813     /* test for any collisions */
814     if ( STableTestForCollisions ( ( void* ) dad, tbl ) ||
815          VectorDoUntil ( & dad -> overrides, false, STableOverridesTestForCollisions, tbl ) )
816     {
817         pop_tbl_scope ( tbl, self );
818         return RC ( rcVDB, rcSchema, rcParsing, rcName, rcExists );
819     }
820 
821     /* pop table scope */
822     pop_tbl_scope ( tbl, self );
823 
824     /* add "dad" to parent list */
825     rc = VectorAppend ( & self -> parents, NULL, dad );
826     if ( rc != 0 )
827         return rc;
828 
829     /* copy column names from parent - should already contain all grandparents */
830     if ( VectorDoUntil ( & dad -> cname, false, STableCopyColumnNames, self ) )
831         return RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
832 
833     /* add "dad" to overrides */
834     rc = STableOverridesMake ( & self -> overrides, dad, & dad -> vprods );
835     if ( rc == 0 )
836     {
837         /* add all grandparents */
838         if ( VectorDoUntil ( & dad -> overrides, false, STableOverridesClone, & self -> overrides ) )
839             rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
840     }
841     else if ( GetRCState ( rc ) == rcExists )
842     {
843         rc = 0;
844     }
845     return rc;
846 }
847 
848 /* CloneExtend
849  *  creates an initially transparent table extension
850  *  used by cursor to permit addition of implicit productions
851  */
STableCloneExtend(const STable * self,STable ** clone,VSchema * schema)852 rc_t CC STableCloneExtend ( const STable *self, STable **clone, VSchema *schema )
853 {
854     rc_t rc;
855     KSymTable tbl;
856 
857     STable *table = malloc ( sizeof * table );
858     if ( table == NULL )
859         return RC ( rcVDB, rcSchema, rcUpdating, rcMemory, rcExhausted );
860 
861     /* need to take a deep look at scope */
862     rc = init_symtab ( & tbl, schema );
863     if ( rc != 0 )
864         return rc;
865 
866     /* this takes care of initializing "scope" */
867     memset ( table, 0, sizeof * table );
868 
869     /* take name and version, since this is an anonymous extension */
870     table -> name = KSymTableFindSymbol ( & tbl, self -> name );
871     KSymTableWhack ( & tbl );
872     assert ( table -> name != NULL );
873     table -> src_file = self -> src_file;
874     table -> src_line = self -> src_line;
875     table -> version = self -> version;
876 
877     /* take on table-wide blob limit */
878     if ( self -> limit != NULL )
879     {
880         table -> limit = self -> limit;
881         atomic32_inc ( & ( ( SExpression* ) table -> limit ) -> refcount );
882     }
883 
884     /* initialize all vectors for single-inheritance */
885     VectorInit ( & table -> parents, 0, 1 );
886     VectorInit ( & table -> overrides, 0, VectorLength ( & self -> overrides ) + 1 );
887     VectorInit ( & table -> col, 0, 16 );
888     VectorInit ( & table -> cname, 0, 16 );
889     VectorInit ( & table -> phys, 0, 16 );
890     VectorInit ( & table -> prod, 0, 64 );
891     VectorInit ( & table -> vprods, 1, 16 );
892     VectorInit ( & table -> syms, 1, 32 );
893 
894     rc = init_tbl_symtab ( & tbl, schema, table );
895     if ( rc == 0 )
896         rc = STableExtend ( & tbl, table, self );
897     if ( rc == 0 )
898     {
899         rc = push_tbl_scope ( & tbl, table );
900         if ( rc == 0 )
901         {
902             if ( VectorDoUntil ( & table -> overrides, false, STableScanVirtuals, & tbl ) )
903                 rc = RC ( rcVDB, rcSchema, rcUpdating, rcMemory, rcExhausted );
904         }
905     }
906 
907     KSymTableWhack ( & tbl );
908 
909     if ( rc == 0 )
910     {
911         /* add table to schema */
912         rc = VectorAppend ( & schema -> tbl, & table -> id, table );
913         if ( rc == 0 )
914         {
915             void *dad;
916             uint32_t idx;
917             SNameOverload *name = ( void* ) table -> name -> u . obj;
918 
919             /* find ourselves in table overloads */
920             dad = VectorFind ( & name -> items, & table -> version, & idx, STableCmp );
921             assert ( dad != NULL );
922             assert ( dad == ( void* ) self );
923 
924             /* set clone in our place */
925             VectorSwap ( & name -> items, idx, table, & dad );
926 
927             * clone = table;
928             return 0;
929         }
930     }
931 
932     STableWhack ( table, NULL ), table = NULL;
933     return rc;
934 }
935 
936 /* ImplicitPhysMember
937  *  adds an implicit physical member
938  */
STableImplicitPhysMember(STable * self,const VTypedecl * td,KSymbol * sym,const String * name)939 rc_t STableImplicitPhysMember ( STable *self,
940     const VTypedecl *td, KSymbol *sym, const String *name )
941 {
942     rc_t rc;
943     SPhysMember *m = malloc ( sizeof * m );
944     if ( m == NULL )
945         rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
946     else
947     {
948         memset ( m, 0, sizeof * m );
949 
950         /* if discovered as static column, give it a type */
951         if ( td != NULL )
952             m -> td = * td;
953 
954         /* create name symbol as required */
955         if ( sym == NULL )
956         {
957             rc = KSymbolMake ( & sym, name, ePhysMember, m );
958             if ( rc == 0 )
959                 BSTreeInsert ( & self -> scope, & sym -> n, KSymbolSort );
960         }
961         if ( sym != NULL )
962         {
963             /* complete handshake with symbol */
964             m -> name = sym;
965             sym -> u . obj = m;
966             sym -> type = ePhysMember;
967 
968             /* add member to table */
969             m -> cid . ctx = self -> id;
970             rc = VectorAppend ( & self -> phys, & m -> cid . id, m );
971             if ( rc == 0 )
972                 return 0;
973         }
974 
975         SPhysMemberWhack ( m, NULL );
976     }
977     return rc;
978 }
979 
980 /* ImplicitColMember
981  *  adds an implicit column member of simple or incomplete type
982  *
983  *  "cname" [ IN ] - column name
984  *
985  *  "pname" [ IN ] - name of physical column
986  */
STableImplicitColMember(STable * self,const String * cname,const String * pname)987 rc_t STableImplicitColMember ( STable *self,
988     const String *cname, const String *pname )
989 {
990     rc_t rc;
991 
992     /* create SColumn */
993     SColumn *col = malloc ( sizeof * col );
994     if ( col == NULL )
995         rc = RC ( rcVDB, rcTable, rcUpdating, rcMemory, rcExhausted );
996     else
997     {
998         const KSymbol *psym;
999         memset ( col, 0, sizeof * col );
1000 
1001         /* look up SPhysMember */
1002         psym = ( const KSymbol* ) BSTreeFind ( & self -> scope, pname, KSymbolCmp );
1003         if ( psym == NULL )
1004             rc = RC ( rcVDB, rcTable, rcUpdating, rcColumn, rcNotFound );
1005         else
1006         {
1007             KSymbol *csym;
1008 
1009             /* create column symbol */
1010             rc = KSymbolMake ( & csym, cname, eColumn, col );
1011             if ( rc == 0 )
1012             {
1013                 BSTNode *exist;
1014 
1015                 /* complete handshake with symbol */
1016                 col -> name = csym;
1017 
1018                 /* insert into table scope and reject on collision
1019                    deep check should have been executed previously */
1020                 rc = BSTreeInsertUnique ( & self -> scope, & csym -> n, & exist, KSymbolSort );
1021                 if ( rc == 0 )
1022                 {
1023                     /* take column typedecl ( if known ) from physical */
1024                     SPhysMember *phys = ( void* ) psym -> u . obj;
1025                     col -> td = phys -> td;
1026 
1027                     /* cross-link the external and physical columns */
1028                     rc = SSymExprMake ( & col -> read, psym, ePhysExpr );
1029                     if ( rc == 0 )
1030                         rc = SSymExprMake ( & phys -> expr, csym, eColExpr );
1031                     if ( rc == 0 )
1032                     {
1033                         /* add column to table */
1034                         col -> cid . ctx = self -> id;
1035                         rc = VectorAppend ( & self -> col, & col -> cid . id, col );
1036                         if ( rc == 0 )
1037                         {
1038                             void *ignore;
1039                             SNameOverload *name;
1040 
1041                             /* create a column name with a single typed column */
1042                             rc = SNameOverloadMake ( & name, csym, 0, 1 );
1043                             if ( rc == 0 )
1044                             {
1045                                 /* being the only column, "col" may be simply
1046                                    inserted rather than using a sorted insert */
1047                                 rc = VectorAppend ( & name -> items, NULL, col );
1048                                 if ( rc == 0 )
1049                                 {
1050                                     /* finally, insert name into table */
1051                                     rc = VectorAppend ( & self -> cname, & name -> cid . id, name );
1052                                     if ( rc == 0 )
1053                                     {
1054                                         name -> cid . ctx = self -> id;
1055                                         return 0;
1056                                     }
1057                                 }
1058 
1059                                 SNameOverloadWhack ( name, NULL );
1060                             }
1061 
1062                             VectorSwap ( & self -> col, col -> cid . id, NULL, & ignore );
1063                         }
1064 
1065                         SExpressionWhack ( phys -> expr ), phys -> expr = NULL;
1066                     }
1067 
1068                     BSTreeUnlink ( & self -> scope, & csym -> n );
1069                 }
1070 
1071                 KSymbolWhack ( & csym -> n, NULL );
1072             }
1073         }
1074 
1075         SColumnWhack ( col, NULL );
1076     }
1077     return rc;
1078 }
1079 
1080 
1081 /* Compare
1082  */
1083 static
KSymbolDeepCompare(const KSymbol * a,const KSymbol * b)1084 int64_t KSymbolDeepCompare ( const KSymbol *a, const KSymbol *b )
1085 {
1086     int64_t diff;
1087 
1088     /* the same symbol */
1089     if ( a == b )
1090         return 0;
1091 
1092     /* parents are first */
1093     if ( a -> dad != NULL )
1094     {
1095         if ( b -> dad != NULL )
1096         {
1097             /* both symbols have parents */
1098             diff = KSymbolDeepCompare ( a -> dad, b -> dad );
1099             if ( diff != 0 )
1100                 return diff;
1101         }
1102         else
1103         {
1104             /* "b" is a root */
1105             diff = KSymbolDeepCompare ( a -> dad, b );
1106             if ( diff != 0 )
1107                 return diff;
1108             return 1;
1109         }
1110     }
1111     else if ( b -> dad != NULL )
1112     {
1113         /* "a" is a root */
1114         diff = KSymbolDeepCompare ( a, b -> dad );
1115         if ( diff != 0 )
1116             return diff;
1117         return -1;
1118     }
1119 
1120     /* perform textual comparison */
1121     return KSymbolSort ( & a -> n, & b -> n );
1122 }
1123 
1124 static
STableNameSort(const void ** a,const void ** b,void * ignore)1125 int64_t CC STableNameSort ( const void **a, const void **b, void *ignore )
1126 {
1127     int diff;
1128     const STable *tb = * b;
1129     const STable *ta = * a;
1130     if ( tb == NULL )
1131         return ta != NULL;
1132     if ( ta == NULL )
1133         return -1;
1134     diff = KSymbolDeepCompare ( ta -> name, tb -> name );
1135     if ( diff != 0 )
1136         return diff;
1137 
1138     return (int64_t) ta -> version - (int64_t) tb -> version;
1139 }
1140 
1141 enum
1142 {
1143     stbl_cmp_insertion = 1 << 0,
1144     stbl_cmp_deletion  = 1 << 1,
1145     stbl_cmp_mismatch  = 1 << 2,
1146     stbl_cmp_newer     = 1 << 3,
1147     stbl_cmp_older     = 1 << 4
1148 };
1149 
STableCompare(const STable * a,const STable * b,const STable ** newer,bool exhaustive)1150 rc_t CC STableCompare ( const STable *a, const STable *b, const STable **newer, bool exhaustive )
1151 {
1152     rc_t stage_rc, cmp_rc = 0;
1153     uint32_t stage_bits, cmp_bits = 0;
1154 
1155     int diff;
1156     Vector va, vb;
1157     uint32_t ia, ib, ca, cb;
1158 
1159     assert ( ( a -> version >> 24 ) == ( b -> version >> 24 ) );
1160 
1161     PARSE_DEBUG (( "STableCompare: testing %N #%.3V against #%.3V\n",
1162                    a -> name, a -> version, b -> version ));
1163 
1164     /* guess the newer of the two based upon version alone */
1165     * newer = a -> version >= b -> version ? a : b;
1166 
1167     /* test #1 - immediate parents */
1168     ca = VectorLength ( & a -> parents );
1169     cb = VectorLength ( & b -> parents );
1170     if ( ca != cb || ca != 0 )
1171     {
1172         /* make a copy */
1173         cmp_rc = VectorCopy ( & a -> parents, & va );
1174         if ( cmp_rc != 0 )
1175             return cmp_rc;
1176         cmp_rc = VectorCopy ( & b -> parents, & vb );
1177         if ( cmp_rc != 0 )
1178         {
1179             VectorWhack ( & va, NULL, NULL );
1180             return cmp_rc;
1181         }
1182         if ( ca > 1 )
1183             VectorReorder ( & va, STableNameSort, NULL );
1184         if ( cb > 1 )
1185             VectorReorder ( & vb, STableNameSort, NULL );
1186 
1187         for ( stage_bits = ia = ib = 0; ia < ca && ib < cb; )
1188         {
1189             const STable *pa = ( const void* ) VectorGet ( & va, ia );
1190             const STable *pb = ( const void* ) VectorGet ( & vb, ib );
1191             if ( pa == pb )
1192             {
1193                 ++ ia, ++ ib;
1194                 continue;
1195             }
1196             diff = KSymbolDeepCompare ( pa -> name, pb -> name );
1197             if ( diff < 0 )
1198             {
1199                 stage_bits |= stbl_cmp_insertion;
1200                 ++ ia;
1201             }
1202             else if ( diff > 0 )
1203             {
1204                 stage_bits |= stbl_cmp_deletion;
1205                 ++ ib;
1206             }
1207             else
1208             {
1209                 if ( pa -> version > pb -> version )
1210                     stage_bits |= stbl_cmp_newer;
1211                 else if ( pa -> version < pb -> version )
1212                     stage_bits |= stbl_cmp_older;
1213 
1214                 ++ ia, ++ ib;
1215             }
1216         }
1217 
1218         VectorWhack ( & va, NULL, NULL );
1219         VectorWhack ( & vb, NULL, NULL );
1220 
1221         PARSE_DEBUG (( "STableCompare: %N #%.3V vs. #%.3V - PARENT COMPARISON:\n%s%s%s%s%s"
1222                        , a -> name, a -> version, b -> version
1223                        , ( stage_bits == 0 )                 ? "  no differences detected\n" : ""
1224                        , ( stage_bits & stbl_cmp_insertion ) ? "  insertion(s) detected\n" : ""
1225                        , ( stage_bits & stbl_cmp_deletion )  ? "  deletion(s) detected\n" : ""
1226                        , ( stage_bits & stbl_cmp_newer )     ? "  newer ancestor(s) detected\n" : ""
1227                        , ( stage_bits & stbl_cmp_older )     ? "  older ancestor(s) detected\n" : ""
1228             ));
1229 
1230         if ( stage_bits != 0 )
1231         {
1232             /* if the table versions are the same, the parents should not have insertions or deletions */
1233             if ( a -> version == b -> version && ( stage_bits & ( stbl_cmp_insertion | stbl_cmp_deletion ) ) != 0 )
1234             {
1235                 stage_rc = RC ( rcVDB, rcSchema, rcParsing, rcTable, rcInconsistent );
1236                 PLOGERR ( klogErr, ( klogErr, stage_rc, "STableCompare: illegal redeclaration of table '$(tbl)' - differing parents."
1237                                      , "tbl=%N#%.3V"
1238                                      , a -> name, b -> version ) );
1239                 if ( ! exhaustive )
1240                     return stage_rc;
1241                 if ( cmp_rc == 0 )
1242                     cmp_rc = stage_rc;
1243             }
1244 
1245             /* if the tables have same parent names but conflicting versions */
1246             if ( ( stage_bits & ( stbl_cmp_newer | stbl_cmp_older ) ) == ( stbl_cmp_newer | stbl_cmp_older ) )
1247             {
1248                 stage_rc = RC ( rcVDB, rcSchema, rcParsing, rcTable, rcInconsistent );
1249                 PLOGERR ( klogErr, ( klogErr, stage_rc, "STableCompare: illegal redeclaration of table '$(tbl)' - both older and newer parent versions."
1250                                      , "tbl=%N#%.3V"
1251                                      , a -> name, b -> version ) );
1252                 if ( ! exhaustive )
1253                     return stage_rc;
1254                 if ( cmp_rc == 0 )
1255                     cmp_rc = stage_rc;
1256             }
1257             else
1258             {
1259                 /* if "a" claims to be newer than "b" */
1260                 if ( a -> version > b -> version )
1261                 {
1262                     if ( ( stage_bits & stbl_cmp_older ) != 0 )
1263                     {
1264                         stage_rc = RC ( rcVDB, rcSchema, rcParsing, rcTable, rcInconsistent );
1265                         PLOGERR ( klogErr, ( klogErr, stage_rc, "STableCompare: illegal redeclaration of table '$(tbl)' - version $(new_vers) has older parents than version $(old_vers)."
1266                                              , "tbl=%N,new_vers=#%.3V,old_vers=#%.3V"
1267                                              , a -> name, a -> version, b -> version ) );
1268                         if ( ! exhaustive )
1269                             return stage_rc;
1270                         if ( cmp_rc == 0 )
1271                             cmp_rc = stage_rc;
1272                     }
1273                 }
1274 
1275                 /* if "b" claims to be newer than "a" */
1276                 else if ( a -> version < b -> version )
1277                 {
1278                     if ( ( stage_bits & stbl_cmp_newer ) != 0 )
1279                     {
1280                         stage_rc = RC ( rcVDB, rcSchema, rcParsing, rcTable, rcInconsistent );
1281                         PLOGERR ( klogErr, ( klogErr, stage_rc, "STableCompare: illegal redeclaration of table '$(tbl)' - version $(old_vers) has newer parents than version $(new_vers)."
1282                                              , "tbl=%N,new_vers=#%.3V,old_vers=#%.3V"
1283                                              , a -> name, b -> version, a -> version ) );
1284                         if ( ! exhaustive )
1285                             return stage_rc;
1286                         if ( cmp_rc == 0 )
1287                             cmp_rc = stage_rc;
1288                     }
1289                 }
1290 
1291                 /* they are the same - check parent versions */
1292                 else if ( ( stage_bits & ( stbl_cmp_newer | stbl_cmp_older ) ) != 0 )
1293                 {
1294                     PLOGMSG ( klogInfo, ( klogInfo, "STableCompare: table '$(tbl)' differs in parent hierarchy"
1295                                           " - latest declaration chosen automatically.", "tbl=%N#%.3V"
1296                                           , a -> name, b -> version ));
1297 
1298                     * newer = ( stage_bits & stbl_cmp_newer ) ? a : b;
1299                 }
1300             }
1301 
1302             cmp_bits |= stage_bits;
1303         }
1304     }
1305 
1306     /* test #2 - immediate extern columns */
1307     /* test #3 - immediate physical columns */
1308     /* test #4 - immediate productions */
1309     /* test #5 - immediate virtual productions */
1310     /* test #6 - deep parents */
1311     /* test #7 - deep extern columns */
1312     /* test #8 - deep physical columns */
1313     /* test #9 - deep productions */
1314     /* test #10 - deep virtual productions */
1315 
1316     return cmp_rc;
1317 }
1318 
1319 
1320 /* Mark
1321  */
STableClearMark(void * item,void * ignore)1322 void CC STableClearMark ( void *item, void *ignore )
1323 {
1324     STable *self = item;
1325     self -> marked = false;
1326 }
1327 
1328 
STableMark(void * item,void * data)1329 void CC STableMark ( void * item, void * data )
1330 {
1331     STable * self = item;
1332     if ( self != NULL && ! self -> marked )
1333     {
1334         self -> marked = true;
1335         SFunctionMark ( ( void * )self -> untyped, data );
1336         VectorForEach ( & self -> col, false, SColumnMark, data );
1337         VectorForEach ( & self -> phys, false, SPhysMemberMark, data );
1338         VectorForEach ( & self -> prod, false, SProductionMark, data );
1339         VectorForEach ( & self -> parents, false, STableMark, data );
1340     }
1341 }
1342 
STableNameMark(const SNameOverload * self,const VSchema * schema)1343 void CC STableNameMark ( const SNameOverload *self, const VSchema *schema )
1344 {
1345     if ( self != NULL )
1346     {
1347         VectorForEach ( & self -> items, false, STableMark, ( void * )schema );
1348     }
1349 }
1350 
1351 
1352 /* Dump
1353  *  dump "table" { }
1354  */
STableDump(const STable * self,struct SDumper * d)1355 rc_t STableDump ( const STable *self, struct SDumper *d )
1356 {
1357     d -> rc = FQNDump ( self != NULL ? self -> name : NULL, d );
1358     if ( d -> rc == 0 && self != NULL )
1359         d -> rc = SDumperVersion ( d, self -> version );
1360     return d -> rc;
1361 }
1362 
1363 #if _DEBUGGING
1364 static
SProductionDumpVirtuals(void * item,void * data)1365 bool CC SProductionDumpVirtuals ( void *item, void *data )
1366 {
1367     SDumper *b = data;
1368     const KSymbol *sym = ( const void* ) item;
1369 
1370     switch ( sym -> type )
1371     {
1372     case eVirtual:
1373         b -> rc = SDumperPrint ( b, "\t *  virtual %N = 0;\n", sym );
1374         break;
1375     case eProduction:
1376     {
1377         const SProduction *prod = sym -> u . obj;
1378         b -> rc = SDumperPrint ( b, "\t *  %E %N;\n", prod -> fd, sym );
1379         break;
1380     }
1381     case eColumn:
1382     {
1383         b -> rc = SDumperPrint ( b, "\t *  column %N;\n", sym );
1384         break;
1385     }
1386     case ePhysMember:
1387     {
1388         const SPhysMember *phys = sym -> u . obj;
1389         if ( phys -> type != NULL )
1390             b -> rc = SDumperPrint ( b, "\t *  physical %E %N;\n", phys -> type, sym );
1391         else
1392             b -> rc = SDumperPrint ( b, "\t *  physical %T %N;\n", & phys -> td, sym );
1393         break;
1394     }}
1395 
1396     return ( b -> rc != 0 ) ? true : false;
1397 }
1398 
1399 static
SProductionDumpOverrides(void * item,void * data)1400 bool CC SProductionDumpOverrides ( void *item, void *data )
1401 {
1402     SDumper *b = data;
1403     const STableOverrides *to = ( const void* ) item;
1404     if ( VectorLength ( & to -> by_parent ) == 0 )
1405         return false;
1406 
1407     b -> rc = SDumperPrint ( b, "\n\t/* %N inherited virtual productions\n", to -> dad -> name );
1408     if ( b -> rc != 0 )
1409         return true;
1410     if ( VectorDoUntil ( & to -> by_parent, false, SProductionDumpVirtuals, b ) )
1411         return true;
1412     b -> rc = SDumperPrint ( b, "\t */\n" );
1413 
1414     return ( b -> rc != 0 ) ? true : false;
1415 }
1416 #endif
1417 
1418 static
STableDumpBody(const STable * self,SDumper * b)1419 bool STableDumpBody ( const STable *self, SDumper *b )
1420 {
1421     bool compact = SDumperMode ( b ) == sdmCompact ? true : false;
1422 
1423     if ( self -> untyped != NULL )
1424     {
1425         b -> rc = SDumperPrint ( b, compact ? "__untyped=%N();" : "\t__untyped = %N ();\n"
1426                                  , self -> untyped -> name
1427             );
1428         if ( b -> rc != 0 )
1429             return true;
1430     }
1431     if ( self -> limit != NULL )
1432     {
1433         b -> rc = SDumperPrint ( b, compact ? "column default limit=%E;" : "\tcolumn default limit = %E;\n"
1434                                  , self -> limit
1435             );
1436         if ( b -> rc != 0 )
1437             return true;
1438     }
1439 #if SLVL >= 8
1440     if ( VectorDoUntil ( & self -> col, false, SColumnDefDump, b ) )
1441         return true;
1442 #endif
1443     if ( VectorDoUntil ( & self -> prod, false, SProductionDefDump, b ) )
1444         return true;
1445 #if SLVL >= 7
1446     if ( VectorDoUntil ( & self -> phys, false, SPhysMemberDefDump, b ) )
1447         return true;
1448 #endif
1449 #if _DEBUGGING
1450     if ( SDumperMode ( b ) == sdmPrint )
1451     {
1452         if ( VectorDoUntil ( & self -> overrides, false, SProductionDumpOverrides, b ) )
1453             return true;
1454 
1455         if ( VectorLength ( & self -> vprods ) != 0 )
1456         {
1457             b -> rc = SDumperPrint ( b, "\n\t/* %N virtual productions\n", self -> name );
1458             if ( b -> rc != 0 )
1459                 return true;
1460             if ( VectorDoUntil ( & self -> vprods, false, SProductionDumpVirtuals, b ) )
1461                 return true;
1462             b -> rc = SDumperPrint ( b, "\t */\n" );
1463             if ( b -> rc != 0 )
1464                 return true;
1465         }
1466     }
1467 #endif
1468 
1469     return false;
1470 }
1471 
1472 static
STableDumpParents(void * item,void * data)1473 bool CC STableDumpParents ( void *item, void *data )
1474 {
1475     SDumper *b = data;
1476     const STable *self = ( const void* ) item;
1477 
1478     b -> rc = SDumperPrint ( b, "\v%N%V", self -> name, self -> version );
1479 
1480     SDumperSepString ( b, SDumperMode ( b ) == sdmCompact ? "," : ", " );
1481 
1482     return ( b -> rc != 0 ) ? true : false;
1483 }
1484 
STableDefDump(void * item,void * data)1485 bool CC STableDefDump ( void *item, void *data )
1486 {
1487     bool rtn;
1488     SDumper *b = data;
1489     const STable *self = ( const void* ) item;
1490     bool compact = SDumperMode ( b ) == sdmCompact ? true : false;
1491 
1492     if ( SDumperMarkedMode ( b ) && ! self -> marked )
1493         return false;
1494 
1495     b -> rc = SDumperPrint ( b, compact ? "table %N" : "\ttable %N", self -> name );
1496 
1497     if ( b -> rc == 0 )
1498         b -> rc = SDumperVersion ( b, self -> version );
1499 
1500     if ( b -> rc == 0 )
1501     {
1502         SDumperSepString ( b, compact ? "=" : " = " );
1503         VectorDoUntil ( & self -> parents, false, STableDumpParents, b );
1504     }
1505 
1506     if ( b -> rc == 0 )
1507         b -> rc = SDumperPrint ( b, compact ? "{" : "\n\t{\n" );
1508 
1509     if ( b -> rc != 0 )
1510         return true;
1511 
1512     if ( ! compact )
1513         SDumperIncIndentLevel ( b );
1514     rtn = STableDumpBody ( self, b );
1515     if ( ! compact )
1516         SDumperDecIndentLevel ( b );
1517 
1518     if ( rtn )
1519         return true;
1520 
1521     b -> rc = SDumperPrint ( b, compact ? "}" : "\t}\n" );
1522 
1523     return ( b -> rc != 0 ) ? true : false;
1524 }
1525 
1526 #endif
1527 
1528 
1529 /*--------------------------------------------------------------------------
1530  * VSchema
1531  */
1532 
1533 #if SLVL >= 7
1534 
1535 /*
1536  * physical-name      = '.' ID
1537  */
physical_name(const KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env)1538 void physical_name ( const KSymTable *tbl, KTokenSource *src, KToken *t, const SchemaEnv *env )
1539 {
1540     KToken t2;
1541     if ( KTokenizerNext ( kDefaultTokenizer, src, & t2 ) -> id != eIdent ||
1542          t -> str . addr + 1 != t2 . str . addr )
1543     {
1544         /* this is just a dot */
1545         KTokenSourceReturn ( src, & t2 );
1546     }
1547     else
1548     {
1549         /* this is a physical name */
1550         t -> str . size += t2 . str . size;
1551         t -> str . len += t2 . str . len;
1552         t -> id = eIdent;
1553         t -> sym = KSymTableFind ( tbl, & t -> str );
1554         if ( t -> sym != NULL )
1555             t -> id = t -> sym -> type;
1556     }
1557 }
1558 
1559 /*
1560  *    physical-decl      = 'physical' [ 'column' ] KCOL '{' <physical-stmts> '}'
1561  *    physical-stmts     = <physical-stmt> ';' [ <physical-stmts> ]
1562  *    physical-stmt      = 'read' ( '=' | '+= ) <cond-expr>
1563  *                       | 'write' ( '=' | '+=' ) <cond-expr>
1564  *                       | '__untyped' '=' <untyped-expr>
1565  */
1566 static
physical_mbr(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SPhysMember * m)1567 rc_t physical_mbr ( KSymTable *tbl, KTokenSource *src, KToken *t,
1568     const SchemaEnv *env, VSchema *self, SPhysMember *m )
1569 {
1570     rc_t rc;
1571 
1572     /* determine static flag */
1573     if ( t -> id == kw_static )
1574     {
1575         next_token ( tbl, src, t );
1576         m -> stat = true;
1577     }
1578 
1579     /* skip keywords */
1580     if ( t -> id == kw_physical )
1581         next_token ( tbl, src, t );
1582     if ( t -> id == kw_column )
1583         next_token ( tbl, src, t );
1584 
1585     /* if member type begins with schema parameters... */
1586     if ( t -> id == eLeftAngle )
1587         rc = phys_encoding_expr ( tbl, src, t, env, self, & m -> td, & m -> type );
1588     else
1589     {
1590         /* get either a typename or a physical column name */
1591         rc = next_fqn ( tbl, src, t, env );
1592         if ( rc == 0 )
1593         {
1594             /* column is probably based upon a physical structure */
1595             if ( t -> id == ePhysical )
1596                 rc = phys_encoding_expr ( tbl, src, t, env, self, & m -> td, & m -> type );
1597             else if ( t -> id != eDatatype )
1598                 return KTokenExpected ( t, klogErr, "typename or physical column type" );
1599             else
1600                 rc = typedecl ( tbl, src, t, env, self, & m -> td );
1601         }
1602     }
1603     if ( rc != 0 )
1604         return KTokenFailure ( t, klogErr, rc, "typename or physical column type" );
1605 
1606     /* get name */
1607     if ( t -> id != ePeriod )
1608         return KTokenExpected ( t, klogErr, "physical name starting with period" );
1609     physical_name ( tbl, src, t, env );
1610     if ( t -> id == eIdent )
1611     {
1612         /* enter name into scope */
1613         rc = KSymTableCreateConstSymbol ( tbl, & m -> name, & t -> str, ePhysMember, m );
1614         if ( rc != 0 )
1615             return KTokenRCExplain ( t, klogInt, rc );
1616     }
1617     else if ( t -> id == ePhysMember )
1618         return KTokenExpected ( t, klogErr, "undefined physical member name" );
1619     else if ( t -> id != eForward && t -> id != eVirtual )
1620         return KTokenExpected ( t, klogErr, "physical member name" );
1621     else
1622     {
1623         m -> name = t -> sym;
1624         ( ( KSymbol* ) t -> sym ) -> u . obj = m;
1625         ( ( KSymbol* ) t -> sym ) -> type = ePhysMember;
1626     }
1627 
1628 
1629     /* get the assignment expression */
1630     if ( next_token ( tbl, src, t ) -> id == eAssign )
1631     {
1632         rc = cond_expr ( tbl, src, next_token ( tbl, src, t ), env, self, & m -> expr );
1633         if ( rc != 0 )
1634             return KTokenFailure ( t, klogErr, rc, "assignment expression" );
1635     }
1636 
1637     /* expect we're done */
1638     return expect ( tbl, src, t, eSemiColon, ";", true );
1639 }
1640 
1641 static
physical_member(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,STable * table)1642 rc_t physical_member ( KSymTable *tbl, KTokenSource *src, KToken *t,
1643     const SchemaEnv *env, VSchema *self, STable *table )
1644 {
1645     rc_t rc;
1646     SPhysMember *m = malloc ( sizeof * m );
1647     if ( m == NULL )
1648         rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
1649     else
1650     {
1651         memset ( m, 0, sizeof * m );
1652         rc = physical_mbr ( tbl, src, t, env, self, m );
1653         if ( rc == 0 )
1654         {
1655             rc = VectorAppend ( & table -> phys, & m -> cid . id, m );
1656             if ( rc == 0 )
1657                 return 0;
1658         }
1659 
1660         SPhysMemberWhack ( m, NULL );
1661     }
1662     return rc;
1663 }
1664 
implicit_physical_member(KSymTable * tbl,const SchemaEnv * env,STable * table,SColumn * c,KSymbol * sym)1665 rc_t implicit_physical_member ( KSymTable *tbl, const SchemaEnv *env,
1666     STable *table, SColumn *c, KSymbol *sym )
1667 {
1668     rc_t rc;
1669     SPhysMember *m = malloc ( sizeof * m );
1670     if ( m == NULL )
1671         rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
1672     else
1673     {
1674         /* create initialized simple physical member */
1675         memset ( m, 0, sizeof * m );
1676         m -> simple = true;
1677 
1678         /* capture type information */
1679         m -> td = c -> td;
1680         if ( c -> ptype != NULL )
1681         {
1682             m -> type = c -> ptype;
1683             atomic32_inc ( & ( ( SExpression* ) c -> ptype ) -> refcount );
1684         }
1685 
1686         /* link up with name */
1687         m -> name = sym;
1688         sym -> u . obj = m;
1689 
1690         /* now create simple input expression */
1691         rc = SSymExprMake ( & m -> expr, c -> name, eColExpr );
1692         if ( rc == 0 )
1693             rc = SSymExprMake ( & c -> read, sym, ePhysExpr );
1694         if ( rc == 0 )
1695         {
1696             rc = VectorAppend ( & table -> phys, & m -> cid . id, m );
1697             if ( rc == 0 )
1698                 return 0;
1699         }
1700 
1701         SPhysMemberWhack ( m, NULL );
1702     }
1703     return rc;
1704 }
1705 #endif
1706 
1707 #if SLVL >= 8
1708 /*
1709  * column-stmt        = 'read' '=' <cond-expr>
1710  *                    | 'validate' '=' <cond-expr>
1711  *                    | 'limit' '=' UINT_EXPR
1712  *                    | ';'
1713  */
1714 static
column_stmt(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SColumn * c,const char ** expected)1715 rc_t column_stmt ( KSymTable *tbl, KTokenSource *src, KToken *t,
1716      const SchemaEnv *env, VSchema *self, SColumn *c, const char **expected )
1717 {
1718     rc_t rc;
1719 
1720     switch ( t -> id )
1721     {
1722     case eSemiColon:
1723         return 0;
1724 
1725     case kw_read:
1726 
1727         if ( c -> simple )
1728             break;
1729 
1730         if ( c -> read != NULL )
1731         {
1732             rc = RC ( rcVDB, rcSchema, rcParsing, rcProduction, rcExists );
1733             return KTokenRCExplain ( t, klogErr, rc );
1734         }
1735 
1736         rc = expect ( tbl, src, next_token ( tbl, src, t ), eAssign, "=", true );
1737         if ( rc == 0 )
1738         {
1739             rc = cond_expr ( tbl, src, t, env, self, & c -> read );
1740             if ( rc != 0 )
1741                 KTokenFailure ( t, klogErr, rc, "read expression" );
1742             else
1743             {
1744                 if ( c -> read_only )
1745                     * expected = "}";
1746                 else if ( c -> validate == NULL && c -> limit == NULL )
1747                     * expected = "validate or limit or }";
1748                 else if ( c -> validate == NULL )
1749                     * expected = "validate or }";
1750                 else if ( c -> limit == NULL )
1751                     * expected = "limit or }";
1752                 else
1753                     * expected = "}";
1754                 return 0;
1755             }
1756         }
1757         break;
1758 
1759     case kw_validate:
1760 
1761         if ( c -> read_only || c -> simple )
1762             break;
1763 
1764         if ( c -> validate != NULL )
1765         {
1766             rc = RC ( rcVDB, rcSchema, rcParsing, rcProduction, rcExists );
1767             return KTokenRCExplain ( t, klogErr, rc );
1768         }
1769 
1770         rc = expect ( tbl, src, next_token ( tbl, src, t ), eAssign, "=", true );
1771         if ( rc == 0 )
1772         {
1773             rc = cond_expr ( tbl, src, t, env, self, & c -> validate );
1774             if ( rc != 0 )
1775                 KTokenFailure ( t, klogErr, rc, "validate expression" );
1776             else
1777             {
1778                 if ( c -> read == NULL && c -> limit == NULL )
1779                     * expected = "read or limit or }";
1780                 else if ( c -> read == NULL )
1781                     * expected = "read or }";
1782                 else if ( c -> limit == NULL )
1783                     * expected = "limit or }";
1784                 else
1785                     * expected = "}";
1786                 return 0;
1787             }
1788         }
1789         break;
1790 
1791     case kw_limit:
1792 
1793         if ( c -> read_only )
1794             break;
1795 
1796         if ( c -> limit != NULL )
1797         {
1798             rc = RC ( rcVDB, rcSchema, rcParsing, rcConstraint, rcExists );
1799             return KTokenRCExplain ( t, klogErr, rc );
1800         }
1801 
1802         rc = expect ( tbl, src, next_token ( tbl, src, t ), eAssign, "=", true );
1803         if ( rc == 0 )
1804         {
1805             rc = const_expr ( tbl, src, t, env, self, & c -> limit );
1806             if ( rc != 0 )
1807                 KTokenFailure ( t, klogErr, rc, "limit constraint" );
1808             else
1809             {
1810                 if ( c -> read == NULL && c -> validate == NULL )
1811                     * expected = "read or validate or }";
1812                 else if ( c -> read == NULL )
1813                     * expected = "read or }";
1814                 else if ( c -> validate == NULL )
1815                     * expected = "validate or }";
1816                 else
1817                     * expected = "}";
1818                 return 0;
1819             }
1820         }
1821         break;
1822     }
1823 
1824     return KTokenExpected ( t, klogErr, * expected );
1825 }
1826 
1827 /*
1828  * column-body        = '{' <column-stmts> '}'
1829  * column-stmts       = <column-stmt> ';' [ <column-stmts> ]
1830  */
1831 static
column_body(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SColumn * c)1832 rc_t column_body ( KSymTable *tbl, KTokenSource *src, KToken *t,
1833     const SchemaEnv *env, VSchema *self, SColumn *c )
1834 {
1835     const char *expected;
1836 
1837     rc_t rc = expect ( tbl, src, t, eLeftCurly, "{", true );
1838     if ( rc != 0 )
1839         return rc;
1840 
1841     expected = c -> read_only ? "read or }" :
1842         ( c -> simple ? "limit or }" :  "read or validate or limit or }" );
1843 
1844     while ( t -> id != eRightCurly )
1845     {
1846         rc = column_stmt ( tbl, src, t, env, self, c, & expected );
1847         if ( rc == 0 )
1848             rc = expect ( tbl, src, t, eSemiColon, ";", true );
1849         if ( rc != 0 )
1850             return rc;
1851     }
1852 
1853     if ( c -> read == NULL && c -> validate == NULL )
1854         c -> simple = true;
1855 
1856     return expect ( tbl, src, t, eRightCurly, "}", true );
1857 }
1858 
1859 /*
1860  * column-decl        = <typedecl> ID <column-body>
1861  */
1862 static
typed_column_decl(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,STable * table,SColumn * c)1863 rc_t typed_column_decl ( KSymTable *tbl, KTokenSource *src, KToken *t,
1864     const SchemaEnv *env, VSchema *self, STable *table, SColumn *c )
1865 {
1866     rc_t rc = 0;
1867 
1868     /* if column was forwarded, give it a type */
1869     if ( t -> id == eForward /*|| t -> id == eVirtual */ ) /* a virtual production cannot be resolved into a column */
1870     {
1871         c -> name = t -> sym;
1872         t -> sym -> type = eColumn;
1873     }
1874 
1875     /* catch case where column exists */
1876     else if ( t -> id == eColumn )
1877     {
1878         const SNameOverload *name = t -> sym -> u . obj;
1879         if ( VectorFind ( & name -> items, & c -> td, NULL, SColumnCmp ) != NULL )
1880             return KTokenExpected ( t, klogErr, "new column name" );
1881         c -> name = t -> sym;
1882     }
1883     else
1884     {
1885         /* allow names defined in scopes other than table and intrinsic */
1886         if ( t -> sym != NULL )
1887         {
1888             KTokenSourceReturn ( src, t );
1889             next_shallow_token ( tbl, src, t, true );
1890         }
1891 
1892         if ( t -> id != eIdent )
1893             return KTokenExpected ( t, klogErr, "column name" );
1894 
1895         rc = KSymTableCreateConstSymbol ( tbl, & c -> name, & t -> str, eColumn, NULL );
1896         if ( rc != 0 )
1897             return KTokenRCExplain ( t, klogInt, rc );
1898     }
1899 
1900     /* we have "[ 'readonly' | ... ] 'column' TYPE ID" by now.
1901        accept a simple assignment for read/validate,
1902        or a semi-colon for implicit physical, or a compound
1903        statement body for read/validate/limit statements */
1904     switch ( next_token ( tbl, src, t ) -> id )
1905     {
1906     case eSemiColon:
1907 
1908         /* acceptable unless readonly */
1909         if ( c -> read_only )
1910             rc = KTokenExpected ( t, klogErr, "= or {" );
1911 
1912         /* this looks like a simple column */
1913         c -> simple = true;
1914         break;
1915 
1916     case eAssign:
1917 
1918         /* if a simple column ( implicit physical ),
1919            then there cannot be a read expression */
1920         if ( c -> simple )
1921             rc = KTokenExpected ( t, klogErr, "; after simple column" );
1922         else
1923         {
1924             /* simple read expression */
1925             next_token ( tbl, src, t );
1926             rc = cond_expr ( tbl, src, t, env, self, & c -> read );
1927             if ( rc != 0 )
1928                 KTokenFailure ( t, klogErr, rc, "read expression" );
1929             else
1930                 rc = expect ( tbl, src, t, eSemiColon, ";", true );
1931         }
1932         break;
1933 
1934     case eLeftCurly:
1935         /* this is a canonical-form column */
1936         rc = column_body ( tbl, src, t, env, self, c );
1937         break;
1938 
1939     default:
1940         rc = KTokenExpected ( t, klogErr, c -> read_only ? "= or {" : "; or = or {" );
1941     }
1942 
1943     /* check for a simple column */
1944     if ( rc == 0 && c -> simple )
1945     {
1946         String physname;
1947         char physnamebuff [ 256 ];
1948 
1949         /* check for existence of corresponding physical member */
1950         if ( c -> name -> name . size >= sizeof physnamebuff )
1951         {
1952             /* this is a very long column name... */
1953             rc = RC ( rcVDB, rcSchema, rcParsing, rcName, rcExcessive );
1954             KTokenFailure ( t, klogErr, rc, "column name" );
1955         }
1956         else
1957         {
1958             KSymbol *sym;
1959 
1960             /* tack a dot onto the beginning and look up the symbol */
1961             physnamebuff [ 0 ] = '.';
1962             memmove ( & physnamebuff [ 1 ], c -> name -> name . addr, c -> name -> name . size );
1963             StringInit ( & physname, physnamebuff, c -> name -> name . size + 1, c -> name -> name . len + 1 );
1964             sym = KSymTableFind ( tbl, & physname );
1965 
1966             /* if the symbol exists, then this CANNOT be a simple column */
1967             if ( sym != NULL && ! ( sym -> type == eForward || sym -> type == eVirtual ) )
1968             {
1969                 /* check for explicit physical type */
1970                 if ( c -> ptype != NULL )
1971                 {
1972                     rc = RC ( rcVDB, rcSchema, rcParsing, rcName, rcExists );
1973                     KTokenFailure ( t, klogErr, rc, "implicit physical column previously declared" );
1974                 }
1975                 else
1976                 {
1977                     rc = RC ( rcVDB, rcSchema, rcParsing, rcExpression, rcNotFound );
1978                     KTokenFailure ( t, klogErr, rc, "missing column read or validate expression" );
1979                 }
1980             }
1981             else if ( ( c -> td . type_id & 0xC0000000 ) != 0 )
1982             {
1983                 rc = RC ( rcVDB, rcSchema, rcParsing, rcType, rcIncorrect );
1984                 KTokenFailure ( t, klogErr, rc, "simple columns cannot have typeset as type" );
1985             }
1986             else
1987             {
1988                 if ( sym != NULL )
1989                     sym -> type = ePhysMember;
1990                 else
1991                 {
1992                     rc = KSymTableCreateSymbol ( tbl, & sym, & physname, ePhysMember, NULL );
1993                     if ( rc != 0 )
1994                         KTokenFailure ( t, klogErr, rc, "failed to create symbol" );
1995                 }
1996                 if ( rc == 0 )
1997                 {
1998                     rc = implicit_physical_member ( tbl, env, table, c, sym );
1999                 }
2000             }
2001         }
2002     }
2003 
2004     return rc;
2005 }
2006 
2007 static
column_decl(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,STable * table,SColumn * c)2008 rc_t column_decl ( KSymTable *tbl, KTokenSource *src, KToken *t,
2009     const SchemaEnv *env, VSchema *self, STable *table, SColumn *c )
2010 {
2011     rc_t rc;
2012 
2013     /* intercept physical type unless marked read-only */
2014     if ( ! c -> read_only )
2015     {
2016         switch ( t -> id )
2017         {
2018         case eNamespace:
2019             rc = next_fqn ( tbl, src, t, env );
2020             if ( rc != 0 )
2021                 return KTokenFailure ( t, klogErr, rc, "typename or physical column type" );
2022             if ( t -> id != ePhysical )
2023                 break;
2024         case ePhysical:
2025         case eLeftAngle:
2026             rc = phys_encoding_expr ( tbl, src, t, env, self, & c -> td, & c -> ptype );
2027             if ( rc != 0 )
2028                 return KTokenFailure ( t, klogErr, rc, "typename or physical column type" );
2029 
2030             /* this column MUST be simple */
2031             c -> simple = true;
2032             return typed_column_decl ( tbl, src, t, env, self, table, c );
2033         }
2034     }
2035 
2036 #if ALLOW_COLUMN_TYPESET
2037     /* read typedecl or typeset */
2038     rc = typespec ( tbl, src, t, env, self, & c -> td );
2039 #else
2040     /* read hard typedecl */
2041     rc = typedecl ( tbl, src, t, env, self, & c -> td );
2042 #endif
2043     if ( rc != 0 )
2044         return KTokenExpected ( t, klogErr, "column type" );
2045 
2046     /* finish the parse with a normal type */
2047     return typed_column_decl ( tbl, src, t, env, self, table, c );
2048 }
2049 
2050 static
column_declaration(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,STable * table)2051 rc_t column_declaration ( KSymTable *tbl, KTokenSource *src, KToken *t,
2052     const SchemaEnv *env, VSchema *self, STable *table )
2053 {
2054     rc_t rc;
2055     SColumn *c;
2056     bool dflt, read_only;
2057 
2058     /* parse 'virtual' and 'default' keywords */
2059     for ( dflt = read_only = false;
2060           t -> id != kw_column; next_token ( tbl, src, t ) )
2061     {
2062         switch ( t -> id )
2063         {
2064         case kw_default:
2065             if ( dflt )
2066                 break;
2067             dflt = true;
2068             continue;
2069 
2070         case kw_extern:
2071             continue;
2072 
2073         case kw_readonly:
2074             if ( read_only )
2075                 break;
2076             read_only = true;
2077             continue;
2078         }
2079 
2080         return KTokenExpected ( t, klogErr, "column" );
2081     }
2082 
2083     /* consume 'column' keyword and look for 'default' or 'limit' */
2084     switch ( next_token ( tbl, src, t ) -> id )
2085     {
2086     case kw_default:
2087     {
2088         KToken t2 = * t;
2089         KTokenSource src2 = * src;
2090         if ( next_token ( tbl, src, t ) -> id != kw_limit )
2091         {
2092             * t = t2;
2093             * src = src2;
2094             break;
2095         }
2096     }
2097     case kw_limit:
2098 
2099         if ( dflt || read_only )
2100             break;
2101 
2102         if ( table -> limit != NULL )
2103         {
2104             rc = RC ( rcVDB, rcSchema, rcParsing, rcConstraint, rcExists );
2105             return KTokenRCExplain ( t, klogErr, rc );
2106         }
2107 
2108         rc = expect ( tbl, src, next_token ( tbl, src, t ), eAssign, "=", true );
2109         if ( rc == 0 )
2110         {
2111             rc = const_expr ( tbl, src, t, env, self, & table -> limit );
2112             if ( rc != 0 )
2113                 KTokenFailure ( t, klogErr, rc, "limit constraint" );
2114             else
2115                 rc = expect ( tbl, src, t, eSemiColon, ";", true );
2116         }
2117         return rc;
2118     }
2119 
2120     /* create column object */
2121     c = malloc ( sizeof * c );
2122     if ( c == NULL )
2123     {
2124         rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
2125         return KTokenRCExplain ( t, klogInt, rc );
2126     }
2127 
2128     memset ( c, 0, sizeof * c );
2129     c -> dflt = dflt;
2130     c -> read_only = read_only;
2131 
2132     /* parse decl */
2133     rc = column_decl ( tbl, src, t, env, self, table, c );
2134     if ( rc == 0 )
2135     {
2136         /* give column its own id within table */
2137         rc = VectorAppend ( & table -> col, & c -> cid . id, c );
2138         if ( rc != 0 )
2139             KTokenRCExplain ( t, klogInt, rc );
2140         else
2141         {
2142             void *ignore;
2143             SNameOverload *name = ( void* ) c -> name -> u . obj;
2144             if ( name == NULL )
2145             {
2146                 rc = SNameOverloadMake ( & name, c -> name, 0, 4 );
2147                 if ( rc == 0 )
2148                 {
2149                     name -> cid . ctx = -1;
2150                     rc = VectorAppend ( & table -> cname, & name -> cid . id, name );
2151                     if ( rc != 0 )
2152                         SNameOverloadWhack ( name, NULL );
2153                 }
2154             }
2155 
2156             if ( rc == 0 )
2157             {
2158                 rc = VectorInsertUnique ( & name -> items, c, NULL, SColumnSort );
2159                 if ( rc == 0 )
2160                     return 0;
2161             }
2162 
2163             /* reverse column insertion */
2164             VectorSwap ( & table -> col, c -> cid . id, NULL, & ignore );
2165 
2166             /* what went wrong */
2167             KTokenRCExplain ( t, klogInt, rc );
2168         }
2169     }
2170 
2171     SColumnWhack ( c, NULL );
2172     return rc;
2173 }
2174 #endif
2175 
2176 #if SLVL >= 6
2177 
2178 static
untyped_tbl_expr(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,STable * table)2179 rc_t untyped_tbl_expr ( KSymTable *tbl, KTokenSource *src, KToken *t,
2180     const SchemaEnv *env, VSchema *self, STable *table )
2181 {
2182     const SNameOverload *name;
2183 
2184     /* expecting a function assignment */
2185     rc_t rc = expect ( tbl, src,
2186         next_token ( tbl, src, t ), eAssign, "=", true );
2187     if ( rc == 0 )
2188         rc = next_fqn ( tbl, src, t, env );
2189     if ( rc != 0 )
2190         return rc;
2191     if ( t -> id != eUntypedFunc )
2192         return KTokenExpected ( t, klogErr, "untyped function expression" );
2193     name = t -> sym -> u . obj;
2194 
2195     rc = expect ( tbl, src,
2196         next_token ( tbl, src, t ), eLeftParen, "(", true );
2197     if ( rc == 0 )
2198         rc = expect ( tbl, src, t, eRightParen, ")", true );
2199     if ( rc == 0 )
2200         rc = expect ( tbl, src, t, eSemiColon, ";", true );
2201 
2202     if ( rc == 0 )
2203     {
2204         table -> untyped = VectorLast ( & name -> items );
2205         if ( table -> untyped == NULL )
2206         {
2207             rc = RC ( rcVDB, rcSchema, rcParsing, rcFunction, rcNotFound );
2208             KTokenRCExplain ( t, klogErr, rc );
2209         }
2210     }
2211 
2212     return rc;
2213 }
2214 
2215 #if SLVL >= 8
2216 static
default_view_decl(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,STable * table)2217 rc_t default_view_decl ( KSymTable *tbl, KTokenSource *src, KToken *t,
2218     const SchemaEnv *env, VSchema *self, STable *table )
2219 {
2220     rc_t rc;
2221     bool string_too_long;
2222 
2223     if ( next_token ( tbl, src, t ) -> id != eString )
2224         return KTokenExpected ( t, klogErr, "default view declaration" );
2225 
2226     string_too_long = false;
2227     if ( t -> str . size >= 236 + 2 )
2228     {
2229         KTokenExpected ( t, klogWarn, "default view declaration less than 236 characters" );
2230         string_too_long = true;
2231     }
2232 
2233     rc = expect ( tbl, src, t, eSemiColon, ";", true );
2234     if ( rc == 0 && ! string_too_long )
2235     {
2236         String decl = t -> str;
2237         ++ decl . addr;
2238         decl . size -= 2;
2239         decl . len -= 2;
2240 
2241         if ( table -> dflt_view != NULL )
2242             StringWhack ( table -> dflt_view );
2243 
2244         rc = StringCopy ( & table -> dflt_view, & decl );
2245     }
2246 
2247     return rc;
2248 }
2249 #endif
2250 
2251 /*
2252  * table-local-decl   = [ 'virtual' ] 'column' <column-decl>
2253  *                    | 'physical' [ 'column' ] <physical-decl>
2254  *                    | <production_stmt>
2255  */
2256 static
table_local_decl(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,STable * table)2257 rc_t table_local_decl ( KSymTable *tbl, KTokenSource *src, KToken *t,
2258     const SchemaEnv *env, VSchema *self, STable *table )
2259 {
2260     rc_t rc;
2261 
2262     switch ( t -> id )
2263     {
2264 #if SLVL >= 8
2265     case kw_default:
2266         if ( env -> default_view_decl )
2267         {
2268             KToken t2;
2269             if ( next_token ( tbl, src, & t2 ) -> id == kw_view )
2270                 return default_view_decl ( tbl, src, t, env, self, table );
2271              KTokenSourceReturn ( src, & t2 );
2272         }
2273         /* no break */
2274     case kw_extern:
2275     case kw_column:
2276     case kw_readonly:
2277         return column_declaration ( tbl, src, t, env, self, table );
2278 #endif
2279 #if SLVL >= 7
2280     case kw_static:
2281     case kw_physical:
2282         return physical_member ( tbl, src, t, env, self, table );
2283 #endif
2284     case kw___untyped:
2285         return untyped_tbl_expr ( tbl, src, t, env, self, table );
2286 #if 0
2287     case kw_index:
2288         break;
2289 #endif
2290     case eSemiColon:
2291         next_token ( tbl, src, t );
2292         rc = 0;
2293         break;
2294 
2295     default:
2296         rc = production_stmt ( tbl, src, t, env, self, & table -> prod, eTable );
2297         if ( rc == 0 )
2298             rc = expect ( tbl, src, t, eSemiColon, ";", true );
2299     }
2300 
2301     return rc;
2302 }
2303 
2304 /*
2305  * table-body         = '{' [ <table-decl-list> ] '}'
2306  *
2307  * table-decl-list    = <tbl-local-decl> ';' [ <table-decl-list> ]
2308  */
2309 
table_fwd_scan(BSTNode * n,void * data)2310 bool CC table_fwd_scan ( BSTNode *n, void *data )
2311 {
2312     STableScanData *pb = data;
2313     KSymbol *sym = ( KSymbol* ) n;
2314     STable *self = pb -> self;
2315 
2316     /* process forwarded symbols */
2317     if ( sym -> type == eForward )
2318     {
2319         /* this symbol was introduced in THIS table */
2320         sym -> u . fwd . ctx = self -> id;
2321 
2322         /* add it to the introduced virtual productions and make it virtual */
2323         pb -> rc = VectorAppend ( & self -> vprods, & sym -> u . fwd . id, sym );
2324         if ( pb -> rc != 0 )
2325             return true;
2326         sym -> type = eVirtual;
2327     }
2328     /* symbols other than fwd or virtual are ignored */
2329     else if ( sym -> type != eVirtual )
2330     {
2331         return false;
2332     }
2333 
2334     /* add symbol to vector to track ownership */
2335     pb -> rc = VectorAppend ( & self -> syms, NULL, sym );
2336     if ( pb -> rc != 0 )
2337         return true;
2338 
2339     /* remove from symbol table */
2340     BSTreeUnlink ( & self -> scope, & sym -> n );
2341     return false;
2342 }
2343 
2344 static
table_body(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,STable * table)2345 rc_t table_body ( KSymTable *tbl, KTokenSource *src, KToken *t,
2346     const SchemaEnv *env, VSchema *self, STable *table )
2347 {
2348     rc_t rc = expect ( tbl, src, t, eLeftCurly, "{", true );
2349     if ( rc != 0 )
2350         return rc;
2351 
2352     while ( t -> id != eRightCurly )
2353     {
2354         rc = table_local_decl ( tbl, src, t, env, self, table );
2355         if ( rc != 0 )
2356             return rc;
2357     }
2358 
2359     rc = expect ( tbl, src, t, eRightCurly, "}", true );
2360     if ( rc == 0 )
2361     {
2362         STableScanData pb;
2363         pb . self = table;
2364         pb . rc = 0;
2365 
2366         /* scan table scope for unresolved forward references */
2367         if ( BSTreeDoUntil ( & table -> scope, false, table_fwd_scan, & pb ) )
2368             KTokenRCExplain ( t, klogInt, rc = pb . rc );
2369     }
2370 
2371     return rc;
2372 }
2373 
2374 /*
2375  * table-syntax
2376  */
2377 static
table_prod_syntax(void * item,void * data)2378 bool CC table_prod_syntax ( void *item, void *data )
2379 {
2380     rc_t *rc = data;
2381     const SProduction *prod = ( const SProduction* ) item;
2382 
2383     if ( ! prod -> trigger )
2384         * rc = eval_expr_syntax ( prod -> fd );
2385     if ( * rc == 0 )
2386         * rc = eval_expr_syntax ( prod -> expr );
2387 
2388     return ( * rc != 0 ) ? true : false;
2389 }
2390 
2391 static
table_stmt_syntax(const STable * table)2392 rc_t table_stmt_syntax ( const STable *table )
2393 {
2394     rc_t rc = 0;
2395     VectorDoUntil ( & table -> prod, false, table_prod_syntax, & rc );
2396     return rc;
2397 }
2398 
2399 #if SLVL >= 8
2400 static
table_typed_column_syntax(void * item,void * data)2401 bool CC table_typed_column_syntax ( void *item, void *data )
2402 {
2403     rc_t *rc = data;
2404     const SColumn *col = ( const SColumn* ) item;
2405 
2406     if ( col -> read != NULL )
2407         * rc = eval_expr_syntax ( col -> read );
2408     if ( * rc == 0 && col -> validate != NULL )
2409         * rc = eval_expr_syntax ( col -> validate );
2410     if ( * rc == 0 && col -> limit != NULL )
2411         * rc = eval_expr_syntax ( col -> limit );
2412 
2413     return ( * rc != 0 ) ? true : false;
2414 }
2415 
2416 static
table_column_syntax(const STable * table)2417 rc_t table_column_syntax ( const STable *table )
2418 {
2419     rc_t rc = 0;
2420     VectorDoUntil ( & table -> col, false, table_typed_column_syntax, & rc );
2421     return rc;
2422 }
2423 #endif
2424 
2425 #if SLVL >= 7
2426 static
table_physcol_syntax(void * item,void * data)2427 bool CC table_physcol_syntax ( void *item, void *data )
2428 {
2429     rc_t *rc = data;
2430     const SPhysMember *col = ( const SPhysMember* ) item;
2431 
2432     if ( col -> expr == NULL )
2433         return false;
2434 
2435     * rc = eval_expr_syntax ( col -> expr );
2436     return ( * rc != 0 ) ? true : false;
2437 }
2438 
2439 static
table_physical_syntax(const STable * table)2440 rc_t table_physical_syntax ( const STable *table )
2441 {
2442     rc_t rc = 0;
2443     VectorDoUntil ( & table -> phys, false, table_physcol_syntax, & rc );
2444     return rc;
2445 }
2446 #endif
2447 
2448 rc_t
table_fix_forward_refs(const STable * table)2449 table_fix_forward_refs ( const STable *table )
2450 {
2451     rc_t rc = table_stmt_syntax ( table );
2452 #if SLVL >= 8
2453     if ( rc == 0 )
2454         rc = table_column_syntax ( table );
2455 #endif
2456 #if SLVL >= 7
2457     if ( rc == 0 )
2458         rc = table_physical_syntax ( table );
2459 #endif
2460     return rc;
2461 }
2462 
2463 /*
2464  * push-tbl-scope
2465  * pop-tbl-scope
2466  */
pop_tbl_scope(KSymTable * tbl,const STable * table)2467 void pop_tbl_scope ( KSymTable *tbl, const STable *table )
2468 {
2469     uint32_t i, count = VectorLength ( & table -> overrides );
2470     for ( ++ count, i = 0; i < count; ++ i )
2471         KSymTablePopScope ( tbl );
2472 }
2473 
push_tbl_scope(KSymTable * tbl,const STable * table)2474 rc_t push_tbl_scope ( KSymTable *tbl, const STable *table )
2475 {
2476     rc_t rc;
2477     uint32_t i = VectorStart ( & table -> overrides );
2478     uint32_t count = VectorLength ( & table -> overrides );
2479     for ( count += i; i < count; ++ i )
2480     {
2481         const STableOverrides *to = ( const void* ) VectorGet ( & table -> overrides, i );
2482         rc = KSymTablePushScope ( tbl, ( BSTree* ) & to -> dad -> scope );
2483         if ( rc != 0 )
2484         {
2485             for ( count = VectorStart ( & table -> overrides ); i > count; -- i )
2486                 KSymTablePopScope ( tbl );
2487             return rc;
2488         }
2489     }
2490 
2491     rc = KSymTablePushScope ( tbl, ( BSTree* ) & table -> scope );
2492     if ( rc != 0 )
2493     {
2494         for ( i = VectorStart ( & table -> overrides ); i < count; ++ i )
2495             KSymTablePopScope ( tbl );
2496     }
2497 
2498     return rc;
2499 }
2500 
2501 /*
2502  * init-tbl-symtab
2503  *  initializes "tbl"
2504  *  places table in scope
2505  *  must be balanced by KSymTableWhack
2506  */
init_tbl_symtab(KSymTable * tbl,const VSchema * schema,const STable * table)2507 rc_t init_tbl_symtab ( KSymTable *tbl, const VSchema *schema, const STable *table )
2508 {
2509     rc_t rc = init_symtab ( tbl, schema );
2510     if ( rc == 0 )
2511     {
2512         rc = push_tbl_scope ( tbl, table );
2513         if ( rc == 0 )
2514             return 0;
2515 
2516         KSymTableWhack ( tbl );
2517     }
2518 
2519     return rc;
2520 }
2521 
2522 
2523 /*
2524  * table-decl         = 'table' <fqn> '#' <maj-min-rel>
2525  *                      [ '=' <table-name> ] <table-body>
2526  * table-body         = '{' [ <table-stmts> ] '}'
2527  * table-stmts        = <table-stmt> ';' [ <table-stmts> ]
2528  */
2529 static
table_decl(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,STable * table)2530 rc_t table_decl ( KSymTable *tbl, KTokenSource *src, KToken *t,
2531     const SchemaEnv *env, VSchema *self, STable *table )
2532 {
2533     /* table name */
2534     rc_t rc = create_fqn ( tbl, src, t, env, eTable, NULL );
2535     if ( rc != 0 && GetRCState ( rc ) != rcExists )
2536         return KTokenFailure ( t, klogErr, rc, "table name" );
2537     table -> name = t -> sym;
2538     table -> src_file = t -> txt -> path;
2539     table -> src_line = t -> lineno;
2540 
2541     /* table version */
2542     if ( next_token ( tbl, src, t ) -> id != eHash )
2543         return KTokenExpected ( t, klogErr, "#" );
2544     next_token ( tbl, src, t );
2545     rc = maj_min_rel ( tbl, src, t, env, self, & table -> version, true );
2546     if ( rc != 0 )
2547         return rc;
2548 
2549     /* prepare vectors */
2550     VectorInit ( & table -> parents, 0, 4 );
2551     VectorInit ( & table -> overrides, 0, 4 );
2552     VectorInit ( & table -> col, 0, 16 );
2553     VectorInit ( & table -> cname, 0, 16 );
2554     VectorInit ( & table -> phys, 0, 16 );
2555     VectorInit ( & table -> prod, 0, 64 );
2556     VectorInit ( & table -> vprods, 1, 16 );
2557     VectorInit ( & table -> syms, 1, 32 );
2558 
2559     /* look for inheritance */
2560     if ( t -> id == eAssign ) do
2561     {
2562         const STable *dad;
2563         const SNameOverload *name;
2564 
2565         /* look for dad */
2566         rc = next_fqn ( tbl, src, next_token ( tbl, src, t ), env );
2567         if ( rc != 0 )
2568             return KTokenFailure ( t, klogErr, rc, "table name" );
2569 
2570         /* insist that dad be a table */
2571         if ( t -> id != eTable )
2572             return KTokenExpected ( t, klogErr, "table name" );
2573         name = t -> sym -> u . obj;
2574 
2575         /* check for version */
2576         if ( next_token ( tbl, src, t ) -> id != eHash )
2577             dad = VectorLast ( & name -> items );
2578         else
2579         {
2580             uint32_t vers;
2581             next_token ( tbl, src, t );
2582             rc = maj_min_rel ( tbl, src, t, env, self, & vers, true );
2583             if ( rc != 0 )
2584                 return rc;
2585             dad = VectorFind ( & name -> items, & vers, NULL, STableCmp );
2586 #if _DEBUGGING && 1
2587             if ( dad != NULL && dad -> version > vers )
2588             {
2589                 PLOGMSG ( klogInfo, ( klogInfo
2590                                       , "table_decl: table '$(tbl)' specifies parent table '$(parent)' - should be $(actual_version)"
2591                                       , "tbl=%N#%.3V,parent=%N#%.3V,actual_version=#%.3V"
2592                                       , table -> name, table -> version
2593                                       , dad -> name, vers
2594                                       , dad -> version
2595                               ));
2596             }
2597 #endif
2598         }
2599 
2600         /* dad should be found */
2601         if ( dad == NULL )
2602         {
2603             rc = RC ( rcVDB, rcSchema, rcParsing, rcTable, rcNotFound );
2604             return KTokenRCExplain ( t, klogErr, rc );
2605         }
2606 
2607         /* take the inheritance */
2608         rc = STableExtend ( tbl, table, dad );
2609         if ( rc != 0 )
2610             return KTokenRCExplain ( t, klogInt, rc );
2611     }
2612     while ( t -> id == eComma );
2613 
2614     /* enter table into scope */
2615     rc = push_tbl_scope ( tbl, table );
2616     if ( rc == 0 )
2617     {
2618         /* scan override tables for virtual symbols */
2619         if ( VectorDoUntil ( & table -> overrides, false, STableScanVirtuals, tbl ) )
2620             rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
2621 
2622         /* parse the definition */
2623         else
2624             rc = table_body ( tbl, src, t, env, self, table );
2625 
2626         /* pop out of scope */
2627         pop_tbl_scope ( tbl, table );
2628     }
2629 
2630     /* fix forward references */
2631     if ( rc == 0 )
2632     {
2633         rc = table_fix_forward_refs ( table );
2634     }
2635 
2636     return rc;
2637 }
2638 
2639 static
column_set_context(void * item,void * data)2640 void CC column_set_context ( void *item, void *data )
2641 {
2642     SColumn *self = item;
2643     self -> cid . ctx = * ( const uint32_t* ) data;
2644 }
2645 
2646 static
name_set_context(void * item,void * data)2647 void CC name_set_context ( void *item, void *data )
2648 {
2649     SNameOverload *self = item;
2650     if ( ( int32_t ) self -> cid . ctx < 0 )
2651         self -> cid . ctx = * ( const uint32_t* ) data;
2652 }
2653 
2654 static
physical_set_context(void * item,void * data)2655 void CC physical_set_context ( void *item, void *data )
2656 {
2657     SPhysMember *self = item;
2658     self -> cid . ctx = * ( const uint32_t* ) data;
2659 }
2660 
2661 static
production_set_context(void * item,void * data)2662 void CC production_set_context ( void *item, void *data )
2663 {
2664     SProduction *self = item;
2665     self -> cid . ctx = * ( const uint32_t* ) data;
2666 }
2667 
2668 static
symbol_set_context(void * item,void * data)2669 void CC symbol_set_context ( void *item, void *data )
2670 {
2671     KSymbol *self = item;
2672     self -> u . fwd . ctx = * ( const uint32_t* ) data;
2673 }
2674 
table_set_context(STable * self,uint32_t p_ctxId)2675 void CC table_set_context ( STable *self, uint32_t p_ctxId )
2676 {
2677     VectorForEach ( & self -> col, false, column_set_context, & p_ctxId );
2678     VectorForEach ( & self -> cname, false, name_set_context, & p_ctxId );
2679     VectorForEach ( & self -> phys, false, physical_set_context, & p_ctxId );
2680     VectorForEach ( & self -> prod, false, production_set_context, & p_ctxId );
2681     VectorForEach ( & self -> vprods, false, symbol_set_context, & p_ctxId );
2682 }
2683 
2684 #if NO_UPDATE_TBL_REF || 0
schema_update_tbl_ref(VSchema *,const STable *,const STable *)2685 rc_t CC schema_update_tbl_ref ( VSchema *, const STable *, const STable * )
2686 {
2687     return 0;
2688 }
2689 #else
2690 typedef struct update_tbl_ref_data update_tbl_ref_data;
2691 struct update_tbl_ref_data
2692 {
2693     const STable *exist, *table;
2694     rc_t rc;
2695 };
2696 
2697 static
table_update_tbl_ref(void * item,void * data)2698 bool CC table_update_tbl_ref ( void *item, void *data )
2699 {
2700     STable *self = item;
2701     update_tbl_ref_data *pb = data;
2702 
2703     bool is_ancestor;
2704 
2705     /* check for having this guy as an immediate parent */
2706     uint32_t i = VectorStart ( & self -> parents );
2707     uint32_t count = VectorLength ( & self -> parents );
2708     for ( count += i; i < count; ++ i )
2709     {
2710         STable *dad = VectorGet ( & self -> parents, i );
2711         if ( ( const STable* ) dad == pb -> exist )
2712         {
2713             void *ignore;
2714             VectorSwap ( & self -> parents, i, pb -> table, & ignore );
2715             PARSE_DEBUG (( "table_update_tbl_ref: replaced parent '%N#%.3V' with version #%.3V in table '%N#%.3V'.\n"
2716                            , dad -> name, dad -> version
2717                            , pb -> table -> version
2718                            , self -> name, self -> version
2719                 ));
2720             break;
2721         }
2722     }
2723 
2724     /* check for having him in the ancestry somewhere */
2725     i = VectorStart ( & self -> overrides );
2726     count = VectorLength ( & self -> overrides );
2727     for ( is_ancestor = false, count += i; i < count; ++ i )
2728     {
2729         STableOverrides *to = VectorGet ( & self -> overrides, i );
2730         if ( to -> dad == pb -> exist )
2731         {
2732             is_ancestor = true;
2733 
2734             /* rewrite overrides to have updated parent */
2735             VectorWhack ( & to -> by_parent, NULL, NULL );
2736             pb -> rc = VectorCopy ( & pb -> table -> vprods, & to -> by_parent );
2737             if ( pb -> rc != 0 )
2738                 return true;
2739             to -> dad = pb -> table;
2740             to -> ctx = pb -> table -> id;
2741             VectorReorder ( & self -> overrides, STableOverridesKSort, NULL );
2742             PARSE_DEBUG (( "table_update_tbl_ref: replaced ancestor '%N#%.3V' with version #%.3V in table '%N#%.3V'.\n"
2743                            , pb -> exist -> name, pb -> exist -> version
2744                            , pb -> table -> version
2745                            , self -> name, self -> version
2746                 ));
2747         }
2748     }
2749 
2750     /* if he's not an ancestor, we're done */
2751     if ( ! is_ancestor )
2752         return false;
2753 
2754     /* remove columns from old parent */
2755     i = VectorStart ( & self -> cname );
2756     count = VectorLength ( & self -> cname );
2757     for ( count += i; i < count; ++ i )
2758     {
2759         Vector cv;
2760         uint32_t cx, cnt;
2761         SNameOverload *name = VectorGet ( & self -> cname, i );
2762 
2763         /* names originating in existing parent get mapped */
2764         if ( name -> cid . ctx == pb -> exist -> id )
2765         {
2766             name -> cid . ctx = pb -> table -> id;
2767             PARSE_DEBUG (( "table_update_tbl_ref: updated context of column name '%N' from %u to %u.\n"
2768                            , name -> name
2769                            , pb -> exist -> id
2770                            , pb -> table -> id
2771                 ));
2772         }
2773 
2774         /* now copy over columns, but eliminate all from old parent */
2775         cx = VectorStart ( & name -> items );
2776         cnt = VectorLength ( & name -> items );
2777         VectorInit ( & cv, cx, cnt );
2778         for ( cnt += cx; cx < cnt; ++ cx )
2779         {
2780             SColumn *c = VectorGet ( & name -> items, cx );
2781             if ( c -> cid . ctx == pb -> exist -> id )
2782             {
2783                 PARSE_DEBUG (( "table_update_tbl_ref: dropping column index %u from name '%N'.\n"
2784                                , cx
2785                                , name -> name
2786                     ));
2787             }
2788             else
2789             {
2790                 pb -> rc = VectorAppend ( & cv, NULL, c );
2791                 if ( pb -> rc != 0 )
2792                     return true;
2793             }
2794         }
2795         VectorWhack ( & name -> items, NULL, NULL );
2796         name -> items = cv;
2797     }
2798 
2799     /* add in all columns from new parent */
2800     if ( VectorDoUntil ( & pb -> table -> cname, false, STableCopyColumnNames, self ) )
2801     {
2802         pb -> rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
2803         return true;
2804     }
2805 
2806     return false;
2807 }
2808 
2809 static
tblmbr_update_tbl_ref(void * item,void * data)2810 bool CC tblmbr_update_tbl_ref ( void *item, void *data )
2811 {
2812     STblMember *self = item;
2813     update_tbl_ref_data *pb = data;
2814 
2815     if ( self -> tbl == pb -> exist )
2816     {
2817         PARSE_DEBUG (( "tblmbr_update_tbl_ref: updated table member '%N %N' from %V to %V.\n"
2818                        , pb -> exist -> name
2819                        , self -> name
2820                        , pb -> exist -> version
2821                        , pb -> table -> version
2822                 ));
2823         self -> tbl = pb -> table;
2824     }
2825 
2826     return false;
2827 }
2828 
2829 static
db_update_tbl_ref(void * item,void * data)2830 bool CC db_update_tbl_ref ( void *item, void *data )
2831 {
2832     SDatabase *self = item;
2833 
2834     /* update table members */
2835     if ( VectorDoUntil ( & self -> tbl, false, tblmbr_update_tbl_ref, data ) )
2836         return true;
2837 
2838     return VectorDoUntil ( & self -> db, false, db_update_tbl_ref, data );
2839 }
2840 
schema_update_tbl_ref(VSchema * self,const STable * exist,const STable * table)2841 rc_t schema_update_tbl_ref ( VSchema *self, const STable *exist, const STable *table )
2842 {
2843     update_tbl_ref_data pb;
2844     pb . exist = exist;
2845     pb . table = table;
2846     pb . rc = 0;
2847 
2848     if ( ! VectorDoUntil ( & self -> tbl, false, table_update_tbl_ref, & pb ) )
2849           VectorDoUntil ( & self -> db, false, db_update_tbl_ref, & pb );
2850 
2851     return pb . rc;
2852 }
2853 #endif
2854 
table_declaration(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self)2855 rc_t table_declaration ( KSymTable *tbl, KTokenSource *src, KToken *t,
2856     const SchemaEnv *env, VSchema *self )
2857 {
2858     rc_t rc;
2859     void *ignore;
2860 
2861     STable *table = calloc ( 1, sizeof * table );
2862     if ( table == NULL )
2863     {
2864         rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
2865         return KTokenRCExplain ( t, klogInt, rc );
2866     }
2867 
2868     rc = table_decl ( tbl, src, t, env, self, table );
2869     if ( rc == 0 )
2870     {
2871         SNameOverload *name = ( void* ) table -> name -> u . obj;
2872         if ( name == NULL )
2873         {
2874             rc = SNameOverloadMake ( & name, table -> name, 0, 4 );
2875             if ( rc == 0 )
2876             {
2877                 rc = VectorAppend ( & self -> tname, & name -> cid . id, name );
2878                 if ( rc != 0 )
2879                     SNameOverloadWhack ( name, NULL );
2880             }
2881         }
2882 
2883         if ( rc == 0 )
2884         {
2885             rc = VectorAppend ( & self -> tbl, & table -> id, table );
2886             if ( rc == 0 )
2887             {
2888                 uint32_t idx;
2889 
2890                 /* set the table context id on all members */
2891                 table_set_context ( table, table -> id );
2892 
2893                 /* add to named table overrides */
2894                 rc = VectorInsertUnique ( & name -> items, table, & idx, STableSort );
2895                 if ( rc == 0 )
2896                     return 0;
2897 
2898                 if ( GetRCState ( rc ) == rcExists )
2899                 {
2900                     const STable *newer;
2901                     STable *exist = VectorGet ( & name -> items, idx );
2902                     rc = STableCompare ( exist, table, & newer, false );
2903                     if ( rc == 0 && newer == table )
2904                     {
2905                         /* put the new one in place of the existing */
2906                         VectorSwap ( & name -> items, idx, table, & ignore );
2907 
2908                         /* tell everyone to use new table */
2909                         return schema_update_tbl_ref ( self, exist, table );
2910                     }
2911                 }
2912 
2913                 VectorSwap ( & self -> tbl, table -> id, NULL, & ignore );
2914             }
2915         }
2916     }
2917     else if ( GetRCState ( rc ) == rcExists )
2918     {
2919         rc = 0;
2920     }
2921 
2922     STableWhack ( table, NULL );
2923 
2924     return rc;
2925 }
2926 
2927 #endif
2928