3 (defvar *compiled-classes
* (make-hash-table))
5 (defvar *invalid-column-names
* nil
)
6 (defparameter *psql-invalid-col-names
* '(end))
8 (defun change-invalid-column-names (name)
9 (declare (special *invalid-column-names
*))
10 #+foo
(format t
"> ~a~%" name
)
11 (if (member name
*invalid-column-names
*)
12 (intern (concatenate 'string
(symbol-name name
) "0"))
15 ;; preliminary sql parser
18 (defparameter keywords
'(create drop if exists table index primary key not null default unique auto_increment enum set
))
19 (defparameter types
'(int unsigned longtext float double decimal varchar smallint char text blob longblob tinyint
))
21 (defun string->symbol
(str &optional
(pkg *package
*))
22 (intern (string-upcase str
) pkg
))
24 (declaim (special *sql-lexer-line
*))
26 (deflexer make-sql-lexer
27 ("[0-9]+([.][0-9]+([Ee][0-9]+)?)"
28 (return (values 'float-number
(num %
0))))
30 (return (values 'fixnum
(int %
0))))
31 ("[:alpha:][a-zA-Z0-9_]*"
32 (return (let ((symb (string->symbol %
0)))
34 ((member symb keywords
) (values symb symb
))
35 ((member symb types
) (values 'type symb
))
36 (t (values 'name %
0))))))
38 (return (values 'name
(string-trim "`" %
0))))
40 (return (values 'string
(string-trim "'" %
0))))
44 (return (let ((symb (intern %
0)))
47 (when (eq (elt %
0 0) #\Newline
)
48 (incf *sql-lexer-line
*))))
51 (define-parser *sql-parser
*
53 (:terminals
(fixnum auto_increment enum set float-number engine charset string
54 name type not null default create drop if exists table index view primary key unique
59 (stmt stmts
#'(lambda (a b
)
63 (expr |;|
#'(lambda (a b
) (car a
)))
64 (|;|
#'(lambda (x) nil
)))
68 (ignore #'(lambda (x) nil
)))
71 (default #'(lambda (x) "default"))
72 (name #'(lambda (x) x
)))
75 (create table name |
(| defs |
)| props
#'(lambda (&rest lst
)
78 :components
(fifth lst
)))))
87 (auto_increment |
=| number
)
91 (def #'(lambda (a) a
))
92 (def |
,| defs
#'(lambda (a b c
)
100 (key-def1 #'(lambda (x) x
))
101 (primary key-def1
#'(lambda (a b
) b
))
102 (unique key-def1
#'(lambda (a b
)
103 (cons b
'(:unique t
) ))))
106 (key |
(| idx-fields |
)|
#'(lambda (&rest lst
)
109 :fields
(third lst
))))
110 (key symb |
(| idx-fields |
)|
#'(lambda (&rest lst
)
113 :fields
(fourth lst
)))))
116 (idx-field #'(lambda (a) a
))
117 (idx-field |
,| idx-fields
#'(lambda (a b c
) (cons a c
))))
121 (symb |
(| number |
)|
#'(lambda (a b c d
) (list a c
))))
124 (symb type-def
#'(lambda (a b
) (list
127 (symb type-def opts
#'(lambda (a b c
) (list
135 (opt opts
#'(lambda (a b
) (cons a b
))))
154 (type-expr type-expr
))
157 (type #'(lambda (a) a
))
158 (enum-set |
(| strings |
)|
#'(lambda (a b c d
)
160 (type |
(| fixnum |
)|
#'(lambda (a b c d
)
168 (string |
,| strings
#'(lambda (a b c
) (cons a c
))))
170 ;; Ignore other statments
184 (defun lispname (str)
185 (cl-ppcre:regex-replace-all
"[ _]"
186 (cl-ppcre:regex-replace-all
"([a-z])([A-Z])" str
"\\1-\\2")
190 (defun test-parser ()
191 (parse-with-lexer (make-sql-lexer "drop table foo; create table foo (bar unsigned int not null, type varchar(30)); ;") *sql-parser
*))
193 (defun convert-type (node)
196 ((rfind-if #'(lambda (x)
197 (member x
'(int smallint
))) node
) 'integer
)
200 ((rfind-if #'(lambda (x)
201 (member x
'(float double
))) node
) 'float
)
204 ((rfind-if #'(lambda (x)
205 (member x
'(char varchar
))) node
) (list 'string
(second (car node
))))
208 (defun compile-field (node)
209 (let* ((name (lispname (getf node
:name
)))
210 (options (getf node
:options
))
212 (string->symbol name
)
213 :type
(convert-type (getf node
:type
))
214 :column
(change-invalid-column-names (string->symbol
(getf node
:name
)))
215 :initarg
(intern (string-upcase name
) :keyword
))))
217 (when (member '(primary key
) options
:test
#'equal
)
219 (nconc field-def
'(:db-kind
:key
))))
222 (defun compile-create-table (node)
223 (let ((class-name (string->symbol
(lispname (getf node
:name
)))))
224 (declare (special *compiled-classes
))
225 (setf (gethash class-name
*compiled-classes
*) (getf node
:name
))
226 `(clsql:def-view-class
,class-name
()
227 ,(let ((fields (list-partition
228 #'(lambda (x) (eq (car x
) 'field
))
229 (getf node
:components
))))
230 (remove nil
(mapcar #'(lambda (node)
231 (compile-field (cdr node
)))
233 (:base-table
,(getf node
:name
)))))
235 (defun compile-sql1 (tree)
237 ,@(loop for node in tree
241 (compile-create-table (cdr node
)))))))
244 (defun ensure-name (x)
247 (pathname (namestring x
))
248 (otherwise "<undefined source>")))
250 (defun parse-sql (stream)
251 (let ((*sql-lexer-line
* 1))
253 (remove nil
(parse-with-lexer (make-sql-lexer (slurp stream
)) *sql-parser
*))
255 (format t
"Error at '~a':~a~%~a" (ensure-name stream
) *sql-lexer-line
* c
)
258 (defun compile-sql (stream)
259 (let ((root (parse-sql stream
)))
260 (compile-sql1 root
)))