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