do_mysql 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|