Commits

Lars Kanis  committed 5cf348b

Add single row mode of PostgreSQL 9.2

  • Participants
  • Parent commits e4900f6
  • Branches single_row_mode

Comments (0)

Files changed (4)

File ext/extconf.rb

 have_func 'PQsetClientEncoding'
 have_func 'PQlibVersion'
 have_func 'PQping'
+have_func 'PQsetSingleRowMode'
 
 have_func 'rb_encdb_alias'
 have_func 'rb_enc_alias'
 
 /*
  * Get the index of encoding +val+.
- * :FIXME: Look into replacing this with rb_enc_get_index() since 1.9.1 isn't really 
+ * :FIXME: Look into replacing this with rb_enc_get_index() since 1.9.1 isn't really
  * used anymore.
  */
 int
  * - returns ASCII-8BIT if the client encoding is unknown.
  */
 rb_encoding *
-pg_get_pg_encoding_as_rb_encoding( int enc_id ) 
+pg_get_pg_encoding_as_rb_encoding( int enc_id )
 {
 	rb_encoding *enc;
 
 	rb_define_const(rb_mPGconstants, "PGRES_EMPTY_QUERY", INT2FIX(PGRES_EMPTY_QUERY));
 	/* #result_status constant: Successful completion of a command returning no data. */
 	rb_define_const(rb_mPGconstants, "PGRES_COMMAND_OK", INT2FIX(PGRES_COMMAND_OK));
-		/* #result_status constant: Successful completion of a command returning data 
+		/* #result_status constant: Successful completion of a command returning data
 	   (such as a SELECT or SHOW). */
 	rb_define_const(rb_mPGconstants, "PGRES_TUPLES_OK", INT2FIX(PGRES_TUPLES_OK));
 	/* #result_status constant: Copy Out (from server) data transfer started. */
 #ifdef HAVE_CONST_PGRES_COPY_BOTH
 	rb_define_const(rb_mPGconstants, "PGRES_COPY_BOTH", INT2FIX(PGRES_COPY_BOTH));
 #endif
+	/* #result_status constant: Single tuple from larger resultset. */
+#ifdef HAVE_PQSETSINGLEROWMODE
+	rb_define_const(rb_mPGconstants, "PGRES_SINGLE_TUPLE", INT2FIX(PGRES_SINGLE_TUPLE));
+#endif
 
 	/******     Result CONSTANTS: result error field codes      ******/
 
 	/* Add the constants to the toplevel namespace */
 	rb_include_module( rb_mPG, rb_mPGconstants );
 
-#ifdef M17N_SUPPORTED	
+#ifdef M17N_SUPPORTED
 	enc_pg2ruby = st_init_numtable();
 	s_id_index = rb_intern("@encoding");
 #endif

File ext/pg_connection.c

 
 
 /********************************************************************
- * 
+ *
  * Document-class: PG::Connection
  *
- * The class to access PostgreSQL RDBMS, based on the libpq interface, 
+ * The class to access PostgreSQL RDBMS, based on the libpq interface,
  * provides convenient OO methods to interact with PostgreSQL.
  *
  * For example, to send query to the database on the localhost:
 
 /*
  * Document-method: allocate
- * 
+ *
  * call-seq:
  *   PG::Connection.allocate -> conn
  */
  *    PG::Connection.new(connection_hash) -> conn
  *    PG::Connection.new(connection_string) -> conn
  *    PG::Connection.new(host, port, options, tty, dbname, user, password) ->  conn
- * 
+ *
  * Create a connection to the specified server.
- * 
+ *
  * [+host+]
  *   server hostname
  * [+hostaddr+]
  *   GSS library to use for GSSAPI authentication
  * [+service+]
  *   service name to use for additional parameters
- * 
+ *
  * Examples:
- * 
+ *
  *   # Connect using all defaults
  *   PG::Connection.new
  *
  *   # As a Hash
  *   PG::Connection.new( :dbname => 'test', :port => 5432 )
- *   
+ *
  *   # As a String
  *   PG::Connection.new( "dbname=test port=5432" )
- *   
+ *
  *   # As an Array
  *   PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
- *  
+ *
  * If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
  * connection will have its +client_encoding+ set accordingly.
- * 
+ *
  * Raises a PG::Error if the connection fails.
  */
 static VALUE
  *
  * Use #connect_poll to poll the status of the connection.
  *
- * NOTE: this does *not* set the connection's +client_encoding+ for you if 
- * Encoding.default_internal is set. To set it after the connection is established, 
- * call #internal_encoding=. You can also set it automatically by setting 
+ * NOTE: this does *not* set the connection's +client_encoding+ for you if
+ * Encoding.default_internal is set. To set it after the connection is established,
+ * call #internal_encoding=. You can also set it automatically by setting
  * ENV['PGCLIENTENCODING'], or include the 'options' connection parameter.
- * 
+ *
  */
 static VALUE
 pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
  *
  * This function is intended to be used by client applications that
  * send commands like: +ALTER USER joe PASSWORD 'pwd'+.
- * The arguments are the cleartext password, and the SQL name 
+ * The arguments are the cleartext password, and the SQL name
  * of the user it is for.
  *
  * Return value is the encrypted password.
  * call-seq:
  *    conn.reset()
  *
- * Resets the backend connection. This method closes the 
+ * Resets the backend connection. This method closes the
  * backend connection and tries to re-connect.
  */
 static VALUE
  * Initiate a connection reset in a nonblocking manner.
  * This will close the current connection and attempt to
  * reconnect using the same connection parameters.
- * Use #reset_poll to check the status of the 
+ * Use #reset_poll to check the status of the
  * connection reset.
  */
 static VALUE
  * _param_name_ is one of
  * * +server_version+
  * * +server_encoding+
- * * +client_encoding+ 
+ * * +client_encoding+
  * * +is_superuser+
  * * +session_authorization+
  * * +DateStyle+
  * * +TimeZone+
  * * +integer_datetimes+
  * * +standard_conforming_strings+
- * 
+ *
  * Returns nil if the value of the parameter is not known.
  */
 static VALUE
  * call-seq:
  *   conn.protocol_version -> Integer
  *
- * The 3.0 protocol will normally be used when communicating with PostgreSQL 7.4 
- * or later servers; pre-7.4 servers support only protocol 2.0. (Protocol 1.0 is 
+ * The 3.0 protocol will normally be used when communicating with PostgreSQL 7.4
+ * or later servers; pre-7.4 servers support only protocol 2.0. (Protocol 1.0 is
  * obsolete and not supported by libpq.)
  */
 static VALUE
 	return INT2NUM(PQprotocolVersion(pg_get_pgconn(self)));
 }
 
-/* 
- * call-seq: 
+/*
+ * call-seq:
  *   conn.server_version -> Integer
- * 
+ *
  * The number is formed by converting the major, minor, and revision
  * numbers into two-decimal-digit numbers and appending them together.
  * For example, version 7.4.2 will be returned as 70402, and version
  * 8.1 will be returned as 80100 (leading zeroes are not shown). Zero
  * is returned if the connection is bad.
- * 
+ *
  */
 static VALUE
 pgconn_server_version(VALUE self)
  *     }
  *   or, it may be a String. If it is a string, that is equivalent to the hash:
  *     { :value => <string value>, :type => 0, :format => 0 }
- * 
+ *
  * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
  * inside the SQL query. The 0th element of the +params+ array is bound
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
- * 
+ *
  * If the types are not specified, they will be inferred by PostgreSQL.
  * Instead of specifying type oids, it's recommended to simply add
  * explicit casts in the query to ensure that the right type is used.
  * The optional +result_format+ should be 0 for text results, 1
  * for binary.
  *
- * If the optional code block is given, it will be passed <i>result</i> as an argument, 
- * and the PG::Result object will  automatically be cleared when the block terminates. 
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
+ * and the PG::Result object will  automatically be cleared when the block terminates.
  * In this instance, <code>conn.exec</code> returns the value of the block.
  */
 static VALUE
 	sym_value = ID2SYM(rb_intern("value"));
 	sym_format = ID2SYM(rb_intern("format"));
 	nParams = (int)RARRAY_LEN(params);
-	paramTypes = ALLOC_N(Oid, nParams); 
+	paramTypes = ALLOC_N(Oid, nParams);
 	paramValues = ALLOC_N(char *, nParams);
 	paramLengths = ALLOC_N(int, nParams);
 	paramFormats = ALLOC_N(int, nParams);
 			paramFormats[i] = NUM2INT(param_format);
 	}
 
-	result = PQexecParams(conn, StringValuePtr(command), nParams, paramTypes, 
+	result = PQexecParams(conn, StringValuePtr(command), nParams, paramTypes,
 		(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
 
 	rb_gc_unregister_address(&gc_array);
 	rb_pgresult = pg_new_result(result, self);
 	pg_result_check(rb_pgresult);
 	if (rb_block_given_p()) {
-		return rb_ensure(rb_yield, rb_pgresult, 
+		return rb_ensure(rb_yield, rb_pgresult,
 			pg_result_clear, rb_pgresult);
 	}
 	return rb_pgresult;
  * Returns a PG::Result instance on success.
  * On failure, it raises a PG::Error.
  *
- * +param_types+ is an optional parameter to specify the Oids of the 
+ * +param_types+ is an optional parameter to specify the Oids of the
  * types of the parameters.
  *
  * If the types are not specified, they will be inferred by PostgreSQL.
  * explicit casts in the query to ensure that the right type is used.
  *
  * For example: "SELECT $1::int"
- * 
+ *
  * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
  * inside the SQL query.
  */
 	if(! NIL_P(in_paramtypes)) {
 		Check_Type(in_paramtypes, T_ARRAY);
 		nParams = (int)RARRAY_LEN(in_paramtypes);
-		paramTypes = ALLOC_N(Oid, nParams); 
+		paramTypes = ALLOC_N(Oid, nParams);
 		for(i = 0; i < nParams; i++) {
 			param = rb_ary_entry(in_paramtypes, i);
 			Check_Type(param, T_FIXNUM);
  * Returns a PG::Result instance on success.
  * On failure, it raises a PG::Error.
  *
- * +params+ is an array of the optional bind parameters for the 
+ * +params+ is an array of the optional bind parameters for the
  * SQL query. Each element of the +params+ array may be either:
  *   a hash of the form:
  *     {:value  => String (value of bind parameter)
  *     }
  *   or, it may be a String. If it is a string, that is equivalent to the hash:
  *     { :value => <string value>, :format => 0 }
- * 
+ *
  * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
  * inside the SQL query. The 0th element of the +params+ array is bound
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
  * The optional +result_format+ should be 0 for text results, 1
  * for binary.
  *
- * If the optional code block is given, it will be passed <i>result</i> as an argument, 
- * and the PG::Result object will  automatically be cleared when the block terminates. 
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
+ * and the PG::Result object will  automatically be cleared when the block terminates.
  * In this instance, <code>conn.exec_prepared</code> returns the value of the block.
  */
 static VALUE
 			paramFormats[i] = NUM2INT(param_format);
 	}
 
-	result = PQexecPrepared(conn, StringValuePtr(name), nParams, 
-		(const char * const *)paramValues, paramLengths, paramFormats, 
+	result = PQexecPrepared(conn, StringValuePtr(name), nParams,
+		(const char * const *)paramValues, paramLengths, paramFormats,
 		resultFormat);
 
 	rb_gc_unregister_address(&gc_array);
 	rb_pgresult = pg_new_result(result, self);
 	pg_result_check(rb_pgresult);
 	if (rb_block_given_p()) {
-		return rb_ensure(rb_yield, rb_pgresult, 
+		return rb_ensure(rb_yield, rb_pgresult,
 			pg_result_clear, rb_pgresult);
 	}
 	return rb_pgresult;
  * Connection instance method for versions of 8.1 and higher of libpq
  * uses PQescapeStringConn, which is safer. Avoid calling as a class method,
  * the class method uses the deprecated PQescapeString() API function.
- * 
+ *
  * Returns a SQL-safe version of the String _str_.
- * This is the preferred way to make strings safe for inclusion in 
+ * This is the preferred way to make strings safe for inclusion in
  * SQL queries.
- * 
- * Consider using exec_params, which avoids the need for passing values 
+ *
+ * Consider using exec_params, which avoids the need for passing values
  * inside of SQL commands.
  *
  * Encoding of escaped string will be equal to client encoding of connection.
 	size_t size;
 	int error;
 	VALUE result;
-#ifdef M17N_SUPPORTED	
+#ifdef M17N_SUPPORTED
 	rb_encoding* enc;
 #endif
 
 
 	escaped = ALLOC_N(char, RSTRING_LEN(string) * 2 + 1);
 	if(rb_obj_class(self) == rb_cPGconn) {
-		size = PQescapeStringConn(pg_get_pgconn(self), escaped, 
+		size = PQescapeStringConn(pg_get_pgconn(self), escaped,
 			RSTRING_PTR(string), RSTRING_LEN(string), &error);
 		if(error) {
 			xfree(escaped);
 
 /*
  * call-seq:
- *   conn.escape_bytea( string ) -> String 
+ *   conn.escape_bytea( string ) -> String
  *
  * Connection instance method for versions of 8.1 and higher of libpq
  * uses PQescapeByteaConn, which is safer. Avoid calling as a class method,
  * class method.
  *
  * Escapes binary data for use within an SQL command with the type +bytea+.
- * 
+ *
  * Certain byte values must be escaped (but all byte values may be escaped)
  * when used as part of a +bytea+ literal in an SQL statement. In general, to
  * escape a byte, it is converted into the three digit octal number equal to
  * the octet value, and preceded by two backslashes. The single quote (') and
  * backslash (\) characters have special alternative escape sequences.
- * #escape_bytea performs this operation, escaping only the minimally required 
+ * #escape_bytea performs this operation, escaping only the minimally required
  * bytes.
- * 
- * Consider using exec_params, which avoids the need for passing values inside of 
+ *
+ * Consider using exec_params, which avoids the need for passing values inside of
  * SQL commands.
  */
 static VALUE
 }
 #endif
 
+#ifdef HAVE_PQSETSINGLEROWMODE
+/*
+ * call-seq:
+ *    conn.set_single_row_mode -> self
+ *
+ * To enter single-row mode, call this method immediately after a successful
+ * call of send_query (or a sibling function). This mode selection is effective
+ * only for the currently executing query.
+ */
+static VALUE
+pgconn_set_single_row_mode(VALUE self)
+{
+	PGconn *conn = pg_get_pgconn(self);
+	VALUE error;
+
+	if( PQsetSingleRowMode(conn) == 0 )
+	{
+		error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
+		rb_iv_set(error, "@connection", self);
+		rb_exc_raise(error);
+	}
+
+	return self;
+}
+#endif
+
 /*
  * call-seq:
  *    conn.send_query(sql [, params, result_format ] ) -> nil
  *     }
  *   or, it may be a String. If it is a string, that is equivalent to the hash:
  *     { :value => <string value>, :type => 0, :format => 0 }
- * 
+ *
  * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
  * inside the SQL query. The 0th element of the +params+ array is bound
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
- * 
+ *
  * If the types are not specified, they will be inferred by PostgreSQL.
  * Instead of specifying type oids, it's recommended to simply add
  * explicit casts in the query to ensure that the right type is used.
 	sym_value = ID2SYM(rb_intern("value"));
 	sym_format = ID2SYM(rb_intern("format"));
 	nParams = (int)RARRAY_LEN(params);
-	paramTypes = ALLOC_N(Oid, nParams); 
+	paramTypes = ALLOC_N(Oid, nParams);
 	paramValues = ALLOC_N(char *, nParams);
 	paramLengths = ALLOC_N(int, nParams);
 	paramFormats = ALLOC_N(int, nParams);
 			paramFormats[i] = NUM2INT(param_format);
 	}
 
-	result = PQsendQueryParams(conn, StringValuePtr(command), nParams, paramTypes, 
+	result = PQsendQueryParams(conn, StringValuePtr(command), nParams, paramTypes,
 		(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
 
-	rb_gc_unregister_address(&gc_array);	
+	rb_gc_unregister_address(&gc_array);
 
 	xfree(paramTypes);
 	xfree(paramValues);
  * Sends prepare command asynchronously, and returns immediately.
  * On failure, it raises a PG::Error.
  *
- * +param_types+ is an optional parameter to specify the Oids of the 
+ * +param_types+ is an optional parameter to specify the Oids of the
  * types of the parameters.
  *
  * If the types are not specified, they will be inferred by PostgreSQL.
  * explicit casts in the query to ensure that the right type is used.
  *
  * For example: "SELECT $1::int"
- * 
+ *
  * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
  * inside the SQL query.
  */
 	if(! NIL_P(in_paramtypes)) {
 		Check_Type(in_paramtypes, T_ARRAY);
 		nParams = (int)RARRAY_LEN(in_paramtypes);
-		paramTypes = ALLOC_N(Oid, nParams); 
+		paramTypes = ALLOC_N(Oid, nParams);
 		for(i = 0; i < nParams; i++) {
 			param = rb_ary_entry(in_paramtypes, i);
 			Check_Type(param, T_FIXNUM);
  * asynchronously, and returns immediately.
  * On failure, it raises a PG::Error.
  *
- * +params+ is an array of the optional bind parameters for the 
+ * +params+ is an array of the optional bind parameters for the
  * SQL query. Each element of the +params+ array may be either:
  *   a hash of the form:
  *     {:value  => String (value of bind parameter)
  *     }
  *   or, it may be a String. If it is a string, that is equivalent to the hash:
  *     { :value => <string value>, :format => 0 }
- * 
+ *
  * PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
  * inside the SQL query. The 0th element of the +params+ array is bound
  * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
 			paramFormats[i] = NUM2INT(param_format);
 	}
 
-	result = PQsendQueryPrepared(conn, StringValuePtr(name), nParams, 
-		(const char * const *)paramValues, paramLengths, paramFormats, 
+	result = PQsendQueryPrepared(conn, StringValuePtr(name), nParams,
+		(const char * const *)paramValues, paramLengths, paramFormats,
 		resultFormat);
 
 	rb_gc_unregister_address(&gc_array);
  * call-seq:
  *    conn.send_describe_prepared( statement_name ) -> nil
  *
- * Asynchronously send _command_ to the server. Does not block. 
+ * Asynchronously send _command_ to the server. Does not block.
  * Use in combination with +conn.get_result+.
  */
 static VALUE
  * call-seq:
  *    conn.send_describe_portal( portal_name ) -> nil
  *
- * Asynchronously send _command_ to the server. Does not block. 
+ * Asynchronously send _command_ to the server. Does not block.
  * Use in combination with +conn.get_result+.
  */
 static VALUE
  * Note: call this function repeatedly until it returns +nil+, or else
  * you will not be able to issue further commands.
  *
- * If the optional code block is given, it will be passed <i>result</i> as an argument, 
- * and the PG::Result object will  automatically be cleared when the block terminates. 
+ * If the optional code block is given, it will be passed <i>result</i> as an argument,
+ * and the PG::Result object will  automatically be cleared when the block terminates.
  * In this instance, <code>conn.exec</code> returns the value of the block.
  */
 static VALUE
  * call-seq:
  *    conn.setnonblocking(Boolean) -> nil
  *
- * Sets the nonblocking status of the connection. 
+ * Sets the nonblocking status of the connection.
  * In the blocking state, calls to #send_query
  * will block until the message is sent to the server,
  * but will not wait for the query results.
  * will return an error if the socket is not ready for
  * writing.
  * Note: This function does not affect #exec, because
- * that function doesn't return until the server has 
+ * that function doesn't return until the server has
  * processed the query and returned the results.
  * Returns +nil+.
  */
 
 
 #ifdef _WIN32
-/* 
+/*
  * Duplicate the sockets from libpq and create temporary CRT FDs
  */
 void create_crt_fd(fd_set *os_set, fd_set *crt_set)
  * Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
  * event otherwise.  If used in block form, passes the name of the
  * NOTIFY +event+ and the generating +pid+ into the block.
- * 
+ *
  * Under PostgreSQL 9.0 and later, if the notification is sent with
  * the optional +payload+ string, it will be given to the block as the
  * third argument.
- * 
+ *
  */
 static VALUE
 pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
  * Returns true if the end-of-data was sent, false if it was
  * not sent (false is only possible if the connection
  * is in nonblocking mode, and this command would block).
- */ 
+ */
 static VALUE
 pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
 {
  *    conn.get_copy_data( [ async = false ] ) -> String
  *
  * Return a string containing one row of data, +nil+
- * if the copy is done, or +false+ if the call would 
+ * if the copy is done, or +false+ if the call would
  * block (only possible if _async_ is true).
  *
  */
 /*
  * call-seq:
  *    conn.trace( stream ) -> nil
- * 
- * Enables tracing message passing between backend. The 
+ *
+ * Enables tracing message passing between backend. The
  * trace message will be written to the stream _stream_,
  * which must implement a method +fileno+ that returns
  * a writable file descriptor.
 /*
  * call-seq:
  *    conn.untrace() -> nil
- * 
+ *
  * Disables the message tracing.
  */
 static VALUE
 	VALUE self = (VALUE)arg;
 
 	if ((proc = rb_iv_get(self, "@notice_receiver")) != Qnil) {
-		rb_funcall(proc, rb_intern("call"), 1, 
+		rb_funcall(proc, rb_intern("call"), 1,
 			Data_Wrap_Struct(rb_cPGresult, NULL, NULL, (PGresult*)result));
 	}
 	return;
  * application can override this behavior by supplying its own handling
  * function.
  *
- * For historical reasons, there are two levels of notice handling, called the 
- * notice receiver and notice processor. The default behavior is for the notice 
- * receiver to format the notice and pass a string to the notice processor for 
- * printing. However, an application that chooses to provide its own notice 
- * receiver will typically ignore the notice processor layer and just do all 
+ * For historical reasons, there are two levels of notice handling, called the
+ * notice receiver and notice processor. The default behavior is for the notice
+ * receiver to format the notice and pass a string to the notice processor for
+ * printing. However, an application that chooses to provide its own notice
+ * receiver will typically ignore the notice processor layer and just do all
  * the work in the notice receiver.
  *
  * This function takes a new block to act as the handler, which should
- * accept a single parameter that will be a PG::Result object, and returns 
+ * accept a single parameter that will be a PG::Result object, and returns
  * the Proc object previously set, or +nil+ if it was previously the default.
  *
  * If you pass no arguments, it will reset the handler to the default.
 	VALUE proc, old_proc;
 	PGconn *conn = pg_get_pgconn(self);
 
-	/* If default_notice_receiver is unset, assume that the current 
-	 * notice receiver is the default, and save it to a global variable. 
+	/* If default_notice_receiver is unset, assume that the current
+	 * notice receiver is the default, and save it to a global variable.
 	 * This should not be a problem because the default receiver is
 	 * always the same, so won't vary among connections.
 	 */
  * See #set_notice_receiver for the desription of what this and the
  * notice_processor methods do.
  *
- * This function takes a new block to act as the notice processor and returns 
+ * This function takes a new block to act as the notice processor and returns
  * the Proc object previously set, or +nil+ if it was previously the default.
  * The block should accept a single PG::Result object.
  *
 	VALUE proc, old_proc;
 	PGconn *conn = pg_get_pgconn(self);
 
-	/* If default_notice_processor is unset, assume that the current 
-	 * notice processor is the default, and save it to a global variable. 
+	/* If default_notice_processor is unset, assume that the current
+	 * notice processor is the default, and save it to a global variable.
 	 * This should not be a problem because the default processor is
 	 * always the same, so won't vary among connections.
 	 */
 /*
  * call-seq:
  *    conn.get_client_encoding() -> String
- * 
+ *
  * Returns the client encoding as a String.
  */
 static VALUE
 /*
  * call-seq:
  *    conn.set_client_encoding( encoding )
- * 
+ *
  * Sets the client encoding to the _encoding_ String.
  */
 static VALUE
  *    conn.transaction { |conn| ... } -> nil
  *
  * Executes a +BEGIN+ at the start of the block,
- * and a +COMMIT+ at the end of the block, or 
+ * and a +COMMIT+ at the end of the block, or
  * +ROLLBACK+ if any exception occurs.
  */
 static VALUE
  * Returns a string that is safe for inclusion in a SQL query as an
  * identifier. Note: this is not a quote function for values, but for
  * identifiers.
- * 
+ *
  * For example, in a typical SQL query: <tt>SELECT FOO FROM MYTABLE</tt>
  * The identifier <tt>FOO</tt> is folded to lower case, so it actually
  * means <tt>foo</tt>. If you really want to access the case-sensitive
  * <tt>PG::Connection.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
  * (with double-quotes). PostgreSQL will see the double-quotes, and
  * it will not fold to lower case.
- * 
+ *
  * Similarly, this function also protects against special characters,
  * and other things that might allow SQL injection if the identifier
  * comes from an untrusted source.
 	UNUSED( self );
 
 	if(strlen(str) >= NAMEDATALEN) {
-		rb_raise(rb_eArgError, 
+		rb_raise(rb_eArgError,
 			"Input string is longer than NAMEDATALEN-1 (%d)",
 			NAMEDATALEN-1);
 	}
 	buffer[j++] = '"';
 	for(i = 0; i < strlen(str) && str[i]; i++) {
-		if(str[i] == '"') 
+		if(str[i] == '"')
 			buffer[j++] = '"';
 		buffer[j++] = str[i];
 	}
  * call-seq:
  *    conn.block( [ timeout ] ) -> Boolean
  *
- * Blocks until the server is no longer busy, or until the 
+ * Blocks until the server is no longer busy, or until the
  * optional _timeout_ is reached, whichever comes first.
  * _timeout_ is measured in seconds and can be fractional.
- * 
+ *
  * Returns +false+ if _timeout_ is reached, +true+ otherwise.
- * 
+ *
  * If +true+ is returned, +conn.is_busy+ will return +false+
  * and +conn.get_result+ will not block.
  */
 	int sd = PQsocket( conn );
 	int ret;
 
-	/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs 
+	/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
 	 * and does not wait (nor sleep) any time even if timeout is given.
 	 * Instead use the Winsock events and rb_w32_wait_events(). */
 
 #else /* _WIN32 */
 
 /*
- * Win32 PG::Connection#block -- on Windows, use platform-specific strategies to wait for the socket 
+ * Win32 PG::Connection#block -- on Windows, use platform-specific strategies to wait for the socket
  * instead of rb_thread_select().
  */
 
 
 int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
 
-/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs 
+/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
  * and does not wait (nor sleep) any time even if timeout is given.
  * Instead use the Winsock events and rb_w32_wait_events(). */
 
  *    conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
  *
  * This function has the same behavior as #exec,
- * except that it's implemented using asynchronous command 
- * processing and ruby's +rb_thread_select+ in order to 
+ * except that it's implemented using asynchronous command
+ * processing and ruby's +rb_thread_select+ in order to
  * allow other threads to process while waiting for the
  * server to complete the request.
  */
  * call-seq:
  *    conn.lo_open( oid, [mode] ) -> Fixnum
  *
- * Open a large object of _oid_. Returns a large object descriptor 
+ * Open a large object of _oid_. Returns a large object descriptor
  * instance on success. The _mode_ argument specifies the mode for
  * the opened large object,which is either +INV_READ+, or +INV_WRITE+.
  *
 	if( RSTRING_LEN(buffer) < 0) {
 		rb_raise(rb_ePGerror, "write buffer zero string");
 	}
-	if((n = lo_write(conn, fd, StringValuePtr(buffer), 
+	if((n = lo_write(conn, fd, StringValuePtr(buffer),
 				RSTRING_LEN(buffer))) < 0) {
 		rb_raise(rb_ePGerror, "lo_write failed: %s", PQerrorMessage(conn));
 	}
 {
 	rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
 	rb_include_module(rb_cPGconn, rb_mPGconstants);
-	
+
 	/******     PG::Connection CLASS METHODS     ******/
 	rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
 
 #endif
 	rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
 	rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
+#ifdef HAVE_PQSETSINGLEROWMODE
+	rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
+#endif
 
 	/******     PG::Connection INSTANCE METHODS: Asynchronous Command Processing     ******/
 	rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);

File spec/pg/connection_spec.rb

 	#
 
 	it "can create a connection option string from a Hash of options" do
-		optstring = described_class.parse_connect_args( 
+		optstring = described_class.parse_connect_args(
 			:host => 'pgsql.example.com',
 			:dbname => 'db01',
 			'sslmode' => 'require'
 	end
 
 	it "can create a connection option string from positional parameters" do
-		optstring = described_class.parse_connect_args( 'pgsql.example.com', nil, '-c geqo=off', nil, 
+		optstring = described_class.parse_connect_args( 'pgsql.example.com', nil, '-c geqo=off', nil,
 		                                       'sales' )
 
 		optstring.should be_a( String )
 
 	end
 
+	context "under PostgreSQL 9.2 client library", :postgresql_92 do
+		describe "set_single_row_mode" do
+
+			it "raises an error when called at the wrong time" do
+				expect {
+					@conn.set_single_row_mode
+				}.to raise_error(PG::Error)
+			end
+
+			it "should work in single row mode" do
+				@conn.send_query( "SELECT generate_series(1,10)" )
+				@conn.set_single_row_mode
+
+				results = []
+				loop do
+					@conn.block
+					res = @conn.get_result or break
+					results << res
+				end
+				results.length.should == 11
+				results[0..-2].each do |res|
+					res.result_status.should == PG::PGRES_SINGLE_TUPLE
+					values = res.field_values('generate_series')
+					values.length.should == 1
+					values.first.to_i.should > 0
+				end
+				results.last.result_status.should == PG::PGRES_TUPLES_OK
+				results.last.ntuples.should == 0
+			end
+
+			it "should receive rows before entire query is finished" do
+				# The full query needs at minimum 1 second to complete
+				@conn.send_query( "SELECT generate_series(0,999), NULL UNION ALL SELECT generate_series(1000,1999), pg_sleep(0.001);" )
+				@conn.set_single_row_mode
+
+				start_time = Time.now
+				first_row_time = nil
+				loop do
+					@conn.block
+					@conn.get_result or break
+					first_row_time = Time.now unless first_row_time
+				end
+				(first_row_time - start_time).should < 1.0
+			end
+		end
+	end
+
 	context "multinationalization support", :ruby_19 do
 
 		it "should return the same bytes in text format that are sent as inline text" do