mssqlclient 0.1.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.
@@ -0,0 +1,38 @@
1
+ using namespace System;
2
+ using namespace System::Reflection;
3
+ using namespace System::Runtime::CompilerServices;
4
+ using namespace System::Runtime::InteropServices;
5
+ using namespace System::Security::Permissions;
6
+
7
+ //
8
+ // General Information about an assembly is controlled through the following
9
+ // set of attributes. Change these attribute values to modify the information
10
+ // associated with an assembly.
11
+ //
12
+ [assembly:AssemblyTitleAttribute("MsSqlAdapter")];
13
+ [assembly:AssemblyDescriptionAttribute("")];
14
+ [assembly:AssemblyConfigurationAttribute("")];
15
+ [assembly:AssemblyCompanyAttribute("")];
16
+ [assembly:AssemblyProductAttribute("MsSqlAdapter")];
17
+ [assembly:AssemblyCopyrightAttribute("Copyright (c) 2006")];
18
+ [assembly:AssemblyTrademarkAttribute("")];
19
+ [assembly:AssemblyCultureAttribute("")];
20
+
21
+ //
22
+ // Version information for an assembly consists of the following four values:
23
+ //
24
+ // Major Version
25
+ // Minor Version
26
+ // Build Number
27
+ // Revision
28
+ //
29
+ // You can specify all the value or you can default the Revision and Build Numbers
30
+ // by using the '*' as shown below:
31
+
32
+ [assembly:AssemblyVersionAttribute("1.0.*")];
33
+
34
+ [assembly:ComVisible(false)];
35
+
36
+ [assembly:CLSCompliantAttribute(true)];
37
+
38
+ [assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
@@ -0,0 +1,177 @@
1
+ #include "helpers.h"
2
+
3
+ VALUE g_CBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
4
+ VALUE g_CDate = rb_const_get(rb_cObject, rb_intern("Date"));
5
+ VALUE g_CTime = rb_const_get(rb_cObject, rb_intern("Time"));
6
+ VALUE g_CDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
7
+
8
+ namespace MsSqlClient {
9
+ namespace Helpers {
10
+ VALUE CastToRubyObject(Type^ clr_type, Object^ object) {
11
+ VALUE ruby_value = Qnil;
12
+
13
+ if (object == System::DBNull::Value) {
14
+ ruby_value = Qnil;
15
+ } else if (clr_type == System::DateTime::typeid) {
16
+ return rb_funcall(g_CDate, rb_intern("new"), 3, ToRubyNumber(2006), ToRubyNumber(9), ToRubyNumber(7));
17
+
18
+ gcroot<DateTime^> clr_date_time = (DateTime^)object;
19
+ if (clr_date_time->Hour == 0 && clr_date_time->Minute == 0 && clr_date_time->Second == 0) {
20
+ // Create a Ruby Date Object
21
+ ruby_value = rb_funcall(g_CDate, rb_intern("new"), 3,
22
+ ToRubyNumber(clr_date_time->Year),
23
+ ToRubyNumber(clr_date_time->Month),
24
+ ToRubyNumber(clr_date_time->Day)
25
+ );
26
+ } else {
27
+ // Create a Ruby DateTime Object
28
+ ruby_value = rb_funcall(g_CTime, rb_intern("local"), 3,
29
+ ToRubyNumber(clr_date_time->Year),
30
+ ToRubyNumber(clr_date_time->Month),
31
+ ToRubyNumber(clr_date_time->Day),
32
+ ToRubyNumber(clr_date_time->Hour),
33
+ ToRubyNumber(clr_date_time->Minute),
34
+ ToRubyNumber(clr_date_time->Second)
35
+ );
36
+ }
37
+ } else {
38
+ if (clr_type == Boolean::typeid) ruby_value = Helpers::ToRubyBoolean((Boolean)object);
39
+ if (clr_type == SByte::typeid) ruby_value = Helpers::ToRubyNumber((SByte)object);
40
+ if (clr_type == Int16::typeid) ruby_value = Helpers::ToRubyNumber((Int16)object);
41
+ if (clr_type == Int32::typeid) ruby_value = Helpers::ToRubyNumber((Int32)object);
42
+ if (clr_type == Int64::typeid) ruby_value = Helpers::ToRubyNumber((Int64)object);
43
+ if (clr_type == Byte::typeid) ruby_value = Helpers::ToRubyNumber((Byte)object);
44
+ if (clr_type == UInt16::typeid) ruby_value = Helpers::ToRubyNumber((UInt16)object);
45
+ if (clr_type == UInt32::typeid) ruby_value = Helpers::ToRubyNumber((UInt32)object);
46
+ if (clr_type == UInt64::typeid) ruby_value = Helpers::ToRubyNumber((UInt64)object);
47
+ if (clr_type == String::typeid) ruby_value = Helpers::ToRubyString((String^)object);
48
+ if (clr_type == Single::typeid) ruby_value = Helpers::ToRubyNumber((Single)object);
49
+ if (clr_type == Double::typeid) ruby_value = Helpers::ToRubyNumber((Double)object);
50
+ }
51
+
52
+ return ruby_value;
53
+ }
54
+
55
+ VALUE convert_reader_to_rowset(SqlDataReader^ reader) {
56
+ VALUE rows = rb_ary_new();
57
+
58
+ array<Type^> ^field_types = gcnew array<Type^>(reader->FieldCount);
59
+ array<String^> ^field_names = gcnew array<String^>(reader->FieldCount);
60
+
61
+ for (int ordinal = 0; ordinal < field_types->Length; ordinal++) {
62
+ field_names[ordinal] = reader->GetName(ordinal);
63
+ field_types[ordinal] = reader->GetFieldType(ordinal);
64
+ }
65
+
66
+ while (reader->Read()) {
67
+ VALUE record = rb_hash_new();
68
+ for (int ordinal = 0; ordinal < field_types->Length; ordinal++) {
69
+ gcroot<Object^> object = reader->GetValue(ordinal);
70
+ rb_hash_aset(record, ToRubyString(field_names[ordinal]), CastToRubyObject((Type^)field_types[ordinal], object));
71
+ delete object;
72
+ }
73
+
74
+ rb_ary_push(rows, record);
75
+ }
76
+
77
+ delete field_names;
78
+ delete field_types;
79
+
80
+ return rows;
81
+ }
82
+
83
+ VALUE ToRubyObject(Object^ object) {
84
+ Type^ objectType = object->GetType();
85
+ VALUE ruby_value = Qnil;
86
+
87
+ if (System::DBNull::Value == object) {
88
+ ruby_value = Qnil;
89
+ } else if (object->GetType() == System::Decimal::typeid) {
90
+ ruby_value = rb_float_new(Convert::ToDouble(object));
91
+ } else if (object->GetType() == System::DateTime::typeid) {
92
+ char* native_string;
93
+ ConvertToCharStar("Time.parse(\"" + object->ToString() + "\")", native_string);
94
+ return rb_eval_string(native_string);
95
+ } else {
96
+ if (objectType == Boolean::typeid) return Helpers::ToRubyBoolean((Boolean)object);
97
+ if (objectType == SByte::typeid) return Helpers::ToRubyNumber((SByte)object);
98
+ if (objectType == Int16::typeid) return Helpers::ToRubyNumber((Int16)object);
99
+ if (objectType == Int32::typeid) return Helpers::ToRubyNumber((Int32)object);
100
+ if (objectType == Int64::typeid) return Helpers::ToRubyNumber((Int64)object);
101
+ if (objectType == Byte::typeid) return Helpers::ToRubyNumber((Byte)object);
102
+ if (objectType == UInt16::typeid) return Helpers::ToRubyNumber((UInt16)object);
103
+ if (objectType == UInt32::typeid) return Helpers::ToRubyNumber((UInt32)object);
104
+ if (objectType == UInt64::typeid) return Helpers::ToRubyNumber((UInt64)object);
105
+ if (objectType == String::typeid) return Helpers::ToRubyString((String^)object);
106
+ if (objectType == Single::typeid) return Helpers::ToRubyNumber((Single)object);
107
+ if (objectType == Double::typeid) return Helpers::ToRubyNumber((Double)object);
108
+ }
109
+
110
+ return ruby_value;
111
+ }
112
+
113
+ VALUE ToRubyNumber(Int64 value) { return rb_ll2inum(value); }
114
+ VALUE ToRubyNumber(Int32 value) { return rb_int2inum(value); }
115
+ VALUE ToRubyNumber(Int16 value) { return rb_int2inum(value); }
116
+ VALUE ToRubyNumber(SByte value) { return rb_int2inum(value); }
117
+ VALUE ToRubyNumber(UInt64 value) { return rb_ull2inum(value); }
118
+ VALUE ToRubyNumber(UInt32 value) { return rb_uint2inum(value); }
119
+ VALUE ToRubyNumber(UInt16 value) { return rb_uint2inum(value); }
120
+ VALUE ToRubyNumber(Byte value) { return rb_uint2inum(value); }
121
+ VALUE ToRubyNumber(Double value) { return rb_float_new(value); }
122
+ VALUE ToRubyNumber(Single value) { return rb_float_new(value); }
123
+
124
+ VALUE ToRubyNumber(Decimal value) {
125
+ VALUE val = ToRubyString(value.ToString());
126
+ return rb_funcall(g_CBigDecimal, rb_intern("new"), 1, val);
127
+ }
128
+
129
+ VALUE ToRubyBoolean(bool value) { return value ? Qtrue : Qfalse; }
130
+ VALUE ToRubyNil() { return Qnil; }
131
+
132
+ String^ ToClrString(VALUE self) {
133
+ if (self == Qnil) return nullptr;
134
+ char* native_string = STR2CSTR(self);
135
+
136
+ size_t native_size = strlen(native_string);
137
+ array<unsigned char>^ bytes = gcnew array<unsigned char>(native_size);
138
+
139
+ for(unsigned int i = 0; i < native_size; i++) {
140
+ bytes[i] = System::Byte(native_string[i]);
141
+ }
142
+
143
+ String^ return_value = System::Text::Encoding::UTF8->GetString(bytes);
144
+
145
+ delete bytes;
146
+
147
+ return return_value;
148
+ }
149
+
150
+ VALUE ToRubyString(String^ string) {
151
+ if (string == nullptr) return Qnil;
152
+
153
+ char *ptr = (char*)malloc(4+System::Text::Encoding::UTF8->GetByteCount(string));
154
+ cli::array<unsigned char>^ char_array = System::Text::Encoding::UTF8->GetBytes(string);
155
+ cli::pin_ptr<unsigned char> char_pin_ptr = &char_array[0];
156
+ strcpy(ptr, (char*)char_pin_ptr);
157
+ return rb_str_new2((char*)(void*)ptr);
158
+ }
159
+
160
+ bool ConvertToCharStar( String^ source, char*& target ) {
161
+ int len = (( source->Length+1) * 2);
162
+ target = new char[ len ];
163
+ pin_ptr<const wchar_t> wch = PtrToStringChars( source );
164
+ return wcstombs( target, wch, len ) != -1;
165
+ }
166
+
167
+ void release_object(void *objref) {
168
+ if (objref != 0 && *((int*)objref) != 0) {
169
+ int *objectReference = (int*)objref;
170
+ GCHandle handle = (GCHandle)(IntPtr)*objectReference;
171
+ //Identity::RemoveProxyObject(handle.Target);
172
+ handle.Free();
173
+ xfree(objectReference);
174
+ }
175
+ }
176
+ }
177
+ }
@@ -0,0 +1,44 @@
1
+ #include <windows.h>
2
+ #include <vcclr.h>
3
+ #include <ruby.h>
4
+
5
+ #define _CRT_SECURE_NO_DEPRECATE 1
6
+ #pragma warning(disable:4947)
7
+
8
+ using namespace System;
9
+ using namespace System::Data;
10
+ using namespace System::Data::SqlClient;
11
+ using namespace System::Runtime;
12
+ using namespace System::Runtime::InteropServices;
13
+
14
+ namespace MsSqlClient {
15
+ namespace Helpers {
16
+
17
+ VALUE CastToRubyObject(Type^ clr_type, Object^ object);
18
+ VALUE convert_reader_to_rowset(SqlDataReader^ reader);
19
+
20
+ // Marshaling Methods
21
+ VALUE ToRubyString(String^ string);
22
+ VALUE ToRubyObject(Object^ object);
23
+ VALUE ToRubyNumber(Int64 value);
24
+ VALUE ToRubyNumber(Int32 value);
25
+ VALUE ToRubyNumber(Int16 value);
26
+ VALUE ToRubyNumber(SByte value);
27
+ VALUE ToRubyNumber(UInt64 value);
28
+ VALUE ToRubyNumber(UInt32 value);
29
+ VALUE ToRubyNumber(UInt16 value);
30
+ VALUE ToRubyNumber(Byte value);
31
+ VALUE ToRubyNumber(Double value);
32
+ VALUE ToRubyNumber(Single value);
33
+ VALUE ToRubyNumber(Decimal value);
34
+ VALUE ToRubyBoolean(bool value);
35
+ VALUE ToRubyNil();
36
+ String^ ToClrString(VALUE string);
37
+ VALUE ToRubyString(String^ string);
38
+
39
+ bool ConvertToCharStar( String^ source, char*& target );
40
+
41
+ // Garbage Collection
42
+ void release_object(void *objref);
43
+ }
44
+ }
@@ -0,0 +1,20 @@
1
+ 
2
+ Microsoft Visual Studio Solution File, Format Version 9.00
3
+ # Visual Studio 2005
4
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ms_sql_client", "MsSqlClient.express.vcproj", "{358B7FEF-C413-48BA-B3C6-134BCC270245}"
5
+ EndProject
6
+ Global
7
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
8
+ Debug|Win32 = Debug|Win32
9
+ Release|Win32 = Release|Win32
10
+ EndGlobalSection
11
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
12
+ {358B7FEF-C413-48BA-B3C6-134BCC270245}.Debug|Win32.ActiveCfg = Debug|Win32
13
+ {358B7FEF-C413-48BA-B3C6-134BCC270245}.Debug|Win32.Build.0 = Debug|Win32
14
+ {358B7FEF-C413-48BA-B3C6-134BCC270245}.Release|Win32.ActiveCfg = Release|Win32
15
+ {358B7FEF-C413-48BA-B3C6-134BCC270245}.Release|Win32.Build.0 = Release|Win32
16
+ EndGlobalSection
17
+ GlobalSection(SolutionProperties) = preSolution
18
+ HideSolutionNode = FALSE
19
+ EndGlobalSection
20
+ EndGlobal
@@ -0,0 +1,196 @@
1
+ #include "mssqlclient.h"
2
+
3
+ namespace MsSqlClient {
4
+
5
+ VALUE e_ActiveRecordStatementInvalid = rb_eval_string("ActiveRecord::StatementInvalid");
6
+
7
+ gcroot<SqlTransaction^> transaction;
8
+
9
+ // MsSqlAdapter Helper Methods
10
+
11
+ bool in_transaction(VALUE instance) {
12
+ return rb_iv_get(instance, "@in_transaction") == Qtrue;;
13
+ }
14
+
15
+ gcroot<SqlConnection^> get_connection(VALUE instance) {
16
+ if (in_transaction(instance)) {
17
+ return transaction->Connection;
18
+ } else {
19
+ gcroot<SqlConnection^> connection = gcnew SqlConnection();
20
+ connection->ConnectionString = Helpers::ToClrString(rb_funcall(instance, rb_intern("connection_string"), 0));
21
+ connection->Open();
22
+ return connection;
23
+ }
24
+ }
25
+
26
+ void destroy_connection(SqlConnection^ connection) {
27
+ connection->Close();
28
+ delete connection;
29
+ }
30
+
31
+ VALUE c_MsSqlAdapter_begin_db_transaction(VALUE instance) {
32
+ gcroot<SqlConnection^> connection = get_connection(instance);
33
+ transaction = connection->BeginTransaction();
34
+ return rb_iv_set(instance, "@in_transaction", Qtrue);
35
+ }
36
+
37
+ VALUE c_MsSqlAdapter_commit_db_transaction(VALUE instance) {
38
+ gcroot<SqlConnection^> connection = transaction->Connection;
39
+ transaction->Commit();
40
+ destroy_connection(connection);
41
+ delete transaction;
42
+ return rb_iv_set(instance, "@in_transaction", Qfalse);
43
+ }
44
+
45
+ VALUE c_MsSqlAdapter_rollback_db_transaction(VALUE instance) {
46
+ gcroot<SqlConnection^> connection = transaction->Connection;
47
+ transaction->Rollback();
48
+ destroy_connection(connection);
49
+ delete transaction;
50
+ return rb_iv_set(instance, "@in_transaction", Qfalse);
51
+ }
52
+
53
+
54
+ // MsSqlAdapter Instance Methods
55
+
56
+ static VALUE c_MsSqlAdapter_allocate_connection(VALUE self) {
57
+ return Qnil;
58
+ }
59
+
60
+ // This method is not part of the AbstractAdapter implementation
61
+ static VALUE c_MsSqlAdapter_select(VALUE self, VALUE query) {
62
+ try {
63
+ gcroot<SqlConnection^> connection = get_connection(self);
64
+ VALUE records = rb_ary_new();
65
+ gcroot<String^> command_text = Helpers::ToClrString(query);
66
+ gcroot<SqlCommand^> command = connection->CreateCommand();
67
+
68
+ if (in_transaction(self)) {
69
+ command->Transaction = transaction;
70
+ }
71
+
72
+ try {
73
+ command->CommandText = command_text;
74
+ command->CommandType = CommandType::Text;
75
+ gcroot<SqlDataReader^> reader = command->ExecuteReader();
76
+
77
+ if (reader->HasRows) {
78
+ records = Helpers::convert_reader_to_rowset(reader);
79
+ }
80
+
81
+ reader->Close();
82
+ delete reader;
83
+ } catch (SqlException^ sqlEx) {
84
+ char* native_message;
85
+ Helpers::ConvertToCharStar(sqlEx->ToString(), native_message);
86
+ rb_raise(e_ActiveRecordStatementInvalid, native_message);
87
+ command->Cancel();
88
+ } finally {
89
+ delete command;
90
+ delete command_text;
91
+ if (!in_transaction(self)) {
92
+ destroy_connection(connection);
93
+ }
94
+ }
95
+
96
+ return records;
97
+ } catch(Exception^ e) {
98
+ char* native_message;
99
+ Helpers::ConvertToCharStar(e->ToString(), native_message);
100
+ rb_raise(e_ActiveRecordStatementInvalid, native_message);
101
+ }
102
+ }
103
+
104
+ static VALUE c_MsSqlAdapter_insert(VALUE self, VALUE query) {
105
+ gcroot<SqlConnection^> connection = get_connection(self);
106
+ VALUE return_value = Qnil;
107
+ gcroot<String^> command_text = String::Concat(Helpers::ToClrString(query), "\r\nSELECT SCOPE_IDENTITY() as NewIdentity");
108
+ gcroot<SqlCommand^> command;
109
+
110
+ try {
111
+ if (in_transaction(self)) {
112
+ command = transaction->Connection->CreateCommand();
113
+ command->Transaction = transaction;
114
+ } else {
115
+ command = connection->CreateCommand();
116
+ }
117
+
118
+ command->CommandText = command_text;
119
+ command->CommandType = CommandType::Text;
120
+
121
+ gcroot<Object^> value = command->ExecuteScalar();
122
+ return_value = Helpers::ToRubyObject(value);
123
+ } catch (SqlException^ sqlEx) {
124
+ char* native_message;
125
+ Helpers::ConvertToCharStar(String::Format("Command Text: {0}\nError: {1}", command_text, sqlEx->ToString()), native_message);
126
+ rb_raise(e_ActiveRecordStatementInvalid, native_message);
127
+ command->Cancel();
128
+ } finally {
129
+ delete command;
130
+ delete command_text;
131
+
132
+ if (!in_transaction(self)) {
133
+ destroy_connection(connection);
134
+ }
135
+ }
136
+
137
+ return return_value;
138
+
139
+ }
140
+
141
+ static VALUE c_MsSqlAdapter_execute(VALUE self, VALUE query) {
142
+ gcroot<SqlConnection^> connection = get_connection(self);
143
+ VALUE return_value = Qnil;
144
+ gcroot<String^> command_text = Helpers::ToClrString(query);
145
+ gcroot<SqlCommand^> command;
146
+
147
+ try {
148
+
149
+ if (in_transaction(self)) {
150
+ command = transaction->Connection->CreateCommand();
151
+ command->Transaction = transaction;
152
+ } else {
153
+ command = connection->CreateCommand();
154
+ }
155
+
156
+ command->CommandText = command_text;
157
+ command->CommandType = CommandType::Text;
158
+
159
+ return_value = Helpers::ToRubyNumber(command->ExecuteNonQuery());
160
+ } catch (SqlException^ sqlEx) {
161
+ char* native_message;
162
+ Helpers::ConvertToCharStar(String::Format("Command Text: {0}\nError: {1}", command_text, sqlEx->ToString()), native_message);
163
+ rb_raise(e_ActiveRecordStatementInvalid, native_message);
164
+ command->Cancel();
165
+ } finally {
166
+ delete command;
167
+ delete command_text;
168
+
169
+ if (!in_transaction(self)) {
170
+ destroy_connection(connection);
171
+ }
172
+ }
173
+
174
+ return return_value;
175
+ }
176
+
177
+ extern "C" {
178
+
179
+ #pragma unmanaged
180
+ // Main entry point
181
+ __declspec(dllexport) void Init_ms_sql_client() {
182
+ CoInitializeEx(0, COINIT_APARTMENTTHREADED);
183
+
184
+ rb_require("date");
185
+
186
+ VALUE r_MsSqlAdapter_module = rb_define_module("MsSqlClient");
187
+ rb_define_method(r_MsSqlAdapter_module, "_select", RUBY_METHOD_FUNC(c_MsSqlAdapter_select), 1);
188
+ rb_define_method(r_MsSqlAdapter_module, "_insert", RUBY_METHOD_FUNC(c_MsSqlAdapter_insert), 1);
189
+ rb_define_method(r_MsSqlAdapter_module, "_execute", RUBY_METHOD_FUNC(c_MsSqlAdapter_execute), 1);
190
+ rb_define_method(r_MsSqlAdapter_module, "begin_db_transaction", RUBY_METHOD_FUNC(c_MsSqlAdapter_begin_db_transaction), 0);
191
+ rb_define_method(r_MsSqlAdapter_module, "commit_db_transaction", RUBY_METHOD_FUNC(c_MsSqlAdapter_commit_db_transaction), 0);
192
+ rb_define_method(r_MsSqlAdapter_module, "rollback_db_transaction", RUBY_METHOD_FUNC(c_MsSqlAdapter_rollback_db_transaction), 0);
193
+
194
+ }
195
+ }
196
+ }