do_sqlserver-tinytds 0.10.17.alpha
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.
- 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
|
+
|