do_mysql 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (9) hide show
  1. data/LICENSE +20 -0
  2. data/README +4 -0
  3. data/Rakefile +59 -0
  4. data/TODO +5 -0
  5. data/ext/extconf.rb +45 -0
  6. data/ext/mysql_c.c +16602 -0
  7. data/ext/mysql_c.i +67 -0
  8. data/lib/do_mysql.rb +216 -0
  9. 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: