Implement sslmode for MySQL connections.

This allows to bypass SSL when you don't need it, like over localhost for
instance. Takes the same syntax as the PostgreSQL sslmode connection string
parameter.
This commit is contained in:
Dimitri Fontaine 2017-08-24 14:56:59 +02:00
parent b685c8801d
commit 9263baeb49
7 changed files with 105 additions and 106 deletions

View File

@ -1923,7 +1923,10 @@ Must be a connection URL pointing to a MySQL database\.
If the connection URI contains a table name, then only this table is migrated from MySQL to PostgreSQL\.
.
.IP
See the \fBSOURCE CONNECTION STRING\fR section above for details on how to write the connection string\. Environment variables described in \fIhttp://dev\.mysql\.com/doc/refman/5\.0/en/environment\-variables\.html\fR can be used as default values too\. If the user is not provided, then it defaults to \fBUSER\fR environment variable value\. The password can be provided with the environment variable \fBMYSQL_PWD\fR\. The host can be provided with the environment variable \fBMYSQL_HOST\fR and otherwise defaults to \fBlocalhost\fR\. The port can be provided with the environment variable \fBMYSQL_TCP_PORT\fR and otherwise defaults to \fB3306\fR\.
See the \fBSOURCE CONNECTION STRING\fR section above for details on how to write the connection string\. The MySQL connection string accepts the same parameter \fIsslmode\fR as the PostgreSQL connection string, but the \fIverify\fR mode is not implemented (yet)\.
.
.IP
Environment variables described in \fIhttp://dev\.mysql\.com/doc/refman/5\.0/en/environment\-variables\.html\fR can be used as default values too\. If the user is not provided, then it defaults to \fBUSER\fR environment variable value\. The password can be provided with the environment variable \fBMYSQL_PWD\fR\. The host can be provided with the environment variable \fBMYSQL_HOST\fR and otherwise defaults to \fBlocalhost\fR\. The port can be provided with the environment variable \fBMYSQL_TCP_PORT\fR and otherwise defaults to \fB3306\fR\.
.
.IP "\(bu" 4
\fIWITH\fR

View File

@ -1603,9 +1603,13 @@ The `database` command accepts the following clauses and options:
migrated from MySQL to PostgreSQL.
See the `SOURCE CONNECTION STRING` section above for details on how to
write the connection string. Environment variables described in
<http://dev.mysql.com/doc/refman/5.0/en/environment-variables.html> can
be used as default values too. If the user is not provided, then it
write the connection string. The MySQL connection string accepts the
same parameter *sslmode* as the PostgreSQL connection string, but the
*verify* mode is not implemented (yet).
Environment variables described
in <http://dev.mysql.com/doc/refman/5.0/en/environment-variables.html>
can be used as default values too. If the user is not provided, then it
defaults to `USER` environment variable value. The password can be
provided with the environment variable `MYSQL_PWD`. The host can be
provided with the environment variable `MYSQL_HOST` and otherwise

View File

@ -210,8 +210,10 @@
:depends-on ("common")
:components
((:file "mysql-cast-rules")
(:file "mysql-connection")
(:file "mysql-schema"
:depends-on ("mysql-cast-rules"))
:depends-on ("mysql-connection"
"mysql-cast-rules"))
;; (:file "mysql-csv"
;; :depends-on ("mysql-schema"))
(:file "mysql"

View File

@ -104,14 +104,16 @@
(defrule mysql-uri (and mysql-prefix
(? dsn-user-password)
(? dsn-hostname)
mysql-dsn-dbname)
mysql-dsn-dbname
(? dsn-options))
(:lambda (uri)
(destructuring-bind (&key type
user
password
host
port
dbname)
dbname
(use-ssl :no))
(apply #'append uri)
;; Default to environment variables as described in
;; http://dev.mysql.com/doc/refman/5.0/en/environment-variables.html
@ -122,7 +124,8 @@
:host (or host (getenv-default "MYSQL_HOST" "localhost"))
:port (or port (parse-integer
(getenv-default "MYSQL_TCP_PORT" "3306")))
:name dbname))))
:name dbname
:use-ssl use-ssl))))
(defrule mysql-source (and kw-load kw-database kw-from mysql-uri)
(:lambda (source) (bind (((_ _ _ uri) source)) uri)))

View File

@ -0,0 +1,84 @@
;;;
;;; Tools to handle MySQL connection and querying
;;;
(in-package :pgloader.mysql)
(defvar *connection* nil "Current MySQL connection")
;;;
;;; General utility to manage MySQL connection
;;;
(defclass mysql-connection (db-connection)
((use-ssl :initarg :use-ssl :accessor myconn-use-ssl)))
(defmethod initialize-instance :after ((myconn mysql-connection) &key)
"Assign the type slot to mysql."
(setf (slot-value myconn 'type) "mysql"))
(defmethod clone-connection ((c mysql-connection))
(let ((clone
(change-class (call-next-method c) 'mysql-connection)))
(setf (myconn-use-ssl clone) (myconn-use-ssl c))
clone))
(defmethod ssl-mode ((myconn mysql-connection))
"Return non-nil when the connection uses SSL"
(ecase (myconn-use-ssl myconn)
(:try :unspecified)
(:yes t)
(:no nil)))
(defmethod open-connection ((myconn mysql-connection) &key)
(setf (conn-handle myconn)
(if (and (consp (db-host myconn)) (eq :unix (car (db-host myconn))))
(qmynd:mysql-local-connect :path (cdr (db-host myconn))
:username (db-user myconn)
:password (db-pass myconn)
:database (db-name myconn))
(qmynd:mysql-connect :host (db-host myconn)
:port (db-port myconn)
:username (db-user myconn)
:password (db-pass myconn)
:database (db-name myconn)
:ssl (ssl-mode myconn))))
(log-message :debug "CONNECTED TO ~a" myconn)
;; apply mysql-settings, if any
(loop :for (name . value) :in *mysql-settings*
:for sql := (format nil "set ~a = ~a;" name value)
:do (query myconn sql))
;; return the connection object
myconn)
(defmethod close-connection ((myconn mysql-connection))
(qmynd:mysql-disconnect (conn-handle myconn))
(setf (conn-handle myconn) nil)
myconn)
(defmethod query ((myconn mysql-connection)
sql
&key
row-fn
(as-text t)
(result-type 'list))
"Run SQL query against MySQL connection MYCONN."
(log-message :sql "MySQL: sending query: ~a" sql)
(qmynd:mysql-query (conn-handle myconn)
sql
:row-fn row-fn
:as-text as-text
:result-type result-type))
;;;
;;; The generic API query is recent, used to look like this:
;;;
(declaim (inline mysql-query))
(defun mysql-query (query &key row-fn (as-text t) (result-type 'list))
"Execute given QUERY within the current *connection*, and set proper
defaults for pgloader."
(query *connection* query
:row-fn row-fn
:as-text as-text
:result-type result-type))

View File

@ -4,103 +4,6 @@
(in-package :pgloader.mysql)
(defvar *connection* nil "Current MySQL connection")
;;;
;;; General utility to manage MySQL connection
;;;
(defclass mysql-connection (db-connection) ())
(defmethod initialize-instance :after ((myconn mysql-connection) &key)
"Assign the type slot to mysql."
(setf (slot-value myconn 'type) "mysql"))
(defmethod open-connection ((myconn mysql-connection) &key)
(setf (conn-handle myconn)
(if (and (consp (db-host myconn)) (eq :unix (car (db-host myconn))))
(qmynd:mysql-local-connect :path (cdr (db-host myconn))
:username (db-user myconn)
:password (db-pass myconn)
:database (db-name myconn))
(qmynd:mysql-connect :host (db-host myconn)
:port (db-port myconn)
:username (db-user myconn)
:password (db-pass myconn)
:database (db-name myconn))))
(log-message :debug "CONNECTED TO ~a" myconn)
;; apply mysql-settings, if any
(loop :for (name . value) :in *mysql-settings*
:for sql := (format nil "set ~a = ~a;" name value)
:do (query myconn sql))
;; return the connection object
myconn)
(defmethod close-connection ((myconn mysql-connection))
(qmynd:mysql-disconnect (conn-handle myconn))
(setf (conn-handle myconn) nil)
myconn)
(defmethod clone-connection ((c mysql-connection))
(change-class (call-next-method c) 'mysql-connection))
(defmethod query ((myconn mysql-connection)
sql
&key
row-fn
(as-text t)
(result-type 'list))
"Run SQL query against MySQL connection MYCONN."
(log-message :sql "MySQL: sending query: ~a" sql)
(qmynd:mysql-query (conn-handle myconn)
sql
:row-fn row-fn
:as-text as-text
:result-type result-type))
;;;
;;; The generic API query is recent, used to look like this:
;;;
(declaim (inline mysql-query))
(defun mysql-query (query &key row-fn (as-text t) (result-type 'list))
"Execute given QUERY within the current *connection*, and set proper
defaults for pgloader."
(query *connection* query
:row-fn row-fn
:as-text as-text
:result-type result-type))
;;;
;;; Function for accessing the MySQL catalogs, implementing auto-discovery.
;;;
;;; Interactive use only, will create its own database connection.
;;;
;; (defun list-databases ()
;; "Connect to a local database and get the database list"
;; (with-mysql-connection ()
;; (mysql-query "show databases")))
;; (defun list-tables (dbname)
;; "Return a flat list of all the tables names known in given DATABASE"
;; (with-mysql-connection (dbname)
;; (mysql-query (format nil "
;; select table_name
;; from information_schema.tables
;; where table_schema = '~a' and table_type = 'BASE TABLE'
;; order by table_name" dbname))))
;; (defun list-views (dbname &key only-tables)
;; "Return a flat list of all the view names and definitions known in given DBNAME"
;; (with-mysql-connection (dbname)
;; (mysql-query (format nil "
;; select table_name, view_definition
;; from information_schema.views
;; where table_schema = '~a'
;; ~@[and table_name in (~{'~a'~^,~})~]
;; order by table_name" dbname only-tables))))
;;;
;;; Those functions are to be called from withing an already established
;;; MySQL Connection.

View File

@ -1,5 +1,5 @@
load database
from mysql://root@localhost/sakila
from mysql://root@localhost/sakila?sslmode=disable
into postgresql:///sakila
-- WITH include drop, create tables, no truncate,