dbd-sqlanywhere 0.1.2 → 1.0.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.
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'