Another attempt at fixing #323.

Rather than trying hard to have PostgreSQL fully qualify the index name
with tricks around search_path setting at the time ::regclass is
executed, simply join on pg_namespace to retrieve that schema in a new
slot in our pgsql-index structure so that we can then reuse it when
needed.

Also add a test case for the scenario, including both a UNIQUE
constraint and a classic index, because the DROP and CREATE/ALTER
instructions differ.
This commit is contained in:
Dimitri Fontaine 2016-01-17 01:54:36 +01:00
parent 7dd69a11e1
commit d9d9e06c0f
3 changed files with 37 additions and 42 deletions

View File

@ -272,21 +272,11 @@
(defun list-indexes (table)
"List all indexes for TABLE-NAME in SCHEMA. A PostgreSQL connection must
be already established when calling that function."
(let ((schema (or (table-schema table)
(cdr (assoc "search_path" *pg-settings* :test #'string-equal))))
(sql-set-search-path "SET search_path TO '';"))
;; we force the search_path to emty value so that ::regclass special
;; cast and the pg_get_indexdef() and the pg_get_contraintdef() returns
;; the fully qualified table name, even when the table is found in the
;; 'public' schema.
(log-message :debug "~a" sql-set-search-path)
(pgloader.pgsql:pgsql-execute sql-set-search-path)
(prog1
(loop
:with sql-index-list
:= (let ((sql (format nil "
(loop
:with sql-index-list
:= (let ((sql (format nil "
select i.relname,
n.nspname,
indrelid::regclass,
indrelid,
indisprimary,
@ -296,28 +286,26 @@ select i.relname,
pg_get_constraintdef(c.oid)
from pg_index x
join pg_class i ON i.oid = x.indexrelid
join pg_namespace n ON n.oid = i.relnamespace
left join pg_constraint c ON c.conindid = i.oid
where indrelid = '~:[~*public.~;~a.~]~a'::regclass"
schema schema
(table-name table))))
(log-message :debug "~a" sql)
sql)
where indrelid = '~a'::regclass"
(format-table-name table))))
(log-message :debug "~a" sql)
sql)
:for (index-name table-name table-oid primary unique sql conname condef)
:in (pomo:query sql-index-list)
:for (name schema table-name table-oid primary unique sql conname condef)
:in (pomo:query sql-index-list)
:collect (make-pgsql-index :name index-name
:table-name table-name
:table-oid table-oid
:primary primary
:unique unique
:columns nil
:sql sql
:conname (unless (eq :null conname) conname)
:condef (unless (eq :null condef) condef)))
(let ((sql-reset-search-path "reset search_path;"))
(log-message :debug "~a" sql-reset-search-path)
(pgloader.pgsql:pgsql-execute sql-reset-search-path)))))
:collect (make-pgsql-index :name name
:schema schema
:table-name table-name
:table-oid table-oid
:primary primary
:unique unique
:columns nil
:sql sql
:conname (unless (eq :null conname) conname)
:condef (unless (eq :null condef) condef))))
(defun sanitize-user-gucs (gucs)
"Forbid certain actions such as setting a client_encoding different from utf8."

View File

@ -239,7 +239,7 @@
;; the struct is used both for supporting new index creation from non
;; PostgreSQL system and for drop/create indexes when using the 'drop
;; indexes' option (in CSV mode and the like)
name table-name table-oid primary unique columns sql conname condef)
name schema table-name table-oid primary unique columns sql conname condef)
(defgeneric format-pgsql-create-index (table index)
(:documentation
@ -268,11 +268,15 @@
;; ensure good concurrency here, don't take the ACCESS EXCLUSIVE
;; LOCK on the table before we have the index done already
(or (pgsql-index-sql index)
(format nil "CREATE UNIQUE INDEX ~a ON ~a (~{~a~^, ~});"
(format nil "CREATE UNIQUE INDEX ~@[~a.~]~a ON ~a (~{~a~^, ~});"
(pgsql-index-schema index)
index-name
(format-table-name table)
(pgsql-index-columns index)))
(format nil
;; don't use the index schema name here, PostgreSQL doesn't
;; like it, might be implicit from the table's schema
;; itself...
"ALTER TABLE ~a ADD ~a USING INDEX ~a;"
(format-table-name table)
(cond ((pgsql-index-primary index) "PRIMARY KEY")
@ -286,15 +290,17 @@
(t
(or (pgsql-index-sql index)
(format nil "CREATE~:[~; UNIQUE~] INDEX ~a ON ~a (~{~a~^, ~});"
(format nil "CREATE~:[~; UNIQUE~] INDEX ~@[~a.~]~a ON ~a (~{~a~^, ~});"
(pgsql-index-unique index)
(pgsql-index-schema index)
index-name
(format-table-name table)
(pgsql-index-columns index)))))))
(defmethod format-pgsql-drop-index ((table table) (index pgsql-index))
"Generate the PostgreSQL statement to DROP the index."
(let* ((index-name (apply-identifier-case (pgsql-index-name index))))
(let* ((schema-name (apply-identifier-case (pgsql-index-schema index)))
(index-name (apply-identifier-case (pgsql-index-name index))))
(cond ((pgsql-index-conname index)
;; here always quote the constraint name, currently the name
;; comes from one source only, the PostgreSQL database catalogs,
@ -304,7 +310,7 @@
(pgsql-index-conname index)))
(t
(format nil "DROP INDEX ~a;" index-name)))))
(format nil "DROP INDEX ~@[~a.~]~a;" schema-name index-name)))))
;;;
;;; Parallel index building.

View File

@ -12,7 +12,7 @@
*/
LOAD CSV
FROM inline (a, b, c, d, e)
INTO postgresql:///pgloader?partial (a, b, c, e)
INTO postgresql:///pgloader?csv.partial (a, b, c, e)
WITH drop indexes,
fields optionally enclosed by '"',
@ -24,15 +24,16 @@ LOAD CSV
standard_conforming_strings to 'on'
BEFORE LOAD DO
$$ drop table if exists partial; $$,
$$ create table partial (
$$ drop table if exists csv.partial; $$,
$$ create table csv.partial (
a integer unique,
b text,
c text,
d text,
e text
);
$$;
$$,
$$ create index on csv.partial(b); $$ ;