mirror of
https://github.com/dimitri/pgloader.git
synced 2025-08-08 07:16:58 +02:00
144 lines
3.9 KiB
Common Lisp
144 lines
3.9 KiB
Common Lisp
;;;
|
|
;;; Parse the pgloader commands grammar
|
|
;;;
|
|
|
|
(in-package :pgloader.parser)
|
|
|
|
(defparameter *default-postgresql-port* 5432)
|
|
|
|
;;
|
|
;; Some useful rules
|
|
;;
|
|
(defrule whitespace (+ (or #\space #\tab #\newline))
|
|
(:constant 'whitespace))
|
|
|
|
(defrule ignore-whitespace (* whitespace)
|
|
(:constant nil))
|
|
|
|
(defrule punct (or #\, #\- #\_)
|
|
(:text t))
|
|
|
|
(defrule namestring (and (alpha-char-p character)
|
|
(* (or (alpha-char-p character)
|
|
(digit-char-p character)
|
|
punct)))
|
|
(:text t)))
|
|
|
|
(defrule quoted-namestring (and #\' namestring #\')
|
|
(:destructure (open name close) (declare (ignore open close)) name))
|
|
|
|
(defrule name (or namestring quoted-namestring)
|
|
(:text t))
|
|
|
|
(defrule trimmed-name (and ignore-whitespace name)
|
|
(:destructure (whitespace name) (declare (ignore whitespace)) name))))
|
|
|
|
;;
|
|
;; Parse PostgreSQL database connection strings
|
|
;;
|
|
;; at postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]
|
|
;;
|
|
;; http://www.postgresql.org/docs/9.2/static/libpq-connect.html#LIBPQ-CONNSTRING
|
|
;;
|
|
(defrule dsn-port (and ":" (* (digit-char-p character)))
|
|
(:destructure (colon digits &aux (port (coerce digits 'string)))
|
|
(declare (ignore colon))
|
|
(list :port (if (null digits)
|
|
*default-postgresql-port*
|
|
(parse-integer port)))))
|
|
|
|
(defrule dsn-user-password (and namestring
|
|
(? (and ":" (? namestring)))
|
|
"@")
|
|
(:lambda (args)
|
|
(destructuring-bind (username &optional password)
|
|
(butlast args)
|
|
;; password looks like '(":" "password")
|
|
(list :user username :password (cadr password)))))
|
|
|
|
(defrule hostname (and namestring (? (and "." hostname)))
|
|
(:text t))
|
|
|
|
(defrule dsn-hostname (and hostname (? dsn-port))
|
|
(:destructure (hostname &optional port)
|
|
(append (list :host hostname)
|
|
(or port
|
|
(list :port *default-postgresql-port*)))))
|
|
|
|
(defrule dsn-dbname (and "/" namestring)
|
|
(:destructure (slash dbname)
|
|
(declare (ignore slash))
|
|
(list :dbname dbname)))
|
|
|
|
(defrule postgresql-connection-uri (and "postgresql://"
|
|
(? dsn-user-password)
|
|
(? dsn-hostname)
|
|
dsn-dbname)
|
|
(:lambda (uri)
|
|
(destructuring-bind (&key user
|
|
password
|
|
(host "localhost")
|
|
(port 5432)
|
|
dbname)
|
|
;; ignore the postgresql:// prefix, (first uri)
|
|
(append (second uri) (third uri) (fourth uri))
|
|
(list :user user
|
|
:password password
|
|
:host host
|
|
:port port
|
|
:dbname dbname))))
|
|
|
|
(defrule target-dsn (and "at" ignore-whitespace connection-uri)
|
|
(:destructure (at whitespace uri) (declare (ignore at whitespace)) uri))
|
|
|
|
;;
|
|
;; The main target parsing
|
|
;;
|
|
;; COPY target-table-name AT connection-uri
|
|
;; COPY foo AT postgresql://user@localhost:5432/dbname
|
|
;;
|
|
(defrule target (and "COPY" trimmed-name (? (and ignore-whitespace target-dsn)))
|
|
(:destructure (copy target &optional dsn)
|
|
(declare (ignore copy))
|
|
(append (list :table-name target) (cadr dsn))))
|
|
|
|
;;
|
|
;; Source parsing (filename)
|
|
;;
|
|
|
|
;; parsing filename
|
|
(defun filename-character-p (char)
|
|
(or (member char #.(quote (coerce "/\\:.-_!@#$%^&*() " 'list)))
|
|
(alphanumericp char)))
|
|
|
|
(defrule filename (and #\'
|
|
(* (filename-character-p character))
|
|
#\')
|
|
(:destructure (open f close)
|
|
(declare (ignore open close))
|
|
(parse-namestring (coerce f 'string))))
|
|
|
|
(defrule trimmed-filename (and ignore-whitespace filename)
|
|
(:destructure (whitespace filename) (declare (ignore whitespace)) filename))
|
|
|
|
(defrule source (and "FROM" trimmed-filename)
|
|
(:destructure (from source)
|
|
(declare (ignore from))
|
|
source))
|
|
|
|
;;
|
|
;; Putting it all together, the COPY command
|
|
;;
|
|
;; The output format is Lisp code using the pgloader API.
|
|
;;
|
|
(defrule copy (and target ignore-whitespace source)
|
|
(:destructure (target whitespace source)
|
|
(declare (ignore whitespace))
|
|
(destructuring-bind (&key table-name user password host port dbname)
|
|
target
|
|
`(lambda (&key (*pgconn-host* ,host)
|
|
(*pgconn-port* ,port)
|
|
(*pgconn-user* ,user)
|
|
(*pgconn-pass* ,password))
|
|
(pgloader.pgsql:copy-from-file ,dbname ,table-name ,source)))))
|