oedipus 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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);
@@ -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
- int i;
194
- VALUE v;
195
- VALUE q;
196
- VALUE idx;
197
-
198
- q = rb_str_new("?", 1);
199
- sql = rb_funcall(sql, rb_intern("dup"), 0);
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
- // FIXME: Do a real lexical scan of the string, to avoid replacing '?' inside comments/strings
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 ((idx = rb_funcall(sql, rb_intern("index"), 1, q)) == Qnil) {
205
- break;
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
- v = bind_values[i];
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
- if (ODP_KIND_OF_P(v, rb_cInteger)) {
211
- ODP_STR_SUB(sql, idx, ODP_TO_S(v));
212
- } else if (ODP_KIND_OF_P(v, rb_cNumeric)) {
213
- ODP_STR_SUB(sql, idx, ODP_TO_S(ODP_TO_F(v)));
214
- } else {
215
- if (T_STRING != TYPE(v)) {
216
- v = ODP_TO_S(v);
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
- char * v_ptr = RSTRING_PTR(v);
221
- unsigned long v_len = strlen(v_ptr);
232
+ if (!(odp_scan_until_marker(&sql_str, &dest, sql_end - sql_str))) {
233
+ break;
234
+ }
222
235
 
223
- char escaped_str [v_len * 2 + 1];
224
- char quoted_str [v_len * 2 + 3];
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, v_ptr, v_len);
240
+ mysql_real_escape_string(conn->ptr, escaped_str, str, len);
227
241
  sprintf(quoted_str, "'%s'", escaped_str);
228
- ODP_STR_SUB(sql, idx, rb_str_new2(quoted_str));
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
- return sql;
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) {
@@ -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 {
@@ -8,5 +8,5 @@
8
8
  ##
9
9
 
10
10
  module Oedipus
11
- VERSION = "0.0.9"
11
+ VERSION = "0.0.10"
12
12
  end
@@ -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.9
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-05 00:00:00.000000000 Z
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: &20663420 !ruby/object:Gem::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: *20663420
24
+ version_requirements: *27993880
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake-compiler
27
- requirement: &20662600 !ruby/object:Gem::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: *20662600
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: -658671341905469446
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: -658671341905469446
123
+ hash: 4192034159208166427
122
124
  requirements: []
123
125
  rubyforge_project: oedipus
124
126
  rubygems_version: 1.8.11