mirror of
https://github.com/dimitri/pgloader.git
synced 2025-08-07 06:47:00 +02:00
Improve user code parsing, fix #297.
To be able to use "t" (or "nil") as a column name, pgloader needs to be able to generate lisp code where those symbols are available. It's simple enough in that a Common Lisp package that doesn't :use :cl fullfills the condition, so intern user symbols in a specially crafted package that doesn't :use :cl. Now, we still need to be able to run transformation code that is using the :cl package symbols and the pgloader.transforms functions too. In this commit we introduce a heuristic to pick symbols either as functions from pgloader.transforms or anything else in pgloader.user-symbols. And so that user code may use NIL too, we provide an override mechanism to the intern-symbol heuristic and use it only when parsing user code, not when producing Common Lisp code from the parsed load command.
This commit is contained in:
parent
fe812061c4
commit
598c860cf5
@ -155,7 +155,7 @@
|
|||||||
(:use #:cl
|
(:use #:cl
|
||||||
#:pgloader.params #:pgloader.utils #:pgloader.connection
|
#:pgloader.params #:pgloader.utils #:pgloader.connection
|
||||||
#:pgloader.schema)
|
#:pgloader.schema)
|
||||||
(:import-from #:pgloader.transforms #:precision #:scale)
|
(:import-from #:pgloader.transforms #:precision #:scale #:intern-symbol)
|
||||||
(:import-from #:pgloader.parse-date
|
(:import-from #:pgloader.parse-date
|
||||||
#:parse-date-string
|
#:parse-date-string
|
||||||
#:parse-date-format)
|
#:parse-date-format)
|
||||||
|
@ -266,7 +266,7 @@
|
|||||||
(defrule sexp-symbol (and (symbol-first-character-p character)
|
(defrule sexp-symbol (and (symbol-first-character-p character)
|
||||||
(* (symbol-character-p character)))
|
(* (symbol-character-p character)))
|
||||||
(:lambda (schars)
|
(:lambda (schars)
|
||||||
(pgloader.transforms:intern-symbol (text schars))))
|
(pgloader.transforms:intern-symbol (text schars) '(("nil" . cl:nil)))))
|
||||||
|
|
||||||
(defrule sexp-string-char (or (not-doublequote character) (and #\\ #\")))
|
(defrule sexp-string-char (or (not-doublequote character) (and #\\ #\")))
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@
|
|||||||
(field-name-as-symbol (field-name-or-list)
|
(field-name-as-symbol (field-name-or-list)
|
||||||
"we need to deal with symbols as we generate code"
|
"we need to deal with symbols as we generate code"
|
||||||
(typecase field-name-or-list
|
(typecase field-name-or-list
|
||||||
(list (pgloader.transforms:intern-symbol (car field-name-or-list)))
|
(list (intern-symbol (car field-name-or-list)))
|
||||||
(t (pgloader.transforms:intern-symbol field-name-or-list))))
|
(t (intern-symbol field-name-or-list))))
|
||||||
|
|
||||||
(process-field (field-name-or-list)
|
(process-field (field-name-or-list)
|
||||||
"Given a field entry, return a function dealing with nulls for it"
|
"Given a field entry, return a function dealing with nulls for it"
|
||||||
|
@ -7,6 +7,44 @@
|
|||||||
|
|
||||||
(in-package :pgloader.transforms)
|
(in-package :pgloader.transforms)
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; This package is used to generate symbols in the CL code that
|
||||||
|
;;; project-fields produces, allowing to use symbols such as t. It's
|
||||||
|
;;; important that the user-symbols package doesn't :use cl.
|
||||||
|
;;;
|
||||||
|
(defpackage #:pgloader.user-symbols (:use))
|
||||||
|
|
||||||
|
(defun intern-symbol (symbol-name &optional (overrides '()))
|
||||||
|
"Return a symbol in either PGLOADER.TRANSFORMS if it exists there
|
||||||
|
already (it's a user provided function) or a PGLOADER.USER-SYMBOLS
|
||||||
|
package.
|
||||||
|
|
||||||
|
OVERRIDES is an alist of symbol . value, allowing called to force certain
|
||||||
|
values: the classic example is how to parse the \"nil\" symbol-name.
|
||||||
|
Given OVERRIDES as '((nil . nil)) the returned symbol will be cl:nil
|
||||||
|
rather than pgloader.user-symbols::nil."
|
||||||
|
(let ((overriden (assoc symbol-name overrides :test #'string-equal)))
|
||||||
|
(if overriden
|
||||||
|
(cdr overriden)
|
||||||
|
|
||||||
|
(multiple-value-bind (symbol status)
|
||||||
|
(find-symbol (string-upcase symbol-name)
|
||||||
|
(find-package "PGLOADER.TRANSFORMS"))
|
||||||
|
;; pgloader.transforms package (:use :cl) so we might find variable
|
||||||
|
;; names in there that we want to actually intern in
|
||||||
|
;; pgloader.user-symbols so that users may use e.g. t as a column name...
|
||||||
|
;; so only use transform symbol when it denotes a function
|
||||||
|
(cond
|
||||||
|
((and status (fboundp symbol)) symbol) ; a transform function
|
||||||
|
|
||||||
|
(t
|
||||||
|
(intern (string-upcase symbol-name)
|
||||||
|
(find-package "PGLOADER.USER-SYMBOLS"))))))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Some optimisation stanza
|
||||||
|
;;;
|
||||||
(declaim (inline intern-symbol
|
(declaim (inline intern-symbol
|
||||||
zero-dates-to-null
|
zero-dates-to-null
|
||||||
date-with-no-separator
|
date-with-no-separator
|
||||||
@ -25,14 +63,6 @@
|
|||||||
sql-server-uniqueidentifier-to-uuid
|
sql-server-uniqueidentifier-to-uuid
|
||||||
sql-server-bit-to-boolean))
|
sql-server-bit-to-boolean))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
|
||||||
;;; Some tools for reading expressions in the parser, and evaluating them.
|
|
||||||
;;;
|
|
||||||
(defun intern-symbol (symbol-name)
|
|
||||||
(intern (string-upcase symbol-name)
|
|
||||||
(find-package "PGLOADER.TRANSFORMS")))
|
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Transformation functions
|
;;; Transformation functions
|
||||||
|
@ -16,6 +16,7 @@ REGRESS= allcols.load \
|
|||||||
csv-keep-extra-blanks.load \
|
csv-keep-extra-blanks.load \
|
||||||
csv-non-printable.load \
|
csv-non-printable.load \
|
||||||
csv-nulls.load \
|
csv-nulls.load \
|
||||||
|
csv-temp.load \
|
||||||
csv-trim-extra-blanks.load \
|
csv-trim-extra-blanks.load \
|
||||||
csv.load \
|
csv.load \
|
||||||
copy.load \
|
copy.load \
|
||||||
|
29
test/csv-temp.load
Normal file
29
test/csv-temp.load
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
--
|
||||||
|
-- See https://github.com/dimitri/pgloader/issues/297
|
||||||
|
--
|
||||||
|
-- The "t" field would be "temperature", for instance.
|
||||||
|
--
|
||||||
|
|
||||||
|
LOAD CSV
|
||||||
|
FROM inline (a, b, nil, t)
|
||||||
|
INTO postgresql:///pgloader?temp(a,b,nil,t)
|
||||||
|
|
||||||
|
WITH fields terminated by ';'
|
||||||
|
|
||||||
|
BEFORE LOAD DO
|
||||||
|
$$ drop table if exists temp; $$,
|
||||||
|
$$ CREATE TABLE temp
|
||||||
|
(
|
||||||
|
a integer,
|
||||||
|
b timestamp without time zone,
|
||||||
|
nil real,
|
||||||
|
t real
|
||||||
|
);
|
||||||
|
$$;
|
||||||
|
|
||||||
|
|
||||||
|
100;2015-01-01 00:00:00;-6;10
|
||||||
|
101;2015-01-02 00:00:00;-2.1;12.5
|
||||||
|
102;2015-01-03 00:00:00;3.4;5.5
|
||||||
|
103;2015-01-04 00:00:00;4.7;-2.3
|
||||||
|
104;2015-01-05 00:00:00;0.4;0
|
5
test/regress/expected/csv-temp.out
Normal file
5
test/regress/expected/csv-temp.out
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
100 2015-01-01 00:00:00 -6 10
|
||||||
|
101 2015-01-02 00:00:00 -2.1 12.5
|
||||||
|
102 2015-01-03 00:00:00 3.4 5.5
|
||||||
|
103 2015-01-04 00:00:00 4.7 -2.3
|
||||||
|
104 2015-01-05 00:00:00 0.4 0
|
Loading…
Reference in New Issue
Block a user