parsesql.nim 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2009 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## The `parsesql` module implements a high performance SQL file
  10. ## parser. It parses PostgreSQL syntax and the SQL ANSI standard.
  11. ##
  12. ## Unstable API.
  13. import strutils, lexbase
  14. import std/private/decode_helpers
  15. when defined(nimPreviewSlimSystem):
  16. import std/assertions
  17. # ------------------- scanner -------------------------------------------------
  18. type
  19. TokKind = enum ## enumeration of all SQL tokens
  20. tkInvalid, ## invalid token
  21. tkEof, ## end of file reached
  22. tkIdentifier, ## abc
  23. tkQuotedIdentifier, ## "abc"
  24. tkStringConstant, ## 'abc'
  25. tkEscapeConstant, ## e'abc'
  26. tkDollarQuotedConstant, ## $tag$abc$tag$
  27. tkBitStringConstant, ## B'00011'
  28. tkHexStringConstant, ## x'00011'
  29. tkInteger,
  30. tkNumeric,
  31. tkOperator, ## + - * / < > = ~ ! @ # % ^ & | ` ?
  32. tkSemicolon, ## ';'
  33. tkColon, ## ':'
  34. tkComma, ## ','
  35. tkParLe, ## '('
  36. tkParRi, ## ')'
  37. tkBracketLe, ## '['
  38. tkBracketRi, ## ']'
  39. tkDot ## '.'
  40. Token = object # a token
  41. kind: TokKind # the type of the token
  42. literal: string # the parsed (string) literal
  43. SqlLexer* = object of BaseLexer ## the parser object.
  44. filename: string
  45. const
  46. tokKindToStr: array[TokKind, string] = [
  47. "invalid", "[EOF]", "identifier", "quoted identifier", "string constant",
  48. "escape string constant", "dollar quoted constant", "bit string constant",
  49. "hex string constant", "integer constant", "numeric constant", "operator",
  50. ";", ":", ",", "(", ")", "[", "]", "."
  51. ]
  52. reservedKeywords = @[
  53. # statements
  54. "select", "from", "where", "group", "limit", "having",
  55. # functions
  56. "count",
  57. ]
  58. proc close(L: var SqlLexer) =
  59. lexbase.close(L)
  60. proc getColumn(L: SqlLexer): int =
  61. ## get the current column the parser has arrived at.
  62. result = getColNumber(L, L.bufpos)
  63. proc getLine(L: SqlLexer): int =
  64. result = L.lineNumber
  65. proc handleOctChar(c: var SqlLexer, xi: var int) =
  66. if c.buf[c.bufpos] in {'0'..'7'}:
  67. xi = (xi shl 3) or (ord(c.buf[c.bufpos]) - ord('0'))
  68. inc(c.bufpos)
  69. proc getEscapedChar(c: var SqlLexer, tok: var Token) =
  70. inc(c.bufpos)
  71. case c.buf[c.bufpos]
  72. of 'n', 'N':
  73. add(tok.literal, '\L')
  74. inc(c.bufpos)
  75. of 'r', 'R', 'c', 'C':
  76. add(tok.literal, '\c')
  77. inc(c.bufpos)
  78. of 'l', 'L':
  79. add(tok.literal, '\L')
  80. inc(c.bufpos)
  81. of 'f', 'F':
  82. add(tok.literal, '\f')
  83. inc(c.bufpos)
  84. of 'e', 'E':
  85. add(tok.literal, '\e')
  86. inc(c.bufpos)
  87. of 'a', 'A':
  88. add(tok.literal, '\a')
  89. inc(c.bufpos)
  90. of 'b', 'B':
  91. add(tok.literal, '\b')
  92. inc(c.bufpos)
  93. of 'v', 'V':
  94. add(tok.literal, '\v')
  95. inc(c.bufpos)
  96. of 't', 'T':
  97. add(tok.literal, '\t')
  98. inc(c.bufpos)
  99. of '\'', '\"':
  100. add(tok.literal, c.buf[c.bufpos])
  101. inc(c.bufpos)
  102. of '\\':
  103. add(tok.literal, '\\')
  104. inc(c.bufpos)
  105. of 'x', 'X':
  106. inc(c.bufpos)
  107. var xi = 0
  108. if handleHexChar(c.buf[c.bufpos], xi):
  109. inc(c.bufpos)
  110. if handleHexChar(c.buf[c.bufpos], xi):
  111. inc(c.bufpos)
  112. add(tok.literal, chr(xi))
  113. of '0'..'7':
  114. var xi = 0
  115. handleOctChar(c, xi)
  116. handleOctChar(c, xi)
  117. handleOctChar(c, xi)
  118. if (xi <= 255): add(tok.literal, chr(xi))
  119. else: tok.kind = tkInvalid
  120. else: tok.kind = tkInvalid
  121. proc handleCRLF(c: var SqlLexer, pos: int): int =
  122. case c.buf[pos]
  123. of '\c': result = lexbase.handleCR(c, pos)
  124. of '\L': result = lexbase.handleLF(c, pos)
  125. else: result = pos
  126. proc skip(c: var SqlLexer) =
  127. var pos = c.bufpos
  128. var nested = 0
  129. while true:
  130. case c.buf[pos]
  131. of ' ', '\t':
  132. inc(pos)
  133. of '-':
  134. if c.buf[pos+1] == '-':
  135. while not (c.buf[pos] in {'\c', '\L', lexbase.EndOfFile}): inc(pos)
  136. else:
  137. break
  138. of '/':
  139. if c.buf[pos+1] == '*':
  140. inc(pos, 2)
  141. while true:
  142. case c.buf[pos]
  143. of '\0': break
  144. of '\c', '\L':
  145. pos = handleCRLF(c, pos)
  146. of '*':
  147. if c.buf[pos+1] == '/':
  148. inc(pos, 2)
  149. if nested <= 0: break
  150. dec(nested)
  151. else:
  152. inc(pos)
  153. of '/':
  154. if c.buf[pos+1] == '*':
  155. inc(pos, 2)
  156. inc(nested)
  157. else:
  158. inc(pos)
  159. else: inc(pos)
  160. else: break
  161. of '\c', '\L':
  162. pos = handleCRLF(c, pos)
  163. else:
  164. break # EndOfFile also leaves the loop
  165. c.bufpos = pos
  166. proc getString(c: var SqlLexer, tok: var Token, kind: TokKind) =
  167. var pos = c.bufpos + 1
  168. tok.kind = kind
  169. block parseLoop:
  170. while true:
  171. while true:
  172. var ch = c.buf[pos]
  173. if ch == '\'':
  174. if c.buf[pos+1] == '\'':
  175. inc(pos, 2)
  176. add(tok.literal, '\'')
  177. else:
  178. inc(pos)
  179. break
  180. elif ch in {'\c', '\L', lexbase.EndOfFile}:
  181. tok.kind = tkInvalid
  182. break parseLoop
  183. elif (ch == '\\') and kind == tkEscapeConstant:
  184. c.bufpos = pos
  185. getEscapedChar(c, tok)
  186. pos = c.bufpos
  187. else:
  188. add(tok.literal, ch)
  189. inc(pos)
  190. c.bufpos = pos
  191. var line = c.lineNumber
  192. skip(c)
  193. if c.lineNumber > line:
  194. # a new line whitespace has been parsed, so we check if the string
  195. # continues after the whitespace:
  196. pos = c.bufpos
  197. if c.buf[pos] == '\'': inc(pos)
  198. else: break parseLoop
  199. else: break parseLoop
  200. c.bufpos = pos
  201. proc getDollarString(c: var SqlLexer, tok: var Token) =
  202. var pos = c.bufpos + 1
  203. tok.kind = tkDollarQuotedConstant
  204. var tag = "$"
  205. while c.buf[pos] in IdentChars:
  206. add(tag, c.buf[pos])
  207. inc(pos)
  208. if c.buf[pos] == '$': inc(pos)
  209. else:
  210. tok.kind = tkInvalid
  211. return
  212. while true:
  213. case c.buf[pos]
  214. of '\c', '\L':
  215. pos = handleCRLF(c, pos)
  216. add(tok.literal, "\L")
  217. of '\0':
  218. tok.kind = tkInvalid
  219. break
  220. of '$':
  221. inc(pos)
  222. var tag2 = "$"
  223. while c.buf[pos] in IdentChars:
  224. add(tag2, c.buf[pos])
  225. inc(pos)
  226. if c.buf[pos] == '$': inc(pos)
  227. if tag2 == tag: break
  228. add(tok.literal, tag2)
  229. add(tok.literal, '$')
  230. else:
  231. add(tok.literal, c.buf[pos])
  232. inc(pos)
  233. c.bufpos = pos
  234. proc getSymbol(c: var SqlLexer, tok: var Token) =
  235. var pos = c.bufpos
  236. while true:
  237. add(tok.literal, c.buf[pos])
  238. inc(pos)
  239. if c.buf[pos] notin {'a'..'z', 'A'..'Z', '0'..'9', '_', '$',
  240. '\128'..'\255'}:
  241. break
  242. c.bufpos = pos
  243. tok.kind = tkIdentifier
  244. proc getQuotedIdentifier(c: var SqlLexer, tok: var Token, quote = '\"') =
  245. var pos = c.bufpos + 1
  246. tok.kind = tkQuotedIdentifier
  247. while true:
  248. var ch = c.buf[pos]
  249. if ch == quote:
  250. if c.buf[pos+1] == quote:
  251. inc(pos, 2)
  252. add(tok.literal, quote)
  253. else:
  254. inc(pos)
  255. break
  256. elif ch in {'\c', '\L', lexbase.EndOfFile}:
  257. tok.kind = tkInvalid
  258. break
  259. else:
  260. add(tok.literal, ch)
  261. inc(pos)
  262. c.bufpos = pos
  263. proc getBitHexString(c: var SqlLexer, tok: var Token, validChars: set[char]) =
  264. var pos = c.bufpos + 1
  265. block parseLoop:
  266. while true:
  267. while true:
  268. var ch = c.buf[pos]
  269. if ch in validChars:
  270. add(tok.literal, ch)
  271. inc(pos)
  272. elif ch == '\'':
  273. inc(pos)
  274. break
  275. else:
  276. tok.kind = tkInvalid
  277. break parseLoop
  278. c.bufpos = pos
  279. var line = c.lineNumber
  280. skip(c)
  281. if c.lineNumber > line:
  282. # a new line whitespace has been parsed, so we check if the string
  283. # continues after the whitespace:
  284. pos = c.bufpos
  285. if c.buf[pos] == '\'': inc(pos)
  286. else: break parseLoop
  287. else: break parseLoop
  288. c.bufpos = pos
  289. proc getNumeric(c: var SqlLexer, tok: var Token) =
  290. tok.kind = tkInteger
  291. var pos = c.bufpos
  292. while c.buf[pos] in Digits:
  293. add(tok.literal, c.buf[pos])
  294. inc(pos)
  295. if c.buf[pos] == '.':
  296. tok.kind = tkNumeric
  297. add(tok.literal, c.buf[pos])
  298. inc(pos)
  299. while c.buf[pos] in Digits:
  300. add(tok.literal, c.buf[pos])
  301. inc(pos)
  302. if c.buf[pos] in {'E', 'e'}:
  303. tok.kind = tkNumeric
  304. add(tok.literal, c.buf[pos])
  305. inc(pos)
  306. if c.buf[pos] == '+':
  307. inc(pos)
  308. elif c.buf[pos] == '-':
  309. add(tok.literal, c.buf[pos])
  310. inc(pos)
  311. if c.buf[pos] in Digits:
  312. while c.buf[pos] in Digits:
  313. add(tok.literal, c.buf[pos])
  314. inc(pos)
  315. else:
  316. tok.kind = tkInvalid
  317. c.bufpos = pos
  318. proc getOperator(c: var SqlLexer, tok: var Token) =
  319. const operators = {'+', '-', '*', '/', '<', '>', '=', '~', '!', '@', '#', '%',
  320. '^', '&', '|', '`', '?'}
  321. tok.kind = tkOperator
  322. var pos = c.bufpos
  323. var trailingPlusMinus = false
  324. while true:
  325. case c.buf[pos]
  326. of '-':
  327. if c.buf[pos] == '-': break
  328. if not trailingPlusMinus and c.buf[pos+1] notin operators and
  329. tok.literal.len > 0: break
  330. of '/':
  331. if c.buf[pos] == '*': break
  332. of '~', '!', '@', '#', '%', '^', '&', '|', '`', '?':
  333. trailingPlusMinus = true
  334. of '+':
  335. if not trailingPlusMinus and c.buf[pos+1] notin operators and
  336. tok.literal.len > 0: break
  337. of '*', '<', '>', '=': discard
  338. else: break
  339. add(tok.literal, c.buf[pos])
  340. inc(pos)
  341. c.bufpos = pos
  342. proc getTok(c: var SqlLexer, tok: var Token) =
  343. tok.kind = tkInvalid
  344. setLen(tok.literal, 0)
  345. skip(c)
  346. case c.buf[c.bufpos]
  347. of ';':
  348. tok.kind = tkSemicolon
  349. inc(c.bufpos)
  350. add(tok.literal, ';')
  351. of ',':
  352. tok.kind = tkComma
  353. inc(c.bufpos)
  354. add(tok.literal, ',')
  355. of ':':
  356. tok.kind = tkColon
  357. inc(c.bufpos)
  358. add(tok.literal, ':')
  359. of 'e', 'E':
  360. if c.buf[c.bufpos + 1] == '\'':
  361. inc(c.bufpos)
  362. getString(c, tok, tkEscapeConstant)
  363. else:
  364. getSymbol(c, tok)
  365. of 'b', 'B':
  366. if c.buf[c.bufpos + 1] == '\'':
  367. tok.kind = tkBitStringConstant
  368. getBitHexString(c, tok, {'0'..'1'})
  369. else:
  370. getSymbol(c, tok)
  371. of 'x', 'X':
  372. if c.buf[c.bufpos + 1] == '\'':
  373. tok.kind = tkHexStringConstant
  374. getBitHexString(c, tok, {'a'..'f', 'A'..'F', '0'..'9'})
  375. else:
  376. getSymbol(c, tok)
  377. of '$': getDollarString(c, tok)
  378. of '[':
  379. tok.kind = tkBracketLe
  380. inc(c.bufpos)
  381. add(tok.literal, '[')
  382. of ']':
  383. tok.kind = tkBracketRi
  384. inc(c.bufpos)
  385. add(tok.literal, ']')
  386. of '(':
  387. tok.kind = tkParLe
  388. inc(c.bufpos)
  389. add(tok.literal, '(')
  390. of ')':
  391. tok.kind = tkParRi
  392. inc(c.bufpos)
  393. add(tok.literal, ')')
  394. of '.':
  395. if c.buf[c.bufpos + 1] in Digits:
  396. getNumeric(c, tok)
  397. else:
  398. tok.kind = tkDot
  399. inc(c.bufpos)
  400. add(tok.literal, '.')
  401. of '0'..'9': getNumeric(c, tok)
  402. of '\'': getString(c, tok, tkStringConstant)
  403. of '"': getQuotedIdentifier(c, tok, '"')
  404. of '`': getQuotedIdentifier(c, tok, '`')
  405. of lexbase.EndOfFile:
  406. tok.kind = tkEof
  407. tok.literal = "[EOF]"
  408. of 'a', 'c', 'd', 'f'..'w', 'y', 'z', 'A', 'C', 'D', 'F'..'W', 'Y', 'Z', '_',
  409. '\128'..'\255':
  410. getSymbol(c, tok)
  411. of '+', '-', '*', '/', '<', '>', '=', '~', '!', '@', '#', '%',
  412. '^', '&', '|', '?':
  413. getOperator(c, tok)
  414. else:
  415. add(tok.literal, c.buf[c.bufpos])
  416. inc(c.bufpos)
  417. proc errorStr(L: SqlLexer, msg: string): string =
  418. result = "$1($2, $3) Error: $4" % [L.filename, $getLine(L), $getColumn(L), msg]
  419. # ----------------------------- parser ----------------------------------------
  420. # Operator/Element Associativity Description
  421. # . left table/column name separator
  422. # :: left PostgreSQL-style typecast
  423. # [ ] left array element selection
  424. # - right unary minus
  425. # ^ left exponentiation
  426. # * / % left multiplication, division, modulo
  427. # + - left addition, subtraction
  428. # IS IS TRUE, IS FALSE, IS UNKNOWN, IS NULL
  429. # ISNULL test for null
  430. # NOTNULL test for not null
  431. # (any other) left all other native and user-defined oprs
  432. # IN set membership
  433. # BETWEEN range containment
  434. # OVERLAPS time interval overlap
  435. # LIKE ILIKE SIMILAR string pattern matching
  436. # < > less than, greater than
  437. # = right equality, assignment
  438. # NOT right logical negation
  439. # AND left logical conjunction
  440. # OR left logical disjunction
  441. type
  442. SqlNodeKind* = enum ## kind of SQL abstract syntax tree
  443. nkNone,
  444. nkIdent,
  445. nkQuotedIdent,
  446. nkStringLit,
  447. nkBitStringLit,
  448. nkHexStringLit,
  449. nkIntegerLit,
  450. nkNumericLit,
  451. nkPrimaryKey,
  452. nkForeignKey,
  453. nkNotNull,
  454. nkNull,
  455. nkStmtList,
  456. nkDot,
  457. nkDotDot,
  458. nkPrefix,
  459. nkInfix,
  460. nkCall,
  461. nkPrGroup,
  462. nkColumnReference,
  463. nkReferences,
  464. nkDefault,
  465. nkCheck,
  466. nkConstraint,
  467. nkUnique,
  468. nkIdentity,
  469. nkColumnDef, ## name, datatype, constraints
  470. nkInsert,
  471. nkUpdate,
  472. nkDelete,
  473. nkSelect,
  474. nkSelectDistinct,
  475. nkSelectColumns,
  476. nkSelectPair,
  477. nkAsgn,
  478. nkFrom,
  479. nkFromItemPair,
  480. nkGroup,
  481. nkLimit,
  482. nkHaving,
  483. nkOrder,
  484. nkJoin,
  485. nkDesc,
  486. nkUnion,
  487. nkIntersect,
  488. nkExcept,
  489. nkColumnList,
  490. nkValueList,
  491. nkWhere,
  492. nkCreateTable,
  493. nkCreateTableIfNotExists,
  494. nkCreateType,
  495. nkCreateTypeIfNotExists,
  496. nkCreateIndex,
  497. nkCreateIndexIfNotExists,
  498. nkEnumDef
  499. const
  500. LiteralNodes = {
  501. nkIdent, nkQuotedIdent, nkStringLit, nkBitStringLit, nkHexStringLit,
  502. nkIntegerLit, nkNumericLit
  503. }
  504. type
  505. SqlParseError* = object of ValueError ## Invalid SQL encountered
  506. SqlNode* = ref SqlNodeObj ## an SQL abstract syntax tree node
  507. SqlNodeObj* = object ## an SQL abstract syntax tree node
  508. case kind*: SqlNodeKind ## kind of syntax tree
  509. of LiteralNodes:
  510. strVal*: string ## AST leaf: the identifier, numeric literal
  511. ## string literal, etc.
  512. else:
  513. sons*: seq[SqlNode] ## the node's children
  514. SqlParser* = object of SqlLexer ## SQL parser object
  515. tok: Token
  516. proc newNode*(k: SqlNodeKind): SqlNode =
  517. when defined(js): # bug #14117
  518. case k
  519. of LiteralNodes:
  520. result = SqlNode(kind: k, strVal: "")
  521. else:
  522. result = SqlNode(kind: k, sons: @[])
  523. else:
  524. result = SqlNode(kind: k)
  525. proc newNode*(k: SqlNodeKind, s: string): SqlNode =
  526. result = SqlNode(kind: k)
  527. result.strVal = s
  528. proc newNode*(k: SqlNodeKind, sons: seq[SqlNode]): SqlNode =
  529. result = SqlNode(kind: k)
  530. result.sons = sons
  531. proc len*(n: SqlNode): int =
  532. if n.kind in LiteralNodes:
  533. result = 0
  534. else:
  535. result = n.sons.len
  536. proc `[]`*(n: SqlNode; i: int): SqlNode = n.sons[i]
  537. proc `[]`*(n: SqlNode; i: BackwardsIndex): SqlNode = n.sons[n.len - int(i)]
  538. proc add*(father, n: SqlNode) =
  539. add(father.sons, n)
  540. proc getTok(p: var SqlParser) =
  541. getTok(p, p.tok)
  542. proc sqlError(p: SqlParser, msg: string) =
  543. var e: ref SqlParseError
  544. new(e)
  545. e.msg = errorStr(p, msg)
  546. raise e
  547. proc isKeyw(p: SqlParser, keyw: string): bool =
  548. result = p.tok.kind == tkIdentifier and
  549. cmpIgnoreCase(p.tok.literal, keyw) == 0
  550. proc isOpr(p: SqlParser, opr: string): bool =
  551. result = p.tok.kind == tkOperator and
  552. cmpIgnoreCase(p.tok.literal, opr) == 0
  553. proc optKeyw(p: var SqlParser, keyw: string) =
  554. if p.tok.kind == tkIdentifier and cmpIgnoreCase(p.tok.literal, keyw) == 0:
  555. getTok(p)
  556. proc expectIdent(p: SqlParser) =
  557. if p.tok.kind != tkIdentifier and p.tok.kind != tkQuotedIdentifier:
  558. sqlError(p, "identifier expected")
  559. proc expect(p: SqlParser, kind: TokKind) =
  560. if p.tok.kind != kind:
  561. sqlError(p, tokKindToStr[kind] & " expected")
  562. proc eat(p: var SqlParser, kind: TokKind) =
  563. if p.tok.kind == kind:
  564. getTok(p)
  565. else:
  566. sqlError(p, tokKindToStr[kind] & " expected")
  567. proc eat(p: var SqlParser, keyw: string) =
  568. if isKeyw(p, keyw):
  569. getTok(p)
  570. else:
  571. sqlError(p, keyw.toUpperAscii() & " expected")
  572. proc opt(p: var SqlParser, kind: TokKind) =
  573. if p.tok.kind == kind: getTok(p)
  574. proc parseDataType(p: var SqlParser): SqlNode =
  575. if isKeyw(p, "enum"):
  576. result = newNode(nkEnumDef)
  577. getTok(p)
  578. if p.tok.kind == tkParLe:
  579. getTok(p)
  580. result.add(newNode(nkStringLit, p.tok.literal))
  581. getTok(p)
  582. while p.tok.kind == tkComma:
  583. getTok(p)
  584. result.add(newNode(nkStringLit, p.tok.literal))
  585. getTok(p)
  586. eat(p, tkParRi)
  587. else:
  588. expectIdent(p)
  589. result = newNode(nkIdent, p.tok.literal)
  590. getTok(p)
  591. # ignore (12, 13) part:
  592. if p.tok.kind == tkParLe:
  593. getTok(p)
  594. expect(p, tkInteger)
  595. getTok(p)
  596. while p.tok.kind == tkComma:
  597. getTok(p)
  598. expect(p, tkInteger)
  599. getTok(p)
  600. eat(p, tkParRi)
  601. proc getPrecedence(p: SqlParser): int =
  602. if isOpr(p, "*") or isOpr(p, "/") or isOpr(p, "%"):
  603. result = 6
  604. elif isOpr(p, "+") or isOpr(p, "-"):
  605. result = 5
  606. elif isOpr(p, "=") or isOpr(p, "<") or isOpr(p, ">") or isOpr(p, ">=") or
  607. isOpr(p, "<=") or isOpr(p, "<>") or isOpr(p, "!=") or isKeyw(p, "is") or
  608. isKeyw(p, "like") or isKeyw(p, "in"):
  609. result = 4
  610. elif isKeyw(p, "and"):
  611. result = 3
  612. elif isKeyw(p, "or"):
  613. result = 2
  614. elif isKeyw(p, "between"):
  615. result = 1
  616. elif p.tok.kind == tkOperator:
  617. # user-defined operator:
  618. result = 0
  619. else:
  620. result = - 1
  621. proc parseExpr(p: var SqlParser): SqlNode {.gcsafe.}
  622. proc parseSelect(p: var SqlParser): SqlNode {.gcsafe.}
  623. proc identOrLiteral(p: var SqlParser): SqlNode =
  624. case p.tok.kind
  625. of tkQuotedIdentifier:
  626. result = newNode(nkQuotedIdent, p.tok.literal)
  627. getTok(p)
  628. of tkIdentifier:
  629. result = newNode(nkIdent, p.tok.literal)
  630. getTok(p)
  631. of tkStringConstant, tkEscapeConstant, tkDollarQuotedConstant:
  632. result = newNode(nkStringLit, p.tok.literal)
  633. getTok(p)
  634. of tkBitStringConstant:
  635. result = newNode(nkBitStringLit, p.tok.literal)
  636. getTok(p)
  637. of tkHexStringConstant:
  638. result = newNode(nkHexStringLit, p.tok.literal)
  639. getTok(p)
  640. of tkInteger:
  641. result = newNode(nkIntegerLit, p.tok.literal)
  642. getTok(p)
  643. of tkNumeric:
  644. result = newNode(nkNumericLit, p.tok.literal)
  645. getTok(p)
  646. of tkParLe:
  647. getTok(p)
  648. result = newNode(nkPrGroup)
  649. while true:
  650. result.add(parseExpr(p))
  651. if p.tok.kind != tkComma: break
  652. getTok(p)
  653. eat(p, tkParRi)
  654. else:
  655. if p.tok.literal == "*":
  656. result = newNode(nkIdent, p.tok.literal)
  657. getTok(p)
  658. else:
  659. sqlError(p, "expression expected")
  660. getTok(p) # we must consume a token here to prevent endless loops!
  661. proc primary(p: var SqlParser): SqlNode =
  662. if (p.tok.kind == tkOperator and (p.tok.literal == "+" or p.tok.literal ==
  663. "-")) or isKeyw(p, "not"):
  664. result = newNode(nkPrefix)
  665. result.add(newNode(nkIdent, p.tok.literal))
  666. getTok(p)
  667. result.add(primary(p))
  668. return
  669. result = identOrLiteral(p)
  670. while true:
  671. case p.tok.kind
  672. of tkParLe:
  673. var a = result
  674. result = newNode(nkCall)
  675. result.add(a)
  676. getTok(p)
  677. while p.tok.kind != tkParRi:
  678. result.add(parseExpr(p))
  679. if p.tok.kind == tkComma: getTok(p)
  680. else: break
  681. eat(p, tkParRi)
  682. of tkDot:
  683. getTok(p)
  684. var a = result
  685. if p.tok.kind == tkDot:
  686. getTok(p)
  687. result = newNode(nkDotDot)
  688. else:
  689. result = newNode(nkDot)
  690. result.add(a)
  691. if isOpr(p, "*"):
  692. result.add(newNode(nkIdent, "*"))
  693. elif p.tok.kind in {tkIdentifier, tkQuotedIdentifier}:
  694. result.add(newNode(nkIdent, p.tok.literal))
  695. else:
  696. sqlError(p, "identifier expected")
  697. getTok(p)
  698. else: break
  699. proc lowestExprAux(p: var SqlParser, v: var SqlNode, limit: int): int =
  700. var
  701. v2, node, opNode: SqlNode
  702. v = primary(p) # expand while operators have priorities higher than 'limit'
  703. var opPred = getPrecedence(p)
  704. result = opPred
  705. while opPred > limit:
  706. node = newNode(nkInfix)
  707. opNode = newNode(nkIdent, p.tok.literal.toLowerAscii())
  708. getTok(p)
  709. result = lowestExprAux(p, v2, opPred)
  710. node.add(opNode)
  711. node.add(v)
  712. node.add(v2)
  713. v = node
  714. opPred = getPrecedence(p)
  715. proc parseExpr(p: var SqlParser): SqlNode =
  716. discard lowestExprAux(p, result, - 1)
  717. proc parseTableName(p: var SqlParser): SqlNode =
  718. expectIdent(p)
  719. result = primary(p)
  720. proc parseColumnReference(p: var SqlParser): SqlNode =
  721. result = parseTableName(p)
  722. if p.tok.kind == tkParLe:
  723. getTok(p)
  724. var a = result
  725. result = newNode(nkColumnReference)
  726. result.add(a)
  727. result.add(parseTableName(p))
  728. while p.tok.kind == tkComma:
  729. getTok(p)
  730. result.add(parseTableName(p))
  731. eat(p, tkParRi)
  732. proc parseCheck(p: var SqlParser): SqlNode =
  733. getTok(p)
  734. result = newNode(nkCheck)
  735. result.add(parseExpr(p))
  736. proc parseConstraint(p: var SqlParser): SqlNode =
  737. getTok(p)
  738. result = newNode(nkConstraint)
  739. expectIdent(p)
  740. result.add(newNode(nkIdent, p.tok.literal))
  741. getTok(p)
  742. optKeyw(p, "check")
  743. result.add(parseExpr(p))
  744. proc parseParIdentList(p: var SqlParser, father: SqlNode) =
  745. eat(p, tkParLe)
  746. while true:
  747. expectIdent(p)
  748. father.add(newNode(nkIdent, p.tok.literal))
  749. getTok(p)
  750. if p.tok.kind != tkComma: break
  751. getTok(p)
  752. eat(p, tkParRi)
  753. proc parseColumnConstraints(p: var SqlParser, result: SqlNode) =
  754. while true:
  755. if isKeyw(p, "default"):
  756. getTok(p)
  757. var n = newNode(nkDefault)
  758. n.add(parseExpr(p))
  759. result.add(n)
  760. elif isKeyw(p, "references"):
  761. getTok(p)
  762. var n = newNode(nkReferences)
  763. n.add(parseColumnReference(p))
  764. result.add(n)
  765. elif isKeyw(p, "not"):
  766. getTok(p)
  767. eat(p, "null")
  768. result.add(newNode(nkNotNull))
  769. elif isKeyw(p, "null"):
  770. getTok(p)
  771. result.add(newNode(nkNull))
  772. elif isKeyw(p, "identity"):
  773. getTok(p)
  774. result.add(newNode(nkIdentity))
  775. elif isKeyw(p, "primary"):
  776. getTok(p)
  777. eat(p, "key")
  778. result.add(newNode(nkPrimaryKey))
  779. elif isKeyw(p, "check"):
  780. result.add(parseCheck(p))
  781. elif isKeyw(p, "constraint"):
  782. result.add(parseConstraint(p))
  783. elif isKeyw(p, "unique"):
  784. getTok(p)
  785. result.add(newNode(nkUnique))
  786. else:
  787. break
  788. proc parseColumnDef(p: var SqlParser): SqlNode =
  789. expectIdent(p)
  790. result = newNode(nkColumnDef)
  791. result.add(newNode(nkIdent, p.tok.literal))
  792. getTok(p)
  793. result.add(parseDataType(p))
  794. parseColumnConstraints(p, result)
  795. proc parseIfNotExists(p: var SqlParser, k: SqlNodeKind): SqlNode =
  796. getTok(p)
  797. if isKeyw(p, "if"):
  798. getTok(p)
  799. eat(p, "not")
  800. eat(p, "exists")
  801. result = newNode(succ(k))
  802. else:
  803. result = newNode(k)
  804. proc parseTableConstraint(p: var SqlParser): SqlNode =
  805. if isKeyw(p, "primary"):
  806. getTok(p)
  807. eat(p, "key")
  808. result = newNode(nkPrimaryKey)
  809. parseParIdentList(p, result)
  810. elif isKeyw(p, "foreign"):
  811. getTok(p)
  812. eat(p, "key")
  813. result = newNode(nkForeignKey)
  814. parseParIdentList(p, result)
  815. eat(p, "references")
  816. var m = newNode(nkReferences)
  817. m.add(parseColumnReference(p))
  818. result.add(m)
  819. elif isKeyw(p, "unique"):
  820. getTok(p)
  821. eat(p, "key")
  822. result = newNode(nkUnique)
  823. parseParIdentList(p, result)
  824. elif isKeyw(p, "check"):
  825. result = parseCheck(p)
  826. elif isKeyw(p, "constraint"):
  827. result = parseConstraint(p)
  828. else:
  829. sqlError(p, "column definition expected")
  830. proc parseUnique(p: var SqlParser): SqlNode =
  831. result = parseExpr(p)
  832. if result.kind == nkCall: result.kind = nkUnique
  833. proc parseTableDef(p: var SqlParser): SqlNode =
  834. result = parseIfNotExists(p, nkCreateTable)
  835. expectIdent(p)
  836. result.add(newNode(nkIdent, p.tok.literal))
  837. getTok(p)
  838. if p.tok.kind == tkParLe:
  839. getTok(p)
  840. while p.tok.kind != tkParRi:
  841. if isKeyw(p, "constraint"):
  842. result.add parseConstraint(p)
  843. elif isKeyw(p, "primary") or isKeyw(p, "foreign"):
  844. result.add parseTableConstraint(p)
  845. elif isKeyw(p, "unique"):
  846. result.add parseUnique(p)
  847. elif p.tok.kind == tkIdentifier or p.tok.kind == tkQuotedIdentifier:
  848. result.add(parseColumnDef(p))
  849. else:
  850. result.add(parseTableConstraint(p))
  851. if p.tok.kind != tkComma: break
  852. getTok(p)
  853. eat(p, tkParRi)
  854. # skip additional crap after 'create table (...) crap;'
  855. while p.tok.kind notin {tkSemicolon, tkEof}:
  856. getTok(p)
  857. proc parseTypeDef(p: var SqlParser): SqlNode =
  858. result = parseIfNotExists(p, nkCreateType)
  859. expectIdent(p)
  860. result.add(newNode(nkIdent, p.tok.literal))
  861. getTok(p)
  862. eat(p, "as")
  863. result.add(parseDataType(p))
  864. proc parseWhere(p: var SqlParser): SqlNode =
  865. getTok(p)
  866. result = newNode(nkWhere)
  867. result.add(parseExpr(p))
  868. proc parseFromItem(p: var SqlParser): SqlNode =
  869. result = newNode(nkFromItemPair)
  870. if p.tok.kind == tkParLe:
  871. getTok(p)
  872. var select = parseSelect(p)
  873. result.add(select)
  874. eat(p, tkParRi)
  875. else:
  876. result.add(parseExpr(p))
  877. if isKeyw(p, "as"):
  878. getTok(p)
  879. result.add(parseExpr(p))
  880. proc parseIndexDef(p: var SqlParser): SqlNode =
  881. result = parseIfNotExists(p, nkCreateIndex)
  882. if isKeyw(p, "primary"):
  883. getTok(p)
  884. eat(p, "key")
  885. result.add(newNode(nkPrimaryKey))
  886. else:
  887. expectIdent(p)
  888. result.add(newNode(nkIdent, p.tok.literal))
  889. getTok(p)
  890. eat(p, "on")
  891. expectIdent(p)
  892. result.add(newNode(nkIdent, p.tok.literal))
  893. getTok(p)
  894. eat(p, tkParLe)
  895. expectIdent(p)
  896. result.add(newNode(nkIdent, p.tok.literal))
  897. getTok(p)
  898. while p.tok.kind == tkComma:
  899. getTok(p)
  900. expectIdent(p)
  901. result.add(newNode(nkIdent, p.tok.literal))
  902. getTok(p)
  903. eat(p, tkParRi)
  904. proc parseInsert(p: var SqlParser): SqlNode =
  905. getTok(p)
  906. eat(p, "into")
  907. expectIdent(p)
  908. result = newNode(nkInsert)
  909. result.add(newNode(nkIdent, p.tok.literal))
  910. getTok(p)
  911. if p.tok.kind == tkParLe:
  912. var n = newNode(nkColumnList)
  913. parseParIdentList(p, n)
  914. result.add n
  915. else:
  916. result.add(newNode(nkNone))
  917. if isKeyw(p, "default"):
  918. getTok(p)
  919. eat(p, "values")
  920. result.add(newNode(nkDefault))
  921. else:
  922. eat(p, "values")
  923. eat(p, tkParLe)
  924. var n = newNode(nkValueList)
  925. while true:
  926. n.add(parseExpr(p))
  927. if p.tok.kind != tkComma: break
  928. getTok(p)
  929. result.add(n)
  930. eat(p, tkParRi)
  931. proc parseUpdate(p: var SqlParser): SqlNode =
  932. getTok(p)
  933. result = newNode(nkUpdate)
  934. result.add(primary(p))
  935. eat(p, "set")
  936. while true:
  937. var a = newNode(nkAsgn)
  938. expectIdent(p)
  939. a.add(newNode(nkIdent, p.tok.literal))
  940. getTok(p)
  941. if isOpr(p, "="): getTok(p)
  942. else: sqlError(p, "= expected")
  943. a.add(parseExpr(p))
  944. result.add(a)
  945. if p.tok.kind != tkComma: break
  946. getTok(p)
  947. if isKeyw(p, "where"):
  948. result.add(parseWhere(p))
  949. else:
  950. result.add(newNode(nkNone))
  951. proc parseDelete(p: var SqlParser): SqlNode =
  952. getTok(p)
  953. if isOpr(p, "*"):
  954. getTok(p)
  955. result = newNode(nkDelete)
  956. eat(p, "from")
  957. result.add(primary(p))
  958. if isKeyw(p, "where"):
  959. result.add(parseWhere(p))
  960. else:
  961. result.add(newNode(nkNone))
  962. proc parseSelect(p: var SqlParser): SqlNode =
  963. getTok(p)
  964. if isKeyw(p, "distinct"):
  965. getTok(p)
  966. result = newNode(nkSelectDistinct)
  967. elif isKeyw(p, "all"):
  968. getTok(p)
  969. result = newNode(nkSelect)
  970. var a = newNode(nkSelectColumns)
  971. while true:
  972. if isOpr(p, "*"):
  973. a.add(newNode(nkIdent, "*"))
  974. getTok(p)
  975. else:
  976. var pair = newNode(nkSelectPair)
  977. pair.add(parseExpr(p))
  978. a.add(pair)
  979. if isKeyw(p, "as"):
  980. getTok(p)
  981. pair.add(parseExpr(p))
  982. if p.tok.kind != tkComma: break
  983. getTok(p)
  984. result.add(a)
  985. if isKeyw(p, "from"):
  986. var f = newNode(nkFrom)
  987. while true:
  988. getTok(p)
  989. f.add(parseFromItem(p))
  990. if p.tok.kind != tkComma: break
  991. result.add(f)
  992. if isKeyw(p, "where"):
  993. result.add(parseWhere(p))
  994. if isKeyw(p, "group"):
  995. getTok(p)
  996. eat(p, "by")
  997. var g = newNode(nkGroup)
  998. while true:
  999. g.add(parseExpr(p))
  1000. if p.tok.kind != tkComma: break
  1001. getTok(p)
  1002. result.add(g)
  1003. if isKeyw(p, "order"):
  1004. getTok(p)
  1005. eat(p, "by")
  1006. var n = newNode(nkOrder)
  1007. while true:
  1008. var e = parseExpr(p)
  1009. if isKeyw(p, "asc"):
  1010. getTok(p) # is default
  1011. elif isKeyw(p, "desc"):
  1012. getTok(p)
  1013. var x = newNode(nkDesc)
  1014. x.add(e)
  1015. e = x
  1016. n.add(e)
  1017. if p.tok.kind != tkComma: break
  1018. getTok(p)
  1019. result.add(n)
  1020. if isKeyw(p, "having"):
  1021. var h = newNode(nkHaving)
  1022. while true:
  1023. getTok(p)
  1024. h.add(parseExpr(p))
  1025. if p.tok.kind != tkComma: break
  1026. result.add(h)
  1027. if isKeyw(p, "union"):
  1028. result.add(newNode(nkUnion))
  1029. getTok(p)
  1030. elif isKeyw(p, "intersect"):
  1031. result.add(newNode(nkIntersect))
  1032. getTok(p)
  1033. elif isKeyw(p, "except"):
  1034. result.add(newNode(nkExcept))
  1035. getTok(p)
  1036. if isKeyw(p, "join") or isKeyw(p, "inner") or isKeyw(p, "outer") or isKeyw(p, "cross"):
  1037. var join = newNode(nkJoin)
  1038. result.add(join)
  1039. if isKeyw(p, "join"):
  1040. join.add(newNode(nkIdent, ""))
  1041. getTok(p)
  1042. else:
  1043. join.add(newNode(nkIdent, p.tok.literal.toLowerAscii()))
  1044. getTok(p)
  1045. eat(p, "join")
  1046. join.add(parseFromItem(p))
  1047. eat(p, "on")
  1048. join.add(parseExpr(p))
  1049. if isKeyw(p, "limit"):
  1050. getTok(p)
  1051. var l = newNode(nkLimit)
  1052. l.add(parseExpr(p))
  1053. result.add(l)
  1054. proc parseStmt(p: var SqlParser; parent: SqlNode) =
  1055. if isKeyw(p, "create"):
  1056. getTok(p)
  1057. optKeyw(p, "cached")
  1058. optKeyw(p, "memory")
  1059. optKeyw(p, "temp")
  1060. optKeyw(p, "global")
  1061. optKeyw(p, "local")
  1062. optKeyw(p, "temporary")
  1063. optKeyw(p, "unique")
  1064. optKeyw(p, "hash")
  1065. if isKeyw(p, "table"):
  1066. parent.add parseTableDef(p)
  1067. elif isKeyw(p, "type"):
  1068. parent.add parseTypeDef(p)
  1069. elif isKeyw(p, "index"):
  1070. parent.add parseIndexDef(p)
  1071. else:
  1072. sqlError(p, "TABLE expected")
  1073. elif isKeyw(p, "insert"):
  1074. parent.add parseInsert(p)
  1075. elif isKeyw(p, "update"):
  1076. parent.add parseUpdate(p)
  1077. elif isKeyw(p, "delete"):
  1078. parent.add parseDelete(p)
  1079. elif isKeyw(p, "select"):
  1080. parent.add parseSelect(p)
  1081. elif isKeyw(p, "begin"):
  1082. getTok(p)
  1083. else:
  1084. sqlError(p, "SELECT, CREATE, UPDATE or DELETE expected")
  1085. proc parse(p: var SqlParser): SqlNode =
  1086. ## parses the content of `p`'s input stream and returns the SQL AST.
  1087. ## Syntax errors raise an `SqlParseError` exception.
  1088. result = newNode(nkStmtList)
  1089. while p.tok.kind != tkEof:
  1090. parseStmt(p, result)
  1091. if p.tok.kind == tkEof:
  1092. break
  1093. eat(p, tkSemicolon)
  1094. proc close(p: var SqlParser) =
  1095. ## closes the parser `p`. The associated input stream is closed too.
  1096. close(SqlLexer(p))
  1097. type
  1098. SqlWriter = object
  1099. indent: int
  1100. upperCase: bool
  1101. buffer: string
  1102. proc add(s: var SqlWriter, thing: char) =
  1103. s.buffer.add(thing)
  1104. proc prepareAdd(s: var SqlWriter) {.inline.} =
  1105. if s.buffer.len > 0 and s.buffer[^1] notin {' ', '\L', '(', '.'}:
  1106. s.buffer.add(" ")
  1107. proc add(s: var SqlWriter, thing: string) =
  1108. s.prepareAdd
  1109. s.buffer.add(thing)
  1110. proc addKeyw(s: var SqlWriter, thing: string) =
  1111. var keyw = thing
  1112. if s.upperCase:
  1113. keyw = keyw.toUpperAscii()
  1114. s.add(keyw)
  1115. proc addIden(s: var SqlWriter, thing: string) =
  1116. var iden = thing
  1117. if iden.toLowerAscii() in reservedKeywords:
  1118. iden = '"' & iden & '"'
  1119. s.add(iden)
  1120. proc ra(n: SqlNode, s: var SqlWriter) {.gcsafe.}
  1121. proc rs(n: SqlNode, s: var SqlWriter, prefix = "(", suffix = ")", sep = ", ") =
  1122. if n.len > 0:
  1123. s.add(prefix)
  1124. for i in 0 .. n.len-1:
  1125. if i > 0: s.add(sep)
  1126. ra(n.sons[i], s)
  1127. s.add(suffix)
  1128. proc addMulti(s: var SqlWriter, n: SqlNode, sep = ',') =
  1129. if n.len > 0:
  1130. for i in 0 .. n.len-1:
  1131. if i > 0: s.add(sep)
  1132. ra(n.sons[i], s)
  1133. proc addMulti(s: var SqlWriter, n: SqlNode, sep = ',', prefix, suffix: char) =
  1134. if n.len > 0:
  1135. s.add(prefix)
  1136. for i in 0 .. n.len-1:
  1137. if i > 0: s.add(sep)
  1138. ra(n.sons[i], s)
  1139. s.add(suffix)
  1140. proc quoted(s: string): string =
  1141. "\"" & replace(s, "\"", "\"\"") & "\""
  1142. func escape(result: var string; s: string) =
  1143. result.add('\'')
  1144. for c in items(s):
  1145. case c
  1146. of '\0'..'\31':
  1147. result.add("\\x")
  1148. result.add(toHex(ord(c), 2))
  1149. of '\'': result.add("''")
  1150. else: result.add(c)
  1151. result.add('\'')
  1152. proc ra(n: SqlNode, s: var SqlWriter) =
  1153. if n == nil: return
  1154. case n.kind
  1155. of nkNone: discard
  1156. of nkIdent:
  1157. if allCharsInSet(n.strVal, {'\33'..'\127'}):
  1158. s.add(n.strVal)
  1159. else:
  1160. s.add(quoted(n.strVal))
  1161. of nkQuotedIdent:
  1162. s.add(quoted(n.strVal))
  1163. of nkStringLit:
  1164. s.prepareAdd
  1165. s.buffer.escape(n.strVal)
  1166. of nkBitStringLit:
  1167. s.add("b'" & n.strVal & "'")
  1168. of nkHexStringLit:
  1169. s.add("x'" & n.strVal & "'")
  1170. of nkIntegerLit, nkNumericLit:
  1171. s.add(n.strVal)
  1172. of nkPrimaryKey:
  1173. s.addKeyw("primary key")
  1174. rs(n, s)
  1175. of nkForeignKey:
  1176. s.addKeyw("foreign key")
  1177. rs(n, s)
  1178. of nkNotNull:
  1179. s.addKeyw("not null")
  1180. of nkNull:
  1181. s.addKeyw("null")
  1182. of nkDot:
  1183. ra(n.sons[0], s)
  1184. s.add('.')
  1185. ra(n.sons[1], s)
  1186. of nkDotDot:
  1187. ra(n.sons[0], s)
  1188. s.add(". .")
  1189. ra(n.sons[1], s)
  1190. of nkPrefix:
  1191. ra(n.sons[0], s)
  1192. s.add(' ')
  1193. ra(n.sons[1], s)
  1194. of nkInfix:
  1195. ra(n.sons[1], s)
  1196. s.add(' ')
  1197. ra(n.sons[0], s)
  1198. s.add(' ')
  1199. ra(n.sons[2], s)
  1200. of nkCall, nkColumnReference:
  1201. ra(n.sons[0], s)
  1202. s.add('(')
  1203. for i in 1..n.len-1:
  1204. if i > 1: s.add(',')
  1205. ra(n.sons[i], s)
  1206. s.add(')')
  1207. of nkPrGroup:
  1208. s.add('(')
  1209. s.addMulti(n)
  1210. s.add(')')
  1211. of nkReferences:
  1212. s.addKeyw("references")
  1213. ra(n.sons[0], s)
  1214. of nkDefault:
  1215. s.addKeyw("default")
  1216. ra(n.sons[0], s)
  1217. of nkCheck:
  1218. s.addKeyw("check")
  1219. ra(n.sons[0], s)
  1220. of nkConstraint:
  1221. s.addKeyw("constraint")
  1222. ra(n.sons[0], s)
  1223. s.addKeyw("check")
  1224. ra(n.sons[1], s)
  1225. of nkUnique:
  1226. s.addKeyw("unique")
  1227. rs(n, s)
  1228. of nkIdentity:
  1229. s.addKeyw("identity")
  1230. of nkColumnDef:
  1231. rs(n, s, "", "", " ")
  1232. of nkStmtList:
  1233. for i in 0..n.len-1:
  1234. ra(n.sons[i], s)
  1235. s.add(';')
  1236. of nkInsert:
  1237. assert n.len == 3
  1238. s.addKeyw("insert into")
  1239. ra(n.sons[0], s)
  1240. s.add(' ')
  1241. ra(n.sons[1], s)
  1242. if n.sons[2].kind == nkDefault:
  1243. s.addKeyw("default values")
  1244. else:
  1245. ra(n.sons[2], s)
  1246. of nkUpdate:
  1247. s.addKeyw("update")
  1248. ra(n.sons[0], s)
  1249. s.addKeyw("set")
  1250. var L = n.len
  1251. for i in 1 .. L-2:
  1252. if i > 1: s.add(", ")
  1253. var it = n.sons[i]
  1254. assert it.kind == nkAsgn
  1255. ra(it, s)
  1256. ra(n.sons[L-1], s)
  1257. of nkDelete:
  1258. s.addKeyw("delete from")
  1259. ra(n.sons[0], s)
  1260. ra(n.sons[1], s)
  1261. of nkSelect, nkSelectDistinct:
  1262. s.addKeyw("select")
  1263. if n.kind == nkSelectDistinct:
  1264. s.addKeyw("distinct")
  1265. for i in 0 ..< n.len:
  1266. ra(n.sons[i], s)
  1267. of nkSelectColumns:
  1268. for i, column in n.sons:
  1269. if i > 0: s.add(',')
  1270. ra(column, s)
  1271. of nkSelectPair:
  1272. ra(n.sons[0], s)
  1273. if n.sons.len == 2:
  1274. s.addKeyw("as")
  1275. ra(n.sons[1], s)
  1276. of nkFromItemPair:
  1277. if n.sons[0].kind in {nkIdent, nkQuotedIdent}:
  1278. ra(n.sons[0], s)
  1279. else:
  1280. assert n.sons[0].kind == nkSelect
  1281. s.add('(')
  1282. ra(n.sons[0], s)
  1283. s.add(')')
  1284. if n.sons.len == 2:
  1285. s.addKeyw("as")
  1286. ra(n.sons[1], s)
  1287. of nkAsgn:
  1288. ra(n.sons[0], s)
  1289. s.add(" = ")
  1290. ra(n.sons[1], s)
  1291. of nkFrom:
  1292. s.addKeyw("from")
  1293. s.addMulti(n)
  1294. of nkGroup:
  1295. s.addKeyw("group by")
  1296. s.addMulti(n)
  1297. of nkLimit:
  1298. s.addKeyw("limit")
  1299. s.addMulti(n)
  1300. of nkHaving:
  1301. s.addKeyw("having")
  1302. s.addMulti(n)
  1303. of nkOrder:
  1304. s.addKeyw("order by")
  1305. s.addMulti(n)
  1306. of nkJoin:
  1307. var joinType = n.sons[0].strVal
  1308. if joinType == "":
  1309. joinType = "join"
  1310. else:
  1311. joinType &= " " & "join"
  1312. s.addKeyw(joinType)
  1313. ra(n.sons[1], s)
  1314. s.addKeyw("on")
  1315. ra(n.sons[2], s)
  1316. of nkDesc:
  1317. ra(n.sons[0], s)
  1318. s.addKeyw("desc")
  1319. of nkUnion:
  1320. s.addKeyw("union")
  1321. of nkIntersect:
  1322. s.addKeyw("intersect")
  1323. of nkExcept:
  1324. s.addKeyw("except")
  1325. of nkColumnList:
  1326. rs(n, s)
  1327. of nkValueList:
  1328. s.addKeyw("values")
  1329. rs(n, s)
  1330. of nkWhere:
  1331. s.addKeyw("where")
  1332. ra(n.sons[0], s)
  1333. of nkCreateTable, nkCreateTableIfNotExists:
  1334. s.addKeyw("create table")
  1335. if n.kind == nkCreateTableIfNotExists:
  1336. s.addKeyw("if not exists")
  1337. ra(n.sons[0], s)
  1338. s.add('(')
  1339. for i in 1..n.len-1:
  1340. if i > 1: s.add(',')
  1341. ra(n.sons[i], s)
  1342. s.add(");")
  1343. of nkCreateType, nkCreateTypeIfNotExists:
  1344. s.addKeyw("create type")
  1345. if n.kind == nkCreateTypeIfNotExists:
  1346. s.addKeyw("if not exists")
  1347. ra(n.sons[0], s)
  1348. s.addKeyw("as")
  1349. ra(n.sons[1], s)
  1350. of nkCreateIndex, nkCreateIndexIfNotExists:
  1351. s.addKeyw("create index")
  1352. if n.kind == nkCreateIndexIfNotExists:
  1353. s.addKeyw("if not exists")
  1354. ra(n.sons[0], s)
  1355. s.addKeyw("on")
  1356. ra(n.sons[1], s)
  1357. s.add('(')
  1358. for i in 2..n.len-1:
  1359. if i > 2: s.add(", ")
  1360. ra(n.sons[i], s)
  1361. s.add(");")
  1362. of nkEnumDef:
  1363. s.addKeyw("enum")
  1364. rs(n, s)
  1365. proc renderSql*(n: SqlNode, upperCase = false): string =
  1366. ## Converts an SQL abstract syntax tree to its string representation.
  1367. var s: SqlWriter
  1368. s.buffer = ""
  1369. s.upperCase = upperCase
  1370. ra(n, s)
  1371. return s.buffer
  1372. proc `$`*(n: SqlNode): string =
  1373. ## an alias for `renderSql`.
  1374. renderSql(n)
  1375. proc treeReprAux(s: SqlNode, level: int, result: var string) =
  1376. result.add('\n')
  1377. for i in 0 ..< level: result.add(" ")
  1378. result.add($s.kind)
  1379. if s.kind in LiteralNodes:
  1380. result.add(' ')
  1381. result.add(s.strVal)
  1382. else:
  1383. for son in s.sons:
  1384. treeReprAux(son, level + 1, result)
  1385. proc treeRepr*(s: SqlNode): string =
  1386. result = newStringOfCap(128)
  1387. treeReprAux(s, 0, result)
  1388. import streams
  1389. proc open(L: var SqlLexer, input: Stream, filename: string) =
  1390. lexbase.open(L, input)
  1391. L.filename = filename
  1392. proc open(p: var SqlParser, input: Stream, filename: string) =
  1393. ## opens the parser `p` and assigns the input stream `input` to it.
  1394. ## `filename` is only used for error messages.
  1395. open(SqlLexer(p), input, filename)
  1396. p.tok.kind = tkInvalid
  1397. p.tok.literal = ""
  1398. getTok(p)
  1399. proc parseSql*(input: Stream, filename: string): SqlNode =
  1400. ## parses the SQL from `input` into an AST and returns the AST.
  1401. ## `filename` is only used for error messages.
  1402. ## Syntax errors raise an `SqlParseError` exception.
  1403. var p: SqlParser
  1404. open(p, input, filename)
  1405. try:
  1406. result = parse(p)
  1407. finally:
  1408. close(p)
  1409. proc parseSql*(input: string, filename = ""): SqlNode =
  1410. ## parses the SQL from `input` into an AST and returns the AST.
  1411. ## `filename` is only used for error messages.
  1412. ## Syntax errors raise an `SqlParseError` exception.
  1413. parseSql(newStringStream(input), "")