1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

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.
This commit is contained in:
Ryuta Kamizono 2019-04-08 18:57:05 +09:00
parent bf1494a101
commit f185e0ebc9
7 changed files with 47 additions and 48 deletions

View file

@ -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 @@ module ActiveRecord
# +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 @@ module ActiveRecord
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 @@ module ActiveRecord
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 @@ module ActiveRecord
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

View file

@ -55,7 +55,7 @@ module ActiveRecord
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 @@ module ActiveRecord
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]}" \

View file

@ -174,9 +174,8 @@ module ActiveRecord
default,
type_metadata,
field[:Null] == "YES",
table_name,
default_function,
field[:Collation],
collation: field[:Collation],
comment: field[:Comment].presence
)
end

View file

@ -2,42 +2,21 @@
module ActiveRecord
module ConnectionAdapters
# PostgreSQL-specific extensions to column definitions in a table.
class PostgreSQLColumn < Column #:nodoc:
module PostgreSQL
class Column < ConnectionAdapters::Column # :nodoc:
delegate :array, :oid, :fmod, to: :sql_type_metadata
alias :array? :array
def initialize(*, max_identifier_length: 63, **)
def initialize(*, serial: nil, **)
super
@max_identifier_length = max_identifier_length
@serial = serial
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
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}"
@serial
end
end
end
PostgreSQLColumn = PostgreSQL::Column # :nodoc:
end
end

View file

@ -650,16 +650,19 @@ module ActiveRecord
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 @@ module ActiveRecord
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

View file

@ -105,7 +105,7 @@ module ActiveRecord
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)

View file

@ -47,6 +47,7 @@ module ActiveRecord
end
private
attr_accessor :table_name
def initialize(connection, options = {})
@connection = connection
@ -110,6 +111,8 @@ HEADER
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 @@ HEADER
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