Skip to content

Commit

Permalink
Add Database#error_info on PostgreSQL 9.3+ if pg-0.16.0+ is used, to …
Browse files Browse the repository at this point in the history
…get a hash of metadata for a given database exception

This just attempts to offer a simpler interface to the underlying
ruby-pg error metadata extraction methods.
  • Loading branch information
jeremyevans committed Jul 25, 2013
1 parent 9dd5453 commit ac3fcaf
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== HEAD

* Add Database#error_info on PostgreSQL 9.3+ if pg-0.16.0+ is used, to get a hash of metadata for a given database exception (jeremyevans)

* Allow prepared_statements plugin to work with instance_filters and update_primary_key plugins (jeremyevans)

* Support deferrable exclusion constraints on PostgreSQL using the :deferrable option (mfoody) (#687)
Expand Down
25 changes: 25 additions & 0 deletions lib/sequel/adapters/postgres.rb
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,31 @@ def disconnect_connection(conn)
rescue PGError, IOError
end
end

if SEQUEL_POSTGRES_USES_PG && Object.const_defined?(:PG) && ::PG.const_defined?(:Constants) && ::PG::Constants.const_defined?(:PG_DIAG_SCHEMA_NAME)
# Return a hash of information about the related PGError (or Sequel::DatabaseError that
# wraps a PGError), with the following entries:
#
# :schema :: The schema name related to the error
# :table :: The table name related to the error
# :column :: the column name related to the error
# :constraint :: The constraint name related to the error
# :type :: The datatype name related to the error
#
# This requires a PostgreSQL 9.3+ server and 9.3+ client library,
# and ruby-pg 0.16.0+ to be supported.
def error_info(e)
e = e.wrapped_exception if e.is_a?(DatabaseError)
r = e.result
h = {}
h[:schema] = r.error_field(::PG::PG_DIAG_SCHEMA_NAME)
h[:table] = r.error_field(::PG::PG_DIAG_TABLE_NAME)
h[:column] = r.error_field(::PG::PG_DIAG_COLUMN_NAME)
h[:constraint] = r.error_field(::PG::PG_DIAG_CONSTRAINT_NAME)
h[:type] = r.error_field(::PG::PG_DIAG_DATATYPE_NAME)
h
end
end

# Execute the given SQL with the given args on an available connection.
def execute(sql, opts=OPTS, &block)
Expand Down
27 changes: 27 additions & 0 deletions spec/adapters/postgres_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,33 @@ def logger.method_missing(m, msg)
end.should raise_error(Sequel::Postgres::ExclusionConstraintViolation)
end if DB.server_version >= 90000

specify "should support Database#error_info for getting info hash on the given error" do
@db.create_table!(:atest){Integer :t; Integer :t2, :null=>false, :default=>1; constraint :f, :t=>0}
begin
@db[:atest].insert(1)
rescue => e
end
e.should_not be_nil
info = @db.error_info(e)
info[:schema].should == 'public'
info[:table].should == 'atest'
info[:constraint].should == 'f'
info[:column].should be_nil
info[:type].should be_nil

begin
@db[:atest].insert(0, nil)
rescue => e
end
e.should_not be_nil
info = @db.error_info(e.wrapped_exception)
info[:schema].should == 'public'
info[:table].should == 'atest'
info[:constraint].should be_nil
info[:column].should == 't2'
info[:type].should be_nil
end if DB.server_version >= 90300 && DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG && Object.const_defined?(:PG) && ::PG.const_defined?(:Constants) && ::PG::Constants.const_defined?(:PG_DIAG_SCHEMA_NAME)

specify "should support Database#do for executing anonymous code blocks" do
@db.drop_table?(:btest)
@db.do "BEGIN EXECUTE 'CREATE TABLE btest (a INTEGER)'; EXECUTE 'INSERT INTO btest VALUES (1)'; END"
Expand Down

0 comments on commit ac3fcaf

Please sign in to comment.