Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Sybase SCOPE_IDENTITY(), some tests fixed, other skipped #95

Closed
wants to merge 3 commits into from

2 participants

@vjt
vjt commented

Hi,

Sybase doesn't support SCOPE_IDENTITY(), so I've made TDS-Version dependant the choice of two SQL strings that return the last identity column in an Ident field.

This pull request is meant as a discussion of the above strategy.

Thanks,

~Marcello

vjt added some commits
@vjt vjt Fix Sybase schema due to obscure syntax errors
An UTF8 character in a comment make Sybase choke with:

TinyTds::Error: Incorrect syntax near '@@@V0_INT91@@@V1_INT91'

Didn't investigate much, as the characters were located in comments
used only to keep the schema files up to date.
53a0131
@vjt vjt Add abstraction for different IDENTITY functions 51402c8
@vjt vjt Disable some tests for ASE, fix some others f180edb
@metaskills
Collaborator

Nice, I'll take a look at this soon! Ping me if I forget.

@vjt

Ping! It's Friday, a wonderful day to work on Open Source code! :wink:

@metaskills
Collaborator

How about Saturday :)

So I got this in and id a small amount of persnickety cleanup on my part in commit 57442f9. I'm gonna work on doing another release right now. Again, great work!

@metaskills metaskills closed this
@vjt

Thanks for the merge :-) /me happy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 6, 2012
  1. @vjt

    Fix Sybase schema due to obscure syntax errors

    vjt authored
    An UTF8 character in a comment make Sybase choke with:
    
    TinyTds::Error: Incorrect syntax near '@@@V0_INT91@@@V1_INT91'
    
    Didn't investigate much, as the characters were located in comments
    used only to keep the schema files up to date.
  2. @vjt
  3. @vjt
This page is out of date. Refresh to see the latest.
View
13 ext/tiny_tds/client.c
@@ -193,7 +193,7 @@ static VALUE rb_tinytds_execute(VALUE self, VALUE sql) {
return Qfalse;
}
cwrap->userdata->dbsql_sent = 1;
- VALUE result = rb_tinytds_new_result_obj(cwrap->client);
+ VALUE result = rb_tinytds_new_result_obj(cwrap);
rb_iv_set(result, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), intern_dup, 0));
GET_RESULT_WRAPPER(result);
rwrap->local_offset = rb_funcall(cTinyTdsClient, intern_local_offset, 0);
@@ -237,6 +237,11 @@ static VALUE rb_tinytds_return_code(VALUE self) {
}
}
+static VALUE rb_tinytds_identity_sql(VALUE self) {
+ GET_CLIENT_WRAPPER(self);
+ return rb_str_new2(cwrap->identity_insert_sql);
+}
+
static VALUE rb_tinytds_freetds_nine_one_or_higher(VALUE self) {
#ifdef DBSETLDBNAME
return Qtrue;
@@ -304,6 +309,11 @@ static VALUE rb_tinytds_connect(VALUE self, VALUE opts) {
VALUE transposed_encoding = rb_funcall(cTinyTdsClient, intern_transpose_iconv_encoding, 1, charset);
cwrap->encoding = rb_enc_find(StringValuePtr(transposed_encoding));
#endif
+
+ if (dbtds(cwrap->client) <= 7)
+ cwrap->identity_insert_sql = "SELECT CAST(@@IDENTITY AS bigint) AS Ident";
+ else
+ cwrap->identity_insert_sql = "SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident";
}
return self;
}
@@ -326,6 +336,7 @@ void init_tinytds_client() {
rb_define_method(cTinyTdsClient, "encoding", rb_tinytds_encoding, 0);
rb_define_method(cTinyTdsClient, "escape", rb_tinytds_escape, 1);
rb_define_method(cTinyTdsClient, "return_code", rb_tinytds_return_code, 0);
+ rb_define_method(cTinyTdsClient, "identity_sql", rb_tinytds_identity_sql, 0);
rb_define_method(cTinyTdsClient, "freetds_091_or_higer?", rb_tinytds_freetds_nine_one_or_higher, 0);
/* Define TinyTds::Client Protected Methods */
rb_define_protected_method(cTinyTdsClient, "connect", rb_tinytds_connect, 1);
View
1  ext/tiny_tds/client.h
@@ -20,6 +20,7 @@ typedef struct {
short int closed;
VALUE charset;
tinytds_client_userdata *userdata;
+ const char *identity_insert_sql;
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *encoding;
#endif
View
7 ext/tiny_tds/result.c
@@ -91,11 +91,12 @@ static void rb_tinytds_result_free(void *ptr) {
xfree(ptr);
}
-VALUE rb_tinytds_new_result_obj(DBPROCESS *c) {
+VALUE rb_tinytds_new_result_obj(tinytds_client_wrapper *cwrap) {
VALUE obj;
tinytds_result_wrapper *rwrap;
obj = Data_Make_Struct(cTinyTdsResult, tinytds_result_wrapper, rb_tinytds_result_mark, rb_tinytds_result_free, rwrap);
- rwrap->client = c;
+ rwrap->cwrap = cwrap;
+ rwrap->client = cwrap->client;
rwrap->local_offset = Qnil;
rwrap->fields = rb_ary_new();
rwrap->fields_processed = rb_ary_new();
@@ -467,7 +468,7 @@ static VALUE rb_tinytds_result_insert(VALUE self) {
if (rwrap->client) {
rb_tinytds_result_cancel_helper(rwrap->client);
VALUE identity = Qnil;
- dbcmd(rwrap->client, "SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident");
+ dbcmd(rwrap->client, rwrap->cwrap->identity_insert_sql);
if (dbsqlexec(rwrap->client) != FAIL && dbresults(rwrap->client) != FAIL && DBROWS(rwrap->client) != FAIL) {
while (dbnextrow(rwrap->client) != NO_MORE_ROWS) {
int col = 1;
View
3  ext/tiny_tds/result.h
@@ -7,9 +7,10 @@
#endif
void init_tinytds_result();
-VALUE rb_tinytds_new_result_obj(DBPROCESS *c);
+VALUE rb_tinytds_new_result_obj(tinytds_client_wrapper *cwrap);
typedef struct {
+ tinytds_client_wrapper *cwrap;
DBPROCESS *client;
VALUE local_offset;
VALUE fields;
View
11 test/client_test.rb
@@ -25,8 +25,13 @@ class ClientTest < TinyTds::TestCase
end
it 'has getters for the tds version information (brittle since conf takes precedence)' do
- assert_equal 9, @client.tds_version
- assert_equal 'DBTDS_7_1 - Microsoft SQL Server 2000', @client.tds_version_info
+ if sybase_ase?
+ assert_equal 7, @client.tds_version # FIXME this depends on ENV['TINYTDS_UNIT_VERSION']
+ assert_equal 'DBTDS_5_0 - 5.0 SQL Server', @client.tds_version_info
+ else
+ assert_equal 9, @client.tds_version
+ assert_equal 'DBTDS_7_1 - Microsoft SQL Server 2000', @client.tds_version_info
+ end
end
it 'uses UTF-8 client charset/encoding by default' do
@@ -155,7 +160,7 @@ class ClientTest < TinyTds::TestCase
assert_match %r{connection failed}i, e.message, 'ignore if non-english test run'
end
assert_new_connections_work
- end
+ end unless sybase_ase?
end
View
30 test/result_test.rb
@@ -128,11 +128,8 @@ class ResultTest < TinyTds::TestCase
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first['AffectedRows']
assert_instance_of Fixnum, afrows
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
- pk1 = @client.execute("SELECT SCOPE_IDENTITY() AS Ident").each.first['Ident']
- assert_instance_of BigDecimal, pk1, 'native is numeric(38,0) for SCOPE_IDENTITY() function'
- pk2 = @client.execute("SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident").each.first['Ident']
- assert_instance_of Fixnum, pk2, 'we it be able to CAST to bigint'
- assert_equal pk2, pk1.to_i, 'just making sure the 2 line up'
+ pk1 = @client.execute(@client.identity_sql).each.first['Ident']
+ assert_instance_of Fixnum, pk1, 'we it be able to CAST to bigint'
@client.execute("UPDATE [datatypes] SET [varchar_50] = NULL WHERE [varchar_50] = '#{text}'").do
afrows = @client.execute("SELECT @@ROWCOUNT AS AffectedRows").each.first['AffectedRows']
assert_equal 1, afrows
@@ -164,12 +161,12 @@ class ResultTest < TinyTds::TestCase
end
end
- it 'has an #insert method that cancels result rows and returns the SCOPE_IDENTITY() natively' do
+ it 'has an #insert method that cancels result rows and returns IDENTITY natively' do
rollback_transaction(@client) do
text = 'test scope identity rows native'
@client.execute("DELETE FROM [datatypes] WHERE [varchar_50] = '#{text}'").do
@client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").do
- sql_identity = @client.execute("SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident").each.first['Ident']
+ sql_identity = @client.execute(@client.identity_sql).each.first['Ident']
native_identity = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('#{text}')").insert
assert_equal sql_identity+1, native_identity
end
@@ -188,8 +185,14 @@ class ResultTest < TinyTds::TestCase
identity = @client.execute("INSERT INTO [datatypes] ([varchar_50]) VALUES ('something')").insert
assert_equal seed, identity
end
- end
-
+ end unless sybase_ase?
+ # On Sybase, sp_helpindex cannot be used inside a transaction, as
+ # The 'CREATE TABLE' command is not allowed within a multi-statement
+ # transaction in the 'tempdb' database.
+ #
+ # ...and sp_helpindex creates a temporary table #spindtab
+ #
+
it 'must be able to begin/commit transactions with raw sql' do
rollback_transaction(@client) do
@client.execute("BEGIN TRANSACTION").do
@@ -584,7 +587,7 @@ class ResultTest < TinyTds::TestCase
assert_equal [], @client.execute('').each
end
- if sybase_ase?
+ if sqlserver?
it 'must not raise an error when severity is 10 or less' do
(1..10).to_a.each do |severity|
@@ -604,7 +607,7 @@ class ResultTest < TinyTds::TestCase
else
it 'raises an error' do
- action = lambda { @client.execute("RAISERROR (N'Hello World', 16, 1)").do }
+ action = lambda { @client.execute("RAISERROR 50000 N'Hello World'").do }
assert_raise_tinytds_error(action) do |e|
assert_equal "Hello World", e.message
assert_equal 16, e.severity # predefined on ASE
@@ -628,7 +631,8 @@ class ResultTest < TinyTds::TestCase
it 'must error gracefully with bad table name' do
action = lambda { @client.execute('SELECT * FROM [foobar]').each }
assert_raise_tinytds_error(action) do |e|
- assert_match %r|invalid object name.*foobar|i, e.message
+ pattern = sybase_ase? ? /foobar not found/ : %r|invalid object name.*foobar|i
+ assert_match pattern, e.message
assert_equal 16, e.severity
assert_equal 208, e.db_error_number
end
@@ -679,7 +683,7 @@ class ResultTest < TinyTds::TestCase
else
skip 'FreeTDS 0.91 and higher can only pass this test.'
end
- end
+ end unless sybase_ase?
end
View
6 test/schema/sybase_ase.sql
@@ -56,7 +56,7 @@ CREATE TABLE [datatypes] (
-- [xml] [xml] NULL
)
-SET IDENTITY_INSERT [dbo].[datatypes] ON
+SET IDENTITY_INSERT [datatypes] ON
INSERT INTO [datatypes] ([id], [bigint]) VALUES ( 11, -9223372036854775807 )
INSERT INTO [datatypes] ([id], [bigint]) VALUES ( 12, 9223372036854775806 )
@@ -100,7 +100,7 @@ INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 171, N'1234567890'
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 172, N'123456åå' )
INSERT INTO [datatypes] ([id], [nchar_10]) VALUES ( 173, N'abc123' )
-- INSERT INTO [datatypes] ([id], [ntext]) VALUES ( 181, N'test ntext' )
--- INSERT INTO [datatypes] ([id], [ntext]) VALUES ( 182, N'test ntext åå' )
+-- INSERT INTO [datatypes] ([id], [ntext]) VALUES ( 182, N'test ntext' ) -- utf-8 chars in comments make sybase choke
INSERT INTO [datatypes] ([id], [numeric_18_0]) VALUES ( 191, 191 )
INSERT INTO [datatypes] ([id], [numeric_18_0]) VALUES ( 192, 123456789012345678 )
INSERT INTO [datatypes] ([id], [numeric_36_2]) VALUES ( 193, 12345678901234567890.01 )
@@ -108,7 +108,7 @@ INSERT INTO [datatypes] ([id], [numeric_36_2]) VALUES ( 194, 123.46 )
INSERT INTO [datatypes] ([id], [nvarchar_50]) VALUES ( 201, N'test nvarchar_50' )
INSERT INTO [datatypes] ([id], [nvarchar_50]) VALUES ( 202, N'test nvarchar_50 åå' )
-- INSERT INTO [datatypes] ([id], [nvarchar_max]) VALUES ( 211, N'test nvarchar_max' )
--- INSERT INTO [datatypes] ([id], [nvarchar_max]) VALUES ( 212, N'test nvarchar_max åå' )
+-- INSERT INTO [datatypes] ([id], [nvarchar_max]) VALUES ( 212, N'test nvarchar_max' ) -- see 182
INSERT INTO [datatypes] ([id], [real]) VALUES ( 221, 123.45 )
INSERT INTO [datatypes] ([id], [real]) VALUES ( 222, 0.0 )
INSERT INTO [datatypes] ([id], [real]) VALUES ( 223, 0.00001 )
Something went wrong with that request. Please try again.