thinking-sphinx 2.0.6 → 2.0.7

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.
Files changed (50) hide show
  1. data/HISTORY +157 -0
  2. data/lib/cucumber/thinking_sphinx/external_world.rb +12 -0
  3. data/lib/cucumber/thinking_sphinx/internal_world.rb +127 -0
  4. data/lib/cucumber/thinking_sphinx/sql_logger.rb +20 -0
  5. data/lib/thinking-sphinx.rb +1 -0
  6. data/lib/thinking_sphinx/action_controller.rb +31 -0
  7. data/lib/thinking_sphinx/active_record/attribute_updates.rb +53 -0
  8. data/lib/thinking_sphinx/active_record/collection_proxy.rb +40 -0
  9. data/lib/thinking_sphinx/active_record/collection_proxy_with_scopes.rb +27 -0
  10. data/lib/thinking_sphinx/active_record/delta.rb +65 -0
  11. data/lib/thinking_sphinx/active_record/has_many_association.rb +37 -0
  12. data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +21 -0
  13. data/lib/thinking_sphinx/active_record/log_subscriber.rb +61 -0
  14. data/lib/thinking_sphinx/active_record/scopes.rb +110 -0
  15. data/lib/thinking_sphinx/active_record.rb +383 -0
  16. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +87 -0
  17. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +62 -0
  18. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +171 -0
  19. data/lib/thinking_sphinx/association.rb +229 -0
  20. data/lib/thinking_sphinx/attribute.rb +407 -0
  21. data/lib/thinking_sphinx/auto_version.rb +38 -0
  22. data/lib/thinking_sphinx/bundled_search.rb +44 -0
  23. data/lib/thinking_sphinx/class_facet.rb +20 -0
  24. data/lib/thinking_sphinx/configuration.rb +335 -0
  25. data/lib/thinking_sphinx/context.rb +77 -0
  26. data/lib/thinking_sphinx/core/string.rb +15 -0
  27. data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
  28. data/lib/thinking_sphinx/deltas.rb +28 -0
  29. data/lib/thinking_sphinx/deploy/capistrano.rb +99 -0
  30. data/lib/thinking_sphinx/excerpter.rb +23 -0
  31. data/lib/thinking_sphinx/facet.rb +128 -0
  32. data/lib/thinking_sphinx/facet_search.rb +170 -0
  33. data/lib/thinking_sphinx/field.rb +98 -0
  34. data/lib/thinking_sphinx/index/builder.rb +312 -0
  35. data/lib/thinking_sphinx/index/faux_column.rb +118 -0
  36. data/lib/thinking_sphinx/index.rb +157 -0
  37. data/lib/thinking_sphinx/join.rb +37 -0
  38. data/lib/thinking_sphinx/property.rb +185 -0
  39. data/lib/thinking_sphinx/railtie.rb +46 -0
  40. data/lib/thinking_sphinx/search.rb +995 -0
  41. data/lib/thinking_sphinx/search_methods.rb +439 -0
  42. data/lib/thinking_sphinx/sinatra.rb +7 -0
  43. data/lib/thinking_sphinx/source/internal_properties.rb +51 -0
  44. data/lib/thinking_sphinx/source/sql.rb +157 -0
  45. data/lib/thinking_sphinx/source.rb +194 -0
  46. data/lib/thinking_sphinx/tasks.rb +132 -0
  47. data/lib/thinking_sphinx/test.rb +55 -0
  48. data/lib/thinking_sphinx/version.rb +3 -0
  49. data/lib/thinking_sphinx.rb +296 -0
  50. metadata +53 -4
@@ -0,0 +1,194 @@
1
+ require 'thinking_sphinx/source/internal_properties'
2
+ require 'thinking_sphinx/source/sql'
3
+
4
+ module ThinkingSphinx
5
+ class Source
6
+ include ThinkingSphinx::Source::InternalProperties
7
+ include ThinkingSphinx::Source::SQL
8
+
9
+ attr_accessor :model, :fields, :attributes, :joins, :conditions, :groupings,
10
+ :options
11
+ attr_reader :base, :index, :database_configuration
12
+
13
+ def initialize(index, options = {})
14
+ @index = index
15
+ @model = index.model
16
+ @fields = []
17
+ @attributes = []
18
+ @joins = []
19
+ @conditions = []
20
+ @groupings = []
21
+ @options = options
22
+ @associations = {}
23
+ @database_configuration = @model.connection.
24
+ instance_variable_get(:@config).clone
25
+
26
+ @base = join_dependency_class.new(
27
+ @model, [], initial_joins
28
+ )
29
+
30
+ unless @model.descends_from_active_record?
31
+ stored_class = @model.store_full_sti_class ? @model.name : @model.name.demodulize
32
+ @conditions << "#{@model.quoted_table_name}.#{quote_column(@model.inheritance_column)} = '#{stored_class}'"
33
+ end
34
+
35
+ add_internal_attributes_and_facets
36
+ end
37
+
38
+ def name
39
+ index.name
40
+ end
41
+
42
+ def to_riddle_for_core(offset, position)
43
+ source = Riddle::Configuration::SQLSource.new(
44
+ "#{index.core_name}_#{position}", adapter.sphinx_identifier
45
+ )
46
+
47
+ set_source_database_settings source
48
+ set_source_fields source
49
+ set_source_attributes source, offset
50
+ set_source_settings source
51
+ set_source_sql source, offset
52
+
53
+ source
54
+ end
55
+
56
+ def to_riddle_for_delta(offset, position)
57
+ source = Riddle::Configuration::SQLSource.new(
58
+ "#{index.delta_name}_#{position}", adapter.sphinx_identifier
59
+ )
60
+ source.parent = "#{index.core_name}_#{position}"
61
+
62
+ set_source_database_settings source
63
+ set_source_fields source
64
+ set_source_attributes source, offset, true
65
+ set_source_settings source
66
+ set_source_sql source, offset, true
67
+
68
+ source
69
+ end
70
+
71
+ def delta?
72
+ !@index.delta_object.nil?
73
+ end
74
+
75
+ # Gets the association stack for a specific key.
76
+ #
77
+ def association(key)
78
+ @associations[key] ||= Association.children(@model, key)
79
+ end
80
+
81
+ private
82
+
83
+ def adapter
84
+ @adapter ||= @model.sphinx_database_adapter
85
+ end
86
+
87
+ def available_attributes
88
+ attributes.select { |attrib| attrib.available? }
89
+ end
90
+
91
+ def set_source_database_settings(source)
92
+ config = @database_configuration
93
+
94
+ source.sql_host = config[:host] || "localhost"
95
+ source.sql_user = config[:username] || config[:user] || 'root'
96
+ source.sql_pass = (config[:password].to_s || "").gsub('#', '\#')
97
+ source.sql_db = config[:database]
98
+ source.sql_port = config[:port]
99
+ source.sql_sock = config[:socket]
100
+ end
101
+
102
+ def set_source_fields(source)
103
+ fields.each do |field|
104
+ source.sql_file_field << field.unique_name if field.file?
105
+ source.sql_field_string << field.unique_name if field.with_attribute?
106
+ source.sql_field_str2wordcount << field.unique_name if field.with_wordcount?
107
+ end
108
+ end
109
+
110
+ def set_source_attributes(source, offset, delta = false)
111
+ available_attributes.each do |attrib|
112
+ source.send(attrib.type_to_config) << attrib.config_value(offset, delta)
113
+ end
114
+ end
115
+
116
+ def set_source_sql(source, offset, delta = false)
117
+ source.sql_query = to_sql(:offset => offset, :delta => delta).gsub(/\n/, ' ')
118
+ source.sql_query_range = to_sql_query_range(:delta => delta)
119
+ source.sql_query_info = to_sql_query_info(offset)
120
+
121
+ source.sql_query_pre += send(!delta ? :sql_query_pre_for_core : :sql_query_pre_for_delta)
122
+
123
+ if @index.local_options[:group_concat_max_len]
124
+ source.sql_query_pre << "SET SESSION group_concat_max_len = #{@index.local_options[:group_concat_max_len]}"
125
+ end
126
+
127
+ source.sql_query_pre += [adapter.utf8_query_pre].compact if utf8?
128
+ source.sql_query_pre << adapter.utc_query_pre
129
+ end
130
+
131
+ def set_source_settings(source)
132
+ config = ThinkingSphinx::Configuration.instance
133
+ config.source_options.each do |key, value|
134
+ source.send("#{key}=".to_sym, value)
135
+ end
136
+
137
+ source_options = ThinkingSphinx::Configuration::SourceOptions
138
+ @options.each do |key, value|
139
+ if source_options.include?(key.to_s) && !value.nil?
140
+ source.send("#{key}=".to_sym, value)
141
+ end
142
+ end
143
+ end
144
+
145
+ # Returns all associations used amongst all the fields and attributes.
146
+ # This includes all associations between the model and what the actual
147
+ # columns are from.
148
+ #
149
+ def all_associations
150
+ @all_associations ||= (
151
+ # field associations
152
+ @fields.collect { |field|
153
+ field.associations.values
154
+ }.flatten +
155
+ # attribute associations
156
+ @attributes.collect { |attrib|
157
+ attrib.associations.values if attrib.include_as_association?
158
+ }.compact.flatten +
159
+ # explicit joins
160
+ @joins.collect { |join|
161
+ join.associations
162
+ }.flatten
163
+ ).uniq.collect { |assoc|
164
+ # get ancestors as well as column-level associations
165
+ assoc.ancestors
166
+ }.flatten.uniq
167
+ end
168
+
169
+ def utf8?
170
+ @index.options[:charset_type] =~ /utf-8|zh_cn.utf-8/
171
+ end
172
+
173
+ def join_dependency_class
174
+ if rails_3_1?
175
+ ::ActiveRecord::Associations::JoinDependency
176
+ else
177
+ ::ActiveRecord::Associations::ClassMethods::JoinDependency
178
+ end
179
+ end
180
+
181
+ def initial_joins
182
+ if rails_3_1?
183
+ []
184
+ else
185
+ nil
186
+ end
187
+ end
188
+
189
+ def rails_3_1?
190
+ ::ActiveRecord::Associations.constants.include?(:JoinDependency) ||
191
+ ::ActiveRecord::Associations.constants.include?('JoinDependency')
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,132 @@
1
+ require 'fileutils'
2
+ require 'timeout'
3
+
4
+ namespace :thinking_sphinx do
5
+ task :app_env do
6
+ if defined?(Rails)
7
+ Rails.application.require_environment!
8
+ Rails.configuration.cache_classes = false
9
+ elsif defined?(Merb)
10
+ Rake::Task[:merb_env].invoke
11
+ elsif defined?(Sinatra)
12
+ Sinatra::Application.environment = ENV['RACK_ENV']
13
+ end
14
+ end
15
+
16
+ desc "Output the current Thinking Sphinx version"
17
+ task :version => :app_env do
18
+ puts "Thinking Sphinx v" + ThinkingSphinx::Version
19
+ end
20
+
21
+ desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
22
+ task :running_start => :app_env do
23
+ Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
24
+ Rake::Task["thinking_sphinx:start"].invoke
25
+ end
26
+
27
+ desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
28
+ task :start => :app_env do
29
+ config = ThinkingSphinx::Configuration.instance
30
+
31
+ FileUtils.mkdir_p config.searchd_file_path
32
+ raise RuntimeError, "searchd is already running." if sphinx_running?
33
+
34
+ Dir["#{config.searchd_file_path}/*.spl"].each { |file| File.delete(file) }
35
+
36
+ config.controller.start
37
+
38
+ if sphinx_running?
39
+ puts "Started successfully (pid #{sphinx_pid})."
40
+ else
41
+ puts "Failed to start searchd daemon. Check #{config.searchd_log_file}"
42
+ end
43
+ end
44
+
45
+ desc "Stop Sphinx using Thinking Sphinx's settings"
46
+ task :stop => :app_env do
47
+ unless sphinx_running?
48
+ puts "searchd is not running"
49
+ else
50
+ config = ThinkingSphinx::Configuration.instance
51
+ pid = sphinx_pid
52
+ config.controller.stop
53
+
54
+ # Ensure searchd is stopped, but don't try too hard
55
+ Timeout.timeout(config.stop_timeout) do
56
+ sleep(1) until config.controller.stop
57
+ end
58
+
59
+ puts "Stopped search daemon (pid #{pid})."
60
+ end
61
+ end
62
+
63
+ desc "Restart Sphinx"
64
+ task :restart => [:app_env, :stop, :start]
65
+
66
+ desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
67
+ task :configure => :app_env do
68
+ config = ThinkingSphinx::Configuration.instance
69
+ puts "Generating Configuration to #{config.config_file}"
70
+ config.build
71
+ end
72
+
73
+ desc "Index data for Sphinx using Thinking Sphinx's settings"
74
+ task :index => :app_env do
75
+ config = ThinkingSphinx::Configuration.instance
76
+ unless ENV["INDEX_ONLY"] == "true"
77
+ puts "Generating Configuration to #{config.config_file}"
78
+ config.build
79
+ end
80
+
81
+ FileUtils.mkdir_p config.searchd_file_path
82
+ config.controller.index :verbose => true
83
+ end
84
+
85
+ desc "Reindex Sphinx without regenerating the configuration file"
86
+ task :reindex => :app_env do
87
+ config = ThinkingSphinx::Configuration.instance
88
+ FileUtils.mkdir_p config.searchd_file_path
89
+ output = config.controller.index
90
+ puts output
91
+ config.touch_reindex_file(output)
92
+ end
93
+
94
+ desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
95
+ task :rebuild => :app_env do
96
+ Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
97
+ Rake::Task["thinking_sphinx:index"].invoke
98
+ Rake::Task["thinking_sphinx:start"].invoke
99
+ end
100
+ end
101
+
102
+ namespace :ts do
103
+ desc "Output the current Thinking Sphinx version"
104
+ task :version => "thinking_sphinx:version"
105
+ desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
106
+ task :run => "thinking_sphinx:running_start"
107
+ desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
108
+ task :start => "thinking_sphinx:start"
109
+ desc "Stop Sphinx using Thinking Sphinx's settings"
110
+ task :stop => "thinking_sphinx:stop"
111
+ desc "Index data for Sphinx using Thinking Sphinx's settings"
112
+ task :in => "thinking_sphinx:index"
113
+ task :index => "thinking_sphinx:index"
114
+ desc "Reindex Sphinx without regenerating the configuration file"
115
+ task :reindex => "thinking_sphinx:reindex"
116
+ desc "Restart Sphinx"
117
+ task :restart => "thinking_sphinx:restart"
118
+ desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
119
+ task :conf => "thinking_sphinx:configure"
120
+ desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
121
+ task :config => "thinking_sphinx:configure"
122
+ desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
123
+ task :rebuild => "thinking_sphinx:rebuild"
124
+ end
125
+
126
+ def sphinx_pid
127
+ ThinkingSphinx.sphinx_pid
128
+ end
129
+
130
+ def sphinx_running?
131
+ ThinkingSphinx.sphinx_running?
132
+ end
@@ -0,0 +1,55 @@
1
+ class ThinkingSphinx::Test
2
+ def self.init(suppress_delta_output = true)
3
+ set_flags suppress_delta_output
4
+ create_indexes_folder
5
+ end
6
+
7
+ def self.start
8
+ config.build
9
+ config.controller.index
10
+ config.controller.start
11
+ end
12
+
13
+ def self.start_with_autostop
14
+ autostop
15
+ start
16
+ end
17
+
18
+ def self.stop
19
+ config.controller.stop
20
+ sleep(0.5) # Ensure Sphinx has shut down completely
21
+ end
22
+
23
+ def self.autostop
24
+ Kernel.at_exit do
25
+ ThinkingSphinx::Test.stop
26
+ end
27
+ end
28
+
29
+ def self.run(&block)
30
+ begin
31
+ start
32
+ yield
33
+ ensure
34
+ stop
35
+ end
36
+ end
37
+
38
+ def self.config
39
+ @config ||= ::ThinkingSphinx::Configuration.instance
40
+ end
41
+
42
+ def self.index(*indexes)
43
+ config.controller.index *indexes
44
+ end
45
+
46
+ def self.set_flags(suppress_delta_output)
47
+ ::ThinkingSphinx.deltas_enabled = true
48
+ ::ThinkingSphinx.updates_enabled = true
49
+ ::ThinkingSphinx.suppress_delta_output = suppress_delta_output
50
+ end
51
+
52
+ def self.create_indexes_folder
53
+ FileUtils.mkdir_p config.searchd_file_path
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ module ThinkingSphinx
2
+ Version = '2.0.7'
3
+ end
@@ -0,0 +1,296 @@
1
+ require 'thread'
2
+ require 'active_record'
3
+ require 'yaml'
4
+ require 'riddle'
5
+
6
+ require 'thinking_sphinx/auto_version'
7
+ require 'thinking_sphinx/core/string'
8
+ require 'thinking_sphinx/property'
9
+ require 'thinking_sphinx/active_record'
10
+ require 'thinking_sphinx/association'
11
+ require 'thinking_sphinx/attribute'
12
+ require 'thinking_sphinx/bundled_search'
13
+ require 'thinking_sphinx/configuration'
14
+ require 'thinking_sphinx/context'
15
+ require 'thinking_sphinx/excerpter'
16
+ require 'thinking_sphinx/facet'
17
+ require 'thinking_sphinx/class_facet'
18
+ require 'thinking_sphinx/facet_search'
19
+ require 'thinking_sphinx/field'
20
+ require 'thinking_sphinx/index'
21
+ require 'thinking_sphinx/join'
22
+ require 'thinking_sphinx/source'
23
+ require 'thinking_sphinx/search'
24
+ require 'thinking_sphinx/search_methods'
25
+ require 'thinking_sphinx/deltas'
26
+
27
+ require 'thinking_sphinx/adapters/abstract_adapter'
28
+ require 'thinking_sphinx/adapters/mysql_adapter'
29
+ require 'thinking_sphinx/adapters/postgresql_adapter'
30
+
31
+ require 'thinking_sphinx/railtie' if defined?(Rails)
32
+
33
+ module ThinkingSphinx
34
+ mattr_accessor :database_adapter
35
+
36
+ # A ConnectionError will get thrown when a connection to Sphinx can't be
37
+ # made.
38
+ class ConnectionError < StandardError
39
+ end
40
+
41
+ # A StaleIdsException is thrown by Collection.instances_from_matches if there
42
+ # are records in Sphinx but not in the database, so the search can be retried.
43
+ class StaleIdsException < StandardError
44
+ attr_accessor :ids
45
+ def initialize(ids)
46
+ self.ids = ids
47
+ end
48
+ end
49
+
50
+ # A SphinxError occurs when Sphinx responds with an error due to problematic
51
+ # queries or indexes.
52
+ class SphinxError < RuntimeError
53
+ attr_accessor :results
54
+ def initialize(message = nil, results = nil)
55
+ super(message)
56
+ self.results = results
57
+ end
58
+ end
59
+
60
+ # The collection of indexed models. Keep in mind that Rails lazily loads
61
+ # its classes, so this may not actually be populated with _all_ the models
62
+ # that have Sphinx indexes.
63
+ @@sphinx_mutex = Mutex.new
64
+ @@context = nil
65
+ @@define_indexes = true
66
+ @@deltas_enabled = nil
67
+ @@updates_enabled = nil
68
+ @@suppress_delta_output = false
69
+ @@remote_sphinx = false
70
+ @@use_group_by_shortcut = nil
71
+
72
+ def self.mutex
73
+ @@sphinx_mutex
74
+ end
75
+
76
+ def self.context
77
+ if @@context.nil?
78
+ mutex.synchronize do
79
+ if @@context.nil?
80
+ @@context = ThinkingSphinx::Context.new
81
+ @@context.prepare
82
+ end
83
+ end
84
+ end
85
+
86
+ @@context
87
+ end
88
+
89
+ def self.reset_context!(context = nil)
90
+ mutex.synchronize do
91
+ @@context = context
92
+ end
93
+ end
94
+
95
+ def self.unique_id_expression(adapter, offset = nil)
96
+ "* #{adapter.cast_to_int context.indexed_models.size} + #{offset || 0}"
97
+ end
98
+
99
+ # Check if index definition is disabled.
100
+ #
101
+ def self.define_indexes?
102
+ @@define_indexes
103
+ end
104
+
105
+ # Enable/disable indexes - you may want to do this while migrating data.
106
+ #
107
+ # ThinkingSphinx.define_indexes = false
108
+ #
109
+ def self.define_indexes=(value)
110
+ mutex.synchronize do
111
+ @@define_indexes = value
112
+ end
113
+ end
114
+
115
+ # Check if delta indexing is enabled/disabled.
116
+ #
117
+ def self.deltas_enabled?
118
+ if @@deltas_enabled.nil?
119
+ mutex.synchronize do
120
+ if @@deltas_enabled.nil?
121
+ @@deltas_enabled = (
122
+ ThinkingSphinx::Configuration.environment != "test"
123
+ )
124
+ end
125
+ end
126
+ end
127
+
128
+ @@deltas_enabled && !deltas_suspended?
129
+ end
130
+
131
+ # Enable/disable delta indexing.
132
+ #
133
+ # ThinkingSphinx.deltas_enabled = false
134
+ #
135
+ def self.deltas_enabled=(value)
136
+ mutex.synchronize do
137
+ @@deltas_enabled = value
138
+ end
139
+ end
140
+
141
+ # Check if delta indexing is suspended.
142
+ #
143
+ def self.deltas_suspended?
144
+ if Thread.current[:thinking_sphinx_deltas_suspended].nil?
145
+ Thread.current[:thinking_sphinx_deltas_suspended] = false
146
+ end
147
+
148
+ Thread.current[:thinking_sphinx_deltas_suspended]
149
+ end
150
+
151
+ # Suspend/resume delta indexing.
152
+ #
153
+ # ThinkingSphinx.deltas_suspended = false
154
+ #
155
+ def self.deltas_suspended=(value)
156
+ Thread.current[:thinking_sphinx_deltas_suspended] = value
157
+ end
158
+
159
+ # Check if updates are enabled. True by default, unless within the test
160
+ # environment.
161
+ #
162
+ def self.updates_enabled?
163
+ if @@updates_enabled.nil?
164
+ mutex.synchronize do
165
+ if @@updates_enabled.nil?
166
+ @@updates_enabled = (
167
+ ThinkingSphinx::Configuration.environment != "test"
168
+ )
169
+ end
170
+ end
171
+ end
172
+
173
+ @@updates_enabled
174
+ end
175
+
176
+ # Enable/disable updates to Sphinx
177
+ #
178
+ # ThinkingSphinx.updates_enabled = false
179
+ #
180
+ def self.updates_enabled=(value)
181
+ mutex.synchronize do
182
+ @@updates_enabled = value
183
+ end
184
+ end
185
+
186
+ def self.suppress_delta_output?
187
+ @@suppress_delta_output
188
+ end
189
+
190
+ def self.suppress_delta_output=(value)
191
+ mutex.synchronize do
192
+ @@suppress_delta_output = value
193
+ end
194
+ end
195
+
196
+ # Checks to see if MySQL will allow simplistic GROUP BY statements. If not,
197
+ # or if not using MySQL, this will return false.
198
+ #
199
+ def self.use_group_by_shortcut?
200
+ if @@use_group_by_shortcut.nil?
201
+ mutex.synchronize do
202
+ if @@use_group_by_shortcut.nil?
203
+ @@use_group_by_shortcut = !!(
204
+ mysql? && ::ActiveRecord::Base.connection.select_all(
205
+ "SELECT @@global.sql_mode, @@session.sql_mode;"
206
+ ).all? { |key, value|
207
+ value.nil? || value[/ONLY_FULL_GROUP_BY/].nil?
208
+ }
209
+ )
210
+ end
211
+ end
212
+ end
213
+
214
+ @@use_group_by_shortcut
215
+ end
216
+
217
+ def self.reset_use_group_by_shortcut
218
+ mutex.synchronize do
219
+ @@use_group_by_shortcut = nil
220
+ end
221
+ end
222
+
223
+ # An indication of whether Sphinx is running on a remote machine instead of
224
+ # the same machine.
225
+ #
226
+ def self.remote_sphinx?
227
+ @@remote_sphinx
228
+ end
229
+
230
+ # Tells Thinking Sphinx that Sphinx is running on a different machine, and
231
+ # thus it can't reliably guess whether it is running or not (ie: the
232
+ # #sphinx_running? method), and so just assumes it is.
233
+ #
234
+ # Useful for multi-machine deployments. Set it in your production.rb file.
235
+ #
236
+ # ThinkingSphinx.remote_sphinx = true
237
+ #
238
+ def self.remote_sphinx=(value)
239
+ mutex.synchronize do
240
+ @@remote_sphinx = value
241
+ end
242
+ end
243
+
244
+ # Check if Sphinx is running. If remote_sphinx is set to true (indicating
245
+ # Sphinx is on a different machine), this will always return true, and you
246
+ # will have to handle any connection errors yourself.
247
+ #
248
+ def self.sphinx_running?
249
+ remote_sphinx? || sphinx_running_by_pid?
250
+ end
251
+
252
+ # Check if Sphinx is actually running, provided the pid is on the same
253
+ # machine as this code.
254
+ #
255
+ def self.sphinx_running_by_pid?
256
+ !!sphinx_pid && pid_active?(sphinx_pid)
257
+ end
258
+
259
+ def self.sphinx_pid
260
+ if File.exists?(ThinkingSphinx::Configuration.instance.pid_file)
261
+ File.read(ThinkingSphinx::Configuration.instance.pid_file)[/\d+/]
262
+ else
263
+ nil
264
+ end
265
+ end
266
+
267
+ def self.pid_active?(pid)
268
+ !!Process.kill(0, pid.to_i)
269
+ rescue Errno::EPERM => e
270
+ true
271
+ rescue Exception => e
272
+ false
273
+ end
274
+
275
+ def self.microsoft?
276
+ RUBY_PLATFORM =~ /mswin/
277
+ end
278
+
279
+ def self.jruby?
280
+ defined?(JRUBY_VERSION)
281
+ end
282
+
283
+ def self.mysql?
284
+ ::ActiveRecord::Base.connection.class.name.demodulize == "MysqlAdapter" ||
285
+ ::ActiveRecord::Base.connection.class.name.demodulize == "Mysql2Adapter" ||
286
+ ::ActiveRecord::Base.connection.class.name.demodulize == "MysqlplusAdapter" || (
287
+ jruby? && ::ActiveRecord::Base.connection.config[:adapter] == "jdbcmysql"
288
+ )
289
+ end
290
+
291
+ def self.rails_3_1?
292
+ !!defined?(::ActiveRecord::Associations::CollectionProxy)
293
+ end
294
+
295
+ extend ThinkingSphinx::SearchMethods::ClassMethods
296
+ end