tiny_tds 2.1.2 → 3.2.1

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.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +571 -0
  3. data/.gitignore +2 -0
  4. data/CHANGELOG.md +56 -1
  5. data/Gemfile +1 -8
  6. data/ISSUE_TEMPLATE.md +1 -1
  7. data/README.md +89 -89
  8. data/Rakefile +44 -30
  9. data/VERSION +1 -1
  10. data/docker-compose.yml +34 -0
  11. data/ext/tiny_tds/client.c +100 -59
  12. data/ext/tiny_tds/client.h +5 -3
  13. data/ext/tiny_tds/extconf.rb +173 -52
  14. data/ext/tiny_tds/extconsts.rb +4 -11
  15. data/ext/tiny_tds/result.c +52 -45
  16. data/ext/tiny_tds/tiny_tds_ext.c +4 -1
  17. data/lib/tiny_tds/bin.rb +12 -26
  18. data/lib/tiny_tds/client.rb +38 -42
  19. data/lib/tiny_tds/error.rb +0 -2
  20. data/lib/tiny_tds/gem.rb +5 -14
  21. data/lib/tiny_tds/result.rb +0 -2
  22. data/lib/tiny_tds/version.rb +1 -1
  23. data/lib/tiny_tds.rb +28 -47
  24. data/setup_cimgruby_dev.sh +25 -0
  25. data/start_dev.sh +21 -0
  26. data/tasks/native_gem.rake +12 -10
  27. data/tasks/package.rake +1 -3
  28. data/tasks/ports.rake +14 -77
  29. data/tasks/test.rake +3 -5
  30. data/test/bin/install-freetds.sh +2 -4
  31. data/test/bin/install-mssql.ps1 +42 -0
  32. data/test/bin/install-mssqltools.sh +9 -0
  33. data/test/bin/restore-from-native-gem.ps1 +10 -0
  34. data/test/bin/setup_tinytds_db.sh +7 -0
  35. data/test/bin/setup_volume_permissions.sh +10 -0
  36. data/test/client_test.rb +152 -116
  37. data/test/gem_test.rb +39 -118
  38. data/test/result_test.rb +285 -350
  39. data/test/schema_test.rb +369 -395
  40. data/test/sql/db-create.sql +18 -0
  41. data/test/sql/db-login.sql +38 -0
  42. data/test/test_helper.rb +112 -85
  43. data/test/thread_test.rb +22 -31
  44. data/tiny_tds.gemspec +28 -26
  45. metadata +85 -59
  46. data/.travis.yml +0 -24
  47. data/BACKERS.md +0 -32
  48. data/appveyor.yml +0 -51
  49. data/tasks/ports/freetds.rb +0 -37
  50. data/tasks/ports/libiconv.rb +0 -43
  51. data/tasks/ports/openssl.rb +0 -78
  52. data/tasks/ports/recipe.rb +0 -52
  53. data/test/appveyor/dbsetup.ps1 +0 -27
  54. data/test/appveyor/dbsetup.sql +0 -9
  55. data/test/benchmark/query.rb +0 -77
  56. data/test/benchmark/query_odbc.rb +0 -106
  57. data/test/benchmark/query_tinytds.rb +0 -126
  58. data/test/bin/setup.sh +0 -19
  59. data/test/schema/sqlserver_2000.sql +0 -140
  60. data/test/schema/sqlserver_2005.sql +0 -140
  61. data/test/schema/sqlserver_2014.sql +0 -140
  62. data/test/schema/sqlserver_2016.sql +0 -140
  63. data/test/schema/sybase_ase.sql +0 -138
  64. /data/test/schema/{sqlserver_2008.sql → sqlserver_2017.sql} +0 -0
@@ -86,26 +86,40 @@ static void dbcancel_ubf(DBPROCESS *client) {
86
86
  static void nogvl_setup(DBPROCESS *client) {
87
87
  GET_CLIENT_USERDATA(client);
88
88
  userdata->nonblocking = 1;
89
+ userdata->nonblocking_errors_length = 0;
90
+ userdata->nonblocking_errors = malloc(ERRORS_STACK_INIT_SIZE * sizeof(tinytds_errordata));
91
+ userdata->nonblocking_errors_size = ERRORS_STACK_INIT_SIZE;
89
92
  }
90
93
 
91
94
  static void nogvl_cleanup(DBPROCESS *client) {
92
95
  GET_CLIENT_USERDATA(client);
93
96
  userdata->nonblocking = 0;
97
+ userdata->timing_out = 0;
94
98
  /*
95
99
  Now that the blocking operation is done, we can finally throw any
96
100
  exceptions based on errors from SQL Server.
97
101
  */
98
- if (userdata->nonblocking_error.is_set) {
99
- userdata->nonblocking_error.is_set = 0;
100
- rb_tinytds_raise_error(client,
101
- userdata->nonblocking_error.is_message,
102
- userdata->nonblocking_error.cancel,
103
- userdata->nonblocking_error.error,
104
- userdata->nonblocking_error.source,
105
- userdata->nonblocking_error.severity,
106
- userdata->nonblocking_error.dberr,
107
- userdata->nonblocking_error.oserr);
102
+ short int i;
103
+ for (i = 0; i < userdata->nonblocking_errors_length; i++) {
104
+ tinytds_errordata error = userdata->nonblocking_errors[i];
105
+
106
+ // lookahead to drain any info messages ahead of raising error
107
+ if (!error.is_message) {
108
+ short int j;
109
+ for (j = i; j < userdata->nonblocking_errors_length; j++) {
110
+ tinytds_errordata msg_error = userdata->nonblocking_errors[j];
111
+ if (msg_error.is_message) {
112
+ rb_tinytds_raise_error(client, msg_error);
113
+ }
114
+ }
115
+ }
116
+
117
+ rb_tinytds_raise_error(client, error);
108
118
  }
119
+
120
+ free(userdata->nonblocking_errors);
121
+ userdata->nonblocking_errors_length = 0;
122
+ userdata->nonblocking_errors_size = 0;
109
123
  }
110
124
 
111
125
  static RETCODE nogvl_dbsqlok(DBPROCESS *client) {
@@ -284,42 +298,34 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
284
298
  }
285
299
  break;
286
300
  }
287
- case 40: // SYBMSDATE
288
- case 41: // SYBMSTIME
289
- case 42: // SYBMSDATETIME2
290
- case 43: { // SYBMSDATETIMEOFFSET
291
- #ifdef DBVERSION_73
292
- if (dbtds(rwrap->client) >= DBTDS_7_3) {
293
- DBDATEREC2 dr2;
294
- dbanydatecrack(rwrap->client, &dr2, coltype, data);
295
- switch(coltype) {
296
- case 40: { // SYBMSDATE
297
- val = rb_funcall(cDate, intern_new, 3, INT2NUM(dr2.year), INT2NUM(dr2.month), INT2NUM(dr2.day));
298
- break;
299
- }
300
- case 41: { // SYBMSTIME
301
- VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek);
302
- val = rb_funcall(rb_cTime, timezone, 7, INT2NUM(1900), INT2NUM(1), INT2NUM(1), INT2NUM(dr2.hour), INT2NUM(dr2.minute), INT2NUM(dr2.second), rational_nsec);
303
- break;
304
- }
305
- case 42: { // SYBMSDATETIME2
306
- VALUE rational_nsec = rb_Rational(INT2NUM(dr2.nanosecond), opt_onek);
307
- 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);
308
- break;
309
- }
310
- case 43: { // SYBMSDATETIMEOFFSET
311
- long long numerator = ((long)dr2.second * (long long)1000000000) + (long long)dr2.nanosecond;
312
- VALUE rational_sec = rb_Rational(LL2NUM(numerator), opt_onebil);
313
- 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));
314
- break;
315
- }
316
- }
317
- } else {
318
- 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;
319
311
  }
320
- #else
321
- val = ENCODED_STR_NEW(data, data_len);
322
- #endif
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
+ }
323
329
  break;
324
330
  }
325
331
  case SYBCHAR:
@@ -570,6 +576,7 @@ void init_tinytds_result() {
570
576
  cDate = rb_const_get(rb_cObject, rb_intern("Date"));
571
577
  /* Define TinyTds::Result */
572
578
  cTinyTdsResult = rb_define_class_under(mTinyTds, "Result", rb_cObject);
579
+ rb_undef_alloc_func(cTinyTdsResult);
573
580
  /* Define TinyTds::Result Public Methods */
574
581
  rb_define_method(cTinyTdsResult, "fields", rb_tinytds_result_fields, 0);
575
582
  rb_define_method(cTinyTdsResult, "each", rb_tinytds_result_each, -1);
@@ -1,6 +1,9 @@
1
-
2
1
  #include <tiny_tds_ext.h>
3
2
 
3
+ #ifndef DBVERSION_73
4
+ #error "DBVERSION_73 is not defined. Aborting compilation."
5
+ #endif
6
+
4
7
  VALUE mTinyTds, cTinyTdsError;
5
8
 
6
9
  void Init_tiny_tds() {
data/lib/tiny_tds/bin.rb CHANGED
@@ -1,23 +1,22 @@
1
- require_relative './version'
2
- require_relative './gem'
3
- require 'shellwords'
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 == '-q' }
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['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']) | ['.exe']
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['PATH'].split File::PATH_SEPARATOR
45
+ ENV["PATH"].split File::PATH_SEPARATOR
47
46
  end
48
47
 
49
48
  def with_ports_paths
50
- old_path = ENV['PATH']
49
+ old_path = ENV["PATH"]
51
50
 
52
51
  begin
53
- ENV['PATH'] = [
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['PATH'] = old_path
59
+ ENV["PATH"] = old_path
61
60
  end
62
61
  end
63
62
 
64
63
  def find_bin
65
- File.join @root, 'bin', name
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
- next unless binary?(exe)
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
@@ -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, 'missing :host option if no :dataserver given'
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, ':message_handler must implement `call` (eg, a Proc or a Method)'
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] ||= 'TinyTds'
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('utf8').zero? ? 'UTF-8' : opts[:encoding].upcase
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?('@') && !username.include?('database.windows.net')
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('.').first}"
82
+ "#{user}@#{domain.split(".").first}"
86
83
  end
87
84
 
88
85
  def tds_versions_setter(opts = {})
89
- v = opts[:tds_version] || ENV['TDSVER'] || '7.3'
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
- 'unknown' => 0,
98
- '46' => 1,
99
- '100' => 2,
100
- '42' => 3,
101
- '70' => 4,
102
- '7.0' => 4,
103
- '71' => 5,
104
- '7.1' => 5,
105
- '80' => 5,
106
- '8.0' => 5,
107
- '72' => 6,
108
- '7.2' => 6,
109
- '90' => 6,
110
- '9.0' => 6,
111
- '73' => 7,
112
- '7.3' => 7
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 => { name: 'DBTDS_UNKNOWN', description: 'Unknown' },
121
- 1 => { name: 'DBTDS_2_0', description: 'Pre 4.0 SQL Server' },
122
- 2 => { name: 'DBTDS_3_4', description: 'Microsoft SQL Server (3.0)' },
123
- 3 => { name: 'DBTDS_4_0', description: '4.0 SQL Server' },
124
- 4 => { name: 'DBTDS_4_2', description: '4.2 SQL Server' },
125
- 5 => { name: 'DBTDS_4_6', description: '2.0 OpenServer and 4.6 SQL Server.' },
126
- 6 => { name: 'DBTDS_4_9_5', description: '4.9.5 (NCR) SQL Server' },
127
- 7 => { name: 'DBTDS_5_0', description: '5.0 SQL Server' },
128
- 8 => { name: 'DBTDS_7_0', description: 'Microsoft SQL Server 7.0' },
129
- 9 => { name: 'DBTDS_7_1/DBTDS_8_0', description: 'Microsoft SQL Server 2000' },
130
- 10 => { name: 'DBTDS_7_2/DBTDS_9_0', description: 'Microsoft SQL Server 2005' },
131
- 11 => { name: 'DBTDS_7_3', description: 'Microsoft SQL Server 2008' },
132
- 12 => { name: 'DBTDS_7_4', description: 'Microsoft SQL Server 2012/2014' }
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
@@ -1,6 +1,5 @@
1
1
  module TinyTds
2
2
  class Error < StandardError
3
-
4
3
  attr_accessor :source, :severity, :db_error_number, :os_error_number
5
4
 
6
5
  def initialize(message)
@@ -9,6 +8,5 @@ module TinyTds
9
8
  @db_error_number = nil
10
9
  @os_error_number = nil
11
10
  end
12
-
13
11
  end
14
12
  end
data/lib/tiny_tds/gem.rb CHANGED
@@ -1,31 +1,22 @@
1
- require 'rbconfig'
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 '../../..', __FILE__
7
+ File.expand_path "../../..", __FILE__
8
8
  end
9
9
 
10
10
  def ports_root_path
11
- File.join(root_path,'ports')
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,ports_host,'**','bin'))
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,ports_host,'**','lib'))
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
@@ -1,7 +1,5 @@
1
1
  module TinyTds
2
2
  class Result
3
-
4
3
  include Enumerable
5
-
6
4
  end
7
5
  end
@@ -1,3 +1,3 @@
1
1
  module TinyTds
2
- VERSION = File.read(File.expand_path('../../../VERSION', __FILE__)).chomp
2
+ VERSION = File.read(File.expand_path("../../../VERSION", __FILE__)).chomp
3
3
  end
data/lib/tiny_tds.rb CHANGED
@@ -1,61 +1,42 @@
1
- # encoding: UTF-8
2
- require 'date'
3
- require 'bigdecimal'
4
- require 'rational'
1
+ require "date"
2
+ require "bigdecimal"
5
3
 
6
- require 'tiny_tds/version'
7
- require 'tiny_tds/error'
8
- require 'tiny_tds/client'
9
- require 'tiny_tds/result'
10
- require 'tiny_tds/gem'
4
+ require "tiny_tds/version"
5
+ require "tiny_tds/error"
6
+ require "tiny_tds/client"
7
+ require "tiny_tds/result"
8
+ require "tiny_tds/gem"
11
9
 
12
- # Support multiple ruby versions, fat binaries under Windows.
13
- if RUBY_PLATFORM =~ /mingw|mswin/ && RUBY_VERSION =~ /(\d+.\d+)/
14
- ver = Regexp.last_match(1)
10
+ module TinyTds
11
+ # Is this file part of a fat binary gem with bundled freetds?
12
+ # This path must be enabled by add_dll_directory on Windows.
13
+ gplat = ::Gem::Platform.local
14
+ FREETDS_LIB_PATH = Dir[File.expand_path("../ports/#{gplat.cpu}-#{gplat.os}*/{bin,lib}", __dir__)].first
15
15
 
16
16
  add_dll_path = proc do |path, &block|
17
- begin
18
- require 'ruby_installer/runtime'
19
- RubyInstaller::Runtime.add_dll_directory(path, &block)
20
- rescue LoadError
21
- old_path = ENV['PATH']
22
- ENV['PATH'] = "#{path};#{old_path}"
17
+ if RUBY_PLATFORM =~ /(mswin|mingw)/i && path
23
18
  begin
19
+ require "ruby_installer/runtime"
20
+ RubyInstaller::Runtime.add_dll_directory(path, &block)
21
+ rescue LoadError
22
+ old_path = ENV["PATH"]
23
+ ENV["PATH"] = "#{path};#{old_path}"
24
24
  block.call
25
- ensure
26
- ENV['PATH'] = old_path
27
- end
28
- end
29
- end
30
-
31
- add_dll_paths = proc do |paths, &block|
32
- if path=paths.shift
33
- add_dll_path.call(path) do
34
- add_dll_paths.call(paths, &block)
25
+ ENV["PATH"] = old_path
35
26
  end
36
27
  else
28
+ # libsybdb is found by a relative rpath in the cross compiled extension dll
29
+ # or by the system library loader
37
30
  block.call
38
31
  end
39
32
  end
40
33
 
41
- # Temporary add bin directories for DLL search, so that freetds DLLs can be found.
42
- add_dll_paths.call( TinyTds::Gem.ports_bin_paths ) do
43
- begin
44
- require "tiny_tds/#{ver}/tiny_tds"
45
- rescue LoadError
46
- require 'tiny_tds/tiny_tds'
47
- end
48
- end
49
- else
50
- # Load dependent shared libraries into the process, so that they are already present,
51
- # when tiny_tds.so is loaded. This ensures, that shared libraries are loaded even when
52
- # the path is different between build and run time (e.g. Heroku).
53
- ports_libs = File.join(TinyTds::Gem.ports_root_path,
54
- "#{RbConfig::CONFIG['host']}/lib/*.so")
55
- Dir[ports_libs].each do |lib|
56
- require 'fiddle'
57
- Fiddle.dlopen(lib)
34
+ add_dll_path.call(FREETDS_LIB_PATH) do
35
+ # Try the <major>.<minor> subdirectory for fat binary gems
36
+ major_minor = RUBY_VERSION[/^(\d+\.\d+)/] or
37
+ raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}"
38
+ require "tiny_tds/#{major_minor}/tiny_tds"
39
+ rescue LoadError
40
+ require "tiny_tds/tiny_tds"
58
41
  end
59
-
60
- require 'tiny_tds/tiny_tds'
61
42
  end
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -x
4
+ set -e
5
+
6
+ # this should mirror the steps outlined in the circleci yml
7
+ echo "Installing mssql-tools..."
8
+ sleep 5
9
+ sudo -E ./test/bin/install-mssqltools.sh
10
+
11
+ echo "Configurating tinytds test database..."
12
+ sleep 5
13
+ ./test/bin/setup_tinytds_db.sh
14
+
15
+ echo "Building openssl library..."
16
+ sleep 5
17
+ sudo -E ./test/bin/install-openssl.sh
18
+
19
+ echo "Building freetds library..."
20
+ sleep 5
21
+ sudo -E ./test/bin/install-freetds.sh
22
+
23
+ echo "Installing gems..."
24
+ sleep 5
25
+ bundle install
data/start_dev.sh ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -x
4
+ set -e
5
+
6
+ # set volume read/write permissions to work both outside and inside container
7
+ sudo ./test/bin/setup_volume_permissions.sh
8
+
9
+ docker-compose up -d
10
+ echo "Waiting for containers to start..."
11
+ sleep 10
12
+
13
+ # setup circleci ruby container for development
14
+ docker exec cimg_ruby bash -c './setup_cimgruby_dev.sh'
15
+
16
+ # enter container
17
+ set +x
18
+ echo "cimg/ruby container is ready for tiny_tds development.........."
19
+ echo "To enter container run: docker exec -it cimg_ruby /bin/bash"
20
+ echo "To build solution run: docker exec cimg_ruby bash -c 'bundle exec rake build'"
21
+ echo "To test solution run: docker exec cimg_ruby bash -c 'bundle exec rake test'"
@@ -1,14 +1,16 @@
1
- # encoding: UTF-8
1
+ CrossLibraries.each do |xlib|
2
+ platform = xlib.platform
2
3
 
3
- desc 'Build the windows binary gems per rake-compiler-dock'
4
- task 'gem:windows' => ['ports:cross'] do
5
- require 'rake_compiler_dock'
4
+ desc "Build fat binary gem for platform #{platform}"
5
+ task "gem:native:#{platform}" do
6
+ require "rake_compiler_dock"
6
7
 
7
- # make sure to install our bundle
8
- build = ['bundle']
8
+ RakeCompilerDock.sh <<-EOT, platform: platform
9
+ bundle install &&
10
+ rake native:#{platform} pkg/#{SPEC.full_name}-#{platform}.gem MAKEOPTS=-j`nproc` RUBY_CC_VERSION=#{RakeCompilerDock.set_ruby_cc_version("~> 2.7", "~> 3.0")} MAKEFLAGS="V=1"
11
+ EOT
12
+ end
9
13
 
10
- # and finally build the native gem
11
- build << 'rake cross native gem RUBY_CC_VERSION=2.5.0:2.4.0:2.3.0:2.2.2:2.1.6:2.0.0 CFLAGS="-Wall" MAKE="make -j`nproc`"'
12
-
13
- RakeCompilerDock.sh build.join(' && ')
14
+ desc "Build the native binary gems"
15
+ multitask "gem:native" => "gem:native:#{platform}"
14
16
  end
data/tasks/package.rake CHANGED
@@ -1,8 +1,6 @@
1
- # encoding: UTF-8
2
- require 'rubygems/package_task'
1
+ require "rubygems/package_task"
3
2
 
4
3
  Gem::PackageTask.new(SPEC) do |pkg|
5
4
  pkg.need_tar = false
6
5
  pkg.need_zip = false
7
6
  end
8
-