pgslice 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9db8d56e7e5ea8f2b5769bea524b2db90731c8a3
4
- data.tar.gz: 4d05fabf0ded181cc1ab972988d411fb22518168
2
+ SHA256:
3
+ metadata.gz: '00404860fae8f92d17c1be36fb44f6b8fea7413644bf3f184a2431589c750abc'
4
+ data.tar.gz: db1520df2c4bd9097927cf73900785c42bebeb67f747a12a857c48fdc6ca64a9
5
5
  SHA512:
6
- metadata.gz: c698c0b5176fb902460595f5702d37ea612cc60ddc1438a164810023e540e8daf9a9cff0b505ecbc770e9e4f25c568be0daeb91f86f975fa961b42a1dec9ed10
7
- data.tar.gz: 761b3365b4bb1fe85acfd737ad18fa5e1c7938162dabf20c68d53115dfbbfa429d075d885b5bb6c7b6a3ba71fb38cb84187456c12fb0134ca06a45e08a7c3493
6
+ metadata.gz: accd820d05e151745c26cf7138394ded42f0b50f3272f051b8a154cf6dbc51271a8f810f41602138ed003bfba72a3279129638d7eb312cff4a967d6ef05bfe2e
7
+ data.tar.gz: 1b52fc649ff7f7a6832ad69236c3de3343b00cf762bfe9d935dc2be96552dfcee69e55d2ece4926e1d3b0d8a9123c970db31f706250c3d19501796c0a9a38874
@@ -1,3 +1,9 @@
1
+ ## 0.4.1
2
+
3
+ - Better support for schemas
4
+ - Use latest partition for schema
5
+ - Added support for composite primary keys
6
+
1
7
  ## 0.4.0
2
8
 
3
9
  - Added support for declarative partitioning
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016-2017 Andrew Kane
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -92,6 +92,18 @@ pgslice prep visits created_at month
92
92
  ```
93
93
 
94
94
  ```sql
95
+ -- Postgres 10
96
+
97
+ BEGIN;
98
+
99
+ CREATE TABLE visits_intermediate (LIKE visits INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING STORAGE INCLUDING COMMENTS) PARTITION BY RANGE (created_at);
100
+
101
+ COMMENT ON TABLE visits_intermediate is 'column:created_at,period:day';
102
+
103
+ COMMIT;
104
+
105
+ -- Postgres 9.6 and below
106
+
95
107
  BEGIN;
96
108
 
97
109
  CREATE TABLE visits_intermediate (LIKE visits INCLUDING ALL);
@@ -117,6 +129,32 @@ pgslice add_partitions visits --intermediate --past 1 --future 1
117
129
  ```
118
130
 
119
131
  ```sql
132
+ -- Postgres 10
133
+
134
+ BEGIN;
135
+
136
+ CREATE TABLE visits_201608 PARTITION OF visits_intermediate FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
137
+
138
+ ALTER TABLE visits_201608 ADD PRIMARY KEY (id);
139
+
140
+ CREATE INDEX ON visits_201608 USING btree (user_id);
141
+
142
+ CREATE TABLE visits_201609 PARTITION OF visits_intermediate FOR VALUES FROM ('2016-09-01') TO ('2016-10-01');
143
+
144
+ ALTER TABLE visits_201609 ADD PRIMARY KEY (id);
145
+
146
+ CREATE INDEX ON visits_201609 USING btree (user_id);
147
+
148
+ CREATE TABLE visits_201610 PARTITION OF visits_intermediate FOR VALUES FROM ('2016-10-01') TO ('2016-11-01');
149
+
150
+ ALTER TABLE visits_201610 ADD PRIMARY KEY (id);
151
+
152
+ CREATE INDEX ON visits_201610 USING btree (user_id);
153
+
154
+ COMMIT;
155
+
156
+ -- Postgres 9.6 and below
157
+
120
158
  BEGIN;
121
159
 
122
160
  CREATE TABLE visits_201608
@@ -339,7 +377,7 @@ To use master, run:
339
377
 
340
378
  ```sh
341
379
  gem install specific_install
342
- gem specific_install ankane/pgslice
380
+ gem specific_install https://github.com/ankane/pgslice.git
343
381
  ```
344
382
 
345
383
  ## Docker
@@ -54,7 +54,9 @@ module PgSlice
54
54
 
55
55
  def prep
56
56
  table, column, period = arguments
57
+ table = qualify_table(table)
57
58
  intermediate_table = "#{table}_intermediate"
59
+
58
60
  trigger_name = self.trigger_name(table)
59
61
 
60
62
  if options[:no_partition]
@@ -77,21 +79,21 @@ module PgSlice
77
79
 
78
80
  if declarative && !options[:no_partition]
79
81
  queries << <<-SQL
80
- CREATE TABLE #{quote_ident(intermediate_table)} (LIKE #{quote_ident(table)} INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING STORAGE INCLUDING COMMENTS) PARTITION BY RANGE (#{quote_ident(column)});
82
+ CREATE TABLE #{quote_table(intermediate_table)} (LIKE #{quote_table(table)} INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING STORAGE INCLUDING COMMENTS) PARTITION BY RANGE (#{quote_table(column)});
81
83
  SQL
82
84
 
83
85
  # add comment
84
86
  cast = column_cast(table, column)
85
87
  queries << <<-SQL
86
- COMMENT ON TABLE #{quote_ident(intermediate_table)} is 'column:#{column},period:#{period},cast:#{cast}';
88
+ COMMENT ON TABLE #{quote_table(intermediate_table)} is 'column:#{column},period:#{period},cast:#{cast}';
87
89
  SQL
88
90
  else
89
91
  queries << <<-SQL
90
- CREATE TABLE #{quote_ident(intermediate_table)} (LIKE #{quote_ident(table)} INCLUDING ALL);
92
+ CREATE TABLE #{quote_table(intermediate_table)} (LIKE #{quote_table(table)} INCLUDING ALL);
91
93
  SQL
92
94
 
93
95
  foreign_keys(table).each do |fk_def|
94
- queries << "ALTER TABLE #{quote_ident(intermediate_table)} ADD #{fk_def};"
96
+ queries << "ALTER TABLE #{quote_table(intermediate_table)} ADD #{fk_def};"
95
97
  end
96
98
  end
97
99
 
@@ -108,13 +110,13 @@ CREATE FUNCTION #{quote_ident(trigger_name)}()
108
110
 
109
111
  queries << <<-SQL
110
112
  CREATE TRIGGER #{quote_ident(trigger_name)}
111
- BEFORE INSERT ON #{quote_ident(intermediate_table)}
113
+ BEFORE INSERT ON #{quote_table(intermediate_table)}
112
114
  FOR EACH ROW EXECUTE PROCEDURE #{quote_ident(trigger_name)}();
113
115
  SQL
114
116
 
115
117
  cast = column_cast(table, column)
116
118
  queries << <<-SQL
117
- COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_ident(intermediate_table)} is 'column:#{column},period:#{period},cast:#{cast}';
119
+ COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_table(intermediate_table)} is 'column:#{column},period:#{period},cast:#{cast}';
118
120
  SQL
119
121
  end
120
122
 
@@ -122,7 +124,7 @@ COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_ident(intermediate_ta
122
124
  end
123
125
 
124
126
  def unprep
125
- table = arguments.first
127
+ table = qualify_table(arguments.first)
126
128
  intermediate_table = "#{table}_intermediate"
127
129
  trigger_name = self.trigger_name(table)
128
130
 
@@ -130,14 +132,14 @@ COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_ident(intermediate_ta
130
132
  abort "Table not found: #{intermediate_table}" unless table_exists?(intermediate_table)
131
133
 
132
134
  queries = [
133
- "DROP TABLE #{quote_ident(intermediate_table)} CASCADE;",
135
+ "DROP TABLE #{quote_table(intermediate_table)} CASCADE;",
134
136
  "DROP FUNCTION IF EXISTS #{quote_ident(trigger_name)}();"
135
137
  ]
136
138
  run_queries(queries)
137
139
  end
138
140
 
139
141
  def add_partitions
140
- original_table = arguments.first
142
+ original_table = qualify_table(arguments.first)
141
143
  table = options[:intermediate] ? "#{original_table}_intermediate" : original_table
142
144
  trigger_name = self.trigger_name(original_table)
143
145
 
@@ -158,7 +160,7 @@ COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_ident(intermediate_ta
158
160
  queries = []
159
161
 
160
162
  if needs_comment
161
- queries << "COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_ident(table)} is 'column:#{field},period:#{period},cast:#{cast}';"
163
+ queries << "COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_table(table)} is 'column:#{field},period:#{period},cast:#{cast}';"
162
164
  end
163
165
 
164
166
  # today = utc date
@@ -170,9 +172,10 @@ COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_ident(intermediate_ta
170
172
  elsif options[:intermediate]
171
173
  original_table
172
174
  else
173
- "#{original_table}_#{today.strftime(name_format(period))}"
175
+ existing_partitions(original_table, period).last
174
176
  end
175
- index_defs = execute("SELECT pg_get_indexdef(indexrelid) FROM pg_index WHERE indrelid = #{regclass(schema, schema_table)} AND indisprimary = 'f'").map { |r| r["pg_get_indexdef"] }
177
+
178
+ index_defs = execute("SELECT pg_get_indexdef(indexrelid) FROM pg_index WHERE indrelid = #{regclass(schema_table)} AND indisprimary = 'f'").map { |r| r["pg_get_indexdef"] }
176
179
  fk_defs = foreign_keys(schema_table)
177
180
  primary_key = self.primary_key(schema_table)
178
181
 
@@ -186,24 +189,24 @@ COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_ident(intermediate_ta
186
189
 
187
190
  if declarative
188
191
  queries << <<-SQL
189
- CREATE TABLE #{quote_ident(partition_name)} PARTITION OF #{quote_ident(table)} FOR VALUES FROM (#{sql_date(day, cast, false)}) TO (#{sql_date(advance_date(day, period, 1), cast, false)});
192
+ CREATE TABLE #{quote_table(partition_name)} PARTITION OF #{quote_table(table)} FOR VALUES FROM (#{sql_date(day, cast, false)}) TO (#{sql_date(advance_date(day, period, 1), cast, false)});
190
193
  SQL
191
194
  else
192
195
  queries << <<-SQL
193
- CREATE TABLE #{quote_ident(partition_name)}
196
+ CREATE TABLE #{quote_table(partition_name)}
194
197
  (CHECK (#{quote_ident(field)} >= #{sql_date(day, cast)} AND #{quote_ident(field)} < #{sql_date(advance_date(day, period, 1), cast)}))
195
- INHERITS (#{quote_ident(table)});
198
+ INHERITS (#{quote_table(table)});
196
199
  SQL
197
200
  end
198
201
 
199
- queries << "ALTER TABLE #{quote_ident(partition_name)} ADD PRIMARY KEY (#{quote_ident(primary_key)});" if primary_key
202
+ queries << "ALTER TABLE #{quote_table(partition_name)} ADD PRIMARY KEY (#{primary_key.map { |k| quote_ident(k) }.join(", ")});" if primary_key.any?
200
203
 
201
204
  index_defs.each do |index_def|
202
- queries << index_def.sub(/ ON \S+ USING /, " ON #{quote_ident(partition_name)} USING ").sub(/ INDEX .+ ON /, " INDEX ON ") + ";"
205
+ queries << index_def.sub(/ ON \S+ USING /, " ON #{quote_table(partition_name)} USING ").sub(/ INDEX .+ ON /, " INDEX ON ") + ";"
203
206
  end
204
207
 
205
208
  fk_defs.each do |fk_def|
206
- queries << "ALTER TABLE #{quote_ident(partition_name)} ADD #{fk_def};"
209
+ queries << "ALTER TABLE #{quote_table(partition_name)} ADD #{fk_def};"
207
210
  end
208
211
  end
209
212
 
@@ -213,7 +216,7 @@ CREATE TABLE #{quote_ident(partition_name)}
213
216
  future_defs = []
214
217
  past_defs = []
215
218
  name_format = self.name_format(period)
216
- existing_tables = existing_partitions(original_table)
219
+ existing_tables = existing_partitions(original_table, period)
217
220
  existing_tables = (existing_tables + added_partitions).uniq.sort
218
221
 
219
222
  existing_tables.each do |table|
@@ -221,7 +224,7 @@ CREATE TABLE #{quote_ident(partition_name)}
221
224
  partition_name = "#{original_table}_#{day.strftime(name_format(period))}"
222
225
 
223
226
  sql = "(NEW.#{quote_ident(field)} >= #{sql_date(day, cast)} AND NEW.#{quote_ident(field)} < #{sql_date(advance_date(day, period, 1), cast)}) THEN
224
- INSERT INTO #{quote_ident(partition_name)} VALUES (NEW.*);"
227
+ INSERT INTO #{quote_table(partition_name)} VALUES (NEW.*);"
225
228
 
226
229
  if day.to_date < today
227
230
  past_defs << sql
@@ -255,7 +258,7 @@ CREATE OR REPLACE FUNCTION #{quote_ident(trigger_name)}()
255
258
  end
256
259
 
257
260
  def fill
258
- table = arguments.first
261
+ table = qualify_table(arguments.first)
259
262
 
260
263
  abort "Usage: pgslice fill <table>" if arguments.length != 1
261
264
 
@@ -278,7 +281,7 @@ CREATE OR REPLACE FUNCTION #{quote_ident(trigger_name)}()
278
281
  if period
279
282
  name_format = self.name_format(period)
280
283
 
281
- existing_tables = existing_partitions(table)
284
+ existing_tables = existing_partitions(table, period)
282
285
  if existing_tables.any?
283
286
  starting_time = DateTime.strptime(existing_tables.first.split("_").last, name_format)
284
287
  ending_time = advance_date(DateTime.strptime(existing_tables.last.split("_").last, name_format), period, 1)
@@ -286,8 +289,10 @@ CREATE OR REPLACE FUNCTION #{quote_ident(trigger_name)}()
286
289
  end
287
290
 
288
291
  schema_table = period && declarative ? existing_tables.last : table
289
- primary_key = self.primary_key(schema_table)
292
+
293
+ primary_key = self.primary_key(schema_table)[0]
290
294
  abort "No primary key" unless primary_key
295
+
291
296
  max_source_id = max_id(source_table, primary_key)
292
297
 
293
298
  max_dest_id =
@@ -326,8 +331,8 @@ CREATE OR REPLACE FUNCTION #{quote_ident(trigger_name)}()
326
331
 
327
332
  query = <<-SQL
328
333
  /* #{i} of #{batch_count} */
329
- INSERT INTO #{quote_ident(dest_table)} (#{fields})
330
- SELECT #{fields} FROM #{quote_ident(source_table)}
334
+ INSERT INTO #{quote_table(dest_table)} (#{fields})
335
+ SELECT #{fields} FROM #{quote_table(source_table)}
331
336
  WHERE #{where}
332
337
  SQL
333
338
 
@@ -343,7 +348,7 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
343
348
  end
344
349
 
345
350
  def swap
346
- table = arguments.first
351
+ table = qualify_table(arguments.first)
347
352
  intermediate_table = intermediate_name(table)
348
353
  retired_table = retired_name(table)
349
354
 
@@ -353,8 +358,8 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
353
358
  abort "Table already exists: #{retired_table}" if table_exists?(retired_table)
354
359
 
355
360
  queries = [
356
- "ALTER TABLE #{quote_ident(table)} RENAME TO #{quote_ident(retired_table)};",
357
- "ALTER TABLE #{quote_ident(intermediate_table)} RENAME TO #{quote_ident(table)};"
361
+ "ALTER TABLE #{quote_table(table)} RENAME TO #{quote_no_schema(retired_table)};",
362
+ "ALTER TABLE #{quote_table(intermediate_table)} RENAME TO #{quote_no_schema(table)};"
358
363
  ]
359
364
 
360
365
  self.sequences(table).each do |sequence|
@@ -367,7 +372,7 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
367
372
  end
368
373
 
369
374
  def unswap
370
- table = arguments.first
375
+ table = qualify_table(arguments.first)
371
376
  intermediate_table = intermediate_name(table)
372
377
  retired_table = retired_name(table)
373
378
 
@@ -377,8 +382,8 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
377
382
  abort "Table already exists: #{intermediate_table}" if table_exists?(intermediate_table)
378
383
 
379
384
  queries = [
380
- "ALTER TABLE #{quote_ident(table)} RENAME TO #{quote_ident(intermediate_table)};",
381
- "ALTER TABLE #{quote_ident(retired_table)} RENAME TO #{quote_ident(table)};"
385
+ "ALTER TABLE #{quote_table(table)} RENAME TO #{quote_no_schema(intermediate_table)};",
386
+ "ALTER TABLE #{quote_table(retired_table)} RENAME TO #{quote_no_schema(table)};"
382
387
  ]
383
388
 
384
389
  self.sequences(table).each do |sequence|
@@ -389,14 +394,14 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
389
394
  end
390
395
 
391
396
  def analyze
392
- table = arguments.first
397
+ table = qualify_table(arguments.first)
393
398
  parent_table = options[:swapped] ? table : intermediate_name(table)
394
399
 
395
400
  abort "Usage: pgslice analyze <table>" if arguments.length != 1
396
401
 
397
402
  existing_tables = existing_partitions(table)
398
403
  analyze_list = existing_tables + [parent_table]
399
- run_queries_without_transaction analyze_list.map { |t| "ANALYZE VERBOSE #{quote_ident(t)};" }
404
+ run_queries_without_transaction analyze_list.map { |t| "ANALYZE VERBOSE #{quote_table(t)};" }
400
405
  end
401
406
 
402
407
  # arguments
@@ -508,13 +513,23 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
508
513
  execute("SHOW server_version_num")[0]["server_version_num"].to_i
509
514
  end
510
515
 
511
- def existing_partitions(table)
512
- existing_tables(like: "#{table}_%").select { |t| /\A#{Regexp.escape("#{table}_")}\d{6,8}\z/.match(t) }
516
+ def existing_partitions(table, period = nil)
517
+ count =
518
+ case period
519
+ when "day"
520
+ 8
521
+ when "month"
522
+ 6
523
+ else
524
+ "6,8"
525
+ end
526
+
527
+ existing_tables(like: "#{table}_%").select { |t| /\A#{Regexp.escape("#{table}_")}\d{#{count}}\z/.match(t) }
513
528
  end
514
529
 
515
530
  def existing_tables(like:)
516
- query = "SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = $1 AND tablename LIKE $2"
517
- execute(query, [schema, like]).map { |r| r["tablename"] }.sort
531
+ query = "SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE schemaname = $1 AND tablename LIKE $2"
532
+ execute(query, like.split(".", 2)).map { |r| "#{r["schemaname"]}.#{r["tablename"]}" }.sort
518
533
  end
519
534
 
520
535
  def table_exists?(table)
@@ -522,7 +537,7 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
522
537
  end
523
538
 
524
539
  def columns(table)
525
- execute("SELECT column_name FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2", [schema, table]).map{ |r| r["column_name"] }
540
+ execute("SELECT column_name FROM information_schema.columns WHERE table_schema || '.' || table_name = $1", [table]).map{ |r| r["column_name"] }
526
541
  end
527
542
 
528
543
  # http://stackoverflow.com/a/20537829
@@ -534,20 +549,18 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
534
549
  FROM
535
550
  pg_index, pg_class, pg_attribute, pg_namespace
536
551
  WHERE
537
- relname = $2 AND
552
+ nspname || '.' || relname = $1 AND
538
553
  indrelid = pg_class.oid AND
539
- nspname = $1 AND
540
554
  pg_class.relnamespace = pg_namespace.oid AND
541
555
  pg_attribute.attrelid = pg_class.oid AND
542
556
  pg_attribute.attnum = any(pg_index.indkey) AND
543
557
  indisprimary
544
558
  SQL
545
- row = execute(query, [schema, table])[0]
546
- row && row["attname"]
559
+ execute(query, [table]).map { |r| r["attname"] }
547
560
  end
548
561
 
549
562
  def max_id(table, primary_key, below: nil, where: nil)
550
- query = "SELECT MAX(#{quote_ident(primary_key)}) FROM #{quote_ident(table)}"
563
+ query = "SELECT MAX(#{quote_ident(primary_key)}) FROM #{quote_table(table)}"
551
564
  conditions = []
552
565
  conditions << "#{quote_ident(primary_key)} <= #{below}" if below
553
566
  conditions << where if where
@@ -556,7 +569,7 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
556
569
  end
557
570
 
558
571
  def min_id(table, primary_key, column, cast, starting_time, where)
559
- query = "SELECT MIN(#{quote_ident(primary_key)}) FROM #{quote_ident(table)}"
572
+ query = "SELECT MIN(#{quote_ident(primary_key)}) FROM #{quote_table(table)}"
560
573
  conditions = []
561
574
  conditions << "#{quote_ident(column)} >= #{sql_date(starting_time, cast)}" if starting_time
562
575
  conditions << where if where
@@ -569,7 +582,7 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
569
582
  end
570
583
 
571
584
  def fetch_comment(table)
572
- execute("SELECT obj_description(#{regclass(schema, table)}) AS comment")[0]
585
+ execute("SELECT obj_description(#{regclass(table)}) AS comment")[0]
573
586
  end
574
587
 
575
588
  # http://www.dbforums.com/showthread.php?1667561-How-to-list-sequences-and-the-columns-by-SQL
@@ -593,7 +606,7 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
593
606
  # helpers
594
607
 
595
608
  def trigger_name(table)
596
- "#{table}_insert_trigger"
609
+ "#{table.split(".")[-1]}_insert_trigger"
597
610
  end
598
611
 
599
612
  def intermediate_name(table)
@@ -605,7 +618,7 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
605
618
  end
606
619
 
607
620
  def column_cast(table, column)
608
- data_type = execute("SELECT data_type FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 AND column_name = $3", [schema, table, column])[0]["data_type"]
621
+ data_type = execute("SELECT data_type FROM information_schema.columns WHERE table_schema || '.' || table_name = $1 AND column_name = $2", [table, column])[0]["data_type"]
609
622
  data_type == "timestamp with time zone" ? "timestamptz" : "date"
610
623
  end
611
624
 
@@ -652,12 +665,24 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
652
665
  PG::Connection.quote_ident(value)
653
666
  end
654
667
 
655
- def regclass(schema, table)
656
- "'#{quote_ident(schema)}.#{quote_ident(table)}'::regclass"
668
+ def quote_table(table)
669
+ table.split(".", 2).map { |v| quote_ident(v) }.join(".")
670
+ end
671
+
672
+ def quote_no_schema(table)
673
+ quote_ident(table.split(".", 2)[-1])
674
+ end
675
+
676
+ def regclass(table)
677
+ "'#{quote_table(table)}'::regclass"
657
678
  end
658
679
 
659
680
  def fetch_trigger(trigger_name, table)
660
- execute("SELECT obj_description(oid, 'pg_trigger') AS comment FROM pg_trigger WHERE tgname = $1 AND tgrelid = #{regclass(schema, table)}", [trigger_name])[0]
681
+ execute("SELECT obj_description(oid, 'pg_trigger') AS comment FROM pg_trigger WHERE tgname = $1 AND tgrelid = #{regclass(table)}", [trigger_name])[0]
682
+ end
683
+
684
+ def qualify_table(table)
685
+ table.to_s.include?(".") ? table : [schema, table].join(".")
661
686
  end
662
687
 
663
688
  def settings_from_trigger(original_table, table)
@@ -692,7 +717,7 @@ INSERT INTO #{quote_ident(dest_table)} (#{fields})
692
717
  end
693
718
 
694
719
  def foreign_keys(table)
695
- execute("SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conrelid = #{regclass(schema, table)} AND contype ='f'").map { |r| r["pg_get_constraintdef"] }
720
+ execute("SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conrelid = #{regclass(table)} AND contype ='f'").map { |r| r["pg_get_constraintdef"] }
696
721
  end
697
722
 
698
723
  def server_version_num
@@ -1,3 +1,3 @@
1
1
  module PgSlice
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -11,6 +11,7 @@ Gem::Specification.new do |spec|
11
11
 
12
12
  spec.summary = "Postgres partitioning as easy as pie"
13
13
  spec.homepage = "https://github.com/ankane/pgslice"
14
+ spec.license = "MIT"
14
15
 
15
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
17
  spec.bindir = "exe"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgslice
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-10-07 00:00:00.000000000 Z
11
+ date: 2018-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop
@@ -93,6 +93,7 @@ files:
93
93
  - CHANGELOG.md
94
94
  - Dockerfile
95
95
  - Gemfile
96
+ - LICENSE.txt
96
97
  - README.md
97
98
  - Rakefile
98
99
  - exe/pgslice
@@ -100,7 +101,8 @@ files:
100
101
  - lib/pgslice/version.rb
101
102
  - pgslice.gemspec
102
103
  homepage: https://github.com/ankane/pgslice
103
- licenses: []
104
+ licenses:
105
+ - MIT
104
106
  metadata: {}
105
107
  post_install_message:
106
108
  rdoc_options: []
@@ -118,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
120
  version: '0'
119
121
  requirements: []
120
122
  rubyforge_project:
121
- rubygems_version: 2.6.13
123
+ rubygems_version: 2.7.6
122
124
  signing_key:
123
125
  specification_version: 4
124
126
  summary: Postgres partitioning as easy as pie