ultrasphinx 1.6 → 1.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +5 -1
  3. data/Manifest +47 -7
  4. data/README +4 -4
  5. data/TODO +1 -0
  6. data/examples/default.base +6 -2
  7. data/lib/ultrasphinx.rb +1 -1
  8. data/lib/ultrasphinx/configure.rb +53 -28
  9. data/lib/ultrasphinx/fields.rb +16 -13
  10. data/lib/ultrasphinx/postgresql/concat_ws.sql +35 -0
  11. data/lib/ultrasphinx/postgresql/crc32.sql +7 -0
  12. data/lib/ultrasphinx/postgresql/group_concat.sql +25 -0
  13. data/lib/ultrasphinx/{hex_to_int.sql → postgresql/hex_to_int.sql} +0 -0
  14. data/lib/ultrasphinx/postgresql/language.sql +1 -0
  15. data/lib/ultrasphinx/postgresql/unix_timestamp.sql +12 -0
  16. data/lib/ultrasphinx/search/internals.rb +42 -16
  17. data/lib/ultrasphinx/ultrasphinx.rb +23 -12
  18. data/test/integration/app/app/models/person/user.rb +1 -1
  19. data/test/integration/app/config/database.yml +9 -13
  20. data/test/integration/app/config/ultrasphinx/development.conf +6 -6
  21. data/test/integration/app/config/ultrasphinx/development.conf.canonical +6 -6
  22. data/test/integration/app/db/schema.rb +9 -2
  23. data/test/integration/search_test.rb +16 -6
  24. data/test/setup.rb +5 -1
  25. data/test/ts.multi +2 -0
  26. data/ultrasphinx.gemspec +5 -5
  27. data/vendor/riddle/{MIT-LICENSE → MIT-LICENCE} +0 -0
  28. data/vendor/riddle/README +60 -0
  29. data/vendor/riddle/Rakefile +25 -0
  30. data/vendor/riddle/{riddle.rb → lib/riddle.rb} +3 -0
  31. data/vendor/riddle/{riddle → lib/riddle}/client.rb +73 -4
  32. data/vendor/riddle/{riddle → lib/riddle}/client/filter.rb +0 -0
  33. data/vendor/riddle/{riddle → lib/riddle}/client/message.rb +2 -0
  34. data/vendor/riddle/{riddle → lib/riddle}/client/response.rb +0 -0
  35. data/vendor/riddle/spec/fixtures/data/anchor.bin +0 -0
  36. data/vendor/riddle/spec/fixtures/data/any.bin +0 -0
  37. data/vendor/riddle/spec/fixtures/data/boolean.bin +0 -0
  38. data/vendor/riddle/spec/fixtures/data/distinct.bin +0 -0
  39. data/vendor/riddle/spec/fixtures/data/filter.bin +0 -0
  40. data/vendor/riddle/spec/fixtures/data/filter_array.bin +0 -0
  41. data/vendor/riddle/spec/fixtures/data/filter_array_exclude.bin +0 -0
  42. data/vendor/riddle/spec/fixtures/data/filter_floats.bin +0 -0
  43. data/vendor/riddle/spec/fixtures/data/filter_floats_exclude.bin +0 -0
  44. data/vendor/riddle/spec/fixtures/data/filter_floats_range.bin +0 -0
  45. data/vendor/riddle/spec/fixtures/data/filter_range.bin +0 -0
  46. data/vendor/riddle/spec/fixtures/data/filter_range_exclude.bin +0 -0
  47. data/vendor/riddle/spec/fixtures/data/group.bin +0 -0
  48. data/vendor/riddle/spec/fixtures/data/index.bin +0 -0
  49. data/vendor/riddle/spec/fixtures/data/phrase.bin +0 -0
  50. data/vendor/riddle/spec/fixtures/data/simple.bin +0 -0
  51. data/vendor/riddle/spec/fixtures/data/sort.bin +0 -0
  52. data/vendor/riddle/spec/fixtures/data/update_simple.bin +0 -0
  53. data/vendor/riddle/spec/fixtures/data/weights.bin +0 -0
  54. data/vendor/riddle/spec/fixtures/sphinx/configuration.erb +38 -0
  55. data/vendor/riddle/spec/fixtures/sql/conf.example.yml +3 -0
  56. data/vendor/riddle/spec/fixtures/sql/data.sql +25000 -0
  57. data/vendor/riddle/spec/fixtures/sql/structure.sql +16 -0
  58. data/vendor/riddle/spec/functional/excerpt_spec.rb +102 -0
  59. data/vendor/riddle/spec/functional/search_spec.rb +69 -0
  60. data/vendor/riddle/spec/functional/update_spec.rb +41 -0
  61. data/vendor/riddle/spec/spec_helper.rb +25 -0
  62. data/vendor/riddle/spec/sphinx_helper.rb +91 -0
  63. data/vendor/riddle/spec/unit/client_spec.rb +140 -0
  64. data/vendor/riddle/spec/unit/filter_spec.rb +33 -0
  65. data/vendor/riddle/spec/unit/message_spec.rb +63 -0
  66. data/vendor/riddle/spec/unit/response_spec.rb +64 -0
  67. metadata +95 -55
  68. metadata.gz.sig +0 -0
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,9 @@
1
1
 
2
- vTODO. Use Pat Allan's association configurator.
2
+ v1.6.7. Fix GROUP_CONCAT aggregate problem. Discourage enable_star in default.base. Allow faceting on includes.
3
+
4
+ v1.6.6. Only use DISTINCT when necessary to improve indexing speed.
5
+
6
+ v1.6.5. Many PostgreSQL improvements.
3
7
 
4
8
  v1.6. API changes! Drop Sphinx 0.9.7 compatibility; switch to Pat Allan's 0.9.8 client plugin; remove legacy keynames; fix string sorting bug; improve error handling.
5
9
 
data/Manifest CHANGED
@@ -6,8 +6,13 @@ lib/ultrasphinx/autoload.rb
6
6
  lib/ultrasphinx/configure.rb
7
7
  lib/ultrasphinx/core_extensions.rb
8
8
  lib/ultrasphinx/fields.rb
9
- lib/ultrasphinx/hex_to_int.sql
10
9
  lib/ultrasphinx/is_indexed.rb
10
+ lib/ultrasphinx/postgresql/concat_ws.sql
11
+ lib/ultrasphinx/postgresql/crc32.sql
12
+ lib/ultrasphinx/postgresql/group_concat.sql
13
+ lib/ultrasphinx/postgresql/hex_to_int.sql
14
+ lib/ultrasphinx/postgresql/language.sql
15
+ lib/ultrasphinx/postgresql/unix_timestamp.sql
11
16
  lib/ultrasphinx/search/internals.rb
12
17
  lib/ultrasphinx/search/parser.rb
13
18
  lib/ultrasphinx/search.rb
@@ -124,12 +129,47 @@ test/integration/spell_test.rb
124
129
  test/setup.rb
125
130
  test/test_all.rb
126
131
  test/test_helper.rb
132
+ test/ts.multi
127
133
  test/unit/parser_test.rb
128
134
  TODO
129
- vendor/riddle/MIT-LICENSE
130
- vendor/riddle/riddle/client/filter.rb
131
- vendor/riddle/riddle/client/message.rb
132
- vendor/riddle/riddle/client/response.rb
133
- vendor/riddle/riddle/client.rb
134
- vendor/riddle/riddle.rb
135
+ vendor/riddle/lib/riddle/client/filter.rb
136
+ vendor/riddle/lib/riddle/client/message.rb
137
+ vendor/riddle/lib/riddle/client/response.rb
138
+ vendor/riddle/lib/riddle/client.rb
139
+ vendor/riddle/lib/riddle.rb
140
+ vendor/riddle/MIT-LICENCE
141
+ vendor/riddle/Rakefile
142
+ vendor/riddle/README
143
+ vendor/riddle/spec/fixtures/data/anchor.bin
144
+ vendor/riddle/spec/fixtures/data/any.bin
145
+ vendor/riddle/spec/fixtures/data/boolean.bin
146
+ vendor/riddle/spec/fixtures/data/distinct.bin
147
+ vendor/riddle/spec/fixtures/data/filter.bin
148
+ vendor/riddle/spec/fixtures/data/filter_array.bin
149
+ vendor/riddle/spec/fixtures/data/filter_array_exclude.bin
150
+ vendor/riddle/spec/fixtures/data/filter_floats.bin
151
+ vendor/riddle/spec/fixtures/data/filter_floats_exclude.bin
152
+ vendor/riddle/spec/fixtures/data/filter_floats_range.bin
153
+ vendor/riddle/spec/fixtures/data/filter_range.bin
154
+ vendor/riddle/spec/fixtures/data/filter_range_exclude.bin
155
+ vendor/riddle/spec/fixtures/data/group.bin
156
+ vendor/riddle/spec/fixtures/data/index.bin
157
+ vendor/riddle/spec/fixtures/data/phrase.bin
158
+ vendor/riddle/spec/fixtures/data/simple.bin
159
+ vendor/riddle/spec/fixtures/data/sort.bin
160
+ vendor/riddle/spec/fixtures/data/update_simple.bin
161
+ vendor/riddle/spec/fixtures/data/weights.bin
162
+ vendor/riddle/spec/fixtures/sphinx/configuration.erb
163
+ vendor/riddle/spec/fixtures/sql/conf.example.yml
164
+ vendor/riddle/spec/fixtures/sql/data.sql
165
+ vendor/riddle/spec/fixtures/sql/structure.sql
166
+ vendor/riddle/spec/functional/excerpt_spec.rb
167
+ vendor/riddle/spec/functional/search_spec.rb
168
+ vendor/riddle/spec/functional/update_spec.rb
169
+ vendor/riddle/spec/spec_helper.rb
170
+ vendor/riddle/spec/sphinx_helper.rb
171
+ vendor/riddle/spec/unit/client_spec.rb
172
+ vendor/riddle/spec/unit/filter_spec.rb
173
+ vendor/riddle/spec/unit/message_spec.rb
174
+ vendor/riddle/spec/unit/response_spec.rb
135
175
  vendor/will_paginate/LICENSE
data/README CHANGED
@@ -5,14 +5,14 @@ Ruby on Rails configurator and client to the Sphinx full text search engine.
5
5
 
6
6
  == License
7
7
 
8
- Copyright 2007 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file. Some portions copyright Pat Allan, distributed under the MIT license, and used with permission. Some portions copyright PJ Hyett and Mislav Marohnić, distributed under the MIT license, and used with permission.
8
+ Copyright 2007 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file. Some portions copyright Pat Allan, distributed under the MIT license, and used with permission. Some portions copyright PJ Hyett and Mislav Marohnić, distributed under the MIT license, and used with permission.
9
9
 
10
10
  The public certificate for the gem is at http://rubyforge.org/frs/download.php/25331/evan_weaver-original-public_cert.pem.
11
11
 
12
12
  == Requirements
13
13
 
14
14
  * MySQL (or Postgres, experimental)
15
- * Sphinx 0.9.8-dev r877 or greater
15
+ * Sphinx 0.9.8-dev r871 or greater
16
16
  * Rails 1.2.3 or greater
17
17
 
18
18
  == Features
@@ -33,7 +33,7 @@ Good Rails integration:
33
33
  * <tt>will_paginate</tt> compatibility
34
34
  * query spellcheck
35
35
  * Google-style query parser
36
- * temporary error recovery
36
+ * error recovery
37
37
  * multiple deployment environments
38
38
  * comprehensive Rake tasks
39
39
 
@@ -43,7 +43,7 @@ And some other things.
43
43
 
44
44
  == Installation
45
45
 
46
- First, compile and install Sphinx itself using the 0.9.8 development snapshot (http://www.sphinxsearch.com).
46
+ First, install Sphinx itself. Get the 0.9.8 development snapshot (http://www.sphinxsearch.com), then run <tt>./configure</tt>, <tt>make</tt>, and <tt>sudo make install</tt>. Make sure to set your <tt>./configure</tt> flags : <tt>--prefix</tt> if necessary, and also <tt>--with-pgsql</tt> if you need Postgres support.
47
47
 
48
48
  You also need the <tt>chronic</tt> gem:
49
49
  sudo gem install chronic
data/TODO CHANGED
@@ -1,4 +1,5 @@
1
1
 
2
+ * Use Pat Allan's association configurator, possibly with an API change to avoid the message-passing DSL
2
3
  * Finish unifying filters and textfields
3
4
  * Support exclude filters
4
5
  * Make sure filters can be set to nil
@@ -39,7 +39,7 @@ client
39
39
  source
40
40
  {
41
41
  # Individual SQL source options
42
- sql_range_step = 20000
42
+ sql_range_step = 5000
43
43
  strip_html = 0
44
44
  index_html_attrs =
45
45
  sql_query_post =
@@ -53,7 +53,11 @@ index
53
53
  morphology = stem_en
54
54
  stopwords = # /path/to/stopwords.txt
55
55
  min_word_len = 1
56
- enable_star = 1
56
+
57
+ # Enable these if you need wildcard searching. They will slow down indexing significantly.
58
+ # min_infix_len = 1
59
+ # enable_star = 1
60
+
57
61
  charset_type = utf-8 # or sbcs (Single Byte Character Set)
58
62
  charset_table = 0..9, A..Z->a..z, -, _, ., &, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F,U+C5->U+E5, U+E5, U+C4->U+E4, U+E4, U+D6->U+F6, U+F6, U+16B, U+0c1->a, U+0c4->a, U+0c9->e, U+0cd->i, U+0d3->o, U+0d4->o, U+0da->u, U+0dd->y, U+0e1->a, U+0e4->a, U+0e9->e, U+0ed->i, U+0f3->o, U+0f4->o, U+0fa->u, U+0fd->y, U+104->U+105, U+105, U+106->U+107, U+10c->c, U+10d->c, U+10e->d, U+10f->d, U+116->U+117, U+117, U+118->U+119, U+11a->e, U+11b->e, U+12E->U+12F, U+12F, U+139->l, U+13a->l, U+13d->l, U+13e->l, U+141->U+142, U+142, U+143->U+144, U+144,U+147->n, U+148->n, U+154->r, U+155->r, U+158->r, U+159->r, U+15A->U+15B, U+15B, U+160->s, U+160->U+161, U+161->s, U+164->t, U+165->t, U+16A->U+16B, U+16B, U+16e->u, U+16f->u, U+172->U+173, U+173, U+179->U+17A, U+17A, U+17B->U+17C, U+17C, U+17d->z, U+17e->z,
59
63
  }
@@ -10,7 +10,7 @@ if defined? RAILS_ENV and RAILS_ENV == "development"
10
10
  end
11
11
  end
12
12
 
13
- $LOAD_PATH << "#{File.dirname(__FILE__)}/../vendor/riddle/"
13
+ $LOAD_PATH << "#{File.dirname(__FILE__)}/../vendor/riddle/lib"
14
14
  require 'riddle'
15
15
 
16
16
  require 'ultrasphinx/ultrasphinx'
@@ -72,7 +72,7 @@ module Ultrasphinx
72
72
 
73
73
 
74
74
  def setup_source_database(klass)
75
- # Tentatively supporting Postgres now
75
+ # Supporting Postgres now
76
76
  connection_settings = klass.connection.instance_variable_get("@config")
77
77
 
78
78
  adapter_defaults = ADAPTER_DEFAULTS[ADAPTER]
@@ -95,7 +95,7 @@ module Ultrasphinx
95
95
  "(#{klass.table_name}.#{klass.primary_key} * #{MODEL_CONFIGURATION.size} + #{class_id}) AS id",
96
96
  "#{class_id} AS class_id", "'#{klass.name}' AS class"]
97
97
  remaining_columns = fields.types.keys - ["class", "class_id"]
98
- [column_strings, [], condition_strings, remaining_columns]
98
+ [column_strings, [], condition_strings, [], false, remaining_columns]
99
99
  end
100
100
 
101
101
 
@@ -111,15 +111,21 @@ module Ultrasphinx
111
111
 
112
112
  def build_source(fields, model, options, class_id, klass, source, groups)
113
113
 
114
- column_strings, join_strings, condition_strings, remaining_columns =
115
- setup_source_arrays(klass, fields, class_id, options['conditions'])
114
+ column_strings, join_strings, condition_strings, group_bys, use_distinct, remaining_columns =
115
+ setup_source_arrays(
116
+ klass, fields, class_id, options['conditions'])
116
117
 
117
- column_strings, join_strings, remaining_columns =
118
- build_regular_fields(klass, fields, options['fields'], column_strings, join_strings, remaining_columns)
119
- column_strings, join_strings, remaining_columns =
120
- build_includes(klass, fields, options['include'], column_strings, join_strings, remaining_columns)
121
- column_strings, join_strings, remaining_columns =
122
- build_concatenations(klass, fields, options['concatenate'], column_strings, join_strings, remaining_columns)
118
+ column_strings, join_strings, group_bys, remaining_columns =
119
+ build_regular_fields(
120
+ klass, fields, options['fields'], column_strings, join_strings, group_bys, remaining_columns)
121
+
122
+ column_strings, join_strings, group_bys, remaining_columns =
123
+ build_includes(
124
+ klass, fields, options['include'], column_strings, join_strings, group_bys, remaining_columns)
125
+
126
+ column_strings, join_strings, group_bys, use_distinct, remaining_columns =
127
+ build_concatenations(
128
+ klass, fields, options['concatenate'], column_strings, join_strings, group_bys, use_distinct, remaining_columns)
123
129
 
124
130
  column_strings = add_missing_columns(fields, remaining_columns, column_strings)
125
131
 
@@ -128,26 +134,37 @@ module Ultrasphinx
128
134
  SOURCE_SETTINGS._to_conf_string,
129
135
  setup_source_database(klass),
130
136
  range_select_string(klass),
131
- build_query(klass, column_strings, join_strings, condition_strings),
137
+ build_query(klass, column_strings, join_strings, condition_strings, use_distinct, group_bys),
132
138
  "\n" + groups,
133
139
  query_info_string(klass, class_id),
134
140
  "}\n\n"]
135
141
  end
136
142
 
137
143
 
138
- def build_query(klass, column_strings, join_strings, condition_strings)
144
+ def build_query(klass, column_strings, join_strings, condition_strings, use_distinct, group_bys)
145
+
146
+ primary_key = "#{klass.table_name}.#{klass.primary_key}"
147
+ group_bys = case ADAPTER
148
+ when 'mysql'
149
+ primary_key
150
+ when 'postgresql'
151
+ # Postgres is very fussy about GROUP_BY
152
+ ([primary_key] + group_bys.reject {|s| s == primary_key}.uniq.sort).join(', ')
153
+ end
154
+
139
155
  ["sql_query =",
140
- "SELECT",
156
+ "SELECT",
157
+ # Avoid DISTINCT; it destroys performance
141
158
  column_strings.sort_by do |string|
142
- # sphinx wants them always in the same order, but "id" must be first
159
+ # Sphinx wants them always in the same order, but "id" must be first
143
160
  (field = string[/.*AS (.*)/, 1]) == "id" ? "*" : field
144
161
  end.join(", "),
145
162
  "FROM #{klass.table_name}",
146
163
  join_strings.uniq,
147
- "WHERE #{klass.table_name}.#{klass.primary_key} >= $start AND #{klass.table_name}.#{klass.primary_key} <= $end",
164
+ "WHERE #{primary_key} >= $start AND #{primary_key} <= $end",
148
165
  condition_strings.uniq.map {|condition| "AND #{condition}" },
149
- ADAPTER_SQL_FUNCTIONS[ADAPTER]['group_by']
150
- ].flatten.join(" ")
166
+ "GROUP BY #{group_bys}"
167
+ ].flatten.compact.join(" ")
151
168
  end
152
169
 
153
170
 
@@ -159,17 +176,18 @@ module Ultrasphinx
159
176
  end
160
177
 
161
178
 
162
- def build_regular_fields(klass, fields, entries, column_strings, join_strings, remaining_columns)
179
+ def build_regular_fields(klass, fields, entries, column_strings, join_strings, group_bys, remaining_columns)
163
180
  entries.to_a.each do |entry|
164
181
  source_string = "#{entry['table']}.#{entry['field']}"
182
+ group_bys << source_string
165
183
  column_strings, remaining_columns = install_field(fields, source_string, entry['as'], entry['function_sql'], entry['facet'], column_strings, remaining_columns)
166
184
  end
167
185
 
168
- [column_strings, join_strings, remaining_columns]
186
+ [column_strings, join_strings, group_bys, remaining_columns]
169
187
  end
170
188
 
171
189
 
172
- def build_includes(klass, fields, entries, column_strings, join_strings, remaining_columns)
190
+ def build_includes(klass, fields, entries, column_strings, join_strings, group_bys, remaining_columns)
173
191
  entries.to_a.each do |entry|
174
192
 
175
193
  join_klass = entry['class_name'].constantize
@@ -189,18 +207,19 @@ module Ultrasphinx
189
207
  end
190
208
 
191
209
  source_string = "#{entry['table']}.#{entry['field']}"
210
+ group_bys << source_string
192
211
  column_strings, remaining_columns = install_field(fields, source_string, entry['as'], entry['function_sql'], entry['facet'], column_strings, remaining_columns)
193
212
  end
194
213
 
195
- [column_strings, join_strings, remaining_columns]
214
+ [column_strings, join_strings, group_bys, remaining_columns]
196
215
  end
197
216
 
198
217
 
199
- def build_concatenations(klass, fields, entries, column_strings, join_strings, remaining_columns)
218
+ def build_concatenations(klass, fields, entries, column_strings, join_strings, group_bys, use_distinct, remaining_columns)
200
219
  entries.to_a.each do |entry|
201
220
  if entry['class_name'] and entry['field']
202
- # group concats
203
- # only has_many's or explicit sql right now
221
+ # Group concats
222
+ # Only has_many's or explicit sql right now
204
223
  join_klass = entry['class_name'].constantize
205
224
 
206
225
  join_strings = install_join_unless_association_sql(entry['association_sql'], nil, join_strings) do
@@ -210,13 +229,19 @@ module Ultrasphinx
210
229
  (entry['conditions'] ? " AND (#{entry['conditions']})" : "")
211
230
  end
212
231
 
213
- source_string = "GROUP_CONCAT(DISTINCT #{entry['table']}.#{entry['field']} SEPARATOR ' ')"
232
+ source_string = "#{entry['table']}.#{entry['field']}"
233
+ # We are using the field in an aggregate, so we don't want to add it to group_bys
234
+ source_string = ADAPTER_SQL_FUNCTIONS[ADAPTER]['group_concat']._interpolate(source_string)
235
+ use_distinct = true
236
+
214
237
  column_strings, remaining_columns = install_field(fields, source_string, entry['as'], entry['function_sql'], entry['facet'], column_strings, remaining_columns)
215
238
 
216
239
  elsif entry['fields']
217
- # regular concats
240
+ # Regular concats
218
241
  source_string = "CONCAT_WS(' ', " + entry['fields'].map do |subfield|
219
242
  "#{entry['table']}.#{subfield}"
243
+ end.each do |subsource_string|
244
+ group_bys << subsource_string
220
245
  end.join(', ') + ")"
221
246
 
222
247
  column_strings, remaining_columns = install_field(fields, source_string, entry['as'], entry['function_sql'], entry['facet'], column_strings, remaining_columns)
@@ -226,7 +251,7 @@ module Ultrasphinx
226
251
  end
227
252
  end
228
253
 
229
- [column_strings, join_strings, remaining_columns]
254
+ [column_strings, join_strings, group_bys, use_distinct, remaining_columns]
230
255
  end
231
256
 
232
257
 
@@ -249,7 +274,7 @@ module Ultrasphinx
249
274
 
250
275
  # Generate hashed integer fields for text grouping
251
276
  if with_facet
252
- column_strings << "#{ADAPTER_SQL_FUNCTIONS[ADAPTER]['hash']._interpolate(source_string)} AS #{as}_facet"
277
+ column_strings << "CRC32(#{source_string}) AS #{as}_facet"
253
278
  remaining_columns.delete("#{as}_facet")
254
279
  end
255
280
  [column_strings, remaining_columns]
@@ -60,11 +60,9 @@ This is a special singleton configuration class that stores the index field conf
60
60
 
61
61
  def cast(source_string, field)
62
62
  if types[field] == "date"
63
- "#{ADAPTER_SQL_FUNCTIONS[ADAPTER]['timestamp']._interpolate(source_string)}"
63
+ "UNIX_TIMESTAMP(#{source_string})"
64
64
  elsif types[field] == "integer"
65
65
  source_string # "CAST(#{source_string} AS UNSIGNED)"
66
- elsif source_string =~ /GROUP_CONCAT/
67
- "CAST(#{source_string} AS CHAR)"
68
66
  else
69
67
  source_string
70
68
  end + " AS #{field}"
@@ -77,7 +75,7 @@ This is a special singleton configuration class that stores the index field conf
77
75
  when 'integer', 'float'
78
76
  "0"
79
77
  when 'date'
80
- "UNIX_TIMESTAMP('1970-01-01 00:00:00')"
78
+ "18000" # Midnight on 1/1/1970
81
79
  when nil
82
80
  raise "Field #{field} is missing"
83
81
  else
@@ -104,17 +102,12 @@ This is a special singleton configuration class that stores the index field conf
104
102
  extract_field_alias!(entry, klass)
105
103
 
106
104
  unless klass.columns_hash[entry['field']]
105
+ # XXX I think this is here for migrations
107
106
  Ultrasphinx.say "warning: field #{entry['field']} is not present in #{model}"
108
107
  else
109
108
  save_and_verify_type(entry['as'], klass.columns_hash[entry['field']].type, entry['sortable'], klass)
110
- end
111
-
112
- if entry['facet']
113
- save_and_verify_type(entry['as'], 'text', nil, klass) # source must be a string
114
- save_and_verify_type("#{entry['as']}_facet", 'integer', nil, klass)
115
- end
116
-
117
- entry
109
+ install_facets!(entry, klass)
110
+ end
118
111
  end
119
112
 
120
113
  # Joins are whatever they are in the target
@@ -122,13 +115,15 @@ This is a special singleton configuration class that stores the index field conf
122
115
  extract_table_alias!(entry, klass)
123
116
  extract_field_alias!(entry, klass)
124
117
 
125
- save_and_verify_type(entry['as'] || entry['field'], entry['class_name'].constantize.columns_hash[entry['field']].type, entry['sortable'], klass)
118
+ save_and_verify_type(entry['as'] || entry['field'], entry['class_name'].constantize.columns_hash[entry['field']].type, entry['sortable'], klass)
119
+ install_facets!(entry, klass)
126
120
  end
127
121
 
128
122
  # Regular concats are CHAR, group_concats are BLOB and need to be cast to CHAR
129
123
  options['concatenate'].to_a.each do |entry|
130
124
  extract_table_alias!(entry, klass) # XXX Doesn't actually do anything useful
131
125
  save_and_verify_type(entry['as'], 'text', entry['sortable'], klass)
126
+ install_facets!(entry, klass)
132
127
  end
133
128
 
134
129
  rescue ActiveRecord::StatementInvalid
@@ -139,6 +134,14 @@ This is a special singleton configuration class that stores the index field conf
139
134
  self
140
135
  end
141
136
 
137
+ def install_facets!(entry, klass)
138
+ if entry['facet']
139
+ save_and_verify_type(entry['as'], 'text', nil, klass) # source must be a string
140
+ save_and_verify_type("#{entry['as']}_facet", 'integer', nil, klass)
141
+ end
142
+ entry
143
+ end
144
+
142
145
  def extract_field_alias!(entry, klass)
143
146
  unless entry['as']
144
147
  entry['as'] = entry['field']
@@ -0,0 +1,35 @@
1
+
2
+ /* http://osdir.com/ml/db.postgresql.admIN/2003-08/msg00057.html */
3
+
4
+ CREATE OR REPLACE FUNCTION MAKE_CONCAT_WS() RETURNS text AS '
5
+ declare
6
+ v_args int := 32;
7
+ v_first text := ''CREATE OR REPLACE FUNCTION CONCAT_WS(text,text,text) RETURNS text AS ''''SELECT CASE WHEN $1 IS NULL THEN NULL WHEN $3 IS NULL THEN $2 ELSE $2 || $1 || $3 END'''' LANGUAGE sql IMMUTABLE'';
8
+ v_part1 text := ''CREATE OR REPLACE FUNCTION CONCAT_WS(text,text'';
9
+ v_part2 text := '') RETURNS text AS ''''SELECT CONCAT_WS($1,CONCAT_WS($1,$2'';
10
+ v_part3 text := '')'''' LANGUAGE sql IMMUTABLE'';
11
+ v_sql text;
12
+
13
+ BEGIN
14
+ EXECUTE v_first;
15
+ FOR i IN 4 .. v_args loop
16
+ v_sql := v_part1;
17
+ FOR j IN 3 .. i loop
18
+ v_sql := v_sql || '',text'';
19
+ END loop;
20
+
21
+ v_sql := v_sql || v_part2;
22
+
23
+ FOR j IN 3 .. i - 1 loop
24
+ v_sql := v_sql || '',$'' || j::text;
25
+ END loop;
26
+ v_sql := v_sql || ''),$'' || i::text;
27
+
28
+ v_sql := v_sql || v_part3;
29
+ EXECUTE v_sql;
30
+ END loop;
31
+ RETURN ''OK'';
32
+ END;
33
+ ' LANGUAGE 'plpgsql';
34
+
35
+ SELECT MAKE_CONCAT_WS();
@@ -0,0 +1,7 @@
1
+
2
+ /* Fake CRC32 */
3
+
4
+ CREATE OR REPLACE FUNCTION crc32(text)
5
+ RETURNS int AS $$
6
+ SELECT hex_to_int(SUBSTRING(MD5($1) FROM 1 FOR 8))::int
7
+ $$ VOLATILE LANGUAGE SQL;