PageRenderTime 55ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb

https://github.com/brandondrew/rails
Ruby | 1054 lines | 733 code | 111 blank | 210 comment | 86 complexity | 9b1c135f08626050740e650a40e8d346 MD5 | raw file
  1. require 'active_record/connection_adapters/abstract_adapter'
  2. begin
  3. require_library_or_gem 'pg'
  4. rescue LoadError => e
  5. begin
  6. require_library_or_gem 'postgres'
  7. class PGresult
  8. alias_method :nfields, :num_fields unless self.method_defined?(:nfields)
  9. alias_method :ntuples, :num_tuples unless self.method_defined?(:ntuples)
  10. alias_method :ftype, :type unless self.method_defined?(:ftype)
  11. alias_method :cmd_tuples, :cmdtuples unless self.method_defined?(:cmd_tuples)
  12. end
  13. rescue LoadError
  14. raise e
  15. end
  16. end
  17. module ActiveRecord
  18. class Base
  19. # Establishes a connection to the database that's used by all Active Record objects
  20. def self.postgresql_connection(config) # :nodoc:
  21. config = config.symbolize_keys
  22. host = config[:host]
  23. port = config[:port] || 5432
  24. username = config[:username].to_s if config[:username]
  25. password = config[:password].to_s if config[:password]
  26. if config.has_key?(:database)
  27. database = config[:database]
  28. else
  29. raise ArgumentError, "No database specified. Missing argument: database."
  30. end
  31. # The postgres drivers don't allow the creation of an unconnected PGconn object,
  32. # so just pass a nil connection object for the time being.
  33. ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, [host, port, nil, nil, database, username, password], config)
  34. end
  35. end
  36. module ConnectionAdapters
  37. # PostgreSQL-specific extensions to column definitions in a table.
  38. class PostgreSQLColumn < Column #:nodoc:
  39. # Instantiates a new PostgreSQL column definition in a table.
  40. def initialize(name, default, sql_type = nil, null = true)
  41. super(name, self.class.extract_value_from_default(default), sql_type, null)
  42. end
  43. private
  44. def extract_limit(sql_type)
  45. case sql_type
  46. when /^bigint/i; 8
  47. when /^smallint/i; 2
  48. else super
  49. end
  50. end
  51. # Extracts the scale from PostgreSQL-specific data types.
  52. def extract_scale(sql_type)
  53. # Money type has a fixed scale of 2.
  54. sql_type =~ /^money/ ? 2 : super
  55. end
  56. # Extracts the precision from PostgreSQL-specific data types.
  57. def extract_precision(sql_type)
  58. # Actual code is defined dynamically in PostgreSQLAdapter.connect
  59. # depending on the server specifics
  60. super
  61. end
  62. # Escapes binary strings for bytea input to the database.
  63. def self.string_to_binary(value)
  64. if PGconn.respond_to?(:escape_bytea)
  65. self.class.module_eval do
  66. define_method(:string_to_binary) do |value|
  67. PGconn.escape_bytea(value) if value
  68. end
  69. end
  70. else
  71. self.class.module_eval do
  72. define_method(:string_to_binary) do |value|
  73. if value
  74. result = ''
  75. value.each_byte { |c| result << sprintf('\\\\%03o', c) }
  76. result
  77. end
  78. end
  79. end
  80. end
  81. self.class.string_to_binary(value)
  82. end
  83. # Unescapes bytea output from a database to the binary string it represents.
  84. def self.binary_to_string(value)
  85. # In each case, check if the value actually is escaped PostgreSQL bytea output
  86. # or an unescaped Active Record attribute that was just written.
  87. if PGconn.respond_to?(:unescape_bytea)
  88. self.class.module_eval do
  89. define_method(:binary_to_string) do |value|
  90. if value =~ /\\\d{3}/
  91. PGconn.unescape_bytea(value)
  92. else
  93. value
  94. end
  95. end
  96. end
  97. else
  98. self.class.module_eval do
  99. define_method(:binary_to_string) do |value|
  100. if value =~ /\\\d{3}/
  101. result = ''
  102. i, max = 0, value.size
  103. while i < max
  104. char = value[i]
  105. if char == ?\\
  106. if value[i+1] == ?\\
  107. char = ?\\
  108. i += 1
  109. else
  110. char = value[i+1..i+3].oct
  111. i += 3
  112. end
  113. end
  114. result << char
  115. i += 1
  116. end
  117. result
  118. else
  119. value
  120. end
  121. end
  122. end
  123. end
  124. self.class.binary_to_string(value)
  125. end
  126. # Maps PostgreSQL-specific data types to logical Rails types.
  127. def simplified_type(field_type)
  128. case field_type
  129. # Numeric and monetary types
  130. when /^(?:real|double precision)$/
  131. :float
  132. # Monetary types
  133. when /^money$/
  134. :decimal
  135. # Character types
  136. when /^(?:character varying|bpchar)(?:\(\d+\))?$/
  137. :string
  138. # Binary data types
  139. when /^bytea$/
  140. :binary
  141. # Date/time types
  142. when /^timestamp with(?:out)? time zone$/
  143. :datetime
  144. when /^interval$/
  145. :string
  146. # Geometric types
  147. when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
  148. :string
  149. # Network address types
  150. when /^(?:cidr|inet|macaddr)$/
  151. :string
  152. # Bit strings
  153. when /^bit(?: varying)?(?:\(\d+\))?$/
  154. :string
  155. # XML type
  156. when /^xml$/
  157. :string
  158. # Arrays
  159. when /^\D+\[\]$/
  160. :string
  161. # Object identifier types
  162. when /^oid$/
  163. :integer
  164. # Pass through all types that are not specific to PostgreSQL.
  165. else
  166. super
  167. end
  168. end
  169. # Extracts the value from a PostgreSQL column default definition.
  170. def self.extract_value_from_default(default)
  171. case default
  172. # Numeric types
  173. when /\A\(?(-?\d+(\.\d*)?\)?)\z/
  174. $1
  175. # Character types
  176. when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
  177. $1
  178. # Character types (8.1 formatting)
  179. when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m
  180. $1.gsub(/\\(\d\d\d)/) { $1.oct.chr }
  181. # Binary data types
  182. when /\A'(.*)'::bytea\z/m
  183. $1
  184. # Date/time types
  185. when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
  186. $1
  187. when /\A'(.*)'::interval\z/
  188. $1
  189. # Boolean type
  190. when 'true'
  191. true
  192. when 'false'
  193. false
  194. # Geometric types
  195. when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
  196. $1
  197. # Network address types
  198. when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
  199. $1
  200. # Bit string types
  201. when /\AB'(.*)'::"?bit(?: varying)?"?\z/
  202. $1
  203. # XML type
  204. when /\A'(.*)'::xml\z/m
  205. $1
  206. # Arrays
  207. when /\A'(.*)'::"?\D+"?\[\]\z/
  208. $1
  209. # Object identifier types
  210. when /\A-?\d+\z/
  211. $1
  212. else
  213. # Anything else is blank, some user type, or some function
  214. # and we can't know the value of that, so return nil.
  215. nil
  216. end
  217. end
  218. end
  219. end
  220. module ConnectionAdapters
  221. # The PostgreSQL adapter works both with the native C (http://ruby.scripting.ca/postgres/) and the pure
  222. # Ruby (available both as gem and from http://rubyforge.org/frs/?group_id=234&release_id=1944) drivers.
  223. #
  224. # Options:
  225. #
  226. # * <tt>:host</tt> - Defaults to "localhost".
  227. # * <tt>:port</tt> - Defaults to 5432.
  228. # * <tt>:username</tt> - Defaults to nothing.
  229. # * <tt>:password</tt> - Defaults to nothing.
  230. # * <tt>:database</tt> - The name of the database. No default, must be provided.
  231. # * <tt>:schema_search_path</tt> - An optional schema search path for the connection given as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option.
  232. # * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO <encoding></tt> call on the connection.
  233. # * <tt>:min_messages</tt> - An optional client min messages that is used in a <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
  234. # * <tt>:allow_concurrency</tt> - If true, use async query methods so Ruby threads don't deadlock; otherwise, use blocking query methods.
  235. class PostgreSQLAdapter < AbstractAdapter
  236. ADAPTER_NAME = 'PostgreSQL'.freeze
  237. NATIVE_DATABASE_TYPES = {
  238. :primary_key => "serial primary key".freeze,
  239. :string => { :name => "character varying", :limit => 255 },
  240. :text => { :name => "text" },
  241. :integer => { :name => "integer" },
  242. :float => { :name => "float" },
  243. :decimal => { :name => "decimal" },
  244. :datetime => { :name => "timestamp" },
  245. :timestamp => { :name => "timestamp" },
  246. :time => { :name => "time" },
  247. :date => { :name => "date" },
  248. :binary => { :name => "bytea" },
  249. :boolean => { :name => "boolean" }
  250. }
  251. # Returns 'PostgreSQL' as adapter name for identification purposes.
  252. def adapter_name
  253. ADAPTER_NAME
  254. end
  255. # Initializes and connects a PostgreSQL adapter.
  256. def initialize(connection, logger, connection_parameters, config)
  257. super(connection, logger)
  258. @connection_parameters, @config = connection_parameters, config
  259. connect
  260. end
  261. # Is this connection alive and ready for queries?
  262. def active?
  263. if @connection.respond_to?(:status)
  264. @connection.status == PGconn::CONNECTION_OK
  265. else
  266. # We're asking the driver, not ActiveRecord, so use @connection.query instead of #query
  267. @connection.query 'SELECT 1'
  268. true
  269. end
  270. # postgres-pr raises a NoMethodError when querying if no connection is available.
  271. rescue PGError, NoMethodError
  272. false
  273. end
  274. # Close then reopen the connection.
  275. def reconnect!
  276. if @connection.respond_to?(:reset)
  277. @connection.reset
  278. configure_connection
  279. else
  280. disconnect!
  281. connect
  282. end
  283. end
  284. # Close the connection.
  285. def disconnect!
  286. @connection.close rescue nil
  287. end
  288. def native_database_types #:nodoc:
  289. NATIVE_DATABASE_TYPES
  290. end
  291. # Does PostgreSQL support migrations?
  292. def supports_migrations?
  293. true
  294. end
  295. # Does PostgreSQL support standard conforming strings?
  296. def supports_standard_conforming_strings?
  297. # Temporarily set the client message level above error to prevent unintentional
  298. # error messages in the logs when working on a PostgreSQL database server that
  299. # does not support standard conforming strings.
  300. client_min_messages_old = client_min_messages
  301. self.client_min_messages = 'panic'
  302. # postgres-pr does not raise an exception when client_min_messages is set higher
  303. # than error and "SHOW standard_conforming_strings" fails, but returns an empty
  304. # PGresult instead.
  305. has_support = query('SHOW standard_conforming_strings')[0][0] rescue false
  306. self.client_min_messages = client_min_messages_old
  307. has_support
  308. end
  309. def supports_insert_with_returning?
  310. postgresql_version >= 80200
  311. end
  312. def supports_ddl_transactions?
  313. true
  314. end
  315. # Returns the configured supported identifier length supported by PostgreSQL,
  316. # or report the default of 63 on PostgreSQL 7.x.
  317. def table_alias_length
  318. @table_alias_length ||= (postgresql_version >= 80000 ? query('SHOW max_identifier_length')[0][0].to_i : 63)
  319. end
  320. # QUOTING ==================================================
  321. # Quotes PostgreSQL-specific data types for SQL input.
  322. def quote(value, column = nil) #:nodoc:
  323. if value.kind_of?(String) && column && column.type == :binary
  324. "#{quoted_string_prefix}'#{column.class.string_to_binary(value)}'"
  325. elsif value.kind_of?(String) && column && column.sql_type =~ /^xml$/
  326. "xml '#{quote_string(value)}'"
  327. elsif value.kind_of?(Numeric) && column && column.sql_type =~ /^money$/
  328. # Not truly string input, so doesn't require (or allow) escape string syntax.
  329. "'#{value.to_s}'"
  330. elsif value.kind_of?(String) && column && column.sql_type =~ /^bit/
  331. case value
  332. when /^[01]*$/
  333. "B'#{value}'" # Bit-string notation
  334. when /^[0-9A-F]*$/i
  335. "X'#{value}'" # Hexadecimal notation
  336. end
  337. else
  338. super
  339. end
  340. end
  341. # Quotes strings for use in SQL input in the postgres driver for better performance.
  342. def quote_string(s) #:nodoc:
  343. if PGconn.respond_to?(:escape)
  344. self.class.instance_eval do
  345. define_method(:quote_string) do |s|
  346. PGconn.escape(s)
  347. end
  348. end
  349. else
  350. # There are some incorrectly compiled postgres drivers out there
  351. # that don't define PGconn.escape.
  352. self.class.instance_eval do
  353. remove_method(:quote_string)
  354. end
  355. end
  356. quote_string(s)
  357. end
  358. # Quotes column names for use in SQL queries.
  359. def quote_column_name(name) #:nodoc:
  360. %("#{name}")
  361. end
  362. # Quote date/time values for use in SQL input. Includes microseconds
  363. # if the value is a Time responding to usec.
  364. def quoted_date(value) #:nodoc:
  365. if value.acts_like?(:time) && value.respond_to?(:usec)
  366. "#{super}.#{sprintf("%06d", value.usec)}"
  367. else
  368. super
  369. end
  370. end
  371. # REFERENTIAL INTEGRITY ====================================
  372. def supports_disable_referential_integrity?() #:nodoc:
  373. version = query("SHOW server_version")[0][0].split('.')
  374. (version[0].to_i >= 8 && version[1].to_i >= 1) ? true : false
  375. rescue
  376. return false
  377. end
  378. def disable_referential_integrity(&block) #:nodoc:
  379. if supports_disable_referential_integrity?() then
  380. execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
  381. end
  382. yield
  383. ensure
  384. if supports_disable_referential_integrity?() then
  385. execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
  386. end
  387. end
  388. # DATABASE STATEMENTS ======================================
  389. # Executes a SELECT query and returns an array of rows. Each row is an
  390. # array of field values.
  391. def select_rows(sql, name = nil)
  392. select_raw(sql, name).last
  393. end
  394. # Executes an INSERT query and returns the new record's ID
  395. def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
  396. # Extract the table from the insert sql. Yuck.
  397. table = sql.split(" ", 4)[2].gsub('"', '')
  398. # Try an insert with 'returning id' if available (PG >= 8.2)
  399. if supports_insert_with_returning?
  400. pk, sequence_name = *pk_and_sequence_for(table) unless pk
  401. if pk
  402. id = select_value("#{sql} RETURNING #{quote_column_name(pk)}")
  403. clear_query_cache
  404. return id
  405. end
  406. end
  407. # Otherwise, insert then grab last_insert_id.
  408. if insert_id = super
  409. insert_id
  410. else
  411. # If neither pk nor sequence name is given, look them up.
  412. unless pk || sequence_name
  413. pk, sequence_name = *pk_and_sequence_for(table)
  414. end
  415. # If a pk is given, fallback to default sequence name.
  416. # Don't fetch last insert id for a table without a pk.
  417. if pk && sequence_name ||= default_sequence_name(table, pk)
  418. last_insert_id(table, sequence_name)
  419. end
  420. end
  421. end
  422. # create a 2D array representing the result set
  423. def result_as_array(res) #:nodoc:
  424. ary = []
  425. for i in 0...res.ntuples do
  426. ary << []
  427. for j in 0...res.nfields do
  428. ary[i] << res.getvalue(i,j)
  429. end
  430. end
  431. return ary
  432. end
  433. # Queries the database and returns the results in an Array-like object
  434. def query(sql, name = nil) #:nodoc:
  435. log(sql, name) do
  436. if @async
  437. res = @connection.async_exec(sql)
  438. else
  439. res = @connection.exec(sql)
  440. end
  441. return result_as_array(res)
  442. end
  443. end
  444. # Executes an SQL statement, returning a PGresult object on success
  445. # or raising a PGError exception otherwise.
  446. def execute(sql, name = nil)
  447. log(sql, name) do
  448. if @async
  449. @connection.async_exec(sql)
  450. else
  451. @connection.exec(sql)
  452. end
  453. end
  454. end
  455. # Executes an UPDATE query and returns the number of affected tuples.
  456. def update_sql(sql, name = nil)
  457. super.cmd_tuples
  458. end
  459. # Begins a transaction.
  460. def begin_db_transaction
  461. execute "BEGIN"
  462. end
  463. # Commits a transaction.
  464. def commit_db_transaction
  465. execute "COMMIT"
  466. end
  467. # Aborts a transaction.
  468. def rollback_db_transaction
  469. execute "ROLLBACK"
  470. end
  471. # ruby-pg defines Ruby constants for transaction status,
  472. # ruby-postgres does not.
  473. PQTRANS_IDLE = defined?(PGconn::PQTRANS_IDLE) ? PGconn::PQTRANS_IDLE : 0
  474. # Check whether a transaction is active.
  475. def transaction_active?
  476. @connection.transaction_status != PQTRANS_IDLE
  477. end
  478. # Wrap a block in a transaction. Returns result of block.
  479. def transaction(start_db_transaction = true)
  480. transaction_open = false
  481. begin
  482. if block_given?
  483. if start_db_transaction
  484. begin_db_transaction
  485. transaction_open = true
  486. end
  487. yield
  488. end
  489. rescue Exception => database_transaction_rollback
  490. if transaction_open && transaction_active?
  491. transaction_open = false
  492. rollback_db_transaction
  493. end
  494. raise unless database_transaction_rollback.is_a? ActiveRecord::Rollback
  495. end
  496. ensure
  497. if transaction_open && transaction_active?
  498. begin
  499. commit_db_transaction
  500. rescue Exception => database_transaction_rollback
  501. rollback_db_transaction
  502. raise
  503. end
  504. end
  505. end
  506. # SCHEMA STATEMENTS ========================================
  507. def recreate_database(name) #:nodoc:
  508. drop_database(name)
  509. create_database(name)
  510. end
  511. # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
  512. # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
  513. # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
  514. #
  515. # Example:
  516. # create_database config[:database], config
  517. # create_database 'foo_development', :encoding => 'unicode'
  518. def create_database(name, options = {})
  519. options = options.reverse_merge(:encoding => "utf8")
  520. option_string = options.symbolize_keys.sum do |key, value|
  521. case key
  522. when :owner
  523. " OWNER = \"#{value}\""
  524. when :template
  525. " TEMPLATE = \"#{value}\""
  526. when :encoding
  527. " ENCODING = '#{value}'"
  528. when :tablespace
  529. " TABLESPACE = \"#{value}\""
  530. when :connection_limit
  531. " CONNECTION LIMIT = #{value}"
  532. else
  533. ""
  534. end
  535. end
  536. execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
  537. end
  538. # Drops a PostgreSQL database
  539. #
  540. # Example:
  541. # drop_database 'matt_development'
  542. def drop_database(name) #:nodoc:
  543. if postgresql_version >= 80200
  544. execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
  545. else
  546. begin
  547. execute "DROP DATABASE #{quote_table_name(name)}"
  548. rescue ActiveRecord::StatementInvalid
  549. @logger.warn "#{name} database doesn't exist." if @logger
  550. end
  551. end
  552. end
  553. # Returns the list of all tables in the schema search path or a specified schema.
  554. def tables(name = nil)
  555. schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
  556. query(<<-SQL, name).map { |row| row[0] }
  557. SELECT tablename
  558. FROM pg_tables
  559. WHERE schemaname IN (#{schemas})
  560. SQL
  561. end
  562. # Returns the list of all indexes for a table.
  563. def indexes(table_name, name = nil)
  564. schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
  565. result = query(<<-SQL, name)
  566. SELECT distinct i.relname, d.indisunique, a.attname
  567. FROM pg_class t, pg_class i, pg_index d, pg_attribute a
  568. WHERE i.relkind = 'i'
  569. AND d.indexrelid = i.oid
  570. AND d.indisprimary = 'f'
  571. AND t.oid = d.indrelid
  572. AND t.relname = '#{table_name}'
  573. AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (#{schemas}) )
  574. AND a.attrelid = t.oid
  575. AND ( d.indkey[0]=a.attnum OR d.indkey[1]=a.attnum
  576. OR d.indkey[2]=a.attnum OR d.indkey[3]=a.attnum
  577. OR d.indkey[4]=a.attnum OR d.indkey[5]=a.attnum
  578. OR d.indkey[6]=a.attnum OR d.indkey[7]=a.attnum
  579. OR d.indkey[8]=a.attnum OR d.indkey[9]=a.attnum )
  580. ORDER BY i.relname
  581. SQL
  582. current_index = nil
  583. indexes = []
  584. result.each do |row|
  585. if current_index != row[0]
  586. indexes << IndexDefinition.new(table_name, row[0], row[1] == "t", [])
  587. current_index = row[0]
  588. end
  589. indexes.last.columns << row[2]
  590. end
  591. indexes
  592. end
  593. # Returns the list of all column definitions for a table.
  594. def columns(table_name, name = nil)
  595. # Limit, precision, and scale are all handled by the superclass.
  596. column_definitions(table_name).collect do |name, type, default, notnull|
  597. PostgreSQLColumn.new(name, default, type, notnull == 'f')
  598. end
  599. end
  600. # Returns the current database name.
  601. def current_database
  602. query('select current_database()')[0][0]
  603. end
  604. # Returns the current database encoding format.
  605. def encoding
  606. query(<<-end_sql)[0][0]
  607. SELECT pg_encoding_to_char(pg_database.encoding) FROM pg_database
  608. WHERE pg_database.datname LIKE '#{current_database}'
  609. end_sql
  610. end
  611. # Sets the schema search path to a string of comma-separated schema names.
  612. # Names beginning with $ have to be quoted (e.g. $user => '$user').
  613. # See: http://www.postgresql.org/docs/current/static/ddl-schemas.html
  614. #
  615. # This should be not be called manually but set in database.yml.
  616. def schema_search_path=(schema_csv)
  617. if schema_csv
  618. execute "SET search_path TO #{schema_csv}"
  619. @schema_search_path = schema_csv
  620. end
  621. end
  622. # Returns the active schema search path.
  623. def schema_search_path
  624. @schema_search_path ||= query('SHOW search_path')[0][0]
  625. end
  626. # Returns the current client message level.
  627. def client_min_messages
  628. query('SHOW client_min_messages')[0][0]
  629. end
  630. # Set the client message level.
  631. def client_min_messages=(level)
  632. execute("SET client_min_messages TO '#{level}'")
  633. end
  634. # Returns the sequence name for a table's primary key or some other specified key.
  635. def default_sequence_name(table_name, pk = nil) #:nodoc:
  636. default_pk, default_seq = pk_and_sequence_for(table_name)
  637. default_seq || "#{table_name}_#{pk || default_pk || 'id'}_seq"
  638. end
  639. # Resets the sequence of a table's primary key to the maximum value.
  640. def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
  641. unless pk and sequence
  642. default_pk, default_sequence = pk_and_sequence_for(table)
  643. pk ||= default_pk
  644. sequence ||= default_sequence
  645. end
  646. if pk
  647. if sequence
  648. quoted_sequence = quote_column_name(sequence)
  649. select_value <<-end_sql, 'Reset sequence'
  650. SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false)
  651. end_sql
  652. else
  653. @logger.warn "#{table} has primary key #{pk} with no default sequence" if @logger
  654. end
  655. end
  656. end
  657. # Returns a table's primary key and belonging sequence.
  658. def pk_and_sequence_for(table) #:nodoc:
  659. # First try looking for a sequence with a dependency on the
  660. # given table's primary key.
  661. result = query(<<-end_sql, 'PK and serial sequence')[0]
  662. SELECT attr.attname, seq.relname
  663. FROM pg_class seq,
  664. pg_attribute attr,
  665. pg_depend dep,
  666. pg_namespace name,
  667. pg_constraint cons
  668. WHERE seq.oid = dep.objid
  669. AND seq.relkind = 'S'
  670. AND attr.attrelid = dep.refobjid
  671. AND attr.attnum = dep.refobjsubid
  672. AND attr.attrelid = cons.conrelid
  673. AND attr.attnum = cons.conkey[1]
  674. AND cons.contype = 'p'
  675. AND dep.refobjid = '#{table}'::regclass
  676. end_sql
  677. if result.nil? or result.empty?
  678. # If that fails, try parsing the primary key's default value.
  679. # Support the 7.x and 8.0 nextval('foo'::text) as well as
  680. # the 8.1+ nextval('foo'::regclass).
  681. result = query(<<-end_sql, 'PK and custom sequence')[0]
  682. SELECT attr.attname,
  683. CASE
  684. WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
  685. substr(split_part(def.adsrc, '''', 2),
  686. strpos(split_part(def.adsrc, '''', 2), '.')+1)
  687. ELSE split_part(def.adsrc, '''', 2)
  688. END
  689. FROM pg_class t
  690. JOIN pg_attribute attr ON (t.oid = attrelid)
  691. JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
  692. JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
  693. WHERE t.oid = '#{table}'::regclass
  694. AND cons.contype = 'p'
  695. AND def.adsrc ~* 'nextval'
  696. end_sql
  697. end
  698. # [primary_key, sequence]
  699. [result.first, result.last]
  700. rescue
  701. nil
  702. end
  703. # Renames a table.
  704. def rename_table(name, new_name)
  705. execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
  706. end
  707. # Adds a new column to the named table.
  708. # See TableDefinition#column for details of the options you can use.
  709. def add_column(table_name, column_name, type, options = {})
  710. default = options[:default]
  711. notnull = options[:null] == false
  712. # Add the column.
  713. 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])}")
  714. change_column_default(table_name, column_name, default) if options_include_default?(options)
  715. change_column_null(table_name, column_name, false, default) if notnull
  716. end
  717. # Changes the column of a table.
  718. def change_column(table_name, column_name, type, options = {})
  719. quoted_table_name = quote_table_name(table_name)
  720. begin
  721. execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
  722. rescue ActiveRecord::StatementInvalid => e
  723. raise e if postgresql_version > 80000
  724. # This is PostgreSQL 7.x, so we have to use a more arcane way of doing it.
  725. begin
  726. begin_db_transaction
  727. tmp_column_name = "#{column_name}_ar_tmp"
  728. add_column(table_name, tmp_column_name, type, options)
  729. 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])})"
  730. remove_column(table_name, column_name)
  731. rename_column(table_name, tmp_column_name, column_name)
  732. commit_db_transaction
  733. rescue
  734. rollback_db_transaction
  735. end
  736. end
  737. change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
  738. change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
  739. end
  740. # Changes the default value of a table column.
  741. def change_column_default(table_name, column_name, default)
  742. execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
  743. end
  744. def change_column_null(table_name, column_name, null, default = nil)
  745. unless null || default.nil?
  746. execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
  747. end
  748. execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
  749. end
  750. # Renames a column in a table.
  751. def rename_column(table_name, column_name, new_column_name)
  752. execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
  753. end
  754. # Drops an index from a table.
  755. def remove_index(table_name, options = {})
  756. execute "DROP INDEX #{index_name(table_name, options)}"
  757. end
  758. # Maps logical Rails types to PostgreSQL-specific data types.
  759. def type_to_sql(type, limit = nil, precision = nil, scale = nil)
  760. return super unless type.to_s == 'integer'
  761. case limit
  762. when 1..2; 'smallint'
  763. when 3..4, nil; 'integer'
  764. when 5..8; 'bigint'
  765. else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
  766. end
  767. end
  768. # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
  769. #
  770. # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
  771. # requires that the ORDER BY include the distinct column.
  772. #
  773. # distinct("posts.id", "posts.created_at desc")
  774. def distinct(columns, order_by) #:nodoc:
  775. return "DISTINCT #{columns}" if order_by.blank?
  776. # Construct a clean list of column names from the ORDER BY clause, removing
  777. # any ASC/DESC modifiers
  778. order_columns = order_by.split(',').collect { |s| s.split.first }
  779. order_columns.delete_if &:blank?
  780. order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
  781. # Return a DISTINCT ON() clause that's distinct on the columns we want but includes
  782. # all the required columns for the ORDER BY to work properly.
  783. sql = "DISTINCT ON (#{columns}) #{columns}, "
  784. sql << order_columns * ', '
  785. end
  786. # Returns an ORDER BY clause for the passed order option.
  787. #
  788. # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this
  789. # by wrapping the +sql+ string as a sub-select and ordering in that query.
  790. def add_order_by_for_association_limiting!(sql, options) #:nodoc:
  791. return sql if options[:order].blank?
  792. order = options[:order].split(',').collect { |s| s.strip }.reject(&:blank?)
  793. order.map! { |s| 'DESC' if s =~ /\bdesc$/i }
  794. order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{s}" }.join(', ')
  795. sql.replace "SELECT * FROM (#{sql}) AS id_list ORDER BY #{order}"
  796. end
  797. protected
  798. # Returns the version of the connected PostgreSQL version.
  799. def postgresql_version
  800. @postgresql_version ||=
  801. if @connection.respond_to?(:server_version)
  802. @connection.server_version
  803. else
  804. # Mimic PGconn.server_version behavior
  805. begin
  806. query('SELECT version()')[0][0] =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
  807. ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
  808. rescue
  809. 0
  810. end
  811. end
  812. end
  813. private
  814. # The internal PostgreSQL identifier of the money data type.
  815. MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
  816. # Connects to a PostgreSQL server and sets up the adapter depending on the
  817. # connected server's characteristics.
  818. def connect
  819. @connection = PGconn.connect(*@connection_parameters)
  820. PGconn.translate_results = false if PGconn.respond_to?(:translate_results=)
  821. # Ignore async_exec and async_query when using postgres-pr.
  822. @async = @config[:allow_concurrency] && @connection.respond_to?(:async_exec)
  823. # Use escape string syntax if available. We cannot do this lazily when encountering
  824. # the first string, because that could then break any transactions in progress.
  825. # See: http://www.postgresql.org/docs/current/static/runtime-config-compatible.html
  826. # If PostgreSQL doesn't know the standard_conforming_strings parameter then it doesn't
  827. # support escape string syntax. Don't override the inherited quoted_string_prefix.
  828. if supports_standard_conforming_strings?
  829. self.class.instance_eval do
  830. define_method(:quoted_string_prefix) { 'E' }
  831. end
  832. end
  833. # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
  834. # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
  835. # should know about this but can't detect it there, so deal with it here.
  836. money_precision = (postgresql_version >= 80300) ? 19 : 10
  837. PostgreSQLColumn.module_eval(<<-end_eval)
  838. def extract_precision(sql_type)
  839. if sql_type =~ /^money$/
  840. #{money_precision}
  841. else
  842. super
  843. end
  844. end
  845. end_eval
  846. configure_connection
  847. end
  848. # Configures the encoding, verbosity, and schema search path of the connection.
  849. # This is called by #connect and should not be called manually.
  850. def configure_connection
  851. if @config[:encoding]
  852. if @connection.respond_to?(:set_client_encoding)
  853. @connection.set_client_encoding(@config[:encoding])
  854. else
  855. execute("SET client_encoding TO '#{@config[:encoding]}'")
  856. end
  857. end
  858. self.client_min_messages = @config[:min_messages] if @config[:min_messages]
  859. self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
  860. end
  861. # Returns the current ID of a table's sequence.
  862. def last_insert_id(table, sequence_name) #:nodoc:
  863. Integer(select_value("SELECT currval('#{sequence_name}')"))
  864. end
  865. # Executes a SELECT query and returns the results, performing any data type
  866. # conversions that are required to be performed here instead of in PostgreSQLColumn.
  867. def select(sql, name = nil)
  868. fields, rows = select_raw(sql, name)
  869. result = []
  870. for row in rows
  871. row_hash = {}
  872. fields.each_with_index do |f, i|
  873. row_hash[f] = row[i]
  874. end
  875. result << row_hash
  876. end
  877. result
  878. end
  879. def select_raw(sql, name = nil)
  880. res = execute(sql, name)
  881. results = result_as_array(res)
  882. fields = []
  883. rows = []
  884. if res.ntuples > 0
  885. fields = res.fields
  886. results.each do |row|
  887. hashed_row = {}
  888. row.each_index do |cell_index|
  889. # If this is a money type column and there are any currency symbols,
  890. # then strip them off. Indeed it would be prettier to do this in
  891. # PostgreSQLColumn.string_to_decimal but would break form input
  892. # fields that call value_before_type_cast.
  893. if res.ftype(cell_index) == MONEY_COLUMN_TYPE_OID
  894. # Because money output is formatted according to the locale, there are two
  895. # cases to consider (note the decimal separators):
  896. # (1) $12,345,678.12
  897. # (2) $12.345.678,12
  898. case column = row[cell_index]
  899. when /^-?\D+[\d,]+\.\d{2}$/ # (1)
  900. row[cell_index] = column.gsub(/[^-\d\.]/, '')
  901. when /^-?\D+[\d\.]+,\d{2}$/ # (2)
  902. row[cell_index] = column.gsub(/[^-\d,]/, '').sub(/,/, '.')
  903. end
  904. end
  905. hashed_row[fields[cell_index]] = column
  906. end
  907. rows << row
  908. end
  909. end
  910. res.clear
  911. return fields, rows
  912. end
  913. # Returns the list of a table's column names, data types, and default values.
  914. #
  915. # The underlying query is roughly:
  916. # SELECT column.name, column.type, default.value
  917. # FROM column LEFT JOIN default
  918. # ON column.table_id = default.table_id
  919. # AND column.num = default.column_num
  920. # WHERE column.table_id = get_table_id('table_name')
  921. # AND column.num > 0
  922. # AND NOT column.is_dropped
  923. # ORDER BY column.num
  924. #
  925. # If the table name is not prefixed with a schema, the database will
  926. # take the first match from the schema search path.
  927. #
  928. # Query implementation notes:
  929. # - format_type includes the column size constraint, e.g. varchar(50)
  930. # - ::regclass is a function that gives the id for a table name
  931. def column_definitions(table_name) #:nodoc:
  932. query <<-end_sql
  933. SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
  934. FROM pg_attribute a LEFT JOIN pg_attrdef d
  935. ON a.attrelid = d.adrelid AND a.attnum = d.adnum
  936. WHERE a.attrelid = '#{table_name}'::regclass
  937. AND a.attnum > 0 AND NOT a.attisdropped
  938. ORDER BY a.attnum
  939. end_sql
  940. end
  941. end
  942. end
  943. end