parsesql.nim 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524
  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", "offset", "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. nkOffset,
  483. nkHaving,
  484. nkOrder,
  485. nkJoin,
  486. nkDesc,
  487. nkUnion,
  488. nkIntersect,
  489. nkExcept,
  490. nkColumnList,
  491. nkValueList,
  492. nkWhere,
  493. nkCreateTable,
  494. nkCreateTableIfNotExists,
  495. nkCreateType,
  496. nkCreateTypeIfNotExists,
  497. nkCreateIndex,
  498. nkCreateIndexIfNotExists,
  499. nkEnumDef
  500. const
  501. LiteralNodes = {
  502. nkIdent, nkQuotedIdent, nkStringLit, nkBitStringLit, nkHexStringLit,
  503. nkIntegerLit, nkNumericLit
  504. }
  505. type
  506. SqlParseError* = object of ValueError ## Invalid SQL encountered
  507. SqlNode* = ref SqlNodeObj ## an SQL abstract syntax tree node
  508. SqlNodeObj* = object ## an SQL abstract syntax tree node
  509. case kind*: SqlNodeKind ## kind of syntax tree
  510. of LiteralNodes:
  511. strVal*: string ## AST leaf: the identifier, numeric literal
  512. ## string literal, etc.
  513. else:
  514. sons*: seq[SqlNode] ## the node's children
  515. SqlParser* = object of SqlLexer ## SQL parser object
  516. tok: Token
  517. proc newNode*(k: SqlNodeKind): SqlNode =
  518. when defined(js): # bug #14117
  519. case k
  520. of LiteralNodes:
  521. result = SqlNode(kind: k, strVal: "")
  522. else:
  523. result = SqlNode(kind: k, sons: @[])
  524. else:
  525. result = SqlNode(kind: k)
  526. proc newNode*(k: SqlNodeKind, s: string): SqlNode =
  527. result = SqlNode(kind: k)
  528. result.strVal = s
  529. proc newNode*(k: SqlNodeKind, sons: seq[SqlNode]): SqlNode =
  530. result = SqlNode(kind: k)
  531. result.sons = sons
  532. proc len*(n: SqlNode): int =
  533. if n.kind in LiteralNodes:
  534. result = 0
  535. else:
  536. result = n.sons.len
  537. proc `[]`*(n: SqlNode; i: int): SqlNode = n.sons[i]
  538. proc `[]`*(n: SqlNode; i: BackwardsIndex): SqlNode = n.sons[n.len - int(i)]
  539. proc add*(father, n: SqlNode) =
  540. add(father.sons, n)
  541. proc getTok(p: var SqlParser) =
  542. getTok(p, p.tok)
  543. proc sqlError(p: SqlParser, msg: string) =
  544. var e: ref SqlParseError
  545. new(e)
  546. e.msg = errorStr(p, msg)
  547. raise e
  548. proc isKeyw(p: SqlParser, keyw: string): bool =
  549. result = p.tok.kind == tkIdentifier and
  550. cmpIgnoreCase(p.tok.literal, keyw) == 0
  551. proc isOpr(p: SqlParser, opr: string): bool =
  552. result = p.tok.kind == tkOperator and
  553. cmpIgnoreCase(p.tok.literal, opr) == 0
  554. proc optKeyw(p: var SqlParser, keyw: string) =
  555. if p.tok.kind == tkIdentifier and cmpIgnoreCase(p.tok.literal, keyw) == 0:
  556. getTok(p)
  557. proc expectIdent(p: SqlParser) =
  558. if p.tok.kind != tkIdentifier and p.tok.kind != tkQuotedIdentifier:
  559. sqlError(p, "identifier expected")
  560. proc expect(p: SqlParser, kind: TokKind) =
  561. if p.tok.kind != kind:
  562. sqlError(p, tokKindToStr[kind] & " expected")
  563. proc eat(p: var SqlParser, kind: TokKind) =
  564. if p.tok.kind == kind:
  565. getTok(p)
  566. else:
  567. sqlError(p, tokKindToStr[kind] & " expected")
  568. proc eat(p: var SqlParser, keyw: string) =
  569. if isKeyw(p, keyw):
  570. getTok(p)
  571. else:
  572. sqlError(p, keyw.toUpperAscii() & " expected")
  573. proc opt(p: var SqlParser, kind: TokKind) =
  574. if p.tok.kind == kind: getTok(p)
  575. proc parseDataType(p: var SqlParser): SqlNode =
  576. if isKeyw(p, "enum"):
  577. result = newNode(nkEnumDef)
  578. getTok(p)
  579. if p.tok.kind == tkParLe:
  580. getTok(p)
  581. result.add(newNode(nkStringLit, p.tok.literal))
  582. getTok(p)
  583. while p.tok.kind == tkComma:
  584. getTok(p)
  585. result.add(newNode(nkStringLit, p.tok.literal))
  586. getTok(p)
  587. eat(p, tkParRi)
  588. else:
  589. expectIdent(p)
  590. result = newNode(nkIdent, p.tok.literal)
  591. getTok(p)
  592. # ignore (12, 13) part:
  593. if p.tok.kind == tkParLe:
  594. getTok(p)
  595. expect(p, tkInteger)
  596. getTok(p)
  597. while p.tok.kind == tkComma:
  598. getTok(p)
  599. expect(p, tkInteger)
  600. getTok(p)
  601. eat(p, tkParRi)
  602. proc getPrecedence(p: SqlParser): int =
  603. if isOpr(p, "*") or isOpr(p, "/") or isOpr(p, "%"):
  604. result = 6
  605. elif isOpr(p, "+") or isOpr(p, "-"):
  606. result = 5
  607. elif isOpr(p, "=") or isOpr(p, "<") or isOpr(p, ">") or isOpr(p, ">=") or
  608. isOpr(p, "<=") or isOpr(p, "<>") or isOpr(p, "!=") or isKeyw(p, "is") or
  609. isKeyw(p, "like") or isKeyw(p, "in"):
  610. result = 4
  611. elif isKeyw(p, "and"):
  612. result = 3
  613. elif isKeyw(p, "or"):
  614. result = 2
  615. elif isKeyw(p, "between"):
  616. result = 1
  617. elif p.tok.kind == tkOperator:
  618. # user-defined operator:
  619. result = 0
  620. else:
  621. result = - 1
  622. proc parseExpr(p: var SqlParser): SqlNode {.gcsafe.}
  623. proc parseSelect(p: var SqlParser): SqlNode {.gcsafe.}
  624. proc identOrLiteral(p: var SqlParser): SqlNode =
  625. case p.tok.kind
  626. of tkQuotedIdentifier:
  627. result = newNode(nkQuotedIdent, p.tok.literal)
  628. getTok(p)
  629. of tkIdentifier:
  630. result = newNode(nkIdent, p.tok.literal)
  631. getTok(p)
  632. of tkStringConstant, tkEscapeConstant, tkDollarQuotedConstant:
  633. result = newNode(nkStringLit, p.tok.literal)
  634. getTok(p)
  635. of tkBitStringConstant:
  636. result = newNode(nkBitStringLit, p.tok.literal)
  637. getTok(p)
  638. of tkHexStringConstant:
  639. result = newNode(nkHexStringLit, p.tok.literal)
  640. getTok(p)
  641. of tkInteger:
  642. result = newNode(nkIntegerLit, p.tok.literal)
  643. getTok(p)
  644. of tkNumeric:
  645. result = newNode(nkNumericLit, p.tok.literal)
  646. getTok(p)
  647. of tkParLe:
  648. getTok(p)
  649. result = newNode(nkPrGroup)
  650. while true:
  651. result.add(parseExpr(p))
  652. if p.tok.kind != tkComma: break
  653. getTok(p)
  654. eat(p, tkParRi)
  655. else:
  656. if p.tok.literal == "*":
  657. result = newNode(nkIdent, p.tok.literal)
  658. getTok(p)
  659. else:
  660. sqlError(p, "expression expected")
  661. getTok(p) # we must consume a token here to prevent endless loops!
  662. proc primary(p: var SqlParser): SqlNode =
  663. if (p.tok.kind == tkOperator and (p.tok.literal == "+" or p.tok.literal ==
  664. "-")) or isKeyw(p, "not"):
  665. result = newNode(nkPrefix)
  666. result.add(newNode(nkIdent, p.tok.literal))
  667. getTok(p)
  668. result.add(primary(p))
  669. return
  670. result = identOrLiteral(p)
  671. while true:
  672. case p.tok.kind
  673. of tkParLe:
  674. var a = result
  675. result = newNode(nkCall)
  676. result.add(a)
  677. getTok(p)
  678. while p.tok.kind != tkParRi:
  679. result.add(parseExpr(p))
  680. if p.tok.kind == tkComma: getTok(p)
  681. else: break
  682. eat(p, tkParRi)
  683. of tkDot:
  684. getTok(p)
  685. var a = result
  686. if p.tok.kind == tkDot:
  687. getTok(p)
  688. result = newNode(nkDotDot)
  689. else:
  690. result = newNode(nkDot)
  691. result.add(a)
  692. if isOpr(p, "*"):
  693. result.add(newNode(nkIdent, "*"))
  694. elif p.tok.kind in {tkIdentifier, tkQuotedIdentifier}:
  695. result.add(newNode(nkIdent, p.tok.literal))
  696. else:
  697. sqlError(p, "identifier expected")
  698. getTok(p)
  699. else: break
  700. proc lowestExprAux(p: var SqlParser, v: var SqlNode, limit: int): int =
  701. var
  702. v2, node, opNode: SqlNode
  703. v = primary(p) # expand while operators have priorities higher than 'limit'
  704. var opPred = getPrecedence(p)
  705. result = opPred
  706. while opPred > limit:
  707. node = newNode(nkInfix)
  708. opNode = newNode(nkIdent, p.tok.literal.toLowerAscii())
  709. getTok(p)
  710. result = lowestExprAux(p, v2, opPred)
  711. node.add(opNode)
  712. node.add(v)
  713. node.add(v2)
  714. v = node
  715. opPred = getPrecedence(p)
  716. proc parseExpr(p: var SqlParser): SqlNode =
  717. discard lowestExprAux(p, result, - 1)
  718. proc parseTableName(p: var SqlParser): SqlNode =
  719. expectIdent(p)
  720. result = primary(p)
  721. proc parseColumnReference(p: var SqlParser): SqlNode =
  722. result = parseTableName(p)
  723. if p.tok.kind == tkParLe:
  724. getTok(p)
  725. var a = result
  726. result = newNode(nkColumnReference)
  727. result.add(a)
  728. result.add(parseTableName(p))
  729. while p.tok.kind == tkComma:
  730. getTok(p)
  731. result.add(parseTableName(p))
  732. eat(p, tkParRi)
  733. proc parseCheck(p: var SqlParser): SqlNode =
  734. getTok(p)
  735. result = newNode(nkCheck)
  736. result.add(parseExpr(p))
  737. proc parseConstraint(p: var SqlParser): SqlNode =
  738. getTok(p)
  739. result = newNode(nkConstraint)
  740. expectIdent(p)
  741. result.add(newNode(nkIdent, p.tok.literal))
  742. getTok(p)
  743. optKeyw(p, "check")
  744. result.add(parseExpr(p))
  745. proc parseParIdentList(p: var SqlParser, father: SqlNode) =
  746. eat(p, tkParLe)
  747. while true:
  748. expectIdent(p)
  749. father.add(newNode(nkIdent, p.tok.literal))
  750. getTok(p)
  751. if p.tok.kind != tkComma: break
  752. getTok(p)
  753. eat(p, tkParRi)
  754. proc parseColumnConstraints(p: var SqlParser, result: SqlNode) =
  755. while true:
  756. if isKeyw(p, "default"):
  757. getTok(p)
  758. var n = newNode(nkDefault)
  759. n.add(parseExpr(p))
  760. result.add(n)
  761. elif isKeyw(p, "references"):
  762. getTok(p)
  763. var n = newNode(nkReferences)
  764. n.add(parseColumnReference(p))
  765. result.add(n)
  766. elif isKeyw(p, "not"):
  767. getTok(p)
  768. eat(p, "null")
  769. result.add(newNode(nkNotNull))
  770. elif isKeyw(p, "null"):
  771. getTok(p)
  772. result.add(newNode(nkNull))
  773. elif isKeyw(p, "identity"):
  774. getTok(p)
  775. result.add(newNode(nkIdentity))
  776. elif isKeyw(p, "primary"):
  777. getTok(p)
  778. eat(p, "key")
  779. result.add(newNode(nkPrimaryKey))
  780. elif isKeyw(p, "check"):
  781. result.add(parseCheck(p))
  782. elif isKeyw(p, "constraint"):
  783. result.add(parseConstraint(p))
  784. elif isKeyw(p, "unique"):
  785. getTok(p)
  786. result.add(newNode(nkUnique))
  787. else:
  788. break
  789. proc parseColumnDef(p: var SqlParser): SqlNode =
  790. expectIdent(p)
  791. result = newNode(nkColumnDef)
  792. result.add(newNode(nkIdent, p.tok.literal))
  793. getTok(p)
  794. result.add(parseDataType(p))
  795. parseColumnConstraints(p, result)
  796. proc parseIfNotExists(p: var SqlParser, k: SqlNodeKind): SqlNode =
  797. getTok(p)
  798. if isKeyw(p, "if"):
  799. getTok(p)
  800. eat(p, "not")
  801. eat(p, "exists")
  802. result = newNode(succ(k))
  803. else:
  804. result = newNode(k)
  805. proc parseTableConstraint(p: var SqlParser): SqlNode =
  806. if isKeyw(p, "primary"):
  807. getTok(p)
  808. eat(p, "key")
  809. result = newNode(nkPrimaryKey)
  810. parseParIdentList(p, result)
  811. elif isKeyw(p, "foreign"):
  812. getTok(p)
  813. eat(p, "key")
  814. result = newNode(nkForeignKey)
  815. parseParIdentList(p, result)
  816. eat(p, "references")
  817. var m = newNode(nkReferences)
  818. m.add(parseColumnReference(p))
  819. result.add(m)
  820. elif isKeyw(p, "unique"):
  821. getTok(p)
  822. eat(p, "key")
  823. result = newNode(nkUnique)
  824. parseParIdentList(p, result)
  825. elif isKeyw(p, "check"):
  826. result = parseCheck(p)
  827. elif isKeyw(p, "constraint"):
  828. result = parseConstraint(p)
  829. else:
  830. sqlError(p, "column definition expected")
  831. proc parseUnique(p: var SqlParser): SqlNode =
  832. result = parseExpr(p)
  833. if result.kind == nkCall: result.kind = nkUnique
  834. proc parseTableDef(p: var SqlParser): SqlNode =
  835. result = parseIfNotExists(p, nkCreateTable)
  836. expectIdent(p)
  837. result.add(newNode(nkIdent, p.tok.literal))
  838. getTok(p)
  839. if p.tok.kind == tkParLe:
  840. getTok(p)
  841. while p.tok.kind != tkParRi:
  842. if isKeyw(p, "constraint"):
  843. result.add parseConstraint(p)
  844. elif isKeyw(p, "primary") or isKeyw(p, "foreign"):
  845. result.add parseTableConstraint(p)
  846. elif isKeyw(p, "unique"):
  847. result.add parseUnique(p)
  848. elif p.tok.kind == tkIdentifier or p.tok.kind == tkQuotedIdentifier:
  849. result.add(parseColumnDef(p))
  850. else:
  851. result.add(parseTableConstraint(p))
  852. if p.tok.kind != tkComma: break
  853. getTok(p)
  854. eat(p, tkParRi)
  855. # skip additional crap after 'create table (...) crap;'
  856. while p.tok.kind notin {tkSemicolon, tkEof}:
  857. getTok(p)
  858. proc parseTypeDef(p: var SqlParser): SqlNode =
  859. result = parseIfNotExists(p, nkCreateType)
  860. expectIdent(p)
  861. result.add(newNode(nkIdent, p.tok.literal))
  862. getTok(p)
  863. eat(p, "as")
  864. result.add(parseDataType(p))
  865. proc parseWhere(p: var SqlParser): SqlNode =
  866. getTok(p)
  867. result = newNode(nkWhere)
  868. result.add(parseExpr(p))
  869. proc parseFromItem(p: var SqlParser): SqlNode =
  870. result = newNode(nkFromItemPair)
  871. if p.tok.kind == tkParLe:
  872. getTok(p)
  873. var select = parseSelect(p)
  874. result.add(select)
  875. eat(p, tkParRi)
  876. else:
  877. result.add(parseExpr(p))
  878. if isKeyw(p, "as"):
  879. getTok(p)
  880. result.add(parseExpr(p))
  881. proc parseIndexDef(p: var SqlParser): SqlNode =
  882. result = parseIfNotExists(p, nkCreateIndex)
  883. if isKeyw(p, "primary"):
  884. getTok(p)
  885. eat(p, "key")
  886. result.add(newNode(nkPrimaryKey))
  887. else:
  888. expectIdent(p)
  889. result.add(newNode(nkIdent, p.tok.literal))
  890. getTok(p)
  891. eat(p, "on")
  892. expectIdent(p)
  893. result.add(newNode(nkIdent, p.tok.literal))
  894. getTok(p)
  895. eat(p, tkParLe)
  896. expectIdent(p)
  897. result.add(newNode(nkIdent, p.tok.literal))
  898. getTok(p)
  899. while p.tok.kind == tkComma:
  900. getTok(p)
  901. expectIdent(p)
  902. result.add(newNode(nkIdent, p.tok.literal))
  903. getTok(p)
  904. eat(p, tkParRi)
  905. proc parseInsert(p: var SqlParser): SqlNode =
  906. getTok(p)
  907. eat(p, "into")
  908. expectIdent(p)
  909. result = newNode(nkInsert)
  910. result.add(newNode(nkIdent, p.tok.literal))
  911. getTok(p)
  912. if p.tok.kind == tkParLe:
  913. var n = newNode(nkColumnList)
  914. parseParIdentList(p, n)
  915. result.add n
  916. else:
  917. result.add(newNode(nkNone))
  918. if isKeyw(p, "default"):
  919. getTok(p)
  920. eat(p, "values")
  921. result.add(newNode(nkDefault))
  922. else:
  923. eat(p, "values")
  924. eat(p, tkParLe)
  925. var n = newNode(nkValueList)
  926. while true:
  927. n.add(parseExpr(p))
  928. if p.tok.kind != tkComma: break
  929. getTok(p)
  930. result.add(n)
  931. eat(p, tkParRi)
  932. proc parseUpdate(p: var SqlParser): SqlNode =
  933. getTok(p)
  934. result = newNode(nkUpdate)
  935. result.add(primary(p))
  936. eat(p, "set")
  937. while true:
  938. var a = newNode(nkAsgn)
  939. expectIdent(p)
  940. a.add(newNode(nkIdent, p.tok.literal))
  941. getTok(p)
  942. if isOpr(p, "="): getTok(p)
  943. else: sqlError(p, "= expected")
  944. a.add(parseExpr(p))
  945. result.add(a)
  946. if p.tok.kind != tkComma: break
  947. getTok(p)
  948. if isKeyw(p, "where"):
  949. result.add(parseWhere(p))
  950. else:
  951. result.add(newNode(nkNone))
  952. proc parseDelete(p: var SqlParser): SqlNode =
  953. getTok(p)
  954. if isOpr(p, "*"):
  955. getTok(p)
  956. result = newNode(nkDelete)
  957. eat(p, "from")
  958. result.add(primary(p))
  959. if isKeyw(p, "where"):
  960. result.add(parseWhere(p))
  961. else:
  962. result.add(newNode(nkNone))
  963. proc parseSelect(p: var SqlParser): SqlNode =
  964. getTok(p)
  965. if isKeyw(p, "distinct"):
  966. getTok(p)
  967. result = newNode(nkSelectDistinct)
  968. elif isKeyw(p, "all"):
  969. getTok(p)
  970. result = newNode(nkSelect)
  971. var a = newNode(nkSelectColumns)
  972. while true:
  973. if isOpr(p, "*"):
  974. a.add(newNode(nkIdent, "*"))
  975. getTok(p)
  976. else:
  977. var pair = newNode(nkSelectPair)
  978. pair.add(parseExpr(p))
  979. a.add(pair)
  980. if isKeyw(p, "as"):
  981. getTok(p)
  982. pair.add(parseExpr(p))
  983. if p.tok.kind != tkComma: break
  984. getTok(p)
  985. result.add(a)
  986. if isKeyw(p, "from"):
  987. var f = newNode(nkFrom)
  988. while true:
  989. getTok(p)
  990. f.add(parseFromItem(p))
  991. if p.tok.kind != tkComma: break
  992. result.add(f)
  993. if isKeyw(p, "where"):
  994. result.add(parseWhere(p))
  995. if isKeyw(p, "group"):
  996. getTok(p)
  997. eat(p, "by")
  998. var g = newNode(nkGroup)
  999. while true:
  1000. g.add(parseExpr(p))
  1001. if p.tok.kind != tkComma: break
  1002. getTok(p)
  1003. result.add(g)
  1004. if isKeyw(p, "order"):
  1005. getTok(p)
  1006. eat(p, "by")
  1007. var n = newNode(nkOrder)
  1008. while true:
  1009. var e = parseExpr(p)
  1010. if isKeyw(p, "asc"):
  1011. getTok(p) # is default
  1012. elif isKeyw(p, "desc"):
  1013. getTok(p)
  1014. var x = newNode(nkDesc)
  1015. x.add(e)
  1016. e = x
  1017. n.add(e)
  1018. if p.tok.kind != tkComma: break
  1019. getTok(p)
  1020. result.add(n)
  1021. if isKeyw(p, "having"):
  1022. var h = newNode(nkHaving)
  1023. while true:
  1024. getTok(p)
  1025. h.add(parseExpr(p))
  1026. if p.tok.kind != tkComma: break
  1027. result.add(h)
  1028. if isKeyw(p, "union"):
  1029. result.add(newNode(nkUnion))
  1030. getTok(p)
  1031. elif isKeyw(p, "intersect"):
  1032. result.add(newNode(nkIntersect))
  1033. getTok(p)
  1034. elif isKeyw(p, "except"):
  1035. result.add(newNode(nkExcept))
  1036. getTok(p)
  1037. if isKeyw(p, "join") or isKeyw(p, "inner") or isKeyw(p, "outer") or isKeyw(p, "cross"):
  1038. var join = newNode(nkJoin)
  1039. result.add(join)
  1040. if isKeyw(p, "join"):
  1041. join.add(newNode(nkIdent, ""))
  1042. getTok(p)
  1043. else:
  1044. join.add(newNode(nkIdent, p.tok.literal.toLowerAscii()))
  1045. getTok(p)
  1046. eat(p, "join")
  1047. join.add(parseFromItem(p))
  1048. eat(p, "on")
  1049. join.add(parseExpr(p))
  1050. if isKeyw(p, "limit"):
  1051. getTok(p)
  1052. var l = newNode(nkLimit)
  1053. l.add(parseExpr(p))
  1054. result.add(l)
  1055. if isKeyw(p, "offset"):
  1056. getTok(p)
  1057. var o = newNode(nkOffset)
  1058. o.add(parseExpr(p))
  1059. result.add(o)
  1060. proc parseStmt(p: var SqlParser; parent: SqlNode) =
  1061. if isKeyw(p, "create"):
  1062. getTok(p)
  1063. optKeyw(p, "cached")
  1064. optKeyw(p, "memory")
  1065. optKeyw(p, "temp")
  1066. optKeyw(p, "global")
  1067. optKeyw(p, "local")
  1068. optKeyw(p, "temporary")
  1069. optKeyw(p, "unique")
  1070. optKeyw(p, "hash")
  1071. if isKeyw(p, "table"):
  1072. parent.add parseTableDef(p)
  1073. elif isKeyw(p, "type"):
  1074. parent.add parseTypeDef(p)
  1075. elif isKeyw(p, "index"):
  1076. parent.add parseIndexDef(p)
  1077. else:
  1078. sqlError(p, "TABLE expected")
  1079. elif isKeyw(p, "insert"):
  1080. parent.add parseInsert(p)
  1081. elif isKeyw(p, "update"):
  1082. parent.add parseUpdate(p)
  1083. elif isKeyw(p, "delete"):
  1084. parent.add parseDelete(p)
  1085. elif isKeyw(p, "select"):
  1086. parent.add parseSelect(p)
  1087. elif isKeyw(p, "begin"):
  1088. getTok(p)
  1089. else:
  1090. sqlError(p, "SELECT, CREATE, UPDATE or DELETE expected")
  1091. proc parse(p: var SqlParser): SqlNode =
  1092. ## parses the content of `p`'s input stream and returns the SQL AST.
  1093. ## Syntax errors raise an `SqlParseError` exception.
  1094. result = newNode(nkStmtList)
  1095. while p.tok.kind != tkEof:
  1096. parseStmt(p, result)
  1097. if p.tok.kind == tkEof:
  1098. break
  1099. eat(p, tkSemicolon)
  1100. proc close(p: var SqlParser) =
  1101. ## closes the parser `p`. The associated input stream is closed too.
  1102. close(SqlLexer(p))
  1103. type
  1104. SqlWriter = object
  1105. indent: int
  1106. upperCase: bool
  1107. buffer: string
  1108. proc add(s: var SqlWriter, thing: char) =
  1109. s.buffer.add(thing)
  1110. proc prepareAdd(s: var SqlWriter) {.inline.} =
  1111. if s.buffer.len > 0 and s.buffer[^1] notin {' ', '\L', '(', '.'}:
  1112. s.buffer.add(" ")
  1113. proc add(s: var SqlWriter, thing: string) =
  1114. s.prepareAdd
  1115. s.buffer.add(thing)
  1116. proc addKeyw(s: var SqlWriter, thing: string) =
  1117. var keyw = thing
  1118. if s.upperCase:
  1119. keyw = keyw.toUpperAscii()
  1120. s.add(keyw)
  1121. proc addIden(s: var SqlWriter, thing: string) =
  1122. var iden = thing
  1123. if iden.toLowerAscii() in reservedKeywords:
  1124. iden = '"' & iden & '"'
  1125. s.add(iden)
  1126. proc ra(n: SqlNode, s: var SqlWriter) {.gcsafe.}
  1127. proc rs(n: SqlNode, s: var SqlWriter, prefix = "(", suffix = ")", sep = ", ") =
  1128. if n.len > 0:
  1129. s.add(prefix)
  1130. for i in 0 .. n.len-1:
  1131. if i > 0: s.add(sep)
  1132. ra(n.sons[i], s)
  1133. s.add(suffix)
  1134. proc addMulti(s: var SqlWriter, n: SqlNode, sep = ',') =
  1135. if n.len > 0:
  1136. for i in 0 .. n.len-1:
  1137. if i > 0: s.add(sep)
  1138. ra(n.sons[i], s)
  1139. proc addMulti(s: var SqlWriter, n: SqlNode, sep = ',', prefix, suffix: char) =
  1140. if n.len > 0:
  1141. s.add(prefix)
  1142. for i in 0 .. n.len-1:
  1143. if i > 0: s.add(sep)
  1144. ra(n.sons[i], s)
  1145. s.add(suffix)
  1146. proc quoted(s: string): string =
  1147. "\"" & replace(s, "\"", "\"\"") & "\""
  1148. func escape(result: var string; s: string) =
  1149. result.add('\'')
  1150. for c in items(s):
  1151. case c
  1152. of '\0'..'\31':
  1153. result.add("\\x")
  1154. result.add(toHex(ord(c), 2))
  1155. of '\'': result.add("''")
  1156. else: result.add(c)
  1157. result.add('\'')
  1158. proc ra(n: SqlNode, s: var SqlWriter) =
  1159. if n == nil: return
  1160. case n.kind
  1161. of nkNone: discard
  1162. of nkIdent:
  1163. if allCharsInSet(n.strVal, {'\33'..'\127'}):
  1164. s.add(n.strVal)
  1165. else:
  1166. s.add(quoted(n.strVal))
  1167. of nkQuotedIdent:
  1168. s.add(quoted(n.strVal))
  1169. of nkStringLit:
  1170. s.prepareAdd
  1171. s.buffer.escape(n.strVal)
  1172. of nkBitStringLit:
  1173. s.add("b'" & n.strVal & "'")
  1174. of nkHexStringLit:
  1175. s.add("x'" & n.strVal & "'")
  1176. of nkIntegerLit, nkNumericLit:
  1177. s.add(n.strVal)
  1178. of nkPrimaryKey:
  1179. s.addKeyw("primary key")
  1180. rs(n, s)
  1181. of nkForeignKey:
  1182. s.addKeyw("foreign key")
  1183. rs(n, s)
  1184. of nkNotNull:
  1185. s.addKeyw("not null")
  1186. of nkNull:
  1187. s.addKeyw("null")
  1188. of nkDot:
  1189. ra(n.sons[0], s)
  1190. s.add('.')
  1191. ra(n.sons[1], s)
  1192. of nkDotDot:
  1193. ra(n.sons[0], s)
  1194. s.add(". .")
  1195. ra(n.sons[1], s)
  1196. of nkPrefix:
  1197. ra(n.sons[0], s)
  1198. s.add(' ')
  1199. ra(n.sons[1], s)
  1200. of nkInfix:
  1201. ra(n.sons[1], s)
  1202. s.add(' ')
  1203. ra(n.sons[0], s)
  1204. s.add(' ')
  1205. ra(n.sons[2], s)
  1206. of nkCall, nkColumnReference:
  1207. ra(n.sons[0], s)
  1208. s.add('(')
  1209. for i in 1..n.len-1:
  1210. if i > 1: s.add(',')
  1211. ra(n.sons[i], s)
  1212. s.add(')')
  1213. of nkPrGroup:
  1214. s.add('(')
  1215. s.addMulti(n)
  1216. s.add(')')
  1217. of nkReferences:
  1218. s.addKeyw("references")
  1219. ra(n.sons[0], s)
  1220. of nkDefault:
  1221. s.addKeyw("default")
  1222. ra(n.sons[0], s)
  1223. of nkCheck:
  1224. s.addKeyw("check")
  1225. ra(n.sons[0], s)
  1226. of nkConstraint:
  1227. s.addKeyw("constraint")
  1228. ra(n.sons[0], s)
  1229. s.addKeyw("check")
  1230. ra(n.sons[1], s)
  1231. of nkUnique:
  1232. s.addKeyw("unique")
  1233. rs(n, s)
  1234. of nkIdentity:
  1235. s.addKeyw("identity")
  1236. of nkColumnDef:
  1237. rs(n, s, "", "", " ")
  1238. of nkStmtList:
  1239. for i in 0..n.len-1:
  1240. ra(n.sons[i], s)
  1241. s.add(';')
  1242. of nkInsert:
  1243. assert n.len == 3
  1244. s.addKeyw("insert into")
  1245. ra(n.sons[0], s)
  1246. s.add(' ')
  1247. ra(n.sons[1], s)
  1248. if n.sons[2].kind == nkDefault:
  1249. s.addKeyw("default values")
  1250. else:
  1251. ra(n.sons[2], s)
  1252. of nkUpdate:
  1253. s.addKeyw("update")
  1254. ra(n.sons[0], s)
  1255. s.addKeyw("set")
  1256. var L = n.len
  1257. for i in 1 .. L-2:
  1258. if i > 1: s.add(", ")
  1259. var it = n.sons[i]
  1260. assert it.kind == nkAsgn
  1261. ra(it, s)
  1262. ra(n.sons[L-1], s)
  1263. of nkDelete:
  1264. s.addKeyw("delete from")
  1265. ra(n.sons[0], s)
  1266. ra(n.sons[1], s)
  1267. of nkSelect, nkSelectDistinct:
  1268. s.addKeyw("select")
  1269. if n.kind == nkSelectDistinct:
  1270. s.addKeyw("distinct")
  1271. for i in 0 ..< n.len:
  1272. ra(n.sons[i], s)
  1273. of nkSelectColumns:
  1274. for i, column in n.sons:
  1275. if i > 0: s.add(',')
  1276. ra(column, s)
  1277. of nkSelectPair:
  1278. ra(n.sons[0], s)
  1279. if n.sons.len == 2:
  1280. s.addKeyw("as")
  1281. ra(n.sons[1], s)
  1282. of nkFromItemPair:
  1283. if n.sons[0].kind in {nkIdent, nkQuotedIdent}:
  1284. ra(n.sons[0], s)
  1285. else:
  1286. assert n.sons[0].kind == nkSelect
  1287. s.add('(')
  1288. ra(n.sons[0], s)
  1289. s.add(')')
  1290. if n.sons.len == 2:
  1291. s.addKeyw("as")
  1292. ra(n.sons[1], s)
  1293. of nkAsgn:
  1294. ra(n.sons[0], s)
  1295. s.add(" = ")
  1296. ra(n.sons[1], s)
  1297. of nkFrom:
  1298. s.addKeyw("from")
  1299. s.addMulti(n)
  1300. of nkGroup:
  1301. s.addKeyw("group by")
  1302. s.addMulti(n)
  1303. of nkLimit:
  1304. s.addKeyw("limit")
  1305. s.addMulti(n)
  1306. of nkOffset:
  1307. s.addKeyw("offset")
  1308. s.addMulti(n)
  1309. of nkHaving:
  1310. s.addKeyw("having")
  1311. s.addMulti(n)
  1312. of nkOrder:
  1313. s.addKeyw("order by")
  1314. s.addMulti(n)
  1315. of nkJoin:
  1316. var joinType = n.sons[0].strVal
  1317. if joinType == "":
  1318. joinType = "join"
  1319. else:
  1320. joinType &= " " & "join"
  1321. s.addKeyw(joinType)
  1322. ra(n.sons[1], s)
  1323. s.addKeyw("on")
  1324. ra(n.sons[2], s)
  1325. of nkDesc:
  1326. ra(n.sons[0], s)
  1327. s.addKeyw("desc")
  1328. of nkUnion:
  1329. s.addKeyw("union")
  1330. of nkIntersect:
  1331. s.addKeyw("intersect")
  1332. of nkExcept:
  1333. s.addKeyw("except")
  1334. of nkColumnList:
  1335. rs(n, s)
  1336. of nkValueList:
  1337. s.addKeyw("values")
  1338. rs(n, s)
  1339. of nkWhere:
  1340. s.addKeyw("where")
  1341. ra(n.sons[0], s)
  1342. of nkCreateTable, nkCreateTableIfNotExists:
  1343. s.addKeyw("create table")
  1344. if n.kind == nkCreateTableIfNotExists:
  1345. s.addKeyw("if not exists")
  1346. ra(n.sons[0], s)
  1347. s.add('(')
  1348. for i in 1..n.len-1:
  1349. if i > 1: s.add(',')
  1350. ra(n.sons[i], s)
  1351. s.add(");")
  1352. of nkCreateType, nkCreateTypeIfNotExists:
  1353. s.addKeyw("create type")
  1354. if n.kind == nkCreateTypeIfNotExists:
  1355. s.addKeyw("if not exists")
  1356. ra(n.sons[0], s)
  1357. s.addKeyw("as")
  1358. ra(n.sons[1], s)
  1359. of nkCreateIndex, nkCreateIndexIfNotExists:
  1360. s.addKeyw("create index")
  1361. if n.kind == nkCreateIndexIfNotExists:
  1362. s.addKeyw("if not exists")
  1363. ra(n.sons[0], s)
  1364. s.addKeyw("on")
  1365. ra(n.sons[1], s)
  1366. s.add('(')
  1367. for i in 2..n.len-1:
  1368. if i > 2: s.add(", ")
  1369. ra(n.sons[i], s)
  1370. s.add(");")
  1371. of nkEnumDef:
  1372. s.addKeyw("enum")
  1373. rs(n, s)
  1374. proc renderSql*(n: SqlNode, upperCase = false): string =
  1375. ## Converts an SQL abstract syntax tree to its string representation.
  1376. var s: SqlWriter
  1377. s.buffer = ""
  1378. s.upperCase = upperCase
  1379. ra(n, s)
  1380. return s.buffer
  1381. proc `$`*(n: SqlNode): string =
  1382. ## an alias for `renderSql`.
  1383. renderSql(n)
  1384. proc treeReprAux(s: SqlNode, level: int, result: var string) =
  1385. result.add('\n')
  1386. for i in 0 ..< level: result.add(" ")
  1387. result.add($s.kind)
  1388. if s.kind in LiteralNodes:
  1389. result.add(' ')
  1390. result.add(s.strVal)
  1391. else:
  1392. for son in s.sons:
  1393. treeReprAux(son, level + 1, result)
  1394. proc treeRepr*(s: SqlNode): string =
  1395. result = newStringOfCap(128)
  1396. treeReprAux(s, 0, result)
  1397. import streams
  1398. proc open(L: var SqlLexer, input: Stream, filename: string) =
  1399. lexbase.open(L, input)
  1400. L.filename = filename
  1401. proc open(p: var SqlParser, input: Stream, filename: string) =
  1402. ## opens the parser `p` and assigns the input stream `input` to it.
  1403. ## `filename` is only used for error messages.
  1404. open(SqlLexer(p), input, filename)
  1405. p.tok.kind = tkInvalid
  1406. p.tok.literal = ""
  1407. getTok(p)
  1408. proc parseSql*(input: Stream, filename: string): SqlNode =
  1409. ## parses the SQL from `input` into an AST and returns the AST.
  1410. ## `filename` is only used for error messages.
  1411. ## Syntax errors raise an `SqlParseError` exception.
  1412. var p: SqlParser
  1413. open(p, input, filename)
  1414. try:
  1415. result = parse(p)
  1416. finally:
  1417. close(p)
  1418. proc parseSql*(input: string, filename = ""): SqlNode =
  1419. ## parses the SQL from `input` into an AST and returns the AST.
  1420. ## `filename` is only used for error messages.
  1421. ## Syntax errors raise an `SqlParseError` exception.
  1422. parseSql(newStringStream(input), "")