]> andersk Git - moira.git/blame - server/qvalidate.dc
fixed lint problem; moved prefetch_value to qaccess.dc
[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>
18#include "query.h"
19#include "mr_server.h"
20#include <ctype.h>
21EXEC SQL INCLUDE sqlca;
22EXEC SQL INCLUDE sqlda;
23#include "qrtn.h"
24
25extern char *whoami;
26extern int ingres_errno, mr_errcode;
27
28EXEC SQL BEGIN DECLARE SECTION;
29extern char stmt_buf[];
30EXEC SQL END DECLARE SECTION;
31
32EXEC SQL WHENEVER SQLERROR CALL ingerr;
33
34
35/* Validation Routines */
36
37validate_row(q, argv, v)
38 register struct query *q;
39 char *argv[];
40 register struct validate *v;
41{
42 EXEC SQL BEGIN DECLARE SECTION;
43 char *name;
44 char qual[128];
45 int rowcount;
46 EXEC SQL END DECLARE SECTION;
47
48 /* build where clause */
49 build_qual(v->qual, v->argc, argv, qual);
50
51 if (log_flags & LOG_VALID)
52 /* tell the logfile what we're doing */
53 com_err(whoami, 0, "validating row: %s", qual);
54
55 /* look for the record */
56 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
57 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
58 if(sqlca.sqlcode)
59 return(MR_INTERNAL);
60 EXEC SQL DECLARE csr126 CURSOR FOR stmt;
61 EXEC SQL OPEN csr126;
62 EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
63 EXEC SQL CLOSE csr126;
64 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
65
66 if (ingres_errno) return(mr_errcode);
67 if (rowcount == 0) return(MR_NO_MATCH);
68 if (rowcount > 1) return(MR_NOT_UNIQUE);
69 return(MR_EXISTS);
70}
71
72validate_fields(q, argv, vo, n)
73 struct query *q;
74 register char *argv[];
75 register struct valobj *vo;
76 register int n;
77{
78 register int status;
79
80 while (--n >= 0) {
81 switch (vo->type) {
82 case V_NAME:
83 if (log_flags & LOG_VALID)
84 com_err(whoami, 0, "validating %s in %s: %s",
85 vo->namefield, vo->table, argv[vo->index]);
86 status = validate_name(argv, vo);
87 break;
88
89 case V_ID:
90 if (log_flags & LOG_VALID)
91 com_err(whoami, 0, "validating %s in %s: %s",
92 vo->idfield, vo->table, argv[vo->index]);
93 status = validate_id(q, argv, vo);
94 break;
95
96 case V_DATE:
97 if (log_flags & LOG_VALID)
98 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
99 status = validate_date(argv, vo);
100 break;
101
102 case V_TYPE:
103 if (log_flags & LOG_VALID)
104 com_err(whoami, 0, "validating %s type: %s",
105 vo->table, argv[vo->index]);
106 status = validate_type(argv, vo);
107 break;
108
109 case V_TYPEDATA:
110 if (log_flags & LOG_VALID)
111 com_err(whoami, 0, "validating typed data (%s): %s",
112 argv[vo->index - 1], argv[vo->index]);
113 status = validate_typedata(q, argv, vo);
114 break;
115
116 case V_RENAME:
117 if (log_flags & LOG_VALID)
118 com_err(whoami, 0, "validating rename %s in %s",
119 argv[vo->index], vo->table);
120 status = validate_rename(argv, vo);
121 break;
122
123 case V_CHAR:
124 if (log_flags & LOG_VALID)
125 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
126 status = validate_chars(argv[vo->index]);
127 break;
128
129 case V_SORT:
130 status = MR_EXISTS;
131 break;
132
133 case V_LOCK:
134 status = lock_table(vo);
135 break;
136
137 case V_WILD:
138 status = convert_wildcards(argv[vo->index]);
139 break;
140
141 case V_UPWILD:
142 status = convert_wildcards_uppercase(argv[vo->index]);
143 break;
144
145 }
146
147 if (status != MR_EXISTS) return(status);
148 vo++;
149 }
150
151 if (ingres_errno) return(mr_errcode);
152 return(MR_SUCCESS);
153}
154
155
156/* validate_chars: verify that there are no illegal characters in
157 * the string. Legal characters are printing chars other than
158 * ", *, ?, \, [ and ].
159 */
160static int illegalchars[] = {
161 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
162 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
163 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
165 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
166 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
167 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
169 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
170 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
171 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
173 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
174 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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};
178
179validate_chars(s)
180register char *s;
181{
182 while (*s)
183 if (illegalchars[*s++])
184 return(MR_BAD_CHAR);
185 return(MR_EXISTS);
186}
187
188
189validate_id(q, argv, vo)
190 struct query *q;
191 char *argv[];
192 register struct valobj *vo;
193{
194 EXEC SQL BEGIN DECLARE SECTION;
195 char *name, *tbl, *namefield, *idfield;
196 int id, rowcount;
197 EXEC SQL END DECLARE SECTION;
198 int status;
199 register char *c;
200
201 name = argv[vo->index];
202 tbl = vo->table;
203 namefield = vo->namefield;
204 idfield = vo->idfield;
205
206 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
207 !strcmp(tbl, "machine") ||
208 !strcmp(tbl, "subnet") ||
209 !strcmp(tbl, "filesys") ||
210 !strcmp(tbl, "list") ||
211 !strcmp(tbl, "cluster") ||
212 !strcmp(tbl, "strings")) {
213 if (!strcmp(tbl, "machine") || !strcmp(tbl, "subnet"))
214 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
215 status = name_to_id(name, tbl, &id);
216 if (status == 0) {
217 *(int *)argv[vo->index] = id;
218 return(MR_EXISTS);
219 } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
220 (q->type == APPEND || q->type == UPDATE)) {
221 id=add_string(name);
222 cache_entry(name, "STRING", id);
223 *(int *)argv[vo->index] = id;
224 return(MR_EXISTS);
225 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
226 return(vo->error);
227 else
228 return(status);
229 }
230
231 if (!strcmp(namefield, "uid")) {
232 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
233 } else {
234 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
235 }
236 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
237 if(sqlca.sqlcode)
238 return(MR_INTERNAL);
239 EXEC SQL DECLARE csr127 CURSOR FOR stmt;
240 EXEC SQL OPEN csr127;
241 rowcount=0;
242 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
243 if(sqlca.sqlcode == 0) {
244 rowcount++;
245 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
246 if(sqlca.sqlcode == 0) rowcount++;
247 }
248 EXEC SQL CLOSE csr127;
249 if (ingres_errno)
250 return(mr_errcode);
251
252 if (rowcount != 1) return(vo->error);
253 bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
254 return(MR_EXISTS);
255}
256
257validate_name(argv, vo)
258 char *argv[];
259 register struct valobj *vo;
260{
261 EXEC SQL BEGIN DECLARE SECTION;
262 char *name, *tbl, *namefield;
263 int rowcount;
264 EXEC SQL END DECLARE SECTION;
265 register char *c;
266
267 name = argv[vo->index];
268 tbl = vo->table;
269 namefield = vo->namefield;
270 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
271 for (c = name; *c; c++)
272 if (islower(*c))
273 *c = toupper(*c);
274 }
275 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
276 tbl,tbl,namefield,name);
277 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
278 if(sqlca.sqlcode)
279 return(MR_INTERNAL);
280 EXEC SQL DECLARE csr128 CURSOR FOR stmt;
281 EXEC SQL OPEN csr128;
282 EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
283 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
284 EXEC SQL CLOSE csr128;
285
286 if (ingres_errno) return(mr_errcode);
287 return ((rowcount == 1) ? MR_EXISTS : vo->error);
288}
289
290validate_date(argv, vo)
291 char *argv[];
292 struct valobj *vo;
293{
294 EXEC SQL BEGIN DECLARE SECTION;
295 char *idate;
296 double dd;
297 int errorno;
298 EXEC SQL END DECLARE SECTION;
299
300 idate = argv[vo->index];
301 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
302
303 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
304 return(MR_EXISTS);
305}
306
307
308validate_rename(argv, vo)
309char *argv[];
310struct valobj *vo;
311{
312 EXEC SQL BEGIN DECLARE SECTION;
313 char *name, *tbl, *namefield, *idfield;
314 int id;
315 EXEC SQL END DECLARE SECTION;
316 int status;
317 register char *c;
318
319 c = name = argv[vo->index];
320 while (*c)
321 if (illegalchars[*c++])
322 return(MR_BAD_CHAR);
323 tbl = vo->table;
324 /* minor kludge to upcasify machine names */
325 if (!strcmp(tbl, "machine"))
326 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
327 namefield = vo->namefield;
328 idfield = vo->idfield;
329 id = -1;
330 if (idfield == 0) {
331 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
332 return(MR_EXISTS);
333 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
334 namefield,tbl,namefield,name,namefield);
335 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
336 if(sqlca.sqlcode)
337 return(MR_INTERNAL);
338 EXEC SQL DECLARE csr129 CURSOR FOR stmt;
339 EXEC SQL OPEN csr129;
340 EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
341 if(sqlca.sqlcode == 0) id=1; else id=0;
342 EXEC SQL CLOSE csr129;
343
344 if (ingres_errno) return(mr_errcode);
345 if (id)
346 return(vo->error);
347 else
348 return(MR_EXISTS);
349 }
350 status = name_to_id(name, tbl, &id);
351 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
352 return(MR_EXISTS);
353 else
354 return(vo->error);
355}
356
357
358validate_type(argv, vo)
359 char *argv[];
360 register struct valobj *vo;
361{
362 EXEC SQL BEGIN DECLARE SECTION;
363 char *typename;
364 char *val;
365 int cnt;
366 EXEC SQL END DECLARE SECTION;
367 register char *c;
368
369 typename = vo->table;
370 c = val = argv[vo->index];
371 while (*c) {
372 if (illegalchars[*c++])
373 return(MR_BAD_CHAR);
374 }
375
376 /* uppercase type fields */
377 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
378
379 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
380 WHERE name = :typename AND type='TYPE' AND trans = :val;
381 if (ingres_errno) return(mr_errcode);
382 return (cnt ? MR_EXISTS : vo->error);
383}
384
385/* validate member or type-specific data field */
386
387validate_typedata(q, argv, vo)
388 register struct query *q;
389 register char *argv[];
390 register struct valobj *vo;
391{
392 EXEC SQL BEGIN DECLARE SECTION;
393 char *name;
394 char *field_type;
395 char data_type[129];
396 int id;
397 EXEC SQL END DECLARE SECTION;
398 int status;
399 char *index();
400 register char *c;
401
402 /* get named object */
403 name = argv[vo->index];
404
405 /* get field type string (known to be at index-1) */
406 field_type = argv[vo->index-1];
407
408 /* get corresponding data type associated with field type name */
409 EXEC SQL SELECT trans INTO :data_type FROM alias
410 WHERE name = :field_type AND type='TYPEDATA';
411 if (ingres_errno) return(mr_errcode);
412 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
413
414 /* now retrieve the record id corresponding to the named object */
415 if (index(data_type, ' '))
416 *index(data_type, ' ') = 0;
417 if (!strcmp(data_type, "user")) {
418 /* USER */
419 if (index(name, '@'))
420 return(MR_USER);
421 status = name_to_id(name, data_type, &id);
422 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
423 return(MR_USER);
424 if (status) return(status);
425 } else if (!strcmp(data_type, "list")) {
426 /* LIST */
427 status = name_to_id(name, data_type, &id);
428 if (status && status == MR_NOT_UNIQUE)
429 return(MR_LIST);
430 if (status == MR_NO_MATCH) {
431 /* if idfield is non-zero, then if argv[0] matches the string
432 * that we're trying to resolve, we should get the value of
433 * numvalues.[idfield] for the id.
434 */
435 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
436 set_next_object_id(q->validate->object_id, q->rtable, 0);
437 name = vo->idfield;
438 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
439 WHERE name = :name;
440 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
441 } else
442 return(MR_LIST);
443 } else if (status) return(status);
444 } else if (!strcmp(data_type, "machine")) {
445 /* MACHINE */
446 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
447 status = name_to_id(name, data_type, &id);
448 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
449 return(MR_MACHINE);
450 if (status) return(status);
451 } else if (!strcmp(data_type, "string")) {
452 /* STRING */
453 status = name_to_id(name, data_type, &id);
454 if (status && status == MR_NOT_UNIQUE)
455 return(MR_STRING);
456 if (status == MR_NO_MATCH) {
457 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
458 id=add_string(name);
459 cache_entry(name, "STRING", id);
460 } else if (status) return(status);
461 } else if (!strcmp(data_type, "none")) {
462 id = 0;
463 } else {
464 return(MR_TYPE);
465 }
466
467 /* now set value in argv */
468 *(int *)argv[vo->index] = id;
469
470 return (MR_EXISTS);
471}
472
473
474/* Lock the table named by the validation object */
475
476lock_table(vo)
477struct valobj *vo;
478{
479 sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
480 vo->table,vo->table,vo->idfield);
481 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
482 if (ingres_errno) return(mr_errcode);
483 if (sqlca.sqlerrd[2] != 1)
484 return(vo->error);
485 else
486 return(MR_EXISTS);
487}
488
489
490/* Check the database at startup time. For now this just resets the
491 * inprogress flags that the DCM uses.
492 */
493
494sanity_check_database()
495{
496}
497
498
499/* Dynamic SQL support routines */
500MR_SQLDA_T *mr_alloc_SQLDA()
501{
502 MR_SQLDA_T *it;
503 short *null_indicators;
504 register int j;
505
506 if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
507 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
508 exit(1);
509 }
510
511 if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
512 com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
513 exit(1);
514 }
515
516 for(j=0; j<QMAXARGS; j++) {
6612addc 517 if((it->sqlvar[j].sqldata=(char *)malloc(sizeof(short)+ARGLEN))==NULL) {
73cf66ba 518 com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
519 exit(1);
520 }
521 it->sqlvar[j].sqllen=ARGLEN;
522 it->sqlvar[j].sqlind=null_indicators+j;
523 null_indicators[j]=0;
524 }
525 it->sqln=QMAXARGS;
526 return it;
527}
528
529
530/* Use this after FETCH USING DESCRIPTOR one or more
531 * result columns may contain NULLs. This routine is
532 * not currently needed, since db/schema creates all
533 * columns with a NOT NULL WITH DEFAULT clause.
534 *
535 * This is currently dead flesh, since no Moira columns
536 * allow null values; all use default values.
537 */
538mr_fix_nulls_in_SQLDA(da)
539 MR_SQLDA_T *da;
540{
541 register IISQLVAR *var;
542 register int j;
543 int *intp;
544
545 for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
546 switch(var->sqltype) {
547 case -IISQ_CHA_TYPE:
548 if(*var->sqlind)
549 *var->sqldata='\0';
550 break;
551 case -IISQ_INT_TYPE:
552 if(*var->sqlind) {
553 intp=(int *)var->sqldata;
554 *intp=0;
555 }
556 break;
557 }
558 }
559}
560
73cf66ba 561/* Convert normal Unix-style wildcards to SQL voodoo */
562convert_wildcards(arg)
563 char *arg;
564{
565 static char buffer[ARGLEN];
566 register char *s, *d;
567
568 for(d=buffer,s=arg;*s;s++) {
569 switch(*s) {
570 case '*': *d++='%'; *d++='%'; break;
571 case '?': *d++='_'; break;
572 case '_':
573 case '[':
574 case ']': *d++='*'; *d++ = *s; break;
575 case '%': *d++='*'; *d++='%'; *d++='%'; break;
576 default: *d++ = *s; break;
577 }
578 }
579 *d='\0';
580
581 /* Copy back into argv */
582 strcpy(arg,buffer);
583
584 return(MR_EXISTS);
585}
586
587/* This version includes uppercase conversion, for things like gmac.
588 * This is necessary because "LIKE" doesn't work with "uppercase()".
589 * Including it in a wildcard routine saves making two passes over
590 * the argument string.
591 */
592convert_wildcards_uppercase(arg)
593 char *arg;
594{
595 static char buffer[ARGLEN];
596 register char *s, *d;
597
598 for(d=buffer,s=arg;*s;s++) {
599 switch(*s) {
600 case '*': *d++='%'; *d++='%'; break;
601 case '?': *d++='_'; break;
602 case '_':
603 case '[':
604 case ']': *d++='*'; *d++ = *s; break;
605 case '%': *d++='*'; *d++='%'; *d++='%'; break;
606 default: *d++=toupper(*s); break; /* This is the only diff. */
607 }
608 }
609 *d='\0';
610
611 /* Copy back into argv */
612 strcpy(arg,buffer);
613
614 return(MR_EXISTS);
615}
616
617
618/* Looks like it's time to build an abstraction barrier, Yogi */
619mr_select_any(stmt)
620 EXEC SQL BEGIN DECLARE SECTION;
621 char *stmt;
622 EXEC SQL END DECLARE SECTION;
623{
624 int result=0;
625
626 EXEC SQL PREPARE stmt FROM :stmt;
627 EXEC SQL DESCRIBE stmt INTO :SQLDA;
628 if(SQLDA->sqld==0) /* Not a SELECT */
629 return(MR_INTERNAL);
630 EXEC SQL DECLARE csr CURSOR FOR stmt;
631 EXEC SQL OPEN csr;
632 EXEC SQL FETCH csr USING DESCRIPTOR :SQLDA;
633 if(sqlca.sqlcode==0)
634 result=MR_EXISTS;
635 else if((sqlca.sqlcode<0) && mr_errcode)
636 result=mr_errcode;
637 else
638 result=0;
639 EXEC SQL CLOSE csr;
640 return(result);
641}
642
643
644
645/* Adds a string to the string table. Returns the id number.
646 *
647 */
648int add_string(name)
649 EXEC SQL BEGIN DECLARE SECTION;
650 char *name;
651 EXEC SQL END DECLARE SECTION;
652{
653 EXEC SQL BEGIN DECLARE SECTION;
654 char buf[256];
655 int id;
656 EXEC SQL END DECLARE SECTION;
657
658 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
659 id++;
660 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
661
662 /* Use sprintf to get around problem with doubled single quotes */
663 sprintf(buf,"INSERT INTO strings (string_id, string) VALUES (%d, '%s')",id,name);
664 EXEC SQL EXECUTE IMMEDIATE :buf;
665
666 return(id);
667}
668
This page took 0.133127 seconds and 5 git commands to generate.