activerecord-materialize-adapter 0.2.0 → 0.3.0
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.
- checksums.yaml +4 -4
- data/lib/active_record/connection_adapters/materialize/column.rb +0 -9
- data/lib/active_record/connection_adapters/materialize/database_statements.rb +22 -41
- data/lib/active_record/connection_adapters/materialize/oid.rb +0 -12
- data/lib/active_record/connection_adapters/materialize/oid/type_map_initializer.rb +5 -48
- data/lib/active_record/connection_adapters/materialize/quoting.rb +1 -7
- data/lib/active_record/connection_adapters/materialize/schema/source_statements.rb +66 -0
- data/lib/active_record/connection_adapters/materialize/schema/view_statements.rb +22 -0
- data/lib/active_record/connection_adapters/materialize/schema_creation.rb +18 -53
- data/lib/active_record/connection_adapters/materialize/schema_definitions.rb +3 -6
- data/lib/active_record/connection_adapters/materialize/schema_dumper.rb +82 -22
- data/lib/active_record/connection_adapters/materialize/schema_statements.rb +102 -354
- data/lib/active_record/connection_adapters/materialize/version.rb +1 -1
- data/lib/active_record/connection_adapters/materialize_adapter.rb +100 -253
- metadata +9 -15
- data/lib/active_record/connection_adapters/materialize/oid/cidr.rb +0 -50
- data/lib/active_record/connection_adapters/materialize/oid/legacy_point.rb +0 -44
- data/lib/active_record/connection_adapters/materialize/oid/money.rb +0 -41
- data/lib/active_record/connection_adapters/materialize/oid/point.rb +0 -64
- data/lib/active_record/connection_adapters/materialize/oid/range.rb +0 -96
- data/lib/active_record/connection_adapters/materialize/oid/uuid.rb +0 -25
- data/lib/active_record/connection_adapters/materialize/oid/vector.rb +0 -28
- data/lib/active_record/connection_adapters/materialize/oid/xml.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03b754e13f63726e0e11d14107d145449521404b78ccafb431d83de73dcf2360
|
4
|
+
data.tar.gz: bc53fd81cece00b418ea20ab4068bc5b063bee235f48bcd16f665d7be05ab4f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99041a07b198e3cd30000855d02698fd3e222040f2d25693060e407b9f068242d694785feecf2bb61187a72f30f02446f50e8da0fac2dbc7419ca9228b914523
|
7
|
+
data.tar.gz: dc272b7bbbd43a0ead177606b944b871f94fe8e85597c4e12263f1c987710b0bfd07d1030ea39581fcb7da92457edd6ea7db0cef3bf4700c3508b37945db0e61
|
@@ -6,15 +6,6 @@ module ActiveRecord
|
|
6
6
|
class Column < ActiveRecord::ConnectionAdapters::Column # :nodoc:
|
7
7
|
delegate :oid, :fmod, to: :sql_type_metadata
|
8
8
|
|
9
|
-
def initialize(*, serial: nil, **)
|
10
|
-
super
|
11
|
-
@serial = serial
|
12
|
-
end
|
13
|
-
|
14
|
-
def serial?
|
15
|
-
@serial
|
16
|
-
end
|
17
|
-
|
18
9
|
def array
|
19
10
|
sql_type_metadata.sql_type.end_with?("[]")
|
20
11
|
end
|
@@ -11,9 +11,9 @@ module ActiveRecord
|
|
11
11
|
Materialize::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", binds))
|
12
12
|
end
|
13
13
|
|
14
|
-
# The internal
|
14
|
+
# The internal PostgreSQL identifier of the money data type.
|
15
15
|
MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
|
16
|
-
# The internal
|
16
|
+
# The internal PostgreSQL identifier of the BYTEA data type.
|
17
17
|
BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
|
18
18
|
|
19
19
|
# create a 2D array representing the result set
|
@@ -62,15 +62,17 @@ module ActiveRecord
|
|
62
62
|
def query(sql, name = nil) #:nodoc:
|
63
63
|
materialize_transactions
|
64
64
|
|
65
|
+
result = nil
|
65
66
|
log(sql, name) do
|
66
67
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
67
|
-
|
68
|
+
result = execute_async_and_raise(sql)
|
68
69
|
end
|
69
70
|
end
|
71
|
+
result_as_array result
|
70
72
|
end
|
71
73
|
|
72
74
|
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
73
|
-
:begin, :commit, :explain, :select, :set, :show, :
|
75
|
+
:begin, :commit, :explain, :select, :set, :show, :rollback, :with
|
74
76
|
) # :nodoc:
|
75
77
|
private_constant :READ_QUERY
|
76
78
|
|
@@ -89,20 +91,13 @@ module ActiveRecord
|
|
89
91
|
|
90
92
|
materialize_transactions
|
91
93
|
|
94
|
+
result = nil
|
92
95
|
log(sql, name) do
|
93
96
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
94
|
-
|
97
|
+
result = execute_async_and_raise(sql)
|
95
98
|
end
|
96
99
|
end
|
97
|
-
|
98
|
-
# Known issue: PG::InternalError: ERROR: At least one input has no complete timestamps yet
|
99
|
-
# https://github.com/MaterializeInc/materialize/issues/2917
|
100
|
-
rescue ActiveRecord::StatementInvalid => error
|
101
|
-
if error.message.include? "At least one input has no complete timestamps yet"
|
102
|
-
raise ::Materialize::Errors::IncompleteInput, error.message
|
103
|
-
else
|
104
|
-
raise
|
105
|
-
end
|
100
|
+
result
|
106
101
|
end
|
107
102
|
|
108
103
|
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
@@ -112,6 +107,7 @@ module ActiveRecord
|
|
112
107
|
fields.each_with_index do |fname, i|
|
113
108
|
ftype = result.ftype i
|
114
109
|
fmod = result.fmod i
|
110
|
+
|
115
111
|
types[fname] = get_oid_type(ftype, fmod, fname)
|
116
112
|
end
|
117
113
|
ActiveRecord::Result.new(fields, result.values, types)
|
@@ -130,32 +126,10 @@ module ActiveRecord
|
|
130
126
|
pk = primary_key(table_ref) if table_ref
|
131
127
|
end
|
132
128
|
|
133
|
-
if pk = suppress_composite_primary_key(pk)
|
134
|
-
sql = "#{sql} RETURNING #{quote_column_name(pk)}"
|
135
|
-
end
|
136
|
-
|
137
129
|
super
|
138
130
|
end
|
139
131
|
private :sql_for_insert
|
140
132
|
|
141
|
-
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
142
|
-
if use_insert_returning? || pk == false
|
143
|
-
super
|
144
|
-
else
|
145
|
-
result = exec_query(sql, name, binds)
|
146
|
-
unless sequence_name
|
147
|
-
table_ref = extract_table_ref_from_insert_sql(sql)
|
148
|
-
if table_ref
|
149
|
-
pk = primary_key(table_ref) if pk.nil?
|
150
|
-
pk = suppress_composite_primary_key(pk)
|
151
|
-
sequence_name = default_sequence_name(table_ref, pk)
|
152
|
-
end
|
153
|
-
return result unless sequence_name
|
154
|
-
end
|
155
|
-
last_insert_id_result(sequence_name)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
133
|
# Begins a transaction.
|
160
134
|
def begin_db_transaction
|
161
135
|
execute "BEGIN"
|
@@ -177,6 +151,18 @@ module ActiveRecord
|
|
177
151
|
end
|
178
152
|
|
179
153
|
private
|
154
|
+
# Known issue: PG::InternalError: ERROR: At least one input has no complete timestamps yet
|
155
|
+
# https://github.com/MaterializeInc/materialize/issues/2917
|
156
|
+
def execute_async_and_raise(sql)
|
157
|
+
@connection.async_exec(sql)
|
158
|
+
rescue PG::InternalError => error
|
159
|
+
if error.message.include? "At least one input has no complete timestamps yet"
|
160
|
+
raise ::Materialize::Errors::IncompleteInput, error.message
|
161
|
+
else
|
162
|
+
raise
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
180
166
|
def execute_batch(statements, name = nil)
|
181
167
|
execute(combine_multi_statements(statements))
|
182
168
|
end
|
@@ -185,11 +171,6 @@ module ActiveRecord
|
|
185
171
|
["TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"]
|
186
172
|
end
|
187
173
|
|
188
|
-
# Returns the current ID of a table's sequence.
|
189
|
-
def last_insert_id_result(sequence_name)
|
190
|
-
exec_query("SELECT currval(#{quote(sequence_name)})", "SQL")
|
191
|
-
end
|
192
|
-
|
193
174
|
def suppress_composite_primary_key(pk)
|
194
175
|
pk unless pk.is_a?(Array)
|
195
176
|
end
|
@@ -5,24 +5,12 @@ require "active_record/connection_adapters/materialize/oid/array"
|
|
5
5
|
require "active_record/connection_adapters/materialize/oid/bit"
|
6
6
|
require "active_record/connection_adapters/materialize/oid/bit_varying"
|
7
7
|
require "active_record/connection_adapters/materialize/oid/bytea"
|
8
|
-
require "active_record/connection_adapters/materialize/oid/cidr"
|
9
8
|
require "active_record/connection_adapters/materialize/oid/date"
|
10
9
|
require "active_record/connection_adapters/materialize/oid/date_time"
|
11
10
|
require "active_record/connection_adapters/materialize/oid/decimal"
|
12
11
|
require "active_record/connection_adapters/materialize/oid/enum"
|
13
|
-
require "active_record/connection_adapters/materialize/oid/hstore"
|
14
|
-
require "active_record/connection_adapters/materialize/oid/inet"
|
15
12
|
require "active_record/connection_adapters/materialize/oid/jsonb"
|
16
|
-
require "active_record/connection_adapters/materialize/oid/money"
|
17
13
|
require "active_record/connection_adapters/materialize/oid/oid"
|
18
|
-
require "active_record/connection_adapters/materialize/oid/point"
|
19
|
-
require "active_record/connection_adapters/materialize/oid/legacy_point"
|
20
|
-
require "active_record/connection_adapters/materialize/oid/range"
|
21
|
-
require "active_record/connection_adapters/materialize/oid/specialized_string"
|
22
|
-
require "active_record/connection_adapters/materialize/oid/uuid"
|
23
|
-
require "active_record/connection_adapters/materialize/oid/vector"
|
24
|
-
require "active_record/connection_adapters/materialize/oid/xml"
|
25
|
-
|
26
14
|
require "active_record/connection_adapters/materialize/oid/type_map_initializer"
|
27
15
|
|
28
16
|
module ActiveRecord
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters
|
7
7
|
module Materialize
|
8
8
|
module OID # :nodoc:
|
9
|
-
# This class uses the data from Materialize
|
9
|
+
# This class uses the data from Materialize mz_types table to build
|
10
10
|
# the OID -> Type mapping.
|
11
11
|
# - OID is an integer representing the type.
|
12
12
|
# - Type is an OID::Type object.
|
@@ -18,65 +18,22 @@ module ActiveRecord
|
|
18
18
|
|
19
19
|
def run(records)
|
20
20
|
nodes = records.reject { |row| @store.key? row["oid"].to_i }
|
21
|
-
mapped = nodes.extract! { |row| @store.key? row["
|
22
|
-
ranges = nodes.extract! { |row| row["typtype"] == "r" }
|
23
|
-
enums = nodes.extract! { |row| row["typtype"] == "e" }
|
24
|
-
domains = nodes.extract! { |row| row["typtype"] == "d" }
|
25
|
-
arrays = nodes.extract! { |row| row["typinput"] == "array_in" }
|
26
|
-
composites = nodes.extract! { |row| row["typelem"].to_i != 0 }
|
21
|
+
mapped = nodes.extract! { |row| @store.key? row["name"] }
|
27
22
|
|
28
|
-
mapped.each
|
29
|
-
enums.each { |row| register_enum_type(row) }
|
30
|
-
domains.each { |row| register_domain_type(row) }
|
31
|
-
arrays.each { |row| register_array_type(row) }
|
32
|
-
ranges.each { |row| register_range_type(row) }
|
33
|
-
composites.each { |row| register_composite_type(row) }
|
23
|
+
mapped.each { |row| register_mapped_type(row) }
|
34
24
|
end
|
35
25
|
|
36
26
|
def query_conditions_for_initial_load
|
37
27
|
known_type_names = @store.keys.map { |n| "'#{n}'" }
|
38
28
|
known_type_types = %w('r' 'e' 'd')
|
39
29
|
<<~SQL % [known_type_names.join(", "), known_type_types.join(", ")]
|
40
|
-
|
41
|
-
t.typname IN (%s)
|
42
|
-
OR t.typtype IN (%s)
|
43
|
-
OR t.typelem != 0
|
30
|
+
AND t.name IN (%s)
|
44
31
|
SQL
|
45
32
|
end
|
46
33
|
|
47
34
|
private
|
48
35
|
def register_mapped_type(row)
|
49
|
-
alias_type row["oid"], row["
|
50
|
-
end
|
51
|
-
|
52
|
-
def register_enum_type(row)
|
53
|
-
register row["oid"], OID::Enum.new
|
54
|
-
end
|
55
|
-
|
56
|
-
def register_array_type(row)
|
57
|
-
register_with_subtype(row["oid"], row["typelem"].to_i) do |subtype|
|
58
|
-
OID::Array.new(subtype, row["typdelim"])
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def register_range_type(row)
|
63
|
-
register_with_subtype(row["oid"], row["rngsubtype"].to_i) do |subtype|
|
64
|
-
OID::Range.new(subtype, row["typname"].to_sym)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def register_domain_type(row)
|
69
|
-
if base_type = @store.lookup(row["typbasetype"].to_i)
|
70
|
-
register row["oid"], base_type
|
71
|
-
else
|
72
|
-
warn "unknown base type (OID: #{row["typbasetype"]}) for domain #{row["typname"]}."
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def register_composite_type(row)
|
77
|
-
if subtype = @store.lookup(row["typelem"].to_i)
|
78
|
-
register row["oid"], OID::Vector.new(row["typdelim"], subtype)
|
79
|
-
end
|
36
|
+
alias_type row["oid"], row["name"]
|
80
37
|
end
|
81
38
|
|
82
39
|
def register(oid, oid_type = nil, &block)
|
@@ -116,14 +116,8 @@ module ActiveRecord
|
|
116
116
|
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
117
117
|
|
118
118
|
private
|
119
|
-
def lookup_cast_type(sql_type)
|
120
|
-
super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i)
|
121
|
-
end
|
122
|
-
|
123
119
|
def _quote(value)
|
124
120
|
case value
|
125
|
-
when OID::Xml::Data
|
126
|
-
"xml '#{quote_string(value.to_s)}'"
|
127
121
|
when OID::Bit::Data
|
128
122
|
if value.binary?
|
129
123
|
"B'#{value}'"
|
@@ -152,7 +146,7 @@ module ActiveRecord
|
|
152
146
|
# See https://deveiate.org/code/pg/PG/Connection.html#method-i-exec_prepared-doc
|
153
147
|
# for more information
|
154
148
|
{ value: value.to_s, format: 1 }
|
155
|
-
when OID::
|
149
|
+
when OID::Bit::Data
|
156
150
|
value.to_s
|
157
151
|
when OID::Array::Data
|
158
152
|
encode_array(value)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module Materialize
|
6
|
+
module Schema
|
7
|
+
module SourceStatements
|
8
|
+
|
9
|
+
def sources
|
10
|
+
query_values(data_source_sql(type: "SOURCE"), "SCHEMA")
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get source options from an existing source
|
14
|
+
def source_options(source_name)
|
15
|
+
name_ref, statement = query("SHOW CREATE SOURCE #{quote_table_name(source_name)}", "SCHEMA").first
|
16
|
+
database_name, schema_name, publication_name = name_ref.split(".")
|
17
|
+
materialized = !!/CREATE\sMATERIALIZED/.match(statement)
|
18
|
+
_, source_type, _ = /FROM\s(POSTGRES|KAFKA\sBROKER)\sCONNECTION/.match(statement).to_s.split " "
|
19
|
+
source_type = source_type.to_s.downcase.to_sym
|
20
|
+
|
21
|
+
{
|
22
|
+
database_name: database_name,
|
23
|
+
schema_name: schema_name,
|
24
|
+
source_name: source_name,
|
25
|
+
source_type: source_type,
|
26
|
+
publication: publication_name,
|
27
|
+
materialized: materialized || source_type == :postgres
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
# "host=postgresdb port=5432 user=postgres dbname=source_database"
|
32
|
+
def select_database_config(connection_params)
|
33
|
+
{
|
34
|
+
host: connection_params['host'],
|
35
|
+
port: connection_params['port'],
|
36
|
+
user: connection_params['username'],
|
37
|
+
dbname: connection_params['database'],
|
38
|
+
password: connection_params['password']
|
39
|
+
}.compact
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_source(source_name, publication:, source_type: :postgres, materialized: true, connection_params: nil)
|
43
|
+
materialized_statement = materialized ? 'MATERIALIZED ' : ''
|
44
|
+
connection_string = select_database_config(connection_params).map { |k, v| [k, v].join("=") }.join(" ")
|
45
|
+
case source_type
|
46
|
+
when :postgres
|
47
|
+
execute <<-SQL.squish
|
48
|
+
CREATE #{materialized_statement}SOURCE #{quote_schema_name(source_name)} FROM POSTGRES
|
49
|
+
CONNECTION #{quote(connection_string)}
|
50
|
+
PUBLICATION #{quote(publication)}
|
51
|
+
SQL
|
52
|
+
else
|
53
|
+
raise "Source type #{source_type} is currently unsupported for Materialized sources", NotImplementedError
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def drop_source(source_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def source_exists?(source_name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module Materialize
|
6
|
+
module Schema
|
7
|
+
module ViewStatements
|
8
|
+
|
9
|
+
# Returns an array of view names defined in the database.
|
10
|
+
def materialized_views
|
11
|
+
query_values(data_source_sql(type: "MATERIALIZED"), "SCHEMA")
|
12
|
+
end
|
13
|
+
|
14
|
+
def view_sql(view_name)
|
15
|
+
query("SHOW CREATE VIEW #{quote_table_name(view_name)}", "SCHEMA").first.last
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -5,71 +5,36 @@ module ActiveRecord
|
|
5
5
|
module Materialize
|
6
6
|
class SchemaCreation < AbstractAdapter::SchemaCreation # :nodoc:
|
7
7
|
private
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def visit_AddForeignKey(o)
|
13
|
-
super.dup.tap { |sql| sql << " NOT VALID" unless o.validate? }
|
14
|
-
end
|
15
|
-
|
16
|
-
def visit_ValidateConstraint(name)
|
17
|
-
"VALIDATE CONSTRAINT #{quote_column_name(name)}"
|
18
|
-
end
|
19
|
-
|
20
|
-
def visit_ChangeColumnDefinition(o)
|
21
|
-
column = o.column
|
22
|
-
column.sql_type = type_to_sql(column.type, **column.options)
|
23
|
-
quoted_column_name = quote_column_name(o.name)
|
24
|
-
|
25
|
-
change_column_sql = +"ALTER COLUMN #{quoted_column_name} TYPE #{column.sql_type}"
|
8
|
+
def visit_TableDefinition(o)
|
9
|
+
create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
|
10
|
+
create_sql << "IF NOT EXISTS " if o.if_not_exists
|
11
|
+
create_sql << "#{quote_table_name(o.name)} "
|
26
12
|
|
27
|
-
|
13
|
+
statements = o.columns.map { |c| accept c }
|
28
14
|
|
29
|
-
if
|
30
|
-
|
15
|
+
if supports_indexes_in_create?
|
16
|
+
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
31
17
|
end
|
32
18
|
|
33
|
-
if
|
34
|
-
|
35
|
-
elsif options[:cast_as]
|
36
|
-
cast_as_type = type_to_sql(options[:cast_as], **options)
|
37
|
-
change_column_sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
|
19
|
+
if supports_foreign_keys?
|
20
|
+
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
38
21
|
end
|
39
22
|
|
40
|
-
if
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
quoted_default = quote_default_expression(options[:default], column)
|
45
|
-
change_column_sql << ", ALTER COLUMN #{quoted_column_name} SET DEFAULT #{quoted_default}"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
if options.key?(:null)
|
50
|
-
change_column_sql << ", ALTER COLUMN #{quoted_column_name} #{options[:null] ? 'DROP' : 'SET'} NOT NULL"
|
51
|
-
end
|
52
|
-
|
53
|
-
change_column_sql
|
23
|
+
create_sql << "(#{statements.join(', ')})" if statements.present?
|
24
|
+
add_table_options!(create_sql, table_options(o))
|
25
|
+
create_sql << " AS #{to_sql(o.as)}" if o.as
|
26
|
+
create_sql
|
54
27
|
end
|
55
28
|
|
56
29
|
def add_column_options!(sql, options)
|
57
|
-
|
58
|
-
|
30
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
31
|
+
# must explicitly check for :null to allow change_column to work on migrations
|
32
|
+
if options[:null] == false
|
33
|
+
sql << " NOT NULL"
|
59
34
|
end
|
60
|
-
|
35
|
+
sql
|
61
36
|
end
|
62
37
|
|
63
|
-
# Returns any SQL string to go between CREATE and TABLE. May be nil.
|
64
|
-
def table_modifier_in_create(o)
|
65
|
-
# A table cannot be both TEMPORARY and UNLOGGED, since all TEMPORARY
|
66
|
-
# tables are already UNLOGGED.
|
67
|
-
if o.temporary
|
68
|
-
" TEMPORARY"
|
69
|
-
elsif o.unlogged
|
70
|
-
" UNLOGGED"
|
71
|
-
end
|
72
|
-
end
|
73
38
|
end
|
74
39
|
end
|
75
40
|
end
|