oedipus 0.0.9 → 0.0.10
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/ext/oedipus/lexing.c +96 -0
- data/ext/oedipus/lexing.h +17 -0
- data/ext/oedipus/oedipus.c +53 -28
- data/ext/oedipus/oedipus.h +0 -1
- data/lib/oedipus/version.rb +1 -1
- data/spec/integration/connection_spec.rb +15 -0
- metadata +10 -8
@@ -0,0 +1,96 @@
|
|
1
|
+
/*-- encoding: utf-8 --*/
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Oedipus Sphinx 2 Search.
|
5
|
+
* Copyright © 2012 Chris Corbyn.
|
6
|
+
*
|
7
|
+
* See LICENSE file for details.
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include "lexing.h"
|
11
|
+
|
12
|
+
/* WARNING: Complex pointer (but fast) arithmetic in here... avert your eyes */
|
13
|
+
|
14
|
+
int odp_scan_until_char(char stop, char ** sql_ptr, char ** dest_ptr, unsigned long len) {
|
15
|
+
char * end = *sql_ptr + len;
|
16
|
+
|
17
|
+
for (; *sql_ptr < end; ++(*sql_ptr)) {
|
18
|
+
*((*dest_ptr)++) = **sql_ptr;
|
19
|
+
|
20
|
+
if (**sql_ptr == '\\') {
|
21
|
+
if (*sql_ptr < end) {
|
22
|
+
*((*dest_ptr)++) = *(++(*sql_ptr)); // consume char following escape
|
23
|
+
}
|
24
|
+
} else if (**sql_ptr == stop) {
|
25
|
+
return 1;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
return 0;
|
30
|
+
}
|
31
|
+
|
32
|
+
int odp_scan_multi_line_comment(char ** sql_ptr, char ** dest_ptr, unsigned long len) {
|
33
|
+
char * end = *sql_ptr + len;
|
34
|
+
|
35
|
+
for (; *sql_ptr < end; ++(*sql_ptr)) {
|
36
|
+
*((*dest_ptr)++) = **sql_ptr;
|
37
|
+
|
38
|
+
if (**sql_ptr == '*') {
|
39
|
+
if ((*sql_ptr < end) && (*((*dest_ptr)++) = *(++(*sql_ptr))) == '/') {
|
40
|
+
return 1;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
return 0;
|
46
|
+
}
|
47
|
+
|
48
|
+
int odp_scan_until_marker(char ** sql_ptr, char ** dest_ptr, long len) {
|
49
|
+
char * end = *sql_ptr + len;
|
50
|
+
char c;
|
51
|
+
|
52
|
+
for (; *sql_ptr < end; ++(*sql_ptr)) {
|
53
|
+
c = **sql_ptr;
|
54
|
+
*((*dest_ptr)++) = c;
|
55
|
+
|
56
|
+
switch (c) {
|
57
|
+
case '\\':
|
58
|
+
if (*sql_ptr < end) {
|
59
|
+
*((*dest_ptr)++) = *(++(*sql_ptr));
|
60
|
+
}
|
61
|
+
break;
|
62
|
+
case '\'':
|
63
|
+
++(*sql_ptr);
|
64
|
+
odp_scan_until_char('\'', sql_ptr, dest_ptr, end - *sql_ptr);
|
65
|
+
break;
|
66
|
+
case '"':
|
67
|
+
++(*sql_ptr);
|
68
|
+
odp_scan_until_char('"', sql_ptr, dest_ptr, end - *sql_ptr);
|
69
|
+
break;
|
70
|
+
case '/':
|
71
|
+
if ((*sql_ptr < end) && *(*sql_ptr + 1) == '*') {
|
72
|
+
*((*dest_ptr)++) = *(++(*sql_ptr)); // consume '*' following '/'
|
73
|
+
++(*sql_ptr);
|
74
|
+
odp_scan_multi_line_comment(sql_ptr, dest_ptr, end - *sql_ptr);
|
75
|
+
}
|
76
|
+
break;
|
77
|
+
case '#':
|
78
|
+
++(*sql_ptr);
|
79
|
+
odp_scan_until_char('\n', sql_ptr, dest_ptr, end - *sql_ptr);
|
80
|
+
break;
|
81
|
+
case '-':
|
82
|
+
// FIXME: This shouldn't really work for things like ------ comment
|
83
|
+
if (((*sql_ptr + 1) < end) && *(*sql_ptr + 1) == '-' && *(*sql_ptr + 2) == ' ') {
|
84
|
+
++(*sql_ptr);
|
85
|
+
odp_scan_until_char('\n', sql_ptr, dest_ptr, end - *sql_ptr);
|
86
|
+
}
|
87
|
+
break;
|
88
|
+
case '?':
|
89
|
+
++(*sql_ptr); // discard
|
90
|
+
--(*dest_ptr); // unconsume
|
91
|
+
return 1;
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
return 0;
|
96
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
/*-- encoding: utf-8 --*/
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Oedipus Sphinx 2 Search.
|
5
|
+
* Copyright © 2012 Chris Corbyn.
|
6
|
+
*
|
7
|
+
* See LICENSE file for details.
|
8
|
+
*/
|
9
|
+
|
10
|
+
/*! Consume input from the string pointed to by sql_ptr, into the string pointed to by dest_ptr, until stop is reached (inclusive) */
|
11
|
+
int odp_scan_until_char(char stop, char ** sql_ptr, char ** dest_ptr, unsigned long len);
|
12
|
+
|
13
|
+
/*! Consume input from the string pointed to by sql_ptr, into the string pointed to by dest_ptr, until the end of a multi-line comment is reached (inclusive) */
|
14
|
+
int odp_scan_multi_line_comment(char ** sql_ptr, char ** dest_ptr, unsigned long len);
|
15
|
+
|
16
|
+
/*! Consume input from the string pointed to by sql_ptr, into the string pointed to by dest_ptr, until '?' is found */
|
17
|
+
int odp_scan_until_marker(char ** sql_ptr, char ** dest_ptr, long len);
|
data/ext/oedipus/oedipus.c
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
*/
|
9
9
|
|
10
10
|
#include "oedipus.h"
|
11
|
+
#include "lexing.h"
|
11
12
|
|
12
13
|
/* -- Public methods -- */
|
13
14
|
|
@@ -190,47 +191,71 @@ static void odp_free(OdpMysql * conn) {
|
|
190
191
|
}
|
191
192
|
|
192
193
|
static VALUE odp_replace_bind_values(OdpMysql * conn, VALUE sql, VALUE * bind_values, int num_values) {
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
194
|
+
// FIXME: Refactor this whole method, somehow... use a struct instead of a gazillion variables, so other functions can be called
|
195
|
+
char * sql_str;
|
196
|
+
unsigned long sql_len;
|
197
|
+
char * str_values[num_values];
|
198
|
+
unsigned long escaped_value_lengths[num_values];
|
199
|
+
unsigned long escaped_sql_len;
|
200
|
+
int i;
|
200
201
|
|
201
|
-
|
202
|
+
sql_str = RSTRING_PTR(sql);
|
203
|
+
sql_len = strlen(sql_str);
|
204
|
+
escaped_sql_len = sql_len;
|
202
205
|
|
203
206
|
for (i = 0; i < num_values; ++i) {
|
204
|
-
if (
|
205
|
-
|
207
|
+
if (T_STRING == TYPE(bind_values[i])) {
|
208
|
+
str_values[i] = RSTRING_PTR(bind_values[i]);
|
209
|
+
} else if (ODP_KIND_OF_P(bind_values[i], rb_cNumeric) && !(ODP_KIND_OF_P(bind_values[i], rb_cInteger))) {
|
210
|
+
str_values[i] = RSTRING_PTR(ODP_TO_S(ODP_TO_F(bind_values[i])));
|
211
|
+
} else {
|
212
|
+
str_values[i] = RSTRING_PTR(ODP_TO_S(bind_values[i]));
|
206
213
|
}
|
207
214
|
|
208
|
-
|
215
|
+
escaped_value_lengths[i] = (strlen(str_values[i]) * 2 + 3);
|
216
|
+
escaped_sql_len += escaped_value_lengths[i];
|
217
|
+
}
|
218
|
+
|
219
|
+
{
|
220
|
+
char escaped_sql_str[escaped_sql_len];
|
221
|
+
char * sql_end;
|
222
|
+
char * dest;
|
209
223
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
}
|
224
|
+
sql_end = sql_str + sql_len;
|
225
|
+
dest = escaped_sql_str;
|
226
|
+
|
227
|
+
for (i = 0; i < num_values; ++i) {
|
228
|
+
char * str = str_values[i];
|
229
|
+
char len = strlen(str);
|
230
|
+
long pos = 0;
|
218
231
|
|
219
|
-
{
|
220
|
-
|
221
|
-
|
232
|
+
if (!(odp_scan_until_marker(&sql_str, &dest, sql_end - sql_str))) {
|
233
|
+
break;
|
234
|
+
}
|
222
235
|
|
223
|
-
|
224
|
-
char
|
236
|
+
if (T_STRING == TYPE(bind_values[i])) {
|
237
|
+
char escaped_str[escaped_value_lengths[i]];
|
238
|
+
char quoted_str[escaped_value_lengths[i]];
|
225
239
|
|
226
|
-
mysql_real_escape_string(conn->ptr, escaped_str,
|
240
|
+
mysql_real_escape_string(conn->ptr, escaped_str, str, len);
|
227
241
|
sprintf(quoted_str, "'%s'", escaped_str);
|
228
|
-
|
242
|
+
|
243
|
+
str = quoted_str;
|
244
|
+
len = strlen(quoted_str);
|
245
|
+
}
|
246
|
+
|
247
|
+
for (pos = 0; pos < len; ++pos) {
|
248
|
+
*(dest++) = str[pos];
|
229
249
|
}
|
230
250
|
}
|
231
|
-
}
|
232
251
|
|
233
|
-
|
252
|
+
// copy remainder
|
253
|
+
for (; sql_str < sql_end; ++sql_str) {
|
254
|
+
*(dest++) = *sql_str;
|
255
|
+
}
|
256
|
+
|
257
|
+
return rb_str_new(escaped_sql_str, dest - escaped_sql_str);
|
258
|
+
}
|
234
259
|
}
|
235
260
|
|
236
261
|
static VALUE odp_cast_value(MYSQL_FIELD f, char * v, unsigned long len) {
|
data/ext/oedipus/oedipus.h
CHANGED
@@ -14,7 +14,6 @@
|
|
14
14
|
#define ODP_TO_S(v) rb_funcall(v, rb_intern("to_s"), 0)
|
15
15
|
#define ODP_TO_F(n) rb_funcall(n, rb_intern("to_f"), 0)
|
16
16
|
#define ODP_KIND_OF_P(v, type) (rb_funcall(v, rb_intern("kind_of?"), 1, type) == Qtrue)
|
17
|
-
#define ODP_STR_SUB(s, pos, replace) rb_funcall(s, rb_intern("[]="), 2, pos, replace)
|
18
17
|
|
19
18
|
/*! Internal struct used to reference a mysql connection */
|
20
19
|
typedef struct {
|
data/lib/oedipus/version.rb
CHANGED
@@ -120,5 +120,20 @@ describe Oedipus::Connection do
|
|
120
120
|
it "accepts string bind parameters" do
|
121
121
|
conn.execute("REPLACE INTO posts_rt (id, title) VALUES (?, ?)", 1, "an example with `\"this (quoted) string\\'")
|
122
122
|
end
|
123
|
+
|
124
|
+
it "doesn't confuse bind parameters in replacements" do
|
125
|
+
conn.execute("REPLACE INTO posts_rt (id, title, body) VALUES (?, ?, ?)", 1, "question?", "I think not")
|
126
|
+
end
|
127
|
+
|
128
|
+
it "ignores bind markers inside strings" do
|
129
|
+
conn.execute("REPLACE INTO posts_rt (id, title, state, body) VALUES (?, 'question?', 'other?', ?)", 1, "I think not")
|
130
|
+
end
|
131
|
+
|
132
|
+
it "ignores bind markers inside comments" do
|
133
|
+
conn.execute <<-SQL, 1, "A string"
|
134
|
+
/* is this a comment? *//* another comment ? */
|
135
|
+
REPLACE INTO posts_rt (id, title) VALUES (?, ?)
|
136
|
+
SQL
|
137
|
+
end
|
123
138
|
end
|
124
139
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oedipus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &27993880 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *27993880
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake-compiler
|
27
|
-
requirement: &
|
27
|
+
requirement: &27993440 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *27993440
|
36
36
|
description: ! "== Sphinx 2 Comes to Ruby\n\nOedipus brings full support for Sphinx
|
37
37
|
2 to Ruby:\n\n - real-time indexes (insert, replace, update, delete)\n - faceted
|
38
38
|
search (variations on a base query)\n - multi-queries (multiple queries executed
|
@@ -53,6 +53,8 @@ files:
|
|
53
53
|
- README.md
|
54
54
|
- Rakefile
|
55
55
|
- ext/oedipus/extconf.rb
|
56
|
+
- ext/oedipus/lexing.c
|
57
|
+
- ext/oedipus/lexing.h
|
56
58
|
- ext/oedipus/oedipus.c
|
57
59
|
- ext/oedipus/oedipus.h
|
58
60
|
- lib/oedipus.rb
|
@@ -109,7 +111,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
111
|
version: '0'
|
110
112
|
segments:
|
111
113
|
- 0
|
112
|
-
hash:
|
114
|
+
hash: 4192034159208166427
|
113
115
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
116
|
none: false
|
115
117
|
requirements:
|
@@ -118,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
120
|
version: '0'
|
119
121
|
segments:
|
120
122
|
- 0
|
121
|
-
hash:
|
123
|
+
hash: 4192034159208166427
|
122
124
|
requirements: []
|
123
125
|
rubyforge_project: oedipus
|
124
126
|
rubygems_version: 1.8.11
|