do_mysql 0.2.0
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/LICENSE +20 -0
- data/README +4 -0
- data/Rakefile +59 -0
- data/TODO +5 -0
- data/ext/extconf.rb +45 -0
- data/ext/mysql_c.c +16602 -0
- data/ext/mysql_c.i +67 -0
- data/lib/do_mysql.rb +216 -0
- metadata +63 -0
data/ext/mysql_c.i
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
%module mysql_c
|
2
|
+
%{
|
3
|
+
#include <mysql.h>
|
4
|
+
#include <errmsg.h>
|
5
|
+
#include <mysqld_error.h>
|
6
|
+
|
7
|
+
VALUE mysql_c_fetch_field_names(MYSQL_RES *reader, int count) {
|
8
|
+
VALUE arr = rb_ary_new();
|
9
|
+
int i;
|
10
|
+
for(i = 0; i < count; i++) {
|
11
|
+
rb_ary_push(arr, rb_str_new2(mysql_fetch_field_direct(reader, i)->name));
|
12
|
+
}
|
13
|
+
return arr;
|
14
|
+
}
|
15
|
+
|
16
|
+
VALUE mysql_c_fetch_field_types(MYSQL_RES *reader, int count) {
|
17
|
+
VALUE arr = rb_ary_new();
|
18
|
+
int i;
|
19
|
+
for(i = 0; i < count; i++) {
|
20
|
+
rb_ary_push(arr, INT2NUM(mysql_fetch_field_direct(reader, i)->type));
|
21
|
+
}
|
22
|
+
return arr;
|
23
|
+
}
|
24
|
+
|
25
|
+
VALUE mysql_c_fetch_row(MYSQL_RES *reader) {
|
26
|
+
VALUE arr = rb_ary_new();
|
27
|
+
MYSQL_ROW result = (MYSQL_ROW)mysql_fetch_row(reader);
|
28
|
+
if(!result) return Qnil;
|
29
|
+
int i;
|
30
|
+
|
31
|
+
for(i = 0; i < reader->field_count; i++) {
|
32
|
+
if(result[i] == NULL) rb_ary_push(arr, Qnil);
|
33
|
+
else rb_ary_push(arr, rb_str_new2(result[i]));
|
34
|
+
}
|
35
|
+
return arr;
|
36
|
+
}
|
37
|
+
|
38
|
+
%}
|
39
|
+
|
40
|
+
%ignore st_mysql_options;
|
41
|
+
%include "/usr/local/mysql-5.0.45-osx10.4-i686/include/mysql.h"
|
42
|
+
|
43
|
+
VALUE mysql_c_fetch_field_names(MYSQL_RES *reader, int count);
|
44
|
+
VALUE mysql_c_fetch_field_types(MYSQL_RES *reader, int count);
|
45
|
+
VALUE mysql_c_fetch_row(MYSQL_RES *reader);
|
46
|
+
|
47
|
+
enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
|
48
|
+
MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG,
|
49
|
+
MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE,
|
50
|
+
MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP,
|
51
|
+
MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24,
|
52
|
+
MYSQL_TYPE_DATE, MYSQL_TYPE_TIME,
|
53
|
+
MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR,
|
54
|
+
MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR,
|
55
|
+
MYSQL_TYPE_BIT,
|
56
|
+
MYSQL_TYPE_NEWDECIMAL=246,
|
57
|
+
MYSQL_TYPE_ENUM=247,
|
58
|
+
MYSQL_TYPE_SET=248,
|
59
|
+
MYSQL_TYPE_TINY_BLOB=249,
|
60
|
+
MYSQL_TYPE_MEDIUM_BLOB=250,
|
61
|
+
MYSQL_TYPE_LONG_BLOB=251,
|
62
|
+
MYSQL_TYPE_BLOB=252,
|
63
|
+
MYSQL_TYPE_VAR_STRING=253,
|
64
|
+
MYSQL_TYPE_STRING=254,
|
65
|
+
MYSQL_TYPE_GEOMETRY=255
|
66
|
+
|
67
|
+
};
|
data/lib/do_mysql.rb
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'mysql_c'
|
2
|
+
require 'data_objects'
|
3
|
+
|
4
|
+
module DataObject
|
5
|
+
module Mysql
|
6
|
+
TYPES = Hash[*Mysql_c.constants.select {|x| x.include?("MYSQL_TYPE")}.map {|x| [Mysql_c.const_get(x), x.gsub(/^MYSQL_TYPE_/, "")]}.flatten]
|
7
|
+
|
8
|
+
QUOTE_STRING = "\""
|
9
|
+
QUOTE_COLUMN = "`"
|
10
|
+
|
11
|
+
class Connection < DataObject::Connection
|
12
|
+
|
13
|
+
attr_reader :db
|
14
|
+
|
15
|
+
def initialize(connection_string)
|
16
|
+
@state = STATE_CLOSED
|
17
|
+
@connection_string = connection_string
|
18
|
+
opts = connection_string.split(" ")
|
19
|
+
opts.each do |opt|
|
20
|
+
k, v = opt.split("=")
|
21
|
+
raise ArgumentError, "you specified an invalid connection component: #{opt}" unless k && v
|
22
|
+
instance_variable_set("@#{k}", v)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def change_database(database_name)
|
27
|
+
@dbname = database_name
|
28
|
+
@connection_string.gsub(/db_name=[^ ]*/, "db_name=#{database_name}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def open
|
32
|
+
@db = Mysql_c.mysql_init(nil)
|
33
|
+
raise ConnectionFailed, "could not allocate a MySQL connection" unless @db
|
34
|
+
conn = Mysql_c.mysql_real_connect(@db, @host, @user, @password, @dbname, @port || 0, @socket, @flags || 0)
|
35
|
+
raise ConnectionFailed, "The connection with connection string #{@connection_string} failed\n#{Mysql_c.mysql_error(@db)}" unless conn
|
36
|
+
@state = STATE_OPEN
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def close
|
41
|
+
if @state == STATE_OPEN
|
42
|
+
Mysql_c.mysql_close(@db)
|
43
|
+
@state = STATE_CLOSED
|
44
|
+
true
|
45
|
+
else
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_command(text)
|
51
|
+
Command.new(self, text)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
class Field
|
57
|
+
attr_reader :name, :type
|
58
|
+
|
59
|
+
def initialize(ptr)
|
60
|
+
@name, @type = ptr.name.to_s, ptr.type.to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Reader < DataObject::Reader
|
65
|
+
|
66
|
+
def initialize(db, reader)
|
67
|
+
@reader = reader
|
68
|
+
unless @reader
|
69
|
+
if Mysql_c.mysql_field_count(db) == 0
|
70
|
+
@records_affected = Mysql_c.mysql_affected_rows(db)
|
71
|
+
close
|
72
|
+
else
|
73
|
+
raise UnknownError, "An unknown error has occured while trying to process a MySQL query.\n#{Mysql_c.mysql_error(db)}"
|
74
|
+
end
|
75
|
+
else
|
76
|
+
@field_count = @reader.field_count
|
77
|
+
@state = STATE_OPEN
|
78
|
+
|
79
|
+
@native_fields, @fields = Mysql_c.mysql_c_fetch_field_types(@reader, @field_count), Mysql_c.mysql_c_fetch_field_names(@reader, @field_count)
|
80
|
+
|
81
|
+
raise UnknownError, "An unknown error has occured while trying to process a MySQL query. There were no fields in the resultset\n#{Mysql_c.mysql_error(db)}" if @native_fields.empty?
|
82
|
+
|
83
|
+
@has_rows = !(@row = Mysql_c.mysql_c_fetch_row(@reader)).nil?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def close
|
88
|
+
if @state == STATE_OPEN
|
89
|
+
Mysql_c.mysql_free_result(@reader)
|
90
|
+
@state = STATE_CLOSED
|
91
|
+
true
|
92
|
+
else
|
93
|
+
false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def name(col)
|
98
|
+
super
|
99
|
+
@fields[col]
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_index(name)
|
103
|
+
super
|
104
|
+
@fields.index(name)
|
105
|
+
end
|
106
|
+
|
107
|
+
def null?(idx)
|
108
|
+
super
|
109
|
+
@row[idx] == nil
|
110
|
+
end
|
111
|
+
|
112
|
+
def current_row
|
113
|
+
@row
|
114
|
+
end
|
115
|
+
|
116
|
+
def item(idx)
|
117
|
+
super
|
118
|
+
typecast(@row[idx], idx)
|
119
|
+
end
|
120
|
+
|
121
|
+
def next
|
122
|
+
super
|
123
|
+
@row = Mysql_c.mysql_c_fetch_row(@reader)
|
124
|
+
close if @row.nil?
|
125
|
+
@row ? true : nil
|
126
|
+
end
|
127
|
+
|
128
|
+
def each
|
129
|
+
return unless has_rows?
|
130
|
+
|
131
|
+
while(true) do
|
132
|
+
yield
|
133
|
+
break unless self.next
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
protected
|
138
|
+
def native_type(col)
|
139
|
+
super
|
140
|
+
TYPES[@native_fields[col].type]
|
141
|
+
end
|
142
|
+
|
143
|
+
def typecast(val, idx)
|
144
|
+
return nil if val.nil?
|
145
|
+
field = @native_fields[idx]
|
146
|
+
case TYPES[field]
|
147
|
+
when "TINY"
|
148
|
+
val != "0"
|
149
|
+
when "BIT"
|
150
|
+
val.to_i(2)
|
151
|
+
when "SHORT", "LONG", "INT24", "LONGLONG"
|
152
|
+
val.to_i
|
153
|
+
when "DECIMAL", "NEWDECIMAL", "FLOAT", "DOUBLE", "YEAR"
|
154
|
+
val.to_f
|
155
|
+
when "TIMESTAMP", "DATETIME"
|
156
|
+
DateTime.parse(val) rescue nil
|
157
|
+
when "TIME"
|
158
|
+
DateTime.parse(val).to_time rescue nil
|
159
|
+
when "DATE"
|
160
|
+
Date.parse(val) rescue nil
|
161
|
+
when "NULL"
|
162
|
+
nil
|
163
|
+
else
|
164
|
+
val
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class Command < DataObject::Command
|
170
|
+
|
171
|
+
def execute_reader(*args)
|
172
|
+
super
|
173
|
+
sql = escape_sql(args)
|
174
|
+
@connection.logger.debug { sql }
|
175
|
+
result = Mysql_c.mysql_query(@connection.db, sql)
|
176
|
+
# TODO: Real Error
|
177
|
+
raise QueryError, "Your query failed.\n#{Mysql_c.mysql_error(@connection.db)}\n#{@text}" unless result == 0
|
178
|
+
reader = Reader.new(@connection.db, Mysql_c.mysql_use_result(@connection.db))
|
179
|
+
if block_given?
|
180
|
+
result = yield(reader)
|
181
|
+
reader.close
|
182
|
+
result
|
183
|
+
else
|
184
|
+
reader
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def execute_non_query(*args)
|
189
|
+
super
|
190
|
+
sql = escape_sql(args)
|
191
|
+
@connection.logger.debug { sql }
|
192
|
+
result = Mysql_c.mysql_query(@connection.db, sql)
|
193
|
+
raise QueryError, "Your query failed.\n#{Mysql_c.mysql_error(@connection.db)}\n#{@text}" unless result == 0
|
194
|
+
reader = Mysql_c.mysql_store_result(@connection.db)
|
195
|
+
raise QueryError, "You called execute_non_query on a query: #{@text}" if reader
|
196
|
+
rows_affected = Mysql_c.mysql_affected_rows(@connection.db)
|
197
|
+
Mysql_c.mysql_free_result(reader)
|
198
|
+
return ResultData.new(@connection, rows_affected, Mysql_c.mysql_insert_id(@connection.db))
|
199
|
+
end
|
200
|
+
|
201
|
+
def quote_time(value)
|
202
|
+
# TIMESTAMP() used for both time and datetime columns
|
203
|
+
quote_datetime(value)
|
204
|
+
end
|
205
|
+
|
206
|
+
def quote_datetime(value)
|
207
|
+
"TIMESTAMP('#{value.strftime("%Y-%m-%d %H:%M:%S")}')"
|
208
|
+
end
|
209
|
+
|
210
|
+
def quote_date(value)
|
211
|
+
"DATE('#{value.strftime("%Y-%m-%d")}')"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: do_mysql
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2007-11-11 00:00:00 -08:00
|
8
|
+
summary: A DataObject.rb driver for mysql
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: wycats@gmail.com
|
12
|
+
homepage: http://dataobjects.devjavu.com
|
13
|
+
rubyforge_project:
|
14
|
+
description: A DataObject.rb driver for mysql
|
15
|
+
autorequire: do_mysql
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Yehuda Katz
|
31
|
+
files:
|
32
|
+
- LICENSE
|
33
|
+
- README
|
34
|
+
- Rakefile
|
35
|
+
- TODO
|
36
|
+
- lib/do_mysql.rb
|
37
|
+
- ext/extconf.rb
|
38
|
+
- ext/mysql_c.c
|
39
|
+
- ext/mysql_c.i
|
40
|
+
test_files: []
|
41
|
+
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
extra_rdoc_files:
|
45
|
+
- README
|
46
|
+
- LICENSE
|
47
|
+
- TODO
|
48
|
+
executables: []
|
49
|
+
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
requirements: []
|
53
|
+
|
54
|
+
dependencies:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: data_objects
|
57
|
+
version_requirement:
|
58
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 0.0.0
|
63
|
+
version:
|