activerecord-sqlanywhere-adapter 0.1.0
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/CHANGELOG +5 -0
- data/LICENSE +23 -0
- data/README +71 -0
- data/lib/active_record/connection_adapters/sqlanywhere_adapter.rb +510 -0
- data/test/connection.rb +25 -0
- data/test/sqlanywhere.drop.sql +35 -0
- data/test/sqlanywhere.sql +222 -0
- data/test/sqlanywhere2.drop.sql +4 -0
- data/test/sqlanywhere2.sql +5 -0
- metadata +77 -0
data/CHANGELOG
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
/*====================================================
|
2
|
+
*
|
3
|
+
* Copyright 2008 iAnywhere Solutions, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
*
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
*
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
*
|
16
|
+
* See the License for the specific language governing permissions and
|
17
|
+
* limitations under the License.
|
18
|
+
*
|
19
|
+
* While not a requirement of the license, if you do modify this file, we
|
20
|
+
* would appreciate hearing about it. Please email sqlany_interfaces@sybase.com
|
21
|
+
*
|
22
|
+
*
|
23
|
+
*====================================================*/
|
data/README
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
=SQL Anywhere ActiveRecord Driver
|
2
|
+
|
3
|
+
This is a SQL Anywhere driver for Ruby ActiveRecord. This driver requires the
|
4
|
+
native SQL Anywhere Ruby driver. To get the native driver, use:
|
5
|
+
|
6
|
+
gem install sqlanywhere
|
7
|
+
|
8
|
+
This driver is designed for use with ActiveRecord 2.0.2 and greater.
|
9
|
+
|
10
|
+
This driver is licensed under the Apache License, Version 2.
|
11
|
+
|
12
|
+
==Making a Connection
|
13
|
+
|
14
|
+
The following code is a sample database configuration object.
|
15
|
+
|
16
|
+
ActiveRecord::Base.configurations = {
|
17
|
+
'arunit' => {
|
18
|
+
:adapter => 'sqlanywhere',
|
19
|
+
:database => 'arunit', #equivalent to the "dbn" parameter
|
20
|
+
:server => 'arunit', #equivalent to the "eng" parameter
|
21
|
+
:username => 'dba', #equivalent to the "uid" parameter
|
22
|
+
:password => 'sql' #equivalent to the "pwd" parameter
|
23
|
+
}
|
24
|
+
|
25
|
+
==Running the ActiveRecord Unit Test Suite
|
26
|
+
|
27
|
+
1. Open <tt><ACTIVERECORD_INSTALL_DIR>/rakefile</tt> and modify the line:
|
28
|
+
|
29
|
+
for adapter in %w( mysql postgresql sqlite sqlite3 firebird db2 oracle sybase openbase frontbase )
|
30
|
+
|
31
|
+
to include <tt>sqlanywhere</tt>. It should now look like:
|
32
|
+
|
33
|
+
for adapter in %w( mysql postgresql sqlite sqlite3 firebird db2 oracle sybase openbase frontbase sqlanywhere )
|
34
|
+
|
35
|
+
2. Create directory to hold the connection definition:
|
36
|
+
|
37
|
+
mkdir <ACTIVERECORD_INSTALL_DIR>/test/connections/native_sqlanywhere
|
38
|
+
|
39
|
+
3. Copy <tt>test/connection.rb</tt> into the newly created directory.
|
40
|
+
|
41
|
+
NOTE: If using ActiveRecord 2.0.2, change the second line of the file from:
|
42
|
+
|
43
|
+
require_dependency 'models/course'
|
44
|
+
|
45
|
+
to:
|
46
|
+
|
47
|
+
require_dependency 'fixtures/course'
|
48
|
+
|
49
|
+
4. Create the two test datbases. These can be created in any directory.
|
50
|
+
|
51
|
+
dbinit arunit
|
52
|
+
dbinit arunit2
|
53
|
+
dbsrv11 arunit arunit2
|
54
|
+
|
55
|
+
<b>If the commands cannot be found, make sure you have set up the SQL Anywhere environment variables correctly.</b> For more information
|
56
|
+
review the online documentation here[http://dcx.sybase.com/index.php#http%3A%2F%2Fdcx.sybase.com%2F1100en%2Fdbadmin_en11%2Fda-envvar-sect1-3672410.html].
|
57
|
+
|
58
|
+
5. If you are using ActiveRecord 2.0.2, you must load the test tables.
|
59
|
+
|
60
|
+
dbisql -c "eng=arunit;dbn=arunit;uid=dba;pwd=sql" sqlanywhere.sql
|
61
|
+
dbisql -c "eng=arunit;dbn=arunit2;uid=dba;pwd=sql" sqlanywhere2.sql
|
62
|
+
|
63
|
+
If you are using a newer version of ActiveRecord, this schema is automatically
|
64
|
+
migrated for you.
|
65
|
+
|
66
|
+
6. Run the unit test suite from the ActiveRecord install directory:
|
67
|
+
|
68
|
+
rake test_sqlanywhere
|
69
|
+
|
70
|
+
<b>If the migration tests fail, make sure you have set up the SQL Anywhere environment variables correctly.</b> For more information
|
71
|
+
review the online documentation here[http://dcx.sybase.com/index.php#http%3A%2F%2Fdcx.sybase.com%2F1100en%2Fdbadmin_en11%2Fda-envvar-sect1-3672410.html].
|
@@ -0,0 +1,510 @@
|
|
1
|
+
#====================================================
|
2
|
+
#
|
3
|
+
# Copyright 2008 iAnywhere Solutions, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
#
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
# While not a requirement of the license, if you do modify this file, we
|
20
|
+
# would appreciate hearing about it. Please email sqlany_interfaces@sybase.com
|
21
|
+
#
|
22
|
+
#
|
23
|
+
#====================================================
|
24
|
+
|
25
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
26
|
+
|
27
|
+
# Singleton class to hold a valid instance of the SQLAnywhereInterface across all connections
|
28
|
+
class SA
|
29
|
+
include Singleton
|
30
|
+
attr_accessor :api
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
unless defined? SQLAnywhere
|
34
|
+
require_library_or_gem 'sqlanywhere'
|
35
|
+
end
|
36
|
+
|
37
|
+
@api = SQLAnywhere::SQLAnywhereInterface.new()
|
38
|
+
result = SQLAnywhere::API.sqlany_initialize_interface(@api)
|
39
|
+
if result == 0
|
40
|
+
raise LoadError, "Could not load SQLAnywhere adapter DLL"
|
41
|
+
end
|
42
|
+
result = @api.sqlany_init()
|
43
|
+
if result == 0
|
44
|
+
raise LoadError, "Could not initialize SQLAnywhere adapter DLL"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module ActiveRecord
|
50
|
+
class Base
|
51
|
+
# Main connection function to SQL Anywhere
|
52
|
+
# Connection Adapter takes four parameters:
|
53
|
+
# * :database (required, no default). Corresponds to "ENG=" in connection string
|
54
|
+
# * :server (optional, defaults to :databse). Corresponds to "DBN=" in connection string
|
55
|
+
# * :username (optional, default to 'dba')
|
56
|
+
# * :password (optioanl, deafult to 'sql')
|
57
|
+
def self.sqlanywhere_connection(config)
|
58
|
+
|
59
|
+
if config.has_key?(:database)
|
60
|
+
database = config[:database]
|
61
|
+
else
|
62
|
+
raise ArgumentError, "No database name was given. Please add a :database option."
|
63
|
+
end
|
64
|
+
|
65
|
+
database = config[:database]
|
66
|
+
server = config[:server] ? config[:server].to_s : database
|
67
|
+
username = config[:username] ? config[:username].to_s : 'dba'
|
68
|
+
password = config[:password] ? config[:password].to_s : 'sql'
|
69
|
+
|
70
|
+
db = SA.instance.api.sqlany_new_connection()
|
71
|
+
SA.instance.api.sqlany_connect(db, "eng=#{server};dbn=#{database};uid=#{username};pwd=#{password}")
|
72
|
+
SA.instance.api.sqlany_execute_immediate(db, "SET OPTION non_keywords = 'LOGIN'")
|
73
|
+
ConnectionAdapters::SQLAnywhereAdapter.new(db, logger)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module ConnectionAdapters
|
78
|
+
class SQLAnywhereColumn < Column
|
79
|
+
private
|
80
|
+
# Overridden to handle SQL Anywhere integer, varchar, binary, and timestamp types
|
81
|
+
def simplified_type(field_type)
|
82
|
+
return :boolean if field_type =~ /tinyint/i
|
83
|
+
return :string if field_type =~ /varchar/i
|
84
|
+
return :binary if field_type =~ /long binary/i
|
85
|
+
return :datetime if field_type =~ /timestamp/i
|
86
|
+
return :integer if field_type =~ /smallint|bigint/i
|
87
|
+
super
|
88
|
+
end
|
89
|
+
|
90
|
+
def extract_limit(sql_type)
|
91
|
+
case sql_type
|
92
|
+
when /^tinyint/i: 1
|
93
|
+
when /^smallint/i: 2
|
94
|
+
when /^integer/i: 4
|
95
|
+
when /^bigint/i: 8
|
96
|
+
else super
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
# Handles the encoding of a binary object into SQL Anywhere
|
102
|
+
# SQL Anywhere requires that binary values be encoded as \xHH, where HH is a hexadecimal number
|
103
|
+
# This function encodes the binary string in this format
|
104
|
+
def self.string_to_binary(value)
|
105
|
+
if value
|
106
|
+
result = ''
|
107
|
+
value.each_byte do |c|
|
108
|
+
res = sprintf('\x%x', c)
|
109
|
+
res.insert(2, '0') if res.length == 3
|
110
|
+
result << res
|
111
|
+
end
|
112
|
+
result
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.binary_to_string(value)
|
117
|
+
%Q/#{value}/
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
class SQLAnywhereAdapter < AbstractAdapter
|
124
|
+
def adapter_name #:nodoc:
|
125
|
+
'SQLAnywhere'
|
126
|
+
end
|
127
|
+
|
128
|
+
def supports_migrations? #:nodoc:
|
129
|
+
true
|
130
|
+
end
|
131
|
+
|
132
|
+
def requires_reloading?
|
133
|
+
false
|
134
|
+
end
|
135
|
+
|
136
|
+
def disconnect!
|
137
|
+
SA.instance.api.sqlany_disconnect( @connection ) rescue nil
|
138
|
+
SA.instance.api.sqlany_free_connection( @connection ) rescue nil
|
139
|
+
super
|
140
|
+
end
|
141
|
+
|
142
|
+
def supports_count_distinct? #:nodoc:
|
143
|
+
true
|
144
|
+
end
|
145
|
+
|
146
|
+
def supports_autoincrement? #:nodoc:
|
147
|
+
true
|
148
|
+
end
|
149
|
+
|
150
|
+
# Maps native ActiveRecord/Ruby types into SQLAnywhere types
|
151
|
+
# TINYINTs are treated as the default boolean value
|
152
|
+
# ActiveRecord allows NULLs in boolean columns, and the SQL Anywhere BIT type does not
|
153
|
+
# As a result, TINYINT must be used. All TINYINT columns will be assumed to be boolean and
|
154
|
+
# should not be used as single-byte integer columns. This restriction is similar to other ActiveRecord database drivers
|
155
|
+
def native_database_types #:nodoc:
|
156
|
+
{
|
157
|
+
:primary_key => 'INTEGER PRIMARY KEY DEFAULT AUTOINCREMENT NOT NULL',
|
158
|
+
:string => { :name => "varchar", :limit => 255 },
|
159
|
+
:text => { :name => "long varchar" },
|
160
|
+
:integer => { :name => "integer" },
|
161
|
+
:float => { :name => "float" },
|
162
|
+
:decimal => { :name => "decimal" },
|
163
|
+
:datetime => { :name => "datetime" },
|
164
|
+
:timestamp => { :name => "datetime" },
|
165
|
+
:time => { :name => "datetime" },
|
166
|
+
:date => { :name => "date" },
|
167
|
+
:binary => { :name => "long binary" },
|
168
|
+
:boolean => { :name => "tinyint"}
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
# QUOTING ==================================================
|
173
|
+
|
174
|
+
# Applies quotations around column names in generated queries
|
175
|
+
def quote_column_name(name) #:nodoc:
|
176
|
+
%Q("#{name}")
|
177
|
+
end
|
178
|
+
|
179
|
+
# Handles special quoting of binary columns. Binary columns will be treated as strings inside of ActiveRecord.
|
180
|
+
# ActiveRecord requires that any strings it inserts into databases must escape the backslash (\).
|
181
|
+
# Since in the binary case, the (\x) is significant to SQL Anywhere, it cannot be escaped.
|
182
|
+
def quote(value, column = nil)
|
183
|
+
case value
|
184
|
+
when String, ActiveSupport::Multibyte::Chars
|
185
|
+
value_S = value.to_s
|
186
|
+
if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
187
|
+
"#{quoted_string_prefix}'#{column.class.string_to_binary(value_S)}'"
|
188
|
+
else
|
189
|
+
super(value, column)
|
190
|
+
end
|
191
|
+
else
|
192
|
+
super(value, column)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def quoted_true
|
197
|
+
'1'
|
198
|
+
end
|
199
|
+
|
200
|
+
def quoted_false
|
201
|
+
'0'
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
# SQL Anywhere, in accordance with the SQL Standard, does not allow a column to appear in the ORDER BY list
|
206
|
+
# that is not also in the SELECT with when obtaining DISTINCT rows beacuse the actual semantics of this query
|
207
|
+
# are unclear. The following functions create a query that mimics the way that SQLite and MySQL handle this query.
|
208
|
+
#
|
209
|
+
# This function (distinct) is based on the Oracle ActiveRecord driver created by Graham Jenkins (2005)
|
210
|
+
# (http://svn.rubyonrails.org/rails/adapters/oracle/lib/active_record/connection_adapters/oracle_adapter.rb)
|
211
|
+
def distinct(columns, order_by)
|
212
|
+
return "DISTINCT #{columns}" if order_by.blank?
|
213
|
+
order_columns = order_by.split(',').map { |s| s.strip }.reject(&:blank?)
|
214
|
+
order_columns = order_columns.zip((0...order_columns.size).to_a).map do |c, i|
|
215
|
+
"FIRST_VALUE(#{c.split.first}) OVER (PARTITION BY #{columns} ORDER BY #{c}) AS alias_#{i}__"
|
216
|
+
end
|
217
|
+
sql = "DISTINCT #{columns}, "
|
218
|
+
sql << order_columns * ", "
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
# This function (add_order_by_for_association_limiting) is based on the Oracle ActiveRecord driver created by Graham Jenkins (2005)
|
223
|
+
# (http://svn.rubyonrails.org/rails/adapters/oracle/lib/active_record/connection_adapters/oracle_adapter.rb)
|
224
|
+
def add_order_by_for_association_limiting!(sql, options)
|
225
|
+
return sql if options[:order].blank?
|
226
|
+
|
227
|
+
order = options[:order].split(',').collect { |s| s.strip }.reject(&:blank?)
|
228
|
+
order.map! {|s| $1 if s =~ / (.*)/}
|
229
|
+
order = order.zip((0...order.size).to_a).map { |s,i| "alias_#{i}__ #{s}" }.join(', ')
|
230
|
+
|
231
|
+
sql << " ORDER BY #{order}"
|
232
|
+
end
|
233
|
+
|
234
|
+
# By default, ActiveRecord attempts to use the MySQL/SQLite syntax of limit and offset. That is, adding LIMIT XX OFFSET XX
|
235
|
+
# at the end of the query. SQL Anywhere uses TOP XX START XX to handle this, adding immediatly following SELECT or SELECT DISTINCT.
|
236
|
+
# This function adds the limit and offset to the appropriate place in the query.
|
237
|
+
def add_limit_offset!(sql, options)
|
238
|
+
temp_sql = ''
|
239
|
+
if limit = options[:limit]
|
240
|
+
temp_sql << " TOP #{self.respond_to?('sanitize_limit') ? sanitize_limit(limit) : limit} "
|
241
|
+
if offset = options[:offset]
|
242
|
+
temp_sql << " START AT #{offset + 1}"
|
243
|
+
end
|
244
|
+
if sql =~ /^select distinct.*/i
|
245
|
+
sql.insert(15, temp_sql);
|
246
|
+
elsif sql =~ /^select.*/i
|
247
|
+
sql.insert(6, temp_sql);
|
248
|
+
else
|
249
|
+
sql = temp_sql;
|
250
|
+
end
|
251
|
+
end
|
252
|
+
sql
|
253
|
+
end
|
254
|
+
|
255
|
+
# The database execution function
|
256
|
+
def execute(sql, name = nil) #:nodoc:
|
257
|
+
return if sql.nil?
|
258
|
+
|
259
|
+
# ActiveRecord allows a query to return TOP 0. SQL Anywhere requires that the TOP value is a positive integer.
|
260
|
+
if sql =~ /TOP 0/i
|
261
|
+
return Array.new()
|
262
|
+
end
|
263
|
+
|
264
|
+
# Executes the query, iterates through the results, and builds an array of hashes.
|
265
|
+
rs = SA.instance.api.sqlany_execute_direct(@connection, sql)
|
266
|
+
raise ActiveRecord::StatementInvalid.new("#{SA.instance.api.sqlany_error(@connection)}:#{sql}") if rs.nil?
|
267
|
+
record = []
|
268
|
+
while SA.instance.api.sqlany_fetch_next(rs) == 1
|
269
|
+
max_cols = SA.instance.api.sqlany_num_cols(rs)
|
270
|
+
result = Hash.new()
|
271
|
+
max_cols.times do |cols|
|
272
|
+
result[SA.instance.api.sqlany_get_column_info(rs, cols)[2]] = SA.instance.api.sqlany_get_column(rs, cols)[1]
|
273
|
+
end
|
274
|
+
record << result
|
275
|
+
end
|
276
|
+
SA.instance.api.sqlany_free_stmt(rs)
|
277
|
+
return record
|
278
|
+
end
|
279
|
+
|
280
|
+
# The database update function.
|
281
|
+
def update_sql(sql, name = nil)
|
282
|
+
rs = SA.instance.api.sqlany_execute_direct(@connection, sql)
|
283
|
+
raise ActiveRecord::StatementInvalid.new("#{SA.instance.api.sqlany_error(@connection)}:#{sql}") if rs.nil?
|
284
|
+
retVal = SA.instance.api.sqlany_affected_rows(rs)
|
285
|
+
SA.instance.api.sqlany_free_stmt(rs)
|
286
|
+
execute (nil) # test suite counts number of executions. Dummy execution needed to pass tests.
|
287
|
+
return retVal
|
288
|
+
end
|
289
|
+
|
290
|
+
# The database delete function.
|
291
|
+
def delete_sql(sql, name = nil) #:nodoc:
|
292
|
+
rs = SA.instance.api.sqlany_execute_direct(@connection, sql)
|
293
|
+
raise ActiveRecord::StatementInvalid.new("#{SA.instance.api.sqlany_error(@connection)}:#{sql}") if rs.nil?
|
294
|
+
retVal = SA.instance.api.sqlany_affected_rows(rs)
|
295
|
+
SA.instance.api.sqlany_free_stmt(rs)
|
296
|
+
execute (nil) # test suite counts number of executions. Dummy execution needed to pass tests.
|
297
|
+
return retVal
|
298
|
+
end
|
299
|
+
|
300
|
+
# The database insert function.
|
301
|
+
# ActiveRecord requires that insert_sql returns the primary key of the row just inserted. In most cases, this can be accomplished
|
302
|
+
# by immediatly querying the @@identity property. If the @@identity property is 0, then passed id_value is used
|
303
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
304
|
+
retval = 0
|
305
|
+
rs = SA.instance.api.sqlany_execute_direct(@connection, sql)
|
306
|
+
raise ActiveRecord::StatementInvalid.new("#{SA.instance.api.sqlany_error(@connection)}:#{sql}") if rs.nil?
|
307
|
+
identity = SA.instance.api.sqlany_execute_direct(@connection, 'SELECT @@identity')
|
308
|
+
raise ActiveRecord::StatementInvalid.new("#{SA.instance.api.sqlany_error(@connection)}:#{sql}") if identity.nil?
|
309
|
+
SA.instance.api.sqlany_fetch_next(identity)
|
310
|
+
retval = SA.instance.api.sqlany_get_column(identity, 0)[1]
|
311
|
+
SA.instance.api.sqlany_free_stmt(identity)
|
312
|
+
SA.instance.api.sqlany_free_stmt(rs)
|
313
|
+
retval = id_value if retval == 0
|
314
|
+
execute (nil) # test suite counts number of executions. Dummy execution needed to pass tests.
|
315
|
+
return retval
|
316
|
+
end
|
317
|
+
|
318
|
+
# Returns a query as an array of arrays
|
319
|
+
def select_rows(sql, name = nil)
|
320
|
+
rs = SA.instance.api.sqlany_execute_direct(@connection, sql)
|
321
|
+
raise ActiveRecord::StatementInvalid.new("#{SA.instance.api.sqlany_error(@connection)}:#{sql}") if rs.nil?
|
322
|
+
record = []
|
323
|
+
while SA.instance.api.sqlany_fetch_next(rs) == 1
|
324
|
+
max_cols = SA.instance.api.sqlany_num_cols(rs)
|
325
|
+
result = Array.new(max_cols)
|
326
|
+
max_cols.times do |cols|
|
327
|
+
result[cols] = SA.instance.api.sqlany_get_column(rs, cols)[1]
|
328
|
+
end
|
329
|
+
record << result
|
330
|
+
end
|
331
|
+
SA.instance.api.sqlany_free_stmt(rs)
|
332
|
+
return record
|
333
|
+
end
|
334
|
+
|
335
|
+
def begin_db_transaction #:nodoc:
|
336
|
+
end
|
337
|
+
|
338
|
+
def commit_db_transaction #:nodoc:
|
339
|
+
SA.instance.api.sqlany_commit(@connection)
|
340
|
+
end
|
341
|
+
|
342
|
+
def rollback_db_transaction #:nodoc:
|
343
|
+
SA.instance.api.sqlany_rollback(@connection)
|
344
|
+
end
|
345
|
+
|
346
|
+
def add_lock!(sql, options) #:nodoc:
|
347
|
+
sql
|
348
|
+
end
|
349
|
+
|
350
|
+
# SQL Anywhere does not support sizing of integers based on the sytax INTEGER(size). Integer sizes
|
351
|
+
# must be captured when generating the SQL and replaced with the appropriate size.
|
352
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
353
|
+
if native = native_database_types[type]
|
354
|
+
if type == :integer
|
355
|
+
case limit
|
356
|
+
when 1
|
357
|
+
column_type_sql = 'tinyint'
|
358
|
+
when 2
|
359
|
+
column_type_sql = 'smallint'
|
360
|
+
when 3..4
|
361
|
+
column_type_sql = 'integer'
|
362
|
+
when 5..8
|
363
|
+
column_type_sql = 'bigint'
|
364
|
+
else
|
365
|
+
column_type_sql = 'integer'
|
366
|
+
end
|
367
|
+
column_type_sql
|
368
|
+
else
|
369
|
+
super(type, limit, precision, scale)
|
370
|
+
end
|
371
|
+
else
|
372
|
+
super(type, limit, precision, scale)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
# Do not return SYS-owned or DBO-owned tables
|
377
|
+
def tables(name = nil) #:nodoc:
|
378
|
+
sql = <<-SQL
|
379
|
+
SELECT table_name
|
380
|
+
FROM systable
|
381
|
+
WHERE creator not in (0,3)
|
382
|
+
SQL
|
383
|
+
|
384
|
+
select(sql, name).map do |row|
|
385
|
+
row["table_name"]
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def columns(table_name, name = nil) #:nodoc:
|
390
|
+
table_structure(table_name).map do |field|
|
391
|
+
field['default'] = field['default'][1..-2] if (!field['default'].nil? and field['default'][0].chr == "'")
|
392
|
+
SQLAnywhereColumn.new(field['name'], field['default'], field['domain'], (field['nulls'] == 1))
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def indexes(table_name, name = nil) #:nodoc:
|
397
|
+
|
398
|
+
sql = <<-SQL
|
399
|
+
SELECT index_name, "unique"
|
400
|
+
FROM systable join (sysidxcol join sysidx)
|
401
|
+
WHERE table_name = '#{table_name}' and index_category > 2
|
402
|
+
SQL
|
403
|
+
select(sql, name).map do |row|
|
404
|
+
index = IndexDefinition.new(table_name, row['index_name'])
|
405
|
+
index.unique = row['unique'] == 1
|
406
|
+
sql = <<-SQL
|
407
|
+
SELECT column_name
|
408
|
+
FROM (systable join systabcol) join (sysidxcol join sysidx)
|
409
|
+
WHERE table_name = '#{table_name}' and index_name = '#{row['index_name']}'
|
410
|
+
SQL
|
411
|
+
index.columns = select(sql).map { |col| col['column_name'] }
|
412
|
+
index
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
def primary_key(table_name) #:nodoc:
|
417
|
+
sql = <<-SQL
|
418
|
+
SELECT systabcol.column_name
|
419
|
+
FROM (systable join systabcol ) left outer join (sysidxcol join sysidx)
|
420
|
+
WHERE table_name = '#{table_name}' AND sysidxcol.sequence = 0
|
421
|
+
SQL
|
422
|
+
rs = select(sql)
|
423
|
+
if !rs.nil? and !rs[0].nil?
|
424
|
+
rs[0]['column_name']
|
425
|
+
else
|
426
|
+
nil
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
def remove_index(table_name, options={}) #:nodoc:
|
431
|
+
execute "DROP INDEX #{table_name}.#{quote_column_name(index_name(table_name, options))}"
|
432
|
+
end
|
433
|
+
|
434
|
+
def rename_table(name, new_name)
|
435
|
+
execute "ALTER TABLE #{quote_table_name(name)} RENAME #{quote_table_name(new_name)}"
|
436
|
+
end
|
437
|
+
|
438
|
+
def remove_column(table_name, column_name) #:nodoc:
|
439
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
|
440
|
+
end
|
441
|
+
|
442
|
+
def change_column_default(table_name, column_name, default) #:nodoc:
|
443
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} DEFAULT #{quote(default)}"
|
444
|
+
end
|
445
|
+
|
446
|
+
def change_column_null(table_name, column_name, null, default = nil)
|
447
|
+
unless null || default.nil?
|
448
|
+
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
449
|
+
end
|
450
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? '' : 'NOT'} NULL")
|
451
|
+
end
|
452
|
+
|
453
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
454
|
+
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
455
|
+
add_column_options!(add_column_sql, options)
|
456
|
+
add_column_sql << ' NULL' if options[:null]
|
457
|
+
execute(add_column_sql)
|
458
|
+
end
|
459
|
+
|
460
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
461
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
|
462
|
+
end
|
463
|
+
|
464
|
+
def drop_column(table_name, column_name)
|
465
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
|
466
|
+
end
|
467
|
+
|
468
|
+
|
469
|
+
protected
|
470
|
+
def select(sql, name = nil) #:nodoc:
|
471
|
+
return execute(sql, name)
|
472
|
+
end
|
473
|
+
|
474
|
+
# Queries the structure of a table including the columns names, defaults, type, and nullability
|
475
|
+
# ActiveRecord uses the type to parse scale and precision information out of the types. As a result,
|
476
|
+
# chars, varchars, binary, nchars, nvarchars must all be returned in the form <i>type</i>(<i>width</i>)
|
477
|
+
# numeric and decimal must be returned in the form <i>type</i>(<i>width</i>, <i>scale</i>)
|
478
|
+
# Nullability is returned as 0 (no nulls allowed) or 1 (nulls allowed)
|
479
|
+
# Alos, ActiveRecord expects an autoincrement column to have default value of NULL
|
480
|
+
|
481
|
+
def table_structure(table_name)
|
482
|
+
sql = <<-SQL
|
483
|
+
SELECT syscolumn.column_name as name,
|
484
|
+
(IF syscolumn."default" = 'autoincrement' then null else syscolumn."default" endif) as "default",
|
485
|
+
(IF syscolumn.domain_id IN (7,8,9,11,33,34,35,3,27) THEN
|
486
|
+
(IF syscolumn.domain_id IN (3, 27)
|
487
|
+
THEN sysdomain.domain_name || '(' || syscolumn.width || ',' || syscolumn.scale || ')'
|
488
|
+
ELSE sysdomain.domain_name || '(' || syscolumn.width || ')'
|
489
|
+
END IF)
|
490
|
+
ELSE sysdomain.domain_name endif) as domain,
|
491
|
+
(if syscolumn.nulls = 'Y' then 1 else 0 endif) as nulls
|
492
|
+
FROM syscolumn, systable, sysdomain
|
493
|
+
WHERE syscolumn.table_id = systable.table_id AND
|
494
|
+
table_name = '#{table_name}' AND
|
495
|
+
syscolumn.domain_id = sysdomain.domain_id
|
496
|
+
SQL
|
497
|
+
returning structure = select(sql) do
|
498
|
+
raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if false
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
# Required to prevent DEFAULT NULL being added to primary keys
|
503
|
+
def options_include_default?(options)
|
504
|
+
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
|
data/test/connection.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
print "Using native SQLAnywhere Interface\n"
|
2
|
+
require_dependency 'models/course'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
ActiveRecord::Base.logger = Logger.new("debug.log")
|
6
|
+
|
7
|
+
ActiveRecord::Base.configurations = {
|
8
|
+
'arunit' => {
|
9
|
+
:adapter => 'sqlanywhere',
|
10
|
+
:database => 'arunit',
|
11
|
+
:server => 'arunit',
|
12
|
+
:username => 'dba',
|
13
|
+
:password => 'sql'
|
14
|
+
},
|
15
|
+
'arunit2' => {
|
16
|
+
:adapter => 'sqlanywhere',
|
17
|
+
:database => 'arunit2',
|
18
|
+
:server => 'arunit',
|
19
|
+
:username => 'dba',
|
20
|
+
:password => 'sql'
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
ActiveRecord::Base.establish_connection 'arunit'
|
25
|
+
Course.establish_connection 'arunit2'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
DROP TABLE accounts
|
2
|
+
DROP TABLE funny_jokes
|
3
|
+
DROP TABLE companies
|
4
|
+
DROP TABLE topics
|
5
|
+
DROP TABLE developers
|
6
|
+
DROP TABLE projects
|
7
|
+
DROP TABLE developers_projects
|
8
|
+
DROP TABLE customers
|
9
|
+
DROP TABLE orders
|
10
|
+
DROP TABLE movies
|
11
|
+
DROP TABLE subscribers
|
12
|
+
DROP TABLE booleantests
|
13
|
+
DROP TABLE auto_id_tests
|
14
|
+
DROP TABLE entrants
|
15
|
+
DROP TABLE colnametests
|
16
|
+
DROP TABLE mixins
|
17
|
+
DROP TABLE people
|
18
|
+
DROP TABLE readers
|
19
|
+
DROP TABLE binaries
|
20
|
+
DROP TABLE computers
|
21
|
+
DROP TABLE tasks
|
22
|
+
DROP TABLE posts
|
23
|
+
DROP TABLE comments
|
24
|
+
DROP TABLE authors
|
25
|
+
DROP TABLE categories
|
26
|
+
DROP TABLE categories_posts
|
27
|
+
DROP TABLE fk_test_has_fk
|
28
|
+
DROP TABLE fk_test_has_pk
|
29
|
+
DROP TABLE keyboards
|
30
|
+
DROP TABLE legacy_things
|
31
|
+
DROP TABLE numeric_data
|
32
|
+
DROP TABLE mixed_case_monkeys
|
33
|
+
DROP TABLE minimalistics
|
34
|
+
DROP TABLE schema_info
|
35
|
+
go
|
@@ -0,0 +1,222 @@
|
|
1
|
+
CREATE TABLE accounts (
|
2
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
3
|
+
firm_id int NULL,
|
4
|
+
credit_limit int NULL
|
5
|
+
)
|
6
|
+
|
7
|
+
CREATE TABLE funny_jokes (
|
8
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
9
|
+
name varchar(50) NULL
|
10
|
+
)
|
11
|
+
|
12
|
+
CREATE TABLE companies (
|
13
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
14
|
+
type varchar(50) NULL,
|
15
|
+
ruby_type varchar(50) NULL,
|
16
|
+
firm_id int NULL,
|
17
|
+
name varchar(50) NULL,
|
18
|
+
client_of int NULL,
|
19
|
+
rating int default 1
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
CREATE TABLE topics (
|
24
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
25
|
+
title varchar(255) NULL,
|
26
|
+
author_name varchar(255) NULL,
|
27
|
+
author_email_address varchar(255) NULL,
|
28
|
+
written_on datetime NULL,
|
29
|
+
bonus_time time NULL,
|
30
|
+
last_read date NULL,
|
31
|
+
content varchar(255) NULL,
|
32
|
+
approved tinyint default 1,
|
33
|
+
replies_count int default 0,
|
34
|
+
parent_id int NULL,
|
35
|
+
type varchar(50) NULL
|
36
|
+
)
|
37
|
+
|
38
|
+
CREATE TABLE developers (
|
39
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
40
|
+
name varchar(100) NULL,
|
41
|
+
salary int default 70000,
|
42
|
+
created_at datetime NULL,
|
43
|
+
updated_at datetime NULL
|
44
|
+
)
|
45
|
+
|
46
|
+
CREATE TABLE projects (
|
47
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
48
|
+
name varchar(100) NULL,
|
49
|
+
type varchar(255) NULL
|
50
|
+
)
|
51
|
+
|
52
|
+
CREATE TABLE developers_projects (
|
53
|
+
developer_id int NOT NULL,
|
54
|
+
project_id int NOT NULL,
|
55
|
+
joined_on datetime NULL,
|
56
|
+
access_level smallint default 1
|
57
|
+
)
|
58
|
+
|
59
|
+
CREATE TABLE orders (
|
60
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
61
|
+
name varchar(100) NULL,
|
62
|
+
billing_customer_id int NULL,
|
63
|
+
shipping_customer_id int NULL
|
64
|
+
)
|
65
|
+
|
66
|
+
CREATE TABLE customers (
|
67
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
68
|
+
name varchar(100) NULL,
|
69
|
+
balance int default 0,
|
70
|
+
address_street varchar(100) NULL,
|
71
|
+
address_city varchar(100) NULL,
|
72
|
+
address_country varchar(100) NULL,
|
73
|
+
gps_location varchar(100) NULL
|
74
|
+
)
|
75
|
+
|
76
|
+
CREATE TABLE movies (
|
77
|
+
movieid integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
78
|
+
name varchar(100) NULL
|
79
|
+
)
|
80
|
+
|
81
|
+
CREATE TABLE subscribers (
|
82
|
+
nick varchar(100) PRIMARY KEY,
|
83
|
+
name varchar(100) NULL
|
84
|
+
)
|
85
|
+
|
86
|
+
CREATE TABLE booleantests (
|
87
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
88
|
+
value int NULL
|
89
|
+
)
|
90
|
+
|
91
|
+
CREATE TABLE auto_id_tests (
|
92
|
+
auto_id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
93
|
+
value int NULL
|
94
|
+
)
|
95
|
+
|
96
|
+
CREATE TABLE entrants (
|
97
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
98
|
+
name varchar(255) NOT NULL,
|
99
|
+
course_id int NOT NULL
|
100
|
+
)
|
101
|
+
|
102
|
+
CREATE TABLE colnametests (
|
103
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
104
|
+
[references] int NOT NULL
|
105
|
+
)
|
106
|
+
|
107
|
+
CREATE TABLE mixins (
|
108
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
109
|
+
parent_id int NULL,
|
110
|
+
pos int NULL,
|
111
|
+
created_at datetime NULL,
|
112
|
+
updated_at datetime NULL,
|
113
|
+
lft int NULL,
|
114
|
+
rgt int NULL,
|
115
|
+
root_id int NULL,
|
116
|
+
type varchar(40) NULL
|
117
|
+
)
|
118
|
+
|
119
|
+
CREATE TABLE people (
|
120
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
121
|
+
first_name varchar(40) NULL,
|
122
|
+
lock_version int DEFAULT 0
|
123
|
+
)
|
124
|
+
|
125
|
+
CREATE TABLE readers (
|
126
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
127
|
+
post_id int NOT NULL,
|
128
|
+
person_id int NOT NULL
|
129
|
+
)
|
130
|
+
|
131
|
+
CREATE TABLE binaries (
|
132
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
133
|
+
data long binary NULL
|
134
|
+
)
|
135
|
+
|
136
|
+
CREATE TABLE computers (
|
137
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
138
|
+
developer int NOT NULL,
|
139
|
+
extendedWarranty int NOT NULL
|
140
|
+
)
|
141
|
+
|
142
|
+
CREATE TABLE posts (
|
143
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
144
|
+
author_id int NULL,
|
145
|
+
title varchar(255) NOT NULL,
|
146
|
+
body varchar(2048) NOT NULL,
|
147
|
+
type varchar(255) DEFAULT NULL
|
148
|
+
)
|
149
|
+
|
150
|
+
CREATE TABLE comments (
|
151
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
152
|
+
post_id int NOT NULL,
|
153
|
+
body varchar(2048) NOT NULL,
|
154
|
+
type varchar(255) NOT NULL
|
155
|
+
)
|
156
|
+
|
157
|
+
CREATE TABLE authors (
|
158
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
159
|
+
name varchar(255) NOT NULL
|
160
|
+
)
|
161
|
+
|
162
|
+
CREATE TABLE tasks (
|
163
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
164
|
+
starting datetime NULL,
|
165
|
+
ending datetime NULL
|
166
|
+
)
|
167
|
+
|
168
|
+
CREATE TABLE categories (
|
169
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
170
|
+
name varchar(255) NOT NULL,
|
171
|
+
type varchar(255) NOT NULL
|
172
|
+
)
|
173
|
+
|
174
|
+
CREATE TABLE categories_posts (
|
175
|
+
category_id int NOT NULL,
|
176
|
+
post_id int NOT NULL
|
177
|
+
)
|
178
|
+
|
179
|
+
CREATE TABLE fk_test_has_pk (
|
180
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY
|
181
|
+
)
|
182
|
+
|
183
|
+
CREATE TABLE fk_test_has_fk (
|
184
|
+
id integer PRIMARY KEY,
|
185
|
+
fk_id integer NOT NULL,
|
186
|
+
|
187
|
+
FOREIGN KEY (fk_id) REFERENCES fk_test_has_pk(id)
|
188
|
+
)
|
189
|
+
|
190
|
+
|
191
|
+
CREATE TABLE keyboards (
|
192
|
+
key_number integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
193
|
+
name varchar(50) NULL
|
194
|
+
)
|
195
|
+
|
196
|
+
--This table has an altered lock_version column name.
|
197
|
+
CREATE TABLE legacy_things (
|
198
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
199
|
+
tps_report_number int default NULL,
|
200
|
+
version int default 0
|
201
|
+
)
|
202
|
+
|
203
|
+
|
204
|
+
CREATE TABLE numeric_data (
|
205
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
206
|
+
bank_balance numeric(10,2),
|
207
|
+
big_bank_balance numeric(15,2),
|
208
|
+
world_population numeric(10),
|
209
|
+
my_house_population numeric(2),
|
210
|
+
decimal_number_with_default numeric(3,2) DEFAULT 2.78
|
211
|
+
)
|
212
|
+
|
213
|
+
CREATE TABLE mixed_case_monkeys (
|
214
|
+
monkeyID integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY,
|
215
|
+
fleaCount integer
|
216
|
+
);
|
217
|
+
|
218
|
+
CREATE TABLE minimalistics (
|
219
|
+
id integer DEFAULT AUTOINCREMENT NOT NULL PRIMARY KEY
|
220
|
+
);
|
221
|
+
|
222
|
+
go
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: activerecord-sqlanywhere-adapter
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2008-11-03 00:00:00 -05:00
|
8
|
+
summary: ActiveRecord driver for SQL Anywhere
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: eric.farrar@ianywhere.com
|
12
|
+
homepage: http://sqlanywhere.rubyforge.org
|
13
|
+
rubyforge_project: sqlanywhere
|
14
|
+
description: ActiveRecord driver for SQL Anywhere
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.8.6
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Eric Farrar
|
31
|
+
files:
|
32
|
+
- lib/active_record/connection_adapters/sqlanywhere_adapter.rb
|
33
|
+
- test/connection.rb
|
34
|
+
- test/sqlanywhere.drop.sql
|
35
|
+
- test/sqlanywhere.sql
|
36
|
+
- test/sqlanywhere2.drop.sql
|
37
|
+
- test/sqlanywhere2.sql
|
38
|
+
- README
|
39
|
+
- CHANGELOG
|
40
|
+
- LICENSE
|
41
|
+
test_files: []
|
42
|
+
|
43
|
+
rdoc_options:
|
44
|
+
- --title
|
45
|
+
- ActiveRecord Driver for SQL Anywhere
|
46
|
+
- --main
|
47
|
+
- README
|
48
|
+
- --line-numbers
|
49
|
+
extra_rdoc_files:
|
50
|
+
- README
|
51
|
+
- CHANGELOG
|
52
|
+
- LICENSE
|
53
|
+
executables: []
|
54
|
+
|
55
|
+
extensions: []
|
56
|
+
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
dependencies:
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: sqlanywhere
|
62
|
+
version_requirement:
|
63
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.1.0
|
68
|
+
version:
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activerecord
|
71
|
+
version_requirement:
|
72
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 2.0.2
|
77
|
+
version:
|