diff --git a/src/package.lisp b/src/package.lisp index d068918..8f3180c 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -71,6 +71,7 @@ #:catalog-name #:catalog-schema-list + #:catalog-types-without-btree #:schema-name #:schema-catalog @@ -410,6 +411,7 @@ ;; postgresql identifiers #:list-reserved-keywords + #:list-typenames-without-btree-support ;; postgresql user provided gucs #:sanitize-user-gucs diff --git a/src/pgsql/connection.lisp b/src/pgsql/connection.lisp index 1641f8a..bab9586 100644 --- a/src/pgsql/connection.lisp +++ b/src/pgsql/connection.lisp @@ -338,6 +338,29 @@ ;;; ;;; PostgreSQL version specific support, that we get once connected ;;; +(defun list-typenames-without-btree-support () + "Fetch PostgresQL data types without btree support, so that it's possible + to later CREATE INDEX ... ON ... USING gist(...), or even something else + than gist. " + (loop :for (typename access-methods) :in + (pomo:query " +select typname, + array_agg(amname order by amname <> 'gist', amname <> 'gin') + from pg_type + join pg_opclass on pg_opclass.opcintype = pg_type.oid + join pg_am on pg_am.oid = pg_opclass.opcmethod + where substring(typname from 1 for 1) <> '_' + and not exists + ( + select amname + from pg_am am + join pg_opclass c on am.oid = c.opcmethod + join pg_type t on c.opcintype = t.oid + where amname = 'btree' and t.oid = pg_type.oid + ) +group by typname;") + :collect (cons typename access-methods))) + (defun list-reserved-keywords (pgconn) "Connect to PostgreSQL DBNAME and fetch reserved keywords." (handler-case diff --git a/src/pgsql/pgsql-ddl.lisp b/src/pgsql/pgsql-ddl.lisp index e6374b2..9e56849 100644 --- a/src/pgsql/pgsql-ddl.lisp +++ b/src/pgsql/pgsql-ddl.lisp @@ -153,7 +153,8 @@ (build-identifier "_" "idx" (table-oid (index-table index)) - (index-name index))))) + (index-name index)))) + (access-method (index-access-method index))) (cond ((or (index-primary index) (and (index-condef index) (index-unique index))) @@ -185,10 +186,11 @@ (t (or (index-sql index) (format stream - "CREATE~:[~; UNIQUE~] INDEX ~a ON ~a (~{~a~^, ~})~@[ WHERE ~a~];" + "CREATE~:[~; UNIQUE~] INDEX ~a ON ~a ~@[USING ~a~](~{~a~^, ~})~@[ WHERE ~a~];" (index-unique index) index-name (format-table-name table) + access-method (index-columns index) (index-filter index))))))) @@ -214,6 +216,28 @@ (format stream "DROP INDEX~:[~; IF EXISTS~] ~@[~s.~]~s~@[ CASCADE~];" if-exists schema-name index-name cascade))))) +(defun index-access-method (index) + "Compute PostgreSQL access method for index. If defaults to btree, but + some types such as POINTS or BOX have no support for btree. If a MySQL + point column has an index in MySQL, then create a GiST index for it in + PostgreSQL." + (when (= 1 (length (index-columns index))) + ;; we only process single-index columns at the moment, which is a simpler + ;; problem space and usefull enough to get started. + (let* ((idx-cols (index-columns index)) + (tbl-cols (table-column-list (index-table index))) + (idx-types (loop :for idx-col :in idx-cols + :collect (column-type-name + (find idx-col tbl-cols + :test #'string-equal + :key #'column-name)))) + (nobtree (catalog-types-without-btree + (schema-catalog (table-schema (index-table index)))))) + (let* ((idx-type (first idx-types)) + (method (cdr (assoc idx-type nobtree :test #'string=)))) + (when method + (aref method 0)))))) + ;;; ;;; Foreign Keys diff --git a/src/sources/common/db-methods.lisp b/src/sources/common/db-methods.lisp index 99b0262..5d1adca 100644 --- a/src/sources/common/db-methods.lisp +++ b/src/sources/common/db-methods.lisp @@ -27,6 +27,9 @@ (log-message :notice "Prepare PostgreSQL database.") (with-pgsql-transaction (:pgconn (target-db copy)) + (setf (catalog-types-without-btree catalog) + (list-typenames-without-btree-support)) + (when create-schemas (with-stats-collection ("Create Schemas" :section :pre :use-result-as-read t diff --git a/src/utils/catalog.lisp b/src/utils/catalog.lisp index 761ebf6..1855740 100644 --- a/src/utils/catalog.lisp +++ b/src/utils/catalog.lisp @@ -42,7 +42,7 @@ ;;; Column structures details depend on the specific source type and are ;;; implemented in each source separately. ;;; -(defstruct catalog name schema-list) +(defstruct catalog name schema-list types-without-btree) (defstruct schema source-name name catalog table-list view-list) (defstruct table source-name name schema oid comment storage-parameter-list ;; field is for SOURCE