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