This commit is contained in:
treeform 2017-12-14 18:31:43 +00:00
commit ee5a76fd9d
2 changed files with 196 additions and 396 deletions

View file

@ -55,6 +55,13 @@ const
";", ":", ",", "(", ")", "[", "]", "." ";", ":", ",", "(", ")", "[", "]", "."
] ]
reservedKeywords = @[
# statements
"select", "from", "where", "group", "limit", "having",
# functions
"count",
]
proc open(L: var SqlLexer, input: Stream, filename: string) = proc open(L: var SqlLexer, input: Stream, filename: string) =
lexbase.open(L, input) lexbase.open(L, input)
L.filename = filename L.filename = filename
@ -274,16 +281,16 @@ proc getSymbol(c: var SqlLexer, tok: var Token) =
c.bufpos = pos c.bufpos = pos
tok.kind = tkIdentifier tok.kind = tkIdentifier
proc getQuotedIdentifier(c: var SqlLexer, tok: var Token) = proc getQuotedIdentifier(c: var SqlLexer, tok: var Token, quote='\"') =
var pos = c.bufpos + 1 var pos = c.bufpos + 1
var buf = c.buf var buf = c.buf
tok.kind = tkQuotedIdentifier tok.kind = tkQuotedIdentifier
while true: while true:
var ch = buf[pos] var ch = buf[pos]
if ch == '\"': if ch == quote:
if buf[pos+1] == '\"': if buf[pos+1] == quote:
inc(pos, 2) inc(pos, 2)
add(tok.literal, '\"') add(tok.literal, quote)
else: else:
inc(pos) inc(pos)
break break
@ -442,7 +449,8 @@ proc getTok(c: var SqlLexer, tok: var Token) =
add(tok.literal, '.') add(tok.literal, '.')
of '0'..'9': getNumeric(c, tok) of '0'..'9': getNumeric(c, tok)
of '\'': getString(c, tok, tkStringConstant) of '\'': getString(c, tok, tkStringConstant)
of '"': getQuotedIdentifier(c, tok) of '"': getQuotedIdentifier(c, tok, '"')
of '`': getQuotedIdentifier(c, tok, '`')
of lexbase.EndOfFile: of lexbase.EndOfFile:
tok.kind = tkEof tok.kind = tkEof
tok.literal = "[EOF]" tok.literal = "[EOF]"
@ -450,7 +458,7 @@ proc getTok(c: var SqlLexer, tok: var Token) =
'\128'..'\255': '\128'..'\255':
getSymbol(c, tok) getSymbol(c, tok)
of '+', '-', '*', '/', '<', '>', '=', '~', '!', '@', '#', '%', of '+', '-', '*', '/', '<', '>', '=', '~', '!', '@', '#', '%',
'^', '&', '|', '`', '?': '^', '&', '|', '?':
getOperator(c, tok) getOperator(c, tok)
else: else:
add(tok.literal, c.buf[c.bufpos]) add(tok.literal, c.buf[c.bufpos])
@ -504,6 +512,7 @@ type
nkPrefix, nkPrefix,
nkInfix, nkInfix,
nkCall, nkCall,
nkPrGroup,
nkColumnReference, nkColumnReference,
nkReferences, nkReferences,
nkDefault, nkDefault,
@ -700,7 +709,8 @@ proc identOrLiteral(p: var SqlParser): SqlNode =
getTok(p) getTok(p)
of tkParLe: of tkParLe:
getTok(p) getTok(p)
result = parseExpr(p) result = newNode(nkPrGroup)
result.add(parseExpr(p))
eat(p, tkParRi) eat(p, tkParRi)
else: else:
sqlError(p, "expression expected") sqlError(p, "expression expected")
@ -752,7 +762,7 @@ proc lowestExprAux(p: var SqlParser, v: var SqlNode, limit: int): int =
result = opPred result = opPred
while opPred > limit: while opPred > limit:
node = newNode(nkInfix) node = newNode(nkInfix)
opNode = newNode(nkIdent, p.tok.literal) opNode = newNode(nkIdent, p.tok.literal.toLower())
getTok(p) getTok(p)
result = lowestExprAux(p, v2, opPred) result = lowestExprAux(p, v2, opPred)
node.add(opNode) node.add(opNode)
@ -1112,7 +1122,8 @@ proc parseSelect(p: var SqlParser): SqlNode =
join.add(newNode(nkIdent, "")) join.add(newNode(nkIdent, ""))
getTok(p) getTok(p)
else: else:
join.add(parseExpr(p)) join.add(newNode(nkIdent, p.tok.literal.toLower()))
getTok(p)
eat(p, "join") eat(p, "join")
join.add(parseFromItem(p)) join.add(parseFromItem(p))
eat(p, "on") eat(p, "on")
@ -1167,8 +1178,6 @@ proc parse(p: var SqlParser): SqlNode =
if p.tok.kind == tkEof: if p.tok.kind == tkEof:
break break
eat(p, tkSemicolon) eat(p, tkSemicolon)
if result.len == 1:
result = result.sons[0]
proc close(p: var SqlParser) = proc close(p: var SqlParser) =
## closes the parser `p`. The associated input stream is closed too. ## closes the parser `p`. The associated input stream is closed too.
@ -1198,44 +1207,25 @@ type
upperCase: bool upperCase: bool
buffer: string buffer: string
proc add(s: var SqlWriter, thing: string) =
s.buffer.add(thing)
proc add(s: var SqlWriter, thing: char) = proc add(s: var SqlWriter, thing: char) =
s.buffer.add(thing) s.buffer.add(thing)
proc addKeyw(s: var SqlWriter, thing: string) = proc add(s: var SqlWriter, thing: string) =
if s.buffer.len > 0 and s.buffer[^1] notin " ,\L(": if s.buffer.len > 0 and s.buffer[^1] notin {' ', '\L', '(', '.'}:
s.buffer.add(" ") s.buffer.add(" ")
if s.upperCase:
s.buffer.add(thing.toUpper())
else:
s.buffer.add(thing) s.buffer.add(thing)
s.buffer.add(" ")
proc rm(s: var SqlWriter, chars = " \L,") = proc addKeyw(s: var SqlWriter, thing: string) =
while s.buffer.len > 0 and s.buffer[^1] in chars: var keyw = thing
s.buffer = s.buffer[0..^2] if s.upperCase:
keyw = keyw.toUpper()
s.add(keyw)
proc newLine(s: var SqlWriter) = proc addIden(s: var SqlWriter, thing: string) =
s.rm(" \L") var iden = thing
s.buffer.add("\L") if iden.toLower() in reservedKeywords:
for i in 0..<s.indent: iden = '"' & iden & '"'
s.buffer.add(" ") s.add(iden)
template inner(s: var SqlWriter, body: untyped) =
inc s.indent
s.newLine()
body
dec s.indent
template innerKeyw(s: var SqlWriter, keyw: string, body: untyped) =
s.newLine()
s.addKeyw(keyw)
inc s.indent
s.newLine()
body
dec s.indent
proc ra(n: SqlNode, s: var SqlWriter) proc ra(n: SqlNode, s: var SqlWriter)
@ -1247,17 +1237,30 @@ proc rs(n: SqlNode, s: var SqlWriter, prefix = "(", suffix = ")", sep = ", ") =
ra(n.sons[i], s) ra(n.sons[i], s)
s.add(suffix) s.add(suffix)
proc addMulti(s: var SqlWriter, n: SqlNode, sep = ',') =
if n.len > 0:
for i in 0 .. n.len-1:
if i > 0: s.add(sep)
ra(n.sons[i], s)
proc addMulti(s: var SqlWriter, n: SqlNode, sep = ',', prefix, suffix: char) =
if n.len > 0:
s.add(prefix)
for i in 0 .. n.len-1:
if i > 0: s.add(sep)
ra(n.sons[i], s)
s.add(suffix)
proc ra(n: SqlNode, s: var SqlWriter) = proc ra(n: SqlNode, s: var SqlWriter) =
if n == nil: return if n == nil: return
case n.kind case n.kind
of nkNone: discard of nkNone: discard
of nkIdent: of nkIdent:
if allCharsInSet(n.strVal, {'\33'..'\127'}): if allCharsInSet(n.strVal, {'\33'..'\127'}) and n.strVal.toLower() notin reservedKeywords:
s.add(n.strVal) s.add(n.strVal)
else: else:
s.add("\"" & replace(n.strVal, "\"", "\"\"") & "\"") s.add("\"" & replace(n.strVal, "\"", "\"\"") & "\"")
of nkStringLit: of nkStringLit:
# TODO add e'' as an option?
s.add(escape(n.strVal, "'", "'")) s.add(escape(n.strVal, "'", "'"))
of nkBitStringLit: of nkBitStringLit:
s.add("b'" & n.strVal & "'") s.add("b'" & n.strVal & "'")
@ -1277,33 +1280,33 @@ proc ra(n: SqlNode, s: var SqlWriter) =
s.addKeyw("null") s.addKeyw("null")
of nkDot: of nkDot:
ra(n.sons[0], s) ra(n.sons[0], s)
s.add(".") s.add('.')
ra(n.sons[1], s) ra(n.sons[1], s)
of nkDotDot: of nkDotDot:
ra(n.sons[0], s) ra(n.sons[0], s)
s.add(". .") s.add(". .")
ra(n.sons[1], s) ra(n.sons[1], s)
of nkPrefix: of nkPrefix:
s.add('(')
ra(n.sons[0], s) ra(n.sons[0], s)
s.add(' ') s.add(' ')
ra(n.sons[1], s) ra(n.sons[1], s)
s.add(')')
of nkInfix: of nkInfix:
s.add('(')
ra(n.sons[1], s) ra(n.sons[1], s)
s.add(' ') s.add(' ')
ra(n.sons[0], s) ra(n.sons[0], s)
s.add(' ') s.add(' ')
ra(n.sons[2], s) ra(n.sons[2], s)
s.add(')')
of nkCall, nkColumnReference: of nkCall, nkColumnReference:
ra(n.sons[0], s) ra(n.sons[0], s)
s.add('(') s.add('(')
for i in 1..n.len-1: for i in 1..n.len-1:
if i > 1: s.add(", ") if i > 1: s.add(',')
ra(n.sons[i], s) ra(n.sons[i], s)
s.add(')') s.add(')')
of nkPrGroup:
s.add('(')
s.addMulti(n)
s.add(')')
of nkReferences: of nkReferences:
s.addKeyw("references") s.addKeyw("references")
ra(n.sons[0], s) ra(n.sons[0], s)
@ -1324,29 +1327,25 @@ proc ra(n: SqlNode, s: var SqlWriter) =
of nkIdentity: of nkIdentity:
s.addKeyw("identity") s.addKeyw("identity")
of nkColumnDef: of nkColumnDef:
s.add("\n ")
rs(n, s, "", "", " ") rs(n, s, "", "", " ")
of nkStmtList: of nkStmtList:
for i in 0..n.len-1: for i in 0..n.len-1:
ra(n.sons[i], s) ra(n.sons[i], s)
s.add("\n") s.add(';')
of nkInsert: of nkInsert:
assert n.len == 3 assert n.len == 3
s.addKeyw("insert into") s.addKeyw("insert into")
ra(n.sons[0], s) ra(n.sons[0], s)
s.add(" ") s.add(' ')
ra(n.sons[1], s) ra(n.sons[1], s)
if n.sons[2].kind == nkDefault: if n.sons[2].kind == nkDefault:
s.addKeyw("default values") s.addKeyw("default values")
else: else:
s.newLine()
ra(n.sons[2], s) ra(n.sons[2], s)
s.rm(" ")
s.add(';')
of nkUpdate: of nkUpdate:
s.innerKeyw("update"): s.addKeyw("update")
ra(n.sons[0], s) ra(n.sons[0], s)
s.innerKeyw("set"): s.addKeyw("set")
var L = n.len var L = n.len
for i in 1 .. L-2: for i in 1 .. L-2:
if i > 1: s.add(", ") if i > 1: s.add(", ")
@ -1354,25 +1353,17 @@ proc ra(n: SqlNode, s: var SqlWriter) =
assert it.kind == nkAsgn assert it.kind == nkAsgn
ra(it, s) ra(it, s)
ra(n.sons[L-1], s) ra(n.sons[L-1], s)
s.add(';')
of nkDelete: of nkDelete:
s.addKeyw("delete from") s.addKeyw("delete from")
ra(n.sons[0], s) ra(n.sons[0], s)
ra(n.sons[1], s) ra(n.sons[1], s)
s.add(';')
of nkSelect, nkSelectDistinct: of nkSelect, nkSelectDistinct:
s.addKeyw("select") s.addKeyw("select")
if n.kind == nkSelectDistinct: if n.kind == nkSelectDistinct:
s.addKeyw("distinct") s.addKeyw("distinct")
s.inner: s.addMulti(n.sons[0])
for son in n.sons[0].sons:
ra(son, s)
s.add(',')
s.newLine()
s.rm()
for i in 1 .. n.len-1: for i in 1 .. n.len-1:
ra(n.sons[i], s) ra(n.sons[i], s)
s.add(';')
of nkSelectColumns: of nkSelectColumns:
assert(false) assert(false)
of nkSelectPair: of nkSelectPair:
@ -1385,12 +1376,9 @@ proc ra(n: SqlNode, s: var SqlWriter) =
ra(n.sons[0], s) ra(n.sons[0], s)
else: else:
assert n.sons[0].kind == nkSelect assert n.sons[0].kind == nkSelect
s.add("(") s.add('(')
s.inner:
ra(n.sons[0], s) ra(n.sons[0], s)
s.rm("; \L") s.add(')')
s.newLine()
s.add(")")
if n.sons.len == 2: if n.sons.len == 2:
s.addKeyw("as") s.addKeyw("as")
ra(n.sons[1], s) ra(n.sons[1], s)
@ -1399,29 +1387,29 @@ proc ra(n: SqlNode, s: var SqlWriter) =
s.add(" = ") s.add(" = ")
ra(n.sons[1], s) ra(n.sons[1], s)
of nkFrom: of nkFrom:
s.innerKeyw("from"): s.addKeyw("from")
rs(n, s, "", "", ", ") s.addMulti(n)
of nkGroup: of nkGroup:
s.innerKeyw("group by"): s.addKeyw("group by")
rs(n, s, "", "", ", ") s.addMulti(n)
of nkLimit: of nkLimit:
s.innerKeyw("limit"): s.addKeyw("limit")
rs(n, s, "", "", ", ") s.addMulti(n)
of nkHaving: of nkHaving:
s.innerKeyw("having"): s.addKeyw("having")
rs(n, s, "", "", ", ") s.addMulti(n)
of nkOrder: of nkOrder:
s.innerKeyw("order by"): s.addKeyw("order by")
rs(n, s, "", "", ", ") s.addMulti(n)
of nkJoin: of nkJoin:
var joinType = n.sons[0].strVal var joinType = n.sons[0].strVal
if joinType == "": if joinType == "":
joinType = "join" joinType = "join"
else: else:
joinType &= " " & "join" joinType &= " " & "join"
s.innerKeyw(joinType): s.addKeyw(joinType)
ra(n.sons[1], s) ra(n.sons[1], s)
s.innerKeyw("on"): s.addKeyw("on")
ra(n.sons[2], s) ra(n.sons[2], s)
of nkDesc: of nkDesc:
ra(n.sons[0], s) ra(n.sons[0], s)
@ -1438,9 +1426,7 @@ proc ra(n: SqlNode, s: var SqlWriter) =
s.addKeyw("values") s.addKeyw("values")
rs(n, s) rs(n, s)
of nkWhere: of nkWhere:
s.newLine()
s.addKeyw("where") s.addKeyw("where")
s.inner:
ra(n.sons[0], s) ra(n.sons[0], s)
of nkCreateTable, nkCreateTableIfNotExists: of nkCreateTable, nkCreateTableIfNotExists:
s.addKeyw("create table") s.addKeyw("create table")
@ -1449,7 +1435,7 @@ proc ra(n: SqlNode, s: var SqlWriter) =
ra(n.sons[0], s) ra(n.sons[0], s)
s.add('(') s.add('(')
for i in 1..n.len-1: for i in 1..n.len-1:
if i > 1: s.add(",") if i > 1: s.add(',')
ra(n.sons[i], s) ra(n.sons[i], s)
s.add(");") s.add(");")
of nkCreateType, nkCreateTypeIfNotExists: of nkCreateType, nkCreateTypeIfNotExists:
@ -1459,7 +1445,6 @@ proc ra(n: SqlNode, s: var SqlWriter) =
ra(n.sons[0], s) ra(n.sons[0], s)
s.addKeyw("as") s.addKeyw("as")
ra(n.sons[1], s) ra(n.sons[1], s)
s.add(';')
of nkCreateIndex, nkCreateIndexIfNotExists: of nkCreateIndex, nkCreateIndexIfNotExists:
s.addKeyw("create index") s.addKeyw("create index")
if n.kind == nkCreateIndexIfNotExists: if n.kind == nkCreateIndexIfNotExists:

View file

@ -1,346 +1,149 @@
discard """ discard """
file: "tparsesql.nim" file: "tparsesql.nim"
output: '''select
foo
from
table;
select
foo
from
table;
select
foo
from
table
limit
10;
select
foo,
bar,
baz
from
table
limit
10;
select
foo as bar
from
table;
select
foo as foo_prime,
bar as bar_prime,
baz as baz_prime
from
table;
select
*
from
table;
select
*
from
table
where
((a = b) and (c = d));
select
*
from
table
where
(not b);
select
*
from
table
where
(a and (not b));
select
*
from
table
where
(((a = b) and (c = d)) or ((n is null) and (((not b) + 1) = 3)));
select
*
from
table
having
((a = b) and (c = d));
select
a,
b
from
table
group by
a;
select
a,
b
from
table
group by
1, 2;
select
t.a
from
t as t;
select
a,
b
from
(
select
*
from
t
);
select
a,
b
from
(
select
*
from
t
) as foo;
select
a,
b
from
(
select
*
from
(
select
*
from
(
select
*
from
(
select
*
from
inner as inner1
) as inner2
) as inner3
) as inner4
) as inner5;
select
a,
b
from
(
select
*
from
a
), (
select
*
from
b
), (
select
*
from
c
);
select
*
from
Products
where
(Price BETWEEN (10 AND 20));
select
id
from
a
join
b
on
(a.id == b.id);
select
id
from
a
join
(
select
id
from
c
) as b
on
(a.id == b.id);
select
id
from
a
INNER join
b
on
(a.id == b.id);
select
id
from
a
OUTER join
b
on
(a.id == b.id);
select
id
from
a
CROSS join
b
on
(a.id == b.id);
create type happiness as enum ('happy', 'very happy', 'ecstatic');
create table holidays(
num_weeks int,
happiness happiness);
create index table1_attr1 on table1(attr1);
select
*
from
myTab
where
(col1 = 'happy');
insert into Customers (CustomerName, ContactName, Address, City, PostalCode, Country)
values ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway');
insert into TableName default values;
update
Customers
set
ContactName = 'Alfred Schmidt', City = 'Frankfurt'
where
(CustomerID = 1);
delete from table_name;
delete from table_name;
select
*
from
Customers;
select
*
from
Customers
where
((((CustomerName LIKE 'L%') OR (CustomerName LIKE 'R%')) OR (CustomerName LIKE 'W%')) AND (Country = 'USA'))
order by
CustomerName;
'''
""" """
import parsesql import parsesql
echo $parseSQL "SELECT foo FROM table;" doAssert $parseSQL("SELECT foo FROM table;") == "select foo from table;"
echo $parseSQL "SELECT foo FROM table" doAssert $parseSQL("""
echo $parseSQL "SELECT foo FROM table limit 10" SELECT
echo $parseSQL "SELECT foo, bar, baz FROM table limit 10" CustomerName,
echo $parseSQL "SELECT foo AS bar FROM table" ContactName,
echo $parseSQL "SELECT foo AS foo_prime, bar AS bar_prime, baz AS baz_prime FROM table" Address,
echo $parseSQL "SELECT * FROM table" City,
PostalCode,
Country,
CustomerName,
ContactName,
Address,
City,
PostalCode,
Country
FROM table;""") == "select CustomerName, ContactName, Address, City, PostalCode, Country, CustomerName, ContactName, Address, City, PostalCode, Country from table;"
doAssert $parseSQL("SELECT foo FROM table limit 10") == "select foo from table limit 10;"
doAssert $parseSQL("SELECT foo, bar, baz FROM table limit 10") == "select foo, bar, baz from table limit 10;"
doAssert $parseSQL("SELECT foo AS bar FROM table") == "select foo as bar from table;"
doAssert $parseSQL("SELECT foo AS foo_prime, bar AS bar_prime, baz AS baz_prime FROM table") == "select foo as foo_prime, bar as bar_prime, baz as baz_prime from table;"
doAssert $parseSQL("SELECT * FROM table") == "select * from table;"
#TODO add count(*) #TODO add count(*)
#echo $parseSQL "SELECT COUNT(*) FROM table" #doAssert $parseSQL("SELECT COUNT(*) FROM table"
echo $parseSQL """
doAssert $parseSQL("""
SELECT * FROM table SELECT * FROM table
WHERE a = b and c = d WHERE a = b and c = d
""" """) == "select * from table where a = b and c = d;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT * FROM table SELECT * FROM table
WHERE not b WHERE not b
""" """) == "select * from table where not b;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT SELECT
* *
FROM FROM
table table
WHERE WHERE
a and not b a and not b
""" """) == "select * from table where a and not b;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT * FROM table SELECT * FROM table
WHERE a = b and c = d or n is null and not b + 1 = 3 WHERE a = b and c = d or n is null and not b + 1 = 3
""" """) == "select * from table where a = b and c = d or n is null and not b + 1 = 3;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT * FROM table
WHERE (a = b and c = d) or (n is null and not b + 1 = 3)
""") == "select * from table where(a = b and c = d) or (n is null and not b + 1 = 3);"
doAssert $parseSQL("""
SELECT * FROM table SELECT * FROM table
HAVING a = b and c = d HAVING a = b and c = d
""" """) == "select * from table having a = b and c = d;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT a, b FROM table SELECT a, b FROM table
GROUP BY a GROUP BY a
""" """) == "select a, b from table group by a;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT a, b FROM table SELECT a, b FROM table
GROUP BY 1, 2 GROUP BY 1, 2
""" """) == "select a, b from table group by 1, 2;"
echo $parseSQL "SELECT t.a FROM t as t"
echo $parseSQL """ doAssert $parseSQL("SELECT t.a FROM t as t") == "select t.a from t as t;"
doAssert $parseSQL("""
SELECT a, b FROM ( SELECT a, b FROM (
SELECT * FROM t SELECT * FROM t
) )
""" """) == "select a, b from(select * from t);"
echo $parseSQL """
doAssert $parseSQL("""
SELECT a, b FROM ( SELECT a, b FROM (
SELECT * FROM t SELECT * FROM t
) as foo ) as foo
""" """) == "select a, b from(select * from t) as foo;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT a, b FROM ( SELECT a, b FROM (
SELECT * FROM ( SELECT * FROM (
SELECT * FROM ( SELECT * FROM (
SELECT * FROM ( SELECT * FROM (
SELECT * FROM inner as inner1 SELECT * FROM innerTable as inner1
) as inner2 ) as inner2
) as inner3 ) as inner3
) as inner4 ) as inner4
) as inner5 ) as inner5
""" """) == "select a, b from(select * from(select * from(select * from(select * from innerTable as inner1) as inner2) as inner3) as inner4) as inner5;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT a, b FROM SELECT a, b FROM
(SELECT * FROM a), (SELECT * FROM a),
(SELECT * FROM b), (SELECT * FROM b),
(SELECT * FROM c) (SELECT * FROM c)
""" """) == "select a, b from(select * from a),(select * from b),(select * from c);"
echo $parseSQL """
doAssert $parseSQL("""
SELECT * FROM Products SELECT * FROM Products
WHERE Price BETWEEN 10 AND 20; WHERE Price BETWEEN 10 AND 20;
""" """) == "select * from Products where Price between 10 and 20;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT id FROM a SELECT id FROM a
JOIN b JOIN b
ON a.id == b.id ON a.id == b.id
""" """) == "select id from a join b on a.id == b.id;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT id FROM a SELECT id FROM a
JOIN (SELECT id from c) as b JOIN (SELECT id from c) as b
ON a.id == b.id ON a.id == b.id
""" """) == "select id from a join(select id from c) as b on a.id == b.id;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT id FROM a SELECT id FROM a
INNER JOIN b INNER JOIN b
ON a.id == b.id ON a.id == b.id
""" """) == "select id from a inner join b on a.id == b.id;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT id FROM a SELECT id FROM a
OUTER JOIN b OUTER JOIN b
ON a.id == b.id ON a.id == b.id
""" """) == "select id from a outer join b on a.id == b.id;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT id FROM a SELECT id FROM a
CROSS JOIN b CROSS JOIN b
ON a.id == b.id ON a.id == b.id
""" """) == "select id from a cross join b on a.id == b.id;"
echo $parseSQL """
doAssert $parseSQL("""
CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic'); CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
CREATE TABLE holidays ( CREATE TABLE holidays (
num_weeks int, num_weeks int,
@ -348,29 +151,41 @@ CREATE TABLE holidays (
); );
CREATE INDEX table1_attr1 ON table1(attr1); CREATE INDEX table1_attr1 ON table1(attr1);
SELECT * FROM myTab WHERE col1 = 'happy'; SELECT * FROM myTab WHERE col1 = 'happy';
""" """) == "create type happiness as enum ('happy' , 'very happy' , 'ecstatic' ); create table holidays(num_weeks int , happiness happiness );; create index table1_attr1 on table1(attr1 );; select * from myTab where col1 = 'happy';"
echo $parseSQL """
doAssert $parseSQL("""
INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country) INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country)
VALUES ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway'); VALUES ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway');
""" """) == "insert into Customers (CustomerName , ContactName , Address , City , PostalCode , Country ) values ('Cardinal' , 'Tom B. Erichsen' , 'Skagen 21' , 'Stavanger' , '4006' , 'Norway' );"
echo $parseSQL """
doAssert $parseSQL("""
INSERT INTO TableName DEFAULT VALUES INSERT INTO TableName DEFAULT VALUES
""" """) == "insert into TableName default values;"
echo $parseSQL """
doAssert $parseSQL("""
UPDATE Customers UPDATE Customers
SET ContactName = 'Alfred Schmidt', City= 'Frankfurt' SET ContactName = 'Alfred Schmidt', City= 'Frankfurt'
WHERE CustomerID = 1; WHERE CustomerID = 1;
""" """) == "update Customers set ContactName = 'Alfred Schmidt' , City = 'Frankfurt' where CustomerID = 1;"
echo $parseSQL "DELETE FROM table_name;"
echo $parseSQL "DELETE * FROM table_name;" doAssert $parseSQL("DELETE FROM table_name;") == "delete from table_name;"
echo $parseSQL """
doAssert $parseSQL("DELETE * FROM table_name;") == "delete from table_name;"
doAssert $parseSQL("""
--Select all: --Select all:
SELECT * FROM Customers; SELECT * FROM Customers;
""" """) == "select * from Customers;"
echo $parseSQL """
doAssert $parseSQL("""
SELECT * FROM Customers WHERE (CustomerName LIKE 'L%' SELECT * FROM Customers WHERE (CustomerName LIKE 'L%'
OR CustomerName LIKE 'R%' /*OR CustomerName LIKE 'S%' OR CustomerName LIKE 'R%' /*OR CustomerName LIKE 'S%'
OR CustomerName LIKE 'T%'*/ OR CustomerName LIKE 'W%') OR CustomerName LIKE 'T%'*/ OR CustomerName LIKE 'W%')
AND Country='USA' AND Country='USA'
ORDER BY CustomerName; ORDER BY CustomerName;
""" """) == "select * from Customers where(CustomerName like 'L%' or CustomerName like 'R%' or CustomerName like 'W%') and Country = 'USA' order by CustomerName;"
# parse keywords as identifires
doAssert $parseSQL("""
SELECT `SELECT`, `FROM` as `GROUP` FROM `WHERE`;
""") == """select "SELECT", "FROM" as "GROUP" from "WHERE";"""