module Sequel::Postgres::DatasetMethods

  1. lib/sequel/adapters/shared/postgres.rb
Parent: Postgres

Instance methods for datasets that connect to a PostgreSQL database.

Constants

ACCESS_EXCLUSIVE = 'ACCESS EXCLUSIVE'.freeze  
ACCESS_SHARE = 'ACCESS SHARE'.freeze  
APOS = Dataset::APOS  
APOS_RE = Dataset::APOS_RE  
AS = Dataset::AS  
BACKSLASH = Dataset::BACKSLASH  
BLOB_RE = /[\000-\037\047\134\177-\377]/n.freeze  
BOOL_FALSE = 'false'.freeze  
BOOL_TRUE = 'true'.freeze  
COMMA = Dataset::COMMA  
COMMA_SEPARATOR = ', '.freeze  
CRLF = "\r\n".freeze  
DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'delete from using where returning')  
DELETE_CLAUSE_METHODS_91 = Dataset.clause_methods(:delete, %w'with delete from using where returning')  
DOUBLE_APOS = Dataset::DOUBLE_APOS  
EMPTY_STRING = ''.freeze  
ESCAPE = Dataset::ESCAPE  
EXCLUSIVE = 'EXCLUSIVE'.freeze  
EXPLAIN = 'EXPLAIN '.freeze  
EXPLAIN_ANALYZE = 'EXPLAIN ANALYZE '.freeze  
FOR_SHARE = ' FOR SHARE'.freeze  
FROM = Dataset::FROM  
INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'insert into columns values returning')  
INSERT_CLAUSE_METHODS_91 = Dataset.clause_methods(:insert, %w'with insert into columns values returning')  
LOCK_MODES = ['ACCESS SHARE', 'ROW SHARE', 'ROW EXCLUSIVE', 'SHARE UPDATE EXCLUSIVE', 'SHARE', 'SHARE ROW EXCLUSIVE', 'EXCLUSIVE', 'ACCESS EXCLUSIVE'].each{|s| s.freeze}  
NULL = LiteralString.new('NULL').freeze  
PAREN_CLOSE = Dataset::PAREN_CLOSE  
PAREN_OPEN = Dataset::PAREN_OPEN  
PG_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze  
QUERY_PLAN = 'QUERY PLAN'.to_sym  
ROW_EXCLUSIVE = 'ROW EXCLUSIVE'.freeze  
ROW_SHARE = 'ROW SHARE'.freeze  
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct columns from join where group having compounds order limit lock')  
SELECT_CLAUSE_METHODS_84 = Dataset.clause_methods(:select, %w'with select distinct columns from join where group having window compounds order limit lock')  
SHARE = 'SHARE'.freeze  
SHARE_ROW_EXCLUSIVE = 'SHARE ROW EXCLUSIVE'.freeze  
SHARE_UPDATE_EXCLUSIVE = 'SHARE UPDATE EXCLUSIVE'.freeze  
SPACE = Dataset::SPACE  
SQL_WITH_RECURSIVE = "WITH RECURSIVE ".freeze  
UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'update table set from where returning')  
UPDATE_CLAUSE_METHODS_91 = Dataset.clause_methods(:update, %w'with update table set from where returning')  
WINDOW = " WINDOW ".freeze  
XOR_OP = ' # '.freeze  

Public Instance methods

analyze ()

Return the results of an EXPLAIN ANALYZE query as a string

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1138
def analyze
  explain(:analyze=>true)
end
complex_expression_sql_append (sql, op, args)

Handle converting the ruby xor operator (^) into the PostgreSQL xor operator (#), and use the ILIKE and NOT ILIKE operators.

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1145
def complex_expression_sql_append(sql, op, args)
  case op
  when :^
    j = XOR_OP
    c = false
    args.each do |a|
      sql << j if c
      literal_append(sql, a)
      c ||= true
    end
  when :ILIKE, :'NOT ILIKE'
    sql << PAREN_OPEN
    literal_append(sql, args.at(0))
    sql << SPACE << op.to_s << SPACE
    literal_append(sql, args.at(1))
    sql << ESCAPE
    literal_append(sql, BACKSLASH)
    sql << PAREN_CLOSE
  else
    super
  end
end
explain (opts=OPTS)

Return the results of an EXPLAIN query as a string

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1169
def explain(opts=OPTS)
  with_sql((opts[:analyze] ? EXPLAIN_ANALYZE : EXPLAIN) + select_sql).map(QUERY_PLAN).join(CRLF)
end
for_share ()

Return a cloned dataset which will use FOR SHARE to lock returned rows.

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1174
def for_share
  lock_style(:share)
end
insert (*values)

Insert given values into the database.

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1187
def insert(*values)
  if @opts[:returning]
    # already know which columns to return, let the standard code
    # handle it
    super
  elsif @opts[:sql]
    # raw SQL used, so don't know which table is being inserted
    # into, and therefore can't determine primary key.  Run the
    # insert statement and return nil.
    super
    nil
  else
    # Force the use of RETURNING with the primary key value.
    returning(insert_pk).insert(*values){|r| return r.values.first}
  end
end
insert_select (*values)

Insert a record returning the record inserted

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1205
def insert_select(*values)
  returning.insert(*values){|r| return r}
end
lock (mode, opts=OPTS)

Locks all tables in the dataset’s FROM clause (but not in JOINs) with the specified mode (e.g. ‘EXCLUSIVE’). If a block is given, starts a new transaction, locks the table, and yields. If a block is not given just locks the tables. Note that PostgreSQL will probably raise an error if you lock the table outside of an existing transaction. Returns nil.

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1214
def lock(mode, opts=OPTS)
  if block_given? # perform locking inside a transaction and yield to block
    @db.transaction(opts){lock(mode, opts); yield}
  else
    sql = 'LOCK TABLE '
    source_list_append(sql, @opts[:from])
    mode = mode.to_s.upcase.strip
    unless LOCK_MODES.include?(mode)
      raise Error, "Unsupported lock mode: #{mode}"
    end
    sql << " IN #{mode} MODE"
    @db.execute(sql, opts)
  end
  nil
end
multi_insert_sql (columns, values)

PostgreSQL allows inserting multiple rows at once.

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1231
def multi_insert_sql(columns, values)
  sql = LiteralString.new('VALUES ')
  expression_list_append(sql, values.map{|r| Array(r)})
  [insert_sql(columns, sql)]
end
supports_cte_in_subqueries? ()

PostgreSQL supports using the WITH clause in subqueries if it supports using WITH at all (i.e. on PostgreSQL 8.4+).

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1239
def supports_cte_in_subqueries?
  supports_cte?
end
supports_distinct_on? ()

DISTINCT ON is a PostgreSQL extension

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1244
def supports_distinct_on?
  true
end
supports_lateral_subqueries? ()

PostgreSQL 9.3rc1+ supports lateral subqueries

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1249
def supports_lateral_subqueries?
  server_version >= 90300
end
supports_modifying_joins? ()

PostgreSQL supports modifying joined datasets

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1254
def supports_modifying_joins?
  true
end
supports_regexp? ()

PostgreSQL supports pattern matching via regular expressions

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1264
def supports_regexp?
  true
end
supports_returning? (type)

Returning is always supported.

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1259
def supports_returning?(type)
  true
end
supports_timestamp_timezones? ()

PostgreSQL supports timezones in literal timestamps

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1269
def supports_timestamp_timezones?
  true
end
supports_window_functions? ()

PostgreSQL 8.4+ supports window functions

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1274
def supports_window_functions?
  server_version >= 80400
end
truncate (opts = OPTS)

Truncates the dataset. Returns nil.

Options:

:cascade

whether to use the CASCADE option, useful when truncating

tables with Foreign Keys.
:only

truncate using ONLY, so child tables are unaffected

:restart

use RESTART IDENTITY to restart any related sequences

:only and :restart only work correctly on PostgreSQL 8.4+.

Usage:

DB[:table].truncate # TRUNCATE TABLE "table"
# => nil
DB[:table].truncate(:cascade => true, :only=>true, :restart=>true) # TRUNCATE TABLE ONLY "table" RESTART IDENTITY CASCADE
# => nil
[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1293
def truncate(opts = OPTS)
  if opts.empty?
    super()
  else
    clone(:truncate_opts=>opts).truncate
  end
end
window (name, opts)

Return a clone of the dataset with an addition named window that can be referenced in window functions.

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1302
def window(name, opts)
  clone(:window=>(@opts[:window]||[]) + [[name, SQL::Window.new(opts)]])
end

Protected Instance methods

_import (columns, values, opts=OPTS)

If returned primary keys are requested, use RETURNING unless already set on the dataset. If RETURNING is already set, use existing returning values. If RETURNING is only set to return a single columns, return an array of just that column. Otherwise, return an array of hashes.

[show source]
# File lib/sequel/adapters/shared/postgres.rb, line 1312
def _import(columns, values, opts=OPTS)
  if @opts[:returning]
    statements = multi_insert_sql(columns, values)
    @db.transaction(opts.merge(:server=>@opts[:server])) do
      statements.map{|st| returning_fetch_rows(st)}
    end.first.map{|v| v.length == 1 ? v.values.first : v}
  elsif opts[:return] == :primary_key
    returning(insert_pk)._import(columns, values, opts)
  else
    super
  end
end