From 13f5821547310dade1550938124c676c43e5afd5 Mon Sep 17 00:00:00 2001 From: Krzysztof Jurewicz Date: Wed, 18 May 2016 21:50:09 +0200 Subject: [PATCH] =?UTF-8?q?Add=20the=20=E2=80=9Cset=20not=20null=E2=80=9D?= =?UTF-8?q?=20cast=20option=20for=20MySQL=20(#407)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use case: Django dissuades setting NULL “on string-based fields […] because empty string values will always be stored as empty strings, not as NULL. If a string-based field has null=True, that means it has two possible values for »no data«: NULL, and the empty string. In most cases, it’s redundant to have two possible values for »no data«; the Django convention is to use the empty string, not NULL.”. pgloader already supports custom transformations which can be used to replace NULL values in string-based columns with empty strings. Setting NOT NULL constraint on those columns could possibly be achieved by running a database query to extract their names and then generating relevant ALTER TABLE statements, but a cast option in pgloader is a more convenient way. --- pgloader.1.md | 6 +++++- src/parsers/command-cast-rules.lisp | 11 ++++++++--- src/sources/common/casting-rules.lisp | 3 ++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/pgloader.1.md b/pgloader.1.md index 721d0c5..7682048 100644 --- a/pgloader.1.md +++ b/pgloader.1.md @@ -1775,7 +1775,7 @@ The `database` command accepts the following clauses and options: The spelling *keep default* explicitly prevents that behaviour and can be used to overload the default casting rules. - - *drop not null*, *keep not null* + - *drop not null*, *keep not null*, *set not null* When the option *drop not null* is listed, pgloader drops any existing `NOT NULL` constraint associated with the given source @@ -1785,6 +1785,10 @@ The `database` command accepts the following clauses and options: The spelling *keep not null* explicitly prevents that behaviour and can be used to overload the default casting rules. + When the option *set not null* is listed, pgloader sets a `NOT NULL` + constraint on the target column regardless whether it has been set + in the source MySQL column. + - *drop typemod*, *keep typemod* When the option *drop typemod* is listed, pgloader drops any diff --git a/src/parsers/command-cast-rules.lisp b/src/parsers/command-cast-rules.lisp index 5417004..e007f89 100644 --- a/src/parsers/command-cast-rules.lisp +++ b/src/parsers/command-cast-rules.lisp @@ -75,21 +75,26 @@ (defrule cast-drop-not-null (and kw-drop kw-not kw-null) (:constant (list :drop-not-null t))) +(defrule cast-set-not-null (and kw-set kw-not kw-null) + (:constant (list :set-not-null t))) + (defrule cast-def (+ (or cast-to-type cast-keep-default cast-drop-default cast-keep-typemod cast-drop-typemod cast-keep-not-null - cast-drop-not-null)) + cast-drop-not-null + cast-set-not-null)) (:lambda (source) (destructuring-bind - (&key type drop-default drop-typemod drop-not-null &allow-other-keys) + (&key type drop-default drop-typemod drop-not-null set-not-null &allow-other-keys) (apply #'append source) (list :type type :drop-default drop-default :drop-typemod drop-typemod - :drop-not-null drop-not-null)))) + :drop-not-null drop-not-null + :set-not-null set-not-null)))) (defun function-name-character-p (char) (or (member char #.(quote (coerce "/.-%" 'list))) diff --git a/src/sources/common/casting-rules.lisp b/src/sources/common/casting-rules.lisp index 39f9b2c..390e22c 100644 --- a/src/sources/common/casting-rules.lisp +++ b/src/sources/common/casting-rules.lisp @@ -91,6 +91,7 @@ (destructuring-bind (&key type drop-default drop-not-null + set-not-null (drop-typemod t) &allow-other-keys) target @@ -108,7 +109,7 @@ :type-name type-name :type-mod (when (and source-typemod (not drop-typemod)) pg-typemod) - :nullable (not (and source-not-null (not drop-not-null))) + :nullable (and (not set-not-null) (or (not source-not-null) drop-not-null)) :default (when (and source-default (not drop-default)) (format-default-value source-default using)) :transform using)))