]> andersk Git - moira.git/blame - server/qvalidate.pc
Remove all references to table locking, since
[moira.git] / server / qvalidate.pc
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);
f0e5d2fe 40int validate_num(char *argv[], struct valobj *vo);
03c05291 41int convert_wildcards_uppercase(char *arg);
73cf66ba 42
960b073b 43extern SQLDA *sqlald(int,int,int);
44
03c05291 45EXEC SQL WHENEVER SQLERROR DO dbmserr();
73cf66ba 46
47/* Validation Routines */
48
03c05291 49int validate_row(q, argv, v)
73cf66ba 50 register struct query *q;
51 char *argv[];
52 register struct validate *v;
53{
54 EXEC SQL BEGIN DECLARE SECTION;
73cf66ba 55 char qual[128];
56 int rowcount;
57 EXEC SQL END DECLARE SECTION;
58
59 /* build where clause */
60 build_qual(v->qual, v->argc, argv, qual);
61
62 if (log_flags & LOG_VALID)
63 /* tell the logfile what we're doing */
64 com_err(whoami, 0, "validating row: %s", qual);
65
66 /* look for the record */
03c05291 67 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",
68 table_name[q->rtable],qual);
69 dosql(sqlbuffer);
70 if (dbms_errno) return(mr_errcode);
71
72 rowcount = atoi(sqlbuffer[0]);
73cf66ba 73 if (rowcount == 0) return(MR_NO_MATCH);
74 if (rowcount > 1) return(MR_NOT_UNIQUE);
75 return(MR_EXISTS);
76}
77
03c05291 78int validate_fields(q, argv, vo, n)
73cf66ba 79 struct query *q;
80 register char *argv[];
81 register struct valobj *vo;
82 register int n;
83{
84 register int status;
85
86 while (--n >= 0) {
87 switch (vo->type) {
88 case V_NAME:
89 if (log_flags & LOG_VALID)
90 com_err(whoami, 0, "validating %s in %s: %s",
03c05291 91 vo->namefield, table_name[vo->table], argv[vo->index]);
73cf66ba 92 status = validate_name(argv, vo);
93 break;
94
95 case V_ID:
96 if (log_flags & LOG_VALID)
97 com_err(whoami, 0, "validating %s in %s: %s",
03c05291 98 vo->idfield, table_name[vo->table], argv[vo->index]);
73cf66ba 99 status = validate_id(q, argv, vo);
100 break;
101
73cf66ba 102 case V_TYPE:
103 if (log_flags & LOG_VALID)
104 com_err(whoami, 0, "validating %s type: %s",
03c05291 105 table_name[vo->table], argv[vo->index]);
73cf66ba 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",
03c05291 119 argv[vo->index], table_name[vo->table]);
73cf66ba 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]);
03c05291 126 status = validate_chars(argv, vo);
127 break;
128
129 case V_LEN:
130 if (log_flags & LOG_VALID)
131 com_err(whoami, 0, "validating length: %s", argv[vo->index]);
132 status = validate_len(argv, vo);
73cf66ba 133 break;
134
f0e5d2fe 135 case V_NUM:
136 if (log_flags & LOG_VALID)
137 com_err(whoami, 0, "validating number: %s", argv[vo->index]);
138 status = validate_num(argv, vo);
139 break;
140
03c05291 141 case V_WILD:
73cf66ba 142 status = convert_wildcards(argv[vo->index]);
143 break;
144
145 case V_UPWILD:
146 status = convert_wildcards_uppercase(argv[vo->index]);
147 break;
148
149 }
150
151 if (status != MR_EXISTS) return(status);
152 vo++;
153 }
154
03c05291 155 if (dbms_errno) return(mr_errcode);
73cf66ba 156 return(MR_SUCCESS);
157}
158
159
160/* validate_chars: verify that there are no illegal characters in
161 * the string. Legal characters are printing chars other than
162 * ", *, ?, \, [ and ].
163 */
164static int illegalchars[] = {
165 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
166 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
167 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
169 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
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, 0, 0, 0, 0, 1, /* p - ^? */
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 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};
182
03c05291 183int validate_chars(argv, vo)
184 char *argv[];
185 register struct valobj *vo;
73cf66ba 186{
03c05291 187 char *s=argv[vo->index];
188 int arg;
189 EXEC SQL BEGIN DECLARE SECTION;
190 int len;
191 char *tname, *cname;
192 EXEC SQL END DECLARE SECTION;
193
194
195 /* check for bad characters */
73cf66ba 196 while (*s)
197 if (illegalchars[*s++])
198 return(MR_BAD_CHAR);
03c05291 199
200 /* check for length */
201 tname = table_name[vo->table];
202 cname = vo->namefield;
203 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
204 WHERE table_name=UPPER(:tname) AND column_name=UPPER(:cname);
205
206 if((strlen(argv[vo->index]) > len) &&
207 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
208 argv[vo->index][len]='\0'; /* truncate */
209
210 return MR_EXISTS;
73cf66ba 211}
212
213
03c05291 214int validate_id(q, argv, vo)
73cf66ba 215 struct query *q;
216 char *argv[];
217 register struct valobj *vo;
218{
219 EXEC SQL BEGIN DECLARE SECTION;
03c05291 220 char *name, *namefield, *idfield;
221 int id, rowcount, tbl;
73cf66ba 222 EXEC SQL END DECLARE SECTION;
223 int status;
224 register char *c;
225
226 name = argv[vo->index];
227 tbl = vo->table;
228 namefield = vo->namefield;
229 idfield = vo->idfield;
230
03c05291 231 if ((tbl==USERS_TABLE && !strcmp(namefield, "login")) ||
232 tbl==MACHINE_TABLE || tbl==SUBNET_TABLE || tbl==FILESYS_TABLE ||
233 tbl==LIST_TABLE || tbl==CLUSTER_TABLE || tbl==STRINGS_TABLE) {
234 if (tbl==MACHINE_TABLE || tbl==SUBNET_TABLE)
235 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
236 status = name_to_id(name, tbl, &id);
237 if (status == 0) {
238 *(int *)argv[vo->index] = id;
239 return(MR_EXISTS);
240 } else if (status == MR_NO_MATCH && tbl==STRINGS_TABLE &&
241 (q->type == APPEND || q->type == UPDATE)) {
242 id=add_string(name);
243 cache_entry(name, STRINGS_TABLE, id);
244 *(int *)argv[vo->index] = id;
245 return(MR_EXISTS);
246 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
247 return(vo->error);
248 else
249 return(status);
73cf66ba 250 } else {
03c05291 251 /* else, it's `dubu', which uses unix_uid from users */
252 EXEC SQL SELECT COUNT(*) INTO :rowcount FROM users
253 WHERE unix_uid = :name;
254 if (dbms_errno) return(mr_errcode);
255 if (rowcount != 1) return(vo->error);
256 EXEC SQL SELECT users_id INTO :id FROM users
257 WHERE unix_uid = :name;
258 *(int *)argv[vo->index] = id;
259 return(MR_EXISTS);
73cf66ba 260 }
73cf66ba 261}
262
03c05291 263int validate_name(argv, vo)
73cf66ba 264 char *argv[];
265 register struct valobj *vo;
266{
03c05291 267 char *name, *namefield;
73cf66ba 268 register char *c;
269
270 name = argv[vo->index];
73cf66ba 271 namefield = vo->namefield;
03c05291 272 if (vo->table==SERVERS_TABLE && !strcmp(namefield, "name")) {
73cf66ba 273 for (c = name; *c; c++)
274 if (islower(*c))
275 *c = toupper(*c);
276 }
277 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
03c05291 278 table_name[vo->table],table_name[vo->table],namefield,name);
279 dosql(sqlbuffer);
280
281 if (dbms_errno) return(mr_errcode);
282 return ((atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error);
73cf66ba 283}
284
03c05291 285int validate_rename(argv, vo)
286 char *argv[];
287 struct valobj *vo;
73cf66ba 288{
289 EXEC SQL BEGIN DECLARE SECTION;
03c05291 290 char *name, *namefield, *idfield;
73cf66ba 291 int id;
292 EXEC SQL END DECLARE SECTION;
293 int status;
294 register char *c;
295
03c05291 296 status = validate_chars(argv, vo);
297 if(status != MR_EXISTS) return status;
298 name=argv[vo->index];
73cf66ba 299 /* minor kludge to upcasify machine names */
03c05291 300 if (vo->table == MACHINE_TABLE)
73cf66ba 301 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
302 namefield = vo->namefield;
303 idfield = vo->idfield;
304 id = -1;
305 if (idfield == 0) {
306 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
307 return(MR_EXISTS);
03c05291 308 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",
309 namefield,table_name[vo->table],namefield,name);
310 dosql(sqlbuffer);
311
312 if (dbms_errno) return(mr_errcode);
313 if (sqlca.sqlcode==SQL_NO_MATCH)
314 return(MR_EXISTS); /* how's _that_ for intuitive? */
73cf66ba 315 else
03c05291 316 return(vo->error);
73cf66ba 317 }
03c05291 318 status = name_to_id(name, vo->table, &id);
73cf66ba 319 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
320 return(MR_EXISTS);
321 else
322 return(vo->error);
323}
324
325
03c05291 326int validate_type(argv, vo)
73cf66ba 327 char *argv[];
328 register struct valobj *vo;
329{
330 EXEC SQL BEGIN DECLARE SECTION;
331 char *typename;
332 char *val;
333 int cnt;
334 EXEC SQL END DECLARE SECTION;
335 register char *c;
336
03c05291 337 typename = vo->namefield;
73cf66ba 338 c = val = argv[vo->index];
339 while (*c) {
340 if (illegalchars[*c++])
341 return(MR_BAD_CHAR);
342 }
343
344 /* uppercase type fields */
345 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
346
347 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
348 WHERE name = :typename AND type='TYPE' AND trans = :val;
03c05291 349 if (dbms_errno) return(mr_errcode);
73cf66ba 350 return (cnt ? MR_EXISTS : vo->error);
351}
352
353/* validate member or type-specific data field */
354
03c05291 355int validate_typedata(q, argv, vo)
73cf66ba 356 register struct query *q;
357 register char *argv[];
358 register struct valobj *vo;
359{
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;
73cf66ba 367 register char *c;
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';
03c05291 378 if (dbms_errno) return(mr_errcode);
73cf66ba 379 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
380
381 /* now retrieve the record id corresponding to the named object */
03c05291 382 if (strchr(data_type, ' '))
383 *strchr(data_type, ' ') = 0;
73cf66ba 384 if (!strcmp(data_type, "user")) {
385 /* USER */
03c05291 386 if (strchr(name, '@'))
73cf66ba 387 return(MR_USER);
03c05291 388 status = name_to_id(name, USERS_TABLE, &id);
73cf66ba 389 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
390 return(MR_USER);
391 if (status) return(status);
392 } else if (!strcmp(data_type, "list")) {
393 /* LIST */
03c05291 394 status = name_to_id(name, LIST_TABLE, &id);
73cf66ba 395 if (status && status == MR_NOT_UNIQUE)
396 return(MR_LIST);
397 if (status == MR_NO_MATCH) {
398 /* if idfield is non-zero, then if argv[0] matches the string
399 * that we're trying to resolve, we should get the value of
400 * numvalues.[idfield] for the id.
401 */
402 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
403 set_next_object_id(q->validate->object_id, q->rtable, 0);
404 name = vo->idfield;
03c05291 405 EXEC SQL SELECT value INTO :id FROM numvalues
73cf66ba 406 WHERE name = :name;
407 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
408 } else
409 return(MR_LIST);
410 } else if (status) return(status);
411 } else if (!strcmp(data_type, "machine")) {
412 /* MACHINE */
413 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
03c05291 414 status = name_to_id(name, MACHINE_TABLE, &id);
73cf66ba 415 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
416 return(MR_MACHINE);
417 if (status) return(status);
418 } else if (!strcmp(data_type, "string")) {
419 /* STRING */
03c05291 420 status = name_to_id(name, STRINGS_TABLE, &id);
73cf66ba 421 if (status && status == MR_NOT_UNIQUE)
422 return(MR_STRING);
423 if (status == MR_NO_MATCH) {
424 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
425 id=add_string(name);
03c05291 426 cache_entry(name, STRINGS_TABLE, id);
73cf66ba 427 } else if (status) return(status);
428 } else if (!strcmp(data_type, "none")) {
429 id = 0;
430 } else {
431 return(MR_TYPE);
432 }
433
434 /* now set value in argv */
435 *(int *)argv[vo->index] = id;
436
437 return (MR_EXISTS);
438}
439
440
03c05291 441/* Make sure the data fits in the field */
442int validate_len(argv, vo)
443 register char *argv[];
444 register struct valobj *vo;
445{
446 EXEC SQL BEGIN DECLARE SECTION;
447 int len;
448 char *tname, *cname;
449 EXEC SQL END DECLARE SECTION;
450
451 tname = table_name[vo->table];
452 cname = vo->namefield;
453 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
454 WHERE table_name=UPPER(:tname) AND column_name=UPPER(:cname);
455
456 if((strlen(argv[vo->index]) > len) &&
457 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
458 argv[vo->index][len]='\0'; /* truncate */
459
460 return MR_EXISTS;
461}
462
f0e5d2fe 463/* Make sure the data is numeric */
464int validate_num(argv, vo)
465 register char *argv[];
466 register struct valobj *vo;
467{
468 char *p = argv[vo->index];
469
470 if (*p == '-') p++;
471 for (;*p;p++)
472 if (*p < '0' || *p > '9') return MR_INTEGER;
473
474 return MR_EXISTS;
475}
476
695afd0d 477/* Check the database at startup time. */
03c05291 478
479void sanity_check_database(void)
480{
695afd0d 481 EXEC SQL BEGIN DECLARE SECTION;
482 int oid, id;
483 EXEC SQL END DECLARE SECTION;
484
485 /* Sometimes a crash can leave strings_id in numvalues in an
486 incorrect state. Check for that and fix it. */
487
488 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name='strings_id';
489
490 for (id=oid+1; sqlca.sqlcode==0; id++)
491 EXEC SQL SELECT string_id INTO :id FROM strings
492 WHERE string_id=:id;
493
494 if (id!=oid+1)
495 EXEC SQL UPDATE numvalues SET value=:id-1 WHERE name='strings_id';
03c05291 496}
497
498
499char *sqlbuffer[QMAXARGS];
73cf66ba 500
501/* Dynamic SQL support routines */
03c05291 502SQLDA *mr_alloc_sqlda()
73cf66ba 503{
03c05291 504 SQLDA *it;
73cf66ba 505 register int j;
506
03c05291 507 it=sqlald(QMAXARGS, ARGLEN, 0);
508 if(it==NULL) {
73cf66ba 509 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
510 exit(1);
511 }
512
73cf66ba 513 for(j=0; j<QMAXARGS; j++) {
03c05291 514 it->V[j]=sqlbuffer[j]=malloc(ARGLEN);
515 it->T[j]=97; /* 97 = CHARZ = null-terminated string */
516 it->L[j]=ARGLEN;
73cf66ba 517 }
03c05291 518
73cf66ba 519 return it;
520}
521
522
73cf66ba 523/* Convert normal Unix-style wildcards to SQL voodoo */
03c05291 524int convert_wildcards(arg)
73cf66ba 525 char *arg;
526{
527 static char buffer[ARGLEN];
528 register char *s, *d;
529
530 for(d=buffer,s=arg;*s;s++) {
531 switch(*s) {
532 case '*': *d++='%'; *d++='%'; break;
533 case '?': *d++='_'; break;
936820fd 534 case '_': *d++='*'; *d++ = *s; break;
73cf66ba 535 case '%': *d++='*'; *d++='%'; *d++='%'; break;
536 default: *d++ = *s; break;
537 }
538 }
539 *d='\0';
540
541 /* Copy back into argv */
542 strcpy(arg,buffer);
543
544 return(MR_EXISTS);
545}
546
547/* This version includes uppercase conversion, for things like gmac.
548 * This is necessary because "LIKE" doesn't work with "uppercase()".
549 * Including it in a wildcard routine saves making two passes over
550 * the argument string.
551 */
03c05291 552int convert_wildcards_uppercase(arg)
73cf66ba 553 char *arg;
554{
555 static char buffer[ARGLEN];
556 register char *s, *d;
557
558 for(d=buffer,s=arg;*s;s++) {
559 switch(*s) {
560 case '*': *d++='%'; *d++='%'; break;
561 case '?': *d++='_'; break;
936820fd 562 case '_': *d++='*'; *d++ = *s; break;
73cf66ba 563 case '%': *d++='*'; *d++='%'; *d++='%'; break;
564 default: *d++=toupper(*s); break; /* This is the only diff. */
565 }
566 }
567 *d='\0';
568
569 /* Copy back into argv */
570 strcpy(arg,buffer);
571
572 return(MR_EXISTS);
573}
574
575
73cf66ba 576/* Adds a string to the string table. Returns the id number.
577 *
578 */
579int add_string(name)
580 EXEC SQL BEGIN DECLARE SECTION;
581 char *name;
582 EXEC SQL END DECLARE SECTION;
583{
584 EXEC SQL BEGIN DECLARE SECTION;
585 char buf[256];
586 int id;
587 EXEC SQL END DECLARE SECTION;
588
589 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
590 id++;
591 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
592
03c05291 593 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
73cf66ba 594
595 return(id);
596}
This page took 0.142435 seconds and 5 git commands to generate.