From 9241f0f77e1abc78bbda83ef2266cf6a5cfe92a7 Mon Sep 17 00:00:00 2001 From: Ken Collins Date: Sun, 4 Sep 2011 10:45:07 -0400 Subject: [PATCH] Update our TDS version constants to reflect changed 8.0/9.0 to 7.1/7.2 DBLIB versions in FreeTDS while making it backward compatible, again like FreeTDS. Even tho you can not configure FreeTDS with TDS version 7.2 or technically even use it, I added tests to prove that we correctly handle both varchar(max) and nvarchar(max) with large amounts of data. --- CHANGELOG | 8 +++++++- ext/tiny_tds/client.c | 2 ++ lib/tiny_tds/client.rb | 32 +++++++++++++++++++------------- tasks/ports.rake | 6 +++--- test/client_test.rb | 2 +- test/result_test.rb | 33 ++++++++++++++++++++++++++++++++- 6 files changed, 64 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4652305c..03808c7d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ * 0.5.0 * +* Update our TDS version constants to reflect changed 8.0/9.0 to 7.1/7.2 DBLIB versions in FreeTDS + while making it backward compatible, again like FreeTDS. Even tho you can not configure FreeTDS with + TDS version 7.2 or technically even use it, I added tests to prove that we correctly handle both + varchar(max) and nvarchar(max) with large amounts of data. + * FreeTDS 0.91 has been released. Update our port scripts. * Add test for 0.91 and higher to handle incorrect syntax in sp_executesql. @@ -39,7 +44,8 @@ * 0.4.2 * -* Iconv is a dep only when compiling locally. However, left in the ability to configure it for native gem installation but you must use --enable-iconv before using --with-iconv-dir=/some/dir +* Iconv is a dep only when compiling locally. However, left in the ability to configure it for native gem installation + but you must use --enable-iconv before using --with-iconv-dir=/some/dir * Really fix what 0.4.1 was supposed to do, force SYBDBLIB compile. diff --git a/ext/tiny_tds/client.c b/ext/tiny_tds/client.c index 06887070..1a4c796b 100644 --- a/ext/tiny_tds/client.c +++ b/ext/tiny_tds/client.c @@ -54,6 +54,8 @@ int tinytds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, c int return_value = INT_CONTINUE; int cancel = 0; switch(dberr) { + case 100: /* SYBEVERDOWN */ + return INT_CANCEL; case SYBESMSG: return return_value; case SYBEICONVI: diff --git a/lib/tiny_tds/client.rb b/lib/tiny_tds/client.rb index b81229ee..39429c0a 100644 --- a/lib/tiny_tds/client.rb +++ b/lib/tiny_tds/client.rb @@ -7,8 +7,10 @@ class Client '100' => 2, '42' => 3, '70' => 4, + '71' => 5, '80' => 5, - '90' => 6 # TODO: untested + '72' => 6, + '90' => 6 }.freeze TDS_VERSIONS_GETTERS = { @@ -21,8 +23,8 @@ class Client 6 => {:name => 'DBTDS_4_9_5', :description => '4.9.5 (NCR) SQL Server'}, 7 => {:name => 'DBTDS_5_0', :description => '5.0 SQL Server'}, 8 => {:name => 'DBTDS_7_0', :description => 'Microsoft SQL Server 7.0'}, - 9 => {:name => 'DBTDS_8_0', :description => 'Microsoft SQL Server 2000'}, - 10 => {:name => 'DBTDS_9_0', :description => 'Microsoft SQL Server 2005'} + 9 => {:name => 'DBTDS_7_1', :description => 'Microsoft SQL Server 2000'}, + 10 => {:name => 'DBTDS_7_2', :description => 'Microsoft SQL Server 2005'} }.freeze @@default_query_options = { @@ -35,15 +37,19 @@ class Client attr_reader :query_options - def self.default_query_options - @@default_query_options - end - - # Most, if not all, iconv encoding names can be found by ruby. Just in case, you can - # overide this method to return a string name that Encoding.find would work with. Default - # is to return the passed encoding. - def self.transpose_iconv_encoding(encoding) - encoding + class << self + + def default_query_options + @@default_query_options + end + + # Most, if not all, iconv encoding names can be found by ruby. Just in case, you can + # overide this method to return a string name that Encoding.find would work with. Default + # is to return the passed encoding. + def transpose_iconv_encoding(encoding) + encoding + end + end @@ -52,7 +58,7 @@ def initialize(opts={}) raise ArgumentError, 'missing :host option if no :dataserver given' if opts[:dataserver].to_s.empty? && opts[:host].to_s.empty? @query_options = @@default_query_options.dup opts[:appname] ||= 'TinyTds' - opts[:tds_version] = TDS_VERSIONS_SETTERS[opts[:tds_version].to_s] || TDS_VERSIONS_SETTERS['80'] + opts[:tds_lversion] = TDS_VERSIONS_SETTERS[opts[:tds_version].to_s] || TDS_VERSIONS_SETTERS['71'] opts[:login_timeout] ||= 60 opts[:timeout] ||= 5 opts[:encoding] = (opts[:encoding].nil? || opts[:encoding].downcase == 'utf8') ? 'UTF-8' : opts[:encoding].upcase diff --git a/tasks/ports.rake b/tasks/ports.rake index 28346088..bb687888 100644 --- a/tasks/ports.rake +++ b/tasks/ports.rake @@ -5,11 +5,11 @@ namespace :ports do # If your using 0.82, you may have to make a conf file to get it to work. For example: # $ export FREETDSCONF='/opt/local/etc/freetds/freetds.conf' - ICONV_VERSION = "1.13.1" FREETDS_VERSION = ENV['TINYTDS_FREETDS_082'] ? "0.82" : "0.91" FREETDS_VERSION_INFO = { - "0.82" => {:files => "http://ibiblio.org/pub/Linux/ALPHA/freetds/old/0.82/freetds-patched.tgz"}, + "0.82" => {:files => "http://ibiblio.org/pub/Linux/ALPHA/freetds/old/0.82/freetds-0.82.tar.gz"}, + # "0.82" => {:files => "http://ibiblio.org/pub/Linux/ALPHA/freetds/old/0.82/freetds-patched.tgz"}, "0.91" => {:files => "http://ibiblio.org/pub/Linux/ALPHA/freetds/stable/freetds-0.91.tar.gz"} } ORIGINAL_HOST = RbConfig::CONFIG["arch"] @@ -42,7 +42,7 @@ namespace :ports do # recipe.configure_options << "--disable-debug" recipe.configure_options << '--sysconfdir="C:/Sites"' if recipe.host != ORIGINAL_HOST recipe.configure_options << "--disable-odbc" - recipe.configure_options << "--with-tdsver=7.1" + recipe.configure_options << ENV['TINYTDS_FREETDS_082'] ? "--with-tdsver=8.0" : "--with-tdsver=7.1" recipe.cook touch checkpoint end diff --git a/test/client_test.rb b/test/client_test.rb index 79e1a397..48131d9b 100644 --- a/test/client_test.rb +++ b/test/client_test.rb @@ -25,7 +25,7 @@ class ClientTest < TinyTds::TestCase should 'have a getters for the tds version information (brittle since conf takes precedence)' do assert_equal 9, @client.tds_version - assert_equal 'DBTDS_8_0 - Microsoft SQL Server 2000', @client.tds_version_info + assert_equal 'DBTDS_7_1 - Microsoft SQL Server 2000', @client.tds_version_info end should 'use UTF-8 client charset/encoding by default' do diff --git a/test/result_test.rb b/test/result_test.rb index c7f42504..058a2322 100644 --- a/test/result_test.rb +++ b/test/result_test.rb @@ -110,7 +110,7 @@ class ResultTest < TinyTds::TestCase assert_equal text, row['varchar_50'] end end - + should 'insert and find unicode data' do rollback_transaction(@client) do text = '✓' @@ -546,6 +546,28 @@ class ResultTest < TinyTds::TestCase end + context 'with data type' do + + context 'char max' do + + setup do + @big_text = 'x' * 2_000_000 + @old_textsize = @client.execute("SELECT @@TEXTSIZE AS [textsize]").each.first['textsize'].inspect + @client.execute("SET TEXTSIZE #{(@big_text.length*2)+1}").do + end + + should 'insert and select large varchar_max' do + insert_and_select_datatype :varchar_max + end + + should 'insert and select large nvarchar_max' do + insert_and_select_datatype :nvarchar_max + end + + end unless sqlserver_2000? + + end + context 'when shit happens' do should 'cope with nil or empty buffer' do @@ -624,5 +646,14 @@ def assert_followup_query assert_equal 1, result.each.first['one'] end + def insert_and_select_datatype(datatype) + rollback_transaction(@client) do + @client.execute("DELETE FROM [datatypes] WHERE [#{datatype}] IS NOT NULL").do + id = @client.execute("INSERT INTO [datatypes] ([#{datatype}]) VALUES (N'#{@big_text}')").insert + found_text = find_value id, datatype + flunk "Large #{datatype} data with a length of #{@big_text.length} did not match found text with length of #{found_text.length}" unless @big_text == found_text + end + end + end