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