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 "kqsh-priv.h"
28 #include "kqsh-tok.h"
29 #include "kqsh-kdb.h"
30 #include "kqsh-vdb.h"
31
32 #include <klib/symbol.h>
33 #include <klib/symtab.h>
34 #include <klib/token.h>
35
36 #include <klib/log.h>
37 #include <klib/rc.h>
38
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <assert.h>
43
44
45 /* alter cursor
46 * 'alter <cursor> add column [ ( <typedecl> ) ] NAME;'
47 *
48 * all data after the 'column' keyword are gathered into
49 * ( typedecl, name ) pairs. we are going to allow comma
50 * separation, but otherwise just gather everything up to
51 * the semi-colon.
52 */
53 static
kqsh_alter_cursor_add_column(KSymTable * tbl,KTokenSource * src,KToken * t,KSymbol * cursor)54 rc_t kqsh_alter_cursor_add_column ( KSymTable *tbl, KTokenSource *src, KToken *t, KSymbol *cursor )
55 {
56 rc_t rc;
57
58 do
59 {
60 size_t i;
61 uint32_t idx;
62 char coldecl [ 256 ];
63
64 for ( i = 0; i < sizeof coldecl - 1; )
65 {
66 /* end of column */
67 if ( t -> id == eSemiColon || t -> id == eComma )
68 break;
69
70 /* accumulate */
71 i += string_copy ( & coldecl [ i ],
72 sizeof coldecl - i, t -> str . addr, t -> str . size );
73
74 next_token ( tbl, src, t );
75 }
76
77 /* the name needs to fit in our buffer */
78 if ( i == sizeof coldecl - 1 )
79 {
80 rc = RC ( rcExe, rcCursor, rcUpdating, rcName, rcExcessive );
81 if ( interactive )
82 {
83 kqsh_printf ( "this is really hard to believe, but you managed to request\n"
84 "a column with a %u byte expression. please stop trying to abuse me.\n",
85 ( unsigned int ) i );
86 }
87 else
88 {
89 LOGERR ( klogErr, rc, "failed to add column to cursor" );
90 }
91 return rc;
92 }
93
94 /* perform the task */
95 rc = _VCursorAddColumn ( cursor -> u . obj, & idx, coldecl );
96 if ( rc != 0 )
97 {
98 PLOGERR ( klogErr, (klogErr, rc, "cannot add column '$(expr)' to cursor '$(curs)'",
99 "expr=%s,curs=%.*s"
100 , coldecl
101 , ( int ) cursor -> name . size, cursor -> name . addr));
102 }
103
104 else if ( interactive )
105 {
106 kqsh_printf ( "added column '%s' ( idx %u ) to cursor '%N' ( %p )\n"
107 , coldecl
108 , idx
109 , cursor
110 , cursor -> u . obj
111 );
112 }
113 }
114 while ( t -> id == eComma );
115
116 if ( t -> id != eSemiColon )
117 return expected ( t, klogErr, ";" );
118
119 return 0;
120 }
121
122 static
kqsh_alter_cursor_add(KSymTable * tbl,KTokenSource * src,KToken * t,KSymbol * cursor)123 rc_t kqsh_alter_cursor_add ( KSymTable *tbl, KTokenSource *src, KToken *t, KSymbol *cursor )
124 {
125 switch ( t -> id )
126 {
127 case kw_column:
128 return kqsh_alter_cursor_add_column ( tbl, src, next_token ( tbl, src, t ), cursor );
129 }
130
131 return expected ( t, klogErr, "column" );
132 }
133
134 static
kqsh_alter_cursor(KSymTable * tbl,KTokenSource * src,KToken * t,KSymbol * cursor)135 rc_t kqsh_alter_cursor ( KSymTable *tbl, KTokenSource *src, KToken *t, KSymbol *cursor )
136 {
137 switch ( t -> id )
138 {
139 case kw_add:
140 return kqsh_alter_cursor_add ( tbl, src, next_token ( tbl, src, t ), cursor );
141 }
142
143 return expected ( t, klogErr, "add" );
144 }
145
146 /* alter schema add path
147 * 'alter <schema> add include [ path ] STRING'
148 * 'alter <schema> add path STRING'
149 */
150 static
kqsh_alter_schema_add_path(KSymTable * tbl,KTokenSource * src,KToken * t,KSymbol * sym)151 rc_t kqsh_alter_schema_add_path ( KSymTable *tbl, KTokenSource *src, KToken *t, KSymbol *sym )
152 {
153 rc_t rc;
154 String path;
155 struct VSchema *schema = ( void* ) sym -> u . obj;
156
157 switch ( t -> id )
158 {
159 case eString:
160 case eEscapedString:
161 path = t -> str;
162 path . addr += 1;
163 path . size -= 2;
164 break;
165
166 case eUntermString:
167 case eUntermEscapedString:
168 CONST_STRING ( & t -> str, "<unterminated string>" );
169 default:
170 return expected ( t, klogErr, "path string" );
171 }
172
173 /* consume semi-colon */
174 if ( next_token ( tbl, src, t ) -> id != eSemiColon )
175 return expected ( t, klogErr, ";" );
176
177 rc = _VSchemaAddIncludePath ( schema, "%.*s", ( int ) path . size, path . addr );
178 if ( rc != 0 )
179 {
180 PLOGERR ( klogErr, (klogErr, rc, "cannot add search path '$(path)' to schema '$(name)'",
181 "path=%.*s,name=%.*s"
182 , ( int ) path . size, path . addr
183 , ( int ) sym -> name . size, sym -> name . addr));
184 }
185 else if ( interactive )
186 {
187 kqsh_printf ( "added search path '%S' to schema '%N' ( %p )\n",
188 & path, sym, schema );
189 }
190
191 return rc;
192 }
193
194 /* alter schema add text
195 * 'alter <schema> add text STRING'
196 */
197 static
kqsh_alter_schema_add_text(KSymTable * tbl,KTokenSource * src,KToken * t,KSymbol * sym)198 rc_t kqsh_alter_schema_add_text ( KSymTable *tbl, KTokenSource *src, KToken *t, KSymbol *sym )
199 {
200 rc_t rc;
201 String text;
202 struct VSchema *schema = ( void* ) sym -> u . obj;
203
204 switch ( t -> id )
205 {
206 case eString:
207 case eEscapedString:
208 text = t -> str;
209 text . addr += 1;
210 text . size -= 2;
211 break;
212
213 case eUntermString:
214 case eUntermEscapedString:
215 CONST_STRING ( & t -> str, "<unterminated string>" );
216 default:
217 return expected ( t, klogErr, "schema text string" );
218 }
219
220 /* consume semi-colon */
221 if ( next_token ( tbl, src, t ) -> id != eSemiColon )
222 return expected ( t, klogErr, ";" );
223
224 /* parse text */
225 rc = _VSchemaParseText ( schema, "kqsh-console", text . addr, text . size );
226 if ( rc != 0 )
227 {
228 PLOGERR ( klogErr, (klogErr, rc, "cannot add text into schema '$(name)'",
229 "name=%.*s", ( int ) sym -> name . size, sym -> name . addr));
230 }
231 else if ( interactive )
232 {
233 kqsh_printf ( "added text to schema '%N' ( %p )\n", sym, schema );
234 }
235
236 return rc;
237 }
238
239 /* alter schema add
240 */
241 static
kqsh_alter_schema_add(KSymTable * tbl,KTokenSource * src,KToken * t,KSymbol * schema)242 rc_t kqsh_alter_schema_add ( KSymTable *tbl, KTokenSource *src, KToken *t, KSymbol *schema )
243 {
244 switch ( t -> id )
245 {
246 case kw_include:
247 if ( next_token ( tbl, src, t ) -> id == kw_path )
248 case kw_path:
249 next_token ( tbl, src, t );
250 return kqsh_alter_schema_add_path ( tbl, src, t, schema );
251 case kw_text:
252 return kqsh_alter_schema_add_text ( tbl, src, next_token ( tbl, src, t ), schema );
253 }
254
255 return expected ( t, klogErr, "include, path or text" );
256 }
257
258
259 /* alter schema load
260 * 'alter <schema> load STRING'
261 */
262 static
kqsh_alter_schema_load(KSymTable * tbl,KTokenSource * src,KToken * t,KSymbol * sym)263 rc_t kqsh_alter_schema_load ( KSymTable *tbl, KTokenSource *src, KToken *t, KSymbol *sym )
264 {
265 rc_t rc;
266 String path;
267 struct VSchema *schema = ( void* ) sym -> u . obj;
268
269 switch ( t -> id )
270 {
271 case eString:
272 case eEscapedString:
273 path = t -> str;
274 path . addr += 1;
275 path . size -= 2;
276 break;
277
278 case eUntermString:
279 case eUntermEscapedString:
280 CONST_STRING ( & t -> str, "<unterminated string>" );
281 default:
282 return expected ( t, klogErr, "path string" );
283 }
284
285 /* consume semi-colon */
286 if ( next_token ( tbl, src, t ) -> id != eSemiColon )
287 return expected ( t, klogErr, ";" );
288
289 rc = _VSchemaParseFile ( schema, "%.*s", ( int ) path . size, path . addr );
290 if ( rc != 0 )
291 {
292 PLOGERR ( klogErr, (klogErr, rc, "cannot load file '$(path)' into schema '$(name)'",
293 "path=%.*s,name=%.*s"
294 , ( int ) path . size, path . addr
295 , ( int ) sym -> name . size, sym -> name . addr));
296 }
297 else if ( interactive )
298 {
299 kqsh_printf ( "loaded file '%S' into schema '%N' ( %p )\n",
300 & path, sym, schema );
301 }
302
303 return rc;
304 }
305
306 /* alter schema
307 */
308 static
kqsh_alter_schema(KSymTable * tbl,KTokenSource * src,KToken * t,KSymbol * schema)309 rc_t kqsh_alter_schema ( KSymTable *tbl, KTokenSource *src, KToken *t, KSymbol *schema )
310 {
311 switch ( t -> id )
312 {
313 case kw_add:
314 return kqsh_alter_schema_add ( tbl, src, next_token ( tbl, src, t ), schema );
315 case kw_load:
316 return kqsh_alter_schema_load ( tbl, src, next_token ( tbl, src, t ), schema );
317 }
318
319 return expected ( t, klogErr, "add or load" );
320 }
321
322
323 /* alter
324 */
kqsh_alter(KSymTable * tbl,KTokenSource * src,KToken * t)325 rc_t kqsh_alter ( KSymTable *tbl, KTokenSource *src, KToken *t )
326 {
327 KSymbol *sym = t -> sym;
328
329 switch ( t -> id )
330 {
331 case kw_cursor:
332 if ( next_token ( tbl, src, t ) -> id != obj_VCursor )
333 break;
334 sym = t -> sym;
335 case obj_VCursor:
336 return kqsh_alter_cursor ( tbl, src, next_token ( tbl, src, t ), sym );
337
338 case kw_schema:
339 if ( next_token ( tbl, src, t ) -> id != obj_VSchema )
340 break;
341 sym = t -> sym;
342 case obj_VSchema:
343 return kqsh_alter_schema ( tbl, src, next_token ( tbl, src, t ), sym );
344 }
345
346 return expected ( t, klogErr, "cursor or schema" );
347 }
348