summary refs log tree commit diff stats
path: root/lib/pure/parsesql.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/parsesql.nim')
-rw-r--r--lib/pure/parsesql.nim218
1 files changed, 109 insertions, 109 deletions
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index cfa60094d..d6fafec08 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## The ``parsesql`` module implements a high performance SQL file 
+## The ``parsesql`` module implements a high performance SQL file
 ## parser. It parses PostgreSQL syntax and the SQL ANSI standard.
 
 import
@@ -37,11 +37,11 @@ type
     tkBracketLe,            ## '['
     tkBracketRi,            ## ']'
     tkDot                   ## '.'
-  
+
   Token = object  # a token
     kind: TokKind           # the type of the token
     literal: string          # the parsed (string) literal
-  
+
   SqlLexer* = object of BaseLexer ## the parser object.
     filename: string
 
@@ -55,82 +55,82 @@ const
     ";", ":", ",", "(", ")", "[", "]", "."
   ]
 
-proc open(L: var SqlLexer, input: Stream, filename: string) = 
+proc open(L: var SqlLexer, input: Stream, filename: string) =
   lexbase.open(L, input)
   L.filename = filename
-  
-proc close(L: var SqlLexer) = 
+
+proc close(L: var SqlLexer) =
   lexbase.close(L)
 
-proc getColumn(L: SqlLexer): int = 
+proc getColumn(L: SqlLexer): int =
   ## get the current column the parser has arrived at.
   result = getColNumber(L, L.bufpos)
 
-proc getLine(L: SqlLexer): int = 
+proc getLine(L: SqlLexer): int =
   result = L.lineNumber
 
-proc handleHexChar(c: var SqlLexer, xi: var int) = 
+proc handleHexChar(c: var SqlLexer, xi: var int) =
   case c.buf[c.bufpos]
-  of '0'..'9': 
+  of '0'..'9':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
     inc(c.bufpos)
-  of 'a'..'f': 
+  of 'a'..'f':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
     inc(c.bufpos)
-  of 'A'..'F': 
+  of 'A'..'F':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
     inc(c.bufpos)
-  else: 
+  else:
     discard
 
-proc handleOctChar(c: var SqlLexer, xi: var int) = 
+proc handleOctChar(c: var SqlLexer, xi: var int) =
   if c.buf[c.bufpos] in {'0'..'7'}:
     xi = (xi shl 3) or (ord(c.buf[c.bufpos]) - ord('0'))
     inc(c.bufpos)
 
-proc getEscapedChar(c: var SqlLexer, tok: var Token) = 
+proc getEscapedChar(c: var SqlLexer, tok: var Token) =
   inc(c.bufpos)
   case c.buf[c.bufpos]
-  of 'n', 'N': 
+  of 'n', 'N':
     add(tok.literal, '\L')
     inc(c.bufpos)
-  of 'r', 'R', 'c', 'C': 
+  of 'r', 'R', 'c', 'C':
     add(tok.literal, '\c')
     inc(c.bufpos)
-  of 'l', 'L': 
+  of 'l', 'L':
     add(tok.literal, '\L')
     inc(c.bufpos)
-  of 'f', 'F': 
+  of 'f', 'F':
     add(tok.literal, '\f')
     inc(c.bufpos)
-  of 'e', 'E': 
+  of 'e', 'E':
     add(tok.literal, '\e')
     inc(c.bufpos)
-  of 'a', 'A': 
+  of 'a', 'A':
     add(tok.literal, '\a')
     inc(c.bufpos)
-  of 'b', 'B': 
+  of 'b', 'B':
     add(tok.literal, '\b')
     inc(c.bufpos)
-  of 'v', 'V': 
+  of 'v', 'V':
     add(tok.literal, '\v')
     inc(c.bufpos)
-  of 't', 'T': 
+  of 't', 'T':
     add(tok.literal, '\t')
     inc(c.bufpos)
-  of '\'', '\"': 
+  of '\'', '\"':
     add(tok.literal, c.buf[c.bufpos])
     inc(c.bufpos)
-  of '\\': 
+  of '\\':
     add(tok.literal, '\\')
     inc(c.bufpos)
-  of 'x', 'X': 
+  of 'x', 'X':
     inc(c.bufpos)
     var xi = 0
     handleHexChar(c, xi)
     handleHexChar(c, xi)
     add(tok.literal, chr(xi))
-  of '0'..'7': 
+  of '0'..'7':
     var xi = 0
     handleOctChar(c, xi)
     handleOctChar(c, xi)
@@ -138,20 +138,20 @@ proc getEscapedChar(c: var SqlLexer, tok: var Token) =
     if (xi <= 255): add(tok.literal, chr(xi))
     else: tok.kind = tkInvalid
   else: tok.kind = tkInvalid
-  
-proc handleCRLF(c: var SqlLexer, pos: int): int = 
+
+proc handleCRLF(c: var SqlLexer, pos: int): int =
   case c.buf[pos]
   of '\c': result = lexbase.handleCR(c, pos)
   of '\L': result = lexbase.handleLF(c, pos)
   else: result = pos
 
-proc skip(c: var SqlLexer) = 
+proc skip(c: var SqlLexer) =
   var pos = c.bufpos
   var buf = c.buf
   var nested = 0
-  while true: 
+  while true:
     case buf[pos]
-    of ' ', '\t': 
+    of ' ', '\t':
       inc(pos)
     of '-':
       if buf[pos+1] == '-':
@@ -164,7 +164,7 @@ proc skip(c: var SqlLexer) =
         while true:
           case buf[pos]
           of '\0': break
-          of '\c', '\L': 
+          of '\c', '\L':
             pos = handleCRLF(c, pos)
             buf = c.buf
           of '*':
@@ -182,20 +182,20 @@ proc skip(c: var SqlLexer) =
               inc(pos)
           else: inc(pos)
       else: break
-    of '\c', '\L': 
+    of '\c', '\L':
       pos = handleCRLF(c, pos)
       buf = c.buf
-    else: 
+    else:
       break                   # EndOfFile also leaves the loop
   c.bufpos = pos
-  
-proc getString(c: var SqlLexer, tok: var Token, kind: TokKind) = 
+
+proc getString(c: var SqlLexer, tok: var Token, kind: TokKind) =
   var pos = c.bufpos + 1
   var buf = c.buf
   tok.kind = kind
   block parseLoop:
     while true:
-      while true: 
+      while true:
         var ch = buf[pos]
         if ch == '\'':
           if buf[pos+1] == '\'':
@@ -203,15 +203,15 @@ proc getString(c: var SqlLexer, tok: var Token, kind: TokKind) =
             add(tok.literal, '\'')
           else:
             inc(pos)
-            break 
-        elif ch in {'\c', '\L', lexbase.EndOfFile}: 
+            break
+        elif ch in {'\c', '\L', lexbase.EndOfFile}:
           tok.kind = tkInvalid
           break parseLoop
-        elif (ch == '\\') and kind == tkEscapeConstant: 
+        elif (ch == '\\') and kind == tkEscapeConstant:
           c.bufpos = pos
           getEscapedChar(c, tok)
           pos = c.bufpos
-        else: 
+        else:
           add(tok.literal, ch)
           inc(pos)
       c.bufpos = pos
@@ -227,7 +227,7 @@ proc getString(c: var SqlLexer, tok: var Token, kind: TokKind) =
       else: break parseLoop
   c.bufpos = pos
 
-proc getDollarString(c: var SqlLexer, tok: var Token) = 
+proc getDollarString(c: var SqlLexer, tok: var Token) =
   var pos = c.bufpos + 1
   var buf = c.buf
   tok.kind = tkDollarQuotedConstant
@@ -241,7 +241,7 @@ proc getDollarString(c: var SqlLexer, tok: var Token) =
     return
   while true:
     case buf[pos]
-    of '\c', '\L': 
+    of '\c', '\L':
       pos = handleCRLF(c, pos)
       buf = c.buf
       add(tok.literal, "\L")
@@ -263,10 +263,10 @@ proc getDollarString(c: var SqlLexer, tok: var Token) =
       inc(pos)
   c.bufpos = pos
 
-proc getSymbol(c: var SqlLexer, tok: var Token) = 
+proc getSymbol(c: var SqlLexer, tok: var Token) =
   var pos = c.bufpos
   var buf = c.buf
-  while true: 
+  while true:
     add(tok.literal, buf[pos])
     inc(pos)
     if buf[pos] notin {'a'..'z','A'..'Z','0'..'9','_','$', '\128'..'\255'}:
@@ -274,7 +274,7 @@ proc getSymbol(c: var SqlLexer, tok: var Token) =
   c.bufpos = pos
   tok.kind = tkIdentifier
 
-proc getQuotedIdentifier(c: var SqlLexer, tok: var Token) = 
+proc getQuotedIdentifier(c: var SqlLexer, tok: var Token) =
   var pos = c.bufpos + 1
   var buf = c.buf
   tok.kind = tkQuotedIdentifier
@@ -287,7 +287,7 @@ proc getQuotedIdentifier(c: var SqlLexer, tok: var Token) =
       else:
         inc(pos)
         break
-    elif ch in {'\c', '\L', lexbase.EndOfFile}: 
+    elif ch in {'\c', '\L', lexbase.EndOfFile}:
       tok.kind = tkInvalid
       break
     else:
@@ -300,15 +300,15 @@ proc getBitHexString(c: var SqlLexer, tok: var Token, validChars: set[char]) =
   var buf = c.buf
   block parseLoop:
     while true:
-      while true: 
+      while true:
         var ch = buf[pos]
         if ch in validChars:
           add(tok.literal, ch)
-          inc(pos)          
+          inc(pos)
         elif ch == '\'':
           inc(pos)
           break
-        else: 
+        else:
           tok.kind = tkInvalid
           break parseLoop
       c.bufpos = pos
@@ -353,7 +353,7 @@ proc getNumeric(c: var SqlLexer, tok: var Token) =
         inc(pos)
     else:
       tok.kind = tkInvalid
-  c.bufpos = pos  
+  c.bufpos = pos
 
 proc getOperator(c: var SqlLexer, tok: var Token) =
   const operators = {'+', '-', '*', '/', '<', '>', '=', '~', '!', '@', '#', '%',
@@ -381,12 +381,12 @@ proc getOperator(c: var SqlLexer, tok: var Token) =
     inc(pos)
   c.bufpos = pos
 
-proc getTok(c: var SqlLexer, tok: var Token) = 
+proc getTok(c: var SqlLexer, tok: var Token) =
   tok.kind = tkInvalid
   setLen(tok.literal, 0)
   skip(c)
   case c.buf[c.bufpos]
-  of ';': 
+  of ';':
     tok.kind = tkSemicolon
     inc(c.bufpos)
     add(tok.literal, ';')
@@ -394,15 +394,15 @@ proc getTok(c: var SqlLexer, tok: var Token) =
     tok.kind = tkComma
     inc(c.bufpos)
     add(tok.literal, ',')
-  of ':': 
+  of ':':
     tok.kind = tkColon
     inc(c.bufpos)
     add(tok.literal, ':')
-  of 'e', 'E': 
-    if c.buf[c.bufpos + 1] == '\'': 
+  of 'e', 'E':
+    if c.buf[c.bufpos + 1] == '\'':
       inc(c.bufpos)
       getString(c, tok, tkEscapeConstant)
-    else: 
+    else:
       getSymbol(c, tok)
   of 'b', 'B':
     if c.buf[c.bufpos + 1] == '\'':
@@ -417,11 +417,11 @@ proc getTok(c: var SqlLexer, tok: var Token) =
     else:
       getSymbol(c, tok)
   of '$': getDollarString(c, tok)
-  of '[': 
+  of '[':
     tok.kind = tkBracketLe
     inc(c.bufpos)
     add(tok.literal, '[')
-  of ']': 
+  of ']':
     tok.kind = tkBracketRi
     inc(c.bufpos)
     add(tok.literal, ']')
@@ -433,7 +433,7 @@ proc getTok(c: var SqlLexer, tok: var Token) =
     tok.kind = tkParRi
     inc(c.bufpos)
     add(tok.literal, ')')
-  of '.': 
+  of '.':
     if c.buf[c.bufpos + 1] in Digits:
       getNumeric(c, tok)
     else:
@@ -443,7 +443,7 @@ proc getTok(c: var SqlLexer, tok: var Token) =
   of '0'..'9': getNumeric(c, tok)
   of '\'': getString(c, tok, tkStringConstant)
   of '"': getQuotedIdentifier(c, tok)
-  of lexbase.EndOfFile: 
+  of lexbase.EndOfFile:
     tok.kind = tkEof
     tok.literal = "[EOF]"
   of 'a', 'c', 'd', 'f'..'w', 'y', 'z', 'A', 'C', 'D', 'F'..'W', 'Y', 'Z', '_',
@@ -455,8 +455,8 @@ proc getTok(c: var SqlLexer, tok: var Token) =
   else:
     add(tok.literal, c.buf[c.bufpos])
     inc(c.bufpos)
-  
-proc errorStr(L: SqlLexer, msg: string): string = 
+
+proc errorStr(L: SqlLexer, msg: string): string =
   result = "$1($2, $3) Error: $4" % [L.filename, $getLine(L), $getColumn(L), msg]
 
 
@@ -496,7 +496,7 @@ type
     nkPrimaryKey,
     nkForeignKey,
     nkNotNull,
-    
+
     nkStmtList,
     nkDot,
     nkDotDot,
@@ -530,13 +530,13 @@ type
     nkValueList,
     nkWhere,
     nkCreateTable,
-    nkCreateTableIfNotExists, 
+    nkCreateTableIfNotExists,
     nkCreateType,
     nkCreateTypeIfNotExists,
     nkCreateIndex,
     nkCreateIndexIfNotExists,
     nkEnumDef
-    
+
 type
   SqlParseError* = object of ValueError ## Invalid SQL encountered
   SqlNode* = ref SqlNodeObj        ## an SQL abstract syntax tree node
@@ -563,11 +563,11 @@ proc newNode(k: SqlNodeKind, s: string): SqlNode =
   new(result)
   result.kind = k
   result.strVal = s
-  
+
 proc len*(n: SqlNode): int =
   if isNil(n.sons): result = 0
   else: result = n.sons.len
-  
+
 proc add*(father, n: SqlNode) =
   if isNil(father.sons): father.sons = @[]
   add(father.sons, n)
@@ -641,11 +641,11 @@ proc parseDataType(p: var SqlParser): SqlNode =
         getTok(p)
       eat(p, tkParRi)
 
-proc getPrecedence(p: SqlParser): int = 
+proc getPrecedence(p: SqlParser): int =
   if isOpr(p, "*") or isOpr(p, "/") or isOpr(p, "%"):
     result = 6
   elif isOpr(p, "+") or isOpr(p, "-"):
-    result = 5  
+    result = 5
   elif isOpr(p, "=") or isOpr(p, "<") or isOpr(p, ">") or isOpr(p, ">=") or
        isOpr(p, "<=") or isOpr(p, "<>") or isOpr(p, "!=") or isKeyw(p, "is") or
        isKeyw(p, "like"):
@@ -664,7 +664,7 @@ proc parseExpr(p: var SqlParser): SqlNode
 
 proc identOrLiteral(p: var SqlParser): SqlNode =
   case p.tok.kind
-  of tkIdentifier, tkQuotedIdentifier: 
+  of tkIdentifier, tkQuotedIdentifier:
     result = newNode(nkIdent, p.tok.literal)
     getTok(p)
   of tkStringConstant, tkEscapeConstant, tkDollarQuotedConstant:
@@ -686,21 +686,21 @@ proc identOrLiteral(p: var SqlParser): SqlNode =
     getTok(p)
     result = parseExpr(p)
     eat(p, tkParRi)
-  else: 
+  else:
     sqlError(p, "expression expected")
     getTok(p) # we must consume a token here to prevend endless loops!
 
-proc primary(p: var SqlParser): SqlNode = 
-  if p.tok.kind == tkOperator or isKeyw(p, "not"): 
+proc primary(p: var SqlParser): SqlNode =
+  if p.tok.kind == tkOperator or isKeyw(p, "not"):
     result = newNode(nkPrefix)
     result.add(newNode(nkIdent, p.tok.literal))
     getTok(p)
     result.add(primary(p))
     return
   result = identOrLiteral(p)
-  while true: 
+  while true:
     case p.tok.kind
-    of tkParLe: 
+    of tkParLe:
       var a = result
       result = newNode(nkCall)
       result.add(a)
@@ -710,7 +710,7 @@ proc primary(p: var SqlParser): SqlNode =
         if p.tok.kind == tkComma: getTok(p)
         else: break
       eat(p, tkParRi)
-    of tkDot: 
+    of tkDot:
       getTok(p)
       var a = result
       if p.tok.kind == tkDot:
@@ -727,14 +727,14 @@ proc primary(p: var SqlParser): SqlNode =
         sqlError(p, "identifier expected")
       getTok(p)
     else: break
-  
-proc lowestExprAux(p: var SqlParser, v: var SqlNode, limit: int): int = 
+
+proc lowestExprAux(p: var SqlParser, v: var SqlNode, limit: int): int =
   var
     v2, node, opNode: SqlNode
   v = primary(p) # expand while operators have priorities higher than 'limit'
   var opPred = getPrecedence(p)
   result = opPred
-  while opPred > limit: 
+  while opPred > limit:
     node = newNode(nkInfix)
     opNode = newNode(nkIdent, p.tok.literal)
     getTok(p)
@@ -744,8 +744,8 @@ proc lowestExprAux(p: var SqlParser, v: var SqlNode, limit: int): int =
     node.add(v2)
     v = node
     opPred = getPrecedence(p)
-  
-proc parseExpr(p: var SqlParser): SqlNode = 
+
+proc parseExpr(p: var SqlParser): SqlNode =
   discard lowestExprAux(p, result, - 1)
 
 proc parseTableName(p: var SqlParser): SqlNode =
@@ -765,7 +765,7 @@ proc parseColumnReference(p: var SqlParser): SqlNode =
       result.add(parseTableName(p))
     eat(p, tkParRi)
 
-proc parseCheck(p: var SqlParser): SqlNode = 
+proc parseCheck(p: var SqlParser): SqlNode =
   getTok(p)
   result = newNode(nkCheck)
   result.add(parseExpr(p))
@@ -817,9 +817,9 @@ proc parseColumnDef(p: var SqlParser): SqlNode =
   result.add(newNode(nkIdent, p.tok.literal))
   getTok(p)
   result.add(parseDataType(p))
-  parseColumnConstraints(p, result)  
+  parseColumnConstraints(p, result)
 
-proc parseIfNotExists(p: var SqlParser, k: SqlNodeKind): SqlNode = 
+proc parseIfNotExists(p: var SqlParser, k: SqlNodeKind): SqlNode =
   getTok(p)
   if isKeyw(p, "if"):
     getTok(p)
@@ -880,7 +880,7 @@ proc parseTableDef(p: var SqlParser): SqlNode =
         result.add(parseTableConstraint(p))
       if p.tok.kind != tkComma: break
     eat(p, tkParRi)
-  
+
 proc parseTypeDef(p: var SqlParser): SqlNode =
   result = parseIfNotExists(p, nkCreateType)
   expectIdent(p)
@@ -966,7 +966,7 @@ proc parseUpdate(p: var SqlParser): SqlNode =
     result.add(parseWhere(p))
   else:
     result.add(nil)
-    
+
 proc parseDelete(p: var SqlParser): SqlNode =
   getTok(p)
   result = newNode(nkDelete)
@@ -1018,14 +1018,14 @@ proc parseSelect(p: var SqlParser): SqlNode =
     while true:
       getTok(p)
       h.add(parseExpr(p))
-      if p.tok.kind != tkComma: break    
+      if p.tok.kind != tkComma: break
     result.add(h)
   if isKeyw(p, "union"):
     result.add(newNode(nkUnion))
     getTok(p)
   elif isKeyw(p, "intersect"):
     result.add(newNode(nkIntersect))
-    getTok(p)  
+    getTok(p)
   elif isKeyw(p, "except"):
     result.add(newNode(nkExcept))
     getTok(p)
@@ -1083,7 +1083,7 @@ proc open(p: var SqlParser, input: Stream, filename: string) =
   p.tok.kind = tkInvalid
   p.tok.literal = ""
   getTok(p)
-  
+
 proc parse(p: var SqlParser): SqlNode =
   ## parses the content of `p`'s input stream and returns the SQL AST.
   ## Syntax errors raise an `EInvalidSql` exception.
@@ -1094,13 +1094,13 @@ proc parse(p: var SqlParser): SqlNode =
     result.add(s)
   if result.len == 1:
     result = result.sons[0]
-  
+
 proc close(p: var SqlParser) =
   ## closes the parser `p`. The associated input stream is closed too.
   close(SqlLexer(p))
 
 proc parseSQL*(input: Stream, filename: string): SqlNode =
-  ## parses the SQL from `input` into an AST and returns the AST. 
+  ## parses the SQL from `input` into an AST and returns the AST.
   ## `filename` is only used for error messages.
   ## Syntax errors raise an `EInvalidSql` exception.
   var p: SqlParser
@@ -1114,7 +1114,7 @@ proc ra(n: SqlNode, s: var string, indent: int)
 
 proc rs(n: SqlNode, s: var string, indent: int,
         prefix = "(", suffix = ")",
-        sep = ", ") = 
+        sep = ", ") =
   if n.len > 0:
     s.add(prefix)
     for i in 0 .. n.len-1:
@@ -1162,7 +1162,7 @@ proc ra(n: SqlNode, s: var string, indent: int) =
     ra(n.sons[1], s, indent)
     s.add(')')
   of nkInfix:
-    s.add('(')    
+    s.add('(')
     ra(n.sons[1], s, indent)
     s.add(' ')
     ra(n.sons[0], s, indent)
@@ -1207,13 +1207,13 @@ proc ra(n: SqlNode, s: var string, indent: int) =
     s.add("insert into ")
     ra(n.sons[0], s, indent)
     ra(n.sons[1], s, indent)
-    if n.sons[2].kind == nkDefault: 
+    if n.sons[2].kind == nkDefault:
       s.add("default values")
     else:
       s.add("\nvalues ")
       ra(n.sons[2], s, indent)
     s.add(';')
-  of nkUpdate: 
+  of nkUpdate:
     s.add("update ")
     ra(n.sons[0], s, indent)
     s.add(" set ")
@@ -1225,7 +1225,7 @@ proc ra(n: SqlNode, s: var string, indent: int) =
       ra(it, s, indent)
     ra(n.sons[L-1], s, indent)
     s.add(';')
-  of nkDelete: 
+  of nkDelete:
     s.add("delete from ")
     ra(n.sons[0], s, indent)
     ra(n.sons[1], s, indent)
@@ -1237,12 +1237,12 @@ proc ra(n: SqlNode, s: var string, indent: int) =
     rs(n.sons[0], s, indent, "", "", ", ")
     for i in 1 .. n.len-1: ra(n.sons[i], s, indent)
     s.add(';')
-  of nkSelectColumns: 
+  of nkSelectColumns:
     assert(false)
   of nkAsgn:
     ra(n.sons[0], s, indent)
     s.add(" = ")
-    ra(n.sons[1], s, indent)  
+    ra(n.sons[1], s, indent)
   of nkFrom:
     s.add("\nfrom ")
     rs(n, s, indent, "", "", ", ")
@@ -1306,23 +1306,23 @@ proc ra(n: SqlNode, s: var string, indent: int) =
     s.add("enum ")
     rs(n, s, indent)
 
-# What I want: 
+# What I want:
 #
-#select(columns = [T1.all, T2.name], 
+#select(columns = [T1.all, T2.name],
 #       fromm = [T1, T2],
 #       where = T1.name ==. T2.name,
 #       orderby = [name]):
-#  
-#for row in dbQuery(db, """select x, y, z 
-#                          from a, b 
+#
+#for row in dbQuery(db, """select x, y, z
+#                          from a, b
 #                          where a.name = b.name"""):
-#  
+#
 
 #select x, y, z:
 #  fromm: Table1, Table2
 #  where: x.name == y.name
 #db.select(fromm = [t1, t2], where = t1.name == t2.name):
-#for x, y, z in db.select(fromm = a, b where = a.name == b.name): 
+#for x, y, z in db.select(fromm = a, b where = a.name == b.name):
 #  writeLine x, y, z
 
 proc renderSQL*(n: SqlNode): string =
@@ -1338,7 +1338,7 @@ when not defined(testing) and isMainModule:
          happiness happiness
       );
       CREATE INDEX table1_attr1 ON table1(attr1);
-      
+
       SELECT * FROM myTab WHERE col1 = 'happy';
   """), "stdin")))