I'm working on a patch for the sqlite3 driver to resolve some of the issues I've been having.

The first issue I had was that the parser was unable to find Tables in the SQL statement. This was because the parser assumed that the only possible white space around keywords was ' ' or 0x20;

eg. strstr(statement," FROM ");

If you had SQL formatted like;

SELECT foo\nFROM bar;

or

SELECT foo\n\tFROM bar;

The parser would fail to find 'bar' because there isn't a ' ' character before FROM. This was a problem for all keywords. I think using strtok would have been a better approach than going char by char. But since the parser works in general, I didn't want to rewrite it all.

The second bug was that the parser would always read past the first "endword" if there was a JOIN just before it. Resulting in tables being added to the list that don't exist. (eg. Artist.name, not a table but a field). Thus in order to fix this you need to check for endwords right away if you're parsing through JOINs.

I'm still having all sorts of issues with the sqlite3 driver but these two things have at least got my application running :)

I also removed some magic references to nottables[] and added some comments to denote the end of large statements.

I ran make check with the patch and 380 tests passed, 0 failed.

Let me know what you think of the patch.

On a side note, write performance to sqlite3 db is incredibly poor (>1s for each INSERT regardless of content or no. of fields). But read performance is great. Any tips on how to tune sqlite3?


Vikram.

Index: libdbi-drivers/drivers/sqlite3/dbd_sqlite3.c
===================================================================
--- libdbi-drivers.orig/drivers/sqlite3/dbd_sqlite3.c	2010-12-25 20:11:38.603387002 -0500
+++ libdbi-drivers/drivers/sqlite3/dbd_sqlite3.c	2010-12-25 20:12:05.273387001 -0500
@@ -771,10 +771,11 @@
   //printf("curr_table before getTables = %s\n",curr_table);
   table_count = getTables(tables,0,statement_copy,curr_table);
   //printf("curr_table after getTables = %s\n",curr_table);
-  //printf("*********TABLELIST************\n");
-  //		for ( counter = 0 ; counter < table_count ; counter++) {
-  //			//printf("%s\n",tables[counter]);
-  //		}
+  //printf("%s\n",statement_copy);
+  printf("*********TABLELIST************\n");
+  for ( counter = 0 ; counter < table_count ; counter++) {
+     printf("[%i] %s\n",counter,tables[counter]);
+  }
 
   // resolve our curr_field to a real column
   char* token;
@@ -1180,6 +1181,27 @@
   return type;
 }
 
+/* Similar to C99 strstr() except ensures that there is
+ * white space around needle. */
+char *strstr_ws(const char *haystack, const char *needle){
+   const char *c = NULL;
+   int len;
+
+   len = strlen(needle);
+
+   c = haystack;
+
+   while( (c = strstr(c,needle)) != NULL){
+      if(c == haystack) return NULL;
+      if( ( *(c-1)  == ' ' || *(c-1) == '\t' || *(c-1) == '\n')
+         &&
+          ( c[len] == ' '  || c[len] == '\t' || c[len] == '\n'))
+           return (char*) c;
+   }
+
+   return NULL;
+}
+
 int getTables(char** tables, int index, const char* statement, char* curr_table) {
   //printf("getTables\n");
 /*   printf("processing %s\n",statement); */
@@ -1195,16 +1217,16 @@
   char* endwords[] = {"where","group","having","union","intersect","except","order","limit"};
   char* nottables[] = {"natural","left","right","full","outer","inner","cross","join","as","on"};
 
-  if ( !(item = strstr(statement, " from ")) ) {
-    if ( !(item = strstr(statement, " FROM ")) )
+  if ( !(item = strstr_ws(statement, "from")) ) {
+    if ( !(item = strstr_ws(statement, "FROM")) )
 /*       printf("no from clause\n"); */
       return index;
   }
-  item += 6;
+  item += strlen("from");
 
   while ( *item != '\0' ) {
 /*     printf("begin parsing at %s\n", item); */
-    if ( *item == ' ' || *item == ',' ) {
+    if ( *item == ' '|| *item == '\t' || *item == ',' ) {
       item++;
     }
     else {
@@ -1229,7 +1251,8 @@
       }
       else {
 /* 	printf("actual word starting here: %s\n", item); */
-	while ( *item && *item != ',' && *item != ' ' && *item != ')' && *item != ';' ) {
+	while ( *item && *item != ',' && *item != ' ' && *item != '\t'
+                                      && *item != ')' && *item != ';' ) {
 	  item++;
 	}
 	char word[item-start+1];
@@ -1256,11 +1279,11 @@
 /* 	    printf("not a table: %s\n", word_lower); */
 	    // if we encounter join or as we set
 	    // a flag because we know what to do next
-	    if ( strcmp(nottables[7],word_lower) == 0 ) {
+	    if ( strcmp("join",word_lower) == 0 ) {
 	      //printf("join found\n");
 	      join_flag = 1;
 	    }
-	    if ( strcmp(nottables[8],word_lower) == 0 ) {
+	    if ( strcmp("as",word_lower) == 0 ) {
 	      //printf("as found\n");
 	      as_flag = 1;
 	    }
@@ -1296,7 +1319,7 @@
 	      join_flag = 0;
 	      int skip_flag = 1;
 	      while ( skip_flag == 1 ) {
-		if ( *item == ' ') {
+		if ( *item == ' '|| *item == '\t' ) {
 		  item++;
 		}
 		else {
@@ -1313,7 +1336,8 @@
 			opens--;
 		    }
 		  }
-		  while ( *item && *item != ',' && *item != ' ' && *item != '(') {
+		  while ( *item && *item != ','  && *item != ' '
+                                && *item != '\t' && *item != '(') {
 		    item++;
 		  }
 		  if ( *item == '\0' ) {
@@ -1335,26 +1359,32 @@
 		    word_lower[i] = tolower(word_lower[i]);
 		    i++;
 		  }
-		  if ( strcmp(nottables[7],word_lower) == 0 ) {
+		  if ( strcmp("join",word_lower) == 0 ) {
 		    //printf("stop skip after join found\n");
 		    // we have found the next join, stop skipping
 		    join_flag = 1;
 		    skip_flag = 0;
 		    break;
 		  }
+                  for ( i = 0 ; i < (sizeof(endwords)/sizeof *(endwords)) ; i++ ) {
+                     if ( strcmp(endwords[i],word_lower) == 0 ) {
+                        /* printf("end word!\n"); */
+                        return index;
+                    }
+                  }
 		}
 	      }
-	    }
-	  }
-	}
+	    } // if join_flag
+	  } // if as_flag else
+	} // if not_word_flag else
 	if ( *item == '\0' ) {
 /* 	  printf("returning %d",index); */
 	  return index;
 	}
-	item++;
-      }
-    }
-  }
+        item++;
+      } // if *item == '(' else
+    } // if *item == ' '|| *item == '\t' || *item == ',' else
+  } // while
 /*   printf("returning %d\n",index); */
   return index;
 }
------------------------------------------------------------------------------
Learn how Oracle Real Application Clusters (RAC) One Node allows customers
to consolidate database storage, standardize their database environment, and, 
should the need arise, upgrade to a full multi-node Oracle RAC database 
without downtime or disruption
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
libdbi-users mailing list
libdbi-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libdbi-users

Reply via email to