]> andersk Git - moira.git/blame - server/qvalidate.dc
Oracle and Solaris/POSIX changes
[moira.git] / server / qvalidate.dc
CommitLineData
73cf66ba 1/*
2 * $Source$
3 * $Author$
4 * $Header$
5 *
6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
8 * <mit-copyright.h>.
9 *
10 */
11
12#ifndef lint
13static char *rcsid_qsupport_dc = "$Header$";
14#endif lint
15
16#include <mit-copyright.h>
17#include <unistd.h>
73cf66ba 18#include "mr_server.h"
03c05291 19#include "query.h"
73cf66ba 20#include <ctype.h>
03c05291 21#include <string.h>
73cf66ba 22EXEC SQL INCLUDE sqlca;
23EXEC SQL INCLUDE sqlda;
24#include "qrtn.h"
25
03c05291 26extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
27extern int dbms_errno, mr_errcode;
73cf66ba 28
29EXEC SQL BEGIN DECLARE SECTION;
30extern char stmt_buf[];
31EXEC SQL END DECLARE SECTION;
32
03c05291 33int validate_chars(char *argv[], struct valobj *vo);
34int validate_id(struct query *, char *argv[], struct valobj *vo);
35int validate_name(char *argv[], struct valobj *vo);
36int validate_rename(char *argv[], struct valobj *vo);
37int validate_type(char *argv[], struct valobj *vo);
38int validate_typedata(struct query *, char *argv[], struct valobj *vo);
39int validate_len(char *argv[], struct valobj *vo);
40int lock_table(struct valobj *vo);
41int readlock_table(struct valobj *vo);
42int convert_wildcards_uppercase(char *arg);
73cf66ba 43
03c05291 44EXEC SQL WHENEVER SQLERROR DO dbmserr();
73cf66ba 45
46/* Validation Routines */
47
03c05291 48int validate_row(q, argv, v)
73cf66ba 49 register struct query *q;
50 char *argv[];
51 register struct validate *v;
52{
53 EXEC SQL BEGIN DECLARE SECTION;
73cf66ba 54 char qual[128];
55 int rowcount;
56 EXEC SQL END DECLARE SECTION;
57
58 /* build where clause */
59 build_qual(v->qual, v->argc, argv, qual);
60
61 if (log_flags & LOG_VALID)
62 /* tell the logfile what we're doing */
63 com_err(whoami, 0, "validating row: %s", qual);
64
65 /* look for the record */
03c05291 66 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",
67 table_name[q->rtable],qual);
68 dosql(sqlbuffer);
69 if (dbms_errno) return(mr_errcode);
70
71 rowcount = atoi(sqlbuffer[0]);
73cf66ba 72 if (rowcount == 0) return(MR_NO_MATCH);
73 if (rowcount > 1) return(MR_NOT_UNIQUE);
74 return(MR_EXISTS);
75}
76
03c05291 77int validate_fields(q, argv, vo, n)
73cf66ba 78 struct query *q;
79 register char *argv[];
80 register struct valobj *vo;
81 register int n;
82{
83 register int status;
84
85 while (--n >= 0) {
86 switch (vo->type) {
87 case V_NAME:
88 if (log_flags & LOG_VALID)
89 com_err(whoami, 0, "validating %s in %s: %s",
03c05291 90 vo->namefield, table_name[vo->table], argv[vo->index]);
73cf66ba 91 status = validate_name(argv, vo);
92 break;
93
94 case V_ID:
95 if (log_flags & LOG_VALID)
96 com_err(whoami, 0, "validating %s in %s: %s",
03c05291 97 vo->idfield, table_name[vo->table], argv[vo->index]);
73cf66ba 98 status = validate_id(q, argv, vo);
99 break;
100
03c05291 101 /*
73cf66ba 102 case V_DATE:
103 if (log_flags & LOG_VALID)
104 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
105 status = validate_date(argv, vo);
106 break;
03c05291 107 */
73cf66ba 108
109 case V_TYPE:
110 if (log_flags & LOG_VALID)
111 com_err(whoami, 0, "validating %s type: %s",
03c05291 112 table_name[vo->table], argv[vo->index]);
73cf66ba 113 status = validate_type(argv, vo);
114 break;
115
116 case V_TYPEDATA:
117 if (log_flags & LOG_VALID)
118 com_err(whoami, 0, "validating typed data (%s): %s",
119 argv[vo->index - 1], argv[vo->index]);
120 status = validate_typedata(q, argv, vo);
121 break;
122
123 case V_RENAME:
124 if (log_flags & LOG_VALID)
125 com_err(whoami, 0, "validating rename %s in %s",
03c05291 126 argv[vo->index], table_name[vo->table]);
73cf66ba 127 status = validate_rename(argv, vo);
128 break;
129
130 case V_CHAR:
131 if (log_flags & LOG_VALID)
132 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
03c05291 133 status = validate_chars(argv, vo);
134 break;
135
136 case V_LEN:
137 if (log_flags & LOG_VALID)
138 com_err(whoami, 0, "validating length: %s", argv[vo->index]);
139 status = validate_len(argv, vo);
73cf66ba 140 break;
141
142 case V_SORT:
143 status = MR_EXISTS;
144 break;
145
146 case V_LOCK:
147 status = lock_table(vo);
148 break;
149
03c05291 150 case V_RLOCK:
151 status = readlock_table(vo);
152 break;
153
154 case V_WILD:
73cf66ba 155 status = convert_wildcards(argv[vo->index]);
156 break;
157
158 case V_UPWILD:
159 status = convert_wildcards_uppercase(argv[vo->index]);
160 break;
161
162 }
163
164 if (status != MR_EXISTS) return(status);
165 vo++;
166 }
167
03c05291 168 if (dbms_errno) return(mr_errcode);
73cf66ba 169 return(MR_SUCCESS);
170}
171
172
173/* validate_chars: verify that there are no illegal characters in
174 * the string. Legal characters are printing chars other than
175 * ", *, ?, \, [ and ].
176 */
177static int illegalchars[] = {
178 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
179 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
180 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
181 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
185 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
186 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
187 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
188 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
189 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
190 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
191 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
192 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
193 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
194};
195
03c05291 196int validate_chars(argv, vo)
197 char *argv[];
198 register struct valobj *vo;
73cf66ba 199{
03c05291 200 char *s=argv[vo->index];
201 int arg;
202 EXEC SQL BEGIN DECLARE SECTION;
203 int len;
204 char *tname, *cname;
205 EXEC SQL END DECLARE SECTION;
206
207
208 /* check for bad characters */
73cf66ba 209 while (*s)
210 if (illegalchars[*s++])
211 return(MR_BAD_CHAR);
03c05291 212
213 /* check for length */
214 tname = table_name[vo->table];
215 cname = vo->namefield;
216 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
217 WHERE table_name=UPPER(:tname) AND column_name=UPPER(:cname);
218
219 if((strlen(argv[vo->index]) > len) &&
220 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
221 argv[vo->index][len]='\0'; /* truncate */
222
223 return MR_EXISTS;
73cf66ba 224}
225
226
03c05291 227int validate_id(q, argv, vo)
73cf66ba 228 struct query *q;
229 char *argv[];
230 register struct valobj *vo;
231{
232 EXEC SQL BEGIN DECLARE SECTION;
03c05291 233 char *name, *namefield, *idfield;
234 int id, rowcount, tbl;
73cf66ba 235 EXEC SQL END DECLARE SECTION;
236 int status;
237 register char *c;
238
239 name = argv[vo->index];
240 tbl = vo->table;
241 namefield = vo->namefield;
242 idfield = vo->idfield;
243
03c05291 244 if ((tbl==USERS_TABLE && !strcmp(namefield, "login")) ||
245 tbl==MACHINE_TABLE || tbl==SUBNET_TABLE || tbl==FILESYS_TABLE ||
246 tbl==LIST_TABLE || tbl==CLUSTER_TABLE || tbl==STRINGS_TABLE) {
247 if (tbl==MACHINE_TABLE || tbl==SUBNET_TABLE)
248 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
249 status = name_to_id(name, tbl, &id);
250 if (status == 0) {
251 *(int *)argv[vo->index] = id;
252 return(MR_EXISTS);
253 } else if (status == MR_NO_MATCH && tbl==STRINGS_TABLE &&
254 (q->type == APPEND || q->type == UPDATE)) {
255 id=add_string(name);
256 cache_entry(name, STRINGS_TABLE, id);
257 *(int *)argv[vo->index] = id;
258 return(MR_EXISTS);
259 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
260 return(vo->error);
261 else
262 return(status);
73cf66ba 263 } else {
03c05291 264 /* else, it's `dubu', which uses unix_uid from users */
265 EXEC SQL SELECT COUNT(*) INTO :rowcount FROM users
266 WHERE unix_uid = :name;
267 if (dbms_errno) return(mr_errcode);
268 if (rowcount != 1) return(vo->error);
269 EXEC SQL SELECT users_id INTO :id FROM users
270 WHERE unix_uid = :name;
271 *(int *)argv[vo->index] = id;
272 return(MR_EXISTS);
73cf66ba 273 }
73cf66ba 274}
275
03c05291 276int validate_name(argv, vo)
73cf66ba 277 char *argv[];
278 register struct valobj *vo;
279{
03c05291 280 char *name, *namefield;
73cf66ba 281 register char *c;
282
283 name = argv[vo->index];
73cf66ba 284 namefield = vo->namefield;
03c05291 285 if (vo->table==SERVERS_TABLE && !strcmp(namefield, "name")) {
73cf66ba 286 for (c = name; *c; c++)
287 if (islower(*c))
288 *c = toupper(*c);
289 }
290 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
03c05291 291 table_name[vo->table],table_name[vo->table],namefield,name);
292 dosql(sqlbuffer);
293
294 if (dbms_errno) return(mr_errcode);
295 return ((atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error);
73cf66ba 296}
297
03c05291 298/*
73cf66ba 299validate_date(argv, vo)
300 char *argv[];
301 struct valobj *vo;
302{
303 EXEC SQL BEGIN DECLARE SECTION;
304 char *idate;
305 double dd;
306 int errorno;
307 EXEC SQL END DECLARE SECTION;
308
309 idate = argv[vo->index];
310 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
73cf66ba 311 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
312 return(MR_EXISTS);
313}
03c05291 314*/
73cf66ba 315
03c05291 316int validate_rename(argv, vo)
317 char *argv[];
318 struct valobj *vo;
73cf66ba 319{
320 EXEC SQL BEGIN DECLARE SECTION;
03c05291 321 char *name, *namefield, *idfield;
73cf66ba 322 int id;
323 EXEC SQL END DECLARE SECTION;
324 int status;
325 register char *c;
326
03c05291 327 status = validate_chars(argv, vo);
328 if(status != MR_EXISTS) return status;
329 name=argv[vo->index];
73cf66ba 330 /* minor kludge to upcasify machine names */
03c05291 331 if (vo->table == MACHINE_TABLE)
73cf66ba 332 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
333 namefield = vo->namefield;
334 idfield = vo->idfield;
335 id = -1;
336 if (idfield == 0) {
337 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
338 return(MR_EXISTS);
03c05291 339 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",
340 namefield,table_name[vo->table],namefield,name);
341 dosql(sqlbuffer);
342
343 if (dbms_errno) return(mr_errcode);
344 if (sqlca.sqlcode==SQL_NO_MATCH)
345 return(MR_EXISTS); /* how's _that_ for intuitive? */
73cf66ba 346 else
03c05291 347 return(vo->error);
73cf66ba 348 }
03c05291 349 status = name_to_id(name, vo->table, &id);
73cf66ba 350 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
351 return(MR_EXISTS);
352 else
353 return(vo->error);
354}
355
356
03c05291 357int validate_type(argv, vo)
73cf66ba 358 char *argv[];
359 register struct valobj *vo;
360{
361 EXEC SQL BEGIN DECLARE SECTION;
362 char *typename;
363 char *val;
364 int cnt;
365 EXEC SQL END DECLARE SECTION;
366 register char *c;
367
03c05291 368 typename = vo->namefield;
73cf66ba 369 c = val = argv[vo->index];
370 while (*c) {
371 if (illegalchars[*c++])
372 return(MR_BAD_CHAR);
373 }
374
375 /* uppercase type fields */
376 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
377
378 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
379 WHERE name = :typename AND type='TYPE' AND trans = :val;
03c05291 380 if (dbms_errno) return(mr_errcode);
73cf66ba 381 return (cnt ? MR_EXISTS : vo->error);
382}
383
384/* validate member or type-specific data field */
385
03c05291 386int validate_typedata(q, argv, vo)
73cf66ba 387 register struct query *q;
388 register char *argv[];
389 register struct valobj *vo;
390{
391 EXEC SQL BEGIN DECLARE SECTION;
392 char *name;
393 char *field_type;
394 char data_type[129];
395 int id;
396 EXEC SQL END DECLARE SECTION;
397 int status;
73cf66ba 398 register char *c;
399
400 /* get named object */
401 name = argv[vo->index];
402
403 /* get field type string (known to be at index-1) */
404 field_type = argv[vo->index-1];
405
406 /* get corresponding data type associated with field type name */
407 EXEC SQL SELECT trans INTO :data_type FROM alias
408 WHERE name = :field_type AND type='TYPEDATA';
03c05291 409 if (dbms_errno) return(mr_errcode);
73cf66ba 410 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
411
412 /* now retrieve the record id corresponding to the named object */
03c05291 413 if (strchr(data_type, ' '))
414 *strchr(data_type, ' ') = 0;
73cf66ba 415 if (!strcmp(data_type, "user")) {
416 /* USER */
03c05291 417 if (strchr(name, '@'))
73cf66ba 418 return(MR_USER);
03c05291 419 status = name_to_id(name, USERS_TABLE, &id);
73cf66ba 420 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
421 return(MR_USER);
422 if (status) return(status);
423 } else if (!strcmp(data_type, "list")) {
424 /* LIST */
03c05291 425 status = name_to_id(name, LIST_TABLE, &id);
73cf66ba 426 if (status && status == MR_NOT_UNIQUE)
427 return(MR_LIST);
428 if (status == MR_NO_MATCH) {
429 /* if idfield is non-zero, then if argv[0] matches the string
430 * that we're trying to resolve, we should get the value of
431 * numvalues.[idfield] for the id.
432 */
433 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
434 set_next_object_id(q->validate->object_id, q->rtable, 0);
435 name = vo->idfield;
03c05291 436 EXEC SQL SELECT value INTO :id FROM numvalues
73cf66ba 437 WHERE name = :name;
438 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
439 } else
440 return(MR_LIST);
441 } else if (status) return(status);
442 } else if (!strcmp(data_type, "machine")) {
443 /* MACHINE */
444 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
03c05291 445 status = name_to_id(name, MACHINE_TABLE, &id);
73cf66ba 446 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
447 return(MR_MACHINE);
448 if (status) return(status);
449 } else if (!strcmp(data_type, "string")) {
450 /* STRING */
03c05291 451 status = name_to_id(name, STRINGS_TABLE, &id);
73cf66ba 452 if (status && status == MR_NOT_UNIQUE)
453 return(MR_STRING);
454 if (status == MR_NO_MATCH) {
455 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
456 id=add_string(name);
03c05291 457 cache_entry(name, STRINGS_TABLE, id);
73cf66ba 458 } else if (status) return(status);
459 } else if (!strcmp(data_type, "none")) {
460 id = 0;
461 } else {
462 return(MR_TYPE);
463 }
464
465 /* now set value in argv */
466 *(int *)argv[vo->index] = id;
467
468 return (MR_EXISTS);
469}
470
471
03c05291 472/* Make sure the data fits in the field */
473int validate_len(argv, vo)
474 register char *argv[];
475 register struct valobj *vo;
476{
477 EXEC SQL BEGIN DECLARE SECTION;
478 int len;
479 char *tname, *cname;
480 EXEC SQL END DECLARE SECTION;
481
482 tname = table_name[vo->table];
483 cname = vo->namefield;
484 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
485 WHERE table_name=UPPER(:tname) AND column_name=UPPER(:cname);
486
487 if((strlen(argv[vo->index]) > len) &&
488 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
489 argv[vo->index][len]='\0'; /* truncate */
490
491 return MR_EXISTS;
492}
493
73cf66ba 494/* Lock the table named by the validation object */
495
03c05291 496int lock_table(vo)
497 struct valobj *vo;
73cf66ba 498{
03c05291 499#ifdef DO_LOCKING
500 sprintf(stmt_buf, "LOCK TABLE %s IN EXCLUSIVE MODE", table_name[vo->table]);
73cf66ba 501 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
03c05291 502 if (dbms_errno)
503 return(mr_errcode);
73cf66ba 504 else
03c05291 505#endif
73cf66ba 506 return(MR_EXISTS);
507}
508
03c05291 509/*
510 * Get a read lock on the table by accessing the magic lock
511 * record. Certain tables are constructed so that they contain
512 * an id field whose value is zero and a modtime field. We
513 * manipulate the modtime field of the id 0 record to effect
514 * locking of the table
73cf66ba 515 */
516
03c05291 517int readlock_table(vo)
518 struct valobj *vo;
73cf66ba 519{
03c05291 520#ifdef DO_LOCKING
521 sprintf(stmt_buf, "LOCK TABLE %s IN SHARE MODE", table_name[vo->table]);
522 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
523
524 if (dbms_errno)
525 return(mr_errcode);
526 if (sqlca.sqlcode)
527 return(vo->error);
528#endif
529 return(MR_EXISTS); /* validate_fields expects us to return
530 * this value if everything went okay
531 */
73cf66ba 532}
533
03c05291 534/* Check the database at startup time. NOT! */
535
536void sanity_check_database(void)
537{
538}
539
540
541char *sqlbuffer[QMAXARGS];
73cf66ba 542
543/* Dynamic SQL support routines */
03c05291 544SQLDA *mr_alloc_sqlda()
73cf66ba 545{
03c05291 546 SQLDA *it;
73cf66ba 547 register int j;
548
03c05291 549 it=sqlald(QMAXARGS, ARGLEN, 0);
550 if(it==NULL) {
73cf66ba 551 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
552 exit(1);
553 }
554
73cf66ba 555 for(j=0; j<QMAXARGS; j++) {
03c05291 556 it->V[j]=sqlbuffer[j]=malloc(ARGLEN);
557 it->T[j]=97; /* 97 = CHARZ = null-terminated string */
558 it->L[j]=ARGLEN;
73cf66ba 559 }
03c05291 560
73cf66ba 561 return it;
562}
563
564
73cf66ba 565/* Convert normal Unix-style wildcards to SQL voodoo */
03c05291 566int convert_wildcards(arg)
73cf66ba 567 char *arg;
568{
569 static char buffer[ARGLEN];
570 register char *s, *d;
571
572 for(d=buffer,s=arg;*s;s++) {
573 switch(*s) {
574 case '*': *d++='%'; *d++='%'; break;
575 case '?': *d++='_'; break;
576 case '_':
577 case '[':
578 case ']': *d++='*'; *d++ = *s; break;
579 case '%': *d++='*'; *d++='%'; *d++='%'; break;
580 default: *d++ = *s; break;
581 }
582 }
583 *d='\0';
584
585 /* Copy back into argv */
586 strcpy(arg,buffer);
587
588 return(MR_EXISTS);
589}
590
591/* This version includes uppercase conversion, for things like gmac.
592 * This is necessary because "LIKE" doesn't work with "uppercase()".
593 * Including it in a wildcard routine saves making two passes over
594 * the argument string.
595 */
03c05291 596int convert_wildcards_uppercase(arg)
73cf66ba 597 char *arg;
598{
599 static char buffer[ARGLEN];
600 register char *s, *d;
601
602 for(d=buffer,s=arg;*s;s++) {
603 switch(*s) {
604 case '*': *d++='%'; *d++='%'; break;
605 case '?': *d++='_'; break;
606 case '_':
607 case '[':
608 case ']': *d++='*'; *d++ = *s; break;
609 case '%': *d++='*'; *d++='%'; *d++='%'; break;
610 default: *d++=toupper(*s); break; /* This is the only diff. */
611 }
612 }
613 *d='\0';
614
615 /* Copy back into argv */
616 strcpy(arg,buffer);
617
618 return(MR_EXISTS);
619}
620
621
73cf66ba 622/* Adds a string to the string table. Returns the id number.
623 *
624 */
625int add_string(name)
626 EXEC SQL BEGIN DECLARE SECTION;
627 char *name;
628 EXEC SQL END DECLARE SECTION;
629{
630 EXEC SQL BEGIN DECLARE SECTION;
631 char buf[256];
632 int id;
633 EXEC SQL END DECLARE SECTION;
634
635 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
636 id++;
637 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
638
03c05291 639 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
73cf66ba 640
641 return(id);
642}
This page took 3.750106 seconds and 5 git commands to generate.