ffi-mysql 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.rdoc +4 -0
- data/README +55 -0
- data/README.rdoc +55 -0
- data/Rakefile +27 -0
- data/lib/ffi-mysql.rb +49 -0
- data/lib/mysql/constants.rb +166 -0
- data/lib/mysql/error.rb +4 -0
- data/lib/mysql/field.rb +89 -0
- data/lib/mysql/mysql.rb +365 -0
- data/lib/mysql/result.rb +168 -0
- data/lib/mysql/stmt.rb +416 -0
- data/lib/mysql/time.rb +33 -0
- data/test/test_mysql.rb +1483 -0
- metadata +103 -0
data/lib/mysql/mysql.rb
ADDED
@@ -0,0 +1,365 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
# @author Frank Fischer
|
4
|
+
#
|
5
|
+
# Basic MySQL class, provides interface to a server.
|
6
|
+
class Mysql
|
7
|
+
|
8
|
+
# FFI interface.
|
9
|
+
module C
|
10
|
+
extend FFI::Library
|
11
|
+
#ffi_lib ["mysqlclient", "libmysqlclient.so.15"]
|
12
|
+
ffi_lib ["mysqlclient", "libmysqlclient.so.15", "libmysqlclient.so.16"]
|
13
|
+
|
14
|
+
# FieldType = enum(:decimal, Mysql::Field::TYPE_DECIMAL,
|
15
|
+
# :tiny, Mysql::Field::TYPE_TINY,
|
16
|
+
# :short, Mysql::Field::TYPE_SHORT,
|
17
|
+
# :long, Mysql::Field::TYPE_LONG,
|
18
|
+
# :float, Mysql::Field::TYPE_FLOAT,
|
19
|
+
# :double, Mysql::Field::TYPE_DOUBLE,
|
20
|
+
# :null, Mysql::Field::TYPE_NULL,
|
21
|
+
# :timestamp, Mysql::Field::TYPE_TIMESTAMP,
|
22
|
+
# :longlong, Mysql::Field::TYPE_LONGLONG,
|
23
|
+
# :int24, Mysql::Field::TYPE_INT24,
|
24
|
+
# :date, Mysql::Field::TYPE_DATE,
|
25
|
+
# :time, Mysql::Field::TYPE_TIME,
|
26
|
+
# :datetime, Mysql::Field::TYPE_DATETIME,
|
27
|
+
# :year, Mysql::Field::TYPE_YEAR,
|
28
|
+
# :newdate, Mysql::Field::TYPE_NEWDATE,
|
29
|
+
# :varchar, Mysql::Field::TYPE_VARCHAR,
|
30
|
+
# :bit, Mysql::Field::TYPE_BIT,
|
31
|
+
# :newdecimal, Mysql::Field::TYPE_NEWDECIMAL,
|
32
|
+
# :enum, Mysql::Field::TYPE_ENUM,
|
33
|
+
# :set, Mysql::Field::TYPE_SET,
|
34
|
+
# :tiny_blob, Mysql::Field::TYPE_TINY_BLOB,
|
35
|
+
# :medium_blob, Mysql::Field::TYPE_MEDIUM_BLOB,
|
36
|
+
# :long_blob, Mysql::Field::TYPE_LONG_BLOB,
|
37
|
+
# :blob, Mysql::Field::TYPE_BLOB,
|
38
|
+
# :var_string, Mysql::Field::TYPE_VAR_STRING,
|
39
|
+
# :string, Mysql::Field::TYPE_STRING,
|
40
|
+
# :geometry, Mysql::Field::TYPE_GEOMETRY,
|
41
|
+
# :char, Mysql::Field::TYPE_CHAR,
|
42
|
+
# :interval, Mysql::Field::TYPE_INTERVAL)
|
43
|
+
FieldType = :uchar
|
44
|
+
|
45
|
+
class Field < FFI::Struct
|
46
|
+
layout(:name, :string,
|
47
|
+
:org_name, :string,
|
48
|
+
:table, :string,
|
49
|
+
:org_table, :string,
|
50
|
+
:db, :string,
|
51
|
+
:catalog, :string,
|
52
|
+
:def, :string,
|
53
|
+
:length, :ulong,
|
54
|
+
:max_length, :ulong,
|
55
|
+
:name_length, :uint,
|
56
|
+
:org_name_length, :uint,
|
57
|
+
:table_length, :uint,
|
58
|
+
:org_table_length, :uint,
|
59
|
+
:db_length, :uint,
|
60
|
+
:catalog_length, :uint,
|
61
|
+
:def_length, :uint,
|
62
|
+
:flags, :uint,
|
63
|
+
:decimals, :uint,
|
64
|
+
:charsetnr, :uint,
|
65
|
+
:type, FieldType)
|
66
|
+
end
|
67
|
+
|
68
|
+
StmtAttrType = enum( :update_max_length, :cursor_type, :prefetch_rows )
|
69
|
+
|
70
|
+
attach_function :mysql_init, [:pointer], :pointer
|
71
|
+
attach_function :mysql_close, [:pointer], :void
|
72
|
+
attach_function :mysql_error, [:pointer], :string
|
73
|
+
attach_function :mysql_get_client_version, [], :int
|
74
|
+
attach_function :mysql_get_client_info, [], :string
|
75
|
+
attach_function :mysql_get_server_version, [:pointer], :int
|
76
|
+
attach_function :mysql_get_server_info, [:pointer], :string
|
77
|
+
attach_function :mysql_real_connect, [:pointer, :string, :string, :string, :string, :uint, :string, :ulong], :pointer
|
78
|
+
attach_function :mysql_options, [:pointer, :int, :pointer], :int
|
79
|
+
attach_function :mysql_set_server_option, [:pointer, :int], :int
|
80
|
+
attach_function :mysql_real_query, [:pointer, :string, :ulong], :int
|
81
|
+
attach_function :mysql_field_count, [:pointer], :uint
|
82
|
+
attach_function :mysql_store_result, [:pointer], :pointer
|
83
|
+
attach_function :mysql_free_result, [:pointer], :void
|
84
|
+
attach_function :mysql_next_result, [:pointer], :int
|
85
|
+
attach_function :mysql_more_results, [:pointer], :bool
|
86
|
+
attach_function :mysql_affected_rows, [:pointer], :ulong_long
|
87
|
+
attach_function :mysql_num_rows, [:pointer], :ulong_long
|
88
|
+
attach_function :mysql_fetch_row, [:pointer], :pointer
|
89
|
+
attach_function :mysql_fetch_lengths, [:pointer], :pointer
|
90
|
+
attach_function :mysql_row_tell, [:pointer], :ulong_long
|
91
|
+
attach_function :mysql_row_seek, [:pointer, :ulong_long], :ulong_long
|
92
|
+
attach_function :mysql_num_fields, [:pointer], :uint
|
93
|
+
attach_function :mysql_fetch_field, [:pointer], :pointer
|
94
|
+
attach_function :mysql_fetch_field_direct, [:pointer, :uint], :pointer
|
95
|
+
attach_function :mysql_field_tell, [:pointer], :uint
|
96
|
+
attach_function :mysql_field_seek, [:pointer, :uint], :uint
|
97
|
+
attach_function :mysql_data_seek, [:pointer, :ulong_long], :void
|
98
|
+
attach_function :mysql_sqlstate, [:pointer], :string
|
99
|
+
attach_function :mysql_stmt_init, [:pointer], :pointer
|
100
|
+
attach_function :mysql_stmt_attr_set, [:pointer, StmtAttrType, :pointer], :int
|
101
|
+
attach_function :mysql_stmt_close, [:pointer], :void
|
102
|
+
attach_function :mysql_stmt_prepare, [:pointer, :string, :ulong], :int
|
103
|
+
attach_function :mysql_stmt_execute, [:pointer], :int
|
104
|
+
attach_function :mysql_stmt_free_result, [:pointer], :int
|
105
|
+
attach_function :mysql_stmt_param_count, [:pointer], :ulong
|
106
|
+
attach_function :mysql_stmt_bind_param, [:pointer, :pointer], :char
|
107
|
+
attach_function :mysql_stmt_result_metadata, [:pointer], :pointer
|
108
|
+
attach_function :mysql_stmt_bind_result, [:pointer, :pointer], :char
|
109
|
+
attach_function :mysql_stmt_affected_rows, [:pointer], :ulong_long
|
110
|
+
attach_function :mysql_stmt_store_result, [:pointer], :int
|
111
|
+
attach_function :mysql_stmt_fetch, [:pointer], :int
|
112
|
+
attach_function :mysql_stmt_data_seek, [:pointer, :ulong_long], :void
|
113
|
+
attach_function :mysql_stmt_field_count, [:pointer], :uint
|
114
|
+
attach_function :mysql_stmt_num_rows, [:pointer], :ulong_long
|
115
|
+
attach_function :mysql_stmt_row_tell, [:pointer], :ulong_long
|
116
|
+
attach_function :mysql_stmt_row_seek, [:pointer, :ulong_long], :ulong_long
|
117
|
+
attach_function :mysql_stmt_insert_id, [:pointer], :ulong_long
|
118
|
+
attach_function :mysql_stmt_sqlstate, [:pointer], :string
|
119
|
+
attach_function :mysql_stmt_errno, [:pointer], :uint
|
120
|
+
attach_function :mysql_stmt_error, [:pointer], :string
|
121
|
+
end
|
122
|
+
|
123
|
+
# Creates a new MySQL object.
|
124
|
+
def self.init
|
125
|
+
mysql = allocate
|
126
|
+
mysql.send :initialize
|
127
|
+
mysql
|
128
|
+
end
|
129
|
+
|
130
|
+
# Creates a new MySQL connector and opens a connection.
|
131
|
+
def self.new( host = nil, user = nil, passwd = nil, db = nil, port = 0, sock = nil, flag = 0)
|
132
|
+
mysql = allocate
|
133
|
+
mysql.send :initialize
|
134
|
+
mysql.real_connect( host, user, passwd, db, port, sock, flag )
|
135
|
+
mysql
|
136
|
+
end
|
137
|
+
|
138
|
+
# @return [Integer] the version of the client
|
139
|
+
def self.client_version
|
140
|
+
C::mysql_get_client_version
|
141
|
+
end
|
142
|
+
|
143
|
+
# @return [Integer] the version of the client
|
144
|
+
def client_version
|
145
|
+
Mysql.client_version
|
146
|
+
end
|
147
|
+
|
148
|
+
# @return [String] string containing the client's version
|
149
|
+
def self.client_info
|
150
|
+
C::mysql_get_client_info
|
151
|
+
end
|
152
|
+
|
153
|
+
# Escape special character in MySQL.
|
154
|
+
# === Note
|
155
|
+
# In Ruby 1.8, this is not safe for multibyte charset such as 'SJIS'.
|
156
|
+
# You should use place-holder in prepared-statement.
|
157
|
+
def self.escape_string(str)
|
158
|
+
str.gsub(/[\0\n\r\\\'\"\x1a]/) do |s|
|
159
|
+
case s
|
160
|
+
when "\0" then "\\0"
|
161
|
+
when "\n" then "\\n"
|
162
|
+
when "\r" then "\\r"
|
163
|
+
when "\x1a" then "\\Z"
|
164
|
+
else "\\#{s}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class << self
|
170
|
+
alias :real_connect :new
|
171
|
+
alias :connect :new
|
172
|
+
alias :get_client_version :client_version
|
173
|
+
alias :get_client_info :client_info
|
174
|
+
alias quote escape_string
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
# if true (the default), query return the first result
|
179
|
+
attr_accessor :query_with_result
|
180
|
+
|
181
|
+
# Creates a new connection to a MySQL server.
|
182
|
+
#
|
183
|
+
# @param (see Mysql#real_connect)
|
184
|
+
def initialize
|
185
|
+
@mysql_free = [true]
|
186
|
+
@mysql = C::mysql_init( nil )
|
187
|
+
@connected = false
|
188
|
+
@query_with_result = true
|
189
|
+
end
|
190
|
+
|
191
|
+
# internal finalizer
|
192
|
+
def self.finalizer(mysql, mysql_free)
|
193
|
+
Proc.new do |*args|
|
194
|
+
unless mysql_free[0]
|
195
|
+
C::mysql_close(mysql)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Opens a new connection to a MySQL server.
|
201
|
+
#
|
202
|
+
# @param [String] host the MySQL server
|
203
|
+
# @param [String] user the username to login
|
204
|
+
# @param [String] passwd the user's password
|
205
|
+
# @param [String] db the name of the database to use
|
206
|
+
# @param [Integer] port the port of the server to use
|
207
|
+
# @param [Integer] flag connection flags
|
208
|
+
def real_connect( host = nil, user = nil, passwd = nil, db = nil, port = 0, sock = nil, flag = 0)
|
209
|
+
raise Error, "Already connected to a MySQL server" if @connected
|
210
|
+
|
211
|
+
ObjectSpace.define_finalizer( self, Mysql.finalizer(@mysql, @mysql_free))
|
212
|
+
|
213
|
+
if C::mysql_real_connect( @mysql, host, user, passwd, db, port, sock, flag ).null?
|
214
|
+
raise Mysql::Error, error_msg
|
215
|
+
end
|
216
|
+
|
217
|
+
@connected = true
|
218
|
+
self
|
219
|
+
end
|
220
|
+
alias :connect :real_connect
|
221
|
+
|
222
|
+
# Closes the connection to the server.
|
223
|
+
def close
|
224
|
+
C::mysql_close(@mysql)
|
225
|
+
@mysql = nil
|
226
|
+
@mysql_free[0] = true
|
227
|
+
@connected = false
|
228
|
+
end
|
229
|
+
|
230
|
+
# @return [Integer] the version of the server
|
231
|
+
def server_version
|
232
|
+
C::mysql_get_server_version(@mysql)
|
233
|
+
end
|
234
|
+
alias get_server_version server_version
|
235
|
+
|
236
|
+
# @return [String] string containing the server's version
|
237
|
+
def server_info
|
238
|
+
C::mysql_get_server_info(@mysql)
|
239
|
+
end
|
240
|
+
alias get_server_info server_info
|
241
|
+
|
242
|
+
# @return [String] the SQLSTATE error code for the most recent statement
|
243
|
+
def sqlstate
|
244
|
+
C::mysql_sqlstate(@mysql)
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
# Sets extra connection options.
|
249
|
+
#
|
250
|
+
# @param [Integer] option the option to set
|
251
|
+
# @param [String,Integer,true,false,nil] the value of the option to set
|
252
|
+
def options( arg, value = nil )
|
253
|
+
result = if value.nil?
|
254
|
+
C::mysql_options( @mysql, arg, nil )
|
255
|
+
elsif value.kind_of? Integer
|
256
|
+
C::mysql_options( @mysql, arg, FFI::MemoryPointer.new(:uint).write_int(value) )
|
257
|
+
elsif value.kind_of? String
|
258
|
+
C::mysql_options( @mysql, arg, FFI::MemoryPointer.from_string(value) )
|
259
|
+
elsif value == true
|
260
|
+
C::mysql_options( @mysql, arg, FFI::MemoryPointer.new(:uint).write_int(1) )
|
261
|
+
elsif value == false
|
262
|
+
C::mysql_options( @mysql, arg, FFI::MemoryPointer.new(:uint).write_int(0) )
|
263
|
+
else
|
264
|
+
raise ArgumentError, "value must one of [String, Integer, nil, true, false]"
|
265
|
+
end
|
266
|
+
raise Error, error_msg if result != 0
|
267
|
+
self
|
268
|
+
end
|
269
|
+
|
270
|
+
# Enables or disables an options for the connection.
|
271
|
+
#
|
272
|
+
# @param [Integer] option server option
|
273
|
+
def set_server_option( option )
|
274
|
+
if C::mysql_set_server_option( @mysql, option ) != 0
|
275
|
+
raise Error, error_msg
|
276
|
+
end
|
277
|
+
self
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
# Execute a query statement.
|
282
|
+
#
|
283
|
+
# @param [String] sql the SQL statement
|
284
|
+
# @yield [optional, Result] calls block once per result set
|
285
|
+
#
|
286
|
+
# @return [Result,self] the first result set if no block is given, self otherwise
|
287
|
+
def query(sql)
|
288
|
+
raise Error, "Not connected" unless @connected
|
289
|
+
if C::mysql_real_query(@mysql, sql, sql.size) != 0
|
290
|
+
raise Error, error_msg
|
291
|
+
end
|
292
|
+
|
293
|
+
if block_given?
|
294
|
+
begin
|
295
|
+
result = store_result
|
296
|
+
yield result
|
297
|
+
ensure
|
298
|
+
result.free
|
299
|
+
end while next_result
|
300
|
+
self
|
301
|
+
elsif query_with_result
|
302
|
+
if field_count == 0
|
303
|
+
nil
|
304
|
+
else
|
305
|
+
store_result
|
306
|
+
end
|
307
|
+
else
|
308
|
+
self
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
# Stores the current result in a result set.
|
313
|
+
# @return [Result] the result set
|
314
|
+
def store_result
|
315
|
+
Result.new(@mysql, C::mysql_store_result(@mysql))
|
316
|
+
end
|
317
|
+
|
318
|
+
# Advances to the next result set.
|
319
|
+
# @return [true,false] true if there's another result set
|
320
|
+
def next_result
|
321
|
+
result = C::mysql_next_result(@mysql)
|
322
|
+
if result == 0
|
323
|
+
true
|
324
|
+
elsif result < 0
|
325
|
+
false
|
326
|
+
else
|
327
|
+
raise Error, error_msg
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
# @return [true,false] true if there's another result set
|
332
|
+
def more_results?
|
333
|
+
C::mysql_more_results(@mysql)
|
334
|
+
end
|
335
|
+
alias more_results more_results?
|
336
|
+
|
337
|
+
# @return [Integer] the number of affected rows by the last query
|
338
|
+
def affected_rows
|
339
|
+
C::mysql_affected_rows(@mysql)
|
340
|
+
end
|
341
|
+
|
342
|
+
# @return [Integer] the number of columns for the most recent query
|
343
|
+
def field_count
|
344
|
+
C::mysql_field_count(@mysql)
|
345
|
+
end
|
346
|
+
|
347
|
+
# @return [Stmt] a new statement
|
348
|
+
def stmt_init
|
349
|
+
Stmt.new( @mysql )
|
350
|
+
end
|
351
|
+
|
352
|
+
# Creates and prepares a new statement.
|
353
|
+
# @param [String] stmt the SQL statement
|
354
|
+
# @return [Stmt] the new prepared statement
|
355
|
+
def prepare( stmt )
|
356
|
+
stmt_init.prepare(stmt)
|
357
|
+
end
|
358
|
+
|
359
|
+
# Returns the current error message.
|
360
|
+
def error_msg
|
361
|
+
C::mysql_error(@mysql)
|
362
|
+
end
|
363
|
+
private :error_msg
|
364
|
+
|
365
|
+
end
|
data/lib/mysql/result.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
class Mysql
|
2
|
+
|
3
|
+
# Result set.
|
4
|
+
class Result
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_reader :fields
|
8
|
+
|
9
|
+
# Create the next result object.
|
10
|
+
def initialize( mysql, result )
|
11
|
+
@mysql = mysql
|
12
|
+
@result = result
|
13
|
+
@num_rows = @num_fields = nil
|
14
|
+
raise ArgumentError, "Invalid result object" if @result.nil? or @result.null?
|
15
|
+
ObjectSpace.define_finalizer( self, Result.finalizer(@result) )
|
16
|
+
end
|
17
|
+
|
18
|
+
# Frees the result object.
|
19
|
+
def free
|
20
|
+
C::mysql_free_result(@result)
|
21
|
+
@result = nil
|
22
|
+
ObjectSpace.undefine_finalizer( self )
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Integer] the number of rows in this result set
|
26
|
+
def num_rows
|
27
|
+
raise Error, "Result has been freed" unless @result
|
28
|
+
@num_rows ||= C::mysql_num_rows(@result)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Integer] the number of columns in this result set
|
32
|
+
def num_fields
|
33
|
+
raise Error, "Result has been freed" unless @result
|
34
|
+
@num_fields ||= C::mysql_num_fields(@result)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Array<Integer>] the array of number of chars for each column
|
38
|
+
def fetch_lengths
|
39
|
+
raise Error, "Result has been freed" unless @result
|
40
|
+
lengths = C::mysql_fetch_lengths(@result)
|
41
|
+
lengths.null? ? nil : lengths.read_array_of_long(num_fields)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Array<String>] Ary of elements of the next row.
|
45
|
+
def fetch_row
|
46
|
+
raise Error, "Result has been freed" unless @result
|
47
|
+
row = C::mysql_fetch_row(@result)
|
48
|
+
if row.null?
|
49
|
+
nil
|
50
|
+
else
|
51
|
+
lengths = fetch_lengths
|
52
|
+
row = row.read_array_of_pointer(lengths.size)
|
53
|
+
(0...lengths.size).map{|i|
|
54
|
+
row[i].null? ? nil : row[i].read_string(lengths[i])
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Iterates over all rows in this result set.
|
60
|
+
# @yield [Array<String>] Called once for each row in this result set
|
61
|
+
# @see fetch_row
|
62
|
+
def each
|
63
|
+
while row = fetch_row
|
64
|
+
yield row
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Integer] the current position of the row cursor
|
69
|
+
def row_tell
|
70
|
+
raise Error, "Result has been freed" unless @result
|
71
|
+
C::mysql_row_tell(@result)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sets the position of the row cursor.
|
75
|
+
# @param [Integer] offset the new position of the row cursor
|
76
|
+
# @return [Integer] the former position of the row cursor
|
77
|
+
def row_seek( offset )
|
78
|
+
raise Error, "Result has been freed" unless @result
|
79
|
+
C::mysql_row_seek(@result, offset)
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param [Boolean] with_table if true, fields are denoted with table "tablename.fieldname"
|
83
|
+
# @return [Hash] hash of elements "field" => "value"
|
84
|
+
def fetch_hash(with_table = false)
|
85
|
+
return nil unless row = fetch_row
|
86
|
+
keys = if with_table
|
87
|
+
@tblcolnames ||= fetch_fields.map{|f| "#{f.table}.#{f.name}"}
|
88
|
+
else
|
89
|
+
@colnames ||= fetch_fields.map{|f| f.name}
|
90
|
+
end
|
91
|
+
|
92
|
+
hash = {}
|
93
|
+
row.each_with_index do |value, i|
|
94
|
+
hash[keys[i]] = value
|
95
|
+
end
|
96
|
+
hash
|
97
|
+
end
|
98
|
+
|
99
|
+
# Iterates over all rows in this result set.
|
100
|
+
# @param [Boolean] with_table if true, fields are denoted with table "tablename.fieldname"
|
101
|
+
# @yield [Hash] Called once for each row in this result set with a row-hash
|
102
|
+
# @see fetch_hash
|
103
|
+
def each_hash(with_table = false)
|
104
|
+
while row = fetch_hash(with_table)
|
105
|
+
yield row
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [Integer] The position of the field cursor after the last fetch_field.
|
110
|
+
def field_tell
|
111
|
+
raise Error, "Result has been freed" unless @result
|
112
|
+
C::mysql_field_tell(@result)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Sets the field cursor to the given offset.
|
116
|
+
# @param [Integer] the new field offset
|
117
|
+
# @return [Integer] the position of the previous field cursor
|
118
|
+
def field_seek(offset)
|
119
|
+
raise Error, "Result has been freed" unless @result
|
120
|
+
C::mysql_field_seek(@result, offset)
|
121
|
+
end
|
122
|
+
|
123
|
+
# @return [Field,nil] the information for the next Field or nil
|
124
|
+
def fetch_field
|
125
|
+
raise Error, "Result has been freed" unless @result
|
126
|
+
field_ptr = C::mysql_fetch_field(@result)
|
127
|
+
if field_ptr.null?
|
128
|
+
nil
|
129
|
+
else
|
130
|
+
Field.new(C::Field.new(field_ptr))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# @param [Integer] fieldnr column number
|
135
|
+
# @return [Field] the information for field of column fieldnr
|
136
|
+
def fetch_field_direct( fieldnr )
|
137
|
+
raise Error, "Result has been freed" unless @result
|
138
|
+
n = num_fields
|
139
|
+
raise Error, "#{fieldnr}: out of range (max: #{n})" if fieldnr < 0 or fieldnr >= n
|
140
|
+
field_ptr = C::mysql_fetch_field_direct(@result, fieldnr)
|
141
|
+
Field.new(C::Field.new(field_ptr))
|
142
|
+
end
|
143
|
+
|
144
|
+
# @return [Array<Field>] array of field-informations for each column in this result set
|
145
|
+
def fetch_fields
|
146
|
+
raise Error, "Result has been freed" unless @result
|
147
|
+
n = num_fields
|
148
|
+
(0...n).map{|i| fetch_field_direct(i)}
|
149
|
+
end
|
150
|
+
|
151
|
+
# Seeks to an arbitrary row in the result set.
|
152
|
+
# @param [Integer] row the number of row to use next
|
153
|
+
# @return [self]
|
154
|
+
def data_seek( row )
|
155
|
+
raise Error, "Result has been freed" unless @result
|
156
|
+
C::mysql_data_seek(@result, row)
|
157
|
+
self
|
158
|
+
end
|
159
|
+
|
160
|
+
# Internal finalizer, calls self.free.
|
161
|
+
def self.finalizer(result)
|
162
|
+
Proc.new do |*args|
|
163
|
+
C::mysql_free_result(result)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|