Skip to content

Commit

Permalink
started using reserved word tables
Browse files Browse the repository at this point in the history
  • Loading branch information
rmculpepper committed Mar 21, 2016
1 parent 9bb7a69 commit 51bceb8
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 34 deletions.
39 changes: 32 additions & 7 deletions private/emit.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#lang racket/base
(require racket/string
racket/include
racket/class
racket/list
(rename-in racket/match [match-define defmatch])
Expand All @@ -15,6 +16,16 @@
;; So we can use map with method names
(define-syntax-rule (map f xs) (for/list ([x (in-list xs)]) (f x)))

;; reserved-word-table : (Hash String => (Listof Symbol))
(define reserved-word-table
(include "keywords.rktd"))

;; reserved-word? : Symbol Symbol [(U '-type '-function #f)] -> Boolean
(define (reserved-word? sym dialect [ctx #f])
(define key (string-downcase (symbol->string sym)))
(define vals (hash-ref reserved-word-table key null))
(and (memq dialect vals) (not (memq ctx vals))))

;; ----------------------------------------

(define emit-sql%
Expand Down Expand Up @@ -84,7 +95,7 @@
(define/public (emit-column c)
(match c
[(column name type not-null?)
(J (emit-ident name) " " (emit-scalar-expr type)
(J (emit-ident name) " " (emit-type type)
(if not-null? " NOT NULL" ""))]))

(define/public (emit-constraint c)
Expand Down Expand Up @@ -361,7 +372,7 @@
[(scalar:app op args)
(define formatter
(cond [(name-ast? op)
(fun-op (emit-name op))]
(fun-op (emit-function-name op))]
[(op-formatter op)
=> values]
[else
Expand Down Expand Up @@ -405,18 +416,32 @@

;; ----------------------------------------

(define/public (emit-name n)
(define/public (emit-name n [ctx #f])
(match n
[(qname qual id)
(J (emit-name qual) "." (emit-ident id))]
[_ (emit-ident n)]))
[_ (emit-ident n ctx)]))

(define/public (emit-type type)
(if (name-ast? type)
(emit-name type '-type)
(emit-scalar-expr type)))
(define/public (emit-function-name n)
(emit-name n '-function))

(define/public (emit-ident id)
(define/public (emit-ident id [ctx #f])
(match id
[(id:quoted (? string? s))
(J "\"" (regexp-replace* #rx"\"" s "\"\"") "\"")]
(J-double-quote s)]
[(id:normal (? symbol? s))
(symbol->string s)]))
(define this-dialect 'sql92)
(cond [(reserved-word? s this-dialect ctx)
;; Need dialect case-folding convention, quotation convention
(J-double-quote (symbol->string s))]
[else (symbol->string s)])]))

(define/public (J-double-quote s)
(J "\"" (regexp-replace* #rx"\"" s "\"\"") "\""))

(define/public (emit-ident-commalist ids)
(J-join (for/list ([id (in-list ids)]) (emit-ident id)) ", "))
Expand Down
61 changes: 34 additions & 27 deletions sql.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,21 @@ is generated in quoted form.
]

The following examples are all equivalent to the SQL qualified name
@tt{table.name}, which by case-folding is also equivalent to
@tt{TABLE.NAME} and @tt{taBLE.naME}:
@tt{mytable.mycolumn}, which by case-folding is also equivalent to
@tt{MYTABLE.MYCOLUMN} and @tt{MyTable.MyColumn}:

@racketblock[
table.name
taBLE.naME
(Name: table NAME)
(Name: (Ident: table) (Ident: NAME))
mytable.mycolumn
MyTable.MyColumn
(Name: mytable MYCOLUMN)
(Name: (Ident: mytable) (Ident: MYNAME))
]

The following example is equivalent to the SQL qualified name
@tt{"Table"."Name"}:
@tt{"MyTable"."MyName"}:

@racketblock[
(Name: (Ident: "Table") (Ident: "Name"))
(Name: (Ident: "MyTable") (Ident: "MyName"))
]

@deftogether[[
Expand All @@ -101,11 +101,18 @@ Quasiquotation macro, predicate, and code generator, respectively, for
@svar[name].

@examples[#:eval the-eval
(name-ast->string (name-qq table.name))
(name-ast->string (name-qq (Name: table NAME)))
(name-ast->string (name-qq (Name: (Ident: "taBLE") (Ident: "naME"))))
(name-ast->string (name-qq mytable.mycolumn))
(name-ast->string (name-qq (Name: mytable MYCOLUMN)))
(name-ast->string (name-qq (Name: (Ident: "MyTable") (Ident: "MyColumn"))))
]
}

Reserved words are automatically quoted (after case-folding, if
necessary):
@interaction[#:eval the-eval
(name-ast->string (name-qq table.mycolumn))
(name-ast->string (name-qq select.insert))
(name-ast->string (name-qq (Name: (Ident: select) (Ident: insert))))
]}

@deftogether[[
@defform[(ident-qq ident)]
Expand Down Expand Up @@ -244,8 +251,8 @@ expressions'', in a mild abuse of syntax.
@racket[\|\|] or as @racket[||]; the latter reads as the empty symbol.

@racketblock[
(|| last ", " first) (code:comment "last || ', ' || first")
(\|\| last ", " first) (code:comment "last || ', ' || first")
(|| lname ", " fname) (code:comment "lname || ', ' || fname")
(\|\| lname ", " fname) (code:comment "lname || ', ' || fname")
]}

@item{Any identifier consisting of only characters in
Expand Down Expand Up @@ -325,7 +332,7 @@ Quasiquotation macro, predicate, and code generator, respectively, for
@svar[scalar-expr].

@examples[#:eval the-eval
(scalar-expr-ast->string (scalar-expr-qq table.column))
(scalar-expr-ast->string (scalar-expr-qq mytable.mycolumn))
(scalar-expr-ast->string (scalar-expr-qq 42))
(scalar-expr-ast->string (scalar-expr-qq "Salutations"))
(scalar-expr-ast->string (scalar-expr-qq "a 'tricky' string"))
Expand All @@ -334,9 +341,9 @@ Quasiquotation macro, predicate, and code generator, respectively, for
(scalar-expr-ast->string (scalar-expr-qq (coalesce x y z)))
(scalar-expr-ast->string (scalar-expr-qq (cast "2015-03-15" DATE)))
(scalar-expr-ast->string (scalar-expr-qq (extract YEAR dob)))
(scalar-expr-ast->string (scalar-expr-qq (is-null table.column)))
(scalar-expr-ast->string (scalar-expr-qq (is-null mytable.mycolumn)))
(scalar-expr-ast->string (scalar-expr-qq (like ph_num "555-____")))
(scalar-expr-ast->string (scalar-expr-qq (|| last ", " first)))
(scalar-expr-ast->string (scalar-expr-qq (|| lname ", " fname)))
]
}

Expand Down Expand Up @@ -539,9 +546,9 @@ Constructor macro, predicate, and code generator for @svar[statement].

@examples[#:eval the-eval
(statement-ast->string
(statement-qq (select a b c #:from table #:where (> a 10))))
(statement-qq (select a b c #:from mytable #:where (> a 10))))
(statement-ast->string
(statement-qq (insert #:into table #:set [a 1] [b 2] [c 3])))
(statement-qq (insert #:into mytable #:set [a 1] [b 2] [c 3])))
]
}

Expand Down Expand Up @@ -628,9 +635,9 @@ respectively, except that the macro name is recognized by its
identifier binding rather than symbolically.

@examples[#:eval the-eval
(select a b c #:from table #:where (> a 10))
(insert #:into table #:set [a 1] [b 2] [c 3])
(insert #:into table
(select a b c #:from mytable #:where (> a 10))
(insert #:into mytable #:set [a 1] [b 2] [c 3])
(insert #:into mytable
#:from (select a b c
#:from other_table
#:where (is-not-null d)))
Expand Down Expand Up @@ -686,13 +693,13 @@ Note: Due to limitations in the @racketmodname[db] library,
the same statement.

@examples[#:eval the-eval
(select a #:from table #:where (= b ?))
(select a #:from mytable #:where (= b ?))
]

The resulting statement can be used with parameters thus:

@racketblock[
(query-value c (select a #:from table #:where (= b ?)) 10)
(query-value c (select a #:from mytable #:where (= b ?)) 10)
]

Using the @lit{unquote} form eliminates the need to keep track of
Expand All @@ -702,13 +709,13 @@ to SQL code containing placeholders.

@examples[#:eval the-eval
(define b-param 10)
(select a #:from table #:where (= b ,b-param))
(select a #:from mytable #:where (= b ,b-param))
]

The resulting statement must be called without additional parameters:

@racketblock[
(query-value c (select a #:from table #:where (= b ,b-param)))
(query-value c (select a #:from mytable #:where (= b ,b-param)))
]

Note that placeholder syntax varies between SQL dialects. We can see
Expand All @@ -717,7 +724,7 @@ the code a statement produces for a specific dialect by setting the

@interaction[#:eval the-eval
(parameterize ((current-sql-dialect 'postgresql))
(print (select a #:from table #:where (= b ,b-param))))
(print (select a #:from mytable #:where (= b ,b-param))))
]

@; ============================================================
Expand Down

0 comments on commit 51bceb8

Please sign in to comment.