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