Repository: rails/rails
File: activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb (Ruby)

Code before:
            raise ArgumentError, "deferred must be :deferred or :immediate"
          end

          constraints = if constraints.empty?
            "ALL"
          else
            constraints.map { |c| quote_table_name(c) }.join(", ")
          end
          execute("SET CONSTRAINTS #{constraints} #{deferred.to_s.upcase}")
        end

        private
          IDLE_TRANSACTION_STATUSES = [PG::PQTRANS_IDLE, PG::PQTRANS_INTRANS, PG::PQTRANS_INERROR]
          private_constant :IDLE_TRANSACTION_STATUSES

          def cancel_any_running_query
            return if @raw_connection.nil? || IDLE_TRANSACTION_STATUSES.include?(@raw_connection.transaction_status)

            if PG.library_version >= 18_00_00 && Gem::Version.new(PG::VERSION) < Gem::Version.new("1.6.0")
              raise NotImplementedError, "PG::Connection#cancel is not supported with the combination of pg gem #{PG::VERSION} and PostgreSQL libpq #{PG.library_version / 10000}. Please upgrade pg gem to 1.6.0 or later."
            end

            @raw_connection.cancel
            @raw_connection.block
          rescue PG::Error
          end

          def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
            update_typemap_for_default_timezone
            result = if prepare
              begin
                stmt_key = prepare_statement(sql, binds, raw_connection)
                notification_payload[:statement_name] = stmt_key
                raw_connection.exec_prepared(stmt_key, type_casted_binds)
              rescue PG::FeatureNotSupported => error
                if is_cached_plan_failure?(error)
                  # Nothing we can do if we are in a transaction because all commands
                  # will raise InFailedSQLTransaction
                  if in_transaction?
                    raise PreparedStatementCacheExpired.new(error.message, connection_pool: @pool)
                  else
                    @lock.synchronize do
                      # outside of transactions we can simply flush this query and retry
                      @statements.delete sql_key(sql)
                    end
                    retry
                  end
                end

                raise
              end

Review comment (suggestion):
Instead of raising, let's just not call `cancel` in this combination of versions. Make sure the reason for this conditional is documented in a comment.

Code after:
            raise ArgumentError, "deferred must be :deferred or :immediate"
          end

          constraints = if constraints.empty?
            "ALL"
          else
            constraints.map { |c| quote_table_name(c) }.join(", ")
          end
          execute("SET CONSTRAINTS #{constraints} #{deferred.to_s.upcase}")
        end

        private
          IDLE_TRANSACTION_STATUSES = [PG::PQTRANS_IDLE, PG::PQTRANS_INTRANS, PG::PQTRANS_INERROR]
          private_constant :IDLE_TRANSACTION_STATUSES

          def cancel_any_running_query
            return if @raw_connection.nil? || IDLE_TRANSACTION_STATUSES.include?(@raw_connection.transaction_status)

            # Skip @raw_connection.cancel (PG::Connection#cancel) when using libpq >= 18 with pg < 1.6.0,
            # because the pg gem cannot obtain the backend_key in that case.
            # This method is only called from exec_rollback_db_transaction and exec_restart_db_transaction.
            # Even without cancel, rollback will still run. However, since any running
            # query must finish first, the rollback may take longer.
            if !(PG.library_version >= 18_00_00 && Gem::Version.new(PG::VERSION) < Gem::Version.new("1.6.0"))
              @raw_connection.cancel
            end
            @raw_connection.block
          rescue PG::Error
          end

          def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
            update_typemap_for_default_timezone
            result = if prepare
              begin
                stmt_key = prepare_statement(sql, binds, raw_connection)
                notification_payload[:statement_name] = stmt_key
                raw_connection.exec_prepared(stmt_key, type_casted_binds)
              rescue PG::FeatureNotSupported => error
                if is_cached_plan_failure?(error)
                  # Nothing we can do if we are in a transaction because all commands
                  # will raise InFailedSQLTransaction
                  if in_transaction?
                    raise PreparedStatementCacheExpired.new(error.message, connection_pool: @pool)
                  else
                    @lock.synchronize do
                      # outside of transactions we can simply flush this query and retry
                      @statements.delete sql_key(sql)
                    end
                    retry
                  end
                end