Module: ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements

Included in:
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
Defined in:
lib/active_record/connection_adapters/postgresql/database_statements.rb

Constant Summary collapse

MONEY_COLUMN_TYPE_OID =

The internal PostgreSQL identifier of the money data type.

790
BYTEA_COLUMN_TYPE_OID =

The internal PostgreSQL identifier of the BYTEA data type.

17

Instance Method Summary collapse

Instance Method Details

#begin_db_transactionObject

Begins a transaction.

[View source]

132
133
134
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 132

def begin_db_transaction
  execute "BEGIN"
end

#begin_isolated_db_transaction(isolation) ⇒ Object

[View source]

136
137
138
139
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 136

def begin_isolated_db_transaction(isolation)
  begin_db_transaction
  execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
end

#commit_db_transactionObject

Commits a transaction.

[View source]

142
143
144
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 142

def commit_db_transaction
  execute "COMMIT"
end

#exec_delete(sql, name = nil, binds = []) ⇒ Object Also known as: exec_update

[View source]

93
94
95
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 93

def exec_delete(sql, name = nil, binds = [])
  execute_and_clear(sql, name, binds) { |result| result.cmd_tuples }
end

#exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) ⇒ Object

[View source]

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 113

def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
  if use_insert_returning? || pk == false
    super
  else
    result = exec_query(sql, name, binds)
    unless sequence_name
      table_ref = extract_table_ref_from_insert_sql(sql)
      if table_ref
        pk = primary_key(table_ref) if pk.nil?
        pk = suppress_composite_primary_key(pk)
        sequence_name = default_sequence_name(table_ref, pk)
      end
      return result unless sequence_name
    end
    last_insert_id_result(sequence_name)
  end
end

#exec_query(sql, name = "SQL", binds = [], prepare: false) ⇒ Object

[View source]

80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 80

def exec_query(sql, name = "SQL", binds = [], prepare: false)
  execute_and_clear(sql, name, binds, prepare: prepare) do |result|
    types = {}
    fields = result.fields
    fields.each_with_index do |fname, i|
      ftype = result.ftype i
      fmod  = result.fmod i
      types[fname] = get_oid_type(ftype, fmod, fname)
    end
    ActiveRecord::Result.new(fields, result.values, types)
  end
end

#exec_rollback_db_transactionObject

Aborts a transaction.

[View source]

147
148
149
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 147

def exec_rollback_db_transaction
  execute "ROLLBACK"
end

#execute(sql, name = nil) ⇒ Object

Executes an SQL statement, returning a PG::Result object on success or raising a PG::Error exception otherwise. Note: the PG::Result object is manually memory managed; if you don't need it specifically, you may want consider the exec_query wrapper.

[View source]

72
73
74
75
76
77
78
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 72

def execute(sql, name = nil)
  log(sql, name) do
    ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
      @connection.async_exec(sql)
    end
  end
end

#explain(arel, binds = []) ⇒ Object

[View source]

7
8
9
10
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 7

def explain(arel, binds = [])
  sql = "EXPLAIN #{to_sql(arel, binds)}"
  PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", binds))
end

#query(sql, name = nil) ⇒ Object

Queries the database and returns the results in an Array-like object

[View source]

60
61
62
63
64
65
66
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 60

def query(sql, name = nil) #:nodoc:
  log(sql, name) do
    ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
      result_as_array @connection.async_exec(sql)
    end
  end
end

#result_as_array(res) ⇒ Object

create a 2D array representing the result set

[View source]

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/active_record/connection_adapters/postgresql/database_statements.rb', line 18

def result_as_array(res) #:nodoc:
  # check if we have any binary column and if they need escaping
  ftypes = Array.new(res.nfields) do |i|
    [i, res.ftype(i)]
  end

  rows = res.values
  return rows unless ftypes.any? { |_, x|
    x == BYTEA_COLUMN_TYPE_OID || x == MONEY_COLUMN_TYPE_OID
  }

  typehash = ftypes.group_by { |_, type| type }
  binaries = typehash[BYTEA_COLUMN_TYPE_OID] || []
  monies   = typehash[MONEY_COLUMN_TYPE_OID] || []

  rows.each do |row|
    # unescape string passed BYTEA field (OID == 17)
    binaries.each do |index, _|
      row[index] = unescape_bytea(row[index])
    end

    # If this is a money type column and there are any currency symbols,
    # then strip them off. Indeed it would be prettier to do this in
    # PostgreSQLColumn.string_to_decimal but would break form input
    # fields that call value_before_type_cast.
    monies.each do |index, _|
      data = row[index]
      # Because money output is formatted according to the locale, there are two
      # cases to consider (note the decimal separators):
      #  (1) $12,345,678.12
      #  (2) $12.345.678,12
      case data
      when /^-?\D+[\d,]+\.\d{2}$/  # (1)
        data.gsub!(/[^-\d.]/, "")
      when /^-?\D+[\d.]+,\d{2}$/  # (2)
        data.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
      end
    end
  end
end