parsesql.nim 35 KB

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