PageRenderTime 57ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/ruby/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/postgresql_adapter.rb

https://github.com/KaylaStuebbe/uwsp-virtual-tour-server
Ruby | 1306 lines | 871 code | 179 blank | 256 comment | 56 complexity | b2354d16a2ed06305eefab91856a05f9 MD5 | raw file
Possible License(s): Apache-2.0, MIT, GPL-2.0, BSD-3-Clause
  1. require 'active_record/connection_adapters/abstract_adapter'
  2. require 'active_support/core_ext/object/blank'
  3. require 'active_record/connection_adapters/statement_pool'
  4. require 'arel/visitors/bind_visitor'
  5. # Make sure we're using pg high enough for PGResult#values
  6. gem 'pg', '~> 0.11'
  7. require 'pg'
  8. module ActiveRecord
  9. class Base
  10. # Establishes a connection to the database that's used by all Active Record objects
  11. def self.postgresql_connection(config) # :nodoc:
  12. config = config.symbolize_keys
  13. host = config[:host]
  14. port = config[:port] || 5432
  15. username = config[:username].to_s if config[:username]
  16. password = config[:password].to_s if config[:password]
  17. if config.key?(:database)
  18. database = config[:database]
  19. else
  20. raise ArgumentError, "No database specified. Missing argument: database."
  21. end
  22. # The postgres drivers don't allow the creation of an unconnected PGconn object,
  23. # so just pass a nil connection object for the time being.
  24. ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, [host, port, nil, nil, database, username, password], config)
  25. end
  26. end
  27. module ConnectionAdapters
  28. # PostgreSQL-specific extensions to column definitions in a table.
  29. class PostgreSQLColumn < Column #:nodoc:
  30. # Instantiates a new PostgreSQL column definition in a table.
  31. def initialize(name, default, sql_type = nil, null = true)
  32. super(name, self.class.extract_value_from_default(default), sql_type, null)
  33. end
  34. # :stopdoc:
  35. class << self
  36. attr_accessor :money_precision
  37. def string_to_time(string)
  38. return string unless String === string
  39. case string
  40. when 'infinity' then 1.0 / 0.0
  41. when '-infinity' then -1.0 / 0.0
  42. else
  43. super
  44. end
  45. end
  46. end
  47. # :startdoc:
  48. private
  49. def extract_limit(sql_type)
  50. case sql_type
  51. when /^bigint/i; 8
  52. when /^smallint/i; 2
  53. else super
  54. end
  55. end
  56. # Extracts the scale from PostgreSQL-specific data types.
  57. def extract_scale(sql_type)
  58. # Money type has a fixed scale of 2.
  59. sql_type =~ /^money/ ? 2 : super
  60. end
  61. # Extracts the precision from PostgreSQL-specific data types.
  62. def extract_precision(sql_type)
  63. if sql_type == 'money'
  64. self.class.money_precision
  65. else
  66. super
  67. end
  68. end
  69. # Maps PostgreSQL-specific data types to logical Rails types.
  70. def simplified_type(field_type)
  71. case field_type
  72. # Numeric and monetary types
  73. when /^(?:real|double precision)$/
  74. :float
  75. # Monetary types
  76. when 'money'
  77. :decimal
  78. # Character types
  79. when /^(?:character varying|bpchar)(?:\(\d+\))?$/
  80. :string
  81. # Binary data types
  82. when 'bytea'
  83. :binary
  84. # Date/time types
  85. when /^timestamp with(?:out)? time zone$/
  86. :datetime
  87. when 'interval'
  88. :string
  89. # Geometric types
  90. when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
  91. :string
  92. # Network address types
  93. when /^(?:cidr|inet|macaddr)$/
  94. :string
  95. # Bit strings
  96. when /^bit(?: varying)?(?:\(\d+\))?$/
  97. :string
  98. # XML type
  99. when 'xml'
  100. :xml
  101. # tsvector type
  102. when 'tsvector'
  103. :tsvector
  104. # Arrays
  105. when /^\D+\[\]$/
  106. :string
  107. # Object identifier types
  108. when 'oid'
  109. :integer
  110. # UUID type
  111. when 'uuid'
  112. :string
  113. # Small and big integer types
  114. when /^(?:small|big)int$/
  115. :integer
  116. # Pass through all types that are not specific to PostgreSQL.
  117. else
  118. super
  119. end
  120. end
  121. # Extracts the value from a PostgreSQL column default definition.
  122. def self.extract_value_from_default(default)
  123. case default
  124. # This is a performance optimization for Ruby 1.9.2 in development.
  125. # If the value is nil, we return nil straight away without checking
  126. # the regular expressions. If we check each regular expression,
  127. # Regexp#=== will call NilClass#to_str, which will trigger
  128. # method_missing (defined by whiny nil in ActiveSupport) which
  129. # makes this method very very slow.
  130. when NilClass
  131. nil
  132. # Numeric types
  133. when /\A\(?(-?\d+(\.\d*)?\)?)\z/
  134. $1
  135. # Character types
  136. when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
  137. $1
  138. # Character types (8.1 formatting)
  139. when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m
  140. $1.gsub(/\\(\d\d\d)/) { $1.oct.chr }
  141. # Binary data types
  142. when /\A'(.*)'::bytea\z/m
  143. $1
  144. # Date/time types
  145. when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
  146. $1
  147. when /\A'(.*)'::interval\z/
  148. $1
  149. # Boolean type
  150. when 'true'
  151. true
  152. when 'false'
  153. false
  154. # Geometric types
  155. when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
  156. $1
  157. # Network address types
  158. when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
  159. $1
  160. # Bit string types
  161. when /\AB'(.*)'::"?bit(?: varying)?"?\z/
  162. $1
  163. # XML type
  164. when /\A'(.*)'::xml\z/m
  165. $1
  166. # Arrays
  167. when /\A'(.*)'::"?\D+"?\[\]\z/
  168. $1
  169. # Object identifier types
  170. when /\A-?\d+\z/
  171. $1
  172. else
  173. # Anything else is blank, some user type, or some function
  174. # and we can't know the value of that, so return nil.
  175. nil
  176. end
  177. end
  178. end
  179. # The PostgreSQL adapter works both with the native C (http://ruby.scripting.ca/postgres/) and the pure
  180. # Ruby (available both as gem and from http://rubyforge.org/frs/?group_id=234&release_id=1944) drivers.
  181. #
  182. # Options:
  183. #
  184. # * <tt>:host</tt> - Defaults to "localhost".
  185. # * <tt>:port</tt> - Defaults to 5432.
  186. # * <tt>:username</tt> - Defaults to nothing.
  187. # * <tt>:password</tt> - Defaults to nothing.
  188. # * <tt>:database</tt> - The name of the database. No default, must be provided.
  189. # * <tt>:schema_search_path</tt> - An optional schema search path for the connection given
  190. # as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option.
  191. # * <tt>:encoding</tt> - An optional client encoding that is used in a <tt>SET client_encoding TO
  192. # <encoding></tt> call on the connection.
  193. # * <tt>:min_messages</tt> - An optional client min messages that is used in a
  194. # <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
  195. class PostgreSQLAdapter < AbstractAdapter
  196. class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
  197. def xml(*args)
  198. options = args.extract_options!
  199. column(args[0], 'xml', options)
  200. end
  201. def tsvector(*args)
  202. options = args.extract_options!
  203. column(args[0], 'tsvector', options)
  204. end
  205. end
  206. ADAPTER_NAME = 'PostgreSQL'
  207. NATIVE_DATABASE_TYPES = {
  208. :primary_key => "serial primary key",
  209. :string => { :name => "character varying", :limit => 255 },
  210. :text => { :name => "text" },
  211. :integer => { :name => "integer" },
  212. :float => { :name => "float" },
  213. :decimal => { :name => "decimal" },
  214. :datetime => { :name => "timestamp" },
  215. :timestamp => { :name => "timestamp" },
  216. :time => { :name => "time" },
  217. :date => { :name => "date" },
  218. :binary => { :name => "bytea" },
  219. :boolean => { :name => "boolean" },
  220. :xml => { :name => "xml" },
  221. :tsvector => { :name => "tsvector" }
  222. }
  223. # Returns 'PostgreSQL' as adapter name for identification purposes.
  224. def adapter_name
  225. ADAPTER_NAME
  226. end
  227. # Returns +true+, since this connection adapter supports prepared statement
  228. # caching.
  229. def supports_statement_cache?
  230. true
  231. end
  232. def supports_index_sort_order?
  233. true
  234. end
  235. class StatementPool < ConnectionAdapters::StatementPool
  236. def initialize(connection, max)
  237. super
  238. @counter = 0
  239. @cache = Hash.new { |h,pid| h[pid] = {} }
  240. end
  241. def each(&block); cache.each(&block); end
  242. def key?(key); cache.key?(key); end
  243. def [](key); cache[key]; end
  244. def length; cache.length; end
  245. def next_key
  246. "a#{@counter + 1}"
  247. end
  248. def []=(sql, key)
  249. while @max <= cache.size
  250. dealloc(cache.shift.last)
  251. end
  252. @counter += 1
  253. cache[sql] = key
  254. end
  255. def clear
  256. cache.each_value do |stmt_key|
  257. dealloc stmt_key
  258. end
  259. cache.clear
  260. end
  261. def delete(sql_key)
  262. dealloc cache[sql_key]
  263. cache.delete sql_key
  264. end
  265. private
  266. def cache
  267. @cache[$$]
  268. end
  269. def dealloc(key)
  270. @connection.query "DEALLOCATE #{key}" if connection_active?
  271. end
  272. def connection_active?
  273. @connection.status == PGconn::CONNECTION_OK
  274. rescue PGError
  275. false
  276. end
  277. end
  278. class BindSubstitution < Arel::Visitors::PostgreSQL # :nodoc:
  279. include Arel::Visitors::BindVisitor
  280. end
  281. # Initializes and connects a PostgreSQL adapter.
  282. def initialize(connection, logger, connection_parameters, config)
  283. super(connection, logger)
  284. if config.fetch(:prepared_statements) { true }
  285. @visitor = Arel::Visitors::PostgreSQL.new self
  286. else
  287. @visitor = BindSubstitution.new self
  288. end
  289. connection_parameters.delete :prepared_statements
  290. @connection_parameters, @config = connection_parameters, config
  291. # @local_tz is initialized as nil to avoid warnings when connect tries to use it
  292. @local_tz = nil
  293. @table_alias_length = nil
  294. connect
  295. @statements = StatementPool.new @connection,
  296. config.fetch(:statement_limit) { 1000 }
  297. if postgresql_version < 80200
  298. raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
  299. end
  300. @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
  301. end
  302. # Clears the prepared statements cache.
  303. def clear_cache!
  304. @statements.clear
  305. end
  306. # Is this connection alive and ready for queries?
  307. def active?
  308. @connection.query 'SELECT 1'
  309. true
  310. rescue PGError
  311. false
  312. end
  313. # Close then reopen the connection.
  314. def reconnect!
  315. clear_cache!
  316. @connection.reset
  317. configure_connection
  318. end
  319. def reset!
  320. clear_cache!
  321. super
  322. end
  323. # Disconnects from the database if already connected. Otherwise, this
  324. # method does nothing.
  325. def disconnect!
  326. clear_cache!
  327. @connection.close rescue nil
  328. end
  329. def native_database_types #:nodoc:
  330. NATIVE_DATABASE_TYPES
  331. end
  332. # Returns true, since this connection adapter supports migrations.
  333. def supports_migrations?
  334. true
  335. end
  336. # Does PostgreSQL support finding primary key on non-Active Record tables?
  337. def supports_primary_key? #:nodoc:
  338. true
  339. end
  340. # Enable standard-conforming strings if available.
  341. def set_standard_conforming_strings
  342. old, self.client_min_messages = client_min_messages, 'panic'
  343. execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
  344. ensure
  345. self.client_min_messages = old
  346. end
  347. def supports_insert_with_returning?
  348. true
  349. end
  350. def supports_ddl_transactions?
  351. true
  352. end
  353. # Returns true, since this connection adapter supports savepoints.
  354. def supports_savepoints?
  355. true
  356. end
  357. # Returns true.
  358. def supports_explain?
  359. true
  360. end
  361. # Returns the configured supported identifier length supported by PostgreSQL
  362. def table_alias_length
  363. @table_alias_length ||= query('SHOW max_identifier_length')[0][0].to_i
  364. end
  365. # QUOTING ==================================================
  366. # Escapes binary strings for bytea input to the database.
  367. def escape_bytea(value)
  368. @connection.escape_bytea(value) if value
  369. end
  370. # Unescapes bytea output from a database to the binary string it represents.
  371. # NOTE: This is NOT an inverse of escape_bytea! This is only to be used
  372. # on escaped binary output from database drive.
  373. def unescape_bytea(value)
  374. @connection.unescape_bytea(value) if value
  375. end
  376. # Quotes PostgreSQL-specific data types for SQL input.
  377. def quote(value, column = nil) #:nodoc:
  378. return super unless column
  379. case value
  380. when Float
  381. return super unless value.infinite? && column.type == :datetime
  382. "'#{value.to_s.downcase}'"
  383. when Numeric
  384. return super unless column.sql_type == 'money'
  385. # Not truly string input, so doesn't require (or allow) escape string syntax.
  386. "'#{value}'"
  387. when String
  388. case column.sql_type
  389. when 'bytea' then "'#{escape_bytea(value)}'"
  390. when 'xml' then "xml '#{quote_string(value)}'"
  391. when /^bit/
  392. case value
  393. when /^[01]*$/ then "B'#{value}'" # Bit-string notation
  394. when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
  395. end
  396. else
  397. super
  398. end
  399. else
  400. super
  401. end
  402. end
  403. def type_cast(value, column)
  404. return super unless column
  405. case value
  406. when String
  407. return super unless 'bytea' == column.sql_type
  408. { :value => value, :format => 1 }
  409. else
  410. super
  411. end
  412. end
  413. # Quotes strings for use in SQL input.
  414. def quote_string(s) #:nodoc:
  415. @connection.escape(s)
  416. end
  417. # Checks the following cases:
  418. #
  419. # - table_name
  420. # - "table.name"
  421. # - schema_name.table_name
  422. # - schema_name."table.name"
  423. # - "schema.name".table_name
  424. # - "schema.name"."table.name"
  425. def quote_table_name(name)
  426. schema, name_part = extract_pg_identifier_from_name(name.to_s)
  427. unless name_part
  428. quote_column_name(schema)
  429. else
  430. table_name, name_part = extract_pg_identifier_from_name(name_part)
  431. "#{quote_column_name(schema)}.#{quote_column_name(table_name)}"
  432. end
  433. end
  434. # Quotes column names for use in SQL queries.
  435. def quote_column_name(name) #:nodoc:
  436. PGconn.quote_ident(name.to_s)
  437. end
  438. # Quote date/time values for use in SQL input. Includes microseconds
  439. # if the value is a Time responding to usec.
  440. def quoted_date(value) #:nodoc:
  441. if value.acts_like?(:time) && value.respond_to?(:usec)
  442. "#{super}.#{sprintf("%06d", value.usec)}"
  443. else
  444. super
  445. end
  446. end
  447. # Set the authorized user for this session
  448. def session_auth=(user)
  449. clear_cache!
  450. exec_query "SET SESSION AUTHORIZATION #{user}"
  451. end
  452. # REFERENTIAL INTEGRITY ====================================
  453. def supports_disable_referential_integrity? #:nodoc:
  454. true
  455. end
  456. def disable_referential_integrity #:nodoc:
  457. if supports_disable_referential_integrity? then
  458. execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
  459. end
  460. yield
  461. ensure
  462. if supports_disable_referential_integrity? then
  463. execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
  464. end
  465. end
  466. # DATABASE STATEMENTS ======================================
  467. def explain(arel, binds = [])
  468. sql = "EXPLAIN #{to_sql(arel, binds)}"
  469. ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
  470. end
  471. class ExplainPrettyPrinter # :nodoc:
  472. # Pretty prints the result of a EXPLAIN in a way that resembles the output of the
  473. # PostgreSQL shell:
  474. #
  475. # QUERY PLAN
  476. # ------------------------------------------------------------------------------
  477. # Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
  478. # Join Filter: (posts.user_id = users.id)
  479. # -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
  480. # Index Cond: (id = 1)
  481. # -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
  482. # Filter: (posts.user_id = 1)
  483. # (6 rows)
  484. #
  485. def pp(result)
  486. header = result.columns.first
  487. lines = result.rows.map(&:first)
  488. # We add 2 because there's one char of padding at both sides, note
  489. # the extra hyphens in the example above.
  490. width = [header, *lines].map(&:length).max + 2
  491. pp = []
  492. pp << header.center(width).rstrip
  493. pp << '-' * width
  494. pp += lines.map {|line| " #{line}"}
  495. nrows = result.rows.length
  496. rows_label = nrows == 1 ? 'row' : 'rows'
  497. pp << "(#{nrows} #{rows_label})"
  498. pp.join("\n") + "\n"
  499. end
  500. end
  501. # Executes a SELECT query and returns an array of rows. Each row is an
  502. # array of field values.
  503. def select_rows(sql, name = nil)
  504. select_raw(sql, name).last
  505. end
  506. # Executes an INSERT query and returns the new record's ID
  507. def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
  508. unless pk
  509. # Extract the table from the insert sql. Yuck.
  510. table_ref = extract_table_ref_from_insert_sql(sql)
  511. pk = primary_key(table_ref) if table_ref
  512. end
  513. if pk
  514. select_value("#{sql} RETURNING #{quote_column_name(pk)}")
  515. else
  516. super
  517. end
  518. end
  519. alias :create :insert
  520. # create a 2D array representing the result set
  521. def result_as_array(res) #:nodoc:
  522. # check if we have any binary column and if they need escaping
  523. ftypes = Array.new(res.nfields) do |i|
  524. [i, res.ftype(i)]
  525. end
  526. rows = res.values
  527. return rows unless ftypes.any? { |_, x|
  528. x == BYTEA_COLUMN_TYPE_OID || x == MONEY_COLUMN_TYPE_OID
  529. }
  530. typehash = ftypes.group_by { |_, type| type }
  531. binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
  532. monies = typehash[MONEY_COLUMN_TYPE_OID] || []
  533. rows.each do |row|
  534. # unescape string passed BYTEA field (OID == 17)
  535. binaries.each do |index, _|
  536. row[index] = unescape_bytea(row[index])
  537. end
  538. # If this is a money type column and there are any currency symbols,
  539. # then strip them off. Indeed it would be prettier to do this in
  540. # PostgreSQLColumn.string_to_decimal but would break form input
  541. # fields that call value_before_type_cast.
  542. monies.each do |index, _|
  543. data = row[index]
  544. # Because money output is formatted according to the locale, there are two
  545. # cases to consider (note the decimal separators):
  546. # (1) $12,345,678.12
  547. # (2) $12.345.678,12
  548. case data
  549. when /^-?\D+[\d,]+\.\d{2}$/ # (1)
  550. data.gsub!(/[^-\d.]/, '')
  551. when /^-?\D+[\d.]+,\d{2}$/ # (2)
  552. data.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
  553. end
  554. end
  555. end
  556. end
  557. # Queries the database and returns the results in an Array-like object
  558. def query(sql, name = nil) #:nodoc:
  559. log(sql, name) do
  560. result_as_array @connection.async_exec(sql)
  561. end
  562. end
  563. # Executes an SQL statement, returning a PGresult object on success
  564. # or raising a PGError exception otherwise.
  565. def execute(sql, name = nil)
  566. log(sql, name) do
  567. @connection.async_exec(sql)
  568. end
  569. end
  570. def substitute_at(column, index)
  571. Arel::Nodes::BindParam.new "$#{index + 1}"
  572. end
  573. def exec_query(sql, name = 'SQL', binds = [])
  574. log(sql, name, binds) do
  575. result = binds.empty? ? exec_no_cache(sql, binds) :
  576. exec_cache(sql, binds)
  577. ret = ActiveRecord::Result.new(result.fields, result_as_array(result))
  578. result.clear
  579. return ret
  580. end
  581. end
  582. def exec_delete(sql, name = 'SQL', binds = [])
  583. log(sql, name, binds) do
  584. result = binds.empty? ? exec_no_cache(sql, binds) :
  585. exec_cache(sql, binds)
  586. affected = result.cmd_tuples
  587. result.clear
  588. affected
  589. end
  590. end
  591. alias :exec_update :exec_delete
  592. def sql_for_insert(sql, pk, id_value, sequence_name, binds)
  593. unless pk
  594. # Extract the table from the insert sql. Yuck.
  595. table_ref = extract_table_ref_from_insert_sql(sql)
  596. pk = primary_key(table_ref) if table_ref
  597. end
  598. sql = "#{sql} RETURNING #{quote_column_name(pk)}" if pk
  599. [sql, binds]
  600. end
  601. # Executes an UPDATE query and returns the number of affected tuples.
  602. def update_sql(sql, name = nil)
  603. super.cmd_tuples
  604. end
  605. # Begins a transaction.
  606. def begin_db_transaction
  607. execute "BEGIN"
  608. end
  609. # Commits a transaction.
  610. def commit_db_transaction
  611. execute "COMMIT"
  612. end
  613. # Aborts a transaction.
  614. def rollback_db_transaction
  615. execute "ROLLBACK"
  616. end
  617. def outside_transaction?
  618. @connection.transaction_status == PGconn::PQTRANS_IDLE
  619. end
  620. def create_savepoint
  621. execute("SAVEPOINT #{current_savepoint_name}")
  622. end
  623. def rollback_to_savepoint
  624. execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
  625. end
  626. def release_savepoint
  627. execute("RELEASE SAVEPOINT #{current_savepoint_name}")
  628. end
  629. # SCHEMA STATEMENTS ========================================
  630. # Drops the database specified on the +name+ attribute
  631. # and creates it again using the provided +options+.
  632. def recreate_database(name, options = {}) #:nodoc:
  633. drop_database(name)
  634. create_database(name, options)
  635. end
  636. # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
  637. # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
  638. # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
  639. #
  640. # Example:
  641. # create_database config[:database], config
  642. # create_database 'foo_development', :encoding => 'unicode'
  643. def create_database(name, options = {})
  644. options = options.reverse_merge(:encoding => "utf8")
  645. option_string = options.symbolize_keys.sum do |key, value|
  646. case key
  647. when :owner
  648. " OWNER = \"#{value}\""
  649. when :template
  650. " TEMPLATE = \"#{value}\""
  651. when :encoding
  652. " ENCODING = '#{value}'"
  653. when :tablespace
  654. " TABLESPACE = \"#{value}\""
  655. when :connection_limit
  656. " CONNECTION LIMIT = #{value}"
  657. else
  658. ""
  659. end
  660. end
  661. execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
  662. end
  663. # Drops a PostgreSQL database.
  664. #
  665. # Example:
  666. # drop_database 'matt_development'
  667. def drop_database(name) #:nodoc:
  668. execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
  669. end
  670. # Returns the list of all tables in the schema search path or a specified schema.
  671. def tables(name = nil)
  672. query(<<-SQL, 'SCHEMA').map { |row| row[0] }
  673. SELECT tablename
  674. FROM pg_tables
  675. WHERE schemaname = ANY (current_schemas(false))
  676. SQL
  677. end
  678. # Returns true if table exists.
  679. # If the schema is not specified as part of +name+ then it will only find tables within
  680. # the current schema search path (regardless of permissions to access tables in other schemas)
  681. def table_exists?(name)
  682. schema, table = Utils.extract_schema_and_table(name.to_s)
  683. return false unless table
  684. binds = [[nil, table]]
  685. binds << [nil, schema] if schema
  686. exec_query(<<-SQL, 'SCHEMA', binds).rows.first[0].to_i > 0
  687. SELECT COUNT(*)
  688. FROM pg_class c
  689. LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
  690. WHERE c.relkind in ('v','r')
  691. AND c.relname = $1
  692. AND n.nspname = #{schema ? '$2' : 'ANY (current_schemas(false))'}
  693. SQL
  694. end
  695. # Returns true if schema exists.
  696. def schema_exists?(name)
  697. exec_query(<<-SQL, 'SCHEMA', [[nil, name]]).rows.first[0].to_i > 0
  698. SELECT COUNT(*)
  699. FROM pg_namespace
  700. WHERE nspname = $1
  701. SQL
  702. end
  703. # Returns an array of indexes for the given table.
  704. def indexes(table_name, name = nil)
  705. result = query(<<-SQL, name)
  706. SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
  707. FROM pg_class t
  708. INNER JOIN pg_index d ON t.oid = d.indrelid
  709. INNER JOIN pg_class i ON d.indexrelid = i.oid
  710. WHERE i.relkind = 'i'
  711. AND d.indisprimary = 'f'
  712. AND t.relname = '#{table_name}'
  713. AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
  714. ORDER BY i.relname
  715. SQL
  716. result.map do |row|
  717. index_name = row[0]
  718. unique = row[1] == 't'
  719. indkey = row[2].split(" ")
  720. inddef = row[3]
  721. oid = row[4]
  722. columns = Hash[query(<<-SQL, "Columns for index #{row[0]} on #{table_name}")]
  723. SELECT a.attnum, a.attname
  724. FROM pg_attribute a
  725. WHERE a.attrelid = #{oid}
  726. AND a.attnum IN (#{indkey.join(",")})
  727. SQL
  728. column_names = columns.values_at(*indkey).compact
  729. # add info on sort order for columns (only desc order is explicitly specified, asc is the default)
  730. desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
  731. orders = desc_order_columns.any? ? Hash[desc_order_columns.map {|order_column| [order_column, :desc]}] : {}
  732. column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names, [], orders)
  733. end.compact
  734. end
  735. # Returns the list of all column definitions for a table.
  736. def columns(table_name, name = nil)
  737. # Limit, precision, and scale are all handled by the superclass.
  738. column_definitions(table_name).collect do |column_name, type, default, notnull|
  739. PostgreSQLColumn.new(column_name, default, type, notnull == 'f')
  740. end
  741. end
  742. # Returns the current database name.
  743. def current_database
  744. query('select current_database()')[0][0]
  745. end
  746. # Returns the current schema name.
  747. def current_schema
  748. query('SELECT current_schema', 'SCHEMA')[0][0]
  749. end
  750. # Returns the current database encoding format.
  751. def encoding
  752. query(<<-end_sql)[0][0]
  753. SELECT pg_encoding_to_char(pg_database.encoding) FROM pg_database
  754. WHERE pg_database.datname LIKE '#{current_database}'
  755. end_sql
  756. end
  757. # Sets the schema search path to a string of comma-separated schema names.
  758. # Names beginning with $ have to be quoted (e.g. $user => '$user').
  759. # See: http://www.postgresql.org/docs/current/static/ddl-schemas.html
  760. #
  761. # This should be not be called manually but set in database.yml.
  762. def schema_search_path=(schema_csv)
  763. if schema_csv
  764. execute("SET search_path TO #{schema_csv}", 'SCHEMA')
  765. @schema_search_path = schema_csv
  766. end
  767. end
  768. # Returns the active schema search path.
  769. def schema_search_path
  770. @schema_search_path ||= query('SHOW search_path', 'SCHEMA')[0][0]
  771. end
  772. # Returns the current client message level.
  773. def client_min_messages
  774. query('SHOW client_min_messages', 'SCHEMA')[0][0]
  775. end
  776. # Set the client message level.
  777. def client_min_messages=(level)
  778. execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
  779. end
  780. # Returns the sequence name for a table's primary key or some other specified key.
  781. def default_sequence_name(table_name, pk = nil) #:nodoc:
  782. serial_sequence(table_name, pk || 'id').split('.').last
  783. rescue ActiveRecord::StatementInvalid
  784. "#{table_name}_#{pk || 'id'}_seq"
  785. end
  786. def serial_sequence(table, column)
  787. result = exec_query(<<-eosql, 'SCHEMA', [[nil, table], [nil, column]])
  788. SELECT pg_get_serial_sequence($1, $2)
  789. eosql
  790. result.rows.first.first
  791. end
  792. # Resets the sequence of a table's primary key to the maximum value.
  793. def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
  794. unless pk and sequence
  795. default_pk, default_sequence = pk_and_sequence_for(table)
  796. pk ||= default_pk
  797. sequence ||= default_sequence
  798. end
  799. if @logger && pk && !sequence
  800. @logger.warn "#{table} has primary key #{pk} with no default sequence"
  801. end
  802. if pk && sequence
  803. quoted_sequence = quote_table_name(sequence)
  804. select_value <<-end_sql, 'Reset sequence'
  805. 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)
  806. end_sql
  807. end
  808. end
  809. # Returns a table's primary key and belonging sequence.
  810. def pk_and_sequence_for(table) #:nodoc:
  811. # First try looking for a sequence with a dependency on the
  812. # given table's primary key.
  813. result = query(<<-end_sql, 'PK and serial sequence')[0]
  814. SELECT attr.attname, seq.relname
  815. FROM pg_class seq,
  816. pg_attribute attr,
  817. pg_depend dep,
  818. pg_namespace name,
  819. pg_constraint cons
  820. WHERE seq.oid = dep.objid
  821. AND seq.relkind = 'S'
  822. AND attr.attrelid = dep.refobjid
  823. AND attr.attnum = dep.refobjsubid
  824. AND attr.attrelid = cons.conrelid
  825. AND attr.attnum = cons.conkey[1]
  826. AND cons.contype = 'p'
  827. AND dep.refobjid = '#{quote_table_name(table)}'::regclass
  828. end_sql
  829. if result.nil? or result.empty?
  830. # If that fails, try parsing the primary key's default value.
  831. # Support the 7.x and 8.0 nextval('foo'::text) as well as
  832. # the 8.1+ nextval('foo'::regclass).
  833. result = query(<<-end_sql, 'PK and custom sequence')[0]
  834. SELECT attr.attname,
  835. CASE
  836. WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
  837. substr(split_part(def.adsrc, '''', 2),
  838. strpos(split_part(def.adsrc, '''', 2), '.')+1)
  839. ELSE split_part(def.adsrc, '''', 2)
  840. END
  841. FROM pg_class t
  842. JOIN pg_attribute attr ON (t.oid = attrelid)
  843. JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
  844. JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
  845. WHERE t.oid = '#{quote_table_name(table)}'::regclass
  846. AND cons.contype = 'p'
  847. AND def.adsrc ~* 'nextval'
  848. end_sql
  849. end
  850. [result.first, result.last]
  851. rescue
  852. nil
  853. end
  854. # Returns just a table's primary key
  855. def primary_key(table)
  856. row = exec_query(<<-end_sql, 'SCHEMA', [[nil, table]]).rows.first
  857. SELECT DISTINCT(attr.attname)
  858. FROM pg_attribute attr
  859. INNER JOIN pg_depend dep ON attr.attrelid = dep.refobjid AND attr.attnum = dep.refobjsubid
  860. INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
  861. WHERE cons.contype = 'p'
  862. AND dep.refobjid = $1::regclass
  863. end_sql
  864. row && row.first
  865. end
  866. # Renames a table.
  867. #
  868. # Example:
  869. # rename_table('octopuses', 'octopi')
  870. def rename_table(name, new_name)
  871. clear_cache!
  872. execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
  873. end
  874. # Adds a new column to the named table.
  875. # See TableDefinition#column for details of the options you can use.
  876. def add_column(table_name, column_name, type, options = {})
  877. clear_cache!
  878. add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
  879. add_column_options!(add_column_sql, options)
  880. execute add_column_sql
  881. end
  882. # Changes the column of a table.
  883. def change_column(table_name, column_name, type, options = {})
  884. clear_cache!
  885. quoted_table_name = quote_table_name(table_name)
  886. execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
  887. change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
  888. change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
  889. end
  890. # Changes the default value of a table column.
  891. def change_column_default(table_name, column_name, default)
  892. clear_cache!
  893. execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
  894. end
  895. def change_column_null(table_name, column_name, null, default = nil)
  896. clear_cache!
  897. unless null || default.nil?
  898. execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
  899. end
  900. execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
  901. end
  902. # Renames a column in a table.
  903. def rename_column(table_name, column_name, new_column_name)
  904. clear_cache!
  905. execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
  906. end
  907. def remove_index!(table_name, index_name) #:nodoc:
  908. execute "DROP INDEX #{quote_table_name(index_name)}"
  909. end
  910. def rename_index(table_name, old_name, new_name)
  911. execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
  912. end
  913. def index_name_length
  914. 63
  915. end
  916. # Maps logical Rails types to PostgreSQL-specific data types.
  917. def type_to_sql(type, limit = nil, precision = nil, scale = nil)
  918. case type.to_s
  919. when 'binary'
  920. # PostgreSQL doesn't support limits on binary (bytea) columns.
  921. # The hard limit is 1Gb, because of a 32-bit size field, and TOAST.
  922. case limit
  923. when nil, 0..0x3fffffff; super(type)
  924. else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
  925. end
  926. when 'integer'
  927. return 'integer' unless limit
  928. case limit
  929. when 1, 2; 'smallint'
  930. when 3, 4; 'integer'
  931. when 5..8; 'bigint'
  932. else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
  933. end
  934. else
  935. super
  936. end
  937. end
  938. # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
  939. #
  940. # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
  941. # requires that the ORDER BY include the distinct column.
  942. #
  943. # distinct("posts.id", "posts.created_at desc")
  944. def distinct(columns, orders) #:nodoc:
  945. return "DISTINCT #{columns}" if orders.empty?
  946. # Construct a clean list of column names from the ORDER BY clause, removing
  947. # any ASC/DESC modifiers
  948. order_columns = orders.collect { |s| s.gsub(/\s+(ASC|DESC)\s*/i, '') }
  949. order_columns.delete_if { |c| c.blank? }
  950. order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
  951. "DISTINCT #{columns}, #{order_columns * ', '}"
  952. end
  953. module Utils
  954. extend self
  955. # Returns an array of <tt>[schema_name, table_name]</tt> extracted from +name+.
  956. # +schema_name+ is nil if not specified in +name+.
  957. # +schema_name+ and +table_name+ exclude surrounding quotes (regardless of whether provided in +name+)
  958. # +name+ supports the range of schema/table references understood by PostgreSQL, for example:
  959. #
  960. # * <tt>table_name</tt>
  961. # * <tt>"table.name"</tt>
  962. # * <tt>schema_name.table_name</tt>
  963. # * <tt>schema_name."table.name"</tt>
  964. # * <tt>"schema.name"."table name"</tt>
  965. def extract_schema_and_table(name)
  966. table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse
  967. [schema, table]
  968. end
  969. end
  970. protected
  971. # Returns the version of the connected PostgreSQL server.
  972. def postgresql_version
  973. @connection.server_version
  974. end
  975. def translate_exception(exception, message)
  976. case exception.message
  977. when /duplicate key value violates unique constraint/
  978. RecordNotUnique.new(message, exception)
  979. when /violates foreign key constraint/
  980. InvalidForeignKey.new(message, exception)
  981. else
  982. super
  983. end
  984. end
  985. private
  986. FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
  987. def exec_no_cache(sql, binds)
  988. @connection.async_exec(sql)
  989. end
  990. def exec_cache(sql, binds)
  991. begin
  992. stmt_key = prepare_statement sql
  993. # Clear the queue
  994. @connection.get_last_result
  995. @connection.send_query_prepared(stmt_key, binds.map { |col, val|
  996. type_cast(val, col)
  997. })
  998. @connection.block
  999. @connection.get_last_result
  1000. rescue PGError => e
  1001. # Get the PG code for the failure. Annoyingly, the code for
  1002. # prepared statements whose return value may have changed is
  1003. # FEATURE_NOT_SUPPORTED. Check here for more details:
  1004. # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
  1005. code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
  1006. if FEATURE_NOT_SUPPORTED == code
  1007. @statements.delete sql_key(sql)
  1008. retry
  1009. else
  1010. raise e
  1011. end
  1012. end
  1013. end
  1014. # Returns the statement identifier for the client side cache
  1015. # of statements
  1016. def sql_key(sql)
  1017. "#{schema_search_path}-#{sql}"
  1018. end
  1019. # Prepare the statement if it hasn't been prepared, return
  1020. # the statement key.
  1021. def prepare_statement(sql)
  1022. sql_key = sql_key(sql)
  1023. unless @statements.key? sql_key
  1024. nextkey = @statements.next_key
  1025. @connection.prepare nextkey, sql
  1026. @statements[sql_key] = nextkey
  1027. end
  1028. @statements[sql_key]
  1029. end
  1030. # The internal PostgreSQL identifier of the money data type.
  1031. MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
  1032. # The internal PostgreSQL identifier of the BYTEA data type.
  1033. BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
  1034. # Connects to a PostgreSQL server and sets up the adapter depending on the
  1035. # connected server's characteristics.
  1036. def connect
  1037. @connection = PGconn.connect(*@connection_parameters)
  1038. # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
  1039. # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
  1040. # should know about this but can't detect it there, so deal with it here.
  1041. PostgreSQLColumn.money_precision = (postgresql_version >= 80300) ? 19 : 10
  1042. configure_connection
  1043. end
  1044. # Configures the encoding, verbosity, schema search path, and time zone of the connection.
  1045. # This is called by #connect and should not be called manually.
  1046. def configure_connection
  1047. if @config[:encoding]
  1048. @connection.set_client_encoding(@config[:encoding])
  1049. end
  1050. self.client_min_messages = @config[:min_messages] if @config[:min_messages]
  1051. self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
  1052. # Use standard-conforming strings if available so we don't have to do the E'...' dance.
  1053. set_standard_conforming_strings
  1054. # If using Active Record's time zone support configure the connection to return
  1055. # TIMESTAMP WITH ZONE types in UTC.
  1056. if ActiveRecord::Base.default_timezone == :utc
  1057. execute("SET time zone 'UTC'", 'SCHEMA')
  1058. elsif @local_tz
  1059. execute("SET time zone '#{@local_tz}'", 'SCHEMA')
  1060. end
  1061. end
  1062. # Returns the current ID of a table's sequence.
  1063. def last_insert_id(sequence_name) #:nodoc:
  1064. r = exec_query("SELECT currval($1)", 'SQL', [[nil, sequence_name]])
  1065. Integer(r.rows.first.first)
  1066. end
  1067. # Executes a SELECT query and returns the results, performing any data type
  1068. # conversions that are required to be performed here instead of in PostgreSQLColumn.
  1069. def select(sql, name = nil, binds = [])
  1070. exec_query(sql, name, binds).to_a
  1071. end
  1072. def select_raw(sql, name = nil)
  1073. res = execute(sql, name)
  1074. results = result_as_array(res)
  1075. fields = res.fields
  1076. res.clear
  1077. return fields, results
  1078. end
  1079. # Returns the list of a table's column names, data types, and default values.
  1080. #
  1081. # The underlying query is roughly:
  1082. # SELECT column.name, column.type, default.value
  1083. # FROM column LEFT JOIN default
  1084. # ON column.table_id = default.table_id
  1085. # AND column.num = default.column_num
  1086. # WHERE column.table_id = get_table_id('table_name')
  1087. # AND column.num > 0
  1088. # AND NOT column.is_dropped
  1089. # ORDER BY column.num
  1090. #
  1091. # If the table name is not prefixed with a schema, the database will
  1092. # take the first match from the schema search path.
  1093. #
  1094. # Query implementation notes:
  1095. # - format_type includes the column size constraint, e.g. varchar(50)
  1096. # - ::regclass is a function that gives the id for a table name
  1097. def column_definitions(table_name) #:nodoc:
  1098. exec_query(<<-end_sql, 'SCHEMA').rows
  1099. SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
  1100. FROM pg_attribute a LEFT JOIN pg_attrdef d
  1101. ON a.attrelid = d.adrelid AND a.attnum = d.adnum
  1102. WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
  1103. AND a.attnum > 0 AND NOT a.attisdropped
  1104. ORDER BY a.attnum
  1105. end_sql
  1106. end
  1107. def extract_pg_identifier_from_name(name)
  1108. match_data = name.start_with?('"') ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)
  1109. if match_data
  1110. rest = name[match_data[0].length, name.length]
  1111. rest = rest[1, rest.length] if rest.start_with? "."
  1112. [match_data[1], (rest.length > 0 ? rest : nil)]
  1113. end
  1114. end
  1115. def extract_table_ref_from_insert_sql(sql)
  1116. sql[/into\s+([^\(]*).*values\s*\(/i]
  1117. $1.strip if $1
  1118. end
  1119. def table_definition
  1120. TableDefinition.new(self)
  1121. end
  1122. end
  1123. end
  1124. end