diff sqlpython/sqlpyPlus.py @ 236:7f999b141fcd

debugging streamlined wild sql
author catherine@dellzilla
date Thu, 26 Feb 2009 20:09:46 -0500
parents 8e5f58d504d4
children 95070e01907d
line wrap: on
line diff
--- a/sqlpython/sqlpyPlus.py	Thu Feb 26 19:01:22 2009 -0500
+++ b/sqlpython/sqlpyPlus.py	Thu Feb 26 20:09:46 2009 -0500
@@ -498,67 +498,58 @@
     columnlistPattern = pyparsing.SkipTo(pyparsing.CaselessKeyword('from'))('columns') + \
                         pyparsing.SkipTo(pyparsing.stringEnd)('remainder')
 
-    negator = pyparsing.Optional('!')('exclude')
-    colNumber = negator + pyparsing.Literal('*') + pyparsing.Word('-' + pyparsing.nums, pyparsing.nums)('column_number')
+    negator = pyparsing.Literal('!')('exclude')
+    colNumber = pyparsing.Optional(negator) + pyparsing.Literal('*') + pyparsing.Word('-' + pyparsing.nums, pyparsing.nums)('column_number')
     colName = negator + pyparsing.Word('$_#' + pyparsing.alphas, '$_#' + pyparsing.alphanums)('standard_word')
-    wildColName = negator + pyparsing.Word('*$_#' + pyparsing.alphas, '*$_#' + pyparsing.alphanums)('wildcard_word')
+    wildColName = pyparsing.Optional(negator) + pyparsing.Word('*$_#' + pyparsing.alphas, '*$_#' + pyparsing.alphanums, min=2)('wildcard_word')
     wildSqlParser = colNumber ^ colName ^ wildColName
     wildSqlParser.ignore(pyparsing.cStyleComment).ignore(Parser.comment_def). \
-                  ignore(pyparsing.sglQuotedString).ignore(pyparsing.dblQuotedString)         
+                  ignore(pyparsing.sglQuotedString).ignore(pyparsing.dblQuotedString)   
+    emptyCommaRegex = re.compile(',\s*,', re.DOTALL)
+    deadStarterCommaRegex = re.compile('^\s*,', re.DOTALL)
+    deadEnderCommaRegex = re.compile(',\s*$', re.DOTALL)    
     def expandWildSql(self, arg):
         try:
             columnlist = self.columnlistPattern.parseString(arg)
         except pyparsing.ParseException:
             return arg
-        notcolnums = list(self.wildSqlNotColnum.scanString(arg))
-        colnums = list(self.wildSqlColnum.scanString(arg))
-        colnames = [cn for cn in self.wildColNamePattern.scanString(arg) if '*' in cn[0][0]]
-        if not (colnums or colnames or notcolnums):
-            return arg
+        parseresults = list(self.wildSqlParser.scanString(columnlist.columns))
+        if not parseresults:
+            return arg       
         self.curs.execute('select * ' + columnlist.remainder, self.varsUsed)
-        columns_available = [d[0] for d in self.curs.description]
+        columns_available = [d[0] for d in self.curs.description]        
         replacers = {}
-        alreadyincluded = []
-        alreadyexcluded = []
-        for colnum in notcolnums:
-            colindex = int(colnum[0].column_number)            
-            if colindex > 0:
-                exclude  = columns_available[colindex-1]
-            else:
-                exclude = columns_available[colindex]            
-            alreadyexcluded.append(exclude)
-            columns_to_add = [c for c in columns_available if c not in alreadyexcluded and c not in alreadyincluded]
-            alreadyincluded.extend(columns_to_add)
-            substval = ', '.join(columns_to_add)
-            substkey = arg[colnum[1]:colnum[2]]
-            replacers[substkey] = columns_to_add
-        for (k, cols) in replacers.items():
-            replacers[k] = [col for col in cols if col not in alreadyexcluded]
-        for colnum in colnums:
-            colindex = int(colnum[0].column_number)
-            if colindex > 0:
-                substval = columns_available[colindex-1]
-            else:
-                substval = columns_available[colindex]
-            substkey = arg[colnum[1]:colnum[2]]
-            replacers[substkey] = substval
-        for colname in colnames:
-            substvals = []
-            target = colname[0][0]
-            target = target.replace('*', '.*')
-            for col in columns_available:
-                if re.match(target, col, flags=re.IGNORECASE):
-                    substvals.append(col)
-            if substvals:
-                replacers[colname[0][0]] = ', '.join(substvals)
+        included = set()
+        excluded = set()        
+        for (col, startpos, endpos) in parseresults:
+            if col.column_number:
+                idx = int(col.column_number)
+                if idx > 0:
+                    idx -= 1                
+                colname = columns_available[idx]                
+                if col.exclude:
+                    included.discard(colname)
+                    include_here = columns_available[:]
+                    include_here.remove(colname)
+                    replacers[arg[startpos:endpos]] = include_here
+                    excluded.add(colname)
+                else:
+                    included.add(colname)
+                    excluded.discard(colname)
+                    replacers[arg[startpos:endpos]] = colname
+                    
         replacers = sorted(replacers.items(), key=len, reverse=True)
-        replacers.reverse()
         result = columnlist.columns
-        for (k, v) in replacers:
-            if v:
-                result = result.replace(k, v)  # could be confused by wildcards inside comments, strings
-            else:
-                result = result.replace(k, '') # no good - adjacent columns result
+        for (target, replacement) in replacers:
+            if isinstance(replacement, list):
+                cols = [r for r in replacement if r not in excluded and r not in included]
+                replacement = ', '.join(cols)
+                included.update(cols)
+            result = result.replace(target, replacement)
+        # some column names could get wiped out completely - fix their dangling commas
+        result = self.emptyCommaRegex.sub(',', result)
+        result = self.deadStarterCommaRegex.sub('', result)
+        result = self.deadEnderCommaRegex.sub('', result)
         return result + columnlist.remainder
         
     rowlimitPattern = pyparsing.Word(pyparsing.nums)('rowlimit')