do_sqlserver-tinytds 0.10.17.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/CONNECTING.markdown +40 -0
- data/ChangeLog.markdown +56 -0
- data/FAQS.markdown +8 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +30 -0
- data/INSTALL.markdown +76 -0
- data/LICENSE +21 -0
- data/README.md +95 -0
- data/Rakefile +7 -0
- data/buildfile +27 -0
- data/do_sqlserver_tinytds.gemspec +31 -0
- data/lib/do_sqlserver.rb +1 -0
- data/lib/do_sqlserver_tinytds.rb +360 -0
- data/lib/do_sqlserver_tinytds/addressable_extension.rb +69 -0
- data/lib/do_sqlserver_tinytds/tiny_tds_extension.rb +123 -0
- data/lib/do_sqlserver_tinytds/transaction.rb +36 -0
- data/lib/do_sqlserver_tinytds/version.rb +5 -0
- data/spec/command_spec.rb +9 -0
- data/spec/connection_spec.rb +21 -0
- data/spec/encoding_spec.rb +8 -0
- data/spec/reader_spec.rb +8 -0
- data/spec/result_spec.rb +16 -0
- data/spec/spec_helper.rb +155 -0
- data/spec/typecast/array_spec.rb +8 -0
- data/spec/typecast/bigdecimal_spec.rb +9 -0
- data/spec/typecast/boolean_spec.rb +9 -0
- data/spec/typecast/byte_array_spec.rb +31 -0
- data/spec/typecast/class_spec.rb +8 -0
- data/spec/typecast/date_spec.rb +11 -0
- data/spec/typecast/datetime_spec.rb +9 -0
- data/spec/typecast/float_spec.rb +9 -0
- data/spec/typecast/integer_spec.rb +8 -0
- data/spec/typecast/nil_spec.rb +10 -0
- data/spec/typecast/other_spec.rb +8 -0
- data/spec/typecast/range_spec.rb +8 -0
- data/spec/typecast/string_spec.rb +8 -0
- data/spec/typecast/time_spec.rb +8 -0
- metadata +169 -0
- metadata.gz.sig +3 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e4350cba1497e5dedf23f8f292ade5f41f37f0c5
|
4
|
+
data.tar.gz: 0d713306670222a6eebe2bc2776f41bd11fd8dcb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 26a8cb0d7faa67fffdd71e27ba35a1d2eaf96adcc1697a1cb7c873215229a966c015974b11ebd83ff3fa65bb7b2d56d2003c6a2486b63aa99be9d987f06f2d7e
|
7
|
+
data.tar.gz: f41621cfb2ec8ed5424484d0d17b8022bf07e941adc4beaf66caa0c5c3a4c331fc3c59aaa0990c26063bc1be936e93e4f1ed73cc11e2869bafdef1176f60450f
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
Binary file
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/CONNECTING.markdown
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
CONNECTING
|
2
|
+
==========
|
3
|
+
|
4
|
+
Various notes (needs to be cleaned-up).
|
5
|
+
|
6
|
+
See:
|
7
|
+
* <http://blogs.msdn.com/sqlexpress/archive/2004/07/23/192044.aspx>
|
8
|
+
* <http://blogs.msdn.com/b/bethmassi/archive/2008/09/17/enabling-remote-sql-express-2008-network-connections-on-vista.aspx>
|
9
|
+
|
10
|
+
|
11
|
+
Example Setup
|
12
|
+
-------------
|
13
|
+
|
14
|
+
* In Visual Studio, click Server Explorer
|
15
|
+
* Right click Data Connections
|
16
|
+
* Create New SQL Server Database
|
17
|
+
* Server Name: YOURPCNAME\SQLEXPRESS
|
18
|
+
* Use Windows Authentication
|
19
|
+
* #Use SQL Server Authentication
|
20
|
+
* #User name: do_test
|
21
|
+
* #Password: do_test
|
22
|
+
* New database name: do_test
|
23
|
+
|
24
|
+
See:
|
25
|
+
<http://social.msdn.microsoft.com/Forums/en-US/Vsexpressinstall/thread/aaf2f68c-4a40-44c8-b7ee-b2f5d94e23c3>
|
26
|
+
|
27
|
+
---
|
28
|
+
|
29
|
+
|
30
|
+
Tips
|
31
|
+
----
|
32
|
+
|
33
|
+
* Check the password is not required to be set on first connect.
|
34
|
+
* Test you can connect locally. Either through Visual Studio SQL Server tools,
|
35
|
+
SQL Server Management Studio, or simply using telnet: `telnet localhost 4322`.
|
36
|
+
* Configure Firewall correctly: http://support.microsoft.com/kb/287932
|
37
|
+
* Specify an instance: in the DO URL append `INSTANCE=SQLEXPRESS`.
|
38
|
+
* You can not add the instance to the hostname, i.e. `192.168.2.110\SQLEXPRESS`
|
39
|
+
as the underlying jTDS driver needs a URL that looks like this:
|
40
|
+
`jdbc:jtds:sqlserver://192.168.2.110:1433/do_test;instance=SQLEXPRESS`.
|
data/ChangeLog.markdown
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
## 0.10.7 2011-10-13
|
2
|
+
|
3
|
+
No changes
|
4
|
+
|
5
|
+
## 0.10.6 2011-05-22
|
6
|
+
|
7
|
+
No changes
|
8
|
+
|
9
|
+
## 0.10.5 2011-05-03
|
10
|
+
|
11
|
+
No changes
|
12
|
+
|
13
|
+
## 0.10.4 2011-04-28
|
14
|
+
|
15
|
+
New features
|
16
|
+
* Add save point to transactions (all)
|
17
|
+
* JRuby 1.9 mode support (encodings etc.)
|
18
|
+
|
19
|
+
Bugfixes
|
20
|
+
* Fix bug when using nested transactions in concurrent scenarios (all)
|
21
|
+
* Use column aliases instead of names (jruby)
|
22
|
+
|
23
|
+
Other
|
24
|
+
* Switch back to RSpec
|
25
|
+
|
26
|
+
## 0.10.3 2011-01-30
|
27
|
+
* No changes
|
28
|
+
|
29
|
+
## 0.10.2 2010-05-19
|
30
|
+
* No changes
|
31
|
+
|
32
|
+
## 0.10.1 2010-01-08
|
33
|
+
|
34
|
+
Initial release as part of mainline DataObjects project.
|
35
|
+
|
36
|
+
* Switch to Jeweler for Gem building tasks (this change may be temporary).
|
37
|
+
* Switch to using Bacon for running specs: This should make specs friendlier to
|
38
|
+
new Ruby implementations that are not yet 100% MRI-compatible, and in turn,
|
39
|
+
pave the road for our own IronRuby and MacRuby support.
|
40
|
+
* Switch to the newly added rake-compiler `JavaExtensionTask` for compiling
|
41
|
+
JRuby extensions, instead of our (broken) home-grown solution.
|
42
|
+
|
43
|
+
* Known Issues:
|
44
|
+
* Writing Extlib::ByteArray is not currently supported.
|
45
|
+
|
46
|
+
## 0.10.0 2009-09-15
|
47
|
+
|
48
|
+
(NOT RELEASED)
|
49
|
+
|
50
|
+
* Improvements
|
51
|
+
* JRuby Support (using *do_jdbc*)
|
52
|
+
|
53
|
+
## 0.0.1 2009-05-11
|
54
|
+
|
55
|
+
* 1 major enhancement:
|
56
|
+
* Initial release
|
data/FAQS.markdown
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
FAQS
|
2
|
+
====
|
3
|
+
|
4
|
+
* Can I use Microsoft's SQL Server driver instead of jTDS?
|
5
|
+
|
6
|
+
No, not currently. Currently the DataObjects Driver implementation is tied not
|
7
|
+
only to a relational database, but to its JDBC driver implementation. You could
|
8
|
+
create an alternate database implementation.
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
do_sqlserver-tinytds (0.10.15)
|
5
|
+
data_objects (~> 0.10.13)
|
6
|
+
tiny_tds (~> 0.5)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
addressable (2.3.4)
|
12
|
+
data_objects (0.10.13)
|
13
|
+
addressable (~> 2.1)
|
14
|
+
diff-lcs (1.1.3)
|
15
|
+
rspec (2.7.0)
|
16
|
+
rspec-core (~> 2.7.0)
|
17
|
+
rspec-expectations (~> 2.7.0)
|
18
|
+
rspec-mocks (~> 2.7.0)
|
19
|
+
rspec-core (2.7.1)
|
20
|
+
rspec-expectations (2.7.0)
|
21
|
+
diff-lcs (~> 1.1.2)
|
22
|
+
rspec-mocks (2.7.0)
|
23
|
+
tiny_tds (0.5.1)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
do_sqlserver-tinytds!
|
30
|
+
rspec (~> 2.5)
|
data/INSTALL.markdown
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
INSTALLING
|
2
|
+
==========
|
3
|
+
|
4
|
+
JRuby variant driver
|
5
|
+
--------------------
|
6
|
+
|
7
|
+
* Install the jTDS JDBC Driver. For your convenience, DO packages it as a Ruby
|
8
|
+
Gem. If installing from source, `cd` to `../jdbc_drivers/sqlserver/` and run
|
9
|
+
`rake install`.
|
10
|
+
* There are currently no other prerequisites for installation.
|
11
|
+
|
12
|
+
1.8.6/7 (MRI) and 1.9.x (YARV) variant
|
13
|
+
--------------------------------------
|
14
|
+
|
15
|
+
1. Install the DBI and DBD::ODBC dependencies:
|
16
|
+
|
17
|
+
sudo gem install dbi
|
18
|
+
sudo gem install dbd-odbc
|
19
|
+
|
20
|
+
2. Install [ODBC Binding for Ruby][rubyodbc]. It it *not* currently available
|
21
|
+
via RubyGems, so you'll have to download the source tarball:
|
22
|
+
|
23
|
+
wget http://www.ch-werner.de/rubyodbc/ruby-odbc-0.9997.tar.gz
|
24
|
+
tar xvfz ruby-odbc-0.9997.tar.gz
|
25
|
+
cd ruby-odbc-0.9997
|
26
|
+
|
27
|
+
|
28
|
+
3. Ensure you read the accompanying `COPYING` file, as the ODBC Binding for Ruby
|
29
|
+
is licensed under the GPL, unlike DataObjects. To install read the
|
30
|
+
accompanying `INSTALL` file. On a recent variant of OS X, installation
|
31
|
+
should look like this:
|
32
|
+
|
33
|
+
ruby extconf.rb
|
34
|
+
make
|
35
|
+
sudo make install
|
36
|
+
|
37
|
+
4. You must also have FreeTDS or [unixODBC][unixodbc] (SQL Server license for
|
38
|
+
unixODBC is commercially licensed though) installed.
|
39
|
+
|
40
|
+
5. To install FreeTDS on OS X, you can use MacPorts:
|
41
|
+
|
42
|
+
sudo port install freetds
|
43
|
+
|
44
|
+
****************************************************************
|
45
|
+
Configuration file freetds.conf does not exist and has been created using
|
46
|
+
/opt/local/etc/freetds/freetds.conf.sample
|
47
|
+
Configuration file locales.conf does not exist and has been created using
|
48
|
+
/opt/local/etc/freetds/locales.conf.sample
|
49
|
+
Configuration file pool.conf does not exist and has been created using
|
50
|
+
/opt/local/etc/freetds/pool.conf.sample
|
51
|
+
****************************************************************
|
52
|
+
|
53
|
+
|
54
|
+
* Then edit your ODBC configuration and add the FreeTDS driver.
|
55
|
+
|
56
|
+
* Using a text editor: On OS X, open `/Library/ODBC/odbcinst.ini` and add
|
57
|
+
the following entries:
|
58
|
+
|
59
|
+
[FreeTDS]
|
60
|
+
Driver = /opt/local/lib/libtdsodbc.so
|
61
|
+
Setup = /opt/local/lib/libtdsodbc.so
|
62
|
+
|
63
|
+
* You can also use a GUI for this (provided in Mac OS X 10.3 - 10.5;
|
64
|
+
[ODBCManager][odbcmanager] available for OS X 10.6)..
|
65
|
+
* Start ODBC Manager
|
66
|
+
* Go to *Drivers*, *Add...*
|
67
|
+
* Enter _FreeTDS_ as Driver Name.
|
68
|
+
* Enter `/usr/local/freetds/lib/libtdsodbc.so` as Driver File
|
69
|
+
* Enter `/usr/local/freetds/lib/libtdsodbc.so` as Setup File
|
70
|
+
* Select *System*
|
71
|
+
* Click *OK*.
|
72
|
+
|
73
|
+
|
74
|
+
[rubyodbc]:http://www.ch-werner.de/rubyodbc/README
|
75
|
+
[unixodbc]:http://www.unixodbc.org/
|
76
|
+
[odbcmanager]:http://www.odbcmanager.net/index.php
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2009 Clifford Heath
|
2
|
+
Copyright (c) 2009 - 2011 Alex Coles
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# do_sqlserver
|
2
|
+
|
3
|
+
* <http://dataobjects.info>
|
4
|
+
|
5
|
+
## Description
|
6
|
+
|
7
|
+
A Microsoft SQL Server adapter for DataObjects,
|
8
|
+
|
9
|
+
## Features/Problems
|
10
|
+
|
11
|
+
This driver implements the DataObjects API for the Microsoft SQL Server
|
12
|
+
relational database.
|
13
|
+
|
14
|
+
Problems with previous MRI implementation (unreleased):
|
15
|
+
|
16
|
+
* Relies on DBI's support for either ADO or ODBC with FreeTDS
|
17
|
+
* Has no tests and no data type conversion yet
|
18
|
+
|
19
|
+
This version uses TinyTDS instead. Is still alpha, and not production ready.
|
20
|
+
|
21
|
+
## Synopsis
|
22
|
+
|
23
|
+
Examples of usage:
|
24
|
+
|
25
|
+
# default port (using SQL Server Express Edition)
|
26
|
+
DataObjects::Connection.new('sqlserver://user:pass@host/database;instance=SQLEXPRESS')
|
27
|
+
# port specified (using SQL Server Express Edition)
|
28
|
+
DataObjects::Connection.new('sqlserver://user:pass@host:1433/database;instance=SQLEXPRESS')
|
29
|
+
|
30
|
+
@connection = DataObjects::Connection.new("sqlserver://john:p3$$@localhost:1433/userinfo")
|
31
|
+
@reader = @connection.create_command('SELECT * FROM users').execute_reader
|
32
|
+
@reader.next!
|
33
|
+
|
34
|
+
* See also the accompanying `CONNECTING.markdown`.
|
35
|
+
|
36
|
+
## Requirements
|
37
|
+
|
38
|
+
This driver is provided for the following platforms:
|
39
|
+
* JRuby 1.3.1 + (1.4+ recommended).
|
40
|
+
|
41
|
+
Code for the following platform is in the repository, but is still under EARLY
|
42
|
+
DEVELOPMENT and is neither RELEASED or SUPPORTED:
|
43
|
+
* Ruby MRI (1.8.6/7), 1.9: tested on Linux, Mac OS X and Windows platforms.
|
44
|
+
|
45
|
+
Additionally you should have the following prerequisites:
|
46
|
+
* `data_objects` gem
|
47
|
+
* `do_jdbc` gem (shared library), if running on JRuby.
|
48
|
+
* `dbi` gem, if running on MRI.
|
49
|
+
* On non-Windows platforms, unixODBC and FreeTDS libraries.
|
50
|
+
|
51
|
+
## Install
|
52
|
+
|
53
|
+
To install the gem:
|
54
|
+
|
55
|
+
gem install do_sqlserver
|
56
|
+
|
57
|
+
To compile and install from source:
|
58
|
+
|
59
|
+
* For MRI:
|
60
|
+
* Installation of do_sqlserver is significantly more involved than for other
|
61
|
+
drivers. Please see the accompanying `INSTALL.markdown`.
|
62
|
+
|
63
|
+
Then:
|
64
|
+
|
65
|
+
sudo gem install do_sqlserver
|
66
|
+
|
67
|
+
For more information, see the SQL Server driver wiki page:
|
68
|
+
<http://wiki.github.com/datamapper/do/sql-server>.
|
69
|
+
|
70
|
+
## Developers
|
71
|
+
|
72
|
+
Follow the above installation instructions. Additionally, you'll need:
|
73
|
+
* `rspec` gem for running specs.
|
74
|
+
* `YARD` gem for generating documentation.
|
75
|
+
|
76
|
+
See the DataObjects wiki for more comprehensive information on installing and
|
77
|
+
contributing to the JRuby-variant of this driver:
|
78
|
+
<http://wiki.github.com/datamapper/do/jruby>.
|
79
|
+
|
80
|
+
To run specs:
|
81
|
+
|
82
|
+
rake spec
|
83
|
+
|
84
|
+
To run specs without compiling extensions first:
|
85
|
+
|
86
|
+
rake spec_no_compile
|
87
|
+
|
88
|
+
To run individual specs:
|
89
|
+
|
90
|
+
rake spec SPEC=spec/connection_spec.rb
|
91
|
+
|
92
|
+
## License
|
93
|
+
|
94
|
+
This code is licensed under an **MIT (X11) License**. Please see the
|
95
|
+
accompanying `LICENSE` file.
|
data/Rakefile
ADDED
data/buildfile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Apache Buildr buildfile for do_sqlserver
|
2
|
+
# see http://incubator.apache.org/buildr/ for more information on Apache Buildr
|
3
|
+
require 'buildr'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
VERSION_NUMBER = '1.0'
|
7
|
+
JDBC_SUPPORT = ['data_objects:jdbc:jar:1.0']
|
8
|
+
TARGET_DIR = 'pkg/classes'
|
9
|
+
repositories.remote << 'http://www.ibiblio.org/maven2/'
|
10
|
+
|
11
|
+
define 'do_sqlserver' do
|
12
|
+
project.version = VERSION_NUMBER
|
13
|
+
project.group = 'data_objects.rb'
|
14
|
+
|
15
|
+
manifest['Copyright'] = 'Raimonds Simanovskis (C) 2009'
|
16
|
+
|
17
|
+
compile.using :target => '1.5', :lint => 'all', :deprecation => 'true'
|
18
|
+
|
19
|
+
define 'ext-java' do
|
20
|
+
package(:jar).clean.include(TARGET_DIR)
|
21
|
+
|
22
|
+
jdbc_support_jar = file('../../do_jdbc/lib/do_jdbc_internal.jar')
|
23
|
+
jdbc_support = artifact('data_objects:jdbc:jar:1.0').from(jdbc_support_jar)
|
24
|
+
|
25
|
+
compile.into(TARGET_DIR).with(JDBC_SUPPORT)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'do_sqlserver_tinytds/version'
|
5
|
+
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = %q{do_sqlserver-tinytds}
|
9
|
+
spec.version = DataObjects::SqlServer::VERSION
|
10
|
+
|
11
|
+
spec.authors = ["Juan Leal", "Caleb Tutty"]
|
12
|
+
spec.description = %q{Implements the DataObjects API for Microsoft SQL Server using TinyTDS}
|
13
|
+
spec.email = %q{sellingangle@hotmail.com caleb@prettymint.co.nz}
|
14
|
+
spec.summary = %q{DataObjects SQL Server Driver using TinyTDS}
|
15
|
+
|
16
|
+
spec.homepage = ""
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files`.split($/)
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
|
23
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
24
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
25
|
+
|
26
|
+
|
27
|
+
spec.add_dependency 'data_objects', '~> 0.10.13'
|
28
|
+
spec.add_dependency 'tiny_tds', '~> 0.5'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 2.5'
|
30
|
+
|
31
|
+
end
|
data/lib/do_sqlserver.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'do_sqlserver_tinytds'
|
@@ -0,0 +1,360 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'data_objects'
|
4
|
+
require 'bigdecimal'
|
5
|
+
require 'date'
|
6
|
+
require 'base64'
|
7
|
+
require 'do_sqlserver_tinytds/version'
|
8
|
+
require 'do_sqlserver_tinytds/transaction'
|
9
|
+
require 'do_sqlserver_tinytds/tiny_tds_extension'
|
10
|
+
require 'do_sqlserver_tinytds/addressable_extension'
|
11
|
+
|
12
|
+
|
13
|
+
module DataObjects
|
14
|
+
module SqlServer
|
15
|
+
|
16
|
+
class Connection < DataObjects::Connection
|
17
|
+
def method_missing(method, *args)
|
18
|
+
if @connection.respond_to?(method)
|
19
|
+
begin
|
20
|
+
@connection.send(method , *args)
|
21
|
+
rescue TinyTds::Error => te
|
22
|
+
case te.db_error_number
|
23
|
+
when 20019
|
24
|
+
#Got a pending transcation there, lets make it let go
|
25
|
+
@connection.close
|
26
|
+
set_tiny_tds_connection
|
27
|
+
#give it another try
|
28
|
+
@connection.send(method, *args)
|
29
|
+
else
|
30
|
+
raise te
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_tiny_tds_connection
|
37
|
+
@connection = TinyTds::Client.new(@options).tap do |client|
|
38
|
+
client.execute("SET ANSI_NULLS ON").do
|
39
|
+
client.execute("SET QUOTED_IDENTIFIER ON").do
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize uri
|
44
|
+
host = uri.host
|
45
|
+
user = uri.user || "sa"
|
46
|
+
password = uri.password || ""
|
47
|
+
path = uri.path.sub(%r{^/*}, '')
|
48
|
+
port = uri.port || "1433"
|
49
|
+
azure = uri.query['azure'] || false
|
50
|
+
|
51
|
+
begin
|
52
|
+
_encoding = uri.query && uri.query["encoding"] || "UTF-8"
|
53
|
+
@encoding = Encoding.find(_encoding) ? _encoding : "UTF-8"
|
54
|
+
rescue
|
55
|
+
@encoding = "UTF-8"
|
56
|
+
end
|
57
|
+
|
58
|
+
@options = {:username => user,
|
59
|
+
:password => password,
|
60
|
+
:port => port ,
|
61
|
+
:encoding => @encoding,
|
62
|
+
:timeout => 5000,
|
63
|
+
:dataserver => host,
|
64
|
+
:database => path,
|
65
|
+
:azure => azure
|
66
|
+
}
|
67
|
+
|
68
|
+
@options[:dataserver] = host
|
69
|
+
|
70
|
+
begin
|
71
|
+
set_tiny_tds_connection
|
72
|
+
#@connection = DBI.connect(connection_string, user, password)
|
73
|
+
rescue Exception => e
|
74
|
+
raise
|
75
|
+
end
|
76
|
+
|
77
|
+
set_date_format = create_command("SET DATEFORMAT YMD").execute_non_query
|
78
|
+
options_reader = create_command("DBCC USEROPTIONS").execute_reader
|
79
|
+
while options_reader.next!
|
80
|
+
key, value = *options_reader.values
|
81
|
+
value = options_reader.values
|
82
|
+
case key
|
83
|
+
when "textsize" # "64512"
|
84
|
+
when "language" # "us_english", "select * from master..syslanguages" for info
|
85
|
+
when "dateformat" # "ymd"
|
86
|
+
when "datefirst" # "7" = Sunday, first day of the week, change with "SET DATEFIRST"
|
87
|
+
when "quoted_identifier" # "SET"
|
88
|
+
when "ansi_null_dflt_on" # "SET"
|
89
|
+
when "ansi_defaults" # "SET"
|
90
|
+
when "ansi_warnings" # "SET"
|
91
|
+
when "ansi_padding" # "SET"
|
92
|
+
when "ansi_nulls" # "SET"
|
93
|
+
when "concat_null_yields_null" # "SET"
|
94
|
+
else
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def using_socket?
|
100
|
+
# This might be an unnecessary feature dragged from the mysql driver
|
101
|
+
raise "Not yet implemented"
|
102
|
+
end
|
103
|
+
|
104
|
+
def character_set
|
105
|
+
@encoding
|
106
|
+
end
|
107
|
+
|
108
|
+
def dispose
|
109
|
+
return false if @connection.closed?
|
110
|
+
@connection.close
|
111
|
+
true
|
112
|
+
rescue
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
def raw
|
117
|
+
@connection
|
118
|
+
end
|
119
|
+
|
120
|
+
:private
|
121
|
+
|
122
|
+
#debugger_on - used only for development when debugging things
|
123
|
+
def debugger_on=(value)
|
124
|
+
$debugger_on = value
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class Command < DataObjects::Command
|
129
|
+
IDENTITY_ROWCOUNT_QUERY = 'SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident, @@ROWCOUNT AS AffectedRows'
|
130
|
+
|
131
|
+
attr_reader :types
|
132
|
+
|
133
|
+
def debugger_on(value)
|
134
|
+
$debugger_on = value
|
135
|
+
end
|
136
|
+
|
137
|
+
def set_types *t
|
138
|
+
@types = t.flatten
|
139
|
+
end
|
140
|
+
|
141
|
+
def execute_non_query *args
|
142
|
+
DataObjects::SqlServer.check_params @text, args
|
143
|
+
|
144
|
+
begin
|
145
|
+
handle = @connection.raw_execute(@text , *args)
|
146
|
+
handle.do
|
147
|
+
rescue TinyTds::Error => te
|
148
|
+
|
149
|
+
handle.cancel if handle && handle.respond_to?(:cancel) && !@connection.sqlsent?
|
150
|
+
|
151
|
+
DataObjects::SqlServer.raise_db_error(te, @text, args)
|
152
|
+
rescue RuntimeError => re
|
153
|
+
case re.message
|
154
|
+
when "closed connection"
|
155
|
+
raise DataObjects::ConnectionError.new(re.message)
|
156
|
+
end
|
157
|
+
rescue Exception => e
|
158
|
+
raise e
|
159
|
+
end
|
160
|
+
|
161
|
+
# Get the inserted ID and the count of affected rows:
|
162
|
+
inserted_id = @connection.execute("SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident").each.first['Ident']
|
163
|
+
row_count = handle.affected_rows
|
164
|
+
Result.new(self, row_count, inserted_id)
|
165
|
+
end
|
166
|
+
|
167
|
+
def execute_reader *args
|
168
|
+
DataObjects::SqlServer.check_params @text, args
|
169
|
+
massage_limit_and_offset args
|
170
|
+
begin
|
171
|
+
handle = @connection.raw_execute(@text, *args)
|
172
|
+
|
173
|
+
rescue Exception => e
|
174
|
+
|
175
|
+
handle.cancel if handle && handle.respond_to?(:cancel) && !@connection.sqlsent?
|
176
|
+
raise
|
177
|
+
end
|
178
|
+
|
179
|
+
Reader.new(self, handle)
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
def massage_limit_and_offset args
|
184
|
+
@text.sub!(%r{SELECT (.*) ORDER BY (.*) LIMIT ([?0-9]*)( OFFSET ([?0-9]*))?}) {
|
185
|
+
what, order, limit, offset = $1, $2, $3, $5
|
186
|
+
|
187
|
+
# LIMIT and OFFSET will probably be set by args. We need exact values, so must
|
188
|
+
# do substitution here, and remove those args from the array. This is made easier
|
189
|
+
# because LIMIT and OFFSET are always the last args in the array.
|
190
|
+
offset = args.pop if offset == '?'
|
191
|
+
limit = args.pop if limit == '?'
|
192
|
+
offset = offset.to_i
|
193
|
+
limit = limit.to_i
|
194
|
+
|
195
|
+
#Reverse the sort direction of each field in the ORDER BY:
|
196
|
+
rev_order = order.split(/, */).map{ |f|
|
197
|
+
f =~ /(.*) DESC *$/ ? $1 : f+" DESC"
|
198
|
+
}*", "
|
199
|
+
|
200
|
+
"SELECT TOP #{limit} * FROM (SELECT TOP #{offset+limit} #{what} ORDER BY #{rev_order}) ORDER BY #{order}"
|
201
|
+
}
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
class Result < DataObjects::Result
|
206
|
+
end
|
207
|
+
|
208
|
+
class Reader < DataObjects::Reader
|
209
|
+
def initialize command, handle
|
210
|
+
@command, @handle = command, handle
|
211
|
+
return unless @handle
|
212
|
+
|
213
|
+
@fields = handle.fields
|
214
|
+
|
215
|
+
@rows = []
|
216
|
+
types = @command.types
|
217
|
+
if types && types.size != @fields.size
|
218
|
+
@handle.cancel if @handle && @handle.respond_to?(:cancel)
|
219
|
+
raise ArgumentError, "Field-count mismatch. Expected #{types.size} fields, but the query yielded #{@fields.size}"
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
@handle.each(:as => :array) do |row|
|
224
|
+
field = -1
|
225
|
+
@rows << row.map do |value|
|
226
|
+
field += 1
|
227
|
+
|
228
|
+
next value if !types && !value.is_a?(Time)
|
229
|
+
|
230
|
+
field_type = types && types[field]
|
231
|
+
value_class = value.class
|
232
|
+
|
233
|
+
r_value = case
|
234
|
+
when field_type == NilClass || value.nil?
|
235
|
+
nil
|
236
|
+
when field_type.nil? && value.is_a?(Time)
|
237
|
+
#sql small dates have zeros for hr, min, sec
|
238
|
+
# and needs to be cast as Date, else cast as DateTime
|
239
|
+
if (value.hour + value.min + value.sec) == 0
|
240
|
+
time_to_date(value)
|
241
|
+
else
|
242
|
+
time_to_date_time(value)
|
243
|
+
end
|
244
|
+
when value.is_a?(field_type) || value_class.kind_of?(field_type) || field_type == TrueClass
|
245
|
+
value
|
246
|
+
when field_type == Integer
|
247
|
+
Integer(value)
|
248
|
+
when field_type == Float
|
249
|
+
Float(value)
|
250
|
+
when field_type == String
|
251
|
+
raise "Value '#{value.inspect}' does not respond to #to_s" unless value.respond_to?(:to_s)
|
252
|
+
value.to_s
|
253
|
+
when field_type == DateTime
|
254
|
+
case
|
255
|
+
when value.is_a?(Time)
|
256
|
+
time_to_date_time(value)
|
257
|
+
when value.is_a?(String)
|
258
|
+
DateTime.parse(value)
|
259
|
+
else
|
260
|
+
DateTime.parse(value.to_s)
|
261
|
+
end
|
262
|
+
when field_type == Date
|
263
|
+
case
|
264
|
+
when value.is_a?(Time) || value.is_a?(DateTime)
|
265
|
+
Date.parse(value.strftime('%Y/%m/%d'))
|
266
|
+
else
|
267
|
+
Date.parse(value)
|
268
|
+
end
|
269
|
+
when field_type == Time
|
270
|
+
Time.parse(value)
|
271
|
+
when field_type == BigDecimal
|
272
|
+
BigDecimal.new(value.to_s)
|
273
|
+
else
|
274
|
+
if value.respond_to?(:to_s)
|
275
|
+
value.to_s
|
276
|
+
else
|
277
|
+
value
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
r_value
|
282
|
+
|
283
|
+
end
|
284
|
+
end
|
285
|
+
@handle.cancel if @handle && @handle.respond_to?(:cancel)
|
286
|
+
@current_row = -1
|
287
|
+
end
|
288
|
+
|
289
|
+
def close
|
290
|
+
if @handle
|
291
|
+
@handle.finish if @handle.respond_to?(:finish) && !@handle.finished?
|
292
|
+
@handle = nil
|
293
|
+
true
|
294
|
+
else
|
295
|
+
false
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def next!
|
300
|
+
(@current_row += 1) < @rows.size
|
301
|
+
end
|
302
|
+
|
303
|
+
def values
|
304
|
+
raise DataObjects::DataError.new("First row has not been fetched") if @current_row < 0
|
305
|
+
raise DataObjects::DataError.new("Last row has been processed") if @current_row >= @rows.size
|
306
|
+
@rows[@current_row]
|
307
|
+
end
|
308
|
+
|
309
|
+
def fields
|
310
|
+
@fields
|
311
|
+
end
|
312
|
+
|
313
|
+
def field_count
|
314
|
+
@fields.size
|
315
|
+
end
|
316
|
+
|
317
|
+
def row_count
|
318
|
+
@rows.size
|
319
|
+
end
|
320
|
+
|
321
|
+
private
|
322
|
+
|
323
|
+
def time_to_date_time(value)
|
324
|
+
DateTime.new(value.year, value.month, value.day,
|
325
|
+
value.hour, value.min, value.sec,
|
326
|
+
Rational(value.gmt_offset / 3600, 24))
|
327
|
+
end
|
328
|
+
|
329
|
+
def time_to_date(value)
|
330
|
+
Date.parse(time_to_date_time(value).strftime('%Y/%m/%d'))
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
private
|
335
|
+
|
336
|
+
def self.check_params cmd, args
|
337
|
+
actual = args.size
|
338
|
+
expected = param_count(cmd)
|
339
|
+
raise ArgumentError.new("Binding mismatch: #{actual} for #{expected}") if actual != expected
|
340
|
+
end
|
341
|
+
|
342
|
+
def self.raise_db_error(e, cmd, args)
|
343
|
+
msg = e.to_str
|
344
|
+
case msg
|
345
|
+
when /Too much parameters/, /No data found/
|
346
|
+
check_params(cmd, args)
|
347
|
+
else
|
348
|
+
e.errstr << " running '#{cmd}'"
|
349
|
+
end
|
350
|
+
raise DataObjects::SQLError.new(e.errstr)
|
351
|
+
end
|
352
|
+
|
353
|
+
def self.param_count cmd
|
354
|
+
cmd.gsub(/'[^']*'/,'').gsub(/"[_|A-Z|a-z|0-9|?]+"/,'').scan(/\?/).size
|
355
|
+
end
|
356
|
+
|
357
|
+
end
|
358
|
+
|
359
|
+
end
|
360
|
+
|