]> andersk Git - moira.git/blob - server/qrtn.dc
c3dc6e8a6e122e4a7691f50d2c24d1b6ad290010
[moira.git] / server / qrtn.dc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987, 1988 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_qrtn_dc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include <string.h>
18 #include "query.h"
19 #include "mr_server.h"
20 EXEC SQL INCLUDE sqlca;  /* SQL Communications Area */
21 EXEC SQL INCLUDE sqlda;  /* SQL Descriptor Area */
22 #include "qrtn.h"
23
24 MR_SQLDA_T *SQLDA;
25 EXEC SQL BEGIN DECLARE SECTION; 
26 int mr_sig_length;
27 int idummy;                            
28 char cdummy[MR_CDUMMY_LEN];            
29 char stmt_buf[MR_STMTBUF_LEN];
30 EXEC SQL END DECLARE SECTION; 
31
32 char *Argv[QMAXARGS];
33
34 int ingres_errno = 0;
35 int mr_errcode = 0;
36 EXEC SQL BEGIN DECLARE SECTION; 
37 int query_timeout = 30;
38 char *database = "moira";
39 EXEC SQL END DECLARE SECTION;
40 extern char *whoami;
41 extern FILE *journal;
42
43 #define INGRES_BAD_DATE1  40206
44 #define INGRES_BAD_DATE2  40207
45 #define INGRES_DEADLOCK   49900
46 #define INGRES_TIMEOUT    39100
47 #define INGRES_BAD_COLUMN 30110
48 #define INGRES_ASGN_ERR   40204
49 #define INGRES_NO_CURSOR  30120
50 #define INGRES_NO_STMT    30130
51
52 /*
53  * ingerr: Called when Ingres indicates an error.
54  */
55
56 void ingerr()
57 {
58     EXEC SQL BEGIN DECLARE SECTION; 
59     char err_msg[256];
60     EXEC SQL END DECLARE SECTION;
61     ingres_errno = -sqlca.sqlcode;
62
63     switch (ingres_errno) {
64       case INGRES_BAD_DATE1:
65       case INGRES_BAD_DATE2:
66         mr_errcode = MR_DATE;
67         break;
68       case INGRES_DEADLOCK:
69         mr_errcode = MR_DEADLOCK;
70         com_err(whoami, 0, "INGRES deadlock detected");
71         break;
72       case INGRES_TIMEOUT:
73 /* May be something other than timeout! #39100 is "Unknown error" 
74  * Really should parse the error message enough to decide if it's a timeout */
75         mr_errcode = MR_BUSY;
76         com_err(whoami, 0, "timed out getting lock");
77         break;
78 /* These should never come up unless someone breaks the query table */
79       case INGRES_NO_CURSOR:
80         if (mr_errcode != MR_BUSY &&
81             mr_errcode != MR_DEADLOCK)
82           mr_errcode = MR_INTERNAL;
83         com_err(whoami, 0, "Cursor not opened");
84         break;
85       case INGRES_NO_STMT:
86         mr_errcode = MR_INTERNAL;
87         com_err(whoami, 0, "Statement not declared");
88         break;
89       case INGRES_BAD_COLUMN:
90         mr_errcode = MR_INTERNAL;
91         com_err(whoami, 0, "Bad column name in query table");
92         break;
93       case INGRES_ASGN_ERR:
94         mr_errcode = MR_INTERNAL;
95         com_err(whoami, 0, "Error in SQL assignment statement");
96         break;
97 /* Others ??? */
98       default:
99         mr_errcode = MR_INGRES_ERR;
100         com_err(whoami, MR_INGRES_ERR, " code %d\n", ingres_errno);
101         EXEC SQL INQUIRE_SQL(:err_msg = errortext);
102         com_err(whoami, 0, "SQL error text = %s", err_msg);
103         critical_alert("MOIRA", "Moira server encountered INGRES ERROR %d", ingres_errno);
104     }
105 }
106
107 /* This is declarative, not executed.  Applies from here on, in this file. */
108 EXEC SQL WHENEVER SQLERROR CALL ingerr;
109
110 int mr_open_database()
111 {
112     register int i;
113     char *malloc();
114     MR_SQLDA_T *mr_alloc_SQLDA();
115     static first_open = 1;
116
117     if (first_open) {
118         first_open = 0;
119
120         /* initialize local argv */
121         for (i = 0; i < 16; i++)
122           Argv[i] = malloc(ARGLEN);
123
124         SQLDA = mr_alloc_SQLDA();       
125
126         incremental_init();
127         flush_cache();
128     }
129         
130     ingres_errno = 0;
131     mr_errcode = 0;
132
133     /* open the database */
134 #ifsql INGRES
135     EXEC SQL CONNECT :database;
136     if(ingres_errno) 
137       return (ingres_errno);
138     EXEC SQL set lockmode session where level = table, timeout = :query_timeout;
139     EXEC SQL set lockmode on capacls where readlock = shared;
140     EXEC SQL set lockmode on alias where readlock = shared;
141 #endsql
142 #ifsql INFORMIX
143     EXEC SQL DATABASE moira
144 #endsql
145
146     if(ingres_errno) 
147         return(mr_errcode);
148
149     EXEC SQL SELECT SIZE(signature) INTO :mr_sig_length FROM users WHERE users_id=0; /* Harmless on second open */
150     EXEC SQL COMMIT WORK;
151     if(ingres_errno)
152         return(mr_errcode);
153
154     return(MR_SUCCESS);
155 }
156
157 int mr_close_database()
158 {
159     flush_cache();
160 #ifsql INGRES
161     EXEC SQL DISCONNECT;
162 #endsql
163 }
164
165 mr_check_access(cl, name, argc, argv_ro)
166     client *cl;
167     char *name;
168     int argc;
169     char *argv_ro[];
170 {
171     struct query *q;
172     struct query *get_query_by_name();
173
174     ingres_errno = 0;
175     mr_errcode = 0;
176
177     q = get_query_by_name(name, cl->args->mr_version_no);
178     if (q == (struct query *)0)
179         return(MR_NO_HANDLE);
180
181     return(mr_verify_query(cl, q, argc, argv_ro));    
182 }
183
184 mr_process_query(cl, name, argc, argv_ro, action, actarg)
185     client *cl;
186     char *name;
187     int argc;
188     char *argv_ro[];
189     int (*action)();
190     char *actarg;
191 {
192     register struct query *q;
193     register int status;
194     register struct validate *v;
195     char qual[256];
196     char sort[32];
197     char *pqual;
198     char *psort;
199     EXEC SQL BEGIN DECLARE SECTION; 
200     char *table_name;
201     EXEC SQL END DECLARE SECTION; 
202     struct save_queue *sq;
203     struct query *get_query_by_name();
204     int sq_save_args();
205     struct save_queue *sq_create();
206     char *build_sort();
207
208     ingres_errno = 0;
209     mr_errcode = 0;
210
211     /* list queries command */
212     if (!strcmp(name, "_list_queries")) {
213         list_queries(cl->args->mr_version_no, action, actarg);
214         return(MR_SUCCESS);
215     }
216
217     /* help query command */
218     if (!strcmp(name, "_help")) {
219         if (argc < 1)
220             return(MR_ARGS);
221         q = get_query_by_name(argv_ro[0], cl->args->mr_version_no);
222         if (q == (struct query *)0) return(MR_NO_HANDLE);
223         help_query(q, action, actarg);
224         return(MR_SUCCESS);
225     }
226
227     /* get query structure, return error if named query does not exist */
228     q = get_query_by_name(name, cl->args->mr_version_no);
229     if (q == (struct query *)0) return(MR_NO_HANDLE);
230     v = q->validate;
231
232     /* setup argument vector, verify access and arguments */
233     if ((status = mr_verify_query(cl, q, argc, argv_ro)) != MR_SUCCESS)
234         goto out;
235
236     /* perform any special query pre-processing */
237     if (v && v->pre_rtn) {
238         status = (*v->pre_rtn)(q, Argv, cl, 0);
239         if (status != MR_SUCCESS)
240             goto out;
241     }
242
243     switch (q->type) {
244     case RETRIEVE:
245         /* for queries that do not permit wildcarding, check if row
246            uniquely exists */
247         if (v && v->field) {
248             status = validate_row(q, Argv, v); 
249             if (status != MR_EXISTS) break;
250         }
251
252         /* build "where" clause if needed */
253         if (q->qual) {
254             build_qual(q->qual, q->argc, Argv, qual); 
255             pqual = qual;
256         } else {
257             pqual = 0;
258         }
259
260         /* build "sort" clause if needed */
261         if (v && v->valobj) {
262             psort = build_sort(v, sort);
263         } else {
264             psort = 0;
265         }
266
267         /* if there is a followup routine, then we must save the results */
268         /* of the first query for use by the followup routine */
269         /* if q->rvar = NULL, perform post_rtn only */
270         if (q->rvar) {
271             if (v && v->post_rtn) {
272                 sq = sq_create();
273                 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
274                 if (status != MR_SUCCESS) {
275                     sq_destroy(sq);
276                     break;
277                 }
278                 status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
279             } else {
280                 /* normal retrieve */
281                 status = do_retrieve(q, pqual, psort, action, actarg);
282             }
283             if (status != MR_SUCCESS) break;
284         } else {
285             status = (*v->post_rtn)(q, Argv, cl, action, actarg);
286         }
287
288         break;
289
290     case UPDATE:
291         /* see if row already exists */
292         if (v->field) {
293             status = validate_row(q, Argv, v);
294             if (status != MR_EXISTS) break;
295         }
296
297         /* build "where" clause and perform update */
298         /* if q->rvar = NULL, perform post_rtn only */
299         if (q->rvar) {
300             build_qual(q->qual, q->argc, Argv, qual);
301             incremental_before(q->rtable, qual, argv_ro);
302             status = do_update(q, &Argv[q->argc], qual, action, actarg);
303             incremental_after(q->rtable, qual, argv_ro);
304             if (status != MR_SUCCESS) break;
305             flush_name(argv_ro[0], q->rtable);
306             table_name = q->rtable;
307             if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif")) {
308                 EXEC SQL UPDATE tblstats
309                   SET updates = updates + 1, modtime = 'now'
310                   WHERE table_name = :table_name;
311             }
312         }
313
314         /* execute followup routine (if any) */
315         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
316
317         break;
318
319     case APPEND:
320         /* see if row already exists */
321         if (v->field) {
322             status = validate_row(q, Argv, v);
323             if (status != MR_NO_MATCH) break;
324         }
325
326         /* build "where" clause if needed */
327         if (q->qual) {
328             build_qual(q->qual, q->argc, Argv, qual);
329             pqual = qual;
330         } else {
331             pqual = 0;
332         }
333
334         /* perform the append */
335         /* if q->rvar = NULL, perform post_rtn only */
336         if (q->rvar) {
337             incremental_clear_before();
338             status = do_append(q, &Argv[q->argc], pqual, action, actarg);
339             if (status != MR_SUCCESS) break;
340             if (v && v->object_id) {
341                 sprintf(qual, "%s.%s = %s",q->rvar, v->object_id, 
342                         Argv[q->argc+q->vcnt]);
343                 incremental_after(q->rtable, qual, argv_ro);
344             } else
345               incremental_after(q->rtable, pqual, argv_ro);
346
347             table_name = q->rtable;
348             EXEC SQL UPDATE tblstats
349               SET appends = appends + 1, modtime = 'now'
350               WHERE table_name = :table_name;
351         }
352         
353         /* execute followup routine */
354         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
355         break;
356
357     case DELETE:
358         /* see if row already exists */
359         if (v->field) {
360             status = validate_row(q, Argv, v);
361             if (status != MR_EXISTS) break;
362         }
363
364         /* build "where" clause and perform delete */
365         /* if q->rvar = NULL, perform post_rtn only */
366         if (q->rvar) {
367             build_qual(q->qual, q->argc, Argv, qual);
368             table_name = q->rtable;
369             incremental_before(q->rtable, qual, argv_ro);
370             status = do_delete(q, qual, action, actarg);
371             incremental_clear_after();
372             if (status != MR_SUCCESS) break;
373             flush_name(argv_ro[0], q->rtable);
374             EXEC SQL UPDATE tblstats
375               SET deletes = deletes + 1, modtime = 'now'
376               WHERE table_name = :table_name;
377         }
378
379         /* execute followup routine */
380         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
381         break;
382
383     }
384
385 out:
386     if (status == MR_SUCCESS && ingres_errno != 0) {
387         com_err(whoami, MR_INTERNAL, "Server didn't notice INGRES ERROR %d",
388                        ingres_errno);
389         status = mr_errcode;
390     }
391
392     if (q->type == RETRIEVE) {
393         EXEC SQL COMMIT WORK;
394     } else {
395         if (status == MR_SUCCESS) {
396         EXEC SQL COMMIT WORK;
397             if (journal) {
398                 char buf[1024], *bp;
399                 int i;
400                 extern time_t now;
401
402                 fprintf(journal, "%% %s %s %s",
403                         cl->clname, cl->entity, ctime(&now));
404                 fprintf(journal, "%s[%d] ", q->name, cl->args->mr_version_no);
405                 for (i = 0; i < argc; i++) {
406                     if (i != 0) {
407                         putc(' ', journal);
408                     }
409                     requote(buf, argv_ro[i], sizeof(buf));
410                     fputs(buf, journal);
411                 }
412                 putc('\n', journal);
413                 fflush(journal);
414             }
415             incremental_update();
416         } else {
417             cache_abort();
418             if (ingres_errno != INGRES_DEADLOCK) {
419                 EXEC SQL ROLLBACK WORK;
420             }
421             incremental_flush();
422         }
423     }
424     cache_commit(); /* commit following abort is safe */
425
426     if (status != MR_SUCCESS && log_flags & LOG_RES)
427         com_err(whoami, status, " (Query failed)");
428     return(status);
429 }
430
431 build_qual(fmt, argc, argv, qual)
432         char *fmt;
433         int argc;
434         char *argv[];
435         char *qual;
436 {
437     register char *c;
438     register int i;
439     char *args[4];
440     char *index();
441
442     c = fmt;
443     for (i = 0; i < argc; i++) {
444         c = index(c, '%');
445         if (c++ == (char *)0) return(MR_ARGS);
446         if (*c == 's')
447             args[i] = argv[i];
448         else if (*c == 'd')
449             *(int *)&args[i] = *(int *)argv[i]; /* sigh */
450         else
451             return(MR_INGRES_ERR);
452     }
453     if (c = index(c, '%')) {
454         args[i] = args[i - 1];
455     }
456
457     switch (argc) {
458     case 0:
459         strcpy(qual, fmt);
460         break;
461
462     case 1:
463         sprintf(qual, fmt, args[0]);
464         break;
465
466     case 2:
467         sprintf(qual, fmt, args[0], args[1]);
468         break;
469
470     case 3:
471         sprintf(qual, fmt, args[0], args[1], args[2]);
472         break;
473
474     case 4:
475         sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
476         break;
477
478     default:
479         com_err(whoami, MR_INTERNAL,
480                 "Internal arg count error processing query");
481         return(MR_INTERNAL);
482     }
483     return(MR_SUCCESS);
484 }
485
486 char *
487 build_sort(v, sort)
488     register struct validate *v;
489     char *sort;
490 {
491     register struct valobj *vo;
492     register int n;
493     char elem[16];
494
495     n = v->objcnt;
496     vo = v->valobj;
497     *sort = 0;
498
499     while (--n >= 0) {
500         if (vo->type == V_SORT) {
501             sprintf(elem, "%d", vo->index + 1);    /* Result column number */
502             if (*sort) strcat(sort, ", ");
503             strcat(sort, elem);
504         }
505         vo++;
506     }
507
508     return ((*sort) ? sort : 0);
509 }
510
511
512 /* Build arguement vector, verify query and arguments */
513
514 mr_verify_query(cl, q, argc, argv_ro)
515     client *cl;
516     struct query *q;
517     int argc;
518     char *argv_ro[];
519 {
520     register int argreq;
521     register int status;
522     register struct validate *v = q->validate;
523     register int i;
524     register int privileged = 0;
525     register char *to,*fr,*stop;
526
527     /* copy the arguments into a local argv that we can modify */
528     if (argc >= QMAXARGS)
529       return(MR_ARGS);
530     for (i = 0; i < argc; i++) {
531         /* Single quotes must be doubled for SQL */
532         for (to=Argv[i], fr=argv_ro[i], stop=to+ARGLEN; (*fr) && (to<stop);) {
533             if(*fr=='\'') 
534               *to++ = *fr;
535             *to++ = *fr++;
536         }
537         if (*fr) 
538           return(MR_ARG_TOO_LONG);
539         *to='\0';
540
541         if (*--to == '\\')
542           return(MR_BAD_CHAR);
543     }
544
545     /* check initial query access */
546     status = check_query_access(q, Argv, cl);
547     if (status != MR_SUCCESS && status != MR_PERM)
548         return(status);
549     if (status == MR_SUCCESS)
550         privileged++;
551
552     /* check argument count */
553     argreq = q->argc;
554     if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
555     if (argc != argreq) return(MR_ARGS);
556
557     /* validate arguments */
558     if (v && v->valobj) {
559         status = validate_fields(q, Argv, v->valobj, v->objcnt);
560         if (status != MR_SUCCESS) return(status);
561     }
562
563     /* perform special query access check */
564     if (!privileged && v && v->acs_rtn) {
565         status = (*v->acs_rtn)(q, Argv, cl);
566         if (status != MR_SUCCESS && status != MR_PERM)
567             return(status);
568         if (status == MR_SUCCESS)
569             privileged++;
570     }
571
572     return(privileged ? MR_SUCCESS : MR_PERM);
573 }
574
575
576 /* This routine caches info from the database.  Each query acl is stored
577  * in the query structure, and whether that acl contains everybody.
578  */
579
580 check_query_access(q, argv, cl)
581     struct query *q;
582     char *argv[];
583     client *cl;
584 {
585     EXEC SQL BEGIN DECLARE SECTION; 
586     char *name;
587     int acl_id;
588     int rowcount;
589     int errorno;
590     static int def_uid;
591     EXEC SQL END DECLARE SECTION; 
592     int status;
593     int client_id;
594     char *client_type;
595
596     /* initialize default uid */
597     if (def_uid == 0) {
598         EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login='default';
599     }
600
601     /* get query access control list */
602     if (q->acl != 0)
603       acl_id = q->acl;
604     else {
605         name = q->shortname;
606         EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
607         if (sqlca.sqlcode < 0) return(MR_INGRES_ERR);
608         if (sqlca.sqlcode == 100) return(MR_PERM);
609         q->acl = acl_id;
610
611         /* check for default access */
612         EXEC SQL SELECT member_id INTO :acl_id FROM imembers
613           WHERE list_id = :acl_id AND member_type = 'USER' 
614             AND member_id = :def_uid;
615         if (sqlca.sqlerrd[2] == 0)
616           q->everybody = 0;
617         else
618           q->everybody = 1;
619     }
620
621     if (q->everybody)
622       return(MR_SUCCESS);
623
624     if (get_client(cl, &client_type, &client_id) != MR_SUCCESS)
625       return(MR_PERM);
626     if (find_member("LIST", acl_id, client_type, client_id, 0))
627       return(MR_SUCCESS);
628     else
629       return(MR_PERM);
630 }
631
632
633 get_client(cl, client_type, client_id)
634     client *cl;
635     char **client_type;
636     int *client_id;
637 {
638     if (cl->users_id > 0) {
639         *client_id = cl->users_id;
640         *client_type = "USER";
641         return(MR_SUCCESS);
642     }
643
644     if (cl->client_id < 0) {
645         *client_id = -cl->users_id;
646         *client_type = "KERBEROS";
647         return(MR_SUCCESS);
648     }
649
650     return(MR_PERM);
651 }
652
653 find_member(list_type, list_id, member_type, member_id)
654     char *list_type;
655     EXEC SQL BEGIN DECLARE SECTION; 
656     int list_id;
657     char *member_type;
658     int member_id;
659     EXEC SQL END DECLARE SECTION;
660 {
661     EXEC SQL BEGIN DECLARE SECTION; 
662     int flag, errorno;
663     EXEC SQL END DECLARE SECTION; 
664
665     if (!strcmp(strtrim(list_type), strtrim(member_type)) &&
666         list_id == member_id)
667         return(1);
668
669     /* see if client is a direct member of list */
670     flag = 0;
671     EXEC SQL SELECT member_id INTO :flag FROM imembers
672       WHERE list_id = :list_id AND member_type = :member_type 
673         AND member_id = :member_id;
674     if(flag!=0) flag=1;             /** Not strictly necessary */
675     if (sqlca.sqlcode == 0)
676       return(flag);            
677     return(0);
678 }
679
680
681 do_retrieve(q, pqual, psort, action, actarg)            
682     register struct query *q;
683 EXEC SQL BEGIN DECLARE SECTION; 
684     char *pqual;
685     char *psort;
686 EXEC SQL END DECLARE SECTION; 
687     int (*action)();
688     char *actarg;
689 {
690     static char **vaddrs = (char **)NULL;
691     int j, rowcount;
692
693     if (!vaddrs) {
694         register int i;
695
696         if ((vaddrs = (char **)malloc(sizeof(char *) * QMAXARGS)) == NULL) {
697             com_err(whoami, MR_NO_MEM, "setting up static argv");
698             exit(1);
699         }
700         for (i = 0; i < QMAXARGS; i++) {  
701             vaddrs[i]=SQLDA->sqlvar[i].sqldata;
702         }
703     }
704
705     build_sql_stmt(stmt_buf,"SELECT",q->tlist,vaddrs,pqual);
706     if(psort) { strcat(stmt_buf," ORDER BY "); strcat(stmt_buf,psort); }
707     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf; 
708     if(sqlca.sqlcode)
709       return(MR_INTERNAL);
710     EXEC SQL DECLARE csr001 CURSOR FOR stmt;
711     EXEC SQL OPEN csr001;
712     rowcount = 0;
713     while(1) {
714         EXEC SQL FETCH csr001 USING DESCRIPTOR :SQLDA;
715         if(sqlca.sqlcode != 0) break;
716         (*action)(q->vcnt, vaddrs, actarg);
717         rowcount++;
718     }
719     EXEC SQL CLOSE csr001;
720
721     if (mr_errcode) return(mr_errcode);
722     return ((rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS);
723 }
724
725 char *sqlstrstr(str,pat)
726     char *str;
727     char *pat;
728 {
729     register char *p=pat;
730     
731     do {
732         if(*str=='\'') {    /* Skip over single-quote delimited substrings */ 
733             while(*++str && (*str!='\'')) 
734                 ; 
735             continue;
736         }
737         if(*str==*p) {
738             register char *s;
739             s=str; 
740             while(*++p && (*++s==*p))
741                 ; 
742             if(*p) p=pat;  /* failed */
743         }
744     } while(*p && *++str);
745
746     if(!*str) str=NULL;
747     return(str);
748 }
749
750 void optimize_sql_stmt(buf)
751 char *buf;
752 {
753     char *point=buf, *pat, *eopat, *esc1, *esc2, *csr;
754
755     for(point=buf; point=sqlstrstr(point,"LIKE"); point++)  {
756         /* Now pointing to string "LIKE" */
757
758         /* Look at next word */
759         for(pat=point+4; *pat==' '; pat++) ;
760
761         /* Is it a single-quote delimited string? */
762         if(*pat!='\'') continue;
763
764         /* look for "escape" clause - save escape character */
765         /* 1. Find end of pattern */
766         for(eopat=pat+1; 1; eopat++) {
767             if(*eopat=='\'') {
768                 if(eopat[1]=='\'')  /* single-quote is self-escaping */
769                     eopat++;
770                 else
771                     break;
772             }
773         }
774
775         /* 2. Look at next word */
776         for(esc1=eopat; *++esc1==' ';) ;
777
778         /* 3. esc1=0 if not "ESCAPE '?'", where the ? may be any character. */
779         if(strncmp(esc1,"ESCAPE",6)) esc1=NULL;
780
781         if(esc1) {
782             for(esc2=esc1+6; *esc2==' '; esc2++) ;
783             
784             if(*esc2++!='\'') continue; /* Bad SQL syntax. Skip. */
785             /* esc2 now points at the escape character itself */
786             if(esc2[1]!='\'') continue; /* Weird escape string. Skip. */
787         } else {
788             esc2="\\";
789         }
790
791         /* Is pattern free from special characters? */
792         for(csr=pat; csr<eopat; csr++) 
793             if((*csr=='%') || (*csr=='_') || (*csr==*esc2)) break;
794         if(csr!=eopat) continue; /* Uses pattern matching. Skip. */
795
796         /* Optimize the query statement */
797         /* 1. Change "LIKE" to " =  " */
798         memcpy(point," =  ",4);
799         
800         /* 2. Change "ESCAPE" to "      " */
801         if(esc1) {
802             memset(esc1,' ',6);
803             /* 3. Change  "'*'" to "   " */
804             /*    (Changes '''' to "    ") */
805             if(esc2) memset(esc2-1,' ',(*esc2=='\'')?4:3); 
806         }
807     }
808 }
809
810 build_sql_stmt(result_buf,cmd,targetlist,argv,qual)
811     char *result_buf;
812     char *cmd;
813     char *targetlist;
814     char *argv[];
815     char *qual;
816 {
817     char fmt_buf[MR_STMTBUF_LEN];
818     register char *res, *fmt;
819
820     if(qual)
821       sprintf(fmt_buf,"%s %s WHERE %s",cmd,targetlist,qual);
822     else
823       sprintf(fmt_buf,"%s %s",cmd,targetlist);
824
825     for(res=result_buf, fmt=fmt_buf; *fmt; fmt++) {
826         if(*fmt=='%') {
827             if(*++fmt) {
828                 switch(*fmt) {                       
829                   case '%':                              /* %% -> % */
830                     *res++ = *fmt;           
831                     break;
832                   case 's':
833                     if(*argv[0]) {
834                         *res='\0';
835                         strcat(res,*argv);
836                         while(*++res) ;
837                     }
838                     argv++;
839                     break;
840                   case 'd':
841                     sprintf(res,"%d",*(int *)*argv++);   /* print to result buffer */
842                     while(*++res) ;
843                     break;
844                   default:                               /* Swallow other %? pairs */
845                     break;
846                 }
847             } else break;
848         } else *res++ = *fmt;                            /* text -> result buffer */
849     }
850     *res='\0';
851
852     optimize_sql_stmt(result_buf);
853 }
854
855 do_update(q, argv, qual, action, actarg)
856     register struct query *q;
857     char *argv[];
858     char *qual;
859     int (*action)();
860     char *actarg;
861 {
862     build_sql_stmt(stmt_buf,"UPDATE",q->tlist,argv,qual);
863     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
864     if (mr_errcode) return(mr_errcode);
865     return(MR_SUCCESS);
866 }
867
868 do_append(q, argv, pqual, action, actarg)
869     register struct query *q;
870     char *argv[];
871     char *pqual;
872     int (*action)();
873     char *actarg;
874 {
875     build_sql_stmt(stmt_buf,"INSERT",q->tlist,argv,pqual);
876     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
877     if (mr_errcode) return(mr_errcode);
878     return(MR_SUCCESS);
879 }
880
881 do_delete(q, qual, action, actarg)
882     register struct query *q;
883     char *qual;
884     int (*action)();
885     char *actarg;
886 {
887     sprintf(stmt_buf,"DELETE FROM %s WHERE %s",q->rtable,qual);
888     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
889     if (mr_errcode) return(mr_errcode);
890     return(MR_SUCCESS);
891 }
892
893
894 /**
895  ** set_next_object_id - set next object id in values table
896  **
897  ** Inputs: object - object name in values table and in objects
898  **         table - name of table objects are found in
899  **         limit - should the ID be range limited
900  **
901  ** - called before an APPEND operation to set the next object id to
902  **   be used for the new record to the next free value
903  **
904  **/
905
906 set_next_object_id(object, table_name, limit)
907     EXEC SQL BEGIN DECLARE SECTION; 
908     char *object;
909     char *table_name;
910     int limit;
911     EXEC SQL END DECLARE SECTION; 
912 {
913     EXEC SQL BEGIN DECLARE SECTION; 
914     int value;
915     EXEC SQL END DECLARE SECTION;
916     int starting_value;
917     
918     EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :object;
919     if (sqlca.sqlerrd[2] != 1)
920         return(MR_NO_ID);
921
922     starting_value=value;
923     while (1) { 
924         if (limit && value > MAX_ID_VALUE) 
925             value = MIN_ID_VALUE;
926
927         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s=%d",object,table_name,object,value);  
928         EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf; 
929         if(sqlca.sqlcode)
930           return(MR_INTERNAL);
931         EXEC SQL DECLARE csr002 CURSOR FOR stmt;
932         EXEC SQL OPEN csr002;
933         EXEC SQL FETCH csr002 USING DESCRIPTOR :SQLDA;
934         if (sqlca.sqlcode < 0) return(mr_errcode);
935         if (sqlca.sqlcode == 100) break;
936
937         EXEC SQL CLOSE csr002;
938         value++;
939         if (limit && value == starting_value) {   
940             com_err(whoami,0,"All id values have been used");
941             return(MR_NO_ID);
942         }
943     }
944     EXEC SQL CLOSE csr002;
945
946     if (LOG_RES)
947         com_err(whoami, 0, "setting ID %s to %d", object, value);
948     EXEC SQL UPDATE numvalues SET value = :value WHERE name = :object;
949     return(MR_SUCCESS);
950 }
951
952
953 /* Turn a kerberos name into the user's ID of the account that principal
954  * owns.  Sets the kerberos ID and user ID.
955  */
956
957 int set_krb_mapping(name, login, ok, kid, uid)
958 char *name;
959 char *login;
960 int ok;
961 int *kid;
962 int *uid;
963 {
964     EXEC SQL BEGIN DECLARE SECTION; 
965     int u_id, k_id;
966     char *krbname;
967     EXEC SQL END DECLARE SECTION; 
968
969     krbname = name;
970     *kid = 0;
971     *uid = 0;
972
973     EXEC SQL SELECT km.users_id, km.string_id INTO :u_id, :k_id
974       FROM krbmap km, strings str
975       WHERE km.string_id = str.string_id AND str.string = :krbname;
976     EXEC SQL COMMIT WORK;
977
978     if (ingres_errno) return(mr_errcode);
979     
980     if (sqlca.sqlerrd[2] == 1) {    /* rowcount */
981         *kid = -k_id;
982         *uid = u_id;
983         return(MR_SUCCESS);
984     }
985
986     if (name_to_id(name, "STRINGS", &k_id) == MR_SUCCESS)
987       *kid = -k_id;
988
989     if (!ok) {             
990         *uid = *kid;
991         return(MR_SUCCESS);
992     }
993
994     if (name_to_id(login, "USERS", uid) != MR_SUCCESS)
995       *uid = 0;
996
997     if (*kid == 0)
998       *kid = *uid;
999     if (ingres_errno) return(mr_errcode);
1000     return(MR_SUCCESS);
1001 }
1002
1003
1004 /* For now this just checks the argc's.  It should also see that there
1005  * are no duplicate names.
1006  */
1007
1008 sanity_check_queries()
1009 {
1010     register int i;
1011     int maxv = 0, maxa = 0;
1012 #ifdef MULTIPROTOCOLS
1013     extern int QueryCount1, QueryCount2;
1014     extern struct query Queries1[], Queries2[];
1015 #else
1016     extern int QueryCount2;
1017     extern struct query Queries2[];
1018 #endif MULTIPROTOCOLS
1019
1020 #define MAX(x,y) ((x) > (y) ? (x) : (y))
1021
1022 #ifdef MULTIPROTOCOLS
1023     for (i = 0; i < QueryCount1; i++) {
1024         maxv = MAX(maxv, Queries1[i].vcnt);
1025         maxa = MAX(maxa, Queries1[i].argc);
1026     }
1027 #endif MULTIPROTOCOLS
1028     for (i = 0; i < QueryCount2; i++) {
1029         maxv = MAX(maxv, Queries2[i].vcnt);
1030         maxa = MAX(maxa, Queries2[i].argc);
1031     }
1032     if (MAX(maxv, maxa) > QMAXARGS) {
1033         com_err(whoami, 0, "A query has more args than QMAXARGS");
1034         exit(1);
1035     }
1036 }
1037
1038 /* eof:qrtn.dc */
This page took 0.196608 seconds and 3 git commands to generate.