提交 f185e0eb 编写于 作者: R Ryuta Kamizono

Except `table_name` from column objects

The `table_name` was added at #23677 to detect whether serial column or
not correctly.

We can do that detection before initialize column object, it makes
column object size smaller, and it probably helps column object
de-duplication.
上级 bf1494a1
......@@ -5,7 +5,7 @@ module ActiveRecord
module ConnectionAdapters
# An abstract definition of a column in a table.
class Column
attr_reader :name, :default, :sql_type_metadata, :null, :table_name, :default_function, :collation, :comment
attr_reader :name, :default, :sql_type_metadata, :null, :default_function, :collation, :comment
delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
......@@ -15,9 +15,8 @@ class Column
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
# +sql_type_metadata+ is various information about the type of the column
# +null+ determines if this column allows +NULL+ values.
def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil, **)
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, **)
@name = name.freeze
@table_name = table_name
@sql_type_metadata = sql_type_metadata
@null = null
@default = default
......@@ -44,7 +43,6 @@ def human_name
def init_with(coder)
@name = coder["name"]
@table_name = coder["table_name"]
@sql_type_metadata = coder["sql_type_metadata"]
@null = coder["null"]
@default = coder["default"]
......@@ -55,7 +53,6 @@ def init_with(coder)
def encode_with(coder)
coder["name"] = @name
coder["table_name"] = @table_name
coder["sql_type_metadata"] = @sql_type_metadata
coder["null"] = @null
coder["default"] = @default
......@@ -77,7 +74,7 @@ def hash
protected
def attributes_for_hash
[self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
[self.class, name, default, sql_type_metadata, null, default_function, collation, comment]
end
end
......
......@@ -55,7 +55,7 @@ def schema_precision(column)
end
def schema_collation(column)
if column.collation && table_name = column.table_name
if column.collation
@table_collation_cache ||= {}
@table_collation_cache[table_name] ||=
@connection.exec_query("SHOW TABLE STATUS LIKE #{@connection.quote(table_name)}", "SCHEMA").first["Collation"]
......@@ -65,13 +65,13 @@ def schema_collation(column)
def extract_expression_for_virtual_column(column)
if @connection.mariadb? && @connection.database_version < "10.2.5"
create_table_info = @connection.send(:create_table_info, column.table_name)
create_table_info = @connection.send(:create_table_info, table_name)
column_name = @connection.quote_column_name(column.name)
if %r/#{column_name} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info
$~[:expression].inspect
end
else
scope = @connection.send(:quoted_scope, column.table_name)
scope = @connection.send(:quoted_scope, table_name)
column_name = @connection.quote(column.name)
sql = "SELECT generation_expression FROM information_schema.columns" \
" WHERE table_schema = #{scope[:schema]}" \
......
......@@ -174,9 +174,8 @@ def new_column_from_field(table_name, field)
default,
type_metadata,
field[:Null] == "YES",
table_name,
default_function,
field[:Collation],
collation: field[:Collation],
comment: field[:Comment].presence
)
end
......
......@@ -2,42 +2,21 @@
module ActiveRecord
module ConnectionAdapters
# PostgreSQL-specific extensions to column definitions in a table.
class PostgreSQLColumn < Column #:nodoc:
delegate :array, :oid, :fmod, to: :sql_type_metadata
alias :array? :array
def initialize(*, max_identifier_length: 63, **)
super
@max_identifier_length = max_identifier_length
end
def serial?
return unless default_function
if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
sequence_name_from_parts(table_name, name, suffix) == sequence_name
module PostgreSQL
class Column < ConnectionAdapters::Column # :nodoc:
delegate :array, :oid, :fmod, to: :sql_type_metadata
alias :array? :array
def initialize(*, serial: nil, **)
super
@serial = serial
end
end
private
attr_reader :max_identifier_length
def sequence_name_from_parts(table_name, column_name, suffix)
over_length = [table_name, column_name, suffix].map(&:length).sum + 2 - max_identifier_length
if over_length > 0
column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
over_length -= column_name.length - column_name_length
column_name = column_name[0, column_name_length - [over_length, 0].min]
end
if over_length > 0
table_name = table_name[0, table_name.length - over_length]
end
"#{table_name}_#{column_name}_#{suffix}"
def serial?
@serial
end
end
end
PostgreSQLColumn = PostgreSQL::Column # :nodoc:
end
end
......@@ -650,16 +650,19 @@ def new_column_from_field(table_name, field)
default_value = extract_value_from_default(default)
default_function = extract_default_function(default_value, default)
PostgreSQLColumn.new(
if match = default_function&.match(/\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z/)
serial = sequence_name_from_parts(table_name, column_name, match[:suffix]) == match[:sequence_name]
end
PostgreSQL::Column.new(
column_name,
default_value,
type_metadata,
!notnull,
table_name,
default_function,
collation,
collation: collation,
comment: comment.presence,
max_identifier_length: max_identifier_length
serial: serial
)
end
......@@ -675,6 +678,22 @@ def fetch_type_metadata(column_name, sql_type, oid, fmod)
PostgreSQLTypeMetadata.new(simple_type, oid: oid, fmod: fmod)
end
def sequence_name_from_parts(table_name, column_name, suffix)
over_length = [table_name, column_name, suffix].sum(&:length) + 2 - max_identifier_length
if over_length > 0
column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
over_length -= column_name.length - column_name_length
column_name = column_name[0, column_name_length - [over_length, 0].min]
end
if over_length > 0
table_name = table_name[0, table_name.length - over_length]
end
"#{table_name}_#{column_name}_#{suffix}"
end
def extract_foreign_key_action(specifier)
case specifier
when "c"; :cascade
......
......@@ -105,7 +105,7 @@ def new_column_from_field(table_name, field)
end
type_metadata = fetch_type_metadata(field["type"])
Column.new(field["name"], default, type_metadata, field["notnull"].to_i == 0, table_name, nil, field["collation"])
Column.new(field["name"], default, type_metadata, field["notnull"].to_i == 0, collation: field["collation"])
end
def data_source_sql(name = nil, type: nil)
......
......@@ -47,6 +47,7 @@ def dump(stream)
end
private
attr_accessor :table_name
def initialize(connection, options = {})
@connection = connection
......@@ -110,6 +111,8 @@ def tables(stream)
def table(table, stream)
columns = @connection.columns(table)
begin
self.table_name = table
tbl = StringIO.new
# first dump primary key column
......@@ -159,6 +162,8 @@ def table(table, stream)
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
stream.puts "# #{e.message}"
stream.puts
ensure
self.table_name = nil
end
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册