pgslice 0.3.4 → 0.3.5

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
2
  SHA1:
3
- metadata.gz: 24b5596e6ea1c788ff5b367fb6ca05b0c76e626f
4
- data.tar.gz: a6776fcdf658bd08f4a6adbeee3239b602eba91d
3
+ metadata.gz: 43cc2dd89adcb7a9ab6967e5d87b28d24e7e8c26
4
+ data.tar.gz: f9661b8e3cdf0239c0ba2174bc0c5694f95d834a
5
5
  SHA512:
6
- metadata.gz: 5bb36f0e164418e57d54ebf9bb0192d75bf20977261fc6e83ff613d15afe3199aace4a0af343f8784518e6b4e460b245ba6029e61e427c5abd0405fff8a70acf
7
- data.tar.gz: da11ed42838cd526441469108892379aadbee43bfcbaa657568b8d7c0721b19e5bc275af330bfd1e924c1bb54ae2109751ab62b207dc440332231b2277b7fa32
6
+ metadata.gz: 41176b19e45fd47d89d50f45b4a4cf9ab5802ed63b68100852e776dc0c821745a85cb80b2f942e5a445fa5752b696c0dce5a6fe6528477f26ec3673d41cbe94f
7
+ data.tar.gz: 04d50a9863351b4b97928e8dfb5f8a018c5723e5daa473a4430c5ed41ff9db355ebb4d1f749a48ebc5eb3ebc7e88e84a8ab795edd394fbd351219a09d30071b8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.3.5
2
+
3
+ - Quote identifiers
4
+
1
5
  ## 0.3.4
2
6
 
3
7
  - Added `analyze` method
data/README.md CHANGED
@@ -181,6 +181,20 @@ INSERT INTO visits_intermediate ("id", "user_id", "ip", "created_at")
181
181
  WHERE id > 20000 AND id <= 30000 AND created_at >= '2016-08-01'::date AND created_at < '2016-11-01'::date
182
182
  ```
183
183
 
184
+ ```sh
185
+ pgslice analyze visits
186
+ ```
187
+
188
+ ```sql
189
+ ANALYZE VERBOSE visits_201608;
190
+
191
+ ANALYZE VERBOSE visits_201609;
192
+
193
+ ANALYZE VERBOSE visits_201610;
194
+
195
+ ANALYZE VERBOSE visits_intermediate;
196
+ ```
197
+
184
198
  ```sh
185
199
  pgslice swap visits
186
200
  ```
data/lib/pgslice.rb CHANGED
@@ -73,13 +73,13 @@ module PgSlice
73
73
  queries = []
74
74
 
75
75
  queries << <<-SQL
76
- CREATE TABLE #{intermediate_table} (LIKE #{table} INCLUDING ALL);
76
+ CREATE TABLE #{quote_ident(intermediate_table)} (LIKE #{quote_ident(table)} INCLUDING ALL);
77
77
  SQL
78
78
 
79
79
  unless options[:no_partition]
80
80
  sql_format = SQL_FORMAT[period.to_sym]
81
81
  queries << <<-SQL
82
- CREATE FUNCTION #{trigger_name}()
82
+ CREATE FUNCTION #{quote_ident(trigger_name)}()
83
83
  RETURNS trigger AS $$
84
84
  BEGIN
85
85
  RAISE EXCEPTION 'Create partitions first.';
@@ -88,14 +88,14 @@ CREATE FUNCTION #{trigger_name}()
88
88
  SQL
89
89
 
90
90
  queries << <<-SQL
91
- CREATE TRIGGER #{trigger_name}
92
- BEFORE INSERT ON #{intermediate_table}
93
- FOR EACH ROW EXECUTE PROCEDURE #{trigger_name}();
91
+ CREATE TRIGGER #{quote_ident(trigger_name)}
92
+ BEFORE INSERT ON #{quote_ident(intermediate_table)}
93
+ FOR EACH ROW EXECUTE PROCEDURE #{quote_ident(trigger_name)}();
94
94
  SQL
95
95
 
96
96
  cast = column_cast(table, column)
97
97
  queries << <<-SQL
98
- COMMENT ON TRIGGER #{trigger_name} ON #{intermediate_table} is 'column:#{column},period:#{period},cast:#{cast}';
98
+ COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_ident(intermediate_table)} is 'column:#{column},period:#{period},cast:#{cast}';
99
99
  SQL
100
100
  end
101
101
 
@@ -111,7 +111,7 @@ SQL
111
111
  abort "Table not found: #{intermediate_table}" unless table_exists?(intermediate_table)
112
112
 
113
113
  queries = [
114
- "DROP TABLE #{intermediate_table} CASCADE;",
114
+ "DROP TABLE #{quote_ident(intermediate_table)} CASCADE;",
115
115
  "DROP FUNCTION IF EXISTS #{trigger_name}();"
116
116
  ]
117
117
  run_queries(queries)
@@ -132,7 +132,7 @@ SQL
132
132
  # ensure table has trigger
133
133
  abort "No trigger on table: #{table}\nDid you mean to use --intermediate?" unless has_trigger?(trigger_name, table)
134
134
 
135
- index_defs = execute("select pg_get_indexdef(indexrelid) from pg_index where indrelid = $1::regclass AND indisprimary = 'f'", [original_table]).map { |r| r["pg_get_indexdef"] }
135
+ index_defs = execute("SELECT pg_get_indexdef(indexrelid) FROM pg_index INNER JOIN pg_stat_user_indexes USING (indexrelid) WHERE relname = $1 AND schemaname = $2 AND indisprimary = 'f'", [original_table, schema]).map { |r| r["pg_get_indexdef"] }
136
136
  primary_key = self.primary_key(table)
137
137
 
138
138
  queries = []
@@ -141,7 +141,7 @@ SQL
141
141
  abort "Could not read settings" unless period
142
142
 
143
143
  if needs_comment
144
- queries << "COMMENT ON TRIGGER #{trigger_name} ON #{table} is 'column:#{field},period:#{period},cast:#{cast}';"
144
+ queries << "COMMENT ON TRIGGER #{quote_ident(trigger_name)} ON #{quote_ident(table)} is 'column:#{field},period:#{period},cast:#{cast}';"
145
145
  end
146
146
 
147
147
  # today = utc date
@@ -155,12 +155,12 @@ SQL
155
155
  added_partitions << partition_name
156
156
 
157
157
  queries << <<-SQL
158
- CREATE TABLE #{partition_name}
159
- (CHECK (#{field} >= #{sql_date(day, cast)} AND #{field} < #{sql_date(advance_date(day, period, 1), cast)}))
160
- INHERITS (#{table});
158
+ CREATE TABLE #{quote_ident(partition_name)}
159
+ (CHECK (#{quote_ident(field)} >= #{sql_date(day, cast)} AND #{quote_ident(field)} < #{sql_date(advance_date(day, period, 1), cast)}))
160
+ INHERITS (#{quote_ident(table)});
161
161
  SQL
162
162
 
163
- queries << "ALTER TABLE #{partition_name} ADD PRIMARY KEY (#{primary_key});" if primary_key
163
+ queries << "ALTER TABLE #{quote_ident(partition_name)} ADD PRIMARY KEY (#{quote_ident(primary_key)});" if primary_key
164
164
 
165
165
  index_defs.each do |index_def|
166
166
  queries << index_def.sub(" ON #{original_table} USING ", " ON #{partition_name} USING ").sub(/ INDEX .+ ON /, " INDEX ON ") + ";"
@@ -179,8 +179,8 @@ CREATE TABLE #{partition_name}
179
179
  day = DateTime.strptime(table.split("_").last, name_format)
180
180
  partition_name = "#{original_table}_#{day.strftime(name_format(period))}"
181
181
 
182
- sql = "(NEW.#{field} >= #{sql_date(day, cast)} AND NEW.#{field} < #{sql_date(advance_date(day, period, 1), cast)}) THEN
183
- INSERT INTO #{partition_name} VALUES (NEW.*);"
182
+ sql = "(NEW.#{quote_ident(field)} >= #{sql_date(day, cast)} AND NEW.#{quote_ident(field)} < #{sql_date(advance_date(day, period, 1), cast)}) THEN
183
+ INSERT INTO #{quote_ident(partition_name)} VALUES (NEW.*);"
184
184
 
185
185
  if day.to_date < today
186
186
  past_defs << sql
@@ -196,7 +196,7 @@ CREATE TABLE #{partition_name}
196
196
 
197
197
  if trigger_defs.any?
198
198
  queries << <<-SQL
199
- CREATE OR REPLACE FUNCTION #{trigger_name}()
199
+ CREATE OR REPLACE FUNCTION #{quote_ident(trigger_name)}()
200
200
  RETURNS trigger AS $$
201
201
  BEGIN
202
202
  IF #{trigger_defs.join("\n ELSIF ")}
@@ -262,7 +262,7 @@ CREATE OR REPLACE FUNCTION #{trigger_name}()
262
262
  end
263
263
 
264
264
  starting_id = max_dest_id
265
- fields = columns(source_table).map { |c| PG::Connection.quote_ident(c) }.join(", ")
265
+ fields = columns(source_table).map { |c| quote_ident(c) }.join(", ")
266
266
  batch_size = options[:batch_size]
267
267
 
268
268
  i = 1
@@ -273,9 +273,9 @@ CREATE OR REPLACE FUNCTION #{trigger_name}()
273
273
  end
274
274
 
275
275
  while starting_id < max_source_id
276
- where = "#{primary_key} > #{starting_id} AND #{primary_key} <= #{starting_id + batch_size}"
276
+ where = "#{quote_ident(primary_key)} > #{starting_id} AND #{quote_ident(primary_key)} <= #{starting_id + batch_size}"
277
277
  if starting_time
278
- where << " AND #{field} >= #{sql_date(starting_time, cast)} AND #{field} < #{sql_date(ending_time, cast)}"
278
+ where << " AND #{quote_ident(field)} >= #{sql_date(starting_time, cast)} AND #{quote_ident(field)} < #{sql_date(ending_time, cast)}"
279
279
  end
280
280
  if options[:where]
281
281
  where << " AND #{options[:where]}"
@@ -283,8 +283,8 @@ CREATE OR REPLACE FUNCTION #{trigger_name}()
283
283
 
284
284
  query = <<-SQL
285
285
  /* #{i} of #{batch_count} */
286
- INSERT INTO #{dest_table} (#{fields})
287
- SELECT #{fields} FROM #{source_table}
286
+ INSERT INTO #{quote_ident(dest_table)} (#{fields})
287
+ SELECT #{fields} FROM #{quote_ident(source_table)}
288
288
  WHERE #{where}
289
289
  SQL
290
290
 
@@ -310,12 +310,12 @@ INSERT INTO #{dest_table} (#{fields})
310
310
  abort "Table already exists: #{retired_table}" if table_exists?(retired_table)
311
311
 
312
312
  queries = [
313
- "ALTER TABLE #{table} RENAME TO #{retired_table};",
314
- "ALTER TABLE #{intermediate_table} RENAME TO #{table};"
313
+ "ALTER TABLE #{quote_ident(table)} RENAME TO #{quote_ident(retired_table)};",
314
+ "ALTER TABLE #{quote_ident(intermediate_table)} RENAME TO #{quote_ident(table)};"
315
315
  ]
316
316
 
317
317
  self.sequences(table).each do |sequence|
318
- queries << "ALTER SEQUENCE #{sequence["sequence_name"]} OWNED BY #{table}.#{sequence["related_column"]};"
318
+ queries << "ALTER SEQUENCE #{quote_ident(sequence["sequence_name"])} OWNED BY #{table}.#{sequence["related_column"]};"
319
319
  end
320
320
 
321
321
  queries.unshift("SET LOCAL lock_timeout = '#{options[:lock_timeout]}';") if server_version_num >= 90300
@@ -334,12 +334,12 @@ INSERT INTO #{dest_table} (#{fields})
334
334
  abort "Table already exists: #{intermediate_table}" if table_exists?(intermediate_table)
335
335
 
336
336
  queries = [
337
- "ALTER TABLE #{table} RENAME TO #{intermediate_table};",
338
- "ALTER TABLE #{retired_table} RENAME TO #{table};"
337
+ "ALTER TABLE #{quote_ident(table)} RENAME TO #{quote_ident(intermediate_table)};",
338
+ "ALTER TABLE #{quote_ident(retired_table)} RENAME TO #{quote_ident(table)};"
339
339
  ]
340
340
 
341
341
  self.sequences(table).each do |sequence|
342
- queries << "ALTER SEQUENCE #{sequence["sequence_name"]} OWNED BY #{table}.#{sequence["related_column"]};"
342
+ queries << "ALTER SEQUENCE #{quote_ident(sequence["sequence_name"])} OWNED BY #{table}.#{sequence["related_column"]};"
343
343
  end
344
344
 
345
345
  run_queries(queries)
@@ -353,7 +353,7 @@ INSERT INTO #{dest_table} (#{fields})
353
353
 
354
354
  existing_tables = self.existing_tables(like: "#{table}_%").select { |t| /\A#{Regexp.escape("#{table}_")}\d{6,8}\z/.match(t) }
355
355
  analyze_list = existing_tables + [parent_table]
356
- run_queries_without_transaction analyze_list.map { |t| "ANALYZE VERBOSE #{t};" }
356
+ run_queries_without_transaction analyze_list.map { |t| "ANALYZE VERBOSE #{quote_ident(t)};" }
357
357
  end
358
358
 
359
359
  # arguments
@@ -486,7 +486,7 @@ INSERT INTO #{dest_table} (#{fields})
486
486
  FROM
487
487
  pg_index, pg_class, pg_attribute, pg_namespace
488
488
  WHERE
489
- pg_class.oid = $2::regclass AND
489
+ relname = $2 AND
490
490
  indrelid = pg_class.oid AND
491
491
  nspname = $1 AND
492
492
  pg_class.relnamespace = pg_namespace.oid AND
@@ -499,25 +499,25 @@ INSERT INTO #{dest_table} (#{fields})
499
499
  end
500
500
 
501
501
  def max_id(table, primary_key, below: nil, where: nil)
502
- query = "SELECT MAX(#{primary_key}) FROM #{table}"
502
+ query = "SELECT MAX(#{quote_ident(primary_key)}) FROM #{quote_ident(table)}"
503
503
  conditions = []
504
- conditions << "#{primary_key} <= #{below}" if below
504
+ conditions << "#{quote_ident(primary_key)} <= #{below}" if below
505
505
  conditions << where if where
506
506
  query << " WHERE #{conditions.join(" AND ")}" if conditions.any?
507
507
  execute(query)[0]["max"].to_i
508
508
  end
509
509
 
510
510
  def min_id(table, primary_key, column, cast, starting_time, where)
511
- query = "SELECT MIN(#{primary_key}) FROM #{table}"
511
+ query = "SELECT MIN(#{quote_ident(primary_key)}) FROM #{quote_ident(table)}"
512
512
  conditions = []
513
- conditions << "#{column} >= #{sql_date(starting_time, cast)}" if starting_time
513
+ conditions << "#{quote_ident(column)} >= #{sql_date(starting_time, cast)}" if starting_time
514
514
  conditions << where if where
515
515
  query << " WHERE #{conditions.join(" AND ")}" if conditions.any?
516
516
  (execute(query)[0]["min"] || 1).to_i
517
517
  end
518
518
 
519
519
  def has_trigger?(trigger_name, table)
520
- execute("SELECT 1 FROM pg_trigger WHERE tgname = $1 AND tgrelid = $2::regclass", [trigger_name, table]).any?
520
+ !fetch_trigger(trigger_name, table).nil?
521
521
  end
522
522
 
523
523
  # http://www.dbforums.com/showthread.php?1667561-How-to-list-sequences-and-the-columns-by-SQL
@@ -595,11 +595,19 @@ INSERT INTO #{dest_table} (#{fields})
595
595
  end
596
596
  end
597
597
 
598
+ def quote_ident(value)
599
+ PG::Connection.quote_ident(value)
600
+ end
601
+
602
+ def fetch_trigger(trigger_name, table)
603
+ execute("SELECT obj_description(oid, 'pg_trigger') AS comment FROM pg_trigger WHERE tgname = $1 AND EXISTS (SELECT 1 FROM pg_stat_user_tables WHERE relid = tgrelid AND relname = $2 AND schemaname = $3)", [trigger_name, table, schema])[0]
604
+ end
605
+
598
606
  def settings_from_trigger(original_table, table)
599
607
  trigger_name = self.trigger_name(original_table)
600
608
 
601
609
  needs_comment = false
602
- comment = execute("SELECT obj_description(oid, 'pg_trigger') AS comment FROM pg_trigger WHERE tgname = $1 AND tgrelid = $2::regclass", [trigger_name, table])[0]
610
+ comment = fetch_trigger(trigger_name, table)
603
611
  if comment
604
612
  field, period, cast = comment["comment"].split(",").map { |v| v.split(":").last } rescue [nil, nil, nil]
605
613
  end
@@ -1,3 +1,3 @@
1
1
  module PgSlice
2
- VERSION = "0.3.4"
2
+ VERSION = "0.3.5"
3
3
  end
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.3.4
4
+ version: 0.3.5
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-07-06 00:00:00.000000000 Z
11
+ date: 2017-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop