parsesql.nim 38 KB

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