| Class | ActiveRecord::ConnectionAdapters::PostgreSQLAdapter |
| In: |
vendor/rails/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 vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 181
181: def initialize(connection, logger, connection_parameters, config)
182: super(connection, logger)
183: @connection_parameters, @config = connection_parameters, config
184:
185: connect
186: end
Is this connection alive and ready for queries?
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 189
189: def active?
190: if @connection.respond_to?(:status)
191: @connection.status == PGconn::CONNECTION_OK
192: else
193: # We're asking the driver, not ActiveRecord, so use @connection.query instead of #query
194: @connection.query 'SELECT 1'
195: true
196: end
197: # postgres-pr raises a NoMethodError when querying if no connection is available.
198: rescue PGError, NoMethodError
199: false
200: end
Returns ‘PostgreSQL’ as adapter name for identification purposes.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 176
176: def adapter_name
177: 'PostgreSQL'
178: end
Adds a new column to the named table. See TableDefinition#column for details of the options you can use.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 700
700: def add_column(table_name, column_name, type, options = {})
701: default = options[:default]
702: notnull = options[:null] == false
703:
704: # Add the column.
705: execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}")
706:
707: change_column_default(table_name, column_name, default) if options_include_default?(options)
708: change_column_null(table_name, column_name, false, default) if notnull
709: end
Begins a transaction.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 472
472: def begin_db_transaction
473: execute "BEGIN"
474: end
Changes the column of a table.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 712
712: def change_column(table_name, column_name, type, options = {})
713: quoted_table_name = quote_table_name(table_name)
714:
715: begin
716: execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
717: rescue ActiveRecord::StatementInvalid
718: # This is PostgreSQL 7.x, so we have to use a more arcane way of doing it.
719: begin
720: begin_db_transaction
721: tmp_column_name = "#{column_name}_ar_tmp"
722: add_column(table_name, tmp_column_name, type, options)
723: execute "UPDATE #{quoted_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])})"
724: remove_column(table_name, column_name)
725: rename_column(table_name, tmp_column_name, column_name)
726: commit_db_transaction
727: rescue
728: rollback_db_transaction
729: end
730: end
731:
732: change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
733: change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
734: end
Changes the default value of a table column.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 737
737: def change_column_default(table_name, column_name, default)
738: execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
739: end
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 741
741: def change_column_null(table_name, column_name, null, default = nil)
742: unless null || default.nil?
743: execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
744: end
745: execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
746: end
Returns the current client message level.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 606
606: def client_min_messages
607: query('SHOW client_min_messages')[0][0]
608: end
Set the client message level.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 611
611: def client_min_messages=(level)
612: execute("SET client_min_messages TO '#{level}'")
613: end
Returns the list of all column definitions for a table.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 581
581: def columns(table_name, name = nil)
582: # Limit, precision, and scale are all handled by the superclass.
583: column_definitions(table_name).collect do |name, type, default, notnull|
584: PostgreSQLColumn.new(name, default, type, notnull == 'f')
585: end
586: end
Commits a transaction.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 477
477: def commit_db_transaction
478: execute "COMMIT"
479: end
Create a new PostgreSQL database. Options include :owner, :template, :encoding, :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 vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 500
500: def create_database(name, options = {})
501: options = options.reverse_merge(:encoding => "utf8")
502:
503: option_string = options.symbolize_keys.sum do |key, value|
504: case key
505: when :owner
506: " OWNER = '#{value}'"
507: when :template
508: " TEMPLATE = #{value}"
509: when :encoding
510: " ENCODING = '#{value}'"
511: when :tablespace
512: " TABLESPACE = #{value}"
513: when :connection_limit
514: " CONNECTION LIMIT = #{value}"
515: else
516: ""
517: end
518: end
519:
520: execute "CREATE DATABASE #{name}#{option_string}"
521: end
Close the connection.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 214
214: def disconnect!
215: @connection.close rescue nil
216: end
Escapes binary strings for bytea input to the database.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 265
265: def escape_bytea(value)
266: if PGconn.respond_to?(:escape_bytea)
267: self.class.instance_eval do
268: define_method(:escape_bytea) do |value|
269: PGconn.escape_bytea(value) if value
270: end
271: end
272: else
273: self.class.instance_eval do
274: define_method(:escape_bytea) do |value|
275: if value
276: result = ''
277: value.each_byte { |c| result << sprintf('\\\\%03o', c) }
278: result
279: end
280: end
281: end
282: end
283: escape_bytea(value)
284: end
Executes an SQL statement, returning a PGresult object on success or raising a PGError exception otherwise.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 456
456: def execute(sql, name = nil)
457: log(sql, name) do
458: if @async
459: @connection.async_exec(sql)
460: else
461: @connection.exec(sql)
462: end
463: end
464: end
Returns the list of all indexes for a table.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 544
544: def indexes(table_name, name = nil)
545: schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
546: result = query("SELECT distinct 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 i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (\#{schemas}) )\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)
547:
548: current_index = nil
549: indexes = []
550:
551: result.each do |row|
552: if current_index != row[0]
553: indexes << IndexDefinition.new(table_name, row[0], row[1] == "t", [])
554: current_index = row[0]
555: end
556:
557: indexes.last.columns << row[2]
558: end
559:
560: indexes
561: end
Executes an INSERT query and returns the new record‘s ID
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 415
415: def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
416: table = sql.split(" ", 4)[2].gsub('"', '')
417: super || pk && last_insert_id(table, sequence_name || default_sequence_name(table, pk))
418: end
Close then reopen the connection.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 203
203: def reconnect!
204: if @connection.respond_to?(:reset)
205: @connection.reset
206: configure_connection
207: else
208: disconnect!
209: connect
210: end
211: end
Drops an index from a table.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 754
754: def remove_index(table_name, options = {})
755: execute "DROP INDEX #{index_name(table_name, options)}"
756: end
Renames a column in a table.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 749
749: def rename_column(table_name, column_name, new_column_name)
750: execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
751: end
Renames a table.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 694
694: def rename_table(name, new_name)
695: execute "ALTER TABLE #{name} RENAME TO #{new_name}"
696: end
Aborts a transaction.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 482
482: def rollback_db_transaction
483: execute "ROLLBACK"
484: end
Returns the active schema search path.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 601
601: def schema_search_path
602: @schema_search_path ||= query('SHOW search_path')[0][0]
603: 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 vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 593
593: def schema_search_path=(schema_csv)
594: if schema_csv
595: execute "SET search_path TO #{schema_csv}"
596: @schema_search_path = schema_csv
597: end
598: end
Executes a SELECT query and returns an array of rows. Each row is an array of field values.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 410
410: def select_rows(sql, name = nil)
411: select_raw(sql, name).last
412: end
Does PostgreSQL support migrations?
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 236
236: def supports_migrations?
237: true
238: end
Does PostgreSQL support standard conforming strings?
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 241
241: def supports_standard_conforming_strings?
242: # Temporarily set the client message level above error to prevent unintentional
243: # error messages in the logs when working on a PostgreSQL database server that
244: # does not support standard conforming strings.
245: client_min_messages_old = client_min_messages
246: self.client_min_messages = 'panic'
247:
248: # postgres-pr does not raise an exception when client_min_messages is set higher
249: # than error and "SHOW standard_conforming_strings" fails, but returns an empty
250: # PGresult instead.
251: has_support = query('SHOW standard_conforming_strings')[0][0] rescue false
252: self.client_min_messages = client_min_messages_old
253: has_support
254: end
Returns the configured supported identifier length supported by PostgreSQL, or report the default of 63 on PostgreSQL 7.x.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 258
258: def table_alias_length
259: @table_alias_length ||= (postgresql_version >= 80000 ? query('SHOW max_identifier_length')[0][0].to_i : 63)
260: end
Returns the list of all tables in the schema search path or a specified schema.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 533
533: def tables(name = nil)
534: schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
535: query("SELECT tablename\nFROM pg_tables\nWHERE schemaname IN (\#{schemas})\n", name).map { |row| row[0] }
536: end
Maps logical Rails types to PostgreSQL-specific data types.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 759
759: def type_to_sql(type, limit = nil, precision = nil, scale = nil)
760: return super unless type.to_s == 'integer'
761:
762: if limit.nil? || limit == 4
763: 'integer'
764: elsif limit < 4
765: 'smallint'
766: else
767: 'bigint'
768: end
769: end
Unescapes bytea output from a database to the binary string it represents. NOTE: This is NOT an inverse of escape_bytea! This is only to be used
on escaped binary output from database drive.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 289
289: def unescape_bytea(value)
290: # In each case, check if the value actually is escaped PostgreSQL bytea output
291: # or an unescaped Active Record attribute that was just written.
292: if PGconn.respond_to?(:unescape_bytea)
293: self.class.instance_eval do
294: define_method(:unescape_bytea) do |value|
295: if value =~ /\\\d{3}/
296: PGconn.unescape_bytea(value)
297: else
298: value
299: end
300: end
301: end
302: else
303: self.class.instance_eval do
304: define_method(:unescape_bytea) do |value|
305: if value =~ /\\\d{3}/
306: result = ''
307: i, max = 0, value.size
308: while i < max
309: char = value[i]
310: if char == ?\\
311: if value[i+1] == ?\\
312: char = ?\\
313: i += 1
314: else
315: char = value[i+1..i+3].oct
316: i += 3
317: end
318: end
319: result << char
320: i += 1
321: end
322: result
323: else
324: value
325: end
326: end
327: end
328: end
329: unescape_bytea(value)
330: end
Executes an UPDATE query and returns the number of affected tuples.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 467
467: def update_sql(sql, name = nil)
468: super.cmd_tuples
469: end
Returns the version of the connected PostgreSQL version.
# File vendor/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb, line 808
808: def postgresql_version
809: @postgresql_version ||=
810: if @connection.respond_to?(:server_version)
811: @connection.server_version
812: else
813: # Mimic PGconn.server_version behavior
814: begin
815: query('SELECT version()')[0][0] =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
816: ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
817: rescue
818: 0
819: end
820: end
821: end