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 <klib/symtab.h>
30 #include <klib/rc.h>
31 #include <klib/symbol.h>
32 
33 #include "schema-priv.h"
34 #include "schema-parse.h"
35 
36 /* Cmp
37  * Sort
38  */
39 int64_t
SViewOverridesCmp(const void * item,const void * n)40 SViewOverridesCmp ( const void *item, const void *n )
41 {
42     const uint32_t *a = item;
43     const SViewOverrides *b = n;
44 
45     return ( int64_t ) * a - ( int64_t ) b -> ctx;
46 }
47 
48 static
49 int64_t
SViewOverridesSort(const void * item,const void * n)50 SViewOverridesSort ( const void *item, const void *n )
51 {
52     const SViewOverrides *a = item;
53     const SViewOverrides *b = n;
54 
55     return ( int64_t ) a -> ctx - ( int64_t ) b -> ctx;
56 }
57 
58 /* Whack
59  */
60 static
61 void
SViewOverridesWhack(void * item,void * ignore)62 SViewOverridesWhack ( void *item, void *ignore )
63 {
64     SViewOverrides *self = item;
65     VectorWhack ( & self -> by_parent, NULL, NULL );
66     free ( self );
67 }
68 
69 /* Make
70  */
71 rc_t
SViewOverridesMake(Vector * parents,const SView * dad,const Vector * overrides)72 SViewOverridesMake ( Vector *parents, const SView *dad, const Vector *overrides )
73 {
74     rc_t rc;
75     SViewOverrides *to;
76 
77     /* first question is whether parent exists */
78     if ( VectorFind ( parents, & dad -> id, NULL, SViewOverridesCmp ) != NULL )
79         return SILENT_RC ( rcVDB, rcSchema, rcParsing, rcTable, rcExists );
80 
81     /* create a new override object */
82     to = malloc ( sizeof * to );
83     if ( to == NULL )
84         return RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
85 
86     /* shallow clone */
87     rc = VectorCopy ( overrides, & to -> by_parent );
88     if ( rc != 0 )
89     {
90         free ( to );
91         return rc;
92     }
93     to -> dad = dad;
94     to -> ctx = dad -> id;
95 
96     /* insert into parent override vector */
97     rc = VectorInsert ( parents, to, NULL, SViewOverridesSort );
98     if ( rc != 0 )
99     {
100         SViewOverridesWhack ( to, NULL );
101         return rc;
102     }
103 
104     return 0;
105 }
106 
107 /* SView
108 */
109 void
SViewWhack(void * item,void * ignore)110 SViewWhack ( void * item, void *ignore )
111 {
112     SView *self = item;
113 
114     /* whack components */
115     VectorWhack ( & self -> params, NULL, NULL );
116     VectorWhack ( & self -> parents, SViewInstanceWhack, NULL );
117 
118     VectorWhack ( & self -> col, SColumnWhack, NULL );
119     VectorWhack ( & self -> cname, SNameOverloadWhack, NULL );
120 
121     VectorWhack ( & self -> prod, SProductionWhack, NULL );
122     VectorWhack ( & self -> vprods, NULL, NULL );
123     VectorWhack ( & self -> syms, ( void ( CC * ) ( void*, void* ) ) KSymbolWhack, NULL );
124 
125     VectorWhack ( & self -> overrides, SViewOverridesWhack, NULL );
126 
127     BSTreeWhack ( & self -> scope, KSymbolWhack, NULL );
128 
129     free ( self );
130 }
131 
132 /* Cmp
133  * Sort
134  */
135 int64_t
SViewCmp(const void * item,const void * n)136 SViewCmp ( const void *item, const void *n )
137 {
138     const uint32_t *a = item;
139     const SView *b = n;
140 
141     if ( * a > b -> version )
142         return 1;
143     return ( int64_t ) ( * a >> 24 ) - ( int64_t ) ( b -> version >> 24 );
144 }
145 
146 int64_t
SViewSort(const void * item,const void * n)147 SViewSort ( const void *item, const void *n )
148 {
149     const SView *a = item;
150     const SView *b = n;
151 
152     return ( int64_t ) ( a -> version >> 24 ) - ( int64_t ) ( b -> version >> 24 );
153 }
154 
155 /*
156  * push-view-scope
157  * pop-view-scope
158  */
159 void
pop_view_scope(struct KSymTable * tbl,const SView * view)160 pop_view_scope ( struct KSymTable * tbl, const SView * view )
161 {
162     uint32_t i, count = VectorLength ( & view -> overrides );
163     for ( ++ count, i = 0; i < count; ++ i )
164         KSymTablePopScope ( tbl );
165 }
166 
167 rc_t
push_view_scope(struct KSymTable * tbl,const SView * view)168 push_view_scope ( struct KSymTable * tbl, const SView * view )
169 {
170     rc_t rc;
171     uint32_t i = VectorStart ( & view -> overrides );
172     uint32_t count = VectorLength ( & view -> overrides );
173     for ( count += i; i < count; ++ i )
174     {
175         const SViewOverrides *to = ( const void* ) VectorGet ( & view -> overrides, i );
176         rc = KSymTablePushScope ( tbl, ( BSTree* ) & to -> dad -> scope );
177         if ( rc != 0 )
178         {
179             for ( count = VectorStart ( & view -> overrides ); i > count; -- i )
180                 KSymTablePopScope ( tbl );
181             return rc;
182         }
183     }
184 
185     rc = KSymTablePushScope ( tbl, ( BSTree* ) & view -> scope );
186     if ( rc != 0 )
187     {
188         for ( i = VectorStart ( & view -> overrides ); i < count; ++ i )
189             KSymTablePopScope ( tbl );
190     }
191 
192     return rc;
193 }
194 
195 bool
view_fwd_scan(BSTNode * n,void * data)196 view_fwd_scan ( BSTNode *n, void *data )
197 {
198     SViewScanData *pb = data;
199     KSymbol *sym = ( KSymbol* ) n;
200     SView *self = pb -> self;
201 
202     /* process forwarded symbols */
203     if ( sym -> type == eForward )
204     {
205         /* this symbol was introduced in THIS view */
206         sym -> u . fwd . ctx = self -> id;
207 
208         /* add it to the introduced virtual productions and make it virtual */
209         pb -> rc = VectorAppend ( & self -> vprods, & sym -> u . fwd . id, sym );
210         if ( pb -> rc != 0 )
211             return true;
212         sym -> type = eVirtual;
213     }
214     /* symbols other than fwd or virtual are ignored */
215     else if ( sym -> type != eVirtual )
216     {
217         return false;
218     }
219 
220     /* add symbol to vector to track ownership */
221     pb -> rc = VectorAppend ( & self -> syms, NULL, sym );
222     if ( pb -> rc != 0 )
223         return true;
224 
225     /* remove from symbol table */
226     BSTreeUnlink ( & self -> scope, & sym -> n );
227     return false;
228 }
229 
230 static
column_set_context(void * item,void * data)231 void column_set_context ( void *item, void *data )
232 {
233     SColumn *self = item;
234     self -> cid . ctx = * ( const uint32_t* ) data;
235 }
236 
237 static
name_set_context(void * item,void * data)238 void name_set_context ( void *item, void *data )
239 {
240     SNameOverload *self = item;
241     if ( ( int32_t ) self -> cid . ctx < 0 )
242         self -> cid . ctx = * ( const uint32_t* ) data;
243 }
244 
245 static
production_set_context(void * item,void * data)246 void production_set_context ( void *item, void *data )
247 {
248     SProduction *self = item;
249     self -> cid . ctx = * ( const uint32_t* ) data;
250 }
251 
252 static
symbol_set_context(void * item,void * data)253 void symbol_set_context ( void *item, void *data )
254 {
255     KSymbol *self = item;
256     self -> u . fwd . ctx = * ( const uint32_t* ) data;
257 }
258 
view_set_context(SView * self,uint32_t p_ctxId)259 void CC view_set_context ( SView *self, uint32_t p_ctxId )
260 {
261     VectorForEach ( & self -> col, false, column_set_context, & p_ctxId );
262     VectorForEach ( & self -> cname, false, name_set_context, & p_ctxId );
263     VectorForEach ( & self -> prod, false, production_set_context, & p_ctxId );
264     VectorForEach ( & self -> vprods, false, symbol_set_context, & p_ctxId );
265 }
266 
267 static
view_prod_syntax(void * item,void * data)268 bool view_prod_syntax ( void *item, void *data )
269 {
270     rc_t *rc = data;
271     const SProduction *prod = ( const SProduction* ) item;
272 
273     * rc = eval_expr_syntax ( prod -> fd );
274     if ( * rc == 0 )
275         * rc = eval_expr_syntax ( prod -> expr );
276 
277     return ( * rc != 0 ) ? true : false;
278 }
279 
280 static
view_stmt_syntax(const SView * view)281 rc_t view_stmt_syntax ( const SView * view )
282 {
283     rc_t rc = 0;
284     VectorDoUntil ( & view -> prod, false, view_prod_syntax, & rc );
285     return rc;
286 }
287 
288 static
view_typed_column_syntax(void * item,void * data)289 bool view_typed_column_syntax ( void *item, void *data )
290 {
291     rc_t *rc = data;
292     const SColumn *col = ( const SColumn* ) item;
293 
294     if ( col -> read != NULL )
295         * rc = eval_expr_syntax ( col -> read );
296     if ( * rc == 0 && col -> validate != NULL )
297         * rc = eval_expr_syntax ( col -> validate );
298     if ( * rc == 0 && col -> limit != NULL )
299         * rc = eval_expr_syntax ( col -> limit );
300 
301     return ( * rc != 0 ) ? true : false;
302 }
303 
304 static
view_column_syntax(const SView * view)305 rc_t view_column_syntax ( const SView *view )
306 {
307     rc_t rc = 0;
308     VectorDoUntil ( & view -> col, false, view_typed_column_syntax, & rc );
309     return rc;
310 }
311 
312 rc_t
view_fix_forward_refs(const SView * view)313 view_fix_forward_refs ( const SView * view )
314 {
315     rc_t rc = view_stmt_syntax ( view );
316     if ( rc == 0 )
317         rc = view_column_syntax ( view );
318     return rc;
319 }
320 
321 void
SViewInstanceWhack(void * item,void * ignore)322 CC SViewInstanceWhack ( void *item, void *ignore )
323 {
324     SViewInstance * self = ( SViewInstance * ) item;
325     VectorWhack ( & self -> params, NULL, NULL );
326     free ( self );
327 }
328 
329 
330 /*
331  * init-tbl-symtab
332  *  initializes "tbl"
333  *  places table in scope
334  *  must be balanced by KSymTableWhack
335  */
336 static
337 rc_t
init_view_symtab(KSymTable * p_tbl,const VSchema * p_schema,const SView * p_view)338 init_view_symtab ( KSymTable * p_tbl, const VSchema * p_schema, const SView * p_view )
339 {
340     rc_t rc = init_symtab ( p_tbl, p_schema );
341     if ( rc == 0 )
342     {
343         rc = push_view_scope ( p_tbl, p_view );
344         if ( rc == 0 )
345         {
346             return 0;
347         }
348 
349         KSymTableWhack ( p_tbl );
350     }
351 
352     return rc;
353 }
354 
355 
356 /* Find
357  *  generic object find within view scope
358  *
359  *  "td" [ OUT, NULL OKAY ] - returns cast type expression
360  *  if given or "any" if not
361  *
362  *  "name" [ OUT ] - returns list of overloaded objects if found
363  *
364  *  "type" [ OUT ] - returns object type id, e.g.:
365  *    eDatatype, eTypeset, eFormat, eFunction, ePhysical, eTable, ...
366  *
367  *  "expr" [ IN ] - NUL terminated name expression identifying object
368  *
369  *  "ctx" [ IN ] - NUL terminated context string for evaluation,
370  *  substitutes for filename in logging reports
371  *
372  *  "dflt" [ IN ] - if true, resolve default value
373  *
374  *  returns principal object identified. if NULL but "name" is not
375  *  NULL, then the object was only partially identified.
376  */
377 const void *
SViewFind(const SView * p_self,const VSchema * p_schema,VTypedecl * p_td,const SNameOverload ** p_name,uint32_t * p_type,const char * p_expr,const char * p_ctx,bool p_dflt)378 SViewFind ( const SView *           p_self,
379             const VSchema *         p_schema,
380             VTypedecl *             p_td,
381             const SNameOverload **  p_name,
382             uint32_t *              p_type,
383             const char *            p_expr,
384             const char *            p_ctx,
385             bool                    p_dflt )
386 {
387     rc_t rc;
388     KSymTable tbl;
389 
390     /* initialize to not-found */
391     const void *obj = NULL;
392     * p_name = NULL;
393     * p_type = 0;
394 
395     /* build a symbol table for view */
396     rc = init_view_symtab ( & tbl, p_schema, p_self );
397     if ( rc == 0 )
398     {
399         obj = resolve_object ( & tbl, p_schema, p_td, p_name, p_type, p_expr, p_ctx, p_dflt );
400         KSymTableWhack ( & tbl );
401     }
402 
403     return obj;
404 }
405 
406 /* FindOverride
407  *  finds an inherited or introduced overridden symbol
408  */
409 const struct KSymbol *
SViewFindOverride(const SView * p_self,const VCtxId * p_cid)410 SViewFindOverride ( const SView * p_self, const VCtxId * p_cid )
411 {
412     const SViewOverrides *to;
413 
414     /* it may be on the existing view */
415     if ( p_cid -> ctx == p_self -> id )
416     {
417         return VectorGet ( & p_self -> vprods, p_cid -> id );
418     }
419 
420     to = ( const void* ) VectorFind ( & p_self -> overrides, & p_cid -> ctx, NULL, SViewOverridesCmp );
421     if ( to == NULL )
422     {
423         return NULL;
424     }
425 
426     return VectorGet ( & to -> by_parent, p_cid -> id );
427 }
428