On this page
module ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements
Public Instance Methods
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 326
def client_min_messages
select_value('SHOW client_min_messages', 'SCHEMA')
end
Returns the current client message level.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 331
def client_min_messages=(level)
execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
end
Set the client message level.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 278
def collation
select_value("SELECT datcollate FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
end
Returns the current database collation.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 38
def create_database(name, options = {})
options = { encoding: 'utf8' }.merge!(options.symbolize_keys)
option_string = options.inject("") do |memo, (key, value)|
memo += case key
when :owner
" OWNER = \"#{value}\""
when :template
" TEMPLATE = \"#{value}\""
when :encoding
" ENCODING = '#{value}'"
when :collation
" LC_COLLATE = '#{value}'"
when :ctype
" LC_CTYPE = '#{value}'"
when :tablespace
" TABLESPACE = \"#{value}\""
when :connection_limit
" CONNECTION LIMIT = #{value}"
else
""
end
end
execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
end
Create a new PostgreSQL database. Options include :owner
, :template
, :encoding
(defaults to utf8), :collation
, :ctype
, :tablespace
, and :connection_limit
(note that MySQL uses :charset
while PostgreSQL uses :encoding
).
Example:
create_database config[:database], config
create_database 'foo_development', encoding: 'unicode'
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 299
def create_schema schema_name
execute "CREATE SCHEMA #{quote_schema_name(schema_name)}"
end
Creates a schema for the given schema name.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 283
def ctype
select_value("SELECT datctype FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
end
Returns the current database ctype.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 263
def current_database
select_value('select current_database()', 'SCHEMA')
end
Returns the current database name.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 268
def current_schema
select_value('SELECT current_schema', 'SCHEMA')
end
Returns the current schema name.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 107
def data_source_exists?(name)
name = Utils.extract_schema_qualified_name(name.to_s)
return false unless name.identifier
select_value(" SELECT COUNT(*)
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
AND c.relname = '#{name.identifier}'
AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
", 'SCHEMA').to_i > 0
end
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 84
def data_sources # :nodoc
select_values(" SELECT c.relname
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r', 'v','m') -- (r)elation/table, (v)iew, (m)aterialized view
AND n.nspname = ANY (current_schemas(false))
", 'SCHEMA')
end
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 304
def drop_schema(schema_name, options = {})
execute "DROP SCHEMA#{' IF EXISTS' if options[:if_exists]} #{quote_schema_name(schema_name)} CASCADE"
end
Drops the schema for the given schema name.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 273
def encoding
select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
end
Returns the current database encoding format.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 678
def fetch_type_metadata(column_name, sql_type, oid, fmod)
cast_type = get_oid_type(oid, fmod, column_name, sql_type)
simple_type = SqlTypeMetadata.new(
sql_type: sql_type,
type: cast_type.type,
limit: cast_type.limit,
precision: cast_type.precision,
scale: cast_type.scale,
)
PostgreSQLTypeMetadata.new(simple_type, oid: oid, fmod: fmod)
end
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 595
def foreign_keys(table_name)
fk_info = select_all(" SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
FROM pg_constraint c
JOIN pg_class t1 ON c.conrelid = t1.oid
JOIN pg_class t2 ON c.confrelid = t2.oid
JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
JOIN pg_namespace t3 ON c.connamespace = t3.oid
WHERE c.contype = 'f'
AND t1.relname = #{quote(table_name)}
AND t3.nspname = ANY (current_schemas(false))
ORDER BY c.conname
".strip_heredoc, 'SCHEMA')
fk_info.map do |row|
options = {
column: row['column'],
name: row['name'],
primary_key: row['primary_key']
}
options[:on_delete] = extract_foreign_key_action(row['on_delete'])
options[:on_update] = extract_foreign_key_action(row['on_update'])
ForeignKeyDefinition.new(table_name, row['to_table'], options)
end
end
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 155
def index_name_exists?(table_name, index_name, default)
table = Utils.extract_schema_qualified_name(table_name.to_s)
index = Utils.extract_schema_qualified_name(index_name.to_s)
select_value(" SELECT COUNT(*)
FROM pg_class t
INNER JOIN pg_index d ON t.oid = d.indrelid
INNER JOIN pg_class i ON d.indexrelid = i.oid
LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
WHERE i.relkind = 'i'
AND i.relname = '#{index.identifier}'
AND t.relname = '#{table.identifier}'
AND n.nspname = #{index.schema ? "'#{index.schema}'" : 'ANY (current_schemas(false))'}
", 'SCHEMA').to_i > 0
end
Verifies existence of an index with a given name.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 173
def indexes(table_name, name = nil)
table = Utils.extract_schema_qualified_name(table_name.to_s)
result = query(" SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
pg_catalog.obj_description(i.oid, 'pg_class') AS comment,
(SELECT COUNT(*) FROM pg_opclass o
JOIN (SELECT unnest(string_to_array(d.indclass::text, ' '))::int oid) c
ON o.oid = c.oid WHERE o.opcdefault = 'f')
FROM pg_class t
INNER JOIN pg_index d ON t.oid = d.indrelid
INNER JOIN pg_class i ON d.indexrelid = i.oid
LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
WHERE i.relkind = 'i'
AND d.indisprimary = 'f'
AND t.relname = '#{table.identifier}'
AND n.nspname = #{table.schema ? "'#{table.schema}'" : 'ANY (current_schemas(false))'}
ORDER BY i.relname
", 'SCHEMA')
result.map do |row|
index_name = row[0]
unique = row[1]
indkey = row[2].split(" ").map(&:to_i)
inddef = row[3]
oid = row[4]
comment = row[5]
opclass = row[6]
using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten
if indkey.include?(0) || opclass > 0
columns = expressions
else
columns = Hash[query(" SELECT a.attnum, a.attname
FROM pg_attribute a
WHERE a.attrelid = #{oid}
AND a.attnum IN (#{indkey.join(",")})
".strip_heredoc, "SCHEMA")].values_at(*indkey).compact
# add info on sort order for columns (only desc order is explicitly specified, asc is the default)
orders = Hash[
expressions.scan(/(\w+) DESC/).flatten.map { |order_column| [order_column, :desc] }
]
end
IndexDefinition.new(table_name, index_name, unique, columns, [], orders, where, nil, using.to_sym, comment.presence)
end.compact
end
Returns an array of indexes for the given table.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 589
def rename_index(table_name, old_name, new_name)
validate_index_length!(table_name, new_name)
execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
end
Renames an index of a table. Raises error if length of new index name is greater than allowed limit.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 468
def rename_table(table_name, new_name)
clear_cache!
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
pk, seq = pk_and_sequence_for(new_name)
if seq && seq.identifier == "#{table_name}_#{pk}_seq"
new_seq = "#{new_name}_#{pk}_seq"
idx = "#{table_name}_pkey"
new_idx = "#{new_name}_pkey"
execute "ALTER TABLE #{seq.quoted} RENAME TO #{quote_table_name(new_seq)}"
execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_table_name(new_idx)}"
end
rename_table_indexes(table_name, new_name)
end
Renames a table. Also renames a table's primary key sequence if the sequence name exists and matches the Active Record default.
Example:
rename_table('octopuses', 'octopi')
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 150
def schema_exists?(name)
select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", 'SCHEMA').to_i > 0
end
Returns true if schema exists.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 288
def schema_names
select_values(" SELECT nspname
FROM pg_namespace
WHERE nspname !~ '^pg_.*'
AND nspname NOT IN ('information_schema')
ORDER by nspname;
", 'SCHEMA')
end
Returns an array of schema names.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 321
def schema_search_path
@schema_search_path ||= select_value('SHOW search_path', 'SCHEMA')
end
Returns the active schema search path.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 313
def schema_search_path=(schema_csv)
if schema_csv
execute("SET search_path TO #{schema_csv}", 'SCHEMA')
@schema_search_path = schema_csv
end
end
Sets the schema search path to a string of comma-separated schema names. Names beginning with $ have to be quoted (e.g. $user => '$user'). See: www.postgresql.org/docs/current/static/ddl-schemas.html
This should be not be called manually but set in database.yml.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 344
def serial_sequence(table, column)
select_value("SELECT pg_get_serial_sequence('#{table}', '#{column}')", 'SCHEMA')
end
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 97
def table_exists?(name)
ActiveSupport::Deprecation.warn(" #table_exists? currently checks both tables and views.
This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
Use #data_source_exists? instead.
".squish)
data_source_exists?(name)
end
Returns true if table exists. If the schema is not specified as part of name
then it will only find tables within the current schema search path (regardless of permissions to access tables in other schemas)
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 74
def tables(name = nil)
if name
ActiveSupport::Deprecation.warn(" Passing arguments to #tables is deprecated without replacement.
".squish)
end
select_values("SELECT tablename FROM pg_tables WHERE schemaname = ANY(current_schemas(false))", 'SCHEMA')
end
Returns the list of all tables in the schema search path.
# File activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb, line 633
def type_to_sql(type, limit = nil, precision = nil, scale = nil, array = nil)
sql = case type.to_s
when 'binary'
# PostgreSQL doesn't support limits on binary (bytea) columns.
# The hard limit is 1GB, because of a 32-bit size field, and TOAST.
case limit
when nil, 0..0x3fffffff; super(type)
else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
end
when 'text'
# PostgreSQL doesn't support limits on text columns.
# The hard limit is 1GB, according to section 8.3 in the manual.
case limit
when nil, 0..0x3fffffff; super(type)
else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
end
when 'integer'
case limit
when 1, 2; 'smallint'
when nil, 3, 4; 'integer'
when 5..8; 'bigint'
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
end
else
super(type, limit, precision, scale)
end
sql << '[]' if array && type != :primary_key
sql
end
Maps logical Rails types to PostgreSQL-specific data types.
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.