Implement per-column MySQL CAST rules.

This commit is contained in:
Dimitri Fontaine 2013-11-18 10:09:21 +01:00
parent 8ce0288b63
commit b31ccded6f
5 changed files with 41 additions and 18 deletions

View File

@ -136,10 +136,6 @@ Some notes about what I intend to be working on next.
- error reporting (done) - error reporting (done)
- add input line number to log file? - add input line number to log file?
### transformation and casts
- add per-column support for cast rules in the system
### data output ### data output
- PostgreSQL COPY Text format output for any supported input - PostgreSQL COPY Text format output for any supported input

View File

@ -860,9 +860,16 @@ The `database` command accepts the following clauses and options:
The cast clause allows to specify custom casting rules, either to The cast clause allows to specify custom casting rules, either to
overload the default casting rules or to amend them with special cases. overload the default casting rules or to amend them with special cases.
A casting rule is expected to follow the form: A casting rule is expected to follow one of the forms:
type <mysql-type-name> [ <guard> ... ] to <pgsql-type-name> [ <option> ... ] type <mysql-type-name> [ <guard> ... ] to <pgsql-type-name> [ <option> ... ]
column <table-name>.<column-name> [ <guards> ] to ...
It's possible for a *casting rule* to either match against a MySQL data
type or against a given *column name* in a given *table name*. That
flexibility allows to cope with cases where the type `tinyint` might
have been used as a `boolean` in some cases but as a `smallint` in
others.
The supported guards are: The supported guards are:

View File

@ -604,26 +604,39 @@
(alexandria:alist-plist guards))) (alexandria:alist-plist guards)))
;; at the moment we only know about extra auto_increment ;; at the moment we only know about extra auto_increment
(defrule cast-source-extra (and ignore-whitespace (defrule cast-source-extra (and kw-with kw-extra kw-auto-increment)
kw-with kw-extra kw-auto-increment)
(:constant (list :auto-increment t))) (:constant (list :auto-increment t)))
(defrule cast-source (and (or kw-column kw-type) (defrule cast-source-type (and kw-type trimmed-name)
trimmed-name (:destructure (kw name) (declare (ignore kw)) (list :type name)))
(defrule table-column-name (and namestring "." namestring)
(:destructure (table-name dot column-name)
(declare (ignore dot))
(list :column (cons (text table-name) (text column-name)))))
(defrule cast-source-column (and kw-column table-column-name)
;; well, we want namestring . namestring
(:destructure (kw name) (declare (ignore kw)) name))
(defrule cast-source (and (or cast-source-type cast-source-column)
(? cast-source-extra) (? cast-source-extra)
(? cast-source-guards) (? cast-source-guards)
ignore-whitespace) ignore-whitespace)
(:lambda (source) (:lambda (source)
(destructuring-bind (kw name opts guards ws) source (destructuring-bind (name-and-type opts guards ws) source
(declare (ignore ws)) (declare (ignore ws))
(destructuring-bind (&key (default nil d-s-p) (destructuring-bind (&key (default nil d-s-p)
(typemod nil t-s-p) (typemod nil t-s-p)
&allow-other-keys) guards &allow-other-keys)
(destructuring-bind (&key auto-increment &allow-other-keys) opts guards
`(,kw ,name (destructuring-bind (&key (auto-increment nil ai-s-p)
&allow-other-keys)
opts
`(,@name-and-type
,@(when t-s-p (list :typemod typemod)) ,@(when t-s-p (list :typemod typemod))
,@(when d-s-p (list :default default)) ,@(when d-s-p (list :default default))
:auto-increment ,auto-increment)))))) ,@(when ai-s-p (list :auto-increment auto-increment))))))))
(defrule cast-type-name (and (alpha-char-p character) (defrule cast-type-name (and (alpha-char-p character)
(* (or (alpha-char-p character) (* (or (alpha-char-p character)

View File

@ -181,11 +181,15 @@
using) using)
rule rule
(destructuring-bind (destructuring-bind
;; it's either :type or :column, just cope with both thanks to
;; &allow-other-keys
(&key ((:type rule-source-type) nil t-s-p) (&key ((:type rule-source-type) nil t-s-p)
((:column rule-source-column) nil c-s-p)
((:typemod typemod-expr) nil tm-s-p) ((:typemod typemod-expr) nil tm-s-p)
((:default rule-source-default) nil d-s-p) ((:default rule-source-default) nil d-s-p)
((:not-null rule-source-not-null) nil n-s-p) ((:not-null rule-source-not-null) nil n-s-p)
((:auto-increment rule-source-auto-increment) nil ai-s-p)) ((:auto-increment rule-source-auto-increment) nil ai-s-p)
&allow-other-keys)
rule-source rule-source
(destructuring-bind (&key table-name (destructuring-bind (&key table-name
column-name column-name
@ -196,10 +200,13 @@
not-null not-null
auto-increment) auto-increment)
source source
(declare (ignore table-name column-name ctype)) (declare (ignore ctype))
(when (when
(and (and
(string= type rule-source-type) (or (and t-s-p (string= type rule-source-type))
(and c-s-p
(string-equal table-name (car rule-source-column))
(string-equal column-name (cdr rule-source-column))))
(or (null tm-s-p) (typemod-expr-matches-p typemod-expr typemod)) (or (null tm-s-p) (typemod-expr-matches-p typemod-expr typemod))
(or (null d-s-p) (string= default rule-source-default)) (or (null d-s-p) (string= default rule-source-default))
(or (null n-s-p) (eq not-null rule-source-not-null)) (or (null n-s-p) (eq not-null rule-source-not-null))

View File

@ -6,7 +6,7 @@ LOAD DATABASE
CAST type datetime to timestamptz drop default drop not null using zero-dates-to-null, CAST type datetime to timestamptz drop default drop not null using zero-dates-to-null,
type date drop not null drop default using zero-dates-to-null, type date drop not null drop default using zero-dates-to-null,
type tinyint to boolean drop typemod using tinyint-to-boolean, column bools.a to boolean drop typemod using tinyint-to-boolean,
type char when (= precision 1) to char keep typemod, type char when (= precision 1) to char keep typemod,
type year to integer, type year to integer,
type timestamp to timestamptz drop not null using zero-dates-to-null type timestamp to timestamptz drop not null using zero-dates-to-null