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