diff options
| author | hukl <contact@smyck.org> | 2009-04-28 00:15:53 +0200 |
|---|---|---|
| committer | hukl <contact@smyck.org> | 2009-05-01 17:14:02 +0200 |
| commit | 4bd16f053847f2efe347ebda9136ef2233ee0d2c (patch) | |
| tree | f4c11f89455de991c8d87726d5757b752e7129e2 /vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters | |
| parent | d3a9b46ba5c863a0ff377dcffae9a494fe476e02 (diff) | |
added thinking_sphinx plugin for fulltext search on nodes and heads
Diffstat (limited to 'vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters')
3 files changed, 226 insertions, 0 deletions
diff --git a/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters/abstract_adapter.rb b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters/abstract_adapter.rb new file mode 100644 index 0000000..b68b75e --- /dev/null +++ b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters/abstract_adapter.rb | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | module ThinkingSphinx | ||
| 2 | class AbstractAdapter | ||
| 3 | def initialize(model) | ||
| 4 | @model = model | ||
| 5 | end | ||
| 6 | |||
| 7 | def setup | ||
| 8 | # Deliberately blank - subclasses should do something though. Well, if | ||
| 9 | # they need to. | ||
| 10 | end | ||
| 11 | |||
| 12 | def self.detect(model) | ||
| 13 | case model.connection.class.name | ||
| 14 | when "ActiveRecord::ConnectionAdapters::MysqlAdapter", | ||
| 15 | "ActiveRecord::ConnectionAdapters::MysqlplusAdapter" | ||
| 16 | ThinkingSphinx::MysqlAdapter.new model | ||
| 17 | when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter" | ||
| 18 | ThinkingSphinx::PostgreSQLAdapter.new model | ||
| 19 | when "ActiveRecord::ConnectionAdapters::JdbcAdapter" | ||
| 20 | if model.connection.config[:adapter] == "jdbcmysql" | ||
| 21 | ThinkingSphinx::MysqlAdapter.new model | ||
| 22 | elsif model.connection.config[:adapter] == "jdbcpostgresql" | ||
| 23 | ThinkingSphinx::PostgreSQLAdapter.new model | ||
| 24 | else | ||
| 25 | raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL" | ||
| 26 | end | ||
| 27 | else | ||
| 28 | raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL, not #{model.connection.class.name}" | ||
| 29 | end | ||
| 30 | end | ||
| 31 | |||
| 32 | def quote_with_table(column) | ||
| 33 | "#{@model.quoted_table_name}.#{@model.connection.quote_column_name(column)}" | ||
| 34 | end | ||
| 35 | |||
| 36 | protected | ||
| 37 | |||
| 38 | def connection | ||
| 39 | @connection ||= @model.connection | ||
| 40 | end | ||
| 41 | end | ||
| 42 | end | ||
diff --git a/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters/mysql_adapter.rb b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters/mysql_adapter.rb new file mode 100644 index 0000000..597d4b6 --- /dev/null +++ b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters/mysql_adapter.rb | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | module ThinkingSphinx | ||
| 2 | class MysqlAdapter < AbstractAdapter | ||
| 3 | def setup | ||
| 4 | # Does MySQL actually need to do anything? | ||
| 5 | end | ||
| 6 | |||
| 7 | def sphinx_identifier | ||
| 8 | "mysql" | ||
| 9 | end | ||
| 10 | |||
| 11 | def concatenate(clause, separator = ' ') | ||
| 12 | "CONCAT_WS('#{separator}', #{clause})" | ||
| 13 | end | ||
| 14 | |||
| 15 | def group_concatenate(clause, separator = ' ') | ||
| 16 | "GROUP_CONCAT(DISTINCT #{clause} SEPARATOR '#{separator}')" | ||
| 17 | end | ||
| 18 | |||
| 19 | def cast_to_string(clause) | ||
| 20 | "CAST(#{clause} AS CHAR)" | ||
| 21 | end | ||
| 22 | |||
| 23 | def cast_to_datetime(clause) | ||
| 24 | "UNIX_TIMESTAMP(#{clause})" | ||
| 25 | end | ||
| 26 | |||
| 27 | def cast_to_unsigned(clause) | ||
| 28 | "CAST(#{clause} AS UNSIGNED)" | ||
| 29 | end | ||
| 30 | |||
| 31 | def convert_nulls(clause, default = '') | ||
| 32 | default = "'#{default}'" if default.is_a?(String) | ||
| 33 | |||
| 34 | "IFNULL(#{clause}, #{default})" | ||
| 35 | end | ||
| 36 | |||
| 37 | def boolean(value) | ||
| 38 | value ? 1 : 0 | ||
| 39 | end | ||
| 40 | |||
| 41 | def crc(clause, blank_to_null = false) | ||
| 42 | clause = "NULLIF(#{clause},'')" if blank_to_null | ||
| 43 | "CRC32(#{clause})" | ||
| 44 | end | ||
| 45 | |||
| 46 | def utf8_query_pre | ||
| 47 | "SET NAMES utf8" | ||
| 48 | end | ||
| 49 | |||
| 50 | def time_difference(diff) | ||
| 51 | "DATE_SUB(NOW(), INTERVAL #{diff} SECOND)" | ||
| 52 | end | ||
| 53 | end | ||
| 54 | end \ No newline at end of file | ||
diff --git a/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters/postgresql_adapter.rb b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters/postgresql_adapter.rb new file mode 100644 index 0000000..625971d --- /dev/null +++ b/vendor/plugins/thinking-sphinx/lib/thinking_sphinx/adapters/postgresql_adapter.rb | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | module ThinkingSphinx | ||
| 2 | class PostgreSQLAdapter < AbstractAdapter | ||
| 3 | def setup | ||
| 4 | create_array_accum_function | ||
| 5 | create_crc32_function | ||
| 6 | end | ||
| 7 | |||
| 8 | def sphinx_identifier | ||
| 9 | "pgsql" | ||
| 10 | end | ||
| 11 | |||
| 12 | def concatenate(clause, separator = ' ') | ||
| 13 | clause.split(', ').collect { |field| | ||
| 14 | "COALESCE(CAST(#{field} as varchar), '')" | ||
| 15 | }.join(" || '#{separator}' || ") | ||
| 16 | end | ||
| 17 | |||
| 18 | def group_concatenate(clause, separator = ' ') | ||
| 19 | "array_to_string(array_accum(#{clause}), '#{separator}')" | ||
| 20 | end | ||
| 21 | |||
| 22 | def cast_to_string(clause) | ||
| 23 | clause | ||
| 24 | end | ||
| 25 | |||
| 26 | def cast_to_datetime(clause) | ||
| 27 | "cast(extract(epoch from #{clause}) as int)" | ||
| 28 | end | ||
| 29 | |||
| 30 | def cast_to_unsigned(clause) | ||
| 31 | clause | ||
| 32 | end | ||
| 33 | |||
| 34 | def convert_nulls(clause, default = '') | ||
| 35 | default = "'#{default}'" if default.is_a?(String) | ||
| 36 | |||
| 37 | "COALESCE(#{clause}, #{default})" | ||
| 38 | end | ||
| 39 | |||
| 40 | def boolean(value) | ||
| 41 | value ? 'TRUE' : 'FALSE' | ||
| 42 | end | ||
| 43 | |||
| 44 | def crc(clause, blank_to_null = false) | ||
| 45 | clause = "NULLIF(#{clause},'')" if blank_to_null | ||
| 46 | "crc32(#{clause})" | ||
| 47 | end | ||
| 48 | |||
| 49 | def utf8_query_pre | ||
| 50 | nil | ||
| 51 | end | ||
| 52 | |||
| 53 | def time_difference(diff) | ||
| 54 | "current_timestamp - interval '#{diff} seconds'" | ||
| 55 | end | ||
| 56 | |||
| 57 | private | ||
| 58 | |||
| 59 | def execute(command, output_error = false) | ||
| 60 | connection.execute "begin" | ||
| 61 | connection.execute "savepoint ts" | ||
| 62 | begin | ||
| 63 | connection.execute command | ||
| 64 | rescue StandardError => err | ||
| 65 | puts err if output_error | ||
| 66 | connection.execute "rollback to savepoint ts" | ||
| 67 | end | ||
| 68 | connection.execute "release savepoint ts" | ||
| 69 | connection.execute "commit" | ||
| 70 | end | ||
| 71 | |||
| 72 | def create_array_accum_function | ||
| 73 | if connection.raw_connection.respond_to?(:server_version) && connection.raw_connection.server_version > 80200 | ||
| 74 | execute <<-SQL | ||
| 75 | CREATE AGGREGATE array_accum (anyelement) | ||
| 76 | ( | ||
| 77 | sfunc = array_append, | ||
| 78 | stype = anyarray, | ||
| 79 | initcond = '{}' | ||
| 80 | ); | ||
| 81 | SQL | ||
| 82 | else | ||
| 83 | execute <<-SQL | ||
| 84 | CREATE AGGREGATE array_accum | ||
| 85 | ( | ||
| 86 | basetype = anyelement, | ||
| 87 | sfunc = array_append, | ||
| 88 | stype = anyarray, | ||
| 89 | initcond = '{}' | ||
| 90 | ); | ||
| 91 | SQL | ||
| 92 | end | ||
| 93 | end | ||
| 94 | |||
| 95 | def create_crc32_function | ||
| 96 | execute "CREATE LANGUAGE 'plpgsql';" | ||
| 97 | function = <<-SQL | ||
| 98 | CREATE OR REPLACE FUNCTION crc32(word text) | ||
| 99 | RETURNS bigint AS $$ | ||
| 100 | DECLARE tmp bigint; | ||
| 101 | DECLARE i int; | ||
| 102 | DECLARE j int; | ||
| 103 | DECLARE word_array bytea; | ||
| 104 | BEGIN | ||
| 105 | i = 0; | ||
| 106 | tmp = 4294967295; | ||
| 107 | word_array = decode(replace(word, E'\\\\', E'\\\\\\\\'), 'escape'); | ||
| 108 | LOOP | ||
| 109 | tmp = (tmp # get_byte(word_array, i))::bigint; | ||
| 110 | i = i + 1; | ||
| 111 | j = 0; | ||
| 112 | LOOP | ||
| 113 | tmp = ((tmp >> 1) # (3988292384 * (tmp & 1)))::bigint; | ||
| 114 | j = j + 1; | ||
| 115 | IF j >= 8 THEN | ||
| 116 | EXIT; | ||
| 117 | END IF; | ||
| 118 | END LOOP; | ||
| 119 | IF i >= char_length(word) THEN | ||
| 120 | EXIT; | ||
| 121 | END IF; | ||
| 122 | END LOOP; | ||
| 123 | return (tmp # 4294967295); | ||
| 124 | END | ||
| 125 | $$ IMMUTABLE STRICT LANGUAGE plpgsql; | ||
| 126 | SQL | ||
| 127 | execute function, true | ||
| 128 | end | ||
| 129 | end | ||
| 130 | end \ No newline at end of file | ||
