Skip to content

Commit bda06f8

Browse files
committed
Implement Citus support from a MySQL database.
1 parent 290ad68 commit bda06f8

File tree

8 files changed

+85
-14
lines changed

8 files changed

+85
-14
lines changed

src/load/migrate-database.lisp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@
232232
(defun process-catalog (copy catalog &key alter-table alter-schema distribute)
233233
"Do all the PostgreSQL catalog tweaking here: casts, index WHERE clause
234234
rewriting, pgloader level alter schema and alter table commands."
235+
(log-message :info "Processing source catalogs")
235236

236237
;; cast the catalog into something PostgreSQL can work on
237238
(cast catalog)
@@ -250,6 +251,7 @@
250251

251252
;; we also support schema changes necessary for Citus distribution
252253
(when distribute
254+
(log-message :info "Applying distribution rules")
253255
(setf (catalog-distribution-rules catalog)
254256
(citus-distribute-schema catalog distribute))))
255257

@@ -366,10 +368,12 @@
366368
:alter-schema alter-schema
367369
:distribute distribute)
368370

369-
(citus-rule-is-missing-from-list (e)
371+
#+pgloader-image
372+
((or citus-rule-table-not-found citus-rule-is-missing-from-list) (e)
370373
(log-message :fatal "~a" e)
371374
(return-from copy-database))
372375

376+
#+pgloader-image
373377
(condition (e)
374378
(log-message :fatal "Failed to process catalogs: ~a" e)
375379
(return-from copy-database)))

src/package.lisp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@
190190
#:count-indexes
191191
#:count-fkeys
192192
#:max-indexes-per-table
193+
#:field-name
193194

194195
#:push-to-end
195196
#:with-schema
@@ -299,7 +300,18 @@
299300
(:export #:citus-distribute-schema
300301
#:citus-format-sql-select
301302
#:citus-backfill-table-p
302-
#:citus-rule-is-missing-from-list))
303+
#:citus-rule-table-not-found
304+
#:citus-rule-is-missing-from-list
305+
306+
#:citus-reference-rule
307+
#:citus-reference-rule-p
308+
#:citus-reference-rule-table
309+
310+
#:citus-distributed-rule
311+
#:citus-distributed-rule-p
312+
#:citus-distributed-rule-table
313+
#:citus-distributed-rule-using
314+
#:citus-distributed-rule-from))
303315

304316
(defpackage #:pgloader.utils
305317
(:use #:cl

src/parsers/command-mysql.lisp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@
8989
excluding-matching
9090
decoding-tables-as
9191
before-load
92-
after-load))
92+
after-load
93+
distribute-commands))
9394
(:lambda (clauses-list)
9495
(alexandria:alist-plist clauses-list)))
9596

@@ -164,7 +165,7 @@
164165
&key
165166
gucs mysql-gucs
166167
casts views before after options
167-
alter-table alter-schema
168+
alter-table alter-schema distribute
168169
((:including incl))
169170
((:excluding excl))
170171
((:decoding decoding-as))
@@ -191,6 +192,7 @@
191192
:materialize-views ',views
192193
:alter-table ',alter-table
193194
:alter-schema ',alter-schema
195+
:distribute ',distribute
194196
:set-table-oids t
195197
:on-error-stop on-error-stop
196198
,@(remove-batch-control-option options))
@@ -203,7 +205,7 @@
203205
pg-db-uri
204206
&key
205207
gucs mysql-gucs casts views before after options
206-
alter-table alter-schema
208+
alter-table alter-schema distribute
207209
including excluding decoding)
208210
source
209211
(cond (*dry-run*
@@ -219,6 +221,7 @@
219221
:options options
220222
:alter-table alter-table
221223
:alter-schema alter-schema
224+
:distribute distribute
222225
:including including
223226
:excluding excluding
224227
:decoding decoding))))))

src/pgsql/pgsql-ddl-citus.lisp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
(defmethod format-create-sql ((rule citus-distributed-rule)
1414
&key (stream nil) if-not-exists)
1515
(declare (ignore if-not-exists))
16-
(format stream "SELECT create_distributed_table('~a', '~a');"
17-
(format-table-name (citus-distributed-rule-table rule))
18-
(column-name (citus-distributed-rule-using rule))))
16+
(let* ((rule-table (citus-distributed-rule-table rule))
17+
(rule-col-name (column-name (citus-distributed-rule-using rule))))
18+
(format stream "SELECT create_distributed_table('~a', '~a');"
19+
(format-table-name rule-table)
20+
(apply-identifier-case rule-col-name))))

src/sources/mysql/mysql-cast-rules.lisp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@
186186
(table-name name comment dtype ctype default nullable extra)))
187187
table-name name dtype ctype default nullable extra comment)
188188

189+
(defmethod field-name ((field mysql-column) &key)
190+
(mysql-column-name field))
191+
189192
(defun explode-mysql-enum (ctype)
190193
"Convert MySQL ENUM expression into a list of labels."
191194
(cl-ppcre:register-groups-bind (list)

src/utils/catalog.lisp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@
186186
"Cast a FIELD definition from a source database into a PostgreSQL COLUMN
187187
definition."))
188188

189+
(defgeneric field-name (object &key)
190+
(:documentation "Get the source database column name, or field-name."))
191+
189192

190193
;;;
191194
;;; Implementation of the methods
@@ -373,6 +376,9 @@
373376
(loop :for schema :in (catalog-schema-list catalog)
374377
:do (cast schema)))
375378

379+
(defmethod field-name ((column column) &key)
380+
(column-name column))
381+
376382
;;;
377383
;;; There's no simple equivalent to array_agg() in MS SQL, so the index and
378384
;;; fkey queries return a row per index|fkey column rather than per

src/utils/citus.lisp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,42 @@
4040
;;
4141
;; ERROR Database error 42P16: table ;; "campaigns" is already distributed
4242
;;
43+
;; In the PostgreSQL source case, we have the table OIDs already at this
44+
;; point, but in the general case we don't. Use the names to match what
45+
;; we did up to now.
46+
;;
4347
(loop :for rule :in (append distribution-rules derived-rules)
44-
:unless (member (table-oid (citus-rule-table rule))
48+
:unless (member (table-source-name (citus-rule-table rule))
4549
processed-rules
4650
:key (lambda (rule)
47-
(table-oid (citus-rule-table rule))))
51+
(table-source-name (citus-rule-table rule)))
52+
:test #'equal)
4853
:collect (progn
4954
(push rule processed-rules)
5055
(apply-citus-rule rule)
5156
rule))))
5257

58+
(define-condition citus-rule-table-not-found (error)
59+
((schema-name :initarg :schema-name
60+
:accessor citus-rule-table-not-found-schema-name)
61+
(table-name :initarg :table-name
62+
:accessor citus-rule-table-not-found-table-name))
63+
(:report
64+
(lambda (err stream)
65+
(let ((*print-circle* nil))
66+
(with-slots (schema-name table-name)
67+
err
68+
(format stream
69+
"Could not find table ~s in schema ~s for distribution rules."
70+
table-name schema-name))))))
71+
5372
(defun citus-find-table (catalog table)
54-
(let* ((table-name (table-name table))
73+
(let* ((table-name (cdr (table-source-name table)))
5574
(schema-name (schema-name (table-schema table))))
56-
(find-table (find-schema catalog schema-name) table-name)))
75+
(or (find-table (find-schema catalog schema-name) table-name)
76+
(error (make-condition 'citus-rule-table-not-found
77+
:table-name table-name
78+
:schema-name schema-name)))))
5779

5880
(defgeneric citus-rule-table (rule)
5981
(:documentation "Returns the RULE's table.")
@@ -197,11 +219,11 @@
197219
;; it to our model
198220
(setf (table-citus-rule (citus-distributed-rule-table rule)) rule)
199221

200-
(let* ((table (citus-distributed-rule-table rule))
222+
(let* ((table (citus-distributed-rule-table rule))
201223
(column (find (column-name (citus-distributed-rule-using rule))
202224
(table-field-list table)
203225
:test #'string=
204-
:key #'column-name)))
226+
:key #'field-name)))
205227
(if column
206228

207229
;; add it to the PKEY definition, in first position

test/mysql/f1db-citus.load

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
load database
2+
from mysql://root@localhost/f1db?useSSL=false
3+
into pgsql://localhost:9700/dim
4+
5+
with reset no sequences
6+
7+
distribute f1db.circuits as reference table
8+
distribute f1db.constructorResults using raceId
9+
distribute f1db.constructors as reference table
10+
distribute f1db.constructorStandings using raceId
11+
distribute f1db.drivers as reference table
12+
distribute f1db.driverStandings using raceId
13+
distribute f1db.lapTimes using raceId
14+
distribute f1db.pitStops using raceId
15+
distribute f1db.qualifying using raceId
16+
distribute f1db.races as reference table
17+
distribute f1db.results using raceId
18+
distribute f1db.seasons as reference table
19+
distribute f1db.status as reference table;

0 commit comments

Comments
 (0)