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.
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: