activerecord-materialize-adapter 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|