Compare commits

..

23 Commits
stmt ... master

Author SHA1 Message Date
John Bintz b99e0a057a add LD_RUN_PATH when using hard coded mysql paths 2010-12-07 10:24:30 -05:00
Brian Lopez 52f62c8b44 compiler warnings are annoying 2010-11-27 14:56:05 -08:00
Brian Lopez 66f595a406 Merge branch 'em_fiber' of https://github.com/dj2/mysql2 into dj2-em_fiber 2010-11-27 14:46:34 -08:00
dan sinclair 5f6ff0d4a8 forgot to remove debug 2010-11-27 15:32:54 -05:00
Brian Lopez 80697d11b2 we don't need to print the error here as the caller should be handling that on their own the way they want to 2010-11-27 11:10:18 -08:00
dan sinclair dac2f02c9b if no reactor use synch query 2010-11-26 22:42:34 -05:00
dan sinclair 9d49728c30 add em_fiber spec 2010-11-26 22:42:09 -05:00
dj2 c2e2f0c46c add fibered em connection without activerecord 2010-11-26 11:01:20 -05:00
Youhei Kondou 550c68cade Fix to install with MariDB on Windows 2010-11-13 17:47:58 +09:00
Brian Lopez d48846f13b add support for :read_timeout to be set on a connection 2010-11-09 12:27:04 -08:00
Brian Lopez 99766a2303 mysql_num_fields returns an unsigned int 2010-10-31 12:37:53 -07:00
Brian Lopez badc5e04e3 resultFreed flag only needs to be one byte 2010-10-31 12:34:18 -07:00
Brian Lopez 974a5658d6 active and closed flags only need to be one byte 2010-10-31 12:31:54 -07:00
Brian Lopez 60b8d061ac mysql_errno returns an unsigned int 2010-10-31 12:24:27 -07:00
Brian Lopez 2b37ace3dc only set binary ruby encoding on fields that have a binary flag *and* encoding set 2010-10-31 12:11:20 -07:00
Brian Lopez 1057f976d0 ensure the query is a string earlier in the Mysql2::Client#query codepath for 1.9 2010-10-31 10:11:59 -07:00
Brian Lopez 90ddb63e52 use our own index def class for better compatibility across ActiveRecord versions 2010-10-27 15:36:25 -07:00
Brian Lopez 426cff8adc bump to 0.2.6 to push fixed win32 gems 2010-10-19 17:24:55 -07:00
Brian Lopez f79bf6261e Version bump to 0.2.6 2010-10-19 17:23:43 -07:00
Brian Lopez 05df9e312d update files for 0.2.5 release 2010-10-19 16:33:07 -07:00
Brian Lopez 60fd02ebe6 Version bump to 0.2.5 2010-10-19 16:32:42 -07:00
Brian Lopez 7e75f5ed4c make sure we always set wait_timeout even if a bad value was given 2010-10-19 08:21:41 -07:00
Anko painting e7dcf37bd4 fix to CFLAGS to allow compilation on SPARC with sunstudio compiler 2010-10-18 18:33:34 -07:00
22 changed files with 148 additions and 362 deletions

View File

@ -1,5 +1,17 @@
# Changelog
## 0.2.6 (October 19th, 2010)
* version bump since the 0.2.5 win32 binary gems were broken
## 0.2.5 (October 19th, 2010)
* fixes for easier Win32 binary gem deployment for targeting 1.8 and 1.9 in the same gem
* refactor of connection checks and management to avoid race conditions with the GC/threading to prevent the unexpected loss of connections
* update the default flags during connection
* add support for setting wait_timeout on AR adapter
* upgrade to rspec2
* bugfix for an edge case where the GC would clean up a Mysql2::Client object before the underlying MYSQL pointer had been initialized
* fix to CFLAGS to allow compilation on SPARC with sunstudio compiler - Anko painting <anko.com+github@gmail.com>
## 0.2.4 (September 17th, 2010)
* a few patches for win32 support from Luis Lavena - thanks man!
* bugfix from Eric Wong to avoid a potential stack overflow during Mysql2::Client#escape

View File

@ -1 +1 @@
0.2.4
0.2.6

View File

@ -76,7 +76,7 @@ static void rb_mysql_client_mark(void * wrapper) {
static VALUE rb_raise_mysql2_error(MYSQL *client) {
VALUE e = rb_exc_new2(cMysql2Error, mysql_error(client));
rb_funcall(e, intern_error_number_eql, 1, INT2NUM(mysql_errno(client)));
rb_funcall(e, intern_error_number_eql, 1, UINT2NUM(mysql_errno(client)));
rb_funcall(e, intern_sql_state_eql, 1, rb_tainted_str_new2(mysql_sqlstate(client)));
rb_exc_raise(e);
return Qnil;
@ -264,7 +264,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
fd_set fdset;
int fd, retval;
int async = 0;
VALUE opts, defaults;
VALUE opts, defaults, read_timeout;
GET_CLIENT(self);
REQUIRE_OPEN_DB(wrapper);
@ -290,6 +290,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
opts = defaults;
}
Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
// ensure the string is in the encoding the connection is expecting
@ -302,6 +303,23 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
return rb_raise_mysql2_error(wrapper->client);
}
read_timeout = rb_iv_get(self, "@read_timeout");
struct timeval tv;
struct timeval* tvp = NULL;
if (!NIL_P(read_timeout)) {
Check_Type(read_timeout, T_FIXNUM);
tvp = &tv;
long int sec = FIX2INT(read_timeout);
// TODO: support partial seconds?
// also, this check is here for sanity, we also check up in Ruby
if (sec >= 0) {
tvp->tv_sec = sec;
} else {
rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
}
tvp->tv_usec = 0;
}
if (!async) {
// the below code is largely from do_mysql
// http://github.com/datamapper/do
@ -310,7 +328,11 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, NULL);
retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, tvp);
if (retval == 0) {
rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
}
if (retval < 0) {
rb_sys_fail(0);
@ -516,20 +538,6 @@ static VALUE init_connection(VALUE self) {
return self;
}
/* call-seq: client.create_statement # => Mysql2::Statement
*
* Create a new prepared statement.
*/
static VALUE create_statement(VALUE self) {
MYSQL * client;
MYSQL_STMT * stmt;
Data_Get_Struct(self, MYSQL, client);
stmt = mysql_stmt_init(client);
return Data_Wrap_Struct(cMysql2Statement, 0, mysql_stmt_close, stmt);
}
void init_mysql2_client() {
cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
@ -544,7 +552,6 @@ void init_mysql2_client() {
rb_define_method(cMysql2Client, "async_result", rb_mysql_client_async_result, 0);
rb_define_method(cMysql2Client, "last_id", rb_mysql_client_last_id, 0);
rb_define_method(cMysql2Client, "affected_rows", rb_mysql_client_affected_rows, 0);
rb_define_method(cMysql2Client, "create_statement", create_statement, 0);
rb_define_private_method(cMysql2Client, "reconnect=", set_reconnect, 1);
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);

View File

@ -33,8 +33,8 @@ void init_mysql2_client();
typedef struct {
VALUE encoding;
short int active;
short int closed;
char active;
char closed;
MYSQL *client;
} mysql_client_wrapper;

View File

@ -57,9 +57,13 @@ end
asplode h unless have_header h
end
unless RUBY_PLATFORM =~ /mswin/
unless RUBY_PLATFORM =~ /mswin/ or RUBY_PLATFORM =~ /sparc/
$CFLAGS << ' -Wall -funroll-loops'
end
# $CFLAGS << ' -O0 -ggdb3 -Wextra'
if hard_mysql_path = $libs[%r{-L(/[^ ]+)}, 1]
$LDFLAGS << " -Wl,-rpath,#{hard_mysql_path}"
end
create_makefile('mysql2/mysql2')

View File

@ -2,21 +2,6 @@
VALUE mMysql2, cMysql2Error;
/* call-seq: client.create_statement # => Mysql2::Statement
*
* Create a new prepared statement.
*/
static VALUE create_statement(VALUE self)
{
MYSQL * client;
MYSQL_STMT * stmt;
Data_Get_Struct(self, MYSQL, client);
stmt = mysql_stmt_init(client);
return Data_Wrap_Struct(cMysql2Statement, 0, mysql_stmt_close, stmt);
}
/* Ruby Extension initializer */
void Init_mysql2() {
mMysql2 = rb_define_module("Mysql2");
@ -24,5 +9,4 @@ void Init_mysql2() {
init_mysql2_client();
init_mysql2_result();
init_mysql2_statement();
}

View File

@ -4,6 +4,12 @@
#include <ruby.h>
#include <fcntl.h>
#ifndef HAVE_UINT
#define HAVE_UINT
typedef unsigned short ushort;
typedef unsigned int uint;
#endif
#ifdef HAVE_MYSQL_H
#include <mysql.h>
#include <mysql_com.h>
@ -28,6 +34,5 @@
#include <client.h>
#include <result.h>
#include <statement.h>
#endif

View File

@ -248,7 +248,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
val = rb_str_new(row[i], fieldLengths[i]);
#ifdef HAVE_RUBY_ENCODING_H
// if binary flag is set, respect it's wishes
if (fields[i].flags & BINARY_FLAG) {
if (fields[i].flags & BINARY_FLAG && fields[i].charsetnr == 63) {
rb_enc_associate(val, binaryEncoding);
} else {
// lookup the encoding configured on this field

View File

@ -8,10 +8,10 @@ typedef struct {
VALUE fields;
VALUE rows;
VALUE encoding;
long numberOfFields;
unsigned int numberOfFields;
unsigned long numberOfRows;
unsigned long lastRowProcessed;
short int resultFreed;
char resultFreed;
MYSQL_RES *result;
} mysql2_result_wrapper;

View File

@ -1,203 +0,0 @@
#include <mysql2_ext.h>
VALUE cMysql2Statement;
extern VALUE mMysql2, cMysql2Error;
/* call-seq: stmt.prepare(sql)
*
* Prepare +sql+ for execution
*/
static VALUE prepare(VALUE self, VALUE sql)
{
MYSQL_STMT * stmt;
Data_Get_Struct(self, MYSQL_STMT, stmt);
if(mysql_stmt_prepare(stmt, StringValuePtr(sql), RSTRING_LEN(sql))) {
rb_raise(cMysql2Error, "%s", mysql_stmt_error(stmt));
}
return self;
}
/* call-seq: stmt.param_count # => 2
*
* Returns the number of parameters the prepared statement expects.
*/
static VALUE param_count(VALUE self)
{
MYSQL_STMT * stmt;
Data_Get_Struct(self, MYSQL_STMT, stmt);
return ULL2NUM(mysql_stmt_param_count(stmt));
}
/* call-seq: stmt.field_count # => 2
*
* Returns the number of fields the prepared statement returns.
*/
static VALUE field_count(VALUE self)
{
MYSQL_STMT * stmt;
Data_Get_Struct(self, MYSQL_STMT, stmt);
return UINT2NUM(mysql_stmt_field_count(stmt));
}
/* call-seq: stmt.execute
*
* Executes the current prepared statement, returns +stmt+.
*/
static VALUE execute(VALUE self)
{
MYSQL_STMT * stmt;
Data_Get_Struct(self, MYSQL_STMT, stmt);
if(mysql_stmt_execute(stmt))
rb_raise(cMysql2Error, "%s", mysql_stmt_error(stmt));
return self;
}
/* call-seq: stmt.fields -> array
*
* Returns a list of fields that will be returned by this statement.
*/
static VALUE fields(VALUE self)
{
MYSQL_STMT * stmt;
MYSQL_FIELD * fields;
MYSQL_RES * metadata;
unsigned int field_count;
unsigned int i;
VALUE field_list;
VALUE cMysql2Field;
Data_Get_Struct(self, MYSQL_STMT, stmt);
metadata = mysql_stmt_result_metadata(stmt);
fields = mysql_fetch_fields(metadata);
field_count = mysql_stmt_field_count(stmt);
field_list = rb_ary_new2((long)field_count);
cMysql2Field = rb_const_get(mMysql2, rb_intern("Field"));
for(i = 0; i < field_count; i++) {
VALUE argv[2];
VALUE field;
/* FIXME: encoding. Also, can this return null? */
argv[0] = rb_str_new2(fields[i].name);
argv[1] = INT2NUM(fields[i].type);
field = rb_class_new_instance(2, argv, cMysql2Field);
rb_ary_store(field_list, (long)i, field);
}
return field_list;
}
static VALUE each(VALUE self)
{
MYSQL_STMT * stmt;
MYSQL_FIELD * fields;
MYSQL_RES * metadata;
MYSQL_BIND * binds;
my_bool * is_null;
my_bool * error;
unsigned long * length;
int int_data;
MYSQL_TIME ts;
unsigned int field_count;
unsigned int i;
VALUE block;
Data_Get_Struct(self, MYSQL_STMT, stmt);
block = rb_block_proc();
metadata = mysql_stmt_result_metadata(stmt);
fields = mysql_fetch_fields(metadata);
field_count = mysql_stmt_field_count(stmt);
binds = xcalloc(field_count, sizeof(MYSQL_BIND));
is_null = xcalloc(field_count, sizeof(my_bool));
error = xcalloc(field_count, sizeof(my_bool));
length = xcalloc(field_count, sizeof(unsigned long));
for(i = 0; i < field_count; i++) {
switch(fields[i].type) {
case MYSQL_TYPE_LONGLONG:
binds[i].buffer_type = MYSQL_TYPE_LONG;
binds[i].buffer = (char *)&int_data;
break;
case MYSQL_TYPE_DATETIME:
binds[i].buffer_type = MYSQL_TYPE_DATETIME;
binds[i].buffer = (char *)&ts;
break;
default:
rb_raise(cMysql2Error, "unhandled mysql type: %d", fields[i].type);
}
binds[i].is_null = &is_null[i];
binds[i].length = &length[i];
binds[i].error = &error[i];
}
if(mysql_stmt_bind_result(stmt, binds)) {
xfree(binds);
xfree(is_null);
xfree(error);
xfree(length);
rb_raise(cMysql2Error, "%s", mysql_stmt_error(stmt));
}
while(!mysql_stmt_fetch(stmt)) {
VALUE row = rb_ary_new2((long)field_count);
for(i = 0; i < field_count; i++) {
VALUE column = Qnil;
switch(binds[i].buffer_type) {
case MYSQL_TYPE_LONG:
column = INT2NUM(int_data);
break;
/* FIXME: maybe we want to return a datetime in this case? */
case MYSQL_TYPE_DATETIME:
column = rb_funcall(rb_cTime,
rb_intern("mktime"), 6,
UINT2NUM(ts.year),
UINT2NUM(ts.month),
UINT2NUM(ts.day),
UINT2NUM(ts.hour),
UINT2NUM(ts.minute),
UINT2NUM(ts.second));
break;
default:
rb_raise(cMysql2Error, "unhandled buffer type: %d",
binds[i].buffer_type);
break;
}
rb_ary_store(row, (long)i, column);
}
rb_yield(row);
}
xfree(binds);
xfree(is_null);
xfree(error);
xfree(length);
return self;
}
void init_mysql2_statement()
{
cMysql2Statement = rb_define_class_under(mMysql2, "Statement", rb_cObject);
rb_define_method(cMysql2Statement, "prepare", prepare, 1);
rb_define_method(cMysql2Statement, "param_count", param_count, 0);
rb_define_method(cMysql2Statement, "field_count", field_count, 0);
rb_define_method(cMysql2Statement, "execute", execute, 0);
rb_define_method(cMysql2Statement, "each", each, 0);
rb_define_method(cMysql2Statement, "fields", fields, 0);
}

View File

@ -1,8 +0,0 @@
#ifndef MYSQL2_STATEMENT_H
#define MYSQL2_STATEMENT_H
extern VALUE cMysql2Statement;
void init_mysql2_statement();
#endif

View File

@ -35,7 +35,6 @@ module Mysql2
results = @client.async_result
@deferable.succeed(results)
rescue Exception => e
puts e.backtrace.join("\n\t")
@deferable.fail(e)
end
end

View File

@ -18,6 +18,9 @@ module ActiveRecord
end
module ConnectionAdapters
class Mysql2IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc:
end
class Mysql2Column < Column
BOOL = "tinyint(1)"
def extract_default(default)
@ -447,7 +450,7 @@ module ActiveRecord
if current_index != row[:Key_name]
next if row[:Key_name] == PRIMARY # skip the primary key
current_index = row[:Key_name]
indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [], [])
indexes << Mysql2IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [], [])
end
indexes.last.columns << row[:Column_name]
@ -622,8 +625,9 @@ module ActiveRecord
variable_assignments << "NAMES '#{encoding}'" if encoding
# increase timeout so mysql server doesn't disconnect us
wait_timeout = @config[:wait_timeout] || 2592000
variable_assignments << "@@wait_timeout = #{wait_timeout}" if wait_timeout.is_a?(Fixnum)
wait_timeout = @config[:wait_timeout]
wait_timeout = 2592000 unless wait_timeout.is_a?(Fixnum)
variable_assignments << "@@wait_timeout = #{wait_timeout}"
execute("SET #{variable_assignments.join(', ')}", :skip_logging)
end

View File

@ -7,11 +7,10 @@ require 'mysql2/error'
require 'mysql2/mysql2'
require 'mysql2/client'
require 'mysql2/result'
require 'mysql2/field'
# = Mysql2
#
# A modern, simple and very fast Mysql library for Ruby - binding to libmysql
module Mysql2
VERSION = "0.2.4"
VERSION = "0.2.6"
end

View File

@ -24,6 +24,11 @@ module Mysql2
# force the encoding to utf8
self.charset_name = opts[:encoding] || 'utf8'
@read_timeout = opts[:read_timeout]
if @read_timeout and @read_timeout < 0
raise Mysql2::Error, "read_timeout must be a positive integer, you passed #{@read_timeout}"
end
ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslciper))
user = opts[:username]

View File

@ -23,10 +23,14 @@ module Mysql2
end
def query(sql, opts={})
super(sql, opts.merge(:async => true))
deferable = ::EM::DefaultDeferrable.new
::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
deferable
if ::EM.reactor_running?
super(sql, opts.merge(:async => true))
deferable = ::EM::DefaultDeferrable.new
::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
deferable
else
super(sql, opts)
end
end
end
end

29
lib/mysql2/em_fiber.rb Normal file
View File

@ -0,0 +1,29 @@
# encoding: utf-8
require 'mysql2/em'
require 'fiber'
module Mysql2
module EM
module Fiber
class Client < ::Mysql2::EM::Client
def query(sql, opts={})
if ::EM.reactor_running?
deferable = super(sql, opts)
fiber = ::Fiber.current
deferable.callback do |result|
fiber.resume(result)
end
deferable.errback do |err|
fiber.resume(err)
end
::Fiber.yield
else
super(sql, opts)
end
end
end
end
end
end

View File

@ -1,4 +0,0 @@
module Mysql2
class Field < Struct.new(:name, :type)
end
end

View File

@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = %q{mysql2}
s.version = "0.2.4"
s.version = "0.2.6"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Brian Lopez"]
s.date = %q{2010-10-18}
s.date = %q{2010-10-19}
s.email = %q{seniorlopez@gmail.com}
s.extensions = ["ext/mysql2/extconf.rb"]
s.extra_rdoc_files = [
@ -46,6 +46,7 @@ Gem::Specification.new do |s|
"lib/mysql2.rb",
"lib/mysql2/client.rb",
"lib/mysql2/em.rb",
"lib/mysql2/em_fiber.rb",
"lib/mysql2/error.rb",
"lib/mysql2/result.rb",
"mysql2.gemspec",

22
spec/em/em_fiber_spec.rb Normal file
View File

@ -0,0 +1,22 @@
# encoding: UTF-8
if defined? EventMachine && defined? Fiber
require 'spec_helper'
require 'mysql2/em_fiber'
describe Mysql2::EM::Fiber::Client do
it 'should support queries' do
results = []
EM.run do
Fiber.new {
client1 = Mysql2::EM::Fiber::Client.new
results = client1.query "SELECT sleep(0.1) as first_query"
EM.stop_event_loop
}.resume
end
results.first.keys.should include("first_query")
end
end
else
puts "Either EventMachine or Fibers not available. Skipping tests that use them."
end

View File

@ -85,7 +85,19 @@ describe Mysql2::Client do
@client.should respond_to(:query)
end
it "should expect read_timeout to be a positive integer" do
lambda {
Mysql2::Client.new(:read_timeout => -1)
}.should raise_error(Mysql2::Error)
end
context "#query" do
it "should only accept strings as the query parameter" do
lambda {
@client.query ["SELECT 'not right'"]
}.should raise_error(TypeError)
end
it "should accept an options hash that inherits from Mysql2::Client.default_query_options" do
@client.query "SELECT 1", :something => :else
@client.query_options.should eql(@client.query_options.merge(:something => :else))
@ -118,6 +130,13 @@ describe Mysql2::Client do
}.should raise_error(Mysql2::Error)
end
it "should timeout if we wait longer than :read_timeout" do
client = Mysql2::Client.new(:read_timeout => 1)
lambda {
client.query("SELECT sleep(2)")
}.should raise_error(Mysql2::Error)
end
# XXX this test is not deterministic (because Unix signal handling is not)
# and may fail on a loaded system
if RUBY_PLATFORM !~ /mingw|mswin/

View File

@ -1,93 +0,0 @@
# encoding: UTF-8
require 'spec_helper'
describe Mysql2::Statement do
before :each do
@client = Mysql2::Client.new :host => "localhost", :username => "root"
end
it "should create a statement" do
stmt = @client.create_statement
stmt.should be_kind_of Mysql2::Statement
end
it "prepares some sql" do
stmt = @client.create_statement
lambda { stmt.prepare 'SELECT 1' }.should_not raise_error
end
it "return self when prepare some sql" do
stmt = @client.create_statement
stmt.prepare('SELECT 1').should == stmt
end
it "should raise an exception when server disconnects" do
stmt = @client.create_statement
@client.close
lambda { stmt.prepare 'SELECT 1' }.should raise_error(Mysql2::Error)
end
it "should tell us the param count" do
stmt = @client.create_statement
stmt.prepare 'SELECT ?, ?'
stmt.param_count.should == 2
stmt.prepare 'SELECT 1'
stmt.param_count.should == 0
end
it "should tell us the field count" do
stmt = @client.create_statement
stmt.prepare 'SELECT ?, ?'
stmt.field_count.should == 2
stmt.prepare 'SELECT 1'
stmt.field_count.should == 1
end
it "should let us execute our statement" do
stmt = @client.create_statement
stmt.prepare 'SELECT 1'
stmt.execute.should == stmt
end
it "should raise an exception on error" do
stmt = @client.create_statement
lambda { stmt.execute }.should raise_error(Mysql2::Error)
end
it "should raise an exception without a block" do
stmt = @client.create_statement
stmt.prepare 'SELECT 1'
stmt.execute
lambda { stmt.each }.should raise_error
end
it "should let us iterate over results" do
stmt = @client.create_statement
stmt.prepare 'SELECT 1'
stmt.execute
rows = []
stmt.each { |row| rows << row }
rows.should == [[1]]
end
it "should select dates" do
stmt = @client.create_statement
stmt.prepare 'SELECT NOW()'
stmt.execute
rows = []
stmt.each { |row| rows << row }
rows.first.first.should be_kind_of Time
end
it "should tell us about the fields" do
stmt = @client.create_statement
stmt.prepare 'SELECT 1 as foo, 2'
stmt.execute
list = stmt.fields
list.length.should == 2
list.first.name.should == 'foo'
list[1].name.should == '2'
end
end