drizzle 0.1.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 ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Padraig O'Sullivan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,7 @@
1
+ = drizzle-ruby
2
+
3
+ An interface to Drizzle using FFI and libdrizzle.
4
+
5
+ == Copyright
6
+
7
+ Copyright (c) 2010 Padraig O'Sullivan. See LICENSE for details.
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = "drizzle"
10
+ gem.summary = "A ruby interface to Drizzle using libdrizzle"
11
+ gem.description = "An interface to Drizzle for Ruby that uses libdrizzle"
12
+ gem.email = "osullivan.padraig@gmail.com"
13
+ gem.homepage = "http://github.com/posulliv/drizzle-ruby"
14
+ gem.authors = ["Padraig O'Sullivan"]
15
+ gem.rubyforge_project = "drizzle-ruby"
16
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ Jeweler::RubyforgeTasks.new do |rubyforge|
21
+ rubyforge.doc_task = "rdoc"
22
+ end
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
25
+ exit(1)
26
+ end
27
+
28
+ Rake::TestTask.new(:test) do |test|
29
+ test.libs << 'lib' << 'test'
30
+ test.pattern = 'test/**/test_*.rb'
31
+ test.verbose = true
32
+ end
33
+
34
+ begin
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ end
41
+ rescue LoadError
42
+ task :rcov do
43
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
44
+ end
45
+ end
46
+
47
+ task :test => :check_dependencies
48
+
49
+ task :default => :test
50
+
51
+ Rake::RDocTask.new do |rdoc|
52
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
53
+
54
+ rdoc.rdoc_dir = 'rdoc'
55
+ rdoc.title = "drizzle #{version}"
56
+ rdoc.rdoc_files.include('README*')
57
+ rdoc.rdoc_files.include('lib/**/*.rb')
58
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,15 @@
1
+ # rubygems
2
+ require 'rubygems'
3
+
4
+ # 3rd party
5
+ require 'ffi'
6
+
7
+ # internal requires
8
+ require 'drizzle/ffidrizzle'
9
+ require 'drizzle/drizzle'
10
+ require 'drizzle/result'
11
+ require 'drizzle/connection'
12
+ require 'drizzle/exceptions'
13
+
14
+ module Drizzle
15
+ end
@@ -0,0 +1,207 @@
1
+ require 'drizzle/ffidrizzle'
2
+ require 'drizzle/exceptions'
3
+
4
+ module Drizzle
5
+
6
+ class ConnectionPtr < FFI::AutoPointer
7
+ def self.release(ptr)
8
+ LibDrizzle.drizzle_con_free(ptr)
9
+ end
10
+ end
11
+
12
+ #
13
+ # map of keywords that will be used with the SQL injection
14
+ # prevention plugin in drizzle
15
+ #
16
+ Keywords =
17
+ {
18
+ "add" => true,
19
+ "all" => true,
20
+ "alter" => true,
21
+ "analyze" => true,
22
+ "and" => true,
23
+ "any" => true,
24
+ "as" => true,
25
+ "asc" => true,
26
+ "before" => true,
27
+ "between" => true,
28
+ "by" => true,
29
+ "count" => true,
30
+ "distinct" => true,
31
+ "drop" => true,
32
+ "from" => true,
33
+ "having" => true,
34
+ "or" => true,
35
+ "select" => true,
36
+ "union" => true,
37
+ "where" => true
38
+ }
39
+
40
+
41
+ #
42
+ # connection options
43
+ #
44
+ NONE = 0
45
+ ALLOCATED = 1
46
+ MYSQL = 2
47
+ RAW_PACKET = 4
48
+ RAW_SCRAMBLE = 8
49
+ READY = 16
50
+ NO_RESULT_READ = 32
51
+ INJECTION_PREVENTION = 64
52
+
53
+ #
54
+ # A drizzle connection
55
+ #
56
+ class Connection
57
+
58
+ attr_accessor :host, :port, :db
59
+
60
+ #
61
+ # Creates a connection instance
62
+ #
63
+ # == parameters
64
+ #
65
+ # * host the hostname for the connection
66
+ # * port the port number for the connection
67
+ # * db the database name for the connection
68
+ # * opts connection options
69
+ # * drizzle_ptr FFI pointer to a drizzle_st object
70
+ #
71
+ # Some examples :
72
+ #
73
+ # c = Drizzle::Connection.new
74
+ # c = Drizzle::Connection.new("my_host", 4427)
75
+ # c = Drizzle::Connection.new("my_host", 4427, "my_db")
76
+ # c = Drizzle::Connection.new("my_host", 4427, "my_db", [Drizzle::NONE])
77
+ #
78
+ def initialize(host = "localhost", port = 4427, db = nil, opts = [], drizzle_ptr = nil)
79
+ @host = host
80
+ @port = port
81
+ @db = db
82
+ @drizzle_handle = drizzle_ptr || DrizzlePtr.new(LibDrizzle.drizzle_create(nil))
83
+ @con_ptr = ConnectionPtr.new(LibDrizzle.drizzle_con_create(@drizzle_handle, nil))
84
+ @rand_key = ""
85
+
86
+ opts.each do |opt|
87
+ if opt == INJECTION_PREVENTION
88
+ @randomize_queries = true
89
+ next
90
+ end
91
+ LibDrizzle.drizzle_con_add_options(@con_ptr, LibDrizzle::ConnectionOptions[opt])
92
+ end
93
+ LibDrizzle.drizzle_con_set_tcp(@con_ptr, @host, @port)
94
+ LibDrizzle.drizzle_con_set_db(@con_ptr, @db) if @db
95
+ @ret_ptr = FFI::MemoryPointer.new(:int)
96
+
97
+ #
98
+ # if SQL injection prevention is enabled, we need to retrieve
99
+ # the key to use for randomization from the server
100
+ #
101
+ if @randomize_queries == true
102
+ query = "show variables like '%stad_key%'"
103
+ res = LibDrizzle.drizzle_query_str(@con_ptr, nil, query, @ret_ptr)
104
+ check_return_code
105
+ result = Result.new(res)
106
+ result.buffer_result
107
+ result.each do |row|
108
+ @rand_key = row[1]
109
+ end
110
+ end
111
+ end
112
+
113
+ #
114
+ # set the host and port for the connection
115
+ #
116
+ def set_tcp(host, port)
117
+ @host = host
118
+ @port = port
119
+ LibDrizzle.drizzle_con_set_tcp(@con_ptr, @host, @port)
120
+ end
121
+
122
+ #
123
+ # set the database name for the connection
124
+ #
125
+ def set_db(db_name)
126
+ @db = db_name
127
+ LibDrizzle.drizzle_con_set_db(@con_ptr, @db)
128
+ end
129
+
130
+ #
131
+ # execute a query and construct a result object
132
+ #
133
+ def query(query)
134
+ res = LibDrizzle.drizzle_query_str(@con_ptr, nil, query, @ret_ptr)
135
+ check_return_code
136
+ Result.new(res)
137
+ end
138
+
139
+ #
140
+ # tokenize the input query and append the randomization key to
141
+ # keywords
142
+ #
143
+ def randomize_query(query)
144
+ if @rand_key.empty?
145
+ return query
146
+ end
147
+ toks = query.split(" ")
148
+ new_query = ""
149
+ toks.each do |token|
150
+ if Keywords[token.downcase] == true
151
+ token << @rand_key
152
+ end
153
+ new_query << token << " "
154
+ end
155
+ new_query
156
+ end
157
+
158
+ def check_return_code()
159
+ case LibDrizzle::ReturnCode[@ret_ptr.get_int(0)]
160
+ when :DRIZZLE_RETURN_IO_WAIT
161
+ raise IoWait.new(LibDrizzle.drizzle_error(@drizzle_handle))
162
+ when :DRIZZLE_RETURN_PAUSE
163
+ raise Pause.new(LibDrizzle.drizzle_error(@drizzle_handle))
164
+ when :DRIZZLE_RETURN_ROW_BREAK
165
+ raise RowBreak.new(LibDrizzle.drizzle_error(@drizzle_handle))
166
+ when :DRIZZLE_RETURN_MEMORY
167
+ raise Memory.new(LibDrizzle.drizzle_error(@drizzle_handle))
168
+ when :DRIZZLE_RETURN_INTERNAL_ERROR
169
+ raise InternalError.new(LibDrizzle.drizzle_error(@drizzle_handle))
170
+ when :DRIZZLE_RETURN_NOT_READY
171
+ raise NotReady.new(LibDrizzle.drizzle_error(@drizzle_handle))
172
+ when :DRIZZLE_RETURN_BAD_PACKET_NUMBER
173
+ raise BadPacketNumber.new(LibDrizzle.drizzle_error(@drizzle_handle))
174
+ when :DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET
175
+ raise BadHandshake.new(LibDrizzle.drizzle_error(@drizzle_handle))
176
+ when :DRIZZLE_RETURN_BAD_PACKET
177
+ raise BadPacket.new(LibDrizzle.drizzle_error(@drizzle_handle))
178
+ when :DRIZZLE_RETURN_PROTOCOL_NOT_SUPPORTED
179
+ raise ProtocolNotSupported.new(LibDrizzle.drizzle_error(@drizzle_handle))
180
+ when :DRIZZLE_RETURN_UNEXPECTED_DATA
181
+ raise UnexpectedData.new(LibDrizzle.drizzle_error(@drizzle_handle))
182
+ when :DRIZZLE_RETURN_NO_SCRAMBLE
183
+ raise NoScramble.new(LibDrizzle.drizzle_error(@drizzle_handle))
184
+ when :DRIZZLE_RETURN_AUTH_FAILED
185
+ raise AuthFailed.new(LibDrizzle.drizzle_error(@drizzle_handle))
186
+ when :DRIZZLE_RETURN_NULL_SIZE
187
+ raise NullSize.new(LibDrizzle.drizzle_error(@drizzle_handle))
188
+ when :DRIZZLE_RETURN_TOO_MANY_COLUMNS
189
+ raise TooManyColumns.new(LibDrizzle.drizzle_error(@drizzle_handle))
190
+ when :DRIZZLE_RETURN_ROW_END
191
+ raise RowEnd.new(LibDrizzle.drizzle_error(@drizzle_handle))
192
+ when :DRIZZLE_RETURN_LOST_CONNECTION
193
+ raise LostConnection.new(LibDrizzle.drizzle_error(@drizzle_handle))
194
+ when :DRIZZLE_RETURN_COULD_NOT_CONNECT
195
+ raise CouldNotConnect.new(LibDrizzle.drizzle_error(@drizzle_handle))
196
+ when :DRIZZLE_RETURN_NO_ACTIVE_CONNECTIONS
197
+ raise NoActiveConnections.new(LibDrizzle.drizzle_error(@drizzle_handle))
198
+ when :DRIZZLE_RETURN_HANDSHAKE_FAILED
199
+ raise HandshakeFailed.new(LibDrizzle.drizzle_error(@drizzle_handle))
200
+ when :DRIZZLE_RETURN_TIMEOUT
201
+ raise ReturnTimeout.new(LibDrizzle.drizzle_error(@drizzle_handle))
202
+ end
203
+ end
204
+
205
+ end
206
+
207
+ end
@@ -0,0 +1,58 @@
1
+ require 'drizzle/ffidrizzle'
2
+
3
+ module Drizzle
4
+
5
+ class DrizzlePtr < FFI::AutoPointer
6
+ def self.release(ptr)
7
+ LibDrizzle.drizzle_free(ptr)
8
+ end
9
+ end
10
+
11
+ #
12
+ # A Drizzle instance
13
+ #
14
+ class Drizzle
15
+
16
+ #
17
+ # creates a drizzle instance
18
+ #
19
+ def initialize()
20
+ @handle = DrizzlePtr.new(LibDrizzle.drizzle_create(nil))
21
+ end
22
+
23
+ #
24
+ # create a client connection
25
+ #
26
+ def create_client_connection(host, port, db)
27
+ Connection.new(host, port, db, @handle)
28
+ end
29
+
30
+ #
31
+ # return the libdrizzle API version
32
+ #
33
+ def version()
34
+ LibDrizzle.drizzle_version
35
+ end
36
+
37
+ #
38
+ # return the bug report URL to file libdrizzle bugs at
39
+ #
40
+ def bug_report_url()
41
+ LibDrizzle.drizzle_bugreport
42
+ end
43
+
44
+ #
45
+ # add a query to be run concurrently
46
+ #
47
+ def add_query(conn, query, query_num, opts = [])
48
+ end
49
+
50
+ #
51
+ # execute all queries concurrently
52
+ #
53
+ def run_all()
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,28 @@
1
+ require 'drizzle/ffidrizzle'
2
+
3
+ module Drizzle
4
+
5
+ class IoWait < RuntimeError; end
6
+ class Pause < RuntimeError; end
7
+ class RowBreak < RuntimeError; end
8
+ class Memory < RuntimeError; end
9
+ class InternalError < RuntimeError; end
10
+ class NotReady < RuntimeError; end
11
+ class BadPacketNumber < RuntimeError; end
12
+ class BadHandshake < RuntimeError; end
13
+ class BadPacket < RuntimeError; end
14
+ class ProtocolNotSupported < RuntimeError; end
15
+ class UnexpectedData < RuntimeError; end
16
+ class NoScramble < RuntimeError; end
17
+ class AuthFailed < RuntimeError; end
18
+ class NullSize < RuntimeError; end
19
+ class TooManyColumns < RuntimeError; end
20
+ class RowEnd < RuntimeError; end
21
+ class LostConnection < RuntimeError; end
22
+ class CouldNotConnect < RuntimeError; end
23
+ class NoActiveConnections < RuntimeError; end
24
+ class HandshakeFailed < RuntimeError; end
25
+ class Timeout < RuntimeError; end
26
+ class GeneralError < RuntimeError; end
27
+
28
+ end
@@ -0,0 +1,130 @@
1
+ require 'rubygems'
2
+ require 'ffi'
3
+
4
+ module LibDrizzle
5
+ extend FFI::Library
6
+ ffi_lib 'drizzle'
7
+
8
+ # constants
9
+ MAX_ERROR_SIZE = 2048
10
+ MAX_USER_SIZE = 64
11
+ MAX_PASSWORD_SIZE = 32
12
+ MAX_DB_SIZE = 64
13
+ MAX_INFO_SIZE = 2048
14
+ MAX_SQLSTATE_SIZE = 5
15
+ MAX_CATALOG_SIZE = 128
16
+ MAX_TABLE_SIZE = 128
17
+
18
+ # return codes
19
+ ReturnCode = enum( :DRIZZLE_RETURN_OK, 0,
20
+ :DRIZZLE_RETURN_IO_WAIT,
21
+ :DRIZZLE_RETURN_PAUSE,
22
+ :DRIZZLE_RETURN_ROW_BREAK,
23
+ :DRIZZLE_RETURN_MEMORY,
24
+ :DRIZZLE_RETURN_ERRNO,
25
+ :DRIZZLE_RETURN_INTERNAL_ERROR,
26
+ :DRIZZLE_RETURN_GETADDRINFO,
27
+ :DRIZZLE_RETURN_NOT_READY,
28
+ :DRIZZLE_RETURN_BAD_PACKET_NUMBER,
29
+ :DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET,
30
+ :DRIZZLE_RETURN_BAD_PACKET,
31
+ :DRIZZLE_RETURN_PROTOCOL_NOT_SUPPORTED,
32
+ :DRIZZLE_RETURN_UNEXPECTED_DATA,
33
+ :DRIZZLE_RETURN_NO_SCRAMBLE,
34
+ :DRIZZLE_RETURN_AUTH_FAILED,
35
+ :DRIZZLE_RETURN_NULL_SIZE,
36
+ :DRIZZLE_RETURN_ERROR_CODE,
37
+ :DRIZZLE_RETURN_TOO_MANY_COLUMNS,
38
+ :DRIZZLE_RETURN_ROW_END,
39
+ :DRIZZLE_RETURN_LOST_CONNECTION,
40
+ :DRIZZLE_RETURN_COULD_NOT_CONNECT,
41
+ :DRIZZLE_RETURN_NO_ACTIVE_CONNECTIONS,
42
+ :DRIZZLE_RETURN_HANDSHAKE_FAILED,
43
+ :DRIZZLE_RETURN_TIMEOUT,
44
+ :DRIZZLE_RETURN_MAX )
45
+
46
+ # verbosity levels
47
+ VerbosityLevel = enum( :DRIZZLE_VERBOSE_NEVER, 0,
48
+ :DRIZZLE_VERBOSE_FATAL,
49
+ :DRIZZLE_VERBOSE_ERROR,
50
+ :DRIZZLE_VERBOSE_INFO,
51
+ :DRIZZLE_VERBOSE_DEBUG,
52
+ :DRIZZLE_VERBOSE_CRAZY,
53
+ :DRIZZLE_VERBOSE_MAX )
54
+
55
+ # options for the Drizzle protocol functions.
56
+ CommandTypes = enum( :DRIZZLE_COMMAND_DRIZZLE_SLEEP, 0,
57
+ :DRIZZLE_COMMAND_DRIZZLE_QUIT,
58
+ :DRIZZLE_COMMAND_DRIZZLE_INIT_DB,
59
+ :DRIZZLE_COMMAND_DRIZZLE_QUERY,
60
+ :DRIZZLE_COMMAND_DRIZZLE_SHUTDOWN,
61
+ :DRIZZLE_COMMAND_DRIZZLE_CONNECT,
62
+ :DRIZZLE_COMMAND_DRIZZLE_PING,
63
+ :DRIZZLE_COMMAND_DRIZZLE_END )
64
+
65
+ # Status flags for a drizzle connection
66
+ ConnectionStatus = enum( :DRIZZLE_CON_STATUS_NONE, 0,
67
+ :DRIZZLE_CON_STATUS_IN_TRANS, (1 << 0),
68
+ :DRIZZLE_CON_STATUS_AUTOCOMMIT, (1 << 1),
69
+ :DRIZZLE_CON_STATUS_MORE_RESULTS_EXIST, (1 << 3),
70
+ :DRIZZLE_CON_STATUS_QUERY_NO_GOOD_INDEX_USED, (1 << 4),
71
+ :DRIZZLE_CON_STATUS_QUERY_NO_INDEX_USED, (1 << 5),
72
+ :DRIZZLE_CON_STATUS_CURSOR_EXISTS, (1 << 6),
73
+ :DRIZZLE_CON_STATUS_LAST_ROW_SENT, (1 << 7),
74
+ :DRIZZLE_CON_STATUS_DB_DROPPED, (1 << 8),
75
+ :DRIZZLE_CON_STATUS_NO_BACKSLASH_ESCAPES, (1 << 9),
76
+ :DRIZZLE_CON_STATUS_QUERY_WAS_SLOW, (1 << 10) )
77
+
78
+ # Options for connections
79
+ ConnectionOptions = enum( :DRIZZLE_CON_NONE, 0,
80
+ :DRIZZLE_CON_ALLOCATED, (1 << 0),
81
+ :DRIZZLE_CON_MYSQL, (1 << 1),
82
+ :DRIZZLE_CON_RAW_PACKET, (1 << 2),
83
+ :DRIZZLE_CON_RAW_SCRAMBLE, (1 << 3),
84
+ :DRIZZLE_CON_READY, (1 << 4),
85
+ :DRIZZLE_CON_NO_RESULT_READ, (1 << 5) )
86
+
87
+ # query options
88
+ QueryOptions = enum( :DRIZZLE_QUERY_ALLOCATED, (1 << 0) )
89
+
90
+ # options for main drizzle structure
91
+ Options = enum( :DRIZZLE_NONE, 0,
92
+ :DRIZZLE_ALLOCATED, (1 << 0),
93
+ :DRIZZLE_NON_BLOCKING, (1 << 1),
94
+ :DRIZZLE_FREE_OBJECTS, (1 << 2),
95
+ :DRIZZLE_ASSERT_DANGLING, (1 << 3) )
96
+
97
+ attach_function :drizzle_create, [ :pointer ], :pointer
98
+ attach_function :drizzle_free, [ :pointer ], :void
99
+ attach_function :drizzle_set_verbose, [ :pointer, VerbosityLevel ], :void
100
+
101
+ # connection related functions
102
+ attach_function :drizzle_con_create, [ :pointer, :pointer ], :pointer
103
+ attach_function :drizzle_con_free, [ :pointer ], :void
104
+ attach_function :drizzle_con_set_tcp, [ :pointer, :string, :int ], :void
105
+ attach_function :drizzle_con_set_db, [ :pointer, :string ], :void
106
+ attach_function :drizzle_con_add_options, [ :pointer, ConnectionOptions ], :void
107
+ attach_function :drizzle_con_fd, [ :pointer ], :int
108
+
109
+ # query related functions
110
+ attach_function :drizzle_query_str, [ :pointer, :pointer, :string, :pointer ], :pointer
111
+ attach_function :drizzle_query_add, [ :pointer, :pointer, :pointer, :pointer, :string, :size_t, QueryOptions, :pointer ], :pointer
112
+ attach_function :drizzle_result_read, [ :pointer, :pointer, :pointer ], :pointer
113
+ attach_function :drizzle_row_buffer, [ :pointer, :pointer ], :pointer
114
+ attach_function :drizzle_row_free, [ :pointer ], :void
115
+ attach_function :drizzle_result_buffer, [ :pointer ], ReturnCode
116
+ attach_function :drizzle_result_free, [ :pointer ], :void
117
+ attach_function :drizzle_row_next, [ :pointer ], :pointer
118
+ attach_function :drizzle_column_next, [ :pointer ], :pointer
119
+ attach_function :drizzle_column_name, [ :pointer ], :string
120
+ attach_function :drizzle_column_buffer, [ :pointer ], ReturnCode
121
+ attach_function :drizzle_result_column_count, [ :pointer ], :uint16
122
+ attach_function :drizzle_result_affected_rows, [ :pointer ], :uint64
123
+ attach_function :drizzle_result_insert_id, [ :pointer ], :uint64
124
+
125
+ # miscellaneous functions
126
+ attach_function :drizzle_version, [], :string
127
+ attach_function :drizzle_bugreport, [], :string
128
+ attach_function :drizzle_error, [ :pointer ], :string
129
+
130
+ end
@@ -0,0 +1,95 @@
1
+ require 'drizzle/ffidrizzle'
2
+
3
+ module Drizzle
4
+
5
+ #
6
+ # a result set from a drizzle query
7
+ #
8
+ class Result
9
+
10
+ attr_reader :columns, :rows, :affected_rows, :insert_id
11
+
12
+ #
13
+ # creates a result set instance
14
+ # This result set does not buffer any results until instructed
15
+ # to do so. Results can be fully buffered or buffered at the
16
+ # row level.
17
+ #
18
+ # == parameters
19
+ #
20
+ # * res_ptr FFI memory pointer to a drizzle_result_t object
21
+ #
22
+ def initialize(res_ptr)
23
+ @columns, @rows = [], []
24
+ @res_ptr = res_ptr
25
+ @affected_rows = LibDrizzle.drizzle_result_affected_rows(@res_ptr)
26
+ @insert_id = LibDrizzle.drizzle_result_insert_id(@res_ptr)
27
+ end
28
+
29
+ #
30
+ # buffer all rows and columns and copy them into ruby arrays
31
+ # Free the FFI pointer afterwards
32
+ #
33
+ def buffer_result()
34
+ ret = LibDrizzle.drizzle_result_buffer(@res_ptr)
35
+ if LibDrizzle::ReturnCode[ret] != LibDrizzle::ReturnCode[:DRIZZLE_RETURN_OK]
36
+ LibDrizzle.drizzle_result_free(@res_ptr)
37
+ end
38
+
39
+ loop do
40
+ col_ptr = LibDrizzle.drizzle_column_next(@res_ptr)
41
+ break if col_ptr.null?
42
+ @columns << LibDrizzle.drizzle_column_name(col_ptr).to_sym
43
+ end
44
+
45
+ loop do
46
+ row_ptr = LibDrizzle.drizzle_row_next(@res_ptr)
47
+ break if row_ptr.null?
48
+ @rows << row_ptr.get_array_of_string(0, @columns.size)
49
+ end
50
+
51
+ LibDrizzle.drizzle_result_free(@res_ptr)
52
+ end
53
+
54
+ #
55
+ # buffer an individual row.
56
+ #
57
+ def buffer_row()
58
+ # if the columns have not been read for this result
59
+ # set yet, then we need to do that here. If this is not
60
+ # performed here, we will receive a bad packet error
61
+ read_columns if @columns.empty?
62
+ ret_ptr = FFI::MemoryPointer.new(:int)
63
+ row_ptr = LibDrizzle.drizzle_row_buffer(@res_ptr, ret_ptr)
64
+ if LibDrizzle::ReturnCode[ret_ptr.get_int(0)] != :DRIZZLE_RETURN_OK
65
+ LibDrizzle.drizzle_result_free(@res_ptr)
66
+ end
67
+ if row_ptr.null?
68
+ LibDrizzle.drizzle_result_free(@res_ptr)
69
+ return nil
70
+ end
71
+ num_of_cols = LibDrizzle.drizzle_result_column_count(@res_ptr)
72
+ row = row_ptr.get_array_of_string(0, @columns.size)
73
+ end
74
+
75
+ #
76
+ # buffer all columns for this result set
77
+ #
78
+ def read_columns
79
+ ret = LibDrizzle.drizzle_column_buffer(@res_ptr)
80
+ loop do
81
+ col_ptr = LibDrizzle.drizzle_column_next(@res_ptr)
82
+ break if col_ptr.null?
83
+ @columns << LibDrizzle.drizzle_column_name(col_ptr).to_sym
84
+ end
85
+ end
86
+
87
+ def each
88
+ @rows.each do |row|
89
+ yield row if block_given?
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+
3
+ require File.join(File.dirname(__FILE__), *%w[.. lib drizzle])
4
+
5
+ require 'test/unit'
6
+ require 'shoulda'
7
+ require 'rr'
8
+
9
+ include Drizzle
10
+
11
+ PORT = 4427
12
+
13
+ class Test::Unit::TestCase
14
+ include RR::Adapters::TestUnit
15
+
16
+ def dest_dir(*subdirs)
17
+ File.join(File.dirname(__FILE__), 'dest', *subdirs)
18
+ end
19
+
20
+ def source_dir(*subdirs)
21
+ File.join(File.dirname(__FILE__), 'source', *subdirs)
22
+ end
23
+
24
+ def clear_dest
25
+ FileUtils.rm_rf(dest_dir)
26
+ end
27
+
28
+ end
@@ -0,0 +1,103 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestBasic < Test::Unit::TestCase
4
+
5
+ should "retrieve libdrizzle API version" do
6
+ drizzle = Drizzle::Drizzle.new
7
+ assert_equal "0.7", drizzle.version
8
+ end
9
+
10
+ should "retrieve libdrizzle bug report url" do
11
+ drizzle = Drizzle::Drizzle.new
12
+ assert_equal "https://launchpad.net/libdrizzle", drizzle.bug_report_url
13
+ end
14
+
15
+ should "connect to drizzle successfully" do
16
+ conn = Drizzle::Connection.new("localhost", PORT)
17
+ assert_equal conn.class, Drizzle::Connection
18
+ end
19
+
20
+ should "perform a simple query and buffer all results" do
21
+ conn = Drizzle::Connection.new("localhost", PORT, "data_dictionary")
22
+ res = conn.query("SELECT module_name, module_author FROM MODULES where module_name = 'SchemaEngine'")
23
+ assert_equal res.class, Drizzle::Result
24
+ res.buffer_result
25
+ assert_equal 2, res.columns.size
26
+ res.each do |row|
27
+ assert_equal "Brian Aker", row[1]
28
+ end
29
+ end
30
+
31
+ should "perform another simple query and buffer all results" do
32
+ conn = Drizzle::Connection.new("localhost", PORT, "information_schema", [Drizzle::NONE])
33
+ res = conn.query("SELECT table_schema, table_name FROM TABLES WHERE table_schema = 'DATA_DICTIONARY' AND table_name = 'GLOBAL_STATUS'")
34
+ assert_equal res.class, Drizzle::Result
35
+ res.buffer_result
36
+ assert_equal 2, res.columns.size
37
+ res.each do |row|
38
+ assert_equal "DATA_DICTIONARY", row[0]
39
+ assert_equal "GLOBAL_STATUS", row[1]
40
+ end
41
+ end
42
+
43
+ should "perform a simple query and buffer rows" do
44
+ conn = Drizzle::Connection.new("localhost", PORT, "information_schema")
45
+ res = conn.query("SELECT COUNT(*) FROM COLUMNS WHERE table_name = 'GLOBAL_STATUS'")
46
+ assert_equal res.class, Drizzle::Result
47
+ until (row = res.buffer_row).nil?
48
+ assert_equal "2", row[0]
49
+ end
50
+ end
51
+
52
+ should "create and drop a database" do
53
+ conn = Drizzle::Connection.new("localhost", PORT)
54
+ res = conn.query("CREATE DATABASE padraig")
55
+ res = conn.query("select table_schema from information_schema.tables where table_schema = 'padraig'")
56
+ assert_equal res.class, Drizzle::Result
57
+ res.buffer_result
58
+ assert_equal 1, res.columns.size
59
+ res.each do |row|
60
+ assert_equal "padraig", row[0]
61
+ end
62
+ res = conn.query("DROP DATABASE padraig")
63
+ res = conn.query("select table_schema from information_schema.tables where table_schema = 'padraig'")
64
+ assert_equal res.class, Drizzle::Result
65
+ res.buffer_result
66
+ assert_equal 1, res.columns.size
67
+ assert_equal true, res.rows.empty?
68
+ end
69
+
70
+ should "use different connection options" do
71
+ conn = Drizzle::Connection.new("localhost", PORT, "information_schema", [Drizzle::NONE])
72
+ res = conn.query("SELECT COUNT(*) FROM COLUMNS WHERE table_name = 'GLOBAL_STATUS'")
73
+ assert_equal res.class, Drizzle::Result
74
+ until (row = res.buffer_row).nil?
75
+ assert_equal "2", row[0]
76
+ end
77
+ conn = Drizzle::Connection.new("localhost", PORT, "information_schema", [Drizzle::NONE, Drizzle::MYSQL])
78
+ res = conn.query("SELECT COUNT(*) FROM COLUMNS WHERE table_name = 'GLOBAL_STATUS'")
79
+ assert_equal res.class, Drizzle::Result
80
+ until (row = res.buffer_row).nil?
81
+ assert_equal "2", row[0]
82
+ end
83
+ end
84
+
85
+ should "perform a query with a code block" do
86
+ conn = Drizzle::Connection.new("localhost", PORT, "information_schema", [Drizzle::NONE])
87
+ conn.query("SELECT COUNT(*) FROM COLUMNS WHERE table_name = 'GLOBAL_STATUS'") do |res|
88
+ assert_equal res.class, Drizzle::Result
89
+ until (row = res.buffer_row).nil?
90
+ assert_equal "2", row[0]
91
+ end
92
+ end
93
+ end
94
+
95
+ should "perform a simple show variables command" do
96
+ conn = Drizzle::Connection.new("localhost", PORT, "information_schema", [Drizzle::NONE])
97
+ assert_equal conn.class, Drizzle::Connection
98
+ res = conn.query("show variables")
99
+ assert_equal res.class, Drizzle::Result
100
+ res.buffer_result
101
+ end
102
+
103
+ end
@@ -0,0 +1,133 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestBasic < Test::Unit::TestCase
4
+
5
+ def setup
6
+ conn = Drizzle::Connection.new("localhost", PORT)
7
+ res = conn.query("CREATE DATABASE drizzleruby")
8
+ end
9
+
10
+ def teardown
11
+ conn = Drizzle::Connection.new("localhost", PORT)
12
+ res = conn.query("DROP DATABASE drizzleruby")
13
+ end
14
+
15
+ should "create and drop a table" do
16
+ conn = Drizzle::Connection.new("localhost", PORT, "drizzleruby")
17
+ res = conn.query("select table_schema from information_schema.tables where table_schema = 'drizzleruby'")
18
+ assert_equal res.class, Drizzle::Result
19
+ res.buffer_result
20
+ assert_equal 1, res.columns.size
21
+ res.each do |row|
22
+ assert_equal "drizzleruby", row[0]
23
+ end
24
+ res = conn.query("create table t1(a int, b varchar(255))")
25
+ res = conn.query("select table_schema, table_name from information_schema.tables where table_schema = 'drizzleruby'")
26
+ res.buffer_result
27
+ assert_equal 2, res.columns.size
28
+ res.each do |row|
29
+ assert_equal "t1", row[1]
30
+ end
31
+ res = conn.query("DROP TABLE t1")
32
+ res = conn.query("select table_name from information_schema.tables where table_schema = 'drizzleruby'")
33
+ assert_equal res.class, Drizzle::Result
34
+ res.buffer_result
35
+ assert_equal 1, res.columns.size
36
+ assert_equal true, res.rows.empty?
37
+ end
38
+
39
+ should "update affected rows appropriately" do
40
+ conn = Drizzle::Connection.new("localhost", PORT, "drizzleruby")
41
+ res = conn.query("select table_schema from information_schema.tables where table_schema = 'drizzleruby'")
42
+ assert_equal res.class, Drizzle::Result
43
+ res.buffer_result
44
+ assert_equal 1, res.columns.size
45
+ res.each do |row|
46
+ assert_equal "drizzleruby", row[0]
47
+ end
48
+ res = conn.query("create table t1(a int, b varchar(255))")
49
+ res = conn.query("select table_schema, table_name from information_schema.tables where table_schema = 'drizzleruby'")
50
+ res.buffer_result
51
+ assert_equal 2, res.columns.size
52
+ res.each do |row|
53
+ assert_equal "t1", row[1]
54
+ end
55
+ res = conn.query("insert into t1 values (1, 'padraig')")
56
+ assert_equal 1, res.affected_rows
57
+ assert_equal 0, res.insert_id
58
+ res = conn.query("insert into t1 values (2, 'sarah')")
59
+ assert_equal 1, res.affected_rows
60
+ assert_equal 0, res.insert_id
61
+ res = conn.query("select * from t1 where a = 2")
62
+ res.buffer_result
63
+ assert_equal 2, res.columns.size
64
+ res.each do |row|
65
+ assert_equal "2", row[0]
66
+ assert_equal "sarah", row[1]
67
+ end
68
+ res = conn.query("DROP TABLE t1")
69
+ res = conn.query("select table_name from information_schema.tables where table_schema = 'drizzleruby'")
70
+ assert_equal res.class, Drizzle::Result
71
+ res.buffer_result
72
+ assert_equal 1, res.columns.size
73
+ assert_equal true, res.rows.empty?
74
+ end
75
+
76
+ should "perform a multi-insert statement correctly" do
77
+ conn = Drizzle::Connection.new("localhost", PORT, "drizzleruby")
78
+ res = conn.query("select table_schema from information_schema.tables where table_schema = 'drizzleruby'")
79
+ assert_equal res.class, Drizzle::Result
80
+ res.buffer_result
81
+ assert_equal 1, res.columns.size
82
+ res.each do |row|
83
+ assert_equal "drizzleruby", row[0]
84
+ end
85
+ res = conn.query("create table t1(a int, b varchar(255))")
86
+ res = conn.query("select table_schema, table_name from information_schema.tables where table_schema = 'drizzleruby'")
87
+ res.buffer_result
88
+ assert_equal 2, res.columns.size
89
+ res.each do |row|
90
+ assert_equal "t1", row[1]
91
+ end
92
+ res = conn.query("insert into t1 values (1, 'padraig'), (2, 'sarah'), (3, 'tomas')")
93
+ assert_equal 3, res.affected_rows
94
+ res = conn.query("select * from t1 where a = 2")
95
+ res.buffer_result
96
+ assert_equal 2, res.columns.size
97
+ res.each do |row|
98
+ assert_equal "2", row[0]
99
+ assert_equal "sarah", row[1]
100
+ end
101
+ res = conn.query("DROP TABLE t1")
102
+ res = conn.query("select table_name from information_schema.tables where table_schema = 'drizzleruby'")
103
+ assert_equal res.class, Drizzle::Result
104
+ res.buffer_result
105
+ assert_equal 1, res.columns.size
106
+ assert_equal true, res.rows.empty?
107
+ end
108
+
109
+ should "insert and fetch a blob value correctly" do
110
+ conn = Drizzle::Connection.new("localhost", PORT, "drizzleruby")
111
+ res = conn.query("create table t1(a int, b blob)")
112
+ res = conn.query("insert into t1 values (1, 'padraig'), (2, 'sarah'), (3, 'tomas')")
113
+ assert_equal 3, res.affected_rows
114
+ res = conn.query("insert into t1 values (4, null), (5, 'blahblahblah'), (6, 'southy')")
115
+ assert_equal 3, res.affected_rows
116
+ res = conn.query("select * from t1 where a = 2")
117
+ res.buffer_result
118
+ assert_equal 2, res.columns.size
119
+ res.each do |row|
120
+ assert_equal "2", row[0]
121
+ assert_equal "sarah", row[1]
122
+ end
123
+ res = conn.query("select * from t1 where a = 4")
124
+ res.buffer_result
125
+ assert_equal 2, res.columns.size
126
+ res.each do |row|
127
+ assert_equal "4", row[0]
128
+ assert_equal nil, row[1]
129
+ end
130
+ res = conn.query("DROP TABLE t1")
131
+ end
132
+
133
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: drizzle
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Padraig O'Sullivan
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-04-13 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: thoughtbot-shoulda
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ description: An interface to Drizzle for Ruby that uses libdrizzle
33
+ email: osullivan.padraig@gmail.com
34
+ executables: []
35
+
36
+ extensions: []
37
+
38
+ extra_rdoc_files:
39
+ - LICENSE
40
+ - README.rdoc
41
+ files:
42
+ - LICENSE
43
+ - README.rdoc
44
+ - Rakefile
45
+ - VERSION
46
+ - lib/drizzle.rb
47
+ - lib/drizzle/connection.rb
48
+ - lib/drizzle/drizzle.rb
49
+ - lib/drizzle/exceptions.rb
50
+ - lib/drizzle/ffidrizzle.rb
51
+ - lib/drizzle/result.rb
52
+ - test/helper.rb
53
+ - test/test_basic.rb
54
+ - test/test_complex.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/posulliv/drizzle-ruby
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project: drizzle-ruby
81
+ rubygems_version: 1.3.6
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: A ruby interface to Drizzle using libdrizzle
85
+ test_files:
86
+ - test/helper.rb
87
+ - test/test_basic.rb
88
+ - test/test_complex.rb