6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
13 static char *rcsid_qsupport_dc = "$Header$";
16 #include <mit-copyright.h>
19 #include "mr_server.h"
21 EXEC SQL INCLUDE sqlca;
22 EXEC SQL INCLUDE sqlda;
26 extern int ingres_errno, mr_errcode;
28 EXEC SQL BEGIN DECLARE SECTION;
29 extern char stmt_buf[];
30 EXEC SQL END DECLARE SECTION;
32 EXEC SQL WHENEVER SQLERROR CALL ingerr;
34 #ifdef _DEBUG_MALLOC_INC
36 #define dbg_index(str1,c) DBindex(__FILE__, __LINE__, str1, c)
38 #define dbg_index index
41 /* Validation Routines */
43 validate_row(q, argv, v)
44 register struct query *q;
46 register struct validate *v;
48 EXEC SQL BEGIN DECLARE SECTION;
52 EXEC SQL END DECLARE SECTION;
54 /* build where clause */
55 build_qual(v->qual, v->argc, argv, qual);
57 if (log_flags & LOG_VALID)
58 /* tell the logfile what we're doing */
59 com_err(whoami, 0, "validating row: %s", qual);
61 /* look for the record */
62 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
63 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
66 EXEC SQL DECLARE csr126 CURSOR FOR stmt;
68 EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
69 EXEC SQL CLOSE csr126;
70 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
72 if (ingres_errno) return(mr_errcode);
73 if (rowcount == 0) return(MR_NO_MATCH);
74 if (rowcount > 1) return(MR_NOT_UNIQUE);
78 validate_fields(q, argv, vo, n)
80 register char *argv[];
81 register struct valobj *vo;
89 if (log_flags & LOG_VALID)
90 com_err(whoami, 0, "validating %s in %s: %s",
91 vo->namefield, vo->table, argv[vo->index]);
92 status = validate_name(argv, vo);
96 if (log_flags & LOG_VALID)
97 com_err(whoami, 0, "validating %s in %s: %s",
98 vo->idfield, vo->table, argv[vo->index]);
99 status = validate_id(q, argv, vo);
103 if (log_flags & LOG_VALID)
104 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
105 status = validate_date(argv, vo);
109 if (log_flags & LOG_VALID)
110 com_err(whoami, 0, "validating %s type: %s",
111 vo->table, argv[vo->index]);
112 status = validate_type(argv, vo);
116 if (log_flags & LOG_VALID)
117 com_err(whoami, 0, "validating typed data (%s): %s",
118 argv[vo->index - 1], argv[vo->index]);
119 status = validate_typedata(q, argv, vo);
123 if (log_flags & LOG_VALID)
124 com_err(whoami, 0, "validating rename %s in %s",
125 argv[vo->index], vo->table);
126 status = validate_rename(argv, vo);
130 if (log_flags & LOG_VALID)
131 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
132 status = validate_chars(argv[vo->index]);
140 status = lock_table(vo);
144 status = convert_wildcards(argv[vo->index]);
148 status = convert_wildcards_uppercase(argv[vo->index]);
153 if (status != MR_EXISTS) return(status);
157 if (ingres_errno) return(mr_errcode);
162 /* validate_chars: verify that there are no illegal characters in
163 * the string. Legal characters are printing chars other than
164 * ", *, ?, \, [ and ].
166 static int illegalchars[] = {
167 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
168 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
169 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
172 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
173 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
174 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
175 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
176 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
177 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
178 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
179 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
180 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
181 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
182 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
189 if (illegalchars[*s++])
195 validate_id(q, argv, vo)
198 register struct valobj *vo;
200 EXEC SQL BEGIN DECLARE SECTION;
201 char *name, *tbl, *namefield, *idfield;
203 EXEC SQL END DECLARE SECTION;
207 name = argv[vo->index];
209 namefield = vo->namefield;
210 idfield = vo->idfield;
212 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
213 !strcmp(tbl, "machine") ||
214 !strcmp(tbl, "subnet") ||
215 !strcmp(tbl, "filesys") ||
216 !strcmp(tbl, "list") ||
217 !strcmp(tbl, "cluster") ||
218 !strcmp(tbl, "strings")) {
219 if (!strcmp(tbl, "machine") || !strcmp(tbl, "subnet"))
220 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
221 status = name_to_id(name, tbl, &id);
223 *(int *)argv[vo->index] = id;
225 } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
226 (q->type == APPEND || q->type == UPDATE)) {
228 cache_entry(name, "STRING", id);
229 *(int *)argv[vo->index] = id;
231 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
237 if (!strcmp(namefield, "uid")) {
238 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
240 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
242 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
245 EXEC SQL DECLARE csr127 CURSOR FOR stmt;
246 EXEC SQL OPEN csr127;
248 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
249 if(sqlca.sqlcode == 0) {
251 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
252 if(sqlca.sqlcode == 0) rowcount++;
254 EXEC SQL CLOSE csr127;
258 if (rowcount != 1) return(vo->error);
259 bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
263 validate_name(argv, vo)
265 register struct valobj *vo;
267 EXEC SQL BEGIN DECLARE SECTION;
268 char *name, *tbl, *namefield;
270 EXEC SQL END DECLARE SECTION;
273 name = argv[vo->index];
275 namefield = vo->namefield;
276 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
277 for (c = name; *c; c++)
281 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
282 tbl,tbl,namefield,name);
283 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
286 EXEC SQL DECLARE csr128 CURSOR FOR stmt;
287 EXEC SQL OPEN csr128;
288 EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
289 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
290 EXEC SQL CLOSE csr128;
292 if (ingres_errno) return(mr_errcode);
293 return ((rowcount == 1) ? MR_EXISTS : vo->error);
296 validate_date(argv, vo)
300 EXEC SQL BEGIN DECLARE SECTION;
304 EXEC SQL END DECLARE SECTION;
306 idate = argv[vo->index];
307 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
309 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
314 validate_rename(argv, vo)
318 EXEC SQL BEGIN DECLARE SECTION;
319 char *name, *tbl, *namefield, *idfield;
321 EXEC SQL END DECLARE SECTION;
325 c = name = argv[vo->index];
327 if (illegalchars[*c++])
330 /* minor kludge to upcasify machine names */
331 if (!strcmp(tbl, "machine"))
332 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
333 namefield = vo->namefield;
334 idfield = vo->idfield;
337 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
339 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
340 namefield,tbl,namefield,name,namefield);
341 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
344 EXEC SQL DECLARE csr129 CURSOR FOR stmt;
345 EXEC SQL OPEN csr129;
346 EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
347 if(sqlca.sqlcode == 0) id=1; else id=0;
348 EXEC SQL CLOSE csr129;
350 if (ingres_errno) return(mr_errcode);
356 status = name_to_id(name, tbl, &id);
357 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
364 validate_type(argv, vo)
366 register struct valobj *vo;
368 EXEC SQL BEGIN DECLARE SECTION;
372 EXEC SQL END DECLARE SECTION;
375 typename = vo->table;
376 c = val = argv[vo->index];
378 if (illegalchars[*c++])
382 /* uppercase type fields */
383 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
385 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
386 WHERE name = :typename AND type='TYPE' AND trans = :val;
387 if (ingres_errno) return(mr_errcode);
388 return (cnt ? MR_EXISTS : vo->error);
391 /* validate member or type-specific data field */
393 validate_typedata(q, argv, vo)
394 register struct query *q;
395 register char *argv[];
396 register struct valobj *vo;
398 EXEC SQL BEGIN DECLARE SECTION;
403 EXEC SQL END DECLARE SECTION;
407 /* get named object */
408 name = argv[vo->index];
410 /* get field type string (known to be at index-1) */
411 field_type = argv[vo->index-1];
413 /* get corresponding data type associated with field type name */
414 EXEC SQL SELECT trans INTO :data_type FROM alias
415 WHERE name = :field_type AND type='TYPEDATA';
416 if (ingres_errno) return(mr_errcode);
417 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
419 /* now retrieve the record id corresponding to the named object */
420 if (dbg_index(data_type, ' '))
421 *dbg_index(data_type, ' ') = 0;
422 if (!strcmp(data_type, "user")) {
424 if (dbg_index(name, '@'))
426 status = name_to_id(name, data_type, &id);
427 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
429 if (status) return(status);
430 } else if (!strcmp(data_type, "list")) {
432 status = name_to_id(name, data_type, &id);
433 if (status && status == MR_NOT_UNIQUE)
435 if (status == MR_NO_MATCH) {
436 /* if idfield is non-zero, then if argv[0] matches the string
437 * that we're trying to resolve, we should get the value of
438 * numvalues.[idfield] for the id.
440 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
441 set_next_object_id(q->validate->object_id, q->rtable, 0);
443 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
445 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
448 } else if (status) return(status);
449 } else if (!strcmp(data_type, "machine")) {
451 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
452 status = name_to_id(name, data_type, &id);
453 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
455 if (status) return(status);
456 } else if (!strcmp(data_type, "string")) {
458 status = name_to_id(name, data_type, &id);
459 if (status && status == MR_NOT_UNIQUE)
461 if (status == MR_NO_MATCH) {
462 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
464 cache_entry(name, "STRING", id);
465 } else if (status) return(status);
466 } else if (!strcmp(data_type, "none")) {
472 /* now set value in argv */
473 *(int *)argv[vo->index] = id;
479 /* Lock the table named by the validation object */
484 sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
485 vo->table,vo->table,vo->idfield);
486 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
487 if (ingres_errno) return(mr_errcode);
488 if (sqlca.sqlerrd[2] != 1)
495 /* Check the database at startup time. For now this just resets the
496 * inprogress flags that the DCM uses.
499 sanity_check_database()
504 /* Dynamic SQL support routines */
505 MR_SQLDA_T *mr_alloc_SQLDA()
508 short *null_indicators;
511 if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
512 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
516 if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
517 com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
521 for(j=0; j<QMAXARGS; j++) {
522 if((it->sqlvar[j].sqldata=(char *)malloc(sizeof(short)+ARGLEN))==NULL) {
523 com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
526 it->sqlvar[j].sqllen=ARGLEN;
527 it->sqlvar[j].sqlind=null_indicators+j;
528 null_indicators[j]=0;
535 /* Use this after FETCH USING DESCRIPTOR one or more
536 * result columns may contain NULLs. This routine is
537 * not currently needed, since db/schema creates all
538 * columns with a NOT NULL WITH DEFAULT clause.
540 * This is currently dead flesh, since no Moira columns
541 * allow null values; all use default values.
543 mr_fix_nulls_in_SQLDA(da)
546 register IISQLVAR *var;
550 for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
551 switch(var->sqltype) {
558 intp=(int *)var->sqldata;
566 /* Convert normal Unix-style wildcards to SQL voodoo */
567 convert_wildcards(arg)
570 static char buffer[ARGLEN];
571 register char *s, *d;
573 for(d=buffer,s=arg;*s;s++) {
575 case '*': *d++='%'; *d++='%'; break;
576 case '?': *d++='_'; break;
579 case ']': *d++='*'; *d++ = *s; break;
580 case '%': *d++='*'; *d++='%'; *d++='%'; break;
581 default: *d++ = *s; break;
586 /* Copy back into argv */
592 /* This version includes uppercase conversion, for things like gmac.
593 * This is necessary because "LIKE" doesn't work with "uppercase()".
594 * Including it in a wildcard routine saves making two passes over
595 * the argument string.
597 convert_wildcards_uppercase(arg)
600 static char buffer[ARGLEN];
601 register char *s, *d;
603 for(d=buffer,s=arg;*s;s++) {
605 case '*': *d++='%'; *d++='%'; break;
606 case '?': *d++='_'; break;
609 case ']': *d++='*'; *d++ = *s; break;
610 case '%': *d++='*'; *d++='%'; *d++='%'; break;
611 default: *d++=toupper(*s); break; /* This is the only diff. */
616 /* Copy back into argv */
623 /* Looks like it's time to build an abstraction barrier, Yogi */
625 EXEC SQL BEGIN DECLARE SECTION;
627 EXEC SQL END DECLARE SECTION;
631 EXEC SQL PREPARE stmt FROM :stmt;
632 EXEC SQL DESCRIBE stmt INTO :SQLDA;
633 if(SQLDA->sqld==0) /* Not a SELECT */
635 EXEC SQL DECLARE csr CURSOR FOR stmt;
637 EXEC SQL FETCH csr USING DESCRIPTOR :SQLDA;
640 else if((sqlca.sqlcode<0) && mr_errcode)
650 /* Adds a string to the string table. Returns the id number.
654 EXEC SQL BEGIN DECLARE SECTION;
656 EXEC SQL END DECLARE SECTION;
658 EXEC SQL BEGIN DECLARE SECTION;
661 EXEC SQL END DECLARE SECTION;
663 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
665 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
667 /* Use sprintf to get around problem with doubled single quotes */
668 sprintf(buf,"INSERT INTO strings (string_id, string) VALUES (%d, '%s')",id,name);
669 EXEC SQL EXECUTE IMMEDIATE :buf;