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