lib/do_postgres.rb in do_postgres-0.2.4 vs lib/do_postgres.rb in do_postgres-0.9.2

- old
+ new

@@ -1,246 +1,5 @@ -require 'postgres_c' -require 'data_objects' -module DataObject - module Postgres - TYPES = Hash[*Postgres_c.constants.select {|x| x.include?("OID")}.map {|x| [Postgres_c.const_get(x), x.gsub(/_?OID$/, "")]}.flatten] - QUOTE_STRING = "'" - QUOTE_COLUMN = "\"" - - class Connection < DataObject::Connection - attr_reader :db - - def initialize(connection_string) - @state = STATE_CLOSED - @connection_string = connection_string - end - - def open - @db = Postgres_c.PQconnectdb(@connection_string) - if Postgres_c.PQstatus(@db) != Postgres_c::CONNECTION_OK - raise ConnectionFailed, "Unable to connect to database with provided connection string. \n#{Postgres_c.PQerrorMessage(@db)}" - end - @state = STATE_OPEN - true - end - - def close - Postgres_c.PQfinish(@db) - @state = STATE_CLOSED - true - end - - def create_command(text) - Command.new(self, text) - end - - def begin_transaction - Transaction.new(self) - end - - end - - class Transaction < Connection - - attr_reader :connection - - def initialize(conn) - @connection = conn - exec_sql("BEGIN") - end - - # Commits the transaction - def commit - exec_sql("COMMIT") - end - - # Rolls back the transaction - def rollback(savepoint = nil) - exec_sql("ROLLBACK#{savepoint ? " TO " + savepoint : ""}") - end - - # Creates a savepoint for rolling back later (not commonly supported) - def save(name) - exec_sql("SAVEPOINT #{name}") - end - - def create_command(*args) - @connection.create_command(*args) - end - - protected - - def exec_sql(sql) - @connection.logger.debug(sql) - Postgres_c.PQexec(@connection.db, "COMMIT") - end - - end - - class Reader < DataObject::Reader - - def initialize(db, reader) - @reader = reader - case Postgres_c.PQresultStatus(reader) - when Postgres_c::PGRES_COMMAND_OK - @records_affected = Postgres_c.PQcmdTuples(reader).to_i - close - when Postgres_c::PGRES_TUPLES_OK - @fields, @field_types = [], [] - @field_count = Postgres_c.PQnfields(@reader) - i = 0 - while(i < @field_count) - @field_types.push(Postgres_c.PQftype(@reader, i)) - @fields.push(Postgres_c.PQfname(@reader, i)) - i += 1 - end - @rows = Postgres_c.PQntuples(@reader) - @has_rows = @rows > 0 - @cursor = 0 - @state = STATE_OPEN - end - end - - def real_close - Postgres_c.PQclear(@reader) - end - - def data_type_name(col) - - end - - def name(col) - super - Postgres_c.PQfname(@reader, col) - end - - def get_index(name) - super - @fields.index(name) - end - - def null?(idx) - super - Postgres_c.PQgetisnull(@reader, @cursor, idx) != 0 - end - - def item(idx) - super - val = Postgres_c.PQgetvalue(@reader, @cursor, idx) - typecast(val, @field_types[idx]) - end - - def each - return unless has_rows? - - while(true) do - yield - break unless self.next - end - end - - def next - super - if @cursor >= @rows - 1 - @cursor = nil - close - return nil - end - @cursor += 1 - true - end - - protected - def native_type(col) - TYPES[Postgres_c.PQftype(@reader, col)] - end - - def typecast(val, field_type) - return nil if val.nil? || val == "NULL" - case TYPES[field_type] - when "BOOL" - val == "t" - when "INT2", "INT4", "OID", "TID", "XID", "CID", "INT8" - val == '' ? nil : val.to_i - when "FLOAT4", "FLOAT8", "NUMERIC", "CASH" - val.to_f - when "TIMESTAMP", "TIMETZ", "TIMESTAMPTZ" - DateTime.parse(val) rescue nil - when "TIME" - DateTime.parse(val).to_time rescue nil - when "DATE" - Date.parse(val) rescue nil - else - val - end - end - - end - - class ResultData < DataObject::ResultData - - def last_insert_row - @last_insert_row ||= begin - reader = @conn.create_command("select lastval()").execute_reader - reader.item(0).to_i - rescue QueryError - raise NoInsertError, "You tried to get the last inserted row without doing an insert\n#{Postgres_c.PQerrorMessage(@conn.db)}" - ensure - reader and reader.close - end - end - - end - - class Command < DataObject::Command - - def execute_reader(*args) - super - sql = escape_sql(args) - @connection.logger.debug { sql } - ptr = Postgres_c.PQexec(@connection.db, sql) - unless [Postgres_c::PGRES_COMMAND_OK, Postgres_c::PGRES_TUPLES_OK].include?(Postgres_c.PQresultStatus(ptr)) - raise QueryError, "Your query failed.\n#{Postgres_c.PQerrorMessage(@connection.db)}QUERY: \"#{sql}\"" - else - reader = Reader.new(@connection.db, ptr) - if block_given? - return_value = yield(reader) - reader.close - return_value - else - reader - end - end - end - - def execute_non_query(*args) - super - sql = escape_sql(args) - @connection.logger.debug { sql } - results = Postgres_c.PQexec(@connection.db, sql) - status = Postgres_c.PQresultStatus(results) - if status == Postgres_c::PGRES_TUPLES_OK - Postgres_c.PQclear(results) - raise QueryError, "Your query failed or you tried to execute a SELECT query through execute_non_reader\n#{Postgres_c.PQerrorMessage(@connection.db)}\nQUERY: \"#{sql}\"" - elsif status != Postgres_c::PGRES_COMMAND_OK - Postgres_c.PQclear(results) - raise QueryError, "Your query failed.\n#{Postgres_c.PQerrorMessage(@connection.db)}\nQUERY: \"#{sql}\"" - end - rows_affected = Postgres_c.PQcmdTuples(results).to_i - Postgres_c.PQclear(results) - ResultData.new(@connection, rows_affected) - end - - def quote_string(value) - if value =~ /[\x00-\x80]/ - raise "String cannot contain $Text$ in the body" if value.include?("$Text$") - "$Text$#{value}$Text$" - else - super - end - end - - end - - end -end +require 'rubygems' +require 'data_objects' +require 'do_postgres_ext' +require 'do_postgres/transaction'