drizzle 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +7 -0
- data/Rakefile +58 -0
- data/VERSION +1 -0
- data/lib/drizzle.rb +15 -0
- data/lib/drizzle/connection.rb +207 -0
- data/lib/drizzle/drizzle.rb +58 -0
- data/lib/drizzle/exceptions.rb +28 -0
- data/lib/drizzle/ffidrizzle.rb +130 -0
- data/lib/drizzle/result.rb +95 -0
- data/test/helper.rb +28 -0
- data/test/test_basic.rb +103 -0
- data/test/test_complex.rb +133 -0
- metadata +88 -0
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.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -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
|
data/lib/drizzle.rb
ADDED
@@ -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
|
data/test/helper.rb
ADDED
@@ -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
|
data/test/test_basic.rb
ADDED
@@ -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
|