]> andersk Git - moira.git/blobdiff - server/qrtn.dc
Diane Delgado's changes for a fixed table-locking order
[moira.git] / server / qrtn.dc
index 57d44c378fb6f965e42563d8f5c0c559993db0d1..154e4007da3376536334514912e91bc7d3edbda4 100644 (file)
@@ -14,6 +14,7 @@ static char *rcsid_qrtn_dc = "$Header$";
 #endif lint
 
 #include <mit-copyright.h>
+#include <string.h>
 #include "query.h"
 #include "mr_server.h"
 EXEC SQL INCLUDE sqlca;  /* SQL Communications Area */
@@ -28,22 +29,21 @@ char cdummy[MR_CDUMMY_LEN];
 char stmt_buf[MR_STMTBUF_LEN];
 EXEC SQL END DECLARE SECTION; 
 
-char *Argv[16];
+char *Argv[QMAXARGS];
 
 int ingres_errno = 0;
 int mr_errcode = 0;
 EXEC SQL BEGIN DECLARE SECTION; 
 int query_timeout = 30;
+char *database = "moira";
 EXEC SQL END DECLARE SECTION;
 extern char *whoami;
 extern FILE *journal;
 
-/** Maybe this should be replaced by something like tytso's sql_error */
-
 #define INGRES_BAD_DATE1  40206
 #define INGRES_BAD_DATE2  40207
 #define INGRES_DEADLOCK   49900
-
+#define INGRES_TIMEOUT    39100
 #define INGRES_BAD_COLUMN 30110
 #define INGRES_ASGN_ERR   40204
 #define INGRES_NO_CURSOR  30120
@@ -69,32 +69,33 @@ void ingerr()
        mr_errcode = MR_DEADLOCK;
        com_err(whoami, 0, "INGRES deadlock detected");
        break;
-/*  I just don't know what the equivalent to this is, yet.
- *  case INGRES_TIMEOUT:
- *     mr_errcode = MR_BUSY;
- *     com_err(whoami, 0, "timed out getting lock");
- *     break;
- */
-    case INGRES_NO_CURSOR:
-       mr_errcode = MR_INTERNAL;
+      case INGRES_TIMEOUT:
+/* May be something other than timeout! #39100 is "Unknown error" 
+ * Really should parse the error message enough to decide if it's a timeout */
+       mr_errcode = MR_BUSY;
+       com_err(whoami, 0, "timed out getting lock");
+       break;
+/* These should never come up unless someone breaks the query table */
+      case INGRES_NO_CURSOR:
+       if (mr_errcode != MR_BUSY &&
+           mr_errcode != MR_DEADLOCK)
+         mr_errcode = MR_INTERNAL;
        com_err(whoami, 0, "Cursor not opened");
        break;
-    case INGRES_NO_STMT:
+      case INGRES_NO_STMT:
        mr_errcode = MR_INTERNAL;
        com_err(whoami, 0, "Statement not declared");
        break;
-#if 0
-    /* Taking these out during development lets default: give me the INGRES text */
-    case INGRES_BAD_COLUMN:
+      case INGRES_BAD_COLUMN:
        mr_errcode = MR_INTERNAL;
        com_err(whoami, 0, "Bad column name in query table");
         break;
-    case INGRES_ASGN_ERR:
+      case INGRES_ASGN_ERR:
        mr_errcode = MR_INTERNAL;
        com_err(whoami, 0, "Error in SQL assignment statement");
        break;
-#endif
-    default:
+/* Others ??? */
+      default:
        mr_errcode = MR_INGRES_ERR;
        com_err(whoami, MR_INGRES_ERR, " code %d\n", ingres_errno);
        EXEC SQL INQUIRE_SQL(:err_msg = errortext);
@@ -109,7 +110,6 @@ EXEC SQL WHENEVER SQLERROR CALL ingerr;
 int mr_open_database()
 {
     register int i;
-    char *malloc();
     MR_SQLDA_T *mr_alloc_SQLDA();
     static first_open = 1;
 
@@ -131,7 +131,7 @@ int mr_open_database()
 
     /* open the database */
 #ifsql INGRES
-    EXEC SQL CONNECT moira;
+    EXEC SQL CONNECT :database;
     if(ingres_errno) 
       return (ingres_errno);
     EXEC SQL set lockmode session where level = table, timeout = :query_timeout;
@@ -146,6 +146,7 @@ int mr_open_database()
         return(mr_errcode);
 
     EXEC SQL SELECT SIZE(signature) INTO :mr_sig_length FROM users WHERE users_id=0; /* Harmless on second open */
+    EXEC SQL COMMIT WORK;
     if(ingres_errno)
         return(mr_errcode);
 
@@ -321,16 +322,6 @@ mr_process_query(cl, name, argc, argv_ro, action, actarg)
            if (status != MR_NO_MATCH) break;
        }
 
-#ifdef NEVER
-       /* This is now done by a valobj, which also fetches the id value */
-
-       /* increment id number if necessary */
-       if (v->object_id) {
-           status = set_next_object_id(v->object_id, q->rtable, 0);
-           if (status != MR_SUCCESS) break;
-       }
-#endif
-
        /* build "where" clause if needed */
        if (q->qual) {
            build_qual(q->qual, q->argc, Argv, qual);
@@ -346,7 +337,7 @@ mr_process_query(cl, name, argc, argv_ro, action, actarg)
            status = do_append(q, &Argv[q->argc], pqual, action, actarg);
            if (status != MR_SUCCESS) break;
            if (v && v->object_id) {
-               sprintf(qual, "%s.%s = %s",q->rtable, v->object_id, 
+               sprintf(qual, "%s.%s = %s",q->rvar, v->object_id, 
                        Argv[q->argc+q->vcnt]);
                incremental_after(q->rtable, qual, argv_ro);
            } else
@@ -445,7 +436,6 @@ build_qual(fmt, argc, argv, qual)
     register char *c;
     register int i;
     char *args[4];
-    char *index();
 
     c = fmt;
     for (i = 0; i < argc; i++) {
@@ -499,6 +489,9 @@ build_sort(v, sort)
     register struct valobj *vo;
     register int n;
     char elem[16];
+#ifdef _DEBUG_MALLOC_INC
+#undef index
+#endif
 
     n = v->objcnt;
     vo = v->valobj;
@@ -519,6 +512,8 @@ build_sort(v, sort)
 
 /* Build arguement vector, verify query and arguments */
 
+int privileged;
+
 mr_verify_query(cl, q, argc, argv_ro)
     client *cl;
     struct query *q;
@@ -529,9 +524,10 @@ mr_verify_query(cl, q, argc, argv_ro)
     register int status;
     register struct validate *v = q->validate;
     register int i;
-    register int privileged = 0;
     register char *to,*fr,*stop;
 
+    privileged = 0;
+
     /* copy the arguments into a local argv that we can modify */
     if (argc >= QMAXARGS)
       return(MR_ARGS);
@@ -574,7 +570,7 @@ mr_verify_query(cl, q, argc, argv_ro)
        if (status != MR_SUCCESS && status != MR_PERM)
            return(status);
        if (status == MR_SUCCESS)
-           privileged++;
+           return(MR_SUCCESS);
     }
 
     return(privileged ? MR_SUCCESS : MR_PERM);
@@ -730,6 +726,91 @@ EXEC SQL END DECLARE SECTION;
     return ((rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS);
 }
 
+char *sqlstrstr(str,pat)
+    char *str;
+    char *pat;
+{
+    register char *p=pat;
+    
+    do {
+       if(*str=='\'') {    /* Skip over single-quote delimited substrings */ 
+           while(*++str && (*str!='\'')) 
+               ; 
+           continue;
+       }
+       if(*str==*p) {
+           register char *s;
+           s=str; 
+           while(*++p && (*++s==*p))
+               ; 
+           if(*p) p=pat;  /* failed */
+       }
+    } while(*p && *++str);
+
+    if(!*str) str=NULL;
+    return(str);
+}
+
+void optimize_sql_stmt(buf)
+char *buf;
+{
+    char *point=buf, *pat, *eopat, *esc1, *esc2, *csr;
+
+    for(point=buf; point=sqlstrstr(point,"LIKE"); point++)  {
+       /* Now pointing to string "LIKE" */
+
+       /* Look at next word */
+       for(pat=point+4; *pat==' '; pat++) ;
+
+       /* Is it a single-quote delimited string? */
+       if(*pat!='\'') continue;
+
+       /* look for "escape" clause - save escape character */
+       /* 1. Find end of pattern */
+       for(eopat=pat+1; 1; eopat++) {
+           if(*eopat=='\'') {
+               if(eopat[1]=='\'')  /* single-quote is self-escaping */
+                   eopat++;
+               else
+                   break;
+           }
+       }
+
+       /* 2. Look at next word */
+       for(esc1=eopat; *++esc1==' ';) ;
+
+       /* 3. esc1=0 if not "ESCAPE '?'", where the ? may be any character. */
+       if(strncmp(esc1,"ESCAPE",6)) esc1=NULL;
+
+       if(esc1) {
+           for(esc2=esc1+6; *esc2==' '; esc2++) ;
+           
+           if(*esc2++!='\'') continue; /* Bad SQL syntax. Skip. */
+           /* esc2 now points at the escape character itself */
+           if(esc2[1]!='\'') continue; /* Weird escape string. Skip. */
+       } else {
+           esc2="\\";
+       }
+
+       /* Is pattern free from special characters? */
+       for(csr=pat; csr<eopat; csr++) 
+           if((*csr=='%') || (*csr=='_') || (*csr==*esc2)) break;
+       if(csr!=eopat) continue; /* Uses pattern matching. Skip. */
+
+       /* Optimize the query statement */
+       /* 1. Change "LIKE" to " =  " */
+       memcpy(point," =  ",4);
+       
+       /* 2. Change "ESCAPE" to "      " */
+       if(esc1) {
+           memset(esc1,' ',6);
+           /* 3. Change  "'*'" to "   " */
+           /*    (Changes '''' to "    ") */
+           if(esc2) memset(esc2-1,' ',(*esc2=='\'')?4:3); 
+       }
+    }
+}
+
 build_sql_stmt(result_buf,cmd,targetlist,argv,qual)
     char *result_buf;
     char *cmd;
@@ -771,6 +852,8 @@ build_sql_stmt(result_buf,cmd,targetlist,argv,qual)
        } else *res++ = *fmt;                            /* text -> result buffer */
     }
     *res='\0';
+
+    optimize_sql_stmt(result_buf);
 }
 
 do_update(q, argv, qual, action, actarg)
@@ -894,6 +977,7 @@ int *uid;
     EXEC SQL SELECT km.users_id, km.string_id INTO :u_id, :k_id
       FROM krbmap km, strings str
       WHERE km.string_id = str.string_id AND str.string = :krbname;
+    EXEC SQL COMMIT WORK;
 
     if (ingres_errno) return(mr_errcode);
     
This page took 0.043267 seconds and 4 git commands to generate.