activerecord-cubrid2-adapter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/LICENSE +21 -0
- data/README.md +63 -0
- data/Rakefile +11 -0
- data/VERSION +1 -0
- data/activerecord-cubrid2-adapter.gemspec +26 -0
- data/lib/active_record/connection_adapters/abstract_cubrid2_adapter.rb +750 -0
- data/lib/active_record/connection_adapters/cubrid2/column.rb +28 -0
- data/lib/active_record/connection_adapters/cubrid2/database_statements.rb +192 -0
- data/lib/active_record/connection_adapters/cubrid2/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/cubrid2/quoting.rb +118 -0
- data/lib/active_record/connection_adapters/cubrid2/schema_creation.rb +98 -0
- data/lib/active_record/connection_adapters/cubrid2/schema_definitions.rb +81 -0
- data/lib/active_record/connection_adapters/cubrid2/schema_dumper.rb +31 -0
- data/lib/active_record/connection_adapters/cubrid2/schema_statements.rb +276 -0
- data/lib/active_record/connection_adapters/cubrid2/type_metadata.rb +31 -0
- data/lib/active_record/connection_adapters/cubrid2/version.rb +7 -0
- data/lib/active_record/connection_adapters/cubrid2_adapter.rb +169 -0
- data/lib/activerecord-cubrid2-adapter.rb +4 -0
- data/lib/arel/visitors/cubrid.rb +67 -0
- data/lib/cubrid2/client.rb +93 -0
- data/lib/cubrid2/console.rb +5 -0
- data/lib/cubrid2/error.rb +86 -0
- data/lib/cubrid2/field.rb +3 -0
- data/lib/cubrid2/result.rb +7 -0
- data/lib/cubrid2/statement.rb +11 -0
- data/lib/cubrid2/version.rb +3 -0
- data/lib/cubrid2.rb +76 -0
- data/tests/Gemfile +10 -0
- data/tests/test_activerecord.rb +109 -0
- metadata +102 -0
@@ -0,0 +1,276 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module Cubrid2
|
6
|
+
module SchemaStatements # :nodoc:
|
7
|
+
# Returns an array of indexes for the given table.
|
8
|
+
def indexes(table_name)
|
9
|
+
indexes = []
|
10
|
+
current_index = nil
|
11
|
+
execute_and_free("SHOW KEYS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result|
|
12
|
+
each_hash(result) do |row|
|
13
|
+
if current_index != row[:Key_name]
|
14
|
+
next if row[:Key_name] == 'PRIMARY' # skip the primary key
|
15
|
+
|
16
|
+
current_index = row[:Key_name]
|
17
|
+
|
18
|
+
cubrid_index_type = row[:Index_type].downcase.to_sym
|
19
|
+
|
20
|
+
# currently only support btree
|
21
|
+
# https://www.cubrid.org/manual/en/11.2/sql/query/show.html?highlight=show%20index#show-index
|
22
|
+
index_using = cubrid_index_type
|
23
|
+
index_type = nil
|
24
|
+
|
25
|
+
indexes << [
|
26
|
+
row[:Table],
|
27
|
+
row[:Key_name],
|
28
|
+
row[:Non_unique].to_i == 0,
|
29
|
+
[],
|
30
|
+
{ lengths: {},
|
31
|
+
orders: {},
|
32
|
+
type: index_type,
|
33
|
+
using: index_using,
|
34
|
+
comment: row[:Comment].presence,
|
35
|
+
null: row[:Null] == 'YES',
|
36
|
+
visible: row[:Visible] == 'YES' }
|
37
|
+
]
|
38
|
+
end
|
39
|
+
|
40
|
+
if row[:Func]
|
41
|
+
expression = row[:Func]
|
42
|
+
expression = +"(#{expression})" unless expression.start_with?('(')
|
43
|
+
indexes.last[-2] << expression
|
44
|
+
indexes.last[-1][:expressions] ||= {}
|
45
|
+
indexes.last[-1][:expressions][expression] = expression
|
46
|
+
indexes.last[-1][:orders][expression] = :desc if row[:Collation] == 'D'
|
47
|
+
else
|
48
|
+
indexes.last[-2] << row[:Column_name]
|
49
|
+
indexes.last[-1][:lengths][row[:Column_name]] = row[:Sub_part].to_i if row[:Sub_part]
|
50
|
+
indexes.last[-1][:orders][row[:Column_name]] = :desc if row[:Collation] == 'D'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
indexes.map do |index|
|
56
|
+
options = index.pop
|
57
|
+
|
58
|
+
if expressions = options.delete(:expressions)
|
59
|
+
orders = options.delete(:orders)
|
60
|
+
lengths = options.delete(:lengths)
|
61
|
+
|
62
|
+
columns = index[-1].map do |name|
|
63
|
+
[name.to_sym, expressions[name] || +quote_column_name(name)]
|
64
|
+
end.to_h
|
65
|
+
|
66
|
+
index[-1] = add_options_for_index_columns(
|
67
|
+
columns, order: orders, length: lengths
|
68
|
+
).values.join(', ')
|
69
|
+
end
|
70
|
+
|
71
|
+
IndexDefinition.new(*index, **options)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def remove_column(table_name, column_name, type = nil, **options)
|
76
|
+
remove_foreign_key(table_name, column: column_name) if foreign_key_exists?(table_name, column: column_name)
|
77
|
+
super
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_table(table_name, options: default_row_format, **)
|
81
|
+
super
|
82
|
+
end
|
83
|
+
|
84
|
+
def internal_string_options_for_primary_key
|
85
|
+
super.tap do |options|
|
86
|
+
if !row_format_dynamic_by_default? && charset =~ /^utf8/
|
87
|
+
options[:collation] = collation.sub(/\A[^_]+/, 'utf8')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def update_table_definition(table_name, base)
|
93
|
+
Cubrid2::Table.new(table_name, base)
|
94
|
+
end
|
95
|
+
|
96
|
+
def create_schema_dumper(options)
|
97
|
+
Cubrid2::SchemaDumper.create(self, options)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Maps logical Rails types to Cubrid-specific data types.
|
101
|
+
def type_to_sql(type, limit: nil,
|
102
|
+
precision: nil, scale: nil,
|
103
|
+
size: limit_to_size(limit, type),
|
104
|
+
unsigned: nil, **)
|
105
|
+
|
106
|
+
case type.to_s
|
107
|
+
when 'integer'
|
108
|
+
integer_to_sql(limit)
|
109
|
+
when 'serial'
|
110
|
+
integer_to_sql(8) #bigint
|
111
|
+
when 'float', 'real', 'double', 'double precision'
|
112
|
+
float_to_sql(limit)
|
113
|
+
when 'text', 'string', 'varchar', 'char varing'
|
114
|
+
type_with_size_to_sql('string', size)
|
115
|
+
when 'char', 'character'
|
116
|
+
type_with_size_to_sql('char', size)
|
117
|
+
when 'blob', 'binary'
|
118
|
+
type_with_size_to_sql('blob', size)
|
119
|
+
when 'clob'
|
120
|
+
type_with_size_to_sql('clob', size)
|
121
|
+
when 'nchar', 'nchar varing'
|
122
|
+
raise 'Not supported from cubrid 9.0'
|
123
|
+
else
|
124
|
+
super
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def table_alias_length
|
129
|
+
# https://www.cubrid.org/manual/en/9.1.0/sql/identifier.html#id2
|
130
|
+
222
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def row_format_dynamic_by_default?
|
136
|
+
false
|
137
|
+
end
|
138
|
+
|
139
|
+
def default_row_format
|
140
|
+
return if row_format_dynamic_by_default?
|
141
|
+
|
142
|
+
nil
|
143
|
+
end
|
144
|
+
|
145
|
+
def schema_creation
|
146
|
+
Cubrid2::SchemaCreation.new(self)
|
147
|
+
end
|
148
|
+
|
149
|
+
def create_table_definition(*args, **options)
|
150
|
+
Cubrid2::TableDefinition.new(self, *args, **options)
|
151
|
+
end
|
152
|
+
|
153
|
+
def new_column_from_field(_table_name, field)
|
154
|
+
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
155
|
+
default = field[:Default]
|
156
|
+
default_function = nil
|
157
|
+
|
158
|
+
if type_metadata.type == :datetime # && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
159
|
+
default_function = default
|
160
|
+
default = nil
|
161
|
+
end
|
162
|
+
|
163
|
+
Cubrid2::Column.new(
|
164
|
+
field[:Field],
|
165
|
+
default,
|
166
|
+
type_metadata,
|
167
|
+
field[:Null] == 'YES',
|
168
|
+
default_function,
|
169
|
+
collation: field[:Collation],
|
170
|
+
comment: field[:Comment].presence,
|
171
|
+
extra: field[:Extra]
|
172
|
+
)
|
173
|
+
end
|
174
|
+
|
175
|
+
def fetch_type_metadata(sql_type, extra = '')
|
176
|
+
Cubrid2::TypeMetadata.new(super(sql_type), extra: extra)
|
177
|
+
end
|
178
|
+
|
179
|
+
def extract_foreign_key_action(specifier)
|
180
|
+
case specifier
|
181
|
+
when 'CASCADE' then :cascade
|
182
|
+
when 'SET NULL' then :nullify
|
183
|
+
when 'RESTRICT' then :restrict
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def add_index_length(quoted_columns, **options)
|
188
|
+
lengths = options_for_index_columns(options[:length])
|
189
|
+
quoted_columns.each do |name, column|
|
190
|
+
column << "(#{lengths[name]})" if lengths[name].present?
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def add_options_for_index_columns(quoted_columns, **options)
|
195
|
+
quoted_columns = add_index_length(quoted_columns, **options)
|
196
|
+
super
|
197
|
+
end
|
198
|
+
|
199
|
+
def data_source_sql(name = nil, type: nil)
|
200
|
+
scope = quoted_scope(name, type: type)
|
201
|
+
sql = +'SHOW TABLES '
|
202
|
+
sql << " LIKE #{scope[:name]}" if scope[:name]
|
203
|
+
sql
|
204
|
+
end
|
205
|
+
|
206
|
+
def quoted_scope(name = nil, type: nil)
|
207
|
+
schema, name = extract_schema_qualified_name(name)
|
208
|
+
scope = {}
|
209
|
+
scope[:schema] = schema ? quote(schema) : 'database()'
|
210
|
+
scope[:name] = quote(name) if name
|
211
|
+
scope[:type] = quote(type) if type
|
212
|
+
scope
|
213
|
+
end
|
214
|
+
|
215
|
+
def extract_schema_qualified_name(string)
|
216
|
+
return [] if string.nil?
|
217
|
+
|
218
|
+
q1 = '[`\"\[]'
|
219
|
+
q2 = '[`\"\]]'
|
220
|
+
schema, name = string.scan(/[^`"\[\].]+|#{q1}[^"]*#{q2}/)
|
221
|
+
if name.nil?
|
222
|
+
name = schema
|
223
|
+
schema = nil
|
224
|
+
end
|
225
|
+
[schema, name]
|
226
|
+
end
|
227
|
+
|
228
|
+
def type_with_size_to_sql(type, _size)
|
229
|
+
case type
|
230
|
+
when 'string'
|
231
|
+
'varchar'
|
232
|
+
when 'char'
|
233
|
+
'char'
|
234
|
+
when 'blob'
|
235
|
+
'blob'
|
236
|
+
when 'clob'
|
237
|
+
'clob'
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def limit_to_size(limit, type)
|
242
|
+
case type.to_s
|
243
|
+
when 'text', 'blob', 'binary'
|
244
|
+
case limit
|
245
|
+
when 0..0xff then 'tiny'
|
246
|
+
when nil, 0x100..0xffff then nil
|
247
|
+
when 0x10000..0xffffff then 'medium'
|
248
|
+
when 0x1000000..0xffffffff then 'long'
|
249
|
+
else raise ArgumentError, "No #{type} type has byte size #{limit}"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def integer_to_sql(limit)
|
255
|
+
case limit
|
256
|
+
when 1 then 'smallint'
|
257
|
+
when 2 then 'smallint'
|
258
|
+
when 3 then 'int'
|
259
|
+
when nil, 4 then 'int'
|
260
|
+
when 5..8 then 'bigint'
|
261
|
+
when 9..16 then 'decimal'
|
262
|
+
else raise ArgumentError, "No integer type has byte size #{limit}. Use a decimal with scale 0 instead."
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def float_to_sql(limit)
|
267
|
+
case limit
|
268
|
+
when nil, 1..4 then 'float'
|
269
|
+
when 5..8 then 'double'
|
270
|
+
else raise ArgumentError, "No float type has byte size #{limit}. Use a decimal with scale 0 instead."
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module Cubrid2
|
6
|
+
class TypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc:
|
7
|
+
undef to_yaml if method_defined?(:to_yaml)
|
8
|
+
|
9
|
+
attr_reader :extra
|
10
|
+
|
11
|
+
def initialize(type_metadata, extra: '')
|
12
|
+
super(type_metadata)
|
13
|
+
@extra = extra
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
other.is_a?(TypeMetadata) &&
|
18
|
+
__getobj__ == other.__getobj__ &&
|
19
|
+
extra == other.extra
|
20
|
+
end
|
21
|
+
alias eql? ==
|
22
|
+
|
23
|
+
def hash
|
24
|
+
TypeMetadata.hash ^
|
25
|
+
__getobj__.hash ^
|
26
|
+
extra.hash
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record/connection_adapters/abstract_cubrid2_adapter'
|
4
|
+
require 'active_record/connection_adapters/cubrid2/database_statements'
|
5
|
+
require 'cubrid2'
|
6
|
+
|
7
|
+
module ActiveRecord
|
8
|
+
module ConnectionHandling # :nodoc:
|
9
|
+
ER_DATABASE_CONNECTION_ERROR = -1000
|
10
|
+
|
11
|
+
# Establishes a connection to the database that's used by all Active Record objects.
|
12
|
+
def cubrid2_connection(config)
|
13
|
+
config = config.symbolize_keys
|
14
|
+
config[:flags] ||= 0
|
15
|
+
|
16
|
+
client = Cubrid2::Client.new(config)
|
17
|
+
ConnectionAdapters::Cubrid2Adapter.new(client, logger, nil, config)
|
18
|
+
rescue Cubrid2::Error => e
|
19
|
+
if e.error_number == ER_DATABASE_CONNECTION_ERROR
|
20
|
+
raise ActiveRecord::NoDatabaseError
|
21
|
+
else
|
22
|
+
raise
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module ConnectionAdapters
|
28
|
+
class Cubrid2Adapter < AbstractCubrid2Adapter
|
29
|
+
ADAPTER_NAME = 'Cubrid2'
|
30
|
+
|
31
|
+
include Cubrid2::DatabaseStatements
|
32
|
+
|
33
|
+
def initialize(connection, logger, connection_options, config)
|
34
|
+
superclass_config = config.reverse_merge(prepared_statements: false)
|
35
|
+
super(connection, logger, connection_options, superclass_config)
|
36
|
+
configure_connection
|
37
|
+
end
|
38
|
+
|
39
|
+
def adapter_name
|
40
|
+
ADAPTER_NAME
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.database_exists?(config)
|
44
|
+
!!ActiveRecord::Base.cubrid_connection(config)
|
45
|
+
rescue ActiveRecord::NoDatabaseError
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
def supports_json?
|
50
|
+
database_version >= '10.2'
|
51
|
+
end
|
52
|
+
|
53
|
+
def supports_comments?
|
54
|
+
# https://www.cubrid.org/manual/en/10.0/release_note/r10_0.html#overview
|
55
|
+
database_version >= '10.0'
|
56
|
+
end
|
57
|
+
|
58
|
+
def supports_comments_in_create?
|
59
|
+
supports_comments?
|
60
|
+
end
|
61
|
+
|
62
|
+
def supports_savepoints?
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
def supports_lazy_transactions?
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
# HELPER METHODS ===========================================
|
71
|
+
def each_hash(result) # :nodoc:
|
72
|
+
stmt = result.is_a?(Array) ? result.first : result
|
73
|
+
if block_given?
|
74
|
+
if result && stmt
|
75
|
+
while row = stmt.fetch_hash
|
76
|
+
yield row.symbolize_keys
|
77
|
+
end
|
78
|
+
end
|
79
|
+
else
|
80
|
+
to_enum(:each_hash, stmt)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def error_number(exception)
|
85
|
+
exception.error_number if exception.respond_to?(:error_number)
|
86
|
+
end
|
87
|
+
|
88
|
+
#--
|
89
|
+
# QUOTING ==================================================
|
90
|
+
#++
|
91
|
+
|
92
|
+
def quote_string(string)
|
93
|
+
# escaping with backslash is only allowed when 'no_backslash_escapes' == 'yes' in cubrid config, default is yes.
|
94
|
+
# See: https://www.cubrid.org/manual/ko/11.2/sql/literal.html#id5
|
95
|
+
# "'#{string.gsub("'", "''")}'"
|
96
|
+
string
|
97
|
+
end
|
98
|
+
|
99
|
+
#--
|
100
|
+
# CONNECTION MANAGEMENT ====================================
|
101
|
+
#++
|
102
|
+
|
103
|
+
def active?
|
104
|
+
@connection.ping
|
105
|
+
end
|
106
|
+
|
107
|
+
def reconnect!
|
108
|
+
super
|
109
|
+
disconnect!
|
110
|
+
connect
|
111
|
+
end
|
112
|
+
alias reset! reconnect!
|
113
|
+
|
114
|
+
# Disconnects from the database if already connected.
|
115
|
+
# Otherwise, this method does nothing.
|
116
|
+
def disconnect!
|
117
|
+
super
|
118
|
+
@connection.close
|
119
|
+
end
|
120
|
+
|
121
|
+
def discard! # :nodoc:
|
122
|
+
super
|
123
|
+
#@connection.automatic_close = false
|
124
|
+
@connection = nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def server_version
|
128
|
+
@connection.server_version
|
129
|
+
end
|
130
|
+
|
131
|
+
def ping
|
132
|
+
@connection.ping
|
133
|
+
end
|
134
|
+
|
135
|
+
def cubrid_connection
|
136
|
+
@connection
|
137
|
+
end
|
138
|
+
|
139
|
+
# 오류??
|
140
|
+
def auto_commit
|
141
|
+
@connection.auto_commit
|
142
|
+
end
|
143
|
+
|
144
|
+
def auto_commit=(flag)
|
145
|
+
@connection.auto_commit = flag
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def connect
|
151
|
+
@connection = Cubrid2::Client.new(@config)
|
152
|
+
configure_connection
|
153
|
+
end
|
154
|
+
|
155
|
+
def configure_connection
|
156
|
+
@connection.query_options[:as] = :array
|
157
|
+
super
|
158
|
+
end
|
159
|
+
|
160
|
+
def full_version
|
161
|
+
schema_cache.database_version.full_version_string
|
162
|
+
end
|
163
|
+
|
164
|
+
def get_full_version
|
165
|
+
@connection.server_version
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Arel # :nodoc: all
|
2
|
+
module Visitors
|
3
|
+
class Cubrid < Arel::Visitors::ToSql
|
4
|
+
private
|
5
|
+
|
6
|
+
def visit_Arel_Nodes_Bin(o, collector)
|
7
|
+
collector << 'BINARY '
|
8
|
+
visit o.expr, collector
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_Arel_Nodes_UnqualifiedColumn(o, collector)
|
12
|
+
visit o.expr, collector
|
13
|
+
end
|
14
|
+
|
15
|
+
def visit_Arel_Nodes_SelectCore(o, collector)
|
16
|
+
o.froms ||= Arel.sql('DB_ROOT')
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def visit_Arel_Nodes_Concat(o, collector)
|
21
|
+
collector << ' CONCAT('
|
22
|
+
visit o.left, collector
|
23
|
+
collector << ', '
|
24
|
+
visit o.right, collector
|
25
|
+
collector << ') '
|
26
|
+
collector
|
27
|
+
end
|
28
|
+
|
29
|
+
def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
|
30
|
+
collector = visit o.left, collector
|
31
|
+
collector << ' <=> '
|
32
|
+
visit o.right, collector
|
33
|
+
end
|
34
|
+
|
35
|
+
def visit_Arel_Nodes_IsDistinctFrom(o, collector)
|
36
|
+
collector << 'NOT '
|
37
|
+
visit_Arel_Nodes_IsNotDistinctFrom o, collector
|
38
|
+
end
|
39
|
+
|
40
|
+
def visit_Arel_Nodes_Regexp(o, collector)
|
41
|
+
infix_value o, collector, ' REGEXP '
|
42
|
+
end
|
43
|
+
|
44
|
+
def visit_Arel_Nodes_NotRegexp(o, collector)
|
45
|
+
infix_value o, collector, ' NOT REGEXP '
|
46
|
+
end
|
47
|
+
|
48
|
+
# no-op
|
49
|
+
def visit_Arel_Nodes_NullsFirst(o, collector)
|
50
|
+
visit o.expr, collector
|
51
|
+
end
|
52
|
+
|
53
|
+
# In the simple case, Cubrid allows us to place JOINs directly into the UPDATE
|
54
|
+
# query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
|
55
|
+
# these, we must use a subquery.
|
56
|
+
def prepare_update_statement(o)
|
57
|
+
if o.offset # || has_group_by_and_having?(o) ||
|
58
|
+
has_join_sources?(o) && has_limit_or_offset_or_orders?(o)
|
59
|
+
super
|
60
|
+
else
|
61
|
+
o
|
62
|
+
end
|
63
|
+
end
|
64
|
+
alias prepare_delete_statement prepare_update_statement
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Cubrid2
|
2
|
+
class Client
|
3
|
+
delegate :new, :prepare, to: :@conn
|
4
|
+
|
5
|
+
attr_reader :query_options, :read_timeout, :conn
|
6
|
+
|
7
|
+
def self.default_query_options
|
8
|
+
@default_query_options ||= {
|
9
|
+
auto_commit: true
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(opts = {})
|
14
|
+
raise Cubrid2::Error, 'Options parameter must be a Hash' unless opts.is_a? Hash
|
15
|
+
|
16
|
+
opts = Cubrid2::Util.key_hash_as_symbols(opts)
|
17
|
+
@read_timeout = nil
|
18
|
+
@query_options = self.class.default_query_options.dup
|
19
|
+
@query_options.merge! opts
|
20
|
+
|
21
|
+
%i[auto_commit].each do |key|
|
22
|
+
next unless opts.key?(key)
|
23
|
+
|
24
|
+
case key
|
25
|
+
when :auto_commit
|
26
|
+
send(:"#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation
|
27
|
+
else
|
28
|
+
send(:"#{key}=", opts[key])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
flags = 0
|
33
|
+
|
34
|
+
user = opts[:username] || opts[:user]
|
35
|
+
pass = opts[:password] || opts[:pass]
|
36
|
+
host = opts[:host] || opts[:hostname]
|
37
|
+
port = opts[:port]
|
38
|
+
database = opts[:database] || opts[:dbname] || opts[:db]
|
39
|
+
|
40
|
+
# Correct the data types before passing these values down to the C level
|
41
|
+
user = user.to_s unless user.nil?
|
42
|
+
pass = pass.to_s unless pass.nil?
|
43
|
+
host = host.to_s unless host.nil?
|
44
|
+
port = port.to_i unless port.nil?
|
45
|
+
database = database.to_s unless database.nil?
|
46
|
+
|
47
|
+
@conn = Cubrid.connect database, host, port, user, pass
|
48
|
+
end
|
49
|
+
|
50
|
+
def query(sql, options = {})
|
51
|
+
Thread.handle_interrupt(::Cubrid2::Util::TIMEOUT_ERROR_CLASS => :never) do
|
52
|
+
_query(sql, @query_options.merge(options))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def _query(sql, _options)
|
57
|
+
@conn.query(sql)
|
58
|
+
end
|
59
|
+
|
60
|
+
def query_info
|
61
|
+
info = query_info_string
|
62
|
+
return {} unless info
|
63
|
+
|
64
|
+
info_hash = {}
|
65
|
+
info.split.each_slice(2) { |s| info_hash[s[0].downcase.delete(':').to_sym] = s[1].to_i }
|
66
|
+
info_hash
|
67
|
+
end
|
68
|
+
|
69
|
+
def info
|
70
|
+
self.class.info
|
71
|
+
end
|
72
|
+
|
73
|
+
def ping
|
74
|
+
@conn.server_version.present?
|
75
|
+
end
|
76
|
+
|
77
|
+
def server_version
|
78
|
+
@conn.server_version
|
79
|
+
end
|
80
|
+
|
81
|
+
def close
|
82
|
+
@conn.close
|
83
|
+
end
|
84
|
+
|
85
|
+
def auto_commit
|
86
|
+
@conn.auto_commit
|
87
|
+
end
|
88
|
+
|
89
|
+
def auto_commit=(flag)
|
90
|
+
@conn.auto_commit = flag
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|