| Class | ActiveRecord::ConnectionAdapters::PostgreSQLAdapter |
| In: |
activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
|
| Parent: | AbstractAdapter |
The PostgreSQL adapter works both with the native C (ruby.scripting.ca/postgres/) and the pure Ruby (available both as gem and from rubyforge.org/frs/?group_id=234&release_id=1944) drivers.
Options:
Initializes and connects a PostgreSQL adapter.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 230 def initialize(connection, logger, connection_parameters, config) super(connection, logger) @connection_parameters, @config = connection_parameters, config connect end
Is this connection alive and ready for queries?
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 238 def active? if @connection.respond_to?(:status) @connection.status == PGconn::CONNECTION_OK else # We're asking the driver, not ActiveRecord, so use @connection.query instead of #query @connection.query 'SELECT 1' true end # postgres-pr raises a NoMethodError when querying if no connection is available. rescue PGError, NoMethodError false end
Returns ‘PostgreSQL’ as adapter name for identification purposes.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 225 def adapter_name 'PostgreSQL' end
Adds a column to a table.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 583 def add_column(table_name, column_name, type, options = {}) default = options[:default] notnull = options[:null] == false quoted_column_name = quote_column_name(column_name) # Add the column. execute("ALTER TABLE #{table_name} ADD COLUMN #{quoted_column_name} #{type_to_sql(type, options[:limit])}") # Set optional default. If not null, update nulls to the new default. if options_include_default?(options) change_column_default(table_name, column_name, default) if notnull execute("UPDATE #{table_name} SET #{quoted_column_name}=#{quote(default, options[:column])} WHERE #{quoted_column_name} IS NULL") end end if notnull execute("ALTER TABLE #{table_name} ALTER #{quoted_column_name} SET NOT NULL") end end
Begins a transaction.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 411 def begin_db_transaction execute "BEGIN" end
Changes the column of a table.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 606 def change_column(table_name, column_name, type, options = {}) begin execute "ALTER TABLE #{table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" rescue ActiveRecord::StatementInvalid # This is PostgreSQL 7.x, so we have to use a more arcane way of doing it. begin_db_transaction tmp_column_name = "#{column_name}_ar_tmp" add_column(table_name, tmp_column_name, type, options) execute "UPDATE #{table_name} SET #{quote_column_name(tmp_column_name)} = CAST(#{quote_column_name(column_name)} AS #{type_to_sql(type, options[:limit], options[:precision], options[:scale])})" remove_column(table_name, column_name) rename_column(table_name, tmp_column_name, column_name) commit_db_transaction end if options_include_default?(options) change_column_default(table_name, column_name, options[:default]) end end
Changes the default value of a table column.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 626 def change_column_default(table_name, column_name, default) execute "ALTER TABLE #{table_name} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}" end
Returns the current client message level.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 499 def client_min_messages query('SHOW client_min_messages')[0][0] end
Set the client message level.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 504 def client_min_messages=(level) execute("SET client_min_messages TO '#{level}'") end
Returns the list of all column definitions for a table.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 474 def columns(table_name, name = nil) # Limit, precision, and scale are all handled by superclass. column_definitions(table_name).collect do |name, type, default, notnull| PostgreSQLColumn.new(name, default, type, notnull == 'f') end end
Commits a transaction.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 416 def commit_db_transaction execute "COMMIT" end
Close the connection.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 263 def disconnect! @connection.close rescue nil end
Executes a SQL statement, returning a PGresult object on success or raising a PGError exception otherwise.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 395 def execute(sql, name = nil) log(sql, name) do if @async @connection.async_exec(sql) else @connection.exec(sql) end end end
Returns the list of all indexes for a table.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 439 def indexes(table_name, name = nil) result = query("SELECT i.relname, d.indisunique, a.attname\nFROM pg_class t, pg_class i, pg_index d, pg_attribute a\nWHERE i.relkind = 'i'\nAND d.indexrelid = i.oid\nAND d.indisprimary = 'f'\nAND t.oid = d.indrelid\nAND t.relname = '\#{table_name}'\nAND a.attrelid = t.oid\nAND ( d.indkey[0]=a.attnum OR d.indkey[1]=a.attnum\nOR d.indkey[2]=a.attnum OR d.indkey[3]=a.attnum\nOR d.indkey[4]=a.attnum OR d.indkey[5]=a.attnum\nOR d.indkey[6]=a.attnum OR d.indkey[7]=a.attnum\nOR d.indkey[8]=a.attnum OR d.indkey[9]=a.attnum )\nORDER BY i.relname\n", name) current_index = nil indexes = [] result.each do |row| if current_index != row[0] indexes << IndexDefinition.new(table_name, row[0], row[1] == "t", []) current_index = row[0] end indexes.last.columns << row[2] end indexes end
Executes an INSERT query and returns the new record’s ID
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 377 def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) table = sql.split(" ", 4)[2] super || last_insert_id(table, sequence_name || default_sequence_name(table, pk)) end
Close then reopen the connection.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 252 def reconnect! if @connection.respond_to?(:reset) @connection.reset configure_connection else disconnect! connect end end
Drops an index from a table.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 636 def remove_index(table_name, options = {}) execute "DROP INDEX #{index_name(table_name, options)}" end
Renames a column in a table.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 631 def rename_column(table_name, column_name, new_column_name) execute "ALTER TABLE #{table_name} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}" end
Renames a table.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 578 def rename_table(name, new_name) execute "ALTER TABLE #{name} RENAME TO #{new_name}" end
Aborts a transaction.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 421 def rollback_db_transaction execute "ROLLBACK" end
Returns the active schema search path.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 494 def schema_search_path @schema_search_path ||= query('SHOW search_path')[0][0] 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_adapter.rb, line 486 def schema_search_path=(schema_csv) if schema_csv execute "SET search_path TO #{schema_csv}" @schema_search_path = schema_csv end end
Executes a SELECT query and returns an array of rows. Each row is an array of field values.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 372 def select_rows(sql, name = nil) select_raw(sql, name).last end
Does PostgreSQL support migrations?
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 285 def supports_migrations? true end
Does PostgreSQL support standard conforming strings?
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 290 def supports_standard_conforming_strings? # Temporarily set the client message level above error to prevent unintentional # error messages in the logs when working on a PostgreSQL database server that # does not support standard conforming strings. client_min_messages_old = client_min_messages self.client_min_messages = 'panic' # postgres-pr does not raise an exception when client_min_messages is set higher # than error and "SHOW standard_conforming_strings" fails, but returns an empty # PGresult instead. has_support = execute('SHOW standard_conforming_strings')[0][0] rescue false self.client_min_messages = client_min_messages_old has_support end
Returns the configured supported identifier length supported by PostgreSQL, or report the default of 63 on PostgreSQL 7.x.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 307 def table_alias_length @table_alias_length ||= (postgresql_version >= 80000 ? query('SHOW max_identifier_length')[0][0].to_i : 63) end
Returns the list of all tables in the schema search path or a specified schema.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 428 def tables(name = nil) schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',') query("SELECT tablename\nFROM pg_tables\nWHERE schemaname IN (\#{schemas})\n", name).map { |row| row[0] } end
Maps logical Rails types to PostgreSQL-specific data types.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 641 def type_to_sql(type, limit = nil, precision = nil, scale = nil) return super unless type.to_s == 'integer' if limit.nil? || limit == 4 'integer' elsif limit < 4 'smallint' else 'bigint' end end
Executes an UPDATE query and returns the number of affected tuples.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 406 def update_sql(sql, name = nil) super.cmdtuples end
Returns the version of the connected PostgreSQL version.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 690 def postgresql_version @postgresql_version ||= if @connection.respond_to?(:server_version) @connection.server_version else # Mimic PGconn.server_version behavior begin query('SELECT version()')[0][0] =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/ ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i rescue 0 end end end
Configures the encoding, verbosity, and schema search path of the connection. This is called by connect and should not be called manually.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 749 def configure_connection if @config[:encoding] if @connection.respond_to?(:set_client_encoding) @connection.set_client_encoding(@config[:encoding]) else execute("SET client_encoding TO '#{@config[:encoding]}'") end end self.client_min_messages = @config[:min_messages] if @config[:min_messages] self.schema_search_path = @config[:schema_search_path] || @config[:schema_order] end
Connects to a PostgreSQL server and sets up the adapter depending on the connected server’s characteristics.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 711 def connect @connection = PGconn.connect(*@connection_parameters) PGconn.translate_results = false if PGconn.respond_to?(:translate_results=) # Ignore async_exec and async_query when using postgres-pr. @async = @config[:allow_concurrency] && @connection.respond_to?(:async_exec) # Use escape string syntax if available. We cannot do this lazily when encountering # the first string, because that could then break any transactions in progress. # See: http://www.postgresql.org/docs/current/static/runtime-config-compatible.html # If PostgreSQL doesn't know the standard_conforming_strings parameter then it doesn't # support escape string syntax. Don't override the inherited quoted_string_prefix. if supports_standard_conforming_strings? self.class.instance_eval do define_method(:quoted_string_prefix) { 'E' } end end # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision # should know about this but can't detect it there, so deal with it here. money_precision = (postgresql_version >= 80300) ? 19 : 10 PostgreSQLColumn.module_eval("def extract_precision(sql_type)\nif sql_type =~ /^money$/\n\#{money_precision}\nelse\nsuper\nend\nend\n") configure_connection end
Executes a SELECT query and returns the results, performing any data type conversions that require to be performed here instead of in PostgreSQLColumn.
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 768 def select(sql, name = nil) fields, rows = select_raw(sql, name) result = [] for row in rows row_hash = {} fields.each_with_index do |f, i| row_hash[f] = row[i] end result << row_hash end result end
# File activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 781 def select_raw(sql, name = nil) res = execute(sql, name) results = res.result fields = [] rows = [] if results.length > 0 fields = res.fields results.each do |row| hashed_row = {} row.each_index do |cell_index| # If this is a money type column and there are any currency symbols, # then strip them off. Indeed it would be prettier to do this in # PostgreSQLColumn.string_to_decimal but would break form input # fields that call value_before_type_cast. if res.type(cell_index) == MONEY_COLUMN_TYPE_OID # Because money output is formatted according to the locale, there are two # cases to consider (note the decimal seperators): # (1) $12,345,678.12 # (2) $12.345.678,12 case column = row[cell_index] when /^-?\D+[\d,]+\.\d{2}$/ # (1) row[cell_index] = column.gsub(/[^-\d\.]/, '') when /^-?\D+[\d\.]+,\d{2}$/ # (2) row[cell_index] = column.gsub(/[^-\d,]/, '').sub(/,/, '.') end end hashed_row[fields[cell_index]] = column end rows << row end end res.clear return fields, rows end