dbd-sqlanywhere 0.1.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,12 +1,21 @@
1
- =CHANGE LOG
2
-
3
- =====0.1.1 -- 2008/11/06
4
- - Changed file permissions on archives
5
- - Changed archives to be specific to platform (.zip on windows, .tar.gz
6
- otherwise)
7
- - Removed the default rake task
8
-
9
- =====0.1.0 -- 2008/10/29
10
- - Initial Release
11
- - Wraps DBCAPI functionality
12
- - Tested against DBI 0.4
1
+ =CHANGE LOG
2
+
3
+ =====1.0.0 -- 2012/08/29
4
+ - Changed to have each row element to be stored as String object by "default" so that dbh.convert_types = false would return the String element properly.
5
+ - Changed sth.column_info not to assign any value "precision" and "scale" for the datatype that does not specify the precision or length.
6
+ - Changed sth.rows to return proper value for the number of the affected rows
7
+ - Changed rakefile to use rdoc/task instead of rake/rdoctask(deprecated)
8
+
9
+ =====0.1.2 -- 2009/03/27
10
+ - Changed the order and type of parameter for connection
11
+
12
+ =====0.1.1 -- 2008/11/06
13
+ - Changed file permissions on archives
14
+ - Changed archives to be specific to platform (.zip on windows, .tar.gz
15
+ otherwise)
16
+ - Removed the default rake task
17
+
18
+ =====0.1.0 -- 2008/10/29
19
+ - Initial Release
20
+ - Wraps DBCAPI functionality
21
+ - Tested against DBI 0.4
data/LICENSE CHANGED
@@ -1,23 +1,23 @@
1
- /*====================================================
2
- *
3
- * Copyright 2008-2009 iAnywhere Solutions, Inc.
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- *
10
- * http://www.apache.org/licenses/LICENSE-2.0
11
- *
12
- * Unless required by applicable law or agreed to in writing, software
13
- * distributed under the License is distributed on an "AS IS" BASIS,
14
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- *
16
- * See the License for the specific language governing permissions and
17
- * limitations under the License.
18
- *
19
- * While not a requirement of the license, if you do modify this file, we
20
- * would appreciate hearing about it. Please email sqlany_interfaces@sybase.com
21
- *
22
- *
23
- *====================================================*/
1
+ /*====================================================
2
+ *
3
+ * Copyright 2012 iAnywhere Solutions, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ *
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ *
19
+ * While not a requirement of the license, if you do modify this file, we
20
+ * would appreciate hearing about it. Please email sqlany_interfaces@sybase.com
21
+ *
22
+ *
23
+ *====================================================*/
data/README CHANGED
@@ -1,150 +1,150 @@
1
- =SQL Anywhere DBD Driver for Ruby-DBI
2
-
3
- This is a SQL Anywhere driver for Ruby DBI (http://ruby-dbi.rubyforge.org/). This driver requires the
4
- native SQL Anywhere Ruby driver. To get the native driver, use:
5
-
6
- gem install sqlanywhere
7
-
8
- This driver is designed for use with DBI 0.4 and greater.
9
-
10
- This driver is licensed under the Apache License, Version 2.
11
-
12
- The official code repository is located on GitHub. The repository can be cloned with:
13
-
14
- git clone git://github.com/sqlanywhere/dbd-sqlanywhere.git
15
-
16
- ==Making a Connection
17
-
18
- The following code is a sample database configuration object that connects
19
- to a database called 'Test'.
20
-
21
- require 'dbi'
22
-
23
- DBI.connect('DBI:SQLAnywhere:Test') do | dbh |
24
- if dbh.ping
25
- print "Successfully Connected"
26
- end
27
- end
28
-
29
- The connection function takes the general form:
30
-
31
- dbh = DBI.connect(DBNAME, [USER_NAME], [PASSWORD])
32
-
33
- The DBNAME string can be specified in the following forms:
34
-
35
- "DBI:SQLAnywhere:"
36
- "DBI:SQLAnywhere:{ENG}"
37
- "DBI:SQLAnywhere:{ENG}:{DBN}"
38
- "DBI:SQLAnywhere:{CONNECTION_STRING}" # where CONNECTION_STRING ~= "key1=val1;key2=val2;..."
39
-
40
- For the first form, nothing will be added to the connection string. With the second and third forms
41
- the driver will add ENG and DBN to the connection string accordingly. The fourth form will pass
42
- the supplied connection string through unmolested.
43
-
44
- The USER_NAME and PASSWORD can be passed into the function and they will be automatically appended to the
45
- connection string. Since Ruby DBI will automatically fill in the username and password with defaults if they are omitted,
46
- you should NEVER include a "UID=" or "PWD=" in your connection string or an exception will be thrown.
47
-
48
- Examples:
49
-
50
- Function Call ==> Generated Connection String
51
- ==============================================================================================
52
- DBI.connect("DBI:SQLAnywhere:") ==> "uid=dba;pwd=sql"
53
- DBI.connect("DBI:SQLAnywhere:Demo") ==> "eng=Demo;uid=dba;pwd=sql"
54
- DBI.connect("DBI:SQLAnywhere:Demo:Test") ==> "eng=Demo;dbn=Test;uid=dba;pwd=sql"
55
- DBI.connect("DBI:SQLAnywhere:Demo:Test", 'john', 'doe') ==> "eng=Demo;dbn=Test;uid=john;pwd=doe"
56
- DBI.connect("DBI:SQLAnywhere:eng=Demo;dbn=Test") ==> "eng=Demo;dbn=Test;uid=dba;pwd=sql"
57
- DBI.connect("DBI:SQLAnywhere:eng=Demo;dbn=Test;uid=john") ==> EXCEPTION! UID cannot be specified in the connection string
58
- DBI.connect("DBI:SQLAnywhere:CommLinks=tcpip(port=2638)") ==> "CommLinks=tcpip(port=2638);uid=dba;pwd=sql"
59
-
60
-
61
- ==Running Test Suite
62
-
63
- For information on running the Ruby/DBI DBD Tests, please see
64
-
65
- test/DBD_TESTS
66
-
67
- ==Driver-Specific Features
68
-
69
- At the time of this writing, there was no standard way to handle INOUT and OUT parameters
70
- from stored procedures in DBI.
71
-
72
- When binding to an OUT parameter, you must bind a hash that contains a key called
73
- :name. This :name will be used to retrieve the OUT value after execution. If the
74
- OUT column is of string or binary type, you must also pass a key called :length
75
- with the expected maximum length of the OUT parameter.
76
-
77
- In the case of an INOUT parameter, the :name and :length keys are the same as for
78
- OUT parameters, but an additional :value parameter holds the value to be passed
79
- into the stored procedure.
80
-
81
- After execution, you can use the statement-specific function :bound_param
82
- to retrieve the output value using the :name supplied at binding time.
83
-
84
- ===Example of using OUT and INOUT parameters
85
-
86
- # The result that should be printed to console is:
87
- # Complete string is PREFIX-some_string-SUFFIX and is 25 chars long
88
- # Complete string is PREFIXPREFIX-some_string-SUFFIXSUFFIX and is 37 chars long
89
-
90
- require 'dbi'
91
-
92
- begin
93
- DBI.connect("DBI:SQLAnywhere:test") do |dbh|
94
-
95
- sql = <<SQL
96
- IF EXISTS(SELECT * FROM SYS.SYSPROCEDURE where proc_name = 'foo') THEN
97
- DROP PROCEDURE foo;
98
- END IF
99
- SQL
100
-
101
- dbh.do(sql);
102
-
103
- sql = <<SQL
104
- create procedure foo
105
- ( IN prefix char(10),
106
- INOUT buffer varchar(256),
107
- OUT str_len int,
108
- IN suffix char(10)
109
- )
110
- begin
111
- set buffer = prefix || buffer || suffix;
112
- select length( buffer ) into str_len;
113
- end
114
- SQL
115
-
116
- dbh.do(sql);
117
-
118
- buffer = "-some_string-"
119
- prefix = "PREFIX"
120
-
121
- # preparing the statement
122
- sth = dbh.prepare("call foo( ?, ?, ?, ? )")
123
-
124
- # Binding buffer column as :buf, and str_len column as :len
125
- # Note that we must supply a :value for :buf since it is an INOUT
126
- # And we must supply a :length for :buf since it is a string column
127
- sth.execute( prefix, {:name => :buf, :value => buffer, :length => 255}, {:name => :len}, "SUFFIX")
128
-
129
- # Retrieve the OUT value from buffer
130
- new_buffer = sth.func(:bound_param, :buf)
131
-
132
- # Retrieve the OUT value from str_len
133
- length = sth.func(:bound_param, :len)
134
- puts "Complete string is #{new_buffer} and is #{length} chars long"
135
-
136
- # Add the results back into the string, and re-execute
137
- sth.execute("PREFIX", {:name => :buf, :value => new_buffer, :length => 255}, {:name => :len}, "SUFFIX")
138
- new_buffer = sth.func(:bound_param, :buf)
139
- length = sth.func(:bound_param, :len)
140
- puts "Complete string is #{new_buffer} and is #{length} chars long"
141
- end
142
-
143
- rescue DBI::DatabaseError => e
144
- puts "An error occurred"
145
- puts "Error code: #{e.err}"
146
- puts "Error message: #{e.errstr}"
147
- puts "Error SQLSTATE: #{e.state}"
148
- ensure
149
- DBI.disconnect_all
150
- end
1
+ =SQL Anywhere DBD Driver for Ruby-DBI
2
+
3
+ This is a SQL Anywhere driver for Ruby DBI (http://ruby-dbi.rubyforge.org/). This driver requires the
4
+ native SQL Anywhere Ruby driver. To get the native driver, use:
5
+
6
+ gem install sqlanywhere
7
+
8
+ This driver is designed for use with DBI 0.4 and greater.
9
+
10
+ This driver is licensed under the Apache License, Version 2.
11
+
12
+ The official code repository is located on GitHub. The repository can be cloned with:
13
+
14
+ git clone git://github.com/sqlanywhere/dbd-sqlanywhere.git
15
+
16
+ ==Making a Connection
17
+
18
+ The following code is a sample database configuration object that connects
19
+ to a database called 'Test'.
20
+
21
+ require 'dbi'
22
+
23
+ DBI.connect('DBI:SQLAnywhere:Test') do | dbh |
24
+ if dbh.ping
25
+ print "Successfully Connected"
26
+ end
27
+ end
28
+
29
+ The connection function takes the general form:
30
+
31
+ dbh = DBI.connect(DBNAME, [USER_NAME], [PASSWORD])
32
+
33
+ The DBNAME string can be specified in the following forms:
34
+
35
+ "DBI:SQLAnywhere:"
36
+ "DBI:SQLAnywhere:{ENG}"
37
+ "DBI:SQLAnywhere:{ENG}:{DBN}"
38
+ "DBI:SQLAnywhere:{CONNECTION_STRING}" # where CONNECTION_STRING ~= "key1=val1;key2=val2;..."
39
+
40
+ For the first form, nothing will be added to the connection string. With the second and third forms
41
+ the driver will add ENG and DBN to the connection string accordingly. The fourth form will pass
42
+ the supplied connection string through unmolested.
43
+
44
+ The USER_NAME and PASSWORD can be passed into the function and they will be automatically appended to the
45
+ connection string. Since Ruby DBI will automatically fill in the username and password with defaults if they are omitted,
46
+ you should NEVER include a "UID=" or "PWD=" in your connection string or an exception will be thrown.
47
+
48
+ Examples:
49
+
50
+ Function Call ==> Generated Connection String
51
+ ==============================================================================================
52
+ DBI.connect("DBI:SQLAnywhere:") ==> "uid=dba;pwd=sql"
53
+ DBI.connect("DBI:SQLAnywhere:Demo") ==> "eng=Demo;uid=dba;pwd=sql"
54
+ DBI.connect("DBI:SQLAnywhere:Demo:Test") ==> "eng=Demo;dbn=Test;uid=dba;pwd=sql"
55
+ DBI.connect("DBI:SQLAnywhere:Demo:Test", 'john', 'doe') ==> "eng=Demo;dbn=Test;uid=john;pwd=doe"
56
+ DBI.connect("DBI:SQLAnywhere:eng=Demo;dbn=Test") ==> "eng=Demo;dbn=Test;uid=dba;pwd=sql"
57
+ DBI.connect("DBI:SQLAnywhere:eng=Demo;dbn=Test;uid=john") ==> EXCEPTION! UID cannot be specified in the connection string
58
+ DBI.connect("DBI:SQLAnywhere:CommLinks=tcpip(port=2638)") ==> "CommLinks=tcpip(port=2638);uid=dba;pwd=sql"
59
+
60
+
61
+ ==Running Test Suite
62
+
63
+ For information on running the Ruby/DBI DBD Tests, please see
64
+
65
+ test/DBD_TESTS
66
+
67
+ ==Driver-Specific Features
68
+
69
+ At the time of this writing, there was no standard way to handle INOUT and OUT parameters
70
+ from stored procedures in DBI.
71
+
72
+ When binding to an OUT parameter, you must bind a hash that contains a key called
73
+ :name. This :name will be used to retrieve the OUT value after execution. If the
74
+ OUT column is of string or binary type, you must also pass a key called :length
75
+ with the expected maximum length of the OUT parameter.
76
+
77
+ In the case of an INOUT parameter, the :name and :length keys are the same as for
78
+ OUT parameters, but an additional :value parameter holds the value to be passed
79
+ into the stored procedure.
80
+
81
+ After execution, you can use the statement-specific function :bound_param
82
+ to retrieve the output value using the :name supplied at binding time.
83
+
84
+ ===Example of using OUT and INOUT parameters
85
+
86
+ # The result that should be printed to console is:
87
+ # Complete string is PREFIX-some_string-SUFFIX and is 25 chars long
88
+ # Complete string is PREFIXPREFIX-some_string-SUFFIXSUFFIX and is 37 chars long
89
+
90
+ require 'dbi'
91
+
92
+ begin
93
+ DBI.connect("DBI:SQLAnywhere:test") do |dbh|
94
+
95
+ sql = <<SQL
96
+ IF EXISTS(SELECT * FROM SYS.SYSPROCEDURE where proc_name = 'foo') THEN
97
+ DROP PROCEDURE foo;
98
+ END IF
99
+ SQL
100
+
101
+ dbh.do(sql);
102
+
103
+ sql = <<SQL
104
+ create procedure foo
105
+ ( IN prefix char(10),
106
+ INOUT buffer varchar(256),
107
+ OUT str_len int,
108
+ IN suffix char(10)
109
+ )
110
+ begin
111
+ set buffer = prefix || buffer || suffix;
112
+ select length( buffer ) into str_len;
113
+ end
114
+ SQL
115
+
116
+ dbh.do(sql);
117
+
118
+ buffer = "-some_string-"
119
+ prefix = "PREFIX"
120
+
121
+ # preparing the statement
122
+ sth = dbh.prepare("call foo( ?, ?, ?, ? )")
123
+
124
+ # Binding buffer column as :buf, and str_len column as :len
125
+ # Note that we must supply a :value for :buf since it is an INOUT
126
+ # And we must supply a :length for :buf since it is a string column
127
+ sth.execute( prefix, {:name => :buf, :value => buffer, :length => 255}, {:name => :len}, "SUFFIX")
128
+
129
+ # Retrieve the OUT value from buffer
130
+ new_buffer = sth.func(:bound_param, :buf)
131
+
132
+ # Retrieve the OUT value from str_len
133
+ length = sth.func(:bound_param, :len)
134
+ puts "Complete string is #{new_buffer} and is #{length} chars long"
135
+
136
+ # Add the results back into the string, and re-execute
137
+ sth.execute("PREFIX", {:name => :buf, :value => new_buffer, :length => 255}, {:name => :len}, "SUFFIX")
138
+ new_buffer = sth.func(:bound_param, :buf)
139
+ length = sth.func(:bound_param, :len)
140
+ puts "Complete string is #{new_buffer} and is #{length} chars long"
141
+ end
142
+
143
+ rescue DBI::DatabaseError => e
144
+ puts "An error occurred"
145
+ puts "Error code: #{e.err}"
146
+ puts "Error message: #{e.errstr}"
147
+ puts "Error SQLSTATE: #{e.state}"
148
+ ensure
149
+ DBI.disconnect_all
150
+ end
@@ -1,176 +1,176 @@
1
- #====================================================
2
- #
3
- # Copyright 2008-2009 iAnywhere Solutions, Inc.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- #
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
- #
19
- # While not a requirement of the license, if you do modify this file, we
20
- # would appreciate hearing about it. Please email sqlany_interfaces@sybase.com
21
- #
22
- #
23
- #====================================================
24
-
25
- begin
26
- require 'rubygems'
27
- gem 'sqlanywhere'
28
- gem 'dbi'
29
- rescue LoadError => e
30
- end
31
-
32
- require 'dbi'
33
- require 'dbi/typeutil'
34
- require 'sqlanywhere'
35
- require 'singleton'
36
-
37
- module DBI
38
- module DBD
39
- module SQLAnywhere
40
-
41
- VERSION = "0.1.2"
42
-
43
- def self.driver_name
44
- "SQLAnywhere"
45
- end
46
-
47
- class SA
48
- include Singleton
49
- attr_accessor :api
50
-
51
- def initialize
52
- unless defined? SQLAnywhere
53
- require 'sqlanywhere'
54
- end
55
-
56
- @api = ::SQLAnywhere::SQLAnywhereInterface.new()
57
- result = ::SQLAnywhere::API.sqlany_initialize_interface( @api )
58
- if result == 0
59
- raise LoadError, "Could not load SQLAnywhere DLL"
60
- end
61
- result = @api.sqlany_init()
62
- if result == 0
63
- raise LoadError, "Could not initialize SQLAnywhere DLL"
64
- end
65
- end
66
-
67
- def free_api
68
- ::SQLAnywhere::API.sqlany_finalize_interface( @api );
69
- @api = nil
70
- end
71
- end
72
-
73
-
74
- DBI::TypeUtil.register_conversion(driver_name) do |obj|
75
- case obj
76
- when DBI::Binary # these need to be handled specially by the driver
77
- obj.to_s
78
- when ::NilClass
79
- nil
80
- when ::TrueClass
81
- 1
82
- when ::FalseClass
83
- 0
84
- when ::Time
85
- obj.strftime("%H:%M:%S")
86
- when ::Date
87
- obj.strftime("%Y/%m/%d")
88
- when ::DateTime, DBI::Timestamp
89
- DateTime.parse(obj.to_s).strftime("%Y/%m/%d %H:%M:%S")
90
- when ::String
91
- obj
92
- when ::BigDecimal
93
- obj.to_s("F")
94
- when ::Numeric
95
- obj.to_s
96
- else
97
- obj
98
- end
99
- end
100
-
101
-
102
- # This module provides functionality that is used by all the DBD classes
103
- module Utility
104
-
105
- NO_DIRECTION = 0
106
- INPUT_ONLY = 1
107
- OUTPUT_ONLY = 2
108
- INPUT_OUTPUT = 3
109
-
110
- # do_bind takes the following arguments:
111
- # * +prep_stmt+ : a handle the prepared Statement object
112
- # * +param+ : the parameter to bound, obtained by sqlany_describe_bind_param
113
- # * +bindvar+ : the actual value to bind the the parameter. Can be a +VALUE+, or a +HASH+.
114
- # * +i+ : the parameter number to bind. Should be the same as used in sqlany_describe_bind_param
115
- # * +bound+ : hash used to track INOUT, and OUT parameters
116
- #
117
- # +IN+ parameters will be bound once with +INPUT_ONLY+.
118
- # +OUT+ parameters will be bound once with +OUTPUT_ONLY+.
119
- # +INOUT+ parameters will be be bound twice, once as +INPUT_ONLY+, and once as +OUTPUT_ONLY+. +INOUT+ parameters
120
- # will use *different* buffers to pass the input and output values to the DLL.
121
- #
122
- # If the parameter to be bound is +INPUT_ONLY+, +bindvar+ *must* be a regular value type such as
123
- # Bignum, Fixnum, String, etc. This value will be bound to the input parameter
124
- #
125
- # If the parameter to be bound is +OUTPUT_ONLY+, +bindvar+ *must* be a hash with keys:
126
- # ::name => This is the name that you will be used later to retrieve the output value
127
- # ::length => If the output will be a string or binary, the expected length must be stated. If this length is exceeded
128
- # a DatabaseError (truncation) will be raised.
129
- #
130
- # If the parameter to be bound is +INPUT_OUTPUT+, +bindvar+ *must* be a hash with keys:
131
- # ::name => This is the name that you will be used later to retrieve the output value
132
- # ::value => The value to bind to the input.
133
- # ::length => If the output will be a string or binary, the expected length must be stated. If this length is exceeded
134
- # a DatabaseError (truncation) will be raised.
135
- #
136
- def do_bind!(prep_stmt, param, bindvar, i, bound)
137
- # Get the direction
138
- orig_direction = param.get_direction;
139
-
140
- # Bind INPUT
141
- if orig_direction == INPUT_ONLY or orig_direction == INPUT_OUTPUT
142
- param.set_direction(INPUT_ONLY)
143
- # Obtain the value out of the hash if neccessary
144
- if bindvar.class == Hash
145
- raise DBI::ProgrammingError.new("Parameter hash must contain :value key") if !bindvar.has_key?(:value)
146
- param.set_value(bindvar[:value])
147
- else
148
- param.set_value(bindvar)
149
- end
150
- raise error() if SA.instance.api.sqlany_bind_param(prep_stmt, i, param) == 0
151
- end
152
-
153
- # Bind OUTPUT
154
- if orig_direction == OUTPUT_ONLY or orig_direction == INPUT_OUTPUT
155
- param.set_direction(OUTPUT_ONLY)
156
- # Add the +::name+ to the +bound+ hash so its output value can be retrieved later
157
- raise DBI::ProgrammingError.new("Parameter hash must contain :name key") if !bindvar.has_key?(:name)
158
- bound[bindvar[:name]] = i if !bound.nil?
159
- # set the buffer length if appropriate
160
- if bindvar.has_key?(:length)
161
- param.set_buffer_size(bindvar[:length])
162
- end
163
- # +set_value+ sets up the receiveing buffer
164
- param.set_value(nil)
165
- raise error() if SA.instance.api.sqlany_bind_param(prep_stmt, i, param) == 0
166
- end
167
- end
168
- end
169
-
170
- end # module SQLAnywhere
171
- end # module DBD
172
- end # module DBI
173
-
174
- require 'dbd/sqlanywhere/driver'
175
- require 'dbd/sqlanywhere/database'
176
- require 'dbd/sqlanywhere/statement'
1
+ #====================================================
2
+ #
3
+ # Copyright 2012 iAnywhere Solutions, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ #
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ # While not a requirement of the license, if you do modify this file, we
20
+ # would appreciate hearing about it. Please email sqlany_interfaces@sybase.com
21
+ #
22
+ #
23
+ #====================================================
24
+
25
+ begin
26
+ require 'rubygems'
27
+ gem 'sqlanywhere'
28
+ gem 'dbi'
29
+ rescue LoadError => e
30
+ end
31
+
32
+ require 'dbi'
33
+ require 'dbi/typeutil'
34
+ require 'sqlanywhere'
35
+ require 'singleton'
36
+
37
+ module DBI
38
+ module DBD
39
+ module SQLAnywhere
40
+
41
+ VERSION = "1.0.0"
42
+
43
+ def self.driver_name
44
+ "SQLAnywhere"
45
+ end
46
+
47
+ class SA
48
+ include Singleton
49
+ attr_accessor :api
50
+
51
+ def initialize
52
+ unless defined? SQLAnywhere
53
+ require 'sqlanywhere'
54
+ end
55
+
56
+ @api = ::SQLAnywhere::SQLAnywhereInterface.new()
57
+ result = ::SQLAnywhere::API.sqlany_initialize_interface( @api )
58
+ if result == 0
59
+ raise LoadError, "Could not load SQLAnywhere DLL"
60
+ end
61
+ result = @api.sqlany_init()
62
+ if result == 0
63
+ raise LoadError, "Could not initialize SQLAnywhere DLL"
64
+ end
65
+ end
66
+
67
+ def free_api
68
+ ::SQLAnywhere::API.sqlany_finalize_interface( @api );
69
+ @api = nil
70
+ end
71
+ end
72
+
73
+
74
+ DBI::TypeUtil.register_conversion(driver_name) do |obj|
75
+ case obj
76
+ when DBI::Binary # these need to be handled specially by the driver
77
+ obj.to_s
78
+ when ::NilClass
79
+ nil
80
+ when ::TrueClass
81
+ 1
82
+ when ::FalseClass
83
+ 0
84
+ when ::Time
85
+ obj.strftime("%H:%M:%S")
86
+ when ::Date
87
+ obj.strftime("%Y/%m/%d")
88
+ when ::DateTime, DBI::Timestamp
89
+ DateTime.parse(obj.to_s).strftime("%Y/%m/%d %H:%M:%S")
90
+ when ::String
91
+ obj
92
+ when ::BigDecimal
93
+ obj.to_s("F")
94
+ when ::Numeric
95
+ obj.to_s
96
+ else
97
+ obj
98
+ end
99
+ end
100
+
101
+
102
+ # This module provides functionality that is used by all the DBD classes
103
+ module Utility
104
+
105
+ NO_DIRECTION = 0
106
+ INPUT_ONLY = 1
107
+ OUTPUT_ONLY = 2
108
+ INPUT_OUTPUT = 3
109
+
110
+ # do_bind takes the following arguments:
111
+ # * +prep_stmt+ : a handle the prepared Statement object
112
+ # * +param+ : the parameter to bound, obtained by sqlany_describe_bind_param
113
+ # * +bindvar+ : the actual value to bind the the parameter. Can be a +VALUE+, or a +HASH+.
114
+ # * +i+ : the parameter number to bind. Should be the same as used in sqlany_describe_bind_param
115
+ # * +bound+ : hash used to track INOUT, and OUT parameters
116
+ #
117
+ # +IN+ parameters will be bound once with +INPUT_ONLY+.
118
+ # +OUT+ parameters will be bound once with +OUTPUT_ONLY+.
119
+ # +INOUT+ parameters will be be bound twice, once as +INPUT_ONLY+, and once as +OUTPUT_ONLY+. +INOUT+ parameters
120
+ # will use *different* buffers to pass the input and output values to the DLL.
121
+ #
122
+ # If the parameter to be bound is +INPUT_ONLY+, +bindvar+ *must* be a regular value type such as
123
+ # Bignum, Fixnum, String, etc. This value will be bound to the input parameter
124
+ #
125
+ # If the parameter to be bound is +OUTPUT_ONLY+, +bindvar+ *must* be a hash with keys:
126
+ # ::name => This is the name that you will be used later to retrieve the output value
127
+ # ::length => If the output will be a string or binary, the expected length must be stated. If this length is exceeded
128
+ # a DatabaseError (truncation) will be raised.
129
+ #
130
+ # If the parameter to be bound is +INPUT_OUTPUT+, +bindvar+ *must* be a hash with keys:
131
+ # ::name => This is the name that you will be used later to retrieve the output value
132
+ # ::value => The value to bind to the input.
133
+ # ::length => If the output will be a string or binary, the expected length must be stated. If this length is exceeded
134
+ # a DatabaseError (truncation) will be raised.
135
+ #
136
+ def do_bind!(prep_stmt, param, bindvar, i, bound)
137
+ # Get the direction
138
+ orig_direction = param.get_direction;
139
+
140
+ # Bind INPUT
141
+ if orig_direction == INPUT_ONLY or orig_direction == INPUT_OUTPUT
142
+ param.set_direction(INPUT_ONLY)
143
+ # Obtain the value out of the hash if neccessary
144
+ if bindvar.class == Hash
145
+ raise DBI::ProgrammingError.new("Parameter hash must contain :value key") if !bindvar.has_key?(:value)
146
+ param.set_value(bindvar[:value])
147
+ else
148
+ param.set_value(bindvar)
149
+ end
150
+ raise error() if SA.instance.api.sqlany_bind_param(prep_stmt, i, param) == 0
151
+ end
152
+
153
+ # Bind OUTPUT
154
+ if orig_direction == OUTPUT_ONLY or orig_direction == INPUT_OUTPUT
155
+ param.set_direction(OUTPUT_ONLY)
156
+ # Add the +::name+ to the +bound+ hash so its output value can be retrieved later
157
+ raise DBI::ProgrammingError.new("Parameter hash must contain :name key") if !bindvar.has_key?(:name)
158
+ bound[bindvar[:name]] = i if !bound.nil?
159
+ # set the buffer length if appropriate
160
+ if bindvar.has_key?(:length)
161
+ param.set_buffer_size(bindvar[:length])
162
+ end
163
+ # +set_value+ sets up the receiveing buffer
164
+ param.set_value(nil)
165
+ raise error() if SA.instance.api.sqlany_bind_param(prep_stmt, i, param) == 0
166
+ end
167
+ end
168
+ end
169
+
170
+ end # module SQLAnywhere
171
+ end # module DBD
172
+ end # module DBI
173
+
174
+ require 'dbd/sqlanywhere/driver'
175
+ require 'dbd/sqlanywhere/database'
176
+ require 'dbd/sqlanywhere/statement'