Class: Sequel::Postgres::Database

Inherits:
Database show all
Defined in:
lib/sequel_core/adapters/postgres.rb

Constant Summary collapse

RELATION_QUERY =
{:from => [:pg_class], :select => [:relname]}.freeze
RELATION_FILTER =
"(relkind = 'r') AND (relname !~ '^pg|sql')".freeze
SYSTEM_TABLE_REGEXP =
/^pg|sql/.freeze
RE_CURRVAL_ERROR =
/currval of sequence "(.*)" is not yet defined in this session/.freeze
SQL_BEGIN =
'BEGIN'.freeze
SQL_SAVEPOINT =
'SAVEPOINT autopoint_%d'.freeze
SQL_COMMIT =
'COMMIT'.freeze
SQL_ROLLBACK_TO_SAVEPOINT =
'ROLLBACK TO SAVEPOINT autopoint_%d'.freeze
SQL_ROLLBACK =
'ROLLBACK'.freeze
SQL_RELEASE_SAVEPOINT =
'RELEASE SAVEPOINT autopoint_%d'.freeze

Constants inherited from Database

Database::ADAPTERS

Constants included from Schema::SQL

Schema::SQL::AUTOINCREMENT, Schema::SQL::CASCADE, Schema::SQL::COMMA_SEPARATOR, Schema::SQL::NOT_NULL, Schema::SQL::NO_ACTION, Schema::SQL::NULL, Schema::SQL::PRIMARY_KEY, Schema::SQL::RESTRICT, Schema::SQL::SET_DEFAULT, Schema::SQL::SET_NULL, Schema::SQL::TYPES, Schema::SQL::UNDERSCORE, Schema::SQL::UNIQUE, Schema::SQL::UNSIGNED

Instance Attribute Summary

Attributes inherited from Database

#loggers, #opts, #pool, #quote_identifiers

Instance Method Summary collapse

Methods inherited from Database

#<<, #[], adapter_class, adapter_scheme, #add_column, #add_index, #alter_table, connect, #create_or_replace_view, #create_table, #create_table!, #create_view, #drop_column, #drop_index, #drop_table, #drop_view, #fetch, #from, #get, #initialize, #inspect, #log_info, #logger, #logger=, #multi_threaded?, #query, quote_identifiers=, #quote_identifiers?, #rename_column, #rename_table, #select, #set_column_default, #set_column_type, single_threaded=, #single_threaded?, #synchronize, #table_exists?, #test_connection, #typecast_value, #uri, uri_to_options

Methods included from Schema::SQL

#alter_table_sql, #alter_table_sql_list, #auto_increment_sql, #column_definition_sql, #column_list_sql, #constraint_definition_sql, #create_table_sql_list, #default_index_name, #filter_expr, #index_list_sql_list, #literal, #on_delete_clause, #quote_identifier, #rename_table_sql, #schema, #schema_utility_dataset, #type_literal

Constructor Details

This class inherits a constructor from Sequel::Database

Instance Method Details

#connectObject



189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/sequel_core/adapters/postgres.rb', line 189

def connect
  conn = Adapter.connect(
    @opts[:host] || 'localhost',
    @opts[:port] || 5432,
    '', '',
    @opts[:database],
    @opts[:user],
    @opts[:password]
  )
  if encoding = @opts[:encoding] || @opts[:charset]
    conn.set_client_encoding(encoding)
  end
  conn
end

#dataset(opts = nil) ⇒ Object



208
209
210
# File 'lib/sequel_core/adapters/postgres.rb', line 208

def dataset(opts = nil)
  Postgres::Dataset.new(self, opts)
end

#disconnectObject



204
205
206
# File 'lib/sequel_core/adapters/postgres.rb', line 204

def disconnect
  @pool.disconnect {|c| c.finish}
end

#drop_table_sql(name) ⇒ Object



366
367
368
# File 'lib/sequel_core/adapters/postgres.rb', line 366

def drop_table_sql(name)
  "DROP TABLE #{name} CASCADE"
end

#execute(sql, &block) ⇒ Object



226
227
228
229
230
231
232
233
234
# File 'lib/sequel_core/adapters/postgres.rb', line 226

def execute(sql, &block)
  begin
    log_info(sql)
    @pool.hold {|conn| conn.execute(sql, &block)}
  rescue => e
    log_info(e.message)
    raise convert_pgerror(e)
  end
end

#execute_insert(sql, table, values) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/sequel_core/adapters/postgres.rb', line 281

def execute_insert(sql, table, values)
  begin 
    log_info(sql)
    @pool.hold do |conn|
      conn.execute(sql)
      insert_result(conn, table, values)
    end
  rescue => e
    log_info(e.message)
    raise convert_pgerror(e)
  end
end

#index_definition_sql(table_name, index) ⇒ Object



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/sequel_core/adapters/postgres.rb', line 347

def index_definition_sql(table_name, index)
  index_name = index[:name] || default_index_name(table_name, index[:columns])
  expr = literal(Array(index[:columns]))
  unique = "UNIQUE " if index[:unique]
  index_type = index[:type]
  filter = index[:where] || index[:filter]
  filter = " WHERE #{filter_expr(filter)}" if filter
  case index_type
  when :full_text
    lang = index[:language] ? "#{literal(index[:language])}, " : ""
    cols = index[:columns].map {|c| literal(c)}.join(" || ")
    expr = "(to_tsvector(#{lang}#{cols}))"
    index_type = :gin
  when :spatial
    index_type = :gist
  end
  "CREATE #{unique}INDEX #{index_name} ON #{table_name} #{"USING #{index_type} " if index_type}#{expr}#{filter}"
end

#insert_result(conn, table, values) ⇒ Object



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/sequel_core/adapters/postgres.rb', line 243

def insert_result(conn, table, values)
  begin
    result = conn.last_insert_id(table)
    return result if result
  rescue PGError => e
    # An error could occur if the inserted values include a primary key
    # value, while the primary key is serial.
    raise Error.new(e.message =~ RE_CURRVAL_ERROR ? "Could not return primary key value for the inserted record. Are you specifying a primary key value for a serial primary key?" : e.message)
  end
  
  case values
  when Hash
    values[primary_key_for_table(conn, table)]
  when Array
    values.first
  else
    nil
  end
end

#locksObject



220
221
222
223
224
# File 'lib/sequel_core/adapters/postgres.rb', line 220

def locks
  dataset.from("pg_class, pg_locks").
    select("pg_class.relname, pg_locks.*").
    filter("pg_class.relfilenode=pg_locks.relation")
end

#primary_key_for_table(conn, table) ⇒ Object



236
237
238
239
# File 'lib/sequel_core/adapters/postgres.rb', line 236

def primary_key_for_table(conn, table)
  @primary_keys ||= {}
  @primary_keys[table] ||= conn.primary_key(table)
end

#serial_primary_key_optionsObject



343
344
345
# File 'lib/sequel_core/adapters/postgres.rb', line 343

def serial_primary_key_options
  {:primary_key => true, :type => :serial}
end

#server_versionObject



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/sequel_core/adapters/postgres.rb', line 263

def server_version
  return @server_version if @server_version
  @server_version = pool.hold do |conn|
    if conn.respond_to?(:server_version)
      begin
        conn.server_version
      rescue StandardError
        nil
      end
    end
  end
  unless @server_version
    m = /PostgreSQL (\d+)\.(\d+)\.(\d+)/.match(get(:version[]))
    @server_version = (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
  end
  @server_version
end

#tablesObject



216
217
218
# File 'lib/sequel_core/adapters/postgres.rb', line 216

def tables
  dataset(RELATION_QUERY).filter(RELATION_FILTER).map {|r| r[:relname].to_sym}
end

#transactionObject



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/sequel_core/adapters/postgres.rb', line 301

def transaction
  @pool.hold do |conn|
    conn.transaction_depth = 0 if conn.transaction_depth.nil?
    if conn.transaction_depth > 0
      log_info(SQL_SAVEPOINT % conn.transaction_depth)
      conn.execute(SQL_SAVEPOINT % conn.transaction_depth)
    else
      log_info(SQL_BEGIN)
      conn.execute(SQL_BEGIN)
    end
    begin
      conn.transaction_depth += 1
      yield
    rescue ::Exception => e
      if conn.transaction_depth > 1
        log_info(SQL_ROLLBACK_TO_SAVEPOINT % [conn.transaction_depth - 1])
        conn.execute(SQL_ROLLBACK_TO_SAVEPOINT % [conn.transaction_depth - 1])
      else
        log_info(SQL_ROLLBACK)
        conn.execute(SQL_ROLLBACK) rescue nil
      end
      raise convert_pgerror(e) unless Error::Rollback === e
    ensure
      unless e
        begin
          if conn.transaction_depth < 2
            log_info(SQL_COMMIT)
            conn.execute(SQL_COMMIT)
          else
            log_info(SQL_RELEASE_SAVEPOINT % [conn.transaction_depth - 1])
            conn.execute(SQL_RELEASE_SAVEPOINT % [conn.transaction_depth - 1])
          end
        rescue => e
          log_info(e.message)
          raise convert_pgerror(e)
        end
      end
      conn.transaction_depth -= 1
    end
  end
end