tiny_tds 2.1.5 → 3.2.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +590 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +32 -1
- data/Gemfile +1 -8
- data/ISSUE_TEMPLATE.md +1 -1
- data/README.md +75 -88
- data/Rakefile +44 -30
- data/VERSION +1 -1
- data/docker-compose.yml +20 -8
- data/ext/tiny_tds/client.c +10 -15
- data/ext/tiny_tds/extconf.rb +183 -66
- data/ext/tiny_tds/extconsts.rb +4 -11
- data/ext/tiny_tds/result.c +28 -35
- data/ext/tiny_tds/tiny_tds_ext.c +4 -1
- data/lib/tiny_tds/bin.rb +12 -26
- data/lib/tiny_tds/client.rb +38 -42
- data/lib/tiny_tds/error.rb +0 -2
- data/lib/tiny_tds/gem.rb +5 -14
- data/lib/tiny_tds/result.rb +0 -2
- data/lib/tiny_tds/version.rb +1 -1
- data/lib/tiny_tds.rb +28 -47
- data/setup_cimgruby_dev.sh +25 -0
- data/start_dev.sh +21 -0
- data/tasks/native_gem.rake +12 -10
- data/tasks/package.rake +1 -3
- data/tasks/ports.rake +14 -75
- data/tasks/test.rake +3 -5
- data/test/bin/install-freetds.sh +2 -4
- data/test/bin/install-mssql.ps1 +42 -0
- data/test/bin/install-mssqltools.sh +9 -0
- data/test/bin/restore-from-native-gem.ps1 +10 -0
- data/test/bin/setup_tinytds_db.sh +7 -0
- data/test/bin/setup_volume_permissions.sh +10 -0
- data/test/client_test.rb +111 -120
- data/test/gem_test.rb +32 -111
- data/test/result_test.rb +259 -365
- data/test/schema_test.rb +369 -395
- data/test/sql/db-create.sql +18 -0
- data/test/sql/db-login.sql +38 -0
- data/test/test_helper.rb +75 -102
- data/test/thread_test.rb +22 -31
- data/tiny_tds.gemspec +28 -27
- metadata +70 -57
- data/.travis.yml +0 -25
- data/appveyor.yml +0 -72
- data/tasks/ports/freetds.rb +0 -37
- data/tasks/ports/libiconv.rb +0 -43
- data/tasks/ports/openssl.rb +0 -62
- data/tasks/ports/recipe.rb +0 -52
- data/test/appveyor/dbsetup.ps1 +0 -27
- data/test/appveyor/dbsetup.sql +0 -9
- data/test/benchmark/query.rb +0 -77
- data/test/benchmark/query_odbc.rb +0 -106
- data/test/benchmark/query_tinytds.rb +0 -126
- data/test/bin/setup.sh +0 -19
- data/test/schema/sqlserver_2000.sql +0 -140
- data/test/schema/sqlserver_2005.sql +0 -140
- data/test/schema/sqlserver_2014.sql +0 -140
- data/test/schema/sqlserver_2016.sql +0 -140
- data/test/schema/sybase_ase.sql +0 -138
- /data/test/schema/{sqlserver_2008.sql → sqlserver_2017.sql} +0 -0
data/ext/tiny_tds/extconf.rb
CHANGED
@@ -1,73 +1,190 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
print <<HELP
|
14
|
-
usage: ruby #{$0} [options]
|
15
|
-
--with-freetds-dir=DIR
|
16
|
-
Use the freetds library placed under DIR.
|
17
|
-
HELP
|
18
|
-
exit! 0
|
1
|
+
require "mkmf"
|
2
|
+
require_relative "extconsts"
|
3
|
+
|
4
|
+
if ENV["MAINTAINER_MODE"]
|
5
|
+
warn "Maintainer mode enabled."
|
6
|
+
$CFLAGS << # standard:disable Style/GlobalVars
|
7
|
+
" -Wall" \
|
8
|
+
" -ggdb" \
|
9
|
+
" -DDEBUG" \
|
10
|
+
" -pedantic"
|
11
|
+
$LDFLAGS << # standard:disable Style/GlobalVars
|
12
|
+
" -ggdb"
|
19
13
|
end
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
15
|
+
if (gem_platform = with_config("cross-build"))
|
16
|
+
require "mini_portile2"
|
17
|
+
|
18
|
+
openssl_platform = with_config("openssl-platform")
|
19
|
+
|
20
|
+
class BuildRecipe < MiniPortile
|
21
|
+
attr_accessor :gem_platform
|
22
|
+
|
23
|
+
def initialize(name, version, files)
|
24
|
+
super(name, version)
|
25
|
+
self.files = files
|
26
|
+
rootdir = File.expand_path("../../..", __FILE__)
|
27
|
+
self.target = File.join(rootdir, "ports")
|
28
|
+
self.patch_files = Dir[File.join("patches", self.name, self.version, "*.patch")].sort
|
29
|
+
end
|
30
|
+
|
31
|
+
# this will yield all ports into the same directory, making our path configuration for the linker easier
|
32
|
+
def port_path
|
33
|
+
"#{@target}/#{gem_platform}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def cook_and_activate
|
37
|
+
checkpoint = File.join(target, "#{name}-#{version}-#{gem_platform}.installed")
|
38
|
+
|
39
|
+
unless File.exist?(checkpoint)
|
40
|
+
cook
|
41
|
+
FileUtils.touch checkpoint
|
42
|
+
end
|
43
|
+
|
44
|
+
activate
|
45
|
+
self
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
openssl_recipe = BuildRecipe.new("openssl", OPENSSL_VERSION, [OPENSSL_SOURCE_URI]).tap do |recipe|
|
50
|
+
class << recipe
|
51
|
+
attr_accessor :openssl_platform
|
52
|
+
|
53
|
+
def configure
|
54
|
+
envs = []
|
55
|
+
envs << "CFLAGS=-DDSO_WIN32 -DOPENSSL_THREADS" if MiniPortile.windows?
|
56
|
+
envs << "CFLAGS=-fPIC -DOPENSSL_THREADS" if MiniPortile.linux?
|
57
|
+
execute("configure", ["env", *envs, "./Configure", openssl_platform, "threads", "-static", "CROSS_COMPILE=#{host}-", configure_prefix, "--libdir=lib"], altlog: "config.log")
|
58
|
+
end
|
59
|
+
|
60
|
+
def compile
|
61
|
+
execute("compile", "#{make_cmd} build_libs")
|
62
|
+
end
|
63
|
+
|
64
|
+
def install
|
65
|
+
execute("install", "#{make_cmd} install_dev")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
recipe.gem_platform = gem_platform
|
70
|
+
recipe.openssl_platform = openssl_platform
|
71
|
+
recipe.cook_and_activate
|
72
|
+
end
|
73
|
+
|
74
|
+
libiconv_recipe = BuildRecipe.new("libiconv", ICONV_VERSION, [ICONV_SOURCE_URI]).tap do |recipe|
|
75
|
+
recipe.configure_options << "CFLAGS=-fPIC" if MiniPortile.linux?
|
76
|
+
recipe.gem_platform = gem_platform
|
77
|
+
|
78
|
+
recipe.cook_and_activate
|
79
|
+
end
|
80
|
+
|
81
|
+
# remove the ".la" files, otherwise libtool starts to complain when linking into FreeTDS
|
82
|
+
Dir.glob(File.join(libiconv_recipe.path, "lib", "**", "*.la")).each do |la_file|
|
83
|
+
File.delete(la_file)
|
84
|
+
end
|
85
|
+
|
86
|
+
freetds_recipe = BuildRecipe.new("freetds", FREETDS_VERSION, [FREETDS_SOURCE_URI]).tap do |recipe|
|
87
|
+
class << recipe
|
88
|
+
def configure_defaults
|
89
|
+
[
|
90
|
+
"--host=#{@host}",
|
91
|
+
"--enable-shared",
|
92
|
+
"--disable-static",
|
93
|
+
"--disable-odbc"
|
94
|
+
]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# i am not 100% what is going on behind the scenes
|
99
|
+
# it seems that FreeTDS build system prefers OPENSSL_CFLAGS and OPENSSL_LIBS
|
100
|
+
# but the linker still relies on LIBS and CPPFLAGS
|
101
|
+
# removing one or the other leads to build failures in any case of FreeTDS
|
102
|
+
if MiniPortile.linux?
|
103
|
+
recipe.configure_options << "CFLAGS=-fPIC"
|
104
|
+
elsif MiniPortile.windows?
|
105
|
+
recipe.configure_options << "--enable-sspi"
|
106
|
+
end
|
107
|
+
|
108
|
+
# pass an additional runtime path to the linker so defncopy and tsql can find our shared sybdb
|
109
|
+
recipe.configure_options << "LDFLAGS=-L#{openssl_recipe.path}/lib #{"-Wl,-rpath='$$ORIGIN/../lib'" if MiniPortile.linux?}"
|
110
|
+
recipe.configure_options << "LIBS=-liconv -lssl -lcrypto #{"-lwsock32 -lgdi32 -lws2_32 -lcrypt32" if MiniPortile.windows?} #{"-ldl -lpthread" if MiniPortile.linux?}"
|
111
|
+
recipe.configure_options << "CPPFLAGS=-I#{openssl_recipe.path}/include"
|
112
|
+
|
113
|
+
recipe.configure_options << "OPENSSL_CFLAGS=-L#{openssl_recipe.path}/lib"
|
114
|
+
recipe.configure_options << "OPENSSL_LIBS=-lssl -lcrypto #{"-lwsock32 -lgdi32 -lws2_32 -lcrypt32" if MiniPortile.windows?} #{"-ldl -lpthread" if MiniPortile.linux?}"
|
115
|
+
|
116
|
+
recipe.configure_options << "--with-openssl=#{openssl_recipe.path}"
|
117
|
+
recipe.configure_options << "--with-libiconv-prefix=#{libiconv_recipe.path}"
|
118
|
+
recipe.configure_options << "--sysconfdir=C:/Sites" if MiniPortile.windows?
|
119
|
+
|
120
|
+
recipe.gem_platform = gem_platform
|
121
|
+
recipe.cook_and_activate
|
122
|
+
end
|
123
|
+
|
124
|
+
# enable relative path to later load the FreeTDS shared library
|
125
|
+
$LDFLAGS << " '-Wl,-rpath=$$ORIGIN/../../../ports/#{gem_platform}/lib'" # standard:disable Style/GlobalVars
|
126
|
+
|
127
|
+
dir_config("freetds", "#{freetds_recipe.path}/include", "#{freetds_recipe.path}/lib")
|
128
|
+
else
|
129
|
+
# Make sure to check the ports path for the configured host
|
130
|
+
architecture = RbConfig::CONFIG["arch"]
|
131
|
+
|
132
|
+
project_dir = File.expand_path("../../..", __FILE__)
|
133
|
+
freetds_ports_dir = File.join(project_dir, "ports", architecture, "freetds", FREETDS_VERSION)
|
134
|
+
freetds_ports_dir = File.expand_path(freetds_ports_dir)
|
135
|
+
|
136
|
+
# Add all the special path searching from the original tiny_tds build
|
137
|
+
# order is important here! First in, first searched.
|
138
|
+
DIRS = %w[
|
139
|
+
/opt/local
|
140
|
+
/usr/local
|
141
|
+
]
|
142
|
+
|
143
|
+
if /darwin/i.match?(RbConfig::CONFIG["host_os"])
|
144
|
+
# Ruby below 2.7 seems to label the host CPU on Apple Silicon as aarch64
|
145
|
+
# 2.7 and above print is as ARM64
|
146
|
+
target_host_cpu = (Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.7")) ? "aarch64" : "arm64"
|
147
|
+
|
148
|
+
if RbConfig::CONFIG["host_cpu"] == target_host_cpu
|
149
|
+
# Homebrew on Apple Silicon installs into /opt/hombrew
|
150
|
+
# https://docs.brew.sh/Installation
|
151
|
+
# On Intel Macs, it is /usr/local, so no changes necessary to DIRS
|
152
|
+
DIRS.unshift("/opt/homebrew")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
if ENV["RI_DEVKIT"] && ENV["MINGW_PREFIX"] # RubyInstaller Support
|
157
|
+
DIRS.unshift(File.join(ENV["RI_DEVKIT"], ENV["MINGW_PREFIX"]))
|
158
|
+
end
|
159
|
+
|
160
|
+
# Add the ports directory if it exists for local developer builds
|
161
|
+
DIRS.unshift(freetds_ports_dir) if File.directory?(freetds_ports_dir)
|
162
|
+
|
163
|
+
# Grab freetds environment variable for use by people on services like
|
164
|
+
# Heroku who they can't easily use bundler config to set directories
|
165
|
+
DIRS.unshift(ENV["FREETDS_DIR"]) if ENV.has_key?("FREETDS_DIR")
|
166
|
+
|
167
|
+
# Add the search paths for freetds configured above
|
168
|
+
ldirs = DIRS.flat_map do |path|
|
169
|
+
ldir = "#{path}/lib"
|
170
|
+
[ldir, "#{ldir}/freetds"]
|
171
|
+
end
|
172
|
+
|
173
|
+
idirs = DIRS.flat_map do |path|
|
174
|
+
idir = "#{path}/include"
|
175
|
+
[idir, "#{idir}/freetds"]
|
176
|
+
end
|
177
|
+
|
178
|
+
puts "looking for freetds headers in the following directories:\n#{idirs.map { |a| " - #{a}\n" }.join}"
|
179
|
+
puts "looking for freetds library in the following directories:\n#{ldirs.map { |a| " - #{a}\n" }.join}"
|
180
|
+
dir_config("freetds", idirs, ldirs)
|
52
181
|
end
|
53
182
|
|
54
|
-
|
55
|
-
|
56
|
-
dir_config('freetds', idirs, ldirs)
|
57
|
-
|
58
|
-
have_dependencies = [
|
59
|
-
find_header('sybfront.h'),
|
60
|
-
find_header('sybdb.h'),
|
61
|
-
find_library('sybdb', 'tdsdbopen'),
|
62
|
-
find_library('sybdb', 'dbanydatecrack')
|
63
|
-
].inject(true) do |memo, current|
|
64
|
-
memo && current
|
65
|
-
end
|
183
|
+
find_header("sybfront.h") or abort "Can't find the 'sybfront.h' header"
|
184
|
+
find_header("sybdb.h") or abort "Can't find the 'sybdb.h' header"
|
66
185
|
|
67
|
-
unless
|
68
|
-
abort
|
186
|
+
unless have_library("sybdb", "dbanydatecrack")
|
187
|
+
abort "Failed! Do you have FreeTDS 1.0.0 or higher installed?"
|
69
188
|
end
|
70
189
|
|
71
|
-
create_makefile(
|
72
|
-
|
73
|
-
# :startdoc:
|
190
|
+
create_makefile("tiny_tds/tiny_tds")
|
data/ext/tiny_tds/extconsts.rb
CHANGED
@@ -1,15 +1,8 @@
|
|
1
|
-
|
2
|
-
ICONV_VERSION = ENV['TINYTDS_ICONV_VERSION'] || "1.15"
|
1
|
+
ICONV_VERSION = ENV["TINYTDS_ICONV_VERSION"] || "1.18"
|
3
2
|
ICONV_SOURCE_URI = "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-#{ICONV_VERSION}.tar.gz"
|
4
3
|
|
5
|
-
OPENSSL_VERSION = ENV[
|
4
|
+
OPENSSL_VERSION = ENV["TINYTDS_OPENSSL_VERSION"] || "3.4.0"
|
6
5
|
OPENSSL_SOURCE_URI = "https://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz"
|
7
6
|
|
8
|
-
FREETDS_VERSION = ENV[
|
9
|
-
|
10
|
-
h[k] = {files: "http://www.freetds.org/files/stable/freetds-#{k}.tar.bz2"}
|
11
|
-
}
|
12
|
-
FREETDS_VERSION_INFO['1.00'] = {files: 'http://www.freetds.org/files/stable/freetds-1.00.tar.bz2'}
|
13
|
-
FREETDS_VERSION_INFO['0.99'] = {files: 'http://www.freetds.org/files/current/freetds-dev.0.99.678.tar.gz'}
|
14
|
-
FREETDS_VERSION_INFO['0.95'] = {files: 'http://www.freetds.org/files/stable/freetds-0.95.92.tar.gz'}
|
15
|
-
FREETDS_SOURCE_URI = FREETDS_VERSION_INFO[FREETDS_VERSION][:files]
|
7
|
+
FREETDS_VERSION = ENV["TINYTDS_FREETDS_VERSION"] || "1.4.26"
|
8
|
+
FREETDS_SOURCE_URI = "http://www.freetds.org/files/stable/freetds-#{FREETDS_VERSION}.tar.bz2"
|
data/ext/tiny_tds/result.c
CHANGED
@@ -298,42 +298,34 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
|
|
298
298
|
}
|
299
299
|
break;
|
300
300
|
}
|
301
|
-
case
|
302
|
-
case
|
303
|
-
case
|
304
|
-
case
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
val = rb_funcall(cDate, intern_new, 3, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day));
|
312
|
-
break;
|
313
|
-
}
|
314
|
-
case 41: { // SYBMSTIME
|
315
|
-
VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek);
|
316
|
-
val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(1900), INT2NUM(1), INT2NUM(1), INT2NUM(dr2.hour), INT2NUM(dr2.minute), INT2NUM(dr2.second), rational_nsec);
|
317
|
-
break;
|
318
|
-
}
|
319
|
-
case 42: { // SYBMSDATETIME2
|
320
|
-
VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek);
|
321
|
-
val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day), INT2NUM(dr2.hour), INT2NUM(dr2.minute), INT2NUM(dr2.second), rational_nsec);
|
322
|
-
break;
|
323
|
-
}
|
324
|
-
case 43: { // SYBMSDATETIMEOFFSET
|
325
|
-
long long numerator = ((long)dr2.second * (long long)1000000000) + (long long)dr2.nanosecond;
|
326
|
-
VALUE rational_sec = rb_Rational(LL2NUM(numerator), opt_onebil);
|
327
|
-
val = rb_funcall(rb_cTime, intern_new, 7, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day), INT2NUM(dr2.hour), INT2NUM(dr2.minute), rational_sec, INT2NUM(dr2.tzone*60));
|
328
|
-
break;
|
329
|
-
}
|
330
|
-
}
|
331
|
-
} else {
|
332
|
-
val = ENCODED_STR_NEW(data, data_len);
|
301
|
+
case SYBMSDATE:
|
302
|
+
case SYBMSTIME:
|
303
|
+
case SYBMSDATETIME2:
|
304
|
+
case SYBMSDATETIMEOFFSET: {
|
305
|
+
DBDATEREC2 dr2;
|
306
|
+
dbanydatecrack(rwrap->client, &dr2, coltype, data);
|
307
|
+
switch(coltype) {
|
308
|
+
case SYBMSDATE: {
|
309
|
+
val = rb_funcall(cDate, intern_new, 3, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day));
|
310
|
+
break;
|
333
311
|
}
|
334
|
-
|
335
|
-
|
336
|
-
|
312
|
+
case SYBMSTIME: {
|
313
|
+
VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek);
|
314
|
+
val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(1900), INT2NUM(1), INT2NUM(1), INT2NUM(dr2.hour), INT2NUM(dr2.minute), INT2NUM(dr2.second), rational_nsec);
|
315
|
+
break;
|
316
|
+
}
|
317
|
+
case SYBMSDATETIME2: {
|
318
|
+
VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek);
|
319
|
+
val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day), INT2NUM(dr2.hour), INT2NUM(dr2.minute), INT2NUM(dr2.second), rational_nsec);
|
320
|
+
break;
|
321
|
+
}
|
322
|
+
case SYBMSDATETIMEOFFSET: {
|
323
|
+
long long numerator = ((long)dr2.second * (long long)1000000000) + (long long)dr2.nanosecond;
|
324
|
+
VALUE rational_sec = rb_Rational(LL2NUM(numerator), opt_onebil);
|
325
|
+
val = rb_funcall(rb_cTime, intern_new, 7, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day), INT2NUM(dr2.hour), INT2NUM(dr2.minute), rational_sec, INT2NUM(dr2.tzone*60));
|
326
|
+
break;
|
327
|
+
}
|
328
|
+
}
|
337
329
|
break;
|
338
330
|
}
|
339
331
|
case SYBCHAR:
|
@@ -584,6 +576,7 @@ void init_tinytds_result() {
|
|
584
576
|
cDate = rb_const_get(rb_cObject, rb_intern("Date"));
|
585
577
|
/* Define TinyTds::Result */
|
586
578
|
cTinyTdsResult = rb_define_class_under(mTinyTds, "Result", rb_cObject);
|
579
|
+
rb_undef_alloc_func(cTinyTdsResult);
|
587
580
|
/* Define TinyTds::Result Public Methods */
|
588
581
|
rb_define_method(cTinyTdsResult, "fields", rb_tinytds_result_fields, 0);
|
589
582
|
rb_define_method(cTinyTdsResult, "each", rb_tinytds_result_each, -1);
|
data/ext/tiny_tds/tiny_tds_ext.c
CHANGED
data/lib/tiny_tds/bin.rb
CHANGED
@@ -1,23 +1,22 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
3
|
-
require
|
1
|
+
require_relative "version"
|
2
|
+
require_relative "gem"
|
3
|
+
require "shellwords"
|
4
4
|
|
5
5
|
module TinyTds
|
6
6
|
class Bin
|
7
|
-
|
8
7
|
attr_reader :name
|
9
8
|
|
10
9
|
class << self
|
11
10
|
def exe(name, *args)
|
12
11
|
bin = new(name)
|
13
|
-
puts bin.info unless args.any? { |x| x ==
|
12
|
+
puts bin.info unless args.any? { |x| x == "-q" }
|
14
13
|
bin.run(*args)
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
17
|
def initialize(name)
|
19
18
|
@root = Gem.root_path
|
20
|
-
@exts = (ENV[
|
19
|
+
@exts = (ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]) | [".exe"]
|
21
20
|
|
22
21
|
@name = name
|
23
22
|
@binstub = find_bin
|
@@ -33,7 +32,7 @@ module TinyTds
|
|
33
32
|
end
|
34
33
|
|
35
34
|
def path
|
36
|
-
@path ||= @exefile && File.exist?(@exefile) ? @exefile : which
|
35
|
+
@path ||= (@exefile && File.exist?(@exefile)) ? @exefile : which
|
37
36
|
end
|
38
37
|
|
39
38
|
def info
|
@@ -43,26 +42,26 @@ module TinyTds
|
|
43
42
|
private
|
44
43
|
|
45
44
|
def search_paths
|
46
|
-
ENV[
|
45
|
+
ENV["PATH"].split File::PATH_SEPARATOR
|
47
46
|
end
|
48
47
|
|
49
48
|
def with_ports_paths
|
50
|
-
old_path = ENV[
|
49
|
+
old_path = ENV["PATH"]
|
51
50
|
|
52
51
|
begin
|
53
|
-
ENV[
|
52
|
+
ENV["PATH"] = [
|
54
53
|
Gem.ports_bin_paths,
|
55
54
|
old_path
|
56
55
|
].flatten.join File::PATH_SEPARATOR
|
57
56
|
|
58
57
|
yield if block_given?
|
59
58
|
ensure
|
60
|
-
ENV[
|
59
|
+
ENV["PATH"] = old_path
|
61
60
|
end
|
62
61
|
end
|
63
62
|
|
64
63
|
def find_bin
|
65
|
-
File.join @root,
|
64
|
+
File.join @root, "bin", name
|
66
65
|
end
|
67
66
|
|
68
67
|
def find_exe
|
@@ -81,24 +80,11 @@ module TinyTds
|
|
81
80
|
exe = File.expand_path File.join(path, "#{name}#{ext}"), @root
|
82
81
|
next if exe == @binstub
|
83
82
|
next unless File.executable?(exe)
|
84
|
-
|
83
|
+
|
85
84
|
return exe
|
86
85
|
end
|
87
86
|
end
|
88
87
|
nil
|
89
88
|
end
|
90
|
-
|
91
|
-
# Implementation directly copied from ptools.
|
92
|
-
# https://github.com/djberg96/ptools
|
93
|
-
# https://opensource.org/licenses/Artistic-2.0
|
94
|
-
#
|
95
|
-
def binary?(file)
|
96
|
-
bytes = File.stat(file).blksize
|
97
|
-
return false unless bytes
|
98
|
-
bytes = 4096 if bytes > 4096
|
99
|
-
s = (File.read(file, bytes) || '')
|
100
|
-
s = s.encode('US-ASCII', undef: :replace).split(//)
|
101
|
-
((s.size - s.grep(' '..'~').size) / s.size.to_f) > 0.30
|
102
|
-
end
|
103
89
|
end
|
104
90
|
end
|
data/lib/tiny_tds/client.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
module TinyTds
|
2
2
|
class Client
|
3
|
-
|
4
3
|
@default_query_options = {
|
5
4
|
as: :hash,
|
6
5
|
symbolize_keys: false,
|
@@ -13,7 +12,6 @@ module TinyTds
|
|
13
12
|
attr_reader :message_handler
|
14
13
|
|
15
14
|
class << self
|
16
|
-
|
17
15
|
attr_reader :default_query_options
|
18
16
|
|
19
17
|
# Most, if not all, iconv encoding names can be found by ruby. Just in case, you can
|
@@ -27,7 +25,6 @@ module TinyTds
|
|
27
25
|
def local_offset
|
28
26
|
::Time.local(2010).utc_offset.to_r / 86_400
|
29
27
|
end
|
30
|
-
|
31
28
|
end
|
32
29
|
|
33
30
|
# rubocop:disable Metrics/AbcSize
|
@@ -36,23 +33,23 @@ module TinyTds
|
|
36
33
|
# rubocop:disable Metrics/PerceivedComplexity
|
37
34
|
def initialize(opts = {})
|
38
35
|
if opts[:dataserver].to_s.empty? && opts[:host].to_s.empty?
|
39
|
-
raise ArgumentError,
|
36
|
+
raise ArgumentError, "missing :host option if no :dataserver given"
|
40
37
|
end
|
41
38
|
|
42
39
|
@message_handler = opts[:message_handler]
|
43
40
|
if @message_handler && !@message_handler.respond_to?(:call)
|
44
|
-
raise ArgumentError,
|
41
|
+
raise ArgumentError, ":message_handler must implement `call` (eg, a Proc or a Method)"
|
45
42
|
end
|
46
43
|
|
47
44
|
opts[:username] = parse_username(opts)
|
48
45
|
@query_options = self.class.default_query_options.dup
|
49
|
-
opts[:password] = opts[:password].to_s if opts[:password] && opts[:password].to_s.strip !=
|
50
|
-
opts[:appname] ||=
|
46
|
+
opts[:password] = opts[:password].to_s if opts[:password] && opts[:password].to_s.strip != ""
|
47
|
+
opts[:appname] ||= "TinyTds"
|
51
48
|
opts[:tds_version] = tds_versions_setter(opts)
|
52
49
|
opts[:use_utf16] = opts[:use_utf16].nil? || ["true", "1", "yes"].include?(opts[:use_utf16].to_s)
|
53
50
|
opts[:login_timeout] ||= 60
|
54
51
|
opts[:timeout] ||= 5
|
55
|
-
opts[:encoding] = opts[:encoding].nil? || opts[:encoding].casecmp(
|
52
|
+
opts[:encoding] = (opts[:encoding].nil? || opts[:encoding].casecmp("utf8").zero?) ? "UTF-8" : opts[:encoding].upcase
|
56
53
|
opts[:port] ||= 1433
|
57
54
|
opts[:dataserver] = "#{opts[:host]}:#{opts[:port]}" if opts[:dataserver].to_s.empty?
|
58
55
|
forced_integer_keys = [:login_timeout, :port, :timeout]
|
@@ -79,14 +76,14 @@ module TinyTds
|
|
79
76
|
host = opts[:host]
|
80
77
|
username = opts[:username]
|
81
78
|
return username if username.nil? || !opts[:azure]
|
82
|
-
return username if username.include?(
|
83
|
-
user, domain = username.split(
|
79
|
+
return username if username.include?("@") && !username.include?("database.windows.net")
|
80
|
+
user, domain = username.split("@")
|
84
81
|
domain ||= host
|
85
|
-
"#{user}@#{domain.split(
|
82
|
+
"#{user}@#{domain.split(".").first}"
|
86
83
|
end
|
87
84
|
|
88
85
|
def tds_versions_setter(opts = {})
|
89
|
-
v = opts[:tds_version] || ENV[
|
86
|
+
v = opts[:tds_version] || ENV["TDSVER"] || "7.3"
|
90
87
|
TDS_VERSIONS_SETTERS[v.to_s]
|
91
88
|
end
|
92
89
|
|
@@ -94,22 +91,22 @@ module TinyTds
|
|
94
91
|
# DBVERSION_xxx are used with dbsetversion()
|
95
92
|
#
|
96
93
|
TDS_VERSIONS_SETTERS = {
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
94
|
+
"unknown" => 0,
|
95
|
+
"46" => 1,
|
96
|
+
"100" => 2,
|
97
|
+
"42" => 3,
|
98
|
+
"70" => 4,
|
99
|
+
"7.0" => 4,
|
100
|
+
"71" => 5,
|
101
|
+
"7.1" => 5,
|
102
|
+
"80" => 5,
|
103
|
+
"8.0" => 5,
|
104
|
+
"72" => 6,
|
105
|
+
"7.2" => 6,
|
106
|
+
"90" => 6,
|
107
|
+
"9.0" => 6,
|
108
|
+
"73" => 7,
|
109
|
+
"7.3" => 7
|
113
110
|
}.freeze
|
114
111
|
|
115
112
|
# From sybdb.h comments:
|
@@ -117,20 +114,19 @@ module TinyTds
|
|
117
114
|
# The integer values of the constants are poorly chosen.
|
118
115
|
#
|
119
116
|
TDS_VERSIONS_GETTERS = {
|
120
|
-
0
|
121
|
-
1
|
122
|
-
2
|
123
|
-
3
|
124
|
-
4
|
125
|
-
5
|
126
|
-
6
|
127
|
-
7
|
128
|
-
8
|
129
|
-
9
|
130
|
-
10 => {
|
131
|
-
11 => {
|
132
|
-
12 => {
|
117
|
+
0 => {name: "DBTDS_UNKNOWN", description: "Unknown"},
|
118
|
+
1 => {name: "DBTDS_2_0", description: "Pre 4.0 SQL Server"},
|
119
|
+
2 => {name: "DBTDS_3_4", description: "Microsoft SQL Server (3.0)"},
|
120
|
+
3 => {name: "DBTDS_4_0", description: "4.0 SQL Server"},
|
121
|
+
4 => {name: "DBTDS_4_2", description: "4.2 SQL Server"},
|
122
|
+
5 => {name: "DBTDS_4_6", description: "2.0 OpenServer and 4.6 SQL Server."},
|
123
|
+
6 => {name: "DBTDS_4_9_5", description: "4.9.5 (NCR) SQL Server"},
|
124
|
+
7 => {name: "DBTDS_5_0", description: "5.0 SQL Server"},
|
125
|
+
8 => {name: "DBTDS_7_0", description: "Microsoft SQL Server 7.0"},
|
126
|
+
9 => {name: "DBTDS_7_1/DBTDS_8_0", description: "Microsoft SQL Server 2000"},
|
127
|
+
10 => {name: "DBTDS_7_2/DBTDS_9_0", description: "Microsoft SQL Server 2005"},
|
128
|
+
11 => {name: "DBTDS_7_3", description: "Microsoft SQL Server 2008"},
|
129
|
+
12 => {name: "DBTDS_7_4", description: "Microsoft SQL Server 2012/2014"}
|
133
130
|
}.freeze
|
134
|
-
|
135
131
|
end
|
136
132
|
end
|
data/lib/tiny_tds/error.rb
CHANGED
data/lib/tiny_tds/gem.rb
CHANGED
@@ -1,31 +1,22 @@
|
|
1
|
-
require
|
1
|
+
require "rbconfig"
|
2
2
|
|
3
3
|
module TinyTds
|
4
4
|
module Gem
|
5
5
|
class << self
|
6
6
|
def root_path
|
7
|
-
File.expand_path
|
7
|
+
File.expand_path "../../..", __FILE__
|
8
8
|
end
|
9
9
|
|
10
10
|
def ports_root_path
|
11
|
-
File.join(root_path,
|
11
|
+
File.join(root_path, "ports")
|
12
12
|
end
|
13
13
|
|
14
14
|
def ports_bin_paths
|
15
|
-
Dir.glob(File.join(ports_root_path,
|
15
|
+
Dir.glob(File.join(ports_root_path, "**", "bin"))
|
16
16
|
end
|
17
17
|
|
18
18
|
def ports_lib_paths
|
19
|
-
Dir.glob(File.join(ports_root_path,
|
20
|
-
end
|
21
|
-
|
22
|
-
def ports_host
|
23
|
-
h = RbConfig::CONFIG['host']
|
24
|
-
|
25
|
-
# Our fat binary builds with a i686-w64-mingw32 toolchain
|
26
|
-
# but ruby for windows x32-mingw32 reports i686-pc-mingw32
|
27
|
-
# so correct the host here
|
28
|
-
h.gsub('i686-pc-mingw32', 'i686-w64-mingw32')
|
19
|
+
Dir.glob(File.join(ports_root_path, "**", "lib"))
|
29
20
|
end
|
30
21
|
end
|
31
22
|
end
|