thinking-sphinx 1.5.0 → 2.0.0.rc1
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/README.textile +15 -48
- data/VERSION +1 -0
- data/features/attribute_transformation.feature +7 -7
- data/features/attribute_updates.feature +16 -18
- data/features/deleting_instances.feature +13 -16
- data/features/excerpts.feature +0 -8
- data/features/facets.feature +19 -25
- data/features/handling_edits.feature +20 -25
- data/features/searching_across_models.feature +1 -1
- data/features/searching_by_index.feature +5 -6
- data/features/searching_by_model.feature +29 -29
- data/features/sphinx_scopes.feature +0 -26
- data/features/step_definitions/common_steps.rb +6 -18
- data/features/step_definitions/scope_steps.rb +0 -4
- data/features/step_definitions/search_steps.rb +4 -9
- data/features/support/env.rb +10 -3
- data/features/thinking_sphinx/db/fixtures/alphas.rb +10 -8
- data/features/thinking_sphinx/db/fixtures/cats.rb +1 -1
- data/features/thinking_sphinx/db/fixtures/dogs.rb +1 -1
- data/features/thinking_sphinx/db/fixtures/foxes.rb +1 -1
- data/features/thinking_sphinx/db/fixtures/people.rb +1 -1
- data/features/thinking_sphinx/db/fixtures/posts.rb +1 -5
- data/features/thinking_sphinx/db/migrations/create_posts.rb +0 -1
- data/features/thinking_sphinx/models/alpha.rb +0 -1
- data/features/thinking_sphinx/models/beta.rb +0 -5
- data/features/thinking_sphinx/models/developer.rb +1 -6
- data/features/thinking_sphinx/models/music.rb +1 -3
- data/features/thinking_sphinx/models/person.rb +1 -2
- data/features/thinking_sphinx/models/post.rb +0 -1
- data/lib/cucumber/thinking_sphinx/external_world.rb +4 -8
- data/lib/cucumber/thinking_sphinx/internal_world.rb +27 -36
- data/lib/thinking_sphinx.rb +60 -132
- data/lib/thinking_sphinx/active_record.rb +98 -124
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +13 -17
- data/lib/thinking_sphinx/active_record/delta.rb +15 -21
- data/lib/thinking_sphinx/active_record/has_many_association.rb +23 -16
- data/lib/thinking_sphinx/active_record/scopes.rb +0 -18
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +15 -63
- data/lib/thinking_sphinx/adapters/mysql_adapter.rb +0 -4
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +24 -65
- data/lib/thinking_sphinx/association.rb +11 -36
- data/lib/thinking_sphinx/attribute.rb +85 -92
- data/lib/thinking_sphinx/auto_version.rb +3 -21
- data/lib/thinking_sphinx/class_facet.rb +3 -8
- data/lib/thinking_sphinx/configuration.rb +58 -114
- data/lib/thinking_sphinx/context.rb +20 -22
- data/lib/thinking_sphinx/core/array.rb +13 -0
- data/lib/thinking_sphinx/deltas.rb +0 -2
- data/lib/thinking_sphinx/deltas/default_delta.rb +22 -18
- data/lib/thinking_sphinx/deploy/capistrano.rb +31 -30
- data/lib/thinking_sphinx/excerpter.rb +1 -2
- data/lib/thinking_sphinx/facet.rb +35 -45
- data/lib/thinking_sphinx/facet_search.rb +24 -58
- data/lib/thinking_sphinx/field.rb +0 -18
- data/lib/thinking_sphinx/index.rb +36 -38
- data/lib/thinking_sphinx/index/builder.rb +59 -74
- data/lib/thinking_sphinx/property.rb +45 -66
- data/lib/thinking_sphinx/railtie.rb +35 -0
- data/lib/thinking_sphinx/search.rb +250 -506
- data/lib/thinking_sphinx/source.rb +31 -50
- data/lib/thinking_sphinx/source/internal_properties.rb +3 -8
- data/lib/thinking_sphinx/source/sql.rb +31 -71
- data/lib/thinking_sphinx/tasks.rb +27 -48
- data/spec/thinking_sphinx/active_record/delta_spec.rb +41 -36
- data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +0 -96
- data/spec/thinking_sphinx/active_record/scopes_spec.rb +29 -29
- data/spec/thinking_sphinx/active_record_spec.rb +169 -140
- data/spec/thinking_sphinx/association_spec.rb +2 -20
- data/spec/thinking_sphinx/attribute_spec.rb +97 -101
- data/spec/thinking_sphinx/auto_version_spec.rb +11 -75
- data/spec/thinking_sphinx/configuration_spec.rb +62 -63
- data/spec/thinking_sphinx/context_spec.rb +66 -66
- data/spec/thinking_sphinx/facet_search_spec.rb +99 -99
- data/spec/thinking_sphinx/facet_spec.rb +4 -30
- data/spec/thinking_sphinx/field_spec.rb +3 -17
- data/spec/thinking_sphinx/index/builder_spec.rb +132 -169
- data/spec/thinking_sphinx/index_spec.rb +39 -45
- data/spec/thinking_sphinx/search_methods_spec.rb +33 -37
- data/spec/thinking_sphinx/search_spec.rb +269 -491
- data/spec/thinking_sphinx/source_spec.rb +48 -62
- data/spec/thinking_sphinx_spec.rb +49 -49
- data/tasks/distribution.rb +46 -0
- data/tasks/testing.rb +74 -0
- metadata +123 -199
- data/features/field_sorting.feature +0 -18
- data/features/thinking_sphinx/db/.gitignore +0 -1
- data/features/thinking_sphinx/db/fixtures/post_keywords.txt +0 -1
- data/features/thinking_sphinx/models/andrew.rb +0 -17
- data/lib/thinking-sphinx.rb +0 -1
- data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +0 -21
- data/lib/thinking_sphinx/bundled_search.rb +0 -40
- data/lib/thinking_sphinx/connection.rb +0 -71
- data/lib/thinking_sphinx/deltas/delete_job.rb +0 -16
- data/lib/thinking_sphinx/deltas/index_job.rb +0 -17
- data/lib/thinking_sphinx/rails_additions.rb +0 -181
- data/spec/fixtures/data.sql +0 -32
- data/spec/fixtures/database.yml.default +0 -3
- data/spec/fixtures/models.rb +0 -161
- data/spec/fixtures/structure.sql +0 -146
- data/spec/spec_helper.rb +0 -54
- data/spec/sphinx_helper.rb +0 -67
- data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +0 -163
- data/spec/thinking_sphinx/connection_spec.rb +0 -77
- data/spec/thinking_sphinx/rails_additions_spec.rb +0 -203
|
@@ -3,7 +3,7 @@ module ThinkingSphinx
|
|
|
3
3
|
# This module contains all the delta-related code for models. There isn't
|
|
4
4
|
# really anything you need to call manually in here - except perhaps
|
|
5
5
|
# index_delta, but not sure what reason why.
|
|
6
|
-
#
|
|
6
|
+
#
|
|
7
7
|
module Delta
|
|
8
8
|
# Code for after_commit callback is written by Eli Miller:
|
|
9
9
|
# http://elimiller.blogspot.com/2007/06/proper-cache-expiry-with-aftercommit.html
|
|
@@ -16,42 +16,36 @@ module ThinkingSphinx
|
|
|
16
16
|
# if running in the test environment.
|
|
17
17
|
#
|
|
18
18
|
def index_delta(instance = nil)
|
|
19
|
-
|
|
19
|
+
delta_object.index(self, instance)
|
|
20
20
|
end
|
|
21
|
-
|
|
22
|
-
def
|
|
23
|
-
self.sphinx_indexes.
|
|
21
|
+
|
|
22
|
+
def delta_object
|
|
23
|
+
self.sphinx_indexes.first.delta_object
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
def toggled_delta?
|
|
28
|
-
self.class.
|
|
28
|
+
self.class.delta_object.toggled(self)
|
|
29
29
|
end
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
private
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
# Set the delta value for the model to be true.
|
|
34
34
|
def toggle_delta
|
|
35
|
-
self.class.
|
|
36
|
-
obj.toggle(self)
|
|
37
|
-
} if should_toggle_delta?
|
|
35
|
+
self.class.delta_object.toggle(self) if should_toggle_delta?
|
|
38
36
|
end
|
|
39
|
-
|
|
37
|
+
|
|
40
38
|
# Build the delta index for the related model. This won't be called
|
|
41
39
|
# if running in the test environment.
|
|
42
|
-
#
|
|
40
|
+
#
|
|
43
41
|
def index_delta
|
|
44
|
-
self.class.index_delta(self) if self.class.
|
|
45
|
-
obj.toggled(self)
|
|
46
|
-
}
|
|
42
|
+
self.class.index_delta(self) if self.class.delta_object.toggled(self)
|
|
47
43
|
end
|
|
48
|
-
|
|
44
|
+
|
|
49
45
|
def should_toggle_delta?
|
|
50
|
-
return fire_delta? if respond_to?(:fire_delta?)
|
|
51
|
-
|
|
52
46
|
self.new_record? || indexed_data_changed?
|
|
53
47
|
end
|
|
54
|
-
|
|
48
|
+
|
|
55
49
|
def indexed_data_changed?
|
|
56
50
|
sphinx_indexes.any? { |index|
|
|
57
51
|
index.fields.any? { |field| field.changed?(self) } ||
|
|
@@ -2,23 +2,26 @@ module ThinkingSphinx
|
|
|
2
2
|
module ActiveRecord
|
|
3
3
|
module HasManyAssociation
|
|
4
4
|
def search(*args)
|
|
5
|
-
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def facets(*args)
|
|
9
|
-
@reflection.klass.facets(*association_args(args))
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
def association_args(args)
|
|
15
|
-
options = args.extract_options!
|
|
5
|
+
options = args.extract_options!
|
|
16
6
|
options[:with] ||= {}
|
|
17
7
|
options[:with].merge! default_filter
|
|
18
|
-
|
|
19
|
-
args
|
|
8
|
+
|
|
9
|
+
args << options
|
|
10
|
+
@reflection.klass.search(*args)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def method_missing(method, *args, &block)
|
|
14
|
+
if responds_to_scope(method)
|
|
15
|
+
@reflection.klass.
|
|
16
|
+
search(:with => default_filter).
|
|
17
|
+
send(method, *args, &block)
|
|
18
|
+
else
|
|
19
|
+
super
|
|
20
|
+
end
|
|
20
21
|
end
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
22
25
|
def attribute_for_foreign_key
|
|
23
26
|
foreign_key = @reflection.primary_key_name
|
|
24
27
|
stack = [@reflection.options[:through]].compact
|
|
@@ -27,8 +30,7 @@ module ThinkingSphinx
|
|
|
27
30
|
(@reflection.klass.sphinx_indexes || []).each do |index|
|
|
28
31
|
attribute = index.attributes.detect { |attrib|
|
|
29
32
|
attrib.columns.length == 1 &&
|
|
30
|
-
attrib.columns.first.__name == foreign_key.to_sym
|
|
31
|
-
attrib.alias == foreign_key.to_sym
|
|
33
|
+
attrib.columns.first.__name == foreign_key.to_sym
|
|
32
34
|
}
|
|
33
35
|
return attribute unless attribute.nil?
|
|
34
36
|
end
|
|
@@ -39,6 +41,11 @@ module ThinkingSphinx
|
|
|
39
41
|
def default_filter
|
|
40
42
|
{attribute_for_foreign_key.unique_name => @owner.id}
|
|
41
43
|
end
|
|
44
|
+
|
|
45
|
+
def responds_to_scope(scope)
|
|
46
|
+
@reflection.klass.respond_to?(:sphinx_scopes) &&
|
|
47
|
+
@reflection.klass.sphinx_scopes.include?(scope)
|
|
48
|
+
end
|
|
42
49
|
end
|
|
43
50
|
end
|
|
44
51
|
end
|
|
@@ -17,7 +17,6 @@ module ThinkingSphinx
|
|
|
17
17
|
# The scope is automatically applied when the search method is called. It
|
|
18
18
|
# will only be applied if it is an existing sphinx_scope.
|
|
19
19
|
def default_sphinx_scope(sphinx_scope_name)
|
|
20
|
-
add_sphinx_scopes_support_to_has_many_associations
|
|
21
20
|
@default_sphinx_scope = sphinx_scope_name
|
|
22
21
|
end
|
|
23
22
|
|
|
@@ -44,8 +43,6 @@ module ThinkingSphinx
|
|
|
44
43
|
# @articles = Article.latest_first.search 'pancakes'
|
|
45
44
|
#
|
|
46
45
|
def sphinx_scope(method, &block)
|
|
47
|
-
add_sphinx_scopes_support_to_has_many_associations
|
|
48
|
-
|
|
49
46
|
@sphinx_scopes ||= []
|
|
50
47
|
@sphinx_scopes << method
|
|
51
48
|
|
|
@@ -56,13 +53,6 @@ module ThinkingSphinx
|
|
|
56
53
|
|
|
57
54
|
ThinkingSphinx::Search.new(options)
|
|
58
55
|
end
|
|
59
|
-
|
|
60
|
-
define_method("#{method}_without_default".to_sym) do |*args|
|
|
61
|
-
options = {:classes => classes_option, :ignore_default => true}
|
|
62
|
-
options.merge! block.call(*args)
|
|
63
|
-
|
|
64
|
-
ThinkingSphinx::Search.new(options)
|
|
65
|
-
end
|
|
66
56
|
end
|
|
67
57
|
end
|
|
68
58
|
|
|
@@ -79,14 +69,6 @@ module ThinkingSphinx
|
|
|
79
69
|
|
|
80
70
|
sphinx_scopes.clear
|
|
81
71
|
end
|
|
82
|
-
|
|
83
|
-
def add_sphinx_scopes_support_to_has_many_associations
|
|
84
|
-
scope_mixin = ::ThinkingSphinx::ActiveRecord::HasManyAssociationWithScopes
|
|
85
|
-
|
|
86
|
-
::ActiveRecord::Associations::HasManyAssociation.send(:include, scope_mixin)
|
|
87
|
-
::ActiveRecord::Associations::HasManyThroughAssociation.send(:include, scope_mixin)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
72
|
end
|
|
91
73
|
end
|
|
92
74
|
end
|
|
@@ -3,90 +3,42 @@ module ThinkingSphinx
|
|
|
3
3
|
def initialize(model)
|
|
4
4
|
@model = model
|
|
5
5
|
end
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def setup
|
|
8
8
|
# Deliberately blank - subclasses should do something though. Well, if
|
|
9
9
|
# they need to.
|
|
10
10
|
end
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
def self.detect(model)
|
|
13
|
-
adapter = adapter_for_model model
|
|
14
|
-
case adapter
|
|
15
|
-
when :mysql
|
|
16
|
-
ThinkingSphinx::MysqlAdapter.new model
|
|
17
|
-
when :postgresql
|
|
18
|
-
ThinkingSphinx::PostgreSQLAdapter.new model
|
|
19
|
-
when Class
|
|
20
|
-
adapter.new model
|
|
21
|
-
else
|
|
22
|
-
raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL, not #{adapter}"
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.adapter_for_model(model)
|
|
27
|
-
case ThinkingSphinx.database_adapter
|
|
28
|
-
when String
|
|
29
|
-
ThinkingSphinx.database_adapter.to_sym
|
|
30
|
-
when NilClass
|
|
31
|
-
standard_adapter_for_model model
|
|
32
|
-
when Proc
|
|
33
|
-
ThinkingSphinx.database_adapter.call model
|
|
34
|
-
else
|
|
35
|
-
ThinkingSphinx.database_adapter
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def self.standard_adapter_for_model(model)
|
|
40
13
|
case model.connection.class.name
|
|
41
14
|
when "ActiveRecord::ConnectionAdapters::MysqlAdapter",
|
|
42
|
-
"ActiveRecord::ConnectionAdapters::MysqlplusAdapter"
|
|
43
|
-
|
|
44
|
-
"ActiveRecord::ConnectionAdapters::NullDBAdapter"
|
|
45
|
-
:mysql
|
|
15
|
+
"ActiveRecord::ConnectionAdapters::MysqlplusAdapter"
|
|
16
|
+
ThinkingSphinx::MysqlAdapter.new model
|
|
46
17
|
when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
|
|
47
|
-
|
|
18
|
+
ThinkingSphinx::PostgreSQLAdapter.new model
|
|
48
19
|
when "ActiveRecord::ConnectionAdapters::JdbcAdapter"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
:postgresql
|
|
54
|
-
when "jdbc"
|
|
55
|
-
match = /^jdbc:(mysql|postgresql):\/\//.match(model.connection.config[:url])
|
|
56
|
-
if match
|
|
57
|
-
match[1].to_sym
|
|
58
|
-
else
|
|
59
|
-
model.connection.config[:adapter]
|
|
60
|
-
end
|
|
20
|
+
if model.connection.config[:adapter] == "jdbcmysql"
|
|
21
|
+
ThinkingSphinx::MysqlAdapter.new model
|
|
22
|
+
elsif model.connection.config[:adapter] == "jdbcpostgresql"
|
|
23
|
+
ThinkingSphinx::PostgreSQLAdapter.new model
|
|
61
24
|
else
|
|
62
|
-
|
|
25
|
+
raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL"
|
|
63
26
|
end
|
|
64
27
|
else
|
|
65
|
-
model.connection.class.name
|
|
28
|
+
raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL, not #{model.connection.class.name}"
|
|
66
29
|
end
|
|
67
30
|
end
|
|
68
|
-
|
|
31
|
+
|
|
69
32
|
def quote_with_table(column)
|
|
70
33
|
"#{@model.quoted_table_name}.#{@model.connection.quote_column_name(column)}"
|
|
71
34
|
end
|
|
72
|
-
|
|
35
|
+
|
|
73
36
|
def bigint_pattern
|
|
74
37
|
/bigint/i
|
|
75
38
|
end
|
|
76
|
-
|
|
77
|
-
def downcase(clause)
|
|
78
|
-
"LOWER(#{clause})"
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def case(expression, pairs, default)
|
|
82
|
-
"CASE #{expression} " +
|
|
83
|
-
pairs.keys.inject('') { |string, key|
|
|
84
|
-
string + "WHEN '#{key}' THEN #{pairs[key]} "
|
|
85
|
-
} + "ELSE #{default} END"
|
|
86
|
-
end
|
|
87
|
-
|
|
39
|
+
|
|
88
40
|
protected
|
|
89
|
-
|
|
41
|
+
|
|
90
42
|
def connection
|
|
91
43
|
@connection ||= @model.connection
|
|
92
44
|
end
|
|
@@ -4,49 +4,37 @@ module ThinkingSphinx
|
|
|
4
4
|
create_array_accum_function
|
|
5
5
|
create_crc32_function
|
|
6
6
|
end
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
def sphinx_identifier
|
|
9
9
|
"pgsql"
|
|
10
10
|
end
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
def concatenate(clause, separator = ' ')
|
|
13
13
|
if clause[/^COALESCE/]
|
|
14
14
|
clause.split('), ').join(") || '#{separator}' || ")
|
|
15
15
|
else
|
|
16
16
|
clause.split(', ').collect { |field|
|
|
17
|
-
"CAST(COALESCE(#{field}
|
|
17
|
+
"CAST(COALESCE(#{field}, '') as varchar)"
|
|
18
18
|
}.join(" || '#{separator}' || ")
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
def group_concatenate(clause, separator = ' ')
|
|
23
|
-
|
|
24
|
-
"array_to_string(array_agg(COALESCE(#{clause}, '0')), '#{separator}')"
|
|
25
|
-
else
|
|
26
|
-
"array_to_string(array_accum(COALESCE(#{clause}, '0')), '#{separator}')"
|
|
27
|
-
end
|
|
23
|
+
"array_to_string(array_accum(COALESCE(#{clause}, '0')), '#{separator}')"
|
|
28
24
|
end
|
|
29
|
-
|
|
25
|
+
|
|
30
26
|
def cast_to_string(clause)
|
|
31
27
|
clause
|
|
32
28
|
end
|
|
33
|
-
|
|
29
|
+
|
|
34
30
|
def cast_to_datetime(clause)
|
|
35
|
-
|
|
36
|
-
"cast(floor(extract(epoch from #{clause})) as bigint)"
|
|
37
|
-
else
|
|
38
|
-
"cast(floor(extract(epoch from #{clause})) as int)"
|
|
39
|
-
end
|
|
31
|
+
"cast(extract(epoch from #{clause}) as int)"
|
|
40
32
|
end
|
|
41
|
-
|
|
33
|
+
|
|
42
34
|
def cast_to_unsigned(clause)
|
|
43
35
|
clause
|
|
44
36
|
end
|
|
45
|
-
|
|
46
|
-
def cast_to_int(clause)
|
|
47
|
-
"#{clause}::INT8"
|
|
48
|
-
end
|
|
49
|
-
|
|
37
|
+
|
|
50
38
|
def convert_nulls(clause, default = '')
|
|
51
39
|
default = case default
|
|
52
40
|
when String
|
|
@@ -58,44 +46,34 @@ module ThinkingSphinx
|
|
|
58
46
|
else
|
|
59
47
|
default
|
|
60
48
|
end
|
|
61
|
-
|
|
49
|
+
|
|
62
50
|
"COALESCE(#{clause}, #{default})"
|
|
63
51
|
end
|
|
64
|
-
|
|
52
|
+
|
|
65
53
|
def boolean(value)
|
|
66
54
|
value ? 'TRUE' : 'FALSE'
|
|
67
55
|
end
|
|
68
|
-
|
|
56
|
+
|
|
69
57
|
def crc(clause, blank_to_null = false)
|
|
70
58
|
clause = "NULLIF(#{clause},'')" if blank_to_null
|
|
71
59
|
"crc32(#{clause})"
|
|
72
60
|
end
|
|
73
|
-
|
|
61
|
+
|
|
74
62
|
def utf8_query_pre
|
|
75
63
|
nil
|
|
76
64
|
end
|
|
77
|
-
|
|
65
|
+
|
|
78
66
|
def time_difference(diff)
|
|
79
67
|
"current_timestamp - interval '#{diff} seconds'"
|
|
80
68
|
end
|
|
81
|
-
|
|
69
|
+
|
|
82
70
|
def utc_query_pre
|
|
83
|
-
|
|
71
|
+
'SET TIME ZONE UTC'
|
|
84
72
|
end
|
|
85
|
-
|
|
73
|
+
|
|
86
74
|
private
|
|
87
|
-
|
|
75
|
+
|
|
88
76
|
def execute(command, output_error = false)
|
|
89
|
-
if RUBY_PLATFORM == 'java'
|
|
90
|
-
connection.transaction do
|
|
91
|
-
execute_command command, output_error
|
|
92
|
-
end
|
|
93
|
-
else
|
|
94
|
-
execute_command command, output_error
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def execute_command(command, output_error = false)
|
|
99
77
|
connection.execute "begin"
|
|
100
78
|
connection.execute "savepoint ts"
|
|
101
79
|
begin
|
|
@@ -107,11 +85,9 @@ module ThinkingSphinx
|
|
|
107
85
|
connection.execute "release savepoint ts"
|
|
108
86
|
connection.execute "commit"
|
|
109
87
|
end
|
|
110
|
-
|
|
88
|
+
|
|
111
89
|
def create_array_accum_function
|
|
112
|
-
if server_version
|
|
113
|
-
return
|
|
114
|
-
elsif server_version > 80200
|
|
90
|
+
if connection.raw_connection.respond_to?(:server_version) && connection.raw_connection.server_version > 80200
|
|
115
91
|
execute <<-SQL
|
|
116
92
|
CREATE AGGREGATE array_accum (anyelement)
|
|
117
93
|
(
|
|
@@ -132,7 +108,7 @@ module ThinkingSphinx
|
|
|
132
108
|
SQL
|
|
133
109
|
end
|
|
134
110
|
end
|
|
135
|
-
|
|
111
|
+
|
|
136
112
|
def create_crc32_function
|
|
137
113
|
execute "CREATE LANGUAGE 'plpgsql';"
|
|
138
114
|
function = <<-SQL
|
|
@@ -141,16 +117,10 @@ module ThinkingSphinx
|
|
|
141
117
|
DECLARE tmp bigint;
|
|
142
118
|
DECLARE i int;
|
|
143
119
|
DECLARE j int;
|
|
144
|
-
DECLARE byte_length int;
|
|
145
120
|
DECLARE word_array bytea;
|
|
146
121
|
BEGIN
|
|
147
|
-
IF COALESCE(word, '') = '' THEN
|
|
148
|
-
return 0;
|
|
149
|
-
END IF;
|
|
150
|
-
|
|
151
122
|
i = 0;
|
|
152
123
|
tmp = 4294967295;
|
|
153
|
-
byte_length = bit_length(word) / 8;
|
|
154
124
|
word_array = decode(replace(word, E'\\\\', E'\\\\\\\\'), 'escape');
|
|
155
125
|
LOOP
|
|
156
126
|
tmp = (tmp # get_byte(word_array, i))::bigint;
|
|
@@ -163,26 +133,15 @@ module ThinkingSphinx
|
|
|
163
133
|
EXIT;
|
|
164
134
|
END IF;
|
|
165
135
|
END LOOP;
|
|
166
|
-
IF i >=
|
|
136
|
+
IF i >= char_length(word) THEN
|
|
167
137
|
EXIT;
|
|
168
138
|
END IF;
|
|
169
139
|
END LOOP;
|
|
170
140
|
return (tmp # 4294967295);
|
|
171
141
|
END
|
|
172
|
-
$$ IMMUTABLE LANGUAGE plpgsql;
|
|
142
|
+
$$ IMMUTABLE STRICT LANGUAGE plpgsql;
|
|
173
143
|
SQL
|
|
174
144
|
execute function, true
|
|
175
145
|
end
|
|
176
|
-
|
|
177
|
-
def server_version
|
|
178
|
-
if RUBY_PLATFORM == 'java'
|
|
179
|
-
(connection.raw_connection.connection.server_major_version * 10000) +
|
|
180
|
-
(connection.raw_connection.connection.server_minor_version * 100)
|
|
181
|
-
elsif connection.raw_connection.respond_to?(:server_version)
|
|
182
|
-
connection.raw_connection.server_version
|
|
183
|
-
else
|
|
184
|
-
0
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
146
|
end
|
|
188
147
|
end
|