dbgeni 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +29 -0
  3. data/bin/dbgeni +2 -0
  4. data/lib/dbgeni/base.rb +146 -0
  5. data/lib/dbgeni/base_code.rb +143 -0
  6. data/lib/dbgeni/blank_slate.rb +24 -0
  7. data/lib/dbgeni/cli.rb +96 -0
  8. data/lib/dbgeni/code.rb +235 -0
  9. data/lib/dbgeni/code_list.rb +60 -0
  10. data/lib/dbgeni/commands/code.rb +151 -0
  11. data/lib/dbgeni/commands/commands.rb +41 -0
  12. data/lib/dbgeni/commands/config.rb +36 -0
  13. data/lib/dbgeni/commands/dmls.rb +244 -0
  14. data/lib/dbgeni/commands/generate.rb +257 -0
  15. data/lib/dbgeni/commands/initialize.rb +41 -0
  16. data/lib/dbgeni/commands/migrations.rb +243 -0
  17. data/lib/dbgeni/commands/milestones.rb +52 -0
  18. data/lib/dbgeni/commands/new.rb +178 -0
  19. data/lib/dbgeni/config.rb +325 -0
  20. data/lib/dbgeni/connectors/connector.rb +59 -0
  21. data/lib/dbgeni/connectors/mysql.rb +146 -0
  22. data/lib/dbgeni/connectors/oracle.rb +149 -0
  23. data/lib/dbgeni/connectors/sqlite.rb +166 -0
  24. data/lib/dbgeni/connectors/sybase.rb +97 -0
  25. data/lib/dbgeni/dml_cli.rb +35 -0
  26. data/lib/dbgeni/environment.rb +161 -0
  27. data/lib/dbgeni/exceptions/exception.rb +69 -0
  28. data/lib/dbgeni/file_converter.rb +44 -0
  29. data/lib/dbgeni/initializers/initializer.rb +44 -0
  30. data/lib/dbgeni/initializers/mysql.rb +36 -0
  31. data/lib/dbgeni/initializers/oracle.rb +38 -0
  32. data/lib/dbgeni/initializers/sqlite.rb +33 -0
  33. data/lib/dbgeni/initializers/sybase.rb +34 -0
  34. data/lib/dbgeni/logger.rb +60 -0
  35. data/lib/dbgeni/migration.rb +302 -0
  36. data/lib/dbgeni/migration_cli.rb +204 -0
  37. data/lib/dbgeni/migration_list.rb +91 -0
  38. data/lib/dbgeni/migrators/migrator.rb +40 -0
  39. data/lib/dbgeni/migrators/migrator_interface.rb +51 -0
  40. data/lib/dbgeni/migrators/mysql.rb +82 -0
  41. data/lib/dbgeni/migrators/oracle.rb +211 -0
  42. data/lib/dbgeni/migrators/sqlite.rb +90 -0
  43. data/lib/dbgeni/migrators/sybase.rb +118 -0
  44. data/lib/dbgeni/plugin.rb +92 -0
  45. data/lib/dbgeni.rb +52 -0
  46. metadata +87 -0
@@ -0,0 +1,178 @@
1
+ # Expects only one parameter, the directory of the new dbgeni directory structure
2
+
3
+ ARGV << '--help' if ARGV.empty?
4
+
5
+ if ARGV.length > 1 or %w(-h --help).include? ARGV[0]
6
+ puts "Error: only one parameter is allowed for the new command" if ARGV.length > 1
7
+ puts <<-EOF
8
+ Usage: dbgeni new <path/to/directory/for/new/installer/structure>
9
+ EOF
10
+ exit
11
+ end
12
+
13
+ require 'fileutils'
14
+
15
+ directory = ARGV.shift
16
+
17
+ # There can be two commands here - first is to create the directory
18
+ # structure, the second is new-conf to just create the file, but only if
19
+ # the directory exists.
20
+ if %w(n new).include? $initial_command
21
+ if File.directory?(directory)
22
+ puts "Error: The directory already exists"
23
+ exit(1)
24
+ end
25
+
26
+ # create the base directory
27
+ begin
28
+ puts "creating directory: #{directory}"
29
+ FileUtils.mkdir_p(directory)
30
+ rescue Exception => e
31
+ puts "error: failed to create #{directory} - #{e.to_s}"
32
+ exit(1)
33
+ end
34
+
35
+ # create the directory to hold migrations
36
+ begin
37
+ puts "creating directory: #{directory}/migrations"
38
+ FileUtils.mkdir_p(directory+'/migrations')
39
+ rescue Exception => e
40
+ puts "error: failed to create #{directory}/migrations - #{e.to_s}"
41
+ exit(1)
42
+ end
43
+ # create the directory to hold code
44
+ begin
45
+ puts "creating directory: #{directory}/code"
46
+ FileUtils.mkdir_p(directory+'/code')
47
+ rescue Exception => e
48
+ puts "error: failed to create #{directory}/code - #{e.to_s}"
49
+ exit(1)
50
+ end
51
+
52
+ # create the directory to hold dml
53
+ begin
54
+ puts "creating directory: #{directory}/dml"
55
+ FileUtils.mkdir_p(directory+'/dml')
56
+ rescue Exception => e
57
+ puts "error: failed to create #{directory}/dml - #{e.to_s}"
58
+ exit(1)
59
+ end
60
+
61
+ else
62
+ unless File.directory?(directory)
63
+ puts "Error: The directory #{directory} does not exist"
64
+ exit(1)
65
+ end
66
+ end
67
+
68
+
69
+ # Create the initial version of the configuration file
70
+ begin
71
+ puts "creating file: #{directory}/.dbgeni"
72
+ conf = File.open("#{directory}/.dbgeni", "w")
73
+ conf.puts <<-EOF
74
+
75
+ # This directory specifies the location of the migrations directory
76
+ migrations_directory "./migrations"
77
+
78
+ # This directory specifies the location of the DML files directory
79
+ dml_directory "./dml"
80
+
81
+ # This directory specifies the location of any code modules
82
+ code_directory "./code"
83
+
84
+ # This specifes the location of the plugin directory. Specifying this parameter
85
+ # enables plugins and the directory must exist
86
+ # plugin_directory "./dbgeni_plugins"
87
+
88
+ # This specifies the type of database this installer is applied against
89
+ # Valid values are oracle, mysql, sqlite, sybase however this is not validated
90
+ # to enable different database plugins to easily be added.
91
+ database_type "sqlite"
92
+
93
+ # This is the table the installer logs applied migrations in the database
94
+ # The default is dbgeni_migrations
95
+ database_table "dbgeni_migrations"
96
+
97
+ # Use the include_file option to load another config file, perhaps
98
+ # containing environment details for many different environments in one place
99
+ #
100
+ # include_file '/path/to/include/file'
101
+
102
+
103
+ # Environment Section
104
+ #
105
+ # There must be at least one environment, and at a minimum each environment
106
+ # should define a username, database and password (except sqlite which only
107
+ # requires a database to be specified)
108
+ #
109
+ # Typically there will be more than one enviroment block detailling development,
110
+ # test and production but any number of environments are valid provided there is at least one.
111
+ #
112
+ # The environments can be defined here or in an included file.
113
+
114
+ # Defaults - this section is optional and can be used to define parameters that must
115
+ # appear in every environment, for example install_schema. If a parameter is defined
116
+ # here, and also defined in the environment, then the value in the environment block
117
+ # will override the default. If many default blocks are specified, in included files
118
+ # for example, the parameters are merged. If any parameters are duplicated, the last to
119
+ # be loaded will used.
120
+ #
121
+ # defaults {
122
+ # username 'scott'
123
+ # }
124
+
125
+ environment('development') {
126
+
127
+ ### SQLITE
128
+ database 'testdb.sqlite' # This is the only required connection parameter for sqlite
129
+
130
+ ### ORACLE
131
+ #
132
+ # database 'DEV1' # This is the name of an entry in the tns_names.ora file
133
+ # username 'scott' # This is the username to connect as, and also the default schema
134
+ # password 'tiger' # This is the password for the username
135
+ #
136
+ # install_schema 'other' # Optional: If dbgeni connects as a database user, but the application is owned
137
+ # by another user, set the application schema here
138
+
139
+ ### MYSQL
140
+ #
141
+ # database 'DEV1' # This is the database to use after connection
142
+ # username 'scott' # This is the username to connect as
143
+ # password 'tiger' # This is the password for the username
144
+ # hostname '127.0.0.1' # This is the hostname or IP mysql is running on
145
+ # For localhost use the IP 127.0.0.1 or it will not work.
146
+ # port '3306' # This the port of the mysql service
147
+
148
+ ### SYBASE
149
+ #
150
+ # database 'DEV1' # This is the database to use after connection
151
+ # username 'scott' # This is the username to connect as
152
+ # password 'tiger' # This is the password for the username
153
+ # hostname '127.0.0.1' # This is the hostname or IP sybase is running on
154
+ # port '3306' # This the port of the sybase service
155
+ # sybase_service 'dev1' # THis is the sybase service name defined in the sql.ini file
156
+
157
+
158
+ # Other parameters can be defined here to be used as replacement parameters in scripts
159
+ # or in plugins in future versions of dbgeni.
160
+ # param_name 'value'
161
+ }
162
+
163
+ #
164
+ # environment('test') {
165
+ # username 'user'
166
+ # database 'TEST.WORLD'
167
+ # password ''
168
+ # }
169
+ #
170
+
171
+
172
+ EOF
173
+ rescue Exception => e
174
+ puts "error: failed to create #{directory}/.dbgeni - #{e.to_s}"
175
+ exit(1)
176
+ end
177
+
178
+ exit(0)
@@ -0,0 +1,325 @@
1
+ module DBGeni
2
+
3
+ # Config understands the following:
4
+
5
+ # migrations_directory 'value' # This will be checked to ensure its a valid dir
6
+ # # and defaults to 'migrations'
7
+ # environment('development') {
8
+ # username 'user' # this must be here, or it will error
9
+ # database 'MYDB.WORLD' # this must be here, or it will error. For Oracle, this is the TNS Name
10
+ # password '' # If this value is missing, it will be promoted for if the env is used.
11
+ # }
12
+ #
13
+ # environment('other environment') {
14
+ # username '' # the environment block can be repeated for many environments
15
+ # }
16
+ #
17
+ # global_parameters { # These are common parameters to all environments, but they can be
18
+ # # overriden. Basically take global, merge in environment
19
+ # param_name 'value'
20
+ # }
21
+
22
+ class Config
23
+ attr_reader :environments
24
+ attr_reader :current_environment
25
+ attr_reader :migration_directory
26
+ attr_reader :dml_directory
27
+ # ideally wnat code_dir to be code_directory, but then it clashes with the
28
+ # setter used in the config file, so need to change it. Probably more sensible
29
+ # like this than the migrations_directory vs migration_directory
30
+ # _-_
31
+ #
32
+ attr_reader :code_dir
33
+ attr_reader :db_type # oracle, mysql, sqlite etc, default sqlite
34
+ attr_reader :db_table # defaults to dbgeni_migrations
35
+ attr_reader :config_file
36
+ attr_reader :base_directory
37
+
38
+ DEFAULTS_ENV = '__defaults__'
39
+
40
+
41
+ def initialize
42
+ @migration_directory = 'migrations'
43
+ @dml_directory = 'dml'
44
+ @code_dir = 'code'
45
+ @plugin_dir = nil
46
+ @db_type = 'sqlite'
47
+ @db_table = 'dbgeni_migrations'
48
+ @base_dir = '.'
49
+ @environments = Hash.new
50
+ end
51
+
52
+
53
+ def self.load_from_file(filename)
54
+ cfg = self.new
55
+ cfg.load_from_file(filename)
56
+ end
57
+
58
+
59
+ def load_from_file(filename)
60
+ if filename == nil
61
+ raise DBGeni::ConfigFileNotSpecified
62
+ end
63
+ raw_config = ''
64
+ self.base_directory = File.expand_path(File.dirname(filename))
65
+ @config_file = File.expand_path(filename)
66
+ begin
67
+ File.open(@config_file) do |f|
68
+ raw_config = f.read
69
+ end
70
+ rescue Errno::ENOENT
71
+ raise DBGeni::ConfigFileNotExist, "#{@config_location} (expanded from #{filename}) does not exist"
72
+ end
73
+ load(raw_config)
74
+ end
75
+
76
+
77
+ # Normally this is assumed to be the location the config file is in.
78
+ # All relative file operations come from this directory
79
+ def base_directory=(dir)
80
+ @base_directory = dir
81
+ # If change the base directory, then unless migration dir is
82
+ # an absolute path, it will need to change too.
83
+ @migration_directory = File.join(@base_directory, @migration_directory) unless is_absolute_path?(@migration_directory)
84
+ @dml_directory = File.join(@base_directory, @dml_directory) unless is_absolute_path?(@dml_directory)
85
+ @code_dir = File.join(@base_directory, @code_dir) unless is_absolute_path?(@code_dir)
86
+ if @plugin_dir
87
+ @plugin_dir = File.join(@base_directory, @plugin_dir) unless is_absolute_path?(@plugin_dir)
88
+ end
89
+ end
90
+
91
+
92
+ # def get_environment(name)
93
+ # if name == nil
94
+ # # if there is only a single environment defined, then return it
95
+ # if @environments.keys.length == 1
96
+ # @environments[@environments.keys.first]
97
+ # else
98
+ # raise DBGeni::ConfigAmbiguousEnvironment, "More than one environment is defined"
99
+ # end
100
+ # else
101
+ # unless @environments.has_key?(name)
102
+ # raise DBGeni::EnvironmentNotExist
103
+ # end
104
+ # @environments[name]
105
+ # end
106
+ # end
107
+
108
+
109
+ def env
110
+ current_env
111
+ end
112
+
113
+
114
+ def current_env
115
+ if @current_environment
116
+ @environments[@current_environment]
117
+ elsif @environments.keys.reject{|i| i == DEFAULTS_ENV}.length == 1
118
+ @environments[@environments.keys.reject{|i| i == DEFAULTS_ENV}.first]
119
+ else
120
+ raise DBGeni::ConfigAmbiguousEnvironment, "More than one environment is defined"
121
+ end
122
+ end
123
+
124
+
125
+ def set_env(name=nil)
126
+ if name == nil
127
+ valid_envs = @environments.keys.reject{|i| i == DEFAULTS_ENV}
128
+ if valid_envs.length == 1
129
+ @current_environment = valid_envs.first
130
+ else
131
+ raise DBGeni::ConfigAmbiguousEnvironment, "More than one environment is defined"
132
+ end
133
+ elsif @environments.has_key?(name)
134
+ @current_environment = name
135
+ else
136
+ raise DBGeni::EnvironmentNotExist
137
+ end
138
+ end
139
+
140
+
141
+ def load(raw_config, recursed=false)
142
+ begin
143
+ self.instance_eval(raw_config)
144
+ rescue Exception => e
145
+ raise DBGeni::ConfigSyntaxError, e.to_s
146
+ end
147
+ merge_defaults unless recursed
148
+ self
149
+ end
150
+
151
+ def merge_defaults
152
+ if @environments.has_key? DEFAULTS_ENV
153
+ @environments.keys.each do |k|
154
+ next if k == DEFAULTS_ENV
155
+ @environments[k].__merge_defaults(@environments[DEFAULTS_ENV].__params)
156
+ end
157
+ end
158
+ end
159
+
160
+ def to_s
161
+ str = ''
162
+ str << "migrations_directory => #{@migration_directory}\n"
163
+ @environments.keys.sort.each do |k|
164
+ str << "\n\nEnvironment: #{k}\n"
165
+ str << "=============#{(1..k.length).map do "=" end.join}\n\n"
166
+ str << @environments[k].__to_s
167
+ end
168
+ str
169
+ end
170
+
171
+ ######################################
172
+ # Methods below here are for the DSL #
173
+ ######################################
174
+
175
+ # mig_dir could be defined as a file in current directory 'migrations'
176
+ # or it could be a relative directory './somedir/migrations'
177
+ # or it could be a full path '/somedir/migrations' or in windows 'C:\somedir\migrations'
178
+ # To use the migrations it needs to be expanded to a full path *somehow*.
179
+ # If it begins / or <LETTER>:\ then assume its full path, otherwise concatenate
180
+ # to the full path of the config file.
181
+ def migrations_directory(*p)
182
+ if p.length == 0
183
+ @migration_directory
184
+ else
185
+ if is_absolute_path?(p[0])
186
+ # it looks like an absolute path
187
+ @migration_directory = p[0]
188
+ else
189
+ # it looks like a relative path
190
+ if @base_directory
191
+ @migration_directory = File.join(@base_directory, p[0])
192
+ else
193
+ @migration_directory = p[0]
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ def dml_directory(*p)
200
+ if p.length == 0
201
+ @dml_directory
202
+ else
203
+ if is_absolute_path?(p[0])
204
+ # it looks like an absolute path
205
+ @dml_directory = p[0]
206
+ else
207
+ # it looks like a relative path
208
+ if @base_directory
209
+ @dml_directory = File.join(@base_directory, p[0])
210
+ else
211
+ @dml_directory = p[0]
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ def code_directory(*p)
218
+ if p.length == 0
219
+ @code_dir
220
+ else
221
+ if is_absolute_path?(p[0])
222
+ # it looks like an absolute path
223
+ @code_dir = p[0]
224
+ else
225
+ # it looks like a relative path
226
+ if @base_directory
227
+ @code_dir = File.join(@base_directory, p[0])
228
+ else
229
+ @code_dir = p[0]
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+ def plugin_directory(*p)
236
+ if p.length == 0
237
+ @plugin_dir
238
+ else
239
+ if is_absolute_path?(p[0])
240
+ # it looks like an absolute path
241
+ @plugin_dir = p[0]
242
+ else
243
+ # it looks like a relative path
244
+ if @base_directory
245
+ @plugin_dir = File.join(@base_directory, p[0])
246
+ else
247
+ @plugin_dir = p[0]
248
+ end
249
+ end
250
+ end
251
+ end
252
+
253
+
254
+ def database_type(*p)
255
+ # TODO - consider putting validation here
256
+ @db_type = p[0]
257
+ end
258
+
259
+ def database_table(*p)
260
+ # TODO - consider putting validation here
261
+ @db_table = p[0]
262
+ end
263
+
264
+ # For some reason I cannot work out, this method is never getting
265
+ # call in the evaluated block. Ideally wanted to have migrations_directory
266
+ # and migrations_directory= so that it doesn't matter which is called.
267
+ # def migrations_directory=(value)
268
+ # puts "called the equals one"
269
+ # @migration_directory = value
270
+ # end
271
+
272
+
273
+ # Given a block of environment details, generate a new environment
274
+ # object. eg
275
+ # environment('some_name') do
276
+ # database ''
277
+ # user ''
278
+ # password prompt
279
+ #
280
+ # some_dir_path '/path_to_directory'
281
+ def environment(name, &block)
282
+ env = Environment.new(name)
283
+ block.arity < 1 ? env.instance_eval(&block) : block.call(env)
284
+ env.__completed_loading
285
+ if @environments.has_key?(name)
286
+ @environments[name].__merge_environment(env)
287
+ else
288
+ @environments[name] = env
289
+ end
290
+ end
291
+
292
+ def defaults(&block)
293
+ environment(DEFAULTS_ENV, &block)
294
+ end
295
+
296
+
297
+ def include_file(*p)
298
+ file = p[0]
299
+ if !is_absolute_path?(file)
300
+ file = File.join(@base_directory, file)
301
+ end
302
+ begin
303
+ raw_config = ''
304
+ File.open(file) do |f|
305
+ raw_config = f.read
306
+ end
307
+ self.load(raw_config)
308
+ rescue Errno::ENOENT
309
+ raise DBGeni::ConfigFileNotExist, "Included config #{file} does not exist"
310
+ rescue DBGeni::ConfigSyntaxError
311
+ raise DBGeni::ConfigSyntaxError, "Included config #{file} contains errors: #{e.to_s}"
312
+ end
313
+ end
314
+
315
+ private
316
+
317
+ def is_absolute_path?(path)
318
+ if path =~ /^\/|[a-zA-Z]:\\/
319
+ true
320
+ else
321
+ false
322
+ end
323
+ end
324
+ end
325
+ end
@@ -0,0 +1,59 @@
1
+ module DBGeni
2
+
3
+ module Connector
4
+
5
+ def self.initialize(config)
6
+ required_class = setup(config.db_type)
7
+ conn = nil
8
+ begin
9
+ required_method = required_class.method("connect")
10
+ rescue NameError
11
+ raise DBGeni::InvalidConnectorForDBType, config.db_type
12
+ end
13
+ if config.db_type == 'sqlite' or (config.db_type == 'oracle' and RUBY_PLATFORM != 'java')
14
+ # don't need a host or port here, so make this a seperate call block
15
+ conn = required_method.call(config.env.username,
16
+ # SQLITE doesn't need a password, so prevent asking for it
17
+ # or it may be promoted for
18
+ config.db_type == 'sqlite' ? '' : config.env.password,
19
+ config.env.database)
20
+ else
21
+ conn = required_method.call(config.env.username,
22
+ config.env.password,
23
+ config.env.database,
24
+ config.env.hostname,
25
+ config.env.port)
26
+ end
27
+ if config.db_type == 'oracle'
28
+ if config.env.install_schema
29
+ if config.env.username != config.env.install_schema
30
+ conn.execute("alter session set current_schema=#{config.env.install_schema}")
31
+ end
32
+ end
33
+ end
34
+ conn
35
+ end
36
+
37
+ private
38
+
39
+ def self.setup(db_type)
40
+ begin
41
+ require "dbgeni/connectors/#{db_type}"
42
+ rescue Exception => e
43
+ puts "Error requiring connector: #{e.to_s}"
44
+ raise DBGeni::NoConnectorForDBType, db_type
45
+ end
46
+
47
+ required_class = nil
48
+ if Connector.const_defined?(db_type.capitalize)
49
+ required_class = Connector.const_get(db_type.capitalize)
50
+ else
51
+ raise DBGeni::NoConnectorForDBType, db_type
52
+ end
53
+ required_class
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
@@ -0,0 +1,146 @@
1
+ module DBGeni
2
+
3
+ module Connector
4
+
5
+ class Mysql
6
+ if RUBY_PLATFORM == 'java'
7
+ require 'java'
8
+ java_import 'com.mysql.jdbc.Driver'
9
+ java_import 'java.sql.DriverManager'
10
+ else
11
+ require 'mysql'
12
+ end
13
+
14
+ attr_reader :connection
15
+ attr_reader :database
16
+
17
+ def self.connect(user, password, database, host, port)
18
+ self.new(user, password, database, host, port=nil)
19
+ end
20
+
21
+ def disconnect
22
+ @connection.close
23
+ end
24
+
25
+ def execute(sql, *binds)
26
+ if RUBY_PLATFORM == 'java'
27
+ execute_jdbc(sql, *binds)
28
+ else
29
+ execute_native(sql, *binds)
30
+ end
31
+ end
32
+
33
+
34
+ def ping
35
+ results = self.execute('select 1 + 1 from dual')
36
+ if results.length == 1
37
+ true
38
+ else
39
+
40
+ false
41
+ end
42
+ end
43
+
44
+ def commit
45
+ @connection.commit
46
+ end
47
+
48
+ def rollback
49
+ @connection.rollback
50
+ end
51
+
52
+ def date_placeholder(bind_var)
53
+ "?" # ":#{bind_var}"
54
+ end
55
+
56
+ def date_as_string(dtm)
57
+ dtm.strftime '%Y-%m-%d %H:%M:%S'
58
+ end
59
+
60
+ private
61
+
62
+ def initialize(user, password, database, host, port=3306)
63
+ @database = database
64
+ begin
65
+ if RUBY_PLATFORM == 'java'
66
+ @connection = DriverManager.get_connection("jdbc:mysql://#{host}:#{port||3306}/#{database}", user, password)
67
+ else
68
+ @connection = ::Mysql.connect(host, user, password, database, port)
69
+ end
70
+ rescue Exception => e
71
+ raise DBGeni::DBConnectionError, e.to_s
72
+ end
73
+ end
74
+
75
+ def execute_native(sql, *binds)
76
+ # strange exception handling here. If you issue a select, the fetch works fine.
77
+ # However, something like create table blows up when fetch is called with noMethodError
78
+ # so it is being caught and thrown away ... hackish, but the mysql drive seems to be
79
+ # at fault, is badly documented and seems to be a bit rubbish. Ideall uses DBD::Mysql + DBI.
80
+
81
+ results = Array.new
82
+ if sql =~ /^drop\s+(procedure|function|trigger|table)/i
83
+ # cannot prepare these statements, need to just execute
84
+ @connection.query(sql)
85
+ return results
86
+ end
87
+
88
+ begin
89
+ query = @connection.prepare(sql)
90
+ query.execute(*binds)
91
+
92
+ results = Array.new
93
+ if query.num_rows > 0
94
+ while r = query.fetch()
95
+ results.push r
96
+ end
97
+ end
98
+ # everthing is auto commit right now ...
99
+ @connection.commit
100
+ rescue NoMethodError
101
+ ensure
102
+ begin
103
+ query.close()
104
+ rescue
105
+ end
106
+ end
107
+ results
108
+ end
109
+
110
+ def execute_jdbc(sql, *binds)
111
+ begin
112
+ query = @connection.prepare_statement(sql)
113
+ binds.each_with_index do |b, i|
114
+ if b.is_a?(String)
115
+ query.setString(i+1, b)
116
+ elsif b.is_a?(Fixnum)
117
+ query.setInt(i+1, b)
118
+ end
119
+ end
120
+ results = Array.new
121
+ unless sql =~ /^\s*(select|show)/i
122
+ query.execute()
123
+ else
124
+ rset = query.execute_query()
125
+ cols = rset.get_meta_data.get_column_count
126
+ while(r = rset.next) do
127
+ a = Array.new
128
+ 1.upto(cols) do |i|
129
+ a.push rset.get_object(i)
130
+ end
131
+ results.push a
132
+ end
133
+ end
134
+ results
135
+ ensure
136
+ begin
137
+ query.close
138
+ rescue Exception => e
139
+ end
140
+ end
141
+ end
142
+
143
+ end
144
+ end
145
+ end
146
+