class Sequel::Postgres::Dataset
postgres-pr driver.
Dataset class for PostgreSQL datasets that use the pg, postgres, or
def call(type, bind_vars={}, *values, &block)
def call(type, bind_vars={}, *values, &block) ps = to_prepared_statement(type, values) ps.extend(BindArgumentMethods) ps.call(bind_vars, &block) end
def cursor_fetch_rows(sql, &block)
def cursor_fetch_rows(sql, &block) server_opts = {:server=>@opts[:server] || :read_only} db.transaction(server_opts) do begin execute_ddl("DECLARE sequel_cursor NO SCROLL CURSOR WITHOUT HOLD FOR #{sql}", server_opts) rows_per_fetch = @opts[:cursor][:rows_per_fetch].to_i rows_per_fetch = 1000 if rows_per_fetch <= 0 fetch_sql = "FETCH FORWARD #{rows_per_fetch} FROM sequel_cursor" cols = nil # Load columns only in the first fetch, so subsequent fetches are faster execute(fetch_sql) do |res| cols = fetch_rows_set_cols(res) yield_hash_rows(res, cols, &block) return if res.ntuples < rows_per_fetch end loop do execute(fetch_sql) do |res| yield_hash_rows(res, cols, &block) return if res.ntuples < rows_per_fetch end end ensure execute_ddl("CLOSE sequel_cursor", server_opts) end end end
def fetch_rows(sql, &block)
Yield all rows returned by executing the given SQL and converting
def fetch_rows(sql, &block) return cursor_fetch_rows(sql, &block) if @opts[:cursor] execute(sql){|res| yield_hash_rows(res, fetch_rows_set_cols(res), &block)} end
def fetch_rows_set_cols(res)
Set the @columns based on the result set, and return the array of
def fetch_rows_set_cols(res) cols = [] procs = db.conversion_procs res.nfields.times do |fieldnum| cols << [fieldnum, procs[res.ftype(fieldnum)], output_identifier(res.fname(fieldnum))] end @columns = cols.map{|c| c.at(2)} cols end
def literal_blob_append(sql, v)
def literal_blob_append(sql, v) sql << "'" << db.synchronize{|c| c.escape_bytea(v)} << "'" end
def literal_string_append(sql, v)
def literal_string_append(sql, v) sql << "'" << db.synchronize{|c| c.escape_string(v)} << "'" end
def prepare(type, name=nil, *values)
Prepare the given type of statement with the given name, and store
def prepare(type, name=nil, *values) ps = to_prepared_statement(type, values) ps.extend(PreparedStatementMethods) if name ps.prepared_statement_name = name db.prepared_statements[name] = ps end ps end
def prepared_arg_placeholder
PostgreSQL uses $N for placeholders instead of ?, so use a $
def prepared_arg_placeholder PREPARED_ARG_PLACEHOLDER end
def use_cursor(opts={})
This is untested with the prepared statement/bound variable support,
DB[:huge_table].use_cursor(:rows_per_fetch=>10000).each{|row| p row}
DB[:huge_table].use_cursor.each{|row| p row}
Usage:
numbers result in fewer queries but greater memory use.
* :rows_per_fetch - the number of rows per fetch (default 1000). Higher
by default). Options:
all rows in memory (which is what the underlying drivers do
set at once. Can be used to process large datasets without holding
Uses a cursor for fetching records, instead of fetching the entire result
def use_cursor(opts={}) clone(:cursor=>{:rows_per_fetch=>1000}.merge(opts)) end
def yield_hash_rows(res, cols)
For each row in the result set, yield a hash with column name symbol
def yield_hash_rows(res, cols) res.ntuples.times do |recnum| converted_rec = {} cols.each do |fieldnum, type_proc, fieldsym| value = res.getvalue(recnum, fieldnum) converted_rec[fieldsym] = (value && type_proc) ? type_proc.call(value) : value end yield converted_rec end end