autocompl 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/lib/autocompl/repository.rb +11 -1
  3. data/lib/autocompl/version.rb +1 -1
  4. data/test/dummy/log/development.log +467 -0
  5. data/test/dummy/log/test.log +3 -0
  6. data/test/dummy/vendor/bundle/ruby/2.3.0/bin/console +23 -0
  7. data/test/dummy/vendor/bundle/ruby/2.3.0/cache/pg-0.19.0.gem +0 -0
  8. data/test/dummy/vendor/bundle/ruby/2.3.0/cache/pq-0.0.1.gem +0 -0
  9. data/test/dummy/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/pg-0.19.0/gem.build_complete +0 -0
  10. data/test/dummy/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/pg-0.19.0/gem_make.out +78 -0
  11. data/test/dummy/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/pg-0.19.0/mkmf.log +1346 -0
  12. data/test/dummy/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/pg-0.19.0/pg_ext.bundle +0 -0
  13. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/BSDL +22 -0
  14. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ChangeLog +6378 -0
  15. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/Contributors.rdoc +46 -0
  16. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/History.rdoc +363 -0
  17. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/LICENSE +56 -0
  18. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/Manifest.txt +85 -0
  19. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/POSTGRES +23 -0
  20. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/README-OS_X.rdoc +68 -0
  21. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/README-Windows.rdoc +56 -0
  22. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/README.ja.rdoc +14 -0
  23. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/README.rdoc +168 -0
  24. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/Rakefile +216 -0
  25. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/Rakefile.cross +301 -0
  26. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/Makefile +261 -0
  27. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/errorcodes.def +947 -0
  28. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/errorcodes.rb +45 -0
  29. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/errorcodes.txt +467 -0
  30. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/extconf.h +38 -0
  31. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/extconf.rb +112 -0
  32. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/gvl_wrappers.c +13 -0
  33. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/gvl_wrappers.h +257 -0
  34. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/gvl_wrappers.o +0 -0
  35. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg.c +667 -0
  36. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg.h +395 -0
  37. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg.o +0 -0
  38. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_binary_decoder.c +162 -0
  39. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_binary_decoder.o +0 -0
  40. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_binary_encoder.c +162 -0
  41. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_binary_encoder.o +0 -0
  42. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_coder.c +500 -0
  43. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_coder.o +0 -0
  44. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_connection.c +4102 -0
  45. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_connection.o +0 -0
  46. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_copy_coder.c +591 -0
  47. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_copy_coder.o +0 -0
  48. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_errors.c +95 -0
  49. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_errors.o +0 -0
  50. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_ext.bundle +0 -0
  51. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_result.c +1271 -0
  52. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_result.o +0 -0
  53. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_text_decoder.c +421 -0
  54. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_text_decoder.o +0 -0
  55. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_text_encoder.c +683 -0
  56. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_text_encoder.o +0 -0
  57. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map.c +159 -0
  58. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map.o +0 -0
  59. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_all_strings.c +116 -0
  60. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_all_strings.o +0 -0
  61. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_class.c +239 -0
  62. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_class.o +0 -0
  63. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_column.c +312 -0
  64. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_column.o +0 -0
  65. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_mri_type.c +284 -0
  66. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_mri_type.o +0 -0
  67. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_oid.c +355 -0
  68. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_by_oid.o +0 -0
  69. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_in_ruby.c +299 -0
  70. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/pg_type_map_in_ruby.o +0 -0
  71. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/util.c +149 -0
  72. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/util.h +65 -0
  73. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/util.o +0 -0
  74. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/vc/pg.sln +26 -0
  75. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/vc/pg_18/pg.vcproj +216 -0
  76. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/ext/vc/pg_19/pg_19.vcproj +209 -0
  77. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg.rb +64 -0
  78. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/basic_type_mapping.rb +426 -0
  79. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/coder.rb +83 -0
  80. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/connection.rb +271 -0
  81. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/constants.rb +11 -0
  82. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/exceptions.rb +11 -0
  83. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/result.rb +30 -0
  84. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/text_decoder.rb +51 -0
  85. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/text_encoder.rb +35 -0
  86. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg/type_map_by_column.rb +15 -0
  87. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/lib/pg_ext.bundle +0 -0
  88. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/array_insert.rb +20 -0
  89. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/async_api.rb +106 -0
  90. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/async_copyto.rb +39 -0
  91. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/async_mixed.rb +56 -0
  92. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/check_conn.rb +21 -0
  93. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/copyfrom.rb +81 -0
  94. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/copyto.rb +19 -0
  95. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/cursor.rb +21 -0
  96. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/disk_usage_report.rb +186 -0
  97. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/issue-119.rb +94 -0
  98. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/losample.rb +69 -0
  99. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/minimal-testcase.rb +17 -0
  100. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/notify_wait.rb +72 -0
  101. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/pg_statistics.rb +294 -0
  102. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/replication_monitor.rb +231 -0
  103. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/test_binary_values.rb +33 -0
  104. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/wal_shipper.rb +434 -0
  105. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/sample/warehouse_partitions.rb +320 -0
  106. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/data/expected_trace.out +26 -0
  107. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/data/random_binary_data +0 -0
  108. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/helpers.rb +352 -0
  109. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/basic_type_mapping_spec.rb +305 -0
  110. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/connection_spec.rb +1676 -0
  111. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/result_spec.rb +449 -0
  112. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_by_class_spec.rb +138 -0
  113. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_by_column_spec.rb +222 -0
  114. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  115. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_by_oid_spec.rb +149 -0
  116. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_in_ruby_spec.rb +164 -0
  117. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_map_spec.rb +22 -0
  118. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg/type_spec.rb +777 -0
  119. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pg-0.19.0/spec/pg_spec.rb +50 -0
  120. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/Gemfile +4 -0
  121. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/LICENSE.txt +22 -0
  122. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/README.md +76 -0
  123. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/Rakefile +1 -0
  124. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/bin/console +7 -0
  125. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/lib/pq.rb +99 -0
  126. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/pq.gemspec +29 -0
  127. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/spec/helpers.rb +10 -0
  128. data/test/dummy/vendor/bundle/ruby/2.3.0/gems/pq-0.0.1/spec/queue_spec.rb +84 -0
  129. data/test/dummy/vendor/bundle/ruby/2.3.0/specifications/pg-0.19.0.gemspec +63 -0
  130. data/test/dummy/vendor/bundle/ruby/2.3.0/specifications/pq-0.0.1.gemspec +49 -0
  131. metadata +253 -1
@@ -0,0 +1,320 @@
1
+ #!/usr/bin/env ruby
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ #
4
+ # Script to automatically move partitioned tables and their indexes
5
+ # to a separate area on disk.
6
+ #
7
+ # Mahlon E. Smith <mahlon@martini.nu>
8
+ #
9
+ # Example use case:
10
+ #
11
+ # - You've got a heavy insert table, such as syslog data.
12
+ # - This table has a partitioning trigger (or is manually partitioned)
13
+ # by date, to separate incoming stuff from archival/report stuff.
14
+ # - You have a tablespace on cheap or slower disk (maybe even
15
+ # ZFS compressed, or some such!)
16
+ #
17
+ # The only assumption this script makes is that your tables are dated, and
18
+ # the tablespace they're moving into already exists.
19
+ #
20
+ # A full example, using the syslog idea from above, where each child
21
+ # table is date partitioned by a convention of "syslog_YEAR-WEEKOFYEAR":
22
+ #
23
+ # syslog # <--- parent
24
+ # syslog_2012_06 # <--- inherited
25
+ # syslog_2012_07 # <--- inherited
26
+ # syslog_2012_08 # <--- inherited
27
+ # ...
28
+ #
29
+ # You'd run this script like so:
30
+ #
31
+ # ./warehouse_partitions.rb -F syslog_%Y_%U
32
+ #
33
+ # Assuming this was week 12 of the year, tables syslog_2012_06 through
34
+ # syslog_2012_11 would start sequentially migrating into the tablespace
35
+ # called 'warehouse'.
36
+ #
37
+
38
+
39
+ begin
40
+ require 'date'
41
+ require 'ostruct'
42
+ require 'optparse'
43
+ require 'pathname'
44
+ require 'etc'
45
+ require 'pg'
46
+
47
+ rescue LoadError # 1.8 support
48
+ unless Object.const_defined?( :Gem )
49
+ require 'rubygems'
50
+ retry
51
+ end
52
+ raise
53
+ end
54
+
55
+
56
+ ### A tablespace migration class.
57
+ ###
58
+ class PGWarehouse
59
+
60
+ def initialize( opts )
61
+ @opts = opts
62
+ @db = PG.connect(
63
+ :dbname => opts.database,
64
+ :host => opts.host,
65
+ :port => opts.port,
66
+ :user => opts.user,
67
+ :password => opts.pass,
68
+ :sslmode => 'prefer'
69
+ )
70
+ @db.exec "SET search_path TO %s" % [ opts.schema ] if opts.schema
71
+
72
+ @relations = self.relations
73
+ end
74
+
75
+ attr_reader :db
76
+
77
+ ######
78
+ public
79
+ ######
80
+
81
+ ### Perform the tablespace moves.
82
+ ###
83
+ def migrate
84
+ if @relations.empty?
85
+ $stderr.puts 'No tables were found for warehousing.'
86
+ return
87
+ end
88
+
89
+ $stderr.puts "Found %d relation%s to move." % [ relations.length, relations.length == 1 ? '' : 's' ]
90
+ @relations.sort_by{|_,v| v[:name] }.each do |_, val|
91
+ $stderr.print " - Moving table '%s' to '%s'... " % [
92
+ val[:name], @opts.tablespace
93
+ ]
94
+
95
+ if @opts.dryrun
96
+ $stderr.puts '(not really)'
97
+
98
+ else
99
+ age = self.timer do
100
+ db.exec "ALTER TABLE %s SET TABLESPACE %s;" % [
101
+ val[:name], @opts.tablespace
102
+ ]
103
+ end
104
+ puts age
105
+ end
106
+
107
+ val[ :indexes ].each do |idx|
108
+ $stderr.print " - Moving index '%s' to '%s'... " % [
109
+ idx, @opts.tablespace
110
+ ]
111
+ if @opts.dryrun
112
+ $stderr.puts '(not really)'
113
+
114
+ else
115
+ age = self.timer do
116
+ db.exec "ALTER INDEX %s SET TABLESPACE %s;" % [
117
+ idx, @opts.tablespace
118
+ ]
119
+ end
120
+ puts age
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+
127
+ #########
128
+ protected
129
+ #########
130
+
131
+ ### Get OIDs and current tablespaces for everything under the
132
+ ### specified schema.
133
+ ###
134
+ def relations
135
+ return @relations if @relations
136
+ relations = {}
137
+
138
+ query = %q{
139
+ SELECT c.oid AS oid,
140
+ c.relname AS name,
141
+ c.relkind AS kind,
142
+ t.spcname AS tspace
143
+ FROM pg_class AS c
144
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
145
+ LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
146
+ WHERE c.relkind = 'r' }
147
+ query << "AND n.nspname='#{@opts.schema}'" if @opts.schema
148
+
149
+ # Get the relations list, along with each element's current tablespace.
150
+ #
151
+ self.db.exec( query ) do |res|
152
+ res.each do |row|
153
+ relations[ row['oid'] ] = {
154
+ :name => row['name'],
155
+ :tablespace => row['tspace'],
156
+ :indexes => [],
157
+ :parent => nil
158
+ }
159
+ end
160
+ end
161
+
162
+ # Add table inheritence information.
163
+ #
164
+ db.exec 'SELECT inhrelid AS oid, inhparent AS parent FROM pg_inherits' do |res|
165
+ res.each do |row|
166
+ relations[ row['oid'] ][ :parent ] = row['parent']
167
+ end
168
+ end
169
+
170
+ # Remove tables that don't qualify for warehousing.
171
+ #
172
+ # - Tables that are not children of a parent
173
+ # - Tables that are already in the warehouse tablespace
174
+ # - The currently active child (it's likely being written to!)
175
+ # - Any table that can't be parsed into the specified format
176
+ #
177
+ relations.reject! do |oid, val|
178
+ begin
179
+ val[:parent].nil? ||
180
+ val[:tablespace] == @opts.tablespace ||
181
+ val[:name] == Time.now.strftime( @opts.format ) ||
182
+ ! DateTime.strptime( val[:name], @opts.format )
183
+ rescue ArgumentError
184
+ true
185
+ end
186
+ end
187
+
188
+ query = %q{
189
+ SELECT c.oid AS oid,
190
+ i.indexname AS name
191
+ FROM pg_class AS c
192
+ INNER JOIN pg_indexes AS i
193
+ ON i.tablename = c.relname }
194
+ query << "AND i.schemaname='#{@opts.schema}'" if @opts.schema
195
+
196
+ # Attach index names to tables.
197
+ #
198
+ db.exec( query ) do |res|
199
+ res.each do |row|
200
+ relations[ row['oid'] ][ :indexes ] << row['name'] if relations[ row['oid'] ]
201
+ end
202
+ end
203
+
204
+ return relations
205
+ end
206
+
207
+
208
+ ### Wrap arbitrary commands in a human readable timer.
209
+ ###
210
+ def timer
211
+ start = Time.now
212
+ yield
213
+ age = Time.now - start
214
+
215
+ diff = age
216
+ secs = diff % 60
217
+ diff = ( diff - secs ) / 60
218
+ mins = diff % 60
219
+ diff = ( diff - mins ) / 60
220
+ hour = diff % 24
221
+
222
+ return "%02d:%02d:%02d" % [ hour, mins, secs ]
223
+ end
224
+ end
225
+
226
+
227
+ ### Parse command line arguments. Return a struct of global options.
228
+ ###
229
+ def parse_args( args )
230
+ options = OpenStruct.new
231
+ options.database = Etc.getpwuid( Process.uid ).name
232
+ options.host = '127.0.0.1'
233
+ options.port = 5432
234
+ options.user = Etc.getpwuid( Process.uid ).name
235
+ options.sslmode = 'prefer'
236
+ options.tablespace = 'warehouse'
237
+
238
+ opts = OptionParser.new do |opts|
239
+ opts.banner = "Usage: #{$0} [options]"
240
+
241
+ opts.separator ''
242
+ opts.separator 'Connection options:'
243
+
244
+ opts.on( '-d', '--database DBNAME',
245
+ "specify the database to connect to (default: \"#{options.database}\")" ) do |db|
246
+ options.database = db
247
+ end
248
+
249
+ opts.on( '-h', '--host HOSTNAME', 'database server host' ) do |host|
250
+ options.host = host
251
+ end
252
+
253
+ opts.on( '-p', '--port PORT', Integer,
254
+ "database server port (default: \"#{options.port}\")" ) do |port|
255
+ options.port = port
256
+ end
257
+
258
+ opts.on( '-n', '--schema SCHEMA', String,
259
+ "operate on the named schema only (default: none)" ) do |schema|
260
+ options.schema = schema
261
+ end
262
+
263
+ opts.on( '-T', '--tablespace SPACE', String,
264
+ "move old tables to this tablespace (default: \"#{options.tablespace}\")" ) do |tb|
265
+ options.tablespace = tb
266
+ end
267
+
268
+ opts.on( '-F', '--tableformat FORMAT', String,
269
+ "The naming format (strftime) for the inherited tables (default: none)" ) do |format|
270
+ options.format = format
271
+ end
272
+
273
+ opts.on( '-U', '--user NAME',
274
+ "database user name (default: \"#{options.user}\")" ) do |user|
275
+ options.user = user
276
+ end
277
+
278
+ opts.on( '-W', 'force password prompt' ) do |pw|
279
+ print 'Password: '
280
+ begin
281
+ system 'stty -echo'
282
+ options.pass = gets.chomp
283
+ ensure
284
+ system 'stty echo'
285
+ puts
286
+ end
287
+ end
288
+
289
+ opts.separator ''
290
+ opts.separator 'Other options:'
291
+
292
+ opts.on_tail( '--dry-run', "don't actually do anything" ) do
293
+ options.dryrun = true
294
+ end
295
+
296
+ opts.on_tail( '--help', 'show this help, then exit' ) do
297
+ $stderr.puts opts
298
+ exit
299
+ end
300
+
301
+ opts.on_tail( '--version', 'output version information, then exit' ) do
302
+ puts Stats::VERSION
303
+ exit
304
+ end
305
+ end
306
+
307
+ opts.parse!( args )
308
+ return options
309
+ end
310
+
311
+
312
+ if __FILE__ == $0
313
+ opts = parse_args( ARGV )
314
+ raise ArgumentError, "A naming format (-F) is required." unless opts.format
315
+
316
+ $stdout.sync = true
317
+ PGWarehouse.new( opts ).migrate
318
+ end
319
+
320
+
@@ -0,0 +1,26 @@
1
+ To backend> Msg Q
2
+ To backend> "SELECT 1 AS one"
3
+ To backend> Msg complete, length 21
4
+ From backend> T
5
+ From backend (#4)> 28
6
+ From backend (#2)> 1
7
+ From backend> "one"
8
+ From backend (#4)> 0
9
+ From backend (#2)> 0
10
+ From backend (#4)> 23
11
+ From backend (#2)> 4
12
+ From backend (#4)> -1
13
+ From backend (#2)> 0
14
+ From backend> D
15
+ From backend (#4)> 11
16
+ From backend (#2)> 1
17
+ From backend (#4)> 1
18
+ From backend (1)> 1
19
+ From backend> C
20
+ From backend (#4)> 11
21
+ From backend> "SELECT"
22
+ From backend> Z
23
+ From backend (#4)> 5
24
+ From backend> Z
25
+ From backend (#4)> 5
26
+ From backend> T
@@ -0,0 +1,352 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+ require 'rspec'
5
+ require 'shellwords'
6
+ require 'pg'
7
+
8
+ TEST_DIRECTORY = Pathname.getwd + "tmp_test_specs"
9
+
10
+ module PG::TestingHelpers
11
+
12
+ ### Automatically set up the database when it's used, and wrap a transaction around
13
+ ### examples that don't disable it.
14
+ def self::included( mod )
15
+ super
16
+
17
+ if mod.respond_to?( :around )
18
+
19
+ mod.before( :all ) { @conn = setup_testing_db(described_class ? described_class.name : mod.description) }
20
+
21
+ mod.around( :each ) do |example|
22
+ begin
23
+ @conn.exec( 'BEGIN' ) unless example.metadata[:without_transaction]
24
+ if PG.respond_to?( :library_version )
25
+ desc = example.source_location.join(':')
26
+ @conn.exec_params %Q{SET application_name TO '%s'} %
27
+ [@conn.escape_string(desc.slice(-60))]
28
+ end
29
+ example.run
30
+ ensure
31
+ @conn.exec( 'ROLLBACK' ) unless example.metadata[:without_transaction]
32
+ end
33
+ end
34
+
35
+ mod.after( :all ) { teardown_testing_db(@conn) }
36
+ end
37
+
38
+ end
39
+
40
+
41
+ #
42
+ # Examples
43
+ #
44
+
45
+ # Set some ANSI escape code constants (Shamelessly stolen from Perl's
46
+ # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
47
+ ANSI_ATTRIBUTES = {
48
+ 'clear' => 0,
49
+ 'reset' => 0,
50
+ 'bold' => 1,
51
+ 'dark' => 2,
52
+ 'underline' => 4,
53
+ 'underscore' => 4,
54
+ 'blink' => 5,
55
+ 'reverse' => 7,
56
+ 'concealed' => 8,
57
+
58
+ 'black' => 30, 'on_black' => 40,
59
+ 'red' => 31, 'on_red' => 41,
60
+ 'green' => 32, 'on_green' => 42,
61
+ 'yellow' => 33, 'on_yellow' => 43,
62
+ 'blue' => 34, 'on_blue' => 44,
63
+ 'magenta' => 35, 'on_magenta' => 45,
64
+ 'cyan' => 36, 'on_cyan' => 46,
65
+ 'white' => 37, 'on_white' => 47
66
+ }
67
+
68
+
69
+ ###############
70
+ module_function
71
+ ###############
72
+
73
+ ### Create a string that contains the ANSI codes specified and return it
74
+ def ansi_code( *attributes )
75
+ attributes.flatten!
76
+ attributes.collect! {|at| at.to_s }
77
+
78
+ return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
79
+ attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
80
+
81
+ # $stderr.puts " attr is: %p" % [attributes]
82
+ if attributes.empty?
83
+ return ''
84
+ else
85
+ return "\e[%sm" % attributes
86
+ end
87
+ end
88
+
89
+
90
+ ### Colorize the given +string+ with the specified +attributes+ and return it, handling
91
+ ### line-endings, color reset, etc.
92
+ def colorize( *args )
93
+ string = ''
94
+
95
+ if block_given?
96
+ string = yield
97
+ else
98
+ string = args.shift
99
+ end
100
+
101
+ ending = string[/(\s)$/] || ''
102
+ string = string.rstrip
103
+
104
+ return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
105
+ end
106
+
107
+
108
+ ### Output a message with highlighting.
109
+ def message( *msg )
110
+ $stderr.puts( colorize(:bold) { msg.flatten.join(' ') } )
111
+ end
112
+
113
+
114
+ ### Output a logging message if $VERBOSE is true
115
+ def trace( *msg )
116
+ return unless $VERBOSE
117
+ output = colorize( msg.flatten.join(' '), 'yellow' )
118
+ $stderr.puts( output )
119
+ end
120
+
121
+
122
+ ### Return the specified args as a string, quoting any that have a space.
123
+ def quotelist( *args )
124
+ return args.flatten.collect {|part| part.to_s =~ /\s/ ? part.to_s.inspect : part.to_s }
125
+ end
126
+
127
+
128
+ ### Run the specified command +cmd+ with system(), failing if the execution
129
+ ### fails.
130
+ def run( *cmd )
131
+ cmd.flatten!
132
+
133
+ if cmd.length > 1
134
+ trace( quotelist(*cmd) )
135
+ else
136
+ trace( cmd )
137
+ end
138
+
139
+ system( *cmd )
140
+ raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
141
+ end
142
+
143
+
144
+ ### Run the specified command +cmd+ after redirecting stdout and stderr to the specified
145
+ ### +logpath+, failing if the execution fails.
146
+ def log_and_run( logpath, *cmd )
147
+ cmd.flatten!
148
+
149
+ if cmd.length > 1
150
+ trace( quotelist(*cmd) )
151
+ else
152
+ trace( cmd )
153
+ end
154
+
155
+ # Eliminate the noise of creating/tearing down the database by
156
+ # redirecting STDERR/STDOUT to a logfile
157
+ logfh = File.open( logpath, File::WRONLY|File::CREAT|File::APPEND )
158
+ system( *cmd, [STDOUT, STDERR] => logfh )
159
+
160
+ raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
161
+ end
162
+
163
+
164
+ ### Check the current directory for directories that look like they're
165
+ ### testing directories from previous tests, and tell any postgres instances
166
+ ### running in them to shut down.
167
+ def stop_existing_postmasters
168
+ # tmp_test_0.22329534700318
169
+ pat = Pathname.getwd + 'tmp_test_*'
170
+ Pathname.glob( pat.to_s ).each do |testdir|
171
+ datadir = testdir + 'data'
172
+ pidfile = datadir + 'postmaster.pid'
173
+ if pidfile.exist? && pid = pidfile.read.chomp.to_i
174
+ $stderr.puts "pidfile (%p) exists: %d" % [ pidfile, pid ]
175
+ begin
176
+ Process.kill( 0, pid )
177
+ rescue Errno::ESRCH
178
+ $stderr.puts "No postmaster running for %s" % [ datadir ]
179
+ # Process isn't alive, so don't try to stop it
180
+ else
181
+ $stderr.puts "Stopping lingering database at PID %d" % [ pid ]
182
+ run 'pg_ctl', '-D', datadir.to_s, '-m', 'fast', 'stop'
183
+ end
184
+ else
185
+ $stderr.puts "No pidfile (%p)" % [ pidfile ]
186
+ end
187
+ end
188
+ end
189
+
190
+
191
+ ### Set up a PostgreSQL database instance for testing.
192
+ def setup_testing_db( description )
193
+ require 'pg'
194
+ stop_existing_postmasters()
195
+
196
+ puts "Setting up test database for #{description}"
197
+ @test_pgdata = TEST_DIRECTORY + 'data'
198
+ @test_pgdata.mkpath
199
+
200
+ @port = 54321
201
+ ENV['PGPORT'] = @port.to_s
202
+ ENV['PGHOST'] = 'localhost'
203
+ @conninfo = "host=localhost port=#{@port} dbname=test"
204
+
205
+ @logfile = TEST_DIRECTORY + 'setup.log'
206
+ trace "Command output logged to #{@logfile}"
207
+
208
+ begin
209
+ unless (@test_pgdata+"postgresql.conf").exist?
210
+ FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
211
+ $stderr.puts "Running initdb"
212
+ log_and_run @logfile, 'initdb', '-E', 'UTF8', '--no-locale', '-D', @test_pgdata.to_s
213
+ end
214
+
215
+ trace "Starting postgres"
216
+ log_and_run @logfile, 'pg_ctl', '-w', '-o', "-k #{TEST_DIRECTORY.to_s.dump}",
217
+ '-D', @test_pgdata.to_s, 'start'
218
+ sleep 2
219
+
220
+ $stderr.puts "Creating the test DB"
221
+ log_and_run @logfile, 'psql', '-e', '-c', 'DROP DATABASE IF EXISTS test', 'postgres'
222
+ log_and_run @logfile, 'createdb', '-e', 'test'
223
+
224
+ rescue => err
225
+ $stderr.puts "%p during test setup: %s" % [ err.class, err.message ]
226
+ $stderr.puts "See #{@logfile} for details."
227
+ $stderr.puts *err.backtrace if $DEBUG
228
+ fail
229
+ end
230
+
231
+ conn = PG.connect( @conninfo )
232
+ conn.set_notice_processor do |message|
233
+ $stderr.puts( description + ':' + message ) if $DEBUG
234
+ end
235
+
236
+ return conn
237
+ end
238
+
239
+
240
+ def teardown_testing_db( conn )
241
+ puts "Tearing down test database"
242
+
243
+ if conn
244
+ check_for_lingering_connections( conn )
245
+ conn.finish
246
+ end
247
+
248
+ log_and_run @logfile, 'pg_ctl', '-D', @test_pgdata.to_s, 'stop'
249
+ end
250
+
251
+
252
+ def check_for_lingering_connections( conn )
253
+ conn.exec( "SELECT * FROM pg_stat_activity" ) do |res|
254
+ conns = res.find_all {|row| row['pid'].to_i != conn.backend_pid }
255
+ unless conns.empty?
256
+ puts "Lingering connections remain:"
257
+ conns.each do |row|
258
+ puts " [%s] {%s} %s -- %s" % row.values_at( 'pid', 'state', 'application_name', 'query' )
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+
265
+ # Retrieve the names of the column types of a given result set.
266
+ def result_typenames(res)
267
+ @conn.exec( "SELECT " + res.nfields.times.map{|i| "format_type($#{i*2+1},$#{i*2+2})"}.join(","),
268
+ res.nfields.times.map{|i| [res.ftype(i), res.fmod(i)] }.flatten ).
269
+ values[0]
270
+ end
271
+
272
+
273
+ # A matcher for checking the status of a PG::Connection to ensure it's still
274
+ # usable.
275
+ class ConnStillUsableMatcher
276
+
277
+ def initialize
278
+ @conn = nil
279
+ @problem = nil
280
+ end
281
+
282
+ def matches?( conn )
283
+ @conn = conn
284
+ @problem = self.check_for_problems
285
+ return @problem.nil?
286
+ end
287
+
288
+ def check_for_problems
289
+ return "is finished" if @conn.finished?
290
+ return "has bad status" unless @conn.status == PG::CONNECTION_OK
291
+ return "has bad transaction status (%d)" % [ @conn.transaction_status ] unless
292
+ @conn.transaction_status.between?( PG::PQTRANS_IDLE, PG::PQTRANS_INTRANS )
293
+ return "is not usable." unless self.can_exec_query?
294
+ return nil
295
+ end
296
+
297
+ def can_exec_query?
298
+ @conn.send_query( "VALUES (1)" )
299
+ @conn.get_last_result.values == [["1"]]
300
+ end
301
+
302
+ def failure_message
303
+ return "expected %p to be usable, but it %s" % [ @conn, @problem ]
304
+ end
305
+
306
+ def failure_message_when_negated
307
+ "expected %p not to be usable, but it still is" % [ @conn ]
308
+ end
309
+
310
+ end
311
+
312
+
313
+ ### Return a ConnStillUsableMatcher to be used like:
314
+ ###
315
+ ### expect( pg_conn ).to still_be_usable
316
+ ###
317
+ def still_be_usable
318
+ return ConnStillUsableMatcher.new
319
+ end
320
+
321
+ end
322
+
323
+
324
+ RSpec.configure do |config|
325
+ config.include( PG::TestingHelpers )
326
+
327
+ config.run_all_when_everything_filtered = true
328
+ config.filter_run :focus
329
+ config.order = 'random'
330
+ config.mock_with( :rspec ) do |mock|
331
+ mock.syntax = :expect
332
+ end
333
+
334
+ if RUBY_PLATFORM =~ /mingw|mswin/
335
+ config.filter_run_excluding :unix
336
+ else
337
+ config.filter_run_excluding :windows
338
+ end
339
+ config.filter_run_excluding :socket_io unless
340
+ PG::Connection.instance_methods.map( &:to_sym ).include?( :socket_io )
341
+
342
+ if PG.library_version < 90200
343
+ config.filter_run_excluding( :postgresql_92, :postgresql_93, :postgresql_94, :postgresql_95 )
344
+ elsif PG.library_version < 90300
345
+ config.filter_run_excluding( :postgresql_93, :postgresql_94, :postgresql_95 )
346
+ elsif PG.library_version < 90400
347
+ config.filter_run_excluding( :postgresql_94, :postgresql_95 )
348
+ elsif PG.library_version < 90500
349
+ config.filter_run_excluding( :postgresql_95 )
350
+ end
351
+ end
352
+