rdo 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +7 -0
- data/README.md +19 -7
- data/Rakefile +13 -1
- data/ext/rdo/extconf.rb +7 -0
- data/ext/rdo/rdo.c +175 -0
- data/lib/rdo.rb +3 -0
- data/lib/rdo/driver.rb +30 -0
- data/lib/rdo/version.rb +1 -1
- data/rdo.gemspec +2 -1
- data/spec/rdo/driver_spec.rb +96 -0
- data/spec/support/driver_with_backwards_quote.rb +29 -0
- data/spec/support/driver_with_everything.rb +2 -1
- data/spec/support/driver_without_statements.rb +2 -1
- metadata +33 -12
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -6,7 +6,9 @@ interface. Where a feature is not natively supported by the DBMS—for example,
|
|
6
6
|
prepared statements—it is seamlessly emulated, so you don't need to code
|
7
7
|
around it.
|
8
8
|
|
9
|
-
It targets **Ruby
|
9
|
+
It targets **Ruby 1.9** and newer.
|
10
|
+
|
11
|
+
[![Build Status](https://secure.travis-ci.org/d11wtq/rdo.png?branch=master)](http://travis-ci.org/d11wtq/rdo)
|
10
12
|
|
11
13
|
``` ruby
|
12
14
|
require "rdo"
|
@@ -103,21 +105,27 @@ And then execute:
|
|
103
105
|
<td>sqlite, sqlite3</td>
|
104
106
|
<td><a href="https://github.com/d11wtq/rdo-sqlite">rdo-sqlite</a></td>
|
105
107
|
<td><a href="https://github.com/d11wtq">d11wtq</a></td>
|
106
|
-
<td>
|
108
|
+
<td>
|
109
|
+
<img src="https://secure.travis-ci.org/d11wtq/rdo-sqlite.png?branch=master"
|
110
|
+
alt="Build Status" title="Build Status" />
|
111
|
+
</td>
|
107
112
|
</tr>
|
108
113
|
<tr>
|
109
114
|
<th>PostgreSQL</th>
|
110
115
|
<td>postgresql, postgres</td>
|
111
116
|
<td><a href="https://github.com/d11wtq/rdo-postgres">rdo-postgres</a></td>
|
112
117
|
<td><a href="https://github.com/d11wtq">d11wtq</a></td>
|
113
|
-
<td>
|
118
|
+
<td>
|
119
|
+
<img src="https://secure.travis-ci.org/d11wtq/rdo-postgres.png?branch=master"
|
120
|
+
alt="Build Status" title="Build Status" />
|
121
|
+
</td>
|
114
122
|
</tr>
|
115
123
|
<tr>
|
116
124
|
<th>MySQL</th>
|
117
125
|
<td>mysql</td>
|
118
126
|
<td><a href="https://github.com/d11wtq/rdo-mysql">rdo-mysql</a></td>
|
119
127
|
<td><a href="https://github.com/d11wtq">d11wtq</a></td>
|
120
|
-
<td>
|
128
|
+
<td>In development</td>
|
121
129
|
</tr>
|
122
130
|
</tbody>
|
123
131
|
</table>
|
@@ -165,7 +173,7 @@ p conn.open? #=> true
|
|
165
173
|
### One-time use connections
|
166
174
|
|
167
175
|
If you pass a block to RDO.connect, RDO yields the connection into the block,
|
168
|
-
returns the result of the block,
|
176
|
+
returns the result of the block, then closes the connection.
|
169
177
|
|
170
178
|
``` ruby
|
171
179
|
puts RDO.open("sqlite:some.db") do |c|
|
@@ -254,8 +262,8 @@ include any error messaage provided by the DBMS.
|
|
254
262
|
### Tread carefully, there be danger ahead
|
255
263
|
|
256
264
|
While driver developers are expected to provide a suitable implementation,
|
257
|
-
it is generally riskier to
|
258
|
-
|
265
|
+
it is generally riskier to escape and interpolate inputs directly into the
|
266
|
+
SQL than it is to use bind parameters. There are times where you might
|
259
267
|
need to escape some input yourself, however. For that, you can call #quote.
|
260
268
|
|
261
269
|
``` ruby
|
@@ -300,6 +308,10 @@ When sending pull requests, please use topic branches—don't send a pull
|
|
300
308
|
request from the master branch of your fork, as that may change
|
301
309
|
unintentionally.
|
302
310
|
|
311
|
+
I haven't looked at what I need to change to have the drivers compile on
|
312
|
+
Windows yet, but I will do. If anybody beats me to it, pull requests will
|
313
|
+
be gladly accepted! I'll probably add some thin JDBC wrappers for jRuby.
|
314
|
+
|
303
315
|
### Writing a driver for RDO
|
304
316
|
|
305
317
|
The more drivers that RDO has support for, the better. Writing drivers for
|
data/Rakefile
CHANGED
@@ -1,2 +1,14 @@
|
|
1
|
-
#!/usr/bin/env rake
|
2
1
|
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require "rake/extensiontask"
|
4
|
+
|
5
|
+
Rake::ExtensionTask.new('rdo') do |ext|
|
6
|
+
ext.lib_dir = File.join('lib', 'rdo')
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Run the full RSpec suite"
|
10
|
+
RSpec::Core::RakeTask.new('spec') do |t|
|
11
|
+
t.pattern = 'spec/'
|
12
|
+
end
|
13
|
+
|
14
|
+
Rake::Task['spec'].prerequisites << :compile
|
data/ext/rdo/extconf.rb
ADDED
data/ext/rdo/rdo.c
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
/*
|
2
|
+
* RDO—Ruby Data Objects.
|
3
|
+
* Copyright © 2012 Chris Corbyn.
|
4
|
+
*
|
5
|
+
* See LICENSE file for details.
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include <ruby.h>
|
9
|
+
#include <stdio.h>
|
10
|
+
#include <string.h>
|
11
|
+
|
12
|
+
/** Quote parameters in params array */
|
13
|
+
static char ** rdo_driver_quote_params(VALUE self, VALUE * args, int argc, long * len) {
|
14
|
+
char ** quoted = malloc(sizeof(char *) * argc);
|
15
|
+
int idx = 0;
|
16
|
+
VALUE tmp;
|
17
|
+
|
18
|
+
*len = 0;
|
19
|
+
|
20
|
+
for (; idx < argc; ++idx) {
|
21
|
+
switch (TYPE(args[idx])) {
|
22
|
+
case T_NIL:
|
23
|
+
quoted[idx] = strdup("NULL");
|
24
|
+
*len += 4;
|
25
|
+
break;
|
26
|
+
|
27
|
+
case T_FIXNUM:
|
28
|
+
case T_FLOAT:
|
29
|
+
tmp = rb_funcall(args[idx], rb_intern("to_s"), 0);
|
30
|
+
Check_Type(tmp, T_STRING);
|
31
|
+
|
32
|
+
quoted[idx] = strdup(RSTRING_PTR(tmp));
|
33
|
+
*len += RSTRING_LEN(tmp);
|
34
|
+
break;
|
35
|
+
|
36
|
+
default:
|
37
|
+
tmp = rb_funcall(self, rb_intern("quote"), 1, args[idx]);
|
38
|
+
Check_Type(tmp, T_STRING);
|
39
|
+
|
40
|
+
quoted[idx] = malloc(sizeof(char) * (RSTRING_LEN(tmp) + 3));
|
41
|
+
sprintf(quoted[idx], "'%s'", RSTRING_PTR(tmp));
|
42
|
+
*len += 2 + RSTRING_LEN(tmp);
|
43
|
+
break;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
return quoted;
|
48
|
+
}
|
49
|
+
|
50
|
+
/** Release heap memory allocated for quoted params */
|
51
|
+
static void rdo_driver_free_params(char ** quoted, int len) {
|
52
|
+
int i;
|
53
|
+
for (i = 0; i < len; ++i) free(quoted[i]);
|
54
|
+
free(quoted);
|
55
|
+
}
|
56
|
+
|
57
|
+
/**
|
58
|
+
* Takes String stmt, which contains ? markers and interpolates the values in Array params.
|
59
|
+
*
|
60
|
+
* Each value in Array params that is not NilClass, Fixnum or Float is passed
|
61
|
+
* to #quote on the Driver.
|
62
|
+
*
|
63
|
+
* Non-numeric values are surrounded by String quote.
|
64
|
+
*
|
65
|
+
* @param VALUE (String) stmt
|
66
|
+
* SQL, possibly containining '?' markers.
|
67
|
+
*
|
68
|
+
* @param VALUE (Array) params
|
69
|
+
* arguments to interpolate in place of the ? markers
|
70
|
+
*
|
71
|
+
* @return VALUE (String)
|
72
|
+
* the same SQL with the parameters interpolated.
|
73
|
+
*/
|
74
|
+
static VALUE rdo_driver_interpolate(VALUE self, VALUE stmt, VALUE params) {
|
75
|
+
Check_Type(stmt, T_STRING);
|
76
|
+
Check_Type(params, T_ARRAY);
|
77
|
+
|
78
|
+
int argc = RARRAY_LEN(params);
|
79
|
+
long buflen = 0;
|
80
|
+
char ** quoted_params = rdo_driver_quote_params(
|
81
|
+
self,
|
82
|
+
RARRAY_PTR(params), argc,
|
83
|
+
&buflen);
|
84
|
+
char buffer[buflen + RSTRING_LEN(stmt) + 1];
|
85
|
+
|
86
|
+
char * b = buffer;
|
87
|
+
char * s = RSTRING_PTR(stmt);
|
88
|
+
int n = 0;
|
89
|
+
|
90
|
+
int insquote = 0;
|
91
|
+
int indquote = 0;
|
92
|
+
int inmlcmt = 0;
|
93
|
+
int inslcmt = 0;
|
94
|
+
|
95
|
+
// this loop is intentionally kept procedural (for performance)
|
96
|
+
for (; *s; ++s, ++b) {
|
97
|
+
switch (*s) {
|
98
|
+
case '?':
|
99
|
+
if (insquote || indquote || inmlcmt || inslcmt) {
|
100
|
+
*b = *s;
|
101
|
+
} else {
|
102
|
+
if (n < argc) {
|
103
|
+
strcpy(b, quoted_params[n]);
|
104
|
+
b += strlen(quoted_params[n]) - 1;
|
105
|
+
} else {
|
106
|
+
*b = *s;
|
107
|
+
}
|
108
|
+
++n;
|
109
|
+
}
|
110
|
+
break;
|
111
|
+
|
112
|
+
case '-':
|
113
|
+
if (!insquote && !indquote && !inmlcmt && *(s + 1) == '-') {
|
114
|
+
inslcmt = 1;
|
115
|
+
*(b++) = *(s++);
|
116
|
+
}
|
117
|
+
*b = *s;
|
118
|
+
break;
|
119
|
+
|
120
|
+
case '\r':
|
121
|
+
case '\n':
|
122
|
+
inslcmt = 0;
|
123
|
+
*b = *s;
|
124
|
+
break;
|
125
|
+
|
126
|
+
case '/':
|
127
|
+
if (!insquote && !indquote && !inslcmt && *(s + 1) == '*') {
|
128
|
+
++inmlcmt;
|
129
|
+
*(b++) = *(s++);
|
130
|
+
}
|
131
|
+
*b = *s;
|
132
|
+
break;
|
133
|
+
|
134
|
+
case '*':
|
135
|
+
if (inmlcmt && *(s + 1) == '/') {
|
136
|
+
--inmlcmt;
|
137
|
+
*(b++) = *(s++);
|
138
|
+
}
|
139
|
+
*b = *s;
|
140
|
+
break;
|
141
|
+
|
142
|
+
case '\'':
|
143
|
+
if (!indquote && !inmlcmt && !inslcmt) insquote = !insquote;
|
144
|
+
*b = *s;
|
145
|
+
break;
|
146
|
+
|
147
|
+
case '"':
|
148
|
+
if (!insquote && !inmlcmt && !inslcmt) indquote = !indquote;
|
149
|
+
*b = *s;
|
150
|
+
break;
|
151
|
+
|
152
|
+
default:
|
153
|
+
*b = *s;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
*b = '\0';
|
158
|
+
|
159
|
+
rdo_driver_free_params(quoted_params, argc);
|
160
|
+
|
161
|
+
if (n != argc) {
|
162
|
+
rb_raise(rb_eArgError,
|
163
|
+
"Bind parameter mismatch (%i for %i) in query %s",
|
164
|
+
argc, n, RSTRING_PTR(stmt));
|
165
|
+
}
|
166
|
+
|
167
|
+
return rb_str_new2(buffer);
|
168
|
+
}
|
169
|
+
|
170
|
+
/** Extension initializer */
|
171
|
+
void Init_rdo(void) {
|
172
|
+
rb_require("rdo/driver");
|
173
|
+
VALUE cDriver = rb_path2class("RDO::Driver");
|
174
|
+
rb_define_method(cDriver, "interpolate", rdo_driver_interpolate, 2);
|
175
|
+
}
|
data/lib/rdo.rb
CHANGED
data/lib/rdo/driver.rb
CHANGED
@@ -99,6 +99,9 @@ module RDO
|
|
99
99
|
|
100
100
|
# Escape a given value for safe interpolation into a statement.
|
101
101
|
#
|
102
|
+
# The value may be any type of Object and will be formatted to a String
|
103
|
+
# as needed.
|
104
|
+
#
|
102
105
|
# This should be avoided where the driver natively supports bind parameters.
|
103
106
|
#
|
104
107
|
# Drivers MUST override this with a RDBMS-specific solution.
|
@@ -111,6 +114,33 @@ module RDO
|
|
111
114
|
def quote(value)
|
112
115
|
end
|
113
116
|
|
117
|
+
protected
|
118
|
+
|
119
|
+
# Replace the values in params with the '?' markers in sql.
|
120
|
+
#
|
121
|
+
# This method exists for drivers that don't natively support bind
|
122
|
+
# parameters, or don't fully support them (e.g. MySQL). The
|
123
|
+
# implementation is done in C, since the scanning routine is
|
124
|
+
# considerably faster.
|
125
|
+
#
|
126
|
+
# Each value in params is processed according to its type:
|
127
|
+
#
|
128
|
+
# - NilClass, Fixnum, Float, inserted as literals (NULL or a number)
|
129
|
+
# - String passed through #quote, then wrapped in single quotes
|
130
|
+
# - All other objects converted to String then processed as a String
|
131
|
+
#
|
132
|
+
# @param [String] sql
|
133
|
+
# a String of SQL including '?' markers
|
134
|
+
#
|
135
|
+
# @param [Array] params
|
136
|
+
# an Array of objects to interpolate
|
137
|
+
#
|
138
|
+
# @return [String]
|
139
|
+
# the SQL to be executed
|
140
|
+
def interpolate(sql, params)
|
141
|
+
# implemented in ext/rdo/rdo.c
|
142
|
+
end
|
143
|
+
|
114
144
|
private
|
115
145
|
|
116
146
|
def emulated_statement_executor(stmt)
|
data/lib/rdo/version.rb
CHANGED
data/rdo.gemspec
CHANGED
@@ -21,7 +21,6 @@ Gem::Specification.new do |gem|
|
|
21
21
|
* Type casting to Ruby types
|
22
22
|
* Time zone handling (via the DBMS, not via some crazy time logic in Ruby)
|
23
23
|
* Native bind values parameterization of queries, where supported by the DBMS
|
24
|
-
* Buffered result sets (i.e. cursors, to avoid exhausting memory)
|
25
24
|
* Retrieve query info from executed commands (e.g. affected rows)
|
26
25
|
* Access RETURNING values just like any read query
|
27
26
|
* Native prepared statements where supported, emulated where not
|
@@ -48,6 +47,8 @@ Gem::Specification.new do |gem|
|
|
48
47
|
gem.name = "rdo"
|
49
48
|
gem.require_paths = ["lib"]
|
50
49
|
gem.version = RDO::VERSION
|
50
|
+
gem.extensions = ["ext/rdo/extconf.rb"]
|
51
51
|
|
52
52
|
gem.add_development_dependency "rspec"
|
53
|
+
gem.add_development_dependency "rake-compiler"
|
53
54
|
end
|
data/spec/rdo/driver_spec.rb
CHANGED
@@ -26,4 +26,100 @@ describe RDO::Driver do
|
|
26
26
|
stmt.execute(true).should be_a_kind_of(RDO::Result)
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
describe "#interpolate" do
|
31
|
+
let(:driver) { RDO::DriverWithBackwardsQuote.new }
|
32
|
+
|
33
|
+
it "interpolates nil as literal NULL" do
|
34
|
+
driver.send(:interpolate, "SELECT ?", [nil]).should == "SELECT NULL"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "interpolates a Fixnum as a literal integer" do
|
38
|
+
driver.send(:interpolate, "SELECT ? * 4", [123456789]).should == "SELECT 123456789 * 4"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "interpolates a Float as a literal float" do
|
42
|
+
driver.send(:interpolate, "SELECT ? * 4", [12.34]).should == "SELECT 12.34 * 4"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "interpolates a String as a quoted String" do
|
46
|
+
driver.send(:interpolate, "SELECT ?", ["string"]).should == "SELECT 'gnirts'"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "interpolates an Object as a quoted String" do
|
50
|
+
driver.send(:interpolate, "SELECT ?", [Date.new(2012, 9, 22)]).should == "SELECT '22-90-2102'"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "interpolates multiple params" do
|
54
|
+
driver.send(
|
55
|
+
:interpolate,
|
56
|
+
"SELECT ?, ?, ?",
|
57
|
+
["test", 42, nil]
|
58
|
+
).should == "SELECT 'tset', 42, NULL"
|
59
|
+
end
|
60
|
+
|
61
|
+
context "with not enough params" do
|
62
|
+
it "raises an ArgumentError" do
|
63
|
+
expect {
|
64
|
+
driver.send(
|
65
|
+
:interpolate,
|
66
|
+
"SELECT ?, ?, ?",
|
67
|
+
["test", 42]
|
68
|
+
)
|
69
|
+
}.to raise_error(ArgumentError)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "with too many params" do
|
74
|
+
it "raises an ArgumentError" do
|
75
|
+
expect {
|
76
|
+
driver.send(
|
77
|
+
:interpolate,
|
78
|
+
"SELECT ?, ?",
|
79
|
+
["test", 42, nil]
|
80
|
+
)
|
81
|
+
}.to raise_error(ArgumentError)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "with marks placed inside single quotes" do
|
86
|
+
it "ignores the quoted marks" do
|
87
|
+
driver.send(
|
88
|
+
:interpolate,
|
89
|
+
"SELECT 'quoted?', ?, ?",
|
90
|
+
["test", 42]
|
91
|
+
).should == "SELECT 'quoted?', 'tset', 42"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "with marks placed inside double quotes" do
|
96
|
+
it "ignores the quoted marks" do
|
97
|
+
driver.send(
|
98
|
+
:interpolate,
|
99
|
+
"SELECT \"quoted?\", ?, ?",
|
100
|
+
["test", 42]
|
101
|
+
).should == "SELECT \"quoted?\", 'tset', 42"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "with marks placed inside multiline comments" do
|
106
|
+
it "ignores the comments marks" do
|
107
|
+
driver.send(
|
108
|
+
:interpolate,
|
109
|
+
"SELECT /* commented? */ ?, ?",
|
110
|
+
["test", 42]
|
111
|
+
).should == "SELECT /* commented? */ 'tset', 42"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "with marks placed inside line comments" do
|
116
|
+
it "ignores the comments marks" do
|
117
|
+
driver.send(
|
118
|
+
:interpolate,
|
119
|
+
"SELECT\n -- commented?\n ?, ?",
|
120
|
+
["test", 42]
|
121
|
+
).should == "SELECT\n -- commented?\n 'tset', 42"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
29
125
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rdo"
|
2
|
+
|
3
|
+
module RDO
|
4
|
+
class DriverWithBackwardsQuote < Driver
|
5
|
+
def open
|
6
|
+
@open = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def open?
|
10
|
+
!!@open
|
11
|
+
end
|
12
|
+
|
13
|
+
def close
|
14
|
+
@open = false
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute(stmt, *args)
|
19
|
+
Result.new([])
|
20
|
+
end
|
21
|
+
|
22
|
+
def quote(obj)
|
23
|
+
obj.to_s.reverse
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Connection.register_driver(:rdo_with_backwards_quote, DriverWithBackwardsQuote)
|
28
|
+
end
|
29
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rdo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake-compiler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
30
46
|
description: ! "== Ruby Data Objects\n\nIf you're building something in Ruby that
|
31
47
|
needs access to a database, you may\nopt to use an ORM like ActiveRecord, DataMapper
|
32
48
|
or Sequel. But if your needs\ndon't fit well with an ORM—maybe you're even writing
|
@@ -36,27 +52,30 @@ description: ! "== Ruby Data Objects\n\nIf you're building something in Ruby tha
|
|
36
52
|
library:\n\n * Consistent API to connect to various DBMS's\n * Type casting to
|
37
53
|
Ruby types\n * Time zone handling (via the DBMS, not via some crazy time logic
|
38
54
|
in Ruby)\n * Native bind values parameterization of queries, where supported by
|
39
|
-
the DBMS\n *
|
40
|
-
\ *
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
C.\n\nSee the official README for full details."
|
55
|
+
the DBMS\n * Retrieve query info from executed commands (e.g. affected rows)\n
|
56
|
+
\ * Access RETURNING values just like any read query\n * Native prepared statements
|
57
|
+
where supported, emulated where not\n * Results given using simple core Ruby data
|
58
|
+
types\n\n== RDBMS Support\n\nSupport for each RDBMS is provided in separate gems,
|
59
|
+
so as to minimize the\ninstallation requirements and to facilitate the maintenace
|
60
|
+
of each driver. Many\ngems are maintained by separate users who work more closely
|
61
|
+
with those RDBMS's.\n\nDue to the nature of this gem, most of the nitty-gritty code
|
62
|
+
is actually\nwritten in C.\n\nSee the official README for full details."
|
48
63
|
email:
|
49
64
|
- chris@w3style.co.uk
|
50
65
|
executables: []
|
51
|
-
extensions:
|
66
|
+
extensions:
|
67
|
+
- ext/rdo/extconf.rb
|
52
68
|
extra_rdoc_files: []
|
53
69
|
files:
|
54
70
|
- .gitignore
|
55
71
|
- .rspec
|
72
|
+
- .travis.yml
|
56
73
|
- Gemfile
|
57
74
|
- LICENSE
|
58
75
|
- README.md
|
59
76
|
- Rakefile
|
77
|
+
- ext/rdo/extconf.rb
|
78
|
+
- ext/rdo/rdo.c
|
60
79
|
- lib/rdo.rb
|
61
80
|
- lib/rdo/connection.rb
|
62
81
|
- lib/rdo/driver.rb
|
@@ -75,6 +94,7 @@ files:
|
|
75
94
|
- spec/rdo/statement_spec.rb
|
76
95
|
- spec/rdo/util_spec.rb
|
77
96
|
- spec/spec_helper.rb
|
97
|
+
- spec/support/driver_with_backwards_quote.rb
|
78
98
|
- spec/support/driver_with_everything.rb
|
79
99
|
- spec/support/driver_without_statements.rb
|
80
100
|
- util/macros.h
|
@@ -111,5 +131,6 @@ test_files:
|
|
111
131
|
- spec/rdo/statement_spec.rb
|
112
132
|
- spec/rdo/util_spec.rb
|
113
133
|
- spec/spec_helper.rb
|
134
|
+
- spec/support/driver_with_backwards_quote.rb
|
114
135
|
- spec/support/driver_with_everything.rb
|
115
136
|
- spec/support/driver_without_statements.rb
|