lib/pg_conn.rb in pg_conn-0.6.1 vs lib/pg_conn.rb in pg_conn-0.7.0

- old
+ new

@@ -47,12 +47,11 @@ # Name of database def name() @pg_connection.db end alias_method :database, :name # Obsolete - # Database manipulation methods: #exist?, #create, #drop, #list. It is - # named 'rdbms' because #database is already defined + # Database manipulation methods: #exist?, #create, #drop, #list attr_reader :rdbms # Role manipulation methods: #exist?, #create, #drop, #list attr_reader :role @@ -62,10 +61,21 @@ # The transaction timestamp of the most recent SQL statement executed by # #exec or #transaction block attr_reader :timestamp + # PG::Error object if the last statement failed; otherwise nil + attr_reader :err + + # Last error message. The error message is the first line of the PG error + # message that may contain additional info. It doesn't contain a + # terminating newline + def errmsg = err && err.message.sub(/\n.*/m, "") + + # The line number of the last PG::Error. It is not always present + def errline() err && err.message =~ /\n\s*LINE\s+(\d+):/m and $1.to_i end + # :call-seq: # initialize(dbname = nil, user = nil, field_name_class: Symbol) # initialize(connection_hash, field_name_class: Symbol) # initialize(connection_string, field_name_class: Symbol) # initialize(host, port, dbname, user, password, field_name_class: Symbol) @@ -77,24 +87,24 @@ # The possible keys of the connection hash are :host, :port, :dbname, :user, # and :password. The connection string can either be a space-separated list # of <key>=<value> pairs with the same keys as the hash, or a URI with the # format 'postgres[ql]://[user[:password]@][host][:port][/name] # - # The :field_name_class option controls the Ruby type of column names. It can be - # Symbol (the default) or String. The :timestamp option is used - # internally to set the timestamp for transactions - # # If given an array argument, PgConn will not connect to the database and # instead write its commands to the array. In this case, methods extracting # values from the database (eg. #value) will return nil or raise an # exception # # The last variant is used to establish a PgConn from an existing # connection. It doesn't change the connection settings and is not # recommended except in cases where you want to piggyback on an existing # connection (eg. a Rails connection) # + # The :field_name_class option controls the Ruby type of column names. It can be + # Symbol (the default) or String. The :timestamp option is used + # internally to set the timestamp for transactions + # # Note that the connection hash and the connection string may support more # parameters than documented here. Consult # https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING # for the full list # @@ -476,13 +486,14 @@ end end # Execute SQL statement(s) in a transaction and return the number of # affected records (if any). Also sets #timestamp unless a transaction is - # already in progress. The +sql+ argument can be a String or an arbitrarily - # nested array of strings. The empty array is a NOP but the empty string is - # not. + # already in progress. The +sql+ argument can be a command (String) or an + # arbitrarily nested array of commands. Note that you can't have commands + # that span multiple lines. The empty array is a NOP but the empty string + # is not. # # #exec pass Postgres exceptions to the caller unless :fail is false. If # fail is false #exec instead return nil but note that postgres doesn't # ignore it so that if you're inside a transaction, the transaction will be # in an error state and if you're also using subtransactions the whole @@ -493,14 +504,14 @@ transaction(commit: commit) { execute(sql, fail: fail, silent: silent) } end # Execute SQL statement(s) without a transaction block and return the # number of affected records (if any). This used to call procedures that - # may manipulate transactions. The +sql+ argument can be a String or - # an arbitrarily nested array of strings. The empty array is a NOP but the - # empty string is not. #exec pass Postgres exceptions to the caller unless - # :fail is false in which case it returns nil + # may manipulate transactions. The +sql+ argument can be a SQL command or + # an arbitrarily nested array of commands. The empty array is a NOP but the + # empty string is not. #execute pass Postgres exceptions to the caller + # unless :fail is false in which case it returns nil # # TODO: Handle postgres exceptions wrt transaction state and stack def execute(sql, fail: true, silent: false) if @pg_connection pg_exec(sql, fail: fail, silent: silent)&.cmd_tuples @@ -587,11 +598,11 @@ result = nil begin push_transaction result = yield rescue PgConn::Rollback - pop_trancaction(commit: false) + pop_transaction(commit: false) return nil # FIXME: Rescue other postgres errors and wipe-out stack end pop_transaction(commit: commit) result @@ -624,29 +635,31 @@ end else PG::Connection.new *args, **opts end end - + # :call-seq: # pg_exec(string) # pg_exec(array) # - # +arg+ can be a statement or an array of statements. The statements are - # concatenated before being sent to the server. It returns a PG::Result - # object or nil if +arg+ was empty. #exec pass Postgres exceptions to the - # caller unless :fail is false + # Execute statement(s) on the server. If the argument is an array of + # commands, the commands are concatenated with ';' before being sent to the + # server. #pg_exec returns a PG::Result object or nil if +arg+ was empty. + # #exec pass Postgres exceptions to the caller unless :fail is false # # FIXME: Error message prints the last statement but what if another # statement failed? # - # TODO WILD: Parse sql and split it into statements that are executed - # one-by-one so we're able to pinpoint errors in the source + # TODO: Connsider executing statements one-by-one so we're able to + # pin-point Postgres errors without a line number. This may be expensive, + # though # # TODO: Fix silent by not handling exceptions def pg_exec(arg, fail: true, silent: false) if @pg_connection + @err = nil begin last_stmt = nil # To make the current SQL statement visible to the rescue clause. FIXME Not used? if arg.is_a?(String) return nil if arg == "" last_stmt = arg @@ -657,10 +670,11 @@ last_stmt = stmts.last @pg_connection.exec(stmts.join(";\n")) end rescue PG::Error => ex + @err = ex if fail if !silent # FIXME Why do we handle this? $stderr.puts arg $stderr.puts ex.message $stderr.flush @@ -668,9 +682,10 @@ raise else return nil end end + else # @pg_commands is defined if arg.is_a?(String) @pg_commands << arg if arg != "" else @pg_commands.concat(arg)