Fix our SQL parser.

In order to support custom SQL files with several queries and psql like
advanced \i feature, we have our own internal SQL parser in pgloader. The
PostgreSQL variant of SQL is pretty complex and allows dollar-quoting and
other subtleties that we need to take care of.

Here we fix the case when we have a dollar sign ($) as part of a single
quoted text (such as a regexp), so both not a new dollar-quoting tag and a
part of a quoted text being read.

In passing we also fix reading double-quoted identifiers, even when they
contain a dollar sign. After all the following is totally supported by
PostgreSQL:

  create table dollar("$id" serial, foo text);
  select "$id", foo from dollar;

Fix #561.
This commit is contained in:
Dimitri Fontaine 2017-05-29 12:42:12 +02:00
parent 1f9a0b6391
commit 8f92cc5a7d

View File

@ -116,7 +116,14 @@ Another test case for the classic quotes:
(#\' (case (parser-state state)
(:eat (setf (parser-state state) :eqt))
(:esc (setf (parser-state state) :eqt))
(:eqt (setf (parser-state state) :eat)))
(:eqt (setf (parser-state state) :eat))
(:tag
(progn
;; a tag name can't contain a single-quote
;; get back to previous state
(let ((tag (pop-current-tag state)))
(format (parser-stream state) "$~a" tag))
(reset-state state))))
(write-char char (parser-stream state)))
@ -134,6 +141,7 @@ Another test case for the classic quotes:
;; we act depending on the NEW state
(case (parser-state state)
(:eat (write-char char (parser-stream state)))
(:edq (write-char char (parser-stream state)))
(:tag (push-new-tag state))
@ -157,7 +165,7 @@ Another test case for the classic quotes:
(:eat (setf (parser-state state) :eoq))
(otherwise (write-char char (parser-stream state)))))
(otherwise (cond ((member (parser-state state) '(:eat :eqt))
(otherwise (cond ((member (parser-state state) '(:eat :eqt :edq))
(write-char char (parser-stream state)))
;; see
@ -175,9 +183,9 @@ Another test case for the classic quotes:
(extend-current-tag state char)
(progn
;; not a tag actually: remove the
;; parser-tags entry and push back its
;; contents to the main output stream
;; not a tag actually: remove the
;; parser-tags entry and push back its
;; contents to the main output stream
(let ((tag (pop-current-tag state)))
(format (parser-stream state)
"$~a~c"