parsesql can parse more SQL

This commit is contained in:
Araq
2017-09-01 14:42:36 +02:00
parent dcc72ea7a9
commit b2a5f97860

View File

@@ -496,6 +496,7 @@ type
nkPrimaryKey,
nkForeignKey,
nkNotNull,
nkNull,
nkStmtList,
nkDot,
@@ -613,6 +614,9 @@ proc eat(p: var SqlParser, keyw: string) =
else:
sqlError(p, keyw.toUpper() & " expected")
proc opt(p: var SqlParser, kind: TokKind) =
if p.tok.kind == kind: getTok(p)
proc parseDataType(p: var SqlParser): SqlNode =
if isKeyw(p, "enum"):
result = newNode(nkEnumDef)
@@ -705,7 +709,7 @@ proc primary(p: var SqlParser): SqlNode =
result = newNode(nkCall)
result.add(a)
getTok(p)
while true:
while p.tok.kind != tkParRi:
result.add(parseExpr(p))
if p.tok.kind == tkComma: getTok(p)
else: break
@@ -776,9 +780,19 @@ proc parseConstraint(p: var SqlParser): SqlNode =
expectIdent(p)
result.add(newNode(nkIdent, p.tok.literal))
getTok(p)
eat(p, "check")
optKeyw(p, "check")
result.add(parseExpr(p))
proc parseParIdentList(p: var SqlParser, father: SqlNode) =
eat(p, tkParLe)
while true:
expectIdent(p)
father.add(newNode(nkIdent, p.tok.literal))
getTok(p)
if p.tok.kind != tkComma: break
getTok(p)
eat(p, tkParRi)
proc parseColumnConstraints(p: var SqlParser, result: SqlNode) =
while true:
if isKeyw(p, "default"):
@@ -795,6 +809,9 @@ proc parseColumnConstraints(p: var SqlParser, result: SqlNode) =
getTok(p)
eat(p, "null")
result.add(newNode(nkNotNull))
elif isKeyw(p, "null"):
getTok(p)
result.add(newNode(nkNull))
elif isKeyw(p, "identity"):
getTok(p)
result.add(newNode(nkIdentity))
@@ -807,6 +824,7 @@ proc parseColumnConstraints(p: var SqlParser, result: SqlNode) =
elif isKeyw(p, "constraint"):
result.add(parseConstraint(p))
elif isKeyw(p, "unique"):
getTok(p)
result.add(newNode(nkUnique))
else:
break
@@ -829,16 +847,6 @@ proc parseIfNotExists(p: var SqlParser, k: SqlNodeKind): SqlNode =
else:
result = newNode(k)
proc parseParIdentList(p: var SqlParser, father: SqlNode) =
eat(p, tkParLe)
while true:
expectIdent(p)
father.add(newNode(nkIdent, p.tok.literal))
getTok(p)
if p.tok.kind != tkComma: break
getTok(p)
eat(p, tkParRi)
proc parseTableConstraint(p: var SqlParser): SqlNode =
if isKeyw(p, "primary"):
getTok(p)
@@ -866,20 +874,34 @@ proc parseTableConstraint(p: var SqlParser): SqlNode =
else:
sqlError(p, "column definition expected")
proc parseUnique(p: var SqlParser): SqlNode =
result = parseExpr(p)
if result.kind == nkCall: result.kind = nkUnique
proc parseTableDef(p: var SqlParser): SqlNode =
result = parseIfNotExists(p, nkCreateTable)
expectIdent(p)
result.add(newNode(nkIdent, p.tok.literal))
getTok(p)
if p.tok.kind == tkParLe:
while true:
getTok(p)
if p.tok.kind == tkIdentifier or p.tok.kind == tkQuotedIdentifier:
getTok(p)
while p.tok.kind != tkParRi:
if isKeyw(p, "constraint"):
result.add parseConstraint(p)
elif isKeyw(p, "primary") or isKeyw(p, "foreign"):
result.add parseTableConstraint(p)
elif isKeyw(p, "unique"):
result.add parseUnique(p)
elif p.tok.kind == tkIdentifier or p.tok.kind == tkQuotedIdentifier:
result.add(parseColumnDef(p))
else:
result.add(parseTableConstraint(p))
if p.tok.kind != tkComma: break
getTok(p)
eat(p, tkParRi)
# skip additional crap after 'create table (...) crap;'
while p.tok.kind notin {tkSemicolon, tkEof}:
getTok(p)
proc parseTypeDef(p: var SqlParser): SqlNode =
result = parseIfNotExists(p, nkCreateType)
@@ -1046,7 +1068,7 @@ proc parseSelect(p: var SqlParser): SqlNode =
getTok(p)
result.add(n)
proc parseStmt(p: var SqlParser): SqlNode =
proc parseStmt(p: var SqlParser; parent: SqlNode) =
if isKeyw(p, "create"):
getTok(p)
optKeyw(p, "cached")
@@ -1058,21 +1080,23 @@ proc parseStmt(p: var SqlParser): SqlNode =
optKeyw(p, "unique")
optKeyw(p, "hash")
if isKeyw(p, "table"):
result = parseTableDef(p)
parent.add parseTableDef(p)
elif isKeyw(p, "type"):
result = parseTypeDef(p)
parent.add parseTypeDef(p)
elif isKeyw(p, "index"):
result = parseIndexDef(p)
parent.add parseIndexDef(p)
else:
sqlError(p, "TABLE expected")
elif isKeyw(p, "insert"):
result = parseInsert(p)
parent.add parseInsert(p)
elif isKeyw(p, "update"):
result = parseUpdate(p)
parent.add parseUpdate(p)
elif isKeyw(p, "delete"):
result = parseDelete(p)
parent.add parseDelete(p)
elif isKeyw(p, "select"):
result = parseSelect(p)
parent.add parseSelect(p)
elif isKeyw(p, "begin"):
getTok(p)
else:
sqlError(p, "CREATE expected")
@@ -1089,9 +1113,8 @@ proc parse(p: var SqlParser): SqlNode =
## Syntax errors raise an `EInvalidSql` exception.
result = newNode(nkStmtList)
while p.tok.kind != tkEof:
var s = parseStmt(p)
parseStmt(p, result)
eat(p, tkSemicolon)
result.add(s)
if result.len == 1:
result = result.sons[0]
@@ -1147,6 +1170,8 @@ proc ra(n: SqlNode, s: var string, indent: int) =
rs(n, s, indent)
of nkNotNull:
s.add(" not null")
of nkNull:
s.add(" null")
of nkDot:
ra(n.sons[0], s, indent)
s.add(".")
@@ -1330,6 +1355,10 @@ proc renderSQL*(n: SqlNode): string =
result = ""
ra(n, result, 0)
proc `$`*(n: SqlNode): string =
## an alias for `renderSQL`.
renderSQL(n)
when not defined(testing) and isMainModule:
echo(renderSQL(parseSQL(newStringStream("""
CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');