cipherstash-pg 1.0.0.beta.1-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/BSDL +22 -0
  3. data/Contributors.rdoc +46 -0
  4. data/Gemfile +14 -0
  5. data/History.rdoc +789 -0
  6. data/LICENSE +56 -0
  7. data/Manifest.txt +72 -0
  8. data/POSTGRES +23 -0
  9. data/README-OS_X.rdoc +68 -0
  10. data/README-Windows.rdoc +56 -0
  11. data/README.ja.rdoc +13 -0
  12. data/README.rdoc +233 -0
  13. data/Rakefile +115 -0
  14. data/certs/ged.pem +24 -0
  15. data/certs/larskanis-2022.pem +26 -0
  16. data/cipherstash-pg.gemspec +31 -0
  17. data/lib/2.7/pg_ext.so +0 -0
  18. data/lib/3.0/pg_ext.so +0 -0
  19. data/lib/3.1/pg_ext.so +0 -0
  20. data/lib/3.2/pg_ext.so +0 -0
  21. data/lib/cipherstash-pg.rb +15 -0
  22. data/lib/libpq.so.5 +0 -0
  23. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  24. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  25. data/lib/pg/basic_type_map_for_results.rb +81 -0
  26. data/lib/pg/basic_type_registry.rb +301 -0
  27. data/lib/pg/binary_decoder.rb +23 -0
  28. data/lib/pg/coder.rb +104 -0
  29. data/lib/pg/connection.rb +878 -0
  30. data/lib/pg/constants.rb +12 -0
  31. data/lib/pg/exceptions.rb +18 -0
  32. data/lib/pg/result.rb +43 -0
  33. data/lib/pg/text_decoder.rb +46 -0
  34. data/lib/pg/text_encoder.rb +59 -0
  35. data/lib/pg/tuple.rb +30 -0
  36. data/lib/pg/type_map_by_column.rb +16 -0
  37. data/lib/pg/version.rb +4 -0
  38. data/lib/pg.rb +55 -0
  39. data/misc/openssl-pg-segfault.rb +31 -0
  40. data/misc/postgres/History.txt +9 -0
  41. data/misc/postgres/Manifest.txt +5 -0
  42. data/misc/postgres/README.txt +21 -0
  43. data/misc/postgres/Rakefile +21 -0
  44. data/misc/postgres/lib/postgres.rb +16 -0
  45. data/misc/ruby-pg/History.txt +9 -0
  46. data/misc/ruby-pg/Manifest.txt +5 -0
  47. data/misc/ruby-pg/README.txt +21 -0
  48. data/misc/ruby-pg/Rakefile +21 -0
  49. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  50. data/rakelib/task_extension.rb +46 -0
  51. data/sample/array_insert.rb +20 -0
  52. data/sample/async_api.rb +102 -0
  53. data/sample/async_copyto.rb +39 -0
  54. data/sample/async_mixed.rb +56 -0
  55. data/sample/check_conn.rb +21 -0
  56. data/sample/copydata.rb +71 -0
  57. data/sample/copyfrom.rb +81 -0
  58. data/sample/copyto.rb +19 -0
  59. data/sample/cursor.rb +21 -0
  60. data/sample/disk_usage_report.rb +177 -0
  61. data/sample/issue-119.rb +94 -0
  62. data/sample/losample.rb +69 -0
  63. data/sample/minimal-testcase.rb +17 -0
  64. data/sample/notify_wait.rb +72 -0
  65. data/sample/pg_statistics.rb +285 -0
  66. data/sample/replication_monitor.rb +222 -0
  67. data/sample/test_binary_values.rb +33 -0
  68. data/sample/wal_shipper.rb +434 -0
  69. data/sample/warehouse_partitions.rb +311 -0
  70. data/vendor/database-extensions/install.sql +317 -0
  71. data/vendor/database-extensions/uninstall.sql +20 -0
  72. metadata +118 -0
@@ -0,0 +1,311 @@
1
+ # -*- 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
+ require 'date'
40
+ require 'ostruct'
41
+ require 'optparse'
42
+ require 'pathname'
43
+ require 'etc'
44
+ require 'pg'
45
+
46
+
47
+ ### A tablespace migration class.
48
+ ###
49
+ class PGWarehouse
50
+
51
+ def initialize( opts )
52
+ @opts = opts
53
+ @db = PG.connect(
54
+ :dbname => opts.database,
55
+ :host => opts.host,
56
+ :port => opts.port,
57
+ :user => opts.user,
58
+ :password => opts.pass,
59
+ :sslmode => 'prefer'
60
+ )
61
+ @db.exec "SET search_path TO %s" % [ opts.schema ] if opts.schema
62
+
63
+ @relations = self.relations
64
+ end
65
+
66
+ attr_reader :db
67
+
68
+ ######
69
+ public
70
+ ######
71
+
72
+ ### Perform the tablespace moves.
73
+ ###
74
+ def migrate
75
+ if @relations.empty?
76
+ $stderr.puts 'No tables were found for warehousing.'
77
+ return
78
+ end
79
+
80
+ $stderr.puts "Found %d relation%s to move." % [ relations.length, relations.length == 1 ? '' : 's' ]
81
+ @relations.sort_by{|_,v| v[:name] }.each do |_, val|
82
+ $stderr.print " - Moving table '%s' to '%s'... " % [
83
+ val[:name], @opts.tablespace
84
+ ]
85
+
86
+ if @opts.dryrun
87
+ $stderr.puts '(not really)'
88
+
89
+ else
90
+ age = self.timer do
91
+ db.exec "ALTER TABLE %s SET TABLESPACE %s;" % [
92
+ val[:name], @opts.tablespace
93
+ ]
94
+ end
95
+ puts age
96
+ end
97
+
98
+ val[ :indexes ].each do |idx|
99
+ $stderr.print " - Moving index '%s' to '%s'... " % [
100
+ idx, @opts.tablespace
101
+ ]
102
+ if @opts.dryrun
103
+ $stderr.puts '(not really)'
104
+
105
+ else
106
+ age = self.timer do
107
+ db.exec "ALTER INDEX %s SET TABLESPACE %s;" % [
108
+ idx, @opts.tablespace
109
+ ]
110
+ end
111
+ puts age
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+
118
+ #########
119
+ protected
120
+ #########
121
+
122
+ ### Get OIDs and current tablespaces for everything under the
123
+ ### specified schema.
124
+ ###
125
+ def relations
126
+ return @relations if @relations
127
+ relations = {}
128
+
129
+ query = %q{
130
+ SELECT c.oid AS oid,
131
+ c.relname AS name,
132
+ c.relkind AS kind,
133
+ t.spcname AS tspace
134
+ FROM pg_class AS c
135
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
136
+ LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
137
+ WHERE c.relkind = 'r' }
138
+ query << "AND n.nspname='#{@opts.schema}'" if @opts.schema
139
+
140
+ # Get the relations list, along with each element's current tablespace.
141
+ #
142
+ self.db.exec( query ) do |res|
143
+ res.each do |row|
144
+ relations[ row['oid'] ] = {
145
+ :name => row['name'],
146
+ :tablespace => row['tspace'],
147
+ :indexes => [],
148
+ :parent => nil
149
+ }
150
+ end
151
+ end
152
+
153
+ # Add table inheritance information.
154
+ #
155
+ db.exec 'SELECT inhrelid AS oid, inhparent AS parent FROM pg_inherits' do |res|
156
+ res.each do |row|
157
+ relations[ row['oid'] ][ :parent ] = row['parent']
158
+ end
159
+ end
160
+
161
+ # Remove tables that don't qualify for warehousing.
162
+ #
163
+ # - Tables that are not children of a parent
164
+ # - Tables that are already in the warehouse tablespace
165
+ # - The currently active child (it's likely being written to!)
166
+ # - Any table that can't be parsed into the specified format
167
+ #
168
+ relations.reject! do |oid, val|
169
+ begin
170
+ val[:parent].nil? ||
171
+ val[:tablespace] == @opts.tablespace ||
172
+ val[:name] == Time.now.strftime( @opts.format ) ||
173
+ ! DateTime.strptime( val[:name], @opts.format )
174
+ rescue ArgumentError
175
+ true
176
+ end
177
+ end
178
+
179
+ query = %q{
180
+ SELECT c.oid AS oid,
181
+ i.indexname AS name
182
+ FROM pg_class AS c
183
+ INNER JOIN pg_indexes AS i
184
+ ON i.tablename = c.relname }
185
+ query << "AND i.schemaname='#{@opts.schema}'" if @opts.schema
186
+
187
+ # Attach index names to tables.
188
+ #
189
+ db.exec( query ) do |res|
190
+ res.each do |row|
191
+ relations[ row['oid'] ][ :indexes ] << row['name'] if relations[ row['oid'] ]
192
+ end
193
+ end
194
+
195
+ return relations
196
+ end
197
+
198
+
199
+ ### Wrap arbitrary commands in a human readable timer.
200
+ ###
201
+ def timer
202
+ start = Time.now
203
+ yield
204
+ age = Time.now - start
205
+
206
+ diff = age
207
+ secs = diff % 60
208
+ diff = ( diff - secs ) / 60
209
+ mins = diff % 60
210
+ diff = ( diff - mins ) / 60
211
+ hour = diff % 24
212
+
213
+ return "%02d:%02d:%02d" % [ hour, mins, secs ]
214
+ end
215
+ end
216
+
217
+
218
+ ### Parse command line arguments. Return a struct of global options.
219
+ ###
220
+ def parse_args( args )
221
+ options = OpenStruct.new
222
+ options.database = Etc.getpwuid( Process.uid ).name
223
+ options.host = '127.0.0.1'
224
+ options.port = 5432
225
+ options.user = Etc.getpwuid( Process.uid ).name
226
+ options.sslmode = 'prefer'
227
+ options.tablespace = 'warehouse'
228
+
229
+ opts = OptionParser.new do |opts|
230
+ opts.banner = "Usage: #{$0} [options]"
231
+
232
+ opts.separator ''
233
+ opts.separator 'Connection options:'
234
+
235
+ opts.on( '-d', '--database DBNAME',
236
+ "specify the database to connect to (default: \"#{options.database}\")" ) do |db|
237
+ options.database = db
238
+ end
239
+
240
+ opts.on( '-h', '--host HOSTNAME', 'database server host' ) do |host|
241
+ options.host = host
242
+ end
243
+
244
+ opts.on( '-p', '--port PORT', Integer,
245
+ "database server port (default: \"#{options.port}\")" ) do |port|
246
+ options.port = port
247
+ end
248
+
249
+ opts.on( '-n', '--schema SCHEMA', String,
250
+ "operate on the named schema only (default: none)" ) do |schema|
251
+ options.schema = schema
252
+ end
253
+
254
+ opts.on( '-T', '--tablespace SPACE', String,
255
+ "move old tables to this tablespace (default: \"#{options.tablespace}\")" ) do |tb|
256
+ options.tablespace = tb
257
+ end
258
+
259
+ opts.on( '-F', '--tableformat FORMAT', String,
260
+ "The naming format (strftime) for the inherited tables (default: none)" ) do |format|
261
+ options.format = format
262
+ end
263
+
264
+ opts.on( '-U', '--user NAME',
265
+ "database user name (default: \"#{options.user}\")" ) do |user|
266
+ options.user = user
267
+ end
268
+
269
+ opts.on( '-W', 'force password prompt' ) do |pw|
270
+ print 'Password: '
271
+ begin
272
+ system 'stty -echo'
273
+ options.pass = gets.chomp
274
+ ensure
275
+ system 'stty echo'
276
+ puts
277
+ end
278
+ end
279
+
280
+ opts.separator ''
281
+ opts.separator 'Other options:'
282
+
283
+ opts.on_tail( '--dry-run', "don't actually do anything" ) do
284
+ options.dryrun = true
285
+ end
286
+
287
+ opts.on_tail( '--help', 'show this help, then exit' ) do
288
+ $stderr.puts opts
289
+ exit
290
+ end
291
+
292
+ opts.on_tail( '--version', 'output version information, then exit' ) do
293
+ puts Stats::VERSION
294
+ exit
295
+ end
296
+ end
297
+
298
+ opts.parse!( args )
299
+ return options
300
+ end
301
+
302
+
303
+ if __FILE__ == $0
304
+ opts = parse_args( ARGV )
305
+ raise ArgumentError, "A naming format (-F) is required." unless opts.format
306
+
307
+ $stdout.sync = true
308
+ PGWarehouse.new( opts ).migrate
309
+ end
310
+
311
+
@@ -0,0 +1,317 @@
1
+ CREATE EXTENSION IF NOT EXISTS pgcrypto;
2
+
3
+ CREATE TYPE ore_64_8_v1_term AS (
4
+ bytes bytea
5
+ );
6
+
7
+ CREATE TYPE ore_64_8_v1 AS (
8
+ terms ore_64_8_v1_term[]
9
+ );
10
+
11
+ CREATE OR REPLACE FUNCTION compare_ore_64_8_v1_term(a ore_64_8_v1_term, b ore_64_8_v1_term) returns integer AS $$
12
+ DECLARE
13
+ eq boolean := true;
14
+ unequal_block smallint := 0;
15
+ hash_key bytea;
16
+ target_block bytea;
17
+
18
+ left_block_size CONSTANT smallint := 16;
19
+ right_block_size CONSTANT smallint := 32;
20
+ right_offset CONSTANT smallint := 136; -- 8 * 17
21
+
22
+ indicator smallint := 0;
23
+ BEGIN
24
+ IF a IS NULL AND b IS NULL THEN
25
+ RETURN 0;
26
+ END IF;
27
+
28
+ IF a IS NULL THEN
29
+ RETURN -1;
30
+ END IF;
31
+
32
+ IF b IS NULL THEN
33
+ RETURN 1;
34
+ END IF;
35
+
36
+ IF bit_length(a.bytes) != bit_length(b.bytes) THEN
37
+ RAISE EXCEPTION 'Ciphertexts are different lengths';
38
+ END IF;
39
+
40
+ FOR block IN 0..7 LOOP
41
+ -- Compare each PRP (byte from the first 8 bytes) and PRF block (8 byte
42
+ -- chunks of the rest of the value).
43
+ -- NOTE:
44
+ -- * Substr is ordinally indexed (hence 1 and not 0, and 9 and not 8).
45
+ -- * We are not worrying about timing attacks here; don't fret about
46
+ -- the OR or !=.
47
+ IF
48
+ substr(a.bytes, 1 + block, 1) != substr(b.bytes, 1 + block, 1)
49
+ OR substr(a.bytes, 9 + left_block_size * block, left_block_size) != substr(b.bytes, 9 + left_block_size * BLOCK, left_block_size)
50
+ THEN
51
+ -- set the first unequal block we find
52
+ IF eq THEN
53
+ unequal_block := block;
54
+ END IF;
55
+ eq = false;
56
+ END IF;
57
+ END LOOP;
58
+
59
+ IF eq THEN
60
+ RETURN 0::integer;
61
+ END IF;
62
+
63
+ -- Hash key is the IV from the right CT of b
64
+ hash_key := substr(b.bytes, right_offset + 1, 16);
65
+
66
+ -- first right block is at right offset + nonce_size (ordinally indexed)
67
+ target_block := substr(b.bytes, right_offset + 17 + (unequal_block * right_block_size), right_block_size);
68
+
69
+ indicator := (
70
+ get_bit(
71
+ encrypt(
72
+ substr(a.bytes, 9 + (left_block_size * unequal_block), left_block_size),
73
+ hash_key,
74
+ 'aes-ecb'
75
+ ),
76
+ 0
77
+ ) + get_bit(target_block, get_byte(a.bytes, unequal_block))) % 2;
78
+
79
+ IF indicator = 1 THEN
80
+ RETURN 1::integer;
81
+ ELSE
82
+ RETURN -1::integer;
83
+ END IF;
84
+ END;
85
+ $$ LANGUAGE plpgsql;
86
+
87
+
88
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_term_eq(a ore_64_8_v1_term, b ore_64_8_v1_term) RETURNS boolean AS $$
89
+ SELECT compare_ore_64_8_v1_term(a, b) = 0
90
+ $$ LANGUAGE SQL;
91
+
92
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_term_neq(a ore_64_8_v1_term, b ore_64_8_v1_term) RETURNS boolean AS $$
93
+ SELECT compare_ore_64_8_v1_term(a, b) <> 0
94
+ $$ LANGUAGE SQL;
95
+
96
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_term_lt(a ore_64_8_v1_term, b ore_64_8_v1_term) RETURNS boolean AS $$
97
+ SELECT compare_ore_64_8_v1_term(a, b) = -1
98
+ $$ LANGUAGE SQL;
99
+
100
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_term_lte(a ore_64_8_v1_term, b ore_64_8_v1_term) RETURNS boolean AS $$
101
+ SELECT compare_ore_64_8_v1_term(a, b) != 1
102
+ $$ LANGUAGE SQL;
103
+
104
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_term_gt(a ore_64_8_v1_term, b ore_64_8_v1_term) RETURNS boolean AS $$
105
+ SELECT compare_ore_64_8_v1_term(a, b) = 1
106
+ $$ LANGUAGE SQL;
107
+
108
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_term_gte(a ore_64_8_v1_term, b ore_64_8_v1_term) RETURNS boolean AS $$
109
+ SELECT compare_ore_64_8_v1_term(a, b) != -1
110
+ $$ LANGUAGE SQL;
111
+
112
+ CREATE OPERATOR = (
113
+ PROCEDURE="ore_64_8_v1_term_eq",
114
+ LEFTARG=ore_64_8_v1_term,
115
+ RIGHTARG=ore_64_8_v1_term,
116
+ NEGATOR = <>,
117
+ RESTRICT = eqsel,
118
+ JOIN = eqjoinsel,
119
+ HASHES,
120
+ MERGES
121
+ );
122
+
123
+ CREATE OPERATOR <> (
124
+ PROCEDURE="ore_64_8_v1_term_neq",
125
+ LEFTARG=ore_64_8_v1_term,
126
+ RIGHTARG=ore_64_8_v1_term,
127
+ NEGATOR = =,
128
+ RESTRICT = eqsel,
129
+ JOIN = eqjoinsel,
130
+ HASHES,
131
+ MERGES
132
+ );
133
+
134
+ CREATE OPERATOR > (
135
+ PROCEDURE="ore_64_8_v1_term_gt",
136
+ LEFTARG=ore_64_8_v1_term,
137
+ RIGHTARG=ore_64_8_v1_term,
138
+ COMMUTATOR = <,
139
+ NEGATOR = <=,
140
+ RESTRICT = scalargtsel,
141
+ JOIN = scalargtjoinsel
142
+ );
143
+
144
+ CREATE OPERATOR < (
145
+ PROCEDURE="ore_64_8_v1_term_lt",
146
+ LEFTARG=ore_64_8_v1_term,
147
+ RIGHTARG=ore_64_8_v1_term,
148
+ COMMUTATOR = >,
149
+ NEGATOR = >=,
150
+ RESTRICT = scalarltsel,
151
+ JOIN = scalarltjoinsel
152
+ );
153
+
154
+ CREATE OPERATOR <= (
155
+ PROCEDURE="ore_64_8_v1_term_lte",
156
+ LEFTARG=ore_64_8_v1_term,
157
+ RIGHTARG=ore_64_8_v1_term,
158
+ COMMUTATOR = >=,
159
+ NEGATOR = >,
160
+ RESTRICT = scalarlesel,
161
+ JOIN = scalarlejoinsel
162
+ );
163
+
164
+ CREATE OPERATOR >= (
165
+ PROCEDURE="ore_64_8_v1_term_gte",
166
+ LEFTARG=ore_64_8_v1_term,
167
+ RIGHTARG=ore_64_8_v1_term,
168
+ COMMUTATOR = <=,
169
+ NEGATOR = <,
170
+ RESTRICT = scalarlesel,
171
+ JOIN = scalarlejoinsel
172
+ );
173
+
174
+ CREATE OPERATOR FAMILY ore_64_8_v1_term_btree_ops USING btree;
175
+ CREATE OPERATOR CLASS ore_64_8_v1_term_btree_ops DEFAULT FOR TYPE ore_64_8_v1_term USING btree FAMILY ore_64_8_v1_term_btree_ops AS
176
+ OPERATOR 1 <,
177
+ OPERATOR 2 <=,
178
+ OPERATOR 3 =,
179
+ OPERATOR 4 >=,
180
+ OPERATOR 5 >,
181
+ FUNCTION 1 compare_ore_64_8_v1_term(a ore_64_8_v1_term, b ore_64_8_v1_term);
182
+
183
+ -- Compare the "head" of each array and recurse if necessary
184
+ -- This function assumes an empty string is "less than" everything else
185
+ -- so if a is empty we return -1, if be is empty and a isn't, we return 1.
186
+ -- If both are empty we return 0. This cases probably isn't necessary as equality
187
+ -- doesn't always make sense but it's here for completeness.
188
+ -- If both are non-empty, we compare the first element. If they are equal
189
+ -- we need to consider the next block so we recurse, otherwise we return the comparison result.
190
+ CREATE OR REPLACE FUNCTION compare_ore_array(a ore_64_8_v1_term[], b ore_64_8_v1_term[]) returns integer AS $$
191
+ DECLARE
192
+ cmp_result integer;
193
+ BEGIN
194
+ IF (array_length(a, 1) = 0 OR a IS NULL) AND (array_length(b, 1) = 0 OR b IS NULL) THEN
195
+ RETURN 0;
196
+ END IF;
197
+ IF array_length(a, 1) = 0 OR a IS NULL THEN
198
+ RETURN -1;
199
+ END IF;
200
+ IF array_length(b, 1) = 0 OR a IS NULL THEN
201
+ RETURN 1;
202
+ END IF;
203
+
204
+ cmp_result := compare_ore_64_8_v1_term(a[1], b[1]);
205
+ IF cmp_result = 0 THEN
206
+ -- Removes the first element in the array, and calls this fn again to compare the next element/s in the array.
207
+ RETURN compare_ore_array(a[2:array_length(a,1)], b[2:array_length(b,1)]);
208
+ END IF;
209
+
210
+ RETURN cmp_result;
211
+ END
212
+ $$ LANGUAGE plpgsql;
213
+
214
+ -- This function uses lexicographic comparison
215
+ CREATE OR REPLACE FUNCTION compare_ore_64_8_v1(a ore_64_8_v1, b ore_64_8_v1) returns integer AS $$
216
+ DECLARE
217
+ cmp_result integer;
218
+ BEGIN
219
+ -- Recursively compare blocks bailing as soon as we can make a decision
220
+ RETURN compare_ore_array(a.terms, b.terms);
221
+ END
222
+ $$ LANGUAGE plpgsql;
223
+
224
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_eq(a ore_64_8_v1, b ore_64_8_v1) RETURNS boolean AS $$
225
+ SELECT compare_ore_64_8_v1(a, b) = 0
226
+ $$ LANGUAGE SQL;
227
+
228
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_neq(a ore_64_8_v1, b ore_64_8_v1) RETURNS boolean AS $$
229
+ SELECT compare_ore_64_8_v1(a, b) <> 0
230
+ $$ LANGUAGE SQL;
231
+
232
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_lt(a ore_64_8_v1, b ore_64_8_v1) RETURNS boolean AS $$
233
+ SELECT compare_ore_64_8_v1(a, b) = -1
234
+ $$ LANGUAGE SQL;
235
+
236
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_lte(a ore_64_8_v1, b ore_64_8_v1) RETURNS boolean AS $$
237
+ SELECT compare_ore_64_8_v1(a, b) != 1
238
+ $$ LANGUAGE SQL;
239
+
240
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_gt(a ore_64_8_v1, b ore_64_8_v1) RETURNS boolean AS $$
241
+ SELECT compare_ore_64_8_v1(a, b) = 1
242
+ $$ LANGUAGE SQL;
243
+
244
+ CREATE OR REPLACE FUNCTION ore_64_8_v1_gte(a ore_64_8_v1, b ore_64_8_v1) RETURNS boolean AS $$
245
+ SELECT compare_ore_64_8_v1(a, b) != -1
246
+ $$ LANGUAGE SQL;
247
+
248
+ CREATE OPERATOR = (
249
+ PROCEDURE="ore_64_8_v1_eq",
250
+ LEFTARG=ore_64_8_v1,
251
+ RIGHTARG=ore_64_8_v1,
252
+ NEGATOR = <>,
253
+ RESTRICT = eqsel,
254
+ JOIN = eqjoinsel,
255
+ HASHES,
256
+ MERGES
257
+ );
258
+
259
+ CREATE OPERATOR <> (
260
+ PROCEDURE="ore_64_8_v1_neq",
261
+ LEFTARG=ore_64_8_v1,
262
+ RIGHTARG=ore_64_8_v1,
263
+ NEGATOR = =,
264
+ RESTRICT = eqsel,
265
+ JOIN = eqjoinsel,
266
+ HASHES,
267
+ MERGES
268
+ );
269
+
270
+ CREATE OPERATOR > (
271
+ PROCEDURE="ore_64_8_v1_gt",
272
+ LEFTARG=ore_64_8_v1,
273
+ RIGHTARG=ore_64_8_v1,
274
+ COMMUTATOR = <,
275
+ NEGATOR = <=,
276
+ RESTRICT = scalargtsel,
277
+ JOIN = scalargtjoinsel
278
+ );
279
+
280
+ CREATE OPERATOR < (
281
+ PROCEDURE="ore_64_8_v1_lt",
282
+ LEFTARG=ore_64_8_v1,
283
+ RIGHTARG=ore_64_8_v1,
284
+ COMMUTATOR = >,
285
+ NEGATOR = >=,
286
+ RESTRICT = scalarltsel,
287
+ JOIN = scalarltjoinsel
288
+ );
289
+
290
+ CREATE OPERATOR <= (
291
+ PROCEDURE="ore_64_8_v1_lte",
292
+ LEFTARG=ore_64_8_v1,
293
+ RIGHTARG=ore_64_8_v1,
294
+ COMMUTATOR = >=,
295
+ NEGATOR = >,
296
+ RESTRICT = scalarlesel,
297
+ JOIN = scalarlejoinsel
298
+ );
299
+
300
+ CREATE OPERATOR >= (
301
+ PROCEDURE="ore_64_8_v1_gte",
302
+ LEFTARG=ore_64_8_v1,
303
+ RIGHTARG=ore_64_8_v1,
304
+ COMMUTATOR = <=,
305
+ NEGATOR = <,
306
+ RESTRICT = scalarlesel,
307
+ JOIN = scalarlejoinsel
308
+ );
309
+
310
+ CREATE OPERATOR FAMILY ore_64_8_v1_btree_ops USING btree;
311
+ CREATE OPERATOR CLASS ore_64_8_v1_btree_ops DEFAULT FOR TYPE ore_64_8_v1 USING btree FAMILY ore_64_8_v1_btree_ops AS
312
+ OPERATOR 1 <,
313
+ OPERATOR 2 <=,
314
+ OPERATOR 3 =,
315
+ OPERATOR 4 >=,
316
+ OPERATOR 5 >,
317
+ FUNCTION 1 compare_ore_64_8_v1(a ore_64_8_v1, b ore_64_8_v1);
@@ -0,0 +1,20 @@
1
+ -- TODO: what happens if we try to uninstall a type which is in use?
2
+ DROP OPERATOR IF EXISTS = (ore_64_8_v1_term, ore_64_8_v1_term) CASCADE;
3
+ DROP OPERATOR IF EXISTS <> (ore_64_8_v1_term, ore_64_8_v1_term) CASCADE;
4
+ DROP OPERATOR IF EXISTS > (ore_64_8_v1_term, ore_64_8_v1_term) CASCADE;
5
+ DROP OPERATOR IF EXISTS < (ore_64_8_v1_term, ore_64_8_v1_term) CASCADE;
6
+ DROP OPERATOR IF EXISTS <= (ore_64_8_v1_term, ore_64_8_v1_term) CASCADE;
7
+ DROP OPERATOR IF EXISTS >= (ore_64_8_v1_term, ore_64_8_v1_term) CASCADE;
8
+ DROP OPERATOR CLASS IF EXISTS ore_64_8_v1_term_btree_ops USING btree CASCADE;
9
+ DROP OPERATOR FAMILY IF EXISTS ore_64_8_v1_term_btree_ops USING btree CASCADE;
10
+ DROP TYPE IF EXISTS ore_64_8_v1_term CASCADE;
11
+
12
+ DROP OPERATOR IF EXISTS = (ore_64_8_v1, ore_64_8_v1) CASCADE;
13
+ DROP OPERATOR IF EXISTS <> (ore_64_8_v1, ore_64_8_v1) CASCADE;
14
+ DROP OPERATOR IF EXISTS > (ore_64_8_v1, ore_64_8_v1) CASCADE;
15
+ DROP OPERATOR IF EXISTS < (ore_64_8_v1, ore_64_8_v1) CASCADE;
16
+ DROP OPERATOR IF EXISTS <= (ore_64_8_v1, ore_64_8_v1) CASCADE;
17
+ DROP OPERATOR IF EXISTS >= (ore_64_8_v1, ore_64_8_v1) CASCADE;
18
+ DROP OPERATOR CLASS IF EXISTS ore_64_8_v1_btree_ops USING btree CASCADE;
19
+ DROP OPERATOR FAMILY IF EXISTS ore_64_8_v1_btree_ops USING btree CASCADE;
20
+ DROP TYPE IF EXISTS ore_64_8_v1 CASCADE;