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