do_mysql-0.10.17/0000755000004100000410000000000013305246414013541 5ustar www-datawww-datado_mysql-0.10.17/tasks/0000755000004100000410000000000013305246414014666 5ustar www-datawww-datado_mysql-0.10.17/tasks/compile.rake0000644000004100000410000000461613305246414017171 0ustar www-datawww-databegin gem 'rake-compiler', '~>0.7' require 'rake/extensiontask' require 'rake/javaextensiontask' def gemspec @clean_gemspec ||= Gem::Specification::load(File.expand_path('../../do_mysql.gemspec', __FILE__)) end unless JRUBY Rake::ExtensionTask.new('do_mysql', gemspec) do |ext| ext.lib_dir = "lib/#{gemspec.name}" mysql_lib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'vendor', "mysql-#{BINARY_VERSION}-win32")) # automatically add build options to avoid need of manual input if RUBY_PLATFORM =~ /mswin|mingw/ then ext.config_options << "--with-mysql-include=#{mysql_lib}/include" ext.config_options << "--with-mysql-lib=#{mysql_lib}/lib/opt" else ext.cross_compile = true ext.cross_platform = ['x86-mingw32', 'x86-mswin32-60'] ext.cross_config_options << "--with-mysql-include=#{mysql_lib}/include" ext.cross_config_options << "--with-mysql-lib=#{mysql_lib}/lib/opt" ext.cross_compiling do |gemspec| gemspec.post_install_message = <<-POST_INSTALL_MESSAGE ====================================================================================================== You've installed the binary version of #{gemspec.name}. It was built using MySQL version #{BINARY_VERSION}. It's recommended to use the exact same version to avoid potential issues. At the time of building this gem, the necessary DLL files where available in the following download: http://dev.mysql.com/get/Downloads/MySQL-5.0/mysql-noinstall-#{BINARY_VERSION}-win32.zip/from/pick You can put the lib\\opt\\libmysql.dll available in this package in your Ruby bin directory, for example C:\\Ruby\\bin ====================================================================================================== POST_INSTALL_MESSAGE end end end end Rake::JavaExtensionTask.new('do_mysql', gemspec) do |ext| ext.lib_dir = "lib/#{gemspec.name}" ext.ext_dir = 'ext-java/src/main/java' ext.debug = ENV.has_key?('DO_JAVA_DEBUG') && ENV['DO_JAVA_DEBUG'] ext.classpath = '../do_jdbc/lib/do_jdbc_internal.jar' ext.java_compiling do |gem| gem.add_dependency 'jdbc-mysql', '>=5.0.4' gem.add_dependency 'do_jdbc', '0.10.17' end end rescue LoadError warn "To compile, install rake-compiler (gem install rake-compiler)" end do_mysql-0.10.17/tasks/spec.rake0000644000004100000410000000052713305246414016470 0ustar www-datawww-datarequire 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec => [:clean, :compile]) do |spec| spec.pattern = './spec/**/*_spec.rb' end RSpec::Core::RakeTask.new(:rcov => [:clean, :compile]) do |rcov| rcov.pattern = "./spec/**/*_spec.rb" rcov.rcov = true rcov.rcov_opts = File.read('spec/rcov.opts').split(/\s+/) end do_mysql-0.10.17/tasks/retrieve.rake0000644000004100000410000000445113305246414017363 0ustar www-datawww-databegin gem 'rake-compiler', '~>0.7' require 'rake/clean' require 'rake/extensioncompiler' # download mysql library and headers directory "vendor" # only on Windows or cross platform compilation def dlltool(dllname, deffile, libfile) # define if we are using GCC or not if Rake::ExtensionCompiler.mingw_gcc_executable then dir = File.dirname(Rake::ExtensionCompiler.mingw_gcc_executable) tool = case RUBY_PLATFORM when /mingw/ File.join(dir, 'dlltool.exe') when /linux|darwin/ File.join(dir, "#{Rake::ExtensionCompiler.mingw_host}-dlltool") end return "#{tool} --dllname #{dllname} --def #{deffile} --output-lib #{libfile}" else if RUBY_PLATFORM =~ /mswin/ then tool = 'lib.exe' else fail "Unsupported platform for cross-compilation (please, contribute some patches)." end return "#{tool} /DEF:#{deffile} /OUT:#{libfile}" end end file "vendor/mysql-noinstall-#{BINARY_VERSION}-win32.zip" => ['vendor'] do |t| base_version = BINARY_VERSION.gsub(/\.[0-9]+$/, '') url = "http://mysql.proserve.nl/Downloads/MySQL-#{base_version}/#{File.basename(t.name)}" when_writing "downloading #{t.name}" do cd File.dirname(t.name) do sh "wget -c #{url} || curl -L -C - -O #{url}" end end end file "vendor/mysql-#{BINARY_VERSION}-win32/include/mysql.h" => ["vendor/mysql-noinstall-#{BINARY_VERSION}-win32.zip"] do |t| full_file = File.expand_path(t.prerequisites.last) when_writing "creating #{t.name}" do cd "vendor" do sh "unzip #{full_file} mysql-#{BINARY_VERSION}-win32/bin/** mysql-#{BINARY_VERSION}-win32/include/** mysql-#{BINARY_VERSION}-win32/lib/**" end # update file timestamp to avoid Rake perform this extraction again. touch t.name end end # clobber vendored packages CLOBBER.include('vendor') # vendor:mysql task 'vendor:mysql' => ["vendor/mysql-#{BINARY_VERSION}-win32/include/mysql.h"] # hook into cross compilation vendored mysql dependency if RUBY_PLATFORM =~ /mingw|mswin/ then Rake::Task['compile'].prerequisites.unshift 'vendor:mysql' else if Rake::Task.tasks.map {|t| t.name }.include? 'cross' Rake::Task['cross'].prerequisites.unshift 'vendor:mysql' end end rescue LoadError end do_mysql-0.10.17/tasks/ssl.rake0000644000004100000410000000153513305246414016337 0ustar www-datawww-datanamespace :ssl do task :env do require ROOT.join('spec', 'spec_helper') end desc "Check test environment for SSL support." task :check => :env do ssl_supported, messages = DataObjectsSpecHelpers.test_environment_supports_ssl? if DataObjectsSpecHelpers.test_environment_supports_ssl? puts puts "** SSL successfully configured for the test environment **" else puts puts "** SSL is not configured for the test environment **" puts puts DataObjectsSpecHelpers.test_environment_ssl_config_errors.join("\n") puts fail "Run rake ssl:config for instructions on how to configure the test environment." end end desc "Provide instructions on how to configure SSL in your test environment." task :config => :env do puts DataObjectsSpecHelpers.test_environment_ssl_config end end do_mysql-0.10.17/tasks/release.rake0000644000004100000410000000075613305246414017162 0ustar www-datawww-datadesc 'Builds all gems (native, binaries for JRuby and Windows)' task :build_all do `rake clean` `rake build` `rake java gem` `rake cross native gem RUBY_CC_VERSION=1.8.7:1.9.3:2.0.0:2.1.8:2.2.4:2.3.0` end desc 'Release all gems (native, binaries for JRuby and Windows)' task :release_all => :build_all do Dir["pkg/do_mysql-#{DataObjects::Mysql::VERSION}*.gem"].each do |gem_path| command = "gem push #{gem_path}" puts "Executing #{command.inspect}:" sh command end end do_mysql-0.10.17/spec/0000755000004100000410000000000013305246414014473 5ustar www-datawww-datado_mysql-0.10.17/spec/encoding_spec.rb0000644000004100000410000000322213305246414017617 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper')) require 'data_objects/spec/shared/encoding_spec' describe DataObjects::Mysql::Connection do it_should_behave_like 'a driver supporting different encodings' it_should_behave_like 'returning correctly encoded strings for the default database encoding' it_should_behave_like 'returning correctly encoded strings for the default internal encoding' unless JRUBY unless JRUBY describe 'sets the character set through the URI' do before do @utf8mb4_connection = DataObjects::Connection.new("#{CONFIG.scheme}://#{CONFIG.user}:#{CONFIG.pass}@#{CONFIG.host}:#{CONFIG.port}#{CONFIG.database}?encoding=UTF-8-MB4") end after { @utf8mb4_connection.close } it { @utf8mb4_connection.character_set.should == 'UTF-8-MB4' } describe 'writing a multibyte String' do it 'should write a multibyte String' do @command = @utf8mb4_connection.create_command('INSERT INTO users_mb4 (name) VALUES(?)') expect { @command.execute_non_query("😀") }.not_to raise_error(DataObjects::DataError) end end describe 'reading a String' do before do @reader = @utf8mb4_connection.create_command("SELECT name FROM users_mb4").execute_reader @reader.next! @values = @reader.values end after do @reader.close end it 'should return UTF-8 encoded String' do @values.first.should be_kind_of(String) @values.first.encoding.name.should == 'UTF-8' @values.first.should == "😀" end end end end end do_mysql-0.10.17/spec/connection_spec.rb0000644000004100000410000000423113305246414020171 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper')) require 'data_objects/spec/shared/connection_spec' require 'cgi' describe DataObjects::Mysql::Connection do before :all do @driver = CONFIG.scheme @user = CONFIG.user @password = CONFIG.pass @host = CONFIG.host @port = CONFIG.port @database = CONFIG.database @ssl = CONFIG.ssl end it_should_behave_like 'a Connection' it_should_behave_like 'a Connection with authentication support' it_should_behave_like 'a Connection allowing default database' it_should_behave_like 'a Connection with JDBC URL support' if JRUBY it_should_behave_like 'a Connection with SSL support' unless JRUBY it_should_behave_like 'a Connection via JDNI' if JRUBY if DataObjectsSpecHelpers.test_environment_supports_ssl? describe 'connecting with SSL' do it 'should raise an error when passed ssl=true' do lambda { DataObjects::Connection.new("#{CONFIG.uri}?ssl=true") }. should raise_error(ArgumentError) end it 'should raise an error when passed a nonexistent client certificate' do lambda { DataObjects::Connection.new("#{CONFIG.uri}?ssl[client_cert]=nonexistent") }. should raise_error(ArgumentError) end it 'should raise an error when passed a nonexistent client key' do lambda { DataObjects::Connection.new("#{CONFIG.uri}?ssl[client_key]=nonexistent") }. should raise_error(ArgumentError) end it 'should raise an error when passed a nonexistent ca certificate' do lambda { DataObjects::Connection.new("#{CONFIG.uri}?ssl[ca_cert]=nonexistent") }. should raise_error(ArgumentError) end it 'should connect with a specified SSL cipher' do DataObjects::Connection.new("#{CONFIG.uri}?#{CONFIG.ssl}&ssl[cipher]=#{SSLHelpers::CONFIG.cipher}"). ssl_cipher.should == SSLHelpers::CONFIG.cipher end it 'should raise an error with an invalid SSL cipher' do lambda { DataObjects::Connection.new("#{CONFIG.uri}?#{CONFIG.ssl}&ssl[cipher]=invalid") }. should raise_error end end end end do_mysql-0.10.17/spec/command_spec.rb0000644000004100000410000000041613305246414017451 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper')) require 'data_objects/spec/shared/command_spec' describe DataObjects::Mysql::Command do it_should_behave_like 'a Command' it_should_behave_like 'a Command with async' end do_mysql-0.10.17/spec/spec_helper.rb0000644000004100000410000002013513305246414017312 0ustar www-datawww-data$TESTING=true JRUBY = RUBY_PLATFORM =~ /java/ require 'rubygems' require 'rspec' require 'date' require 'ostruct' require 'fileutils' require 'win32console' if RUBY_PLATFORM =~ /mingw|mswin/ driver_lib = File.expand_path('../../lib', __FILE__) $LOAD_PATH.unshift(driver_lib) unless $LOAD_PATH.include?(driver_lib) # Prepend data_objects/do_jdbc in the repository to the load path. # DO NOT USE installed gems, except when running the specs from gem. repo_root = File.expand_path('../../..', __FILE__) (['data_objects'] << ('do_jdbc' if JRUBY)).compact.each do |lib| lib_path = "#{repo_root}/#{lib}/lib" $LOAD_PATH.unshift(lib_path) if File.directory?(lib_path) && !$LOAD_PATH.include?(lib_path) end require 'data_objects' require 'data_objects/spec/setup' require 'data_objects/spec/lib/ssl' require 'data_objects/spec/lib/pending_helpers' require 'do_mysql' DataObjects::Mysql.logger = DataObjects::Logger.new(STDOUT, :off) at_exit { DataObjects.logger.flush } CONFIG = OpenStruct.new CONFIG.scheme = 'mysql' CONFIG.user = ENV['DO_MYSQL_USER'] || 'root' CONFIG.pass = ENV['DO_MYSQL_PASS'] || '' CONFIG.user_info = unless CONFIG.user == 'root' && CONFIG.pass.empty? "#{CONFIG.user}:#{CONFIG.pass}@" else '' end CONFIG.host = ENV['DO_MYSQL_HOST'] || 'localhost' CONFIG.port = ENV['DO_MYSQL_PORT'] || '3306' CONFIG.database = ENV['DO_MYSQL_DATABASE'] || '/do_test' CONFIG.ssl = SSLHelpers.query(:ca_cert, :client_cert, :client_key) CONFIG.driver = 'mysql' CONFIG.jdbc_driver = DataObjects::Mysql.const_get('JDBC_DRIVER') rescue nil CONFIG.uri = ENV["DO_MYSQL_SPEC_URI"] || "#{CONFIG.scheme}://#{CONFIG.user_info}#{CONFIG.host}:#{CONFIG.port}#{CONFIG.database}?zeroDateTimeBehavior=convertToNull" CONFIG.jdbc_uri = "jdbc:#{CONFIG.uri}" CONFIG.sleep = "SELECT sleep(1)" module DataObjectsSpecHelpers def setup_test_environment conn = DataObjects::Connection.new(CONFIG.uri) conn.create_command(<<-EOF).execute_non_query DROP TABLE IF EXISTS `invoices` EOF conn.create_command(<<-EOF).execute_non_query DROP TABLE IF EXISTS `users` EOF conn.create_command(<<-EOF).execute_non_query DROP TABLE IF EXISTS `users_mb4` EOF conn.create_command(<<-EOF).execute_non_query DROP TABLE IF EXISTS `stuff` EOF conn.create_command(<<-EOF).execute_non_query DROP TABLE IF EXISTS `widgets` EOF conn.create_command(<<-EOF).execute_non_query CREATE TABLE `users` ( `id` int(11) NOT NULL auto_increment, `name` varchar(200) default 'Billy' NULL, `fired_at` timestamp, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; EOF conn.create_command(<<-EOF).execute_non_query CREATE TABLE `users_mb4` ( `id` int(11) NOT NULL auto_increment, `name` varchar(200), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; EOF conn.create_command(<<-EOF).execute_non_query CREATE TABLE `invoices` ( `invoice_number` varchar(50) NOT NULL, PRIMARY KEY (`invoice_number`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; EOF conn.create_command(<<-EOF).execute_non_query CREATE TABLE `stuff` ( `id` bigint NOT NULL auto_increment, `value` varchar(50) NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; EOF conn.create_command(<<-EOF).execute_non_query CREATE TABLE `widgets` ( `id` int(11) NOT NULL auto_increment, `code` char(8) default 'A14' NULL, `name` varchar(200) default 'Super Widget' NULL, `shelf_location` tinytext NULL, `description` text NULL, `image_data` blob NULL, `ad_description` mediumtext NULL, `ad_image` mediumblob NULL, `whitepaper_text` longtext NULL, `cad_drawing` longblob NULL, `flags` boolean default false, `number_in_stock` smallint default 500, `number_sold` mediumint default 0, `super_number` bigint default 9223372036854775807, `weight` float default 1.23, `cost1` double default 10.23, `cost2` decimal(8,2) default 50.23, `release_date` date default '2008-02-14', `release_datetime` datetime default '2008-02-14 00:31:12', `release_timestamp` timestamp NULL default '2008-02-14 00:31:31', `status` enum('active','out of stock') NOT NULL default 'active', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; EOF 1.upto(16) do |n| conn.create_command(<<-EOF).execute_non_query insert into widgets(code, name, shelf_location, description, image_data, ad_description, ad_image, whitepaper_text, cad_drawing, super_number, weight) VALUES ('W#{n.to_s.rjust(7,"0")}', 'Widget #{n}', 'A14', 'This is a description', 'IMAGE DATA', 'Buy this product now!', 'AD IMAGE DATA', 'String', 'CAD \001 \000 DRAWING', 1234, 13.4); EOF end conn.create_command(<<-EOF).execute_non_query update widgets set flags = true where id = 2 EOF conn.create_command(<<-EOF).execute_non_query update widgets set ad_description = NULL where id = 3 EOF conn.create_command(<<-EOF).execute_non_query update widgets set flags = NULL where id = 4 EOF conn.create_command(<<-EOF).execute_non_query update widgets set cost1 = NULL where id = 5 EOF conn.create_command(<<-EOF).execute_non_query update widgets set cost2 = NULL where id = 6 EOF conn.create_command(<<-EOF).execute_non_query update widgets set release_date = NULL where id = 7 EOF conn.create_command(<<-EOF).execute_non_query update widgets set release_datetime = NULL where id = 8 EOF conn.create_command(<<-EOF).execute_non_query update widgets set release_timestamp = NULL where id = 9 EOF conn.create_command(<<-EOF).execute_non_query update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10 EOF conn.close end def self.test_environment_ssl_config ssl_config = SSLHelpers::CONFIG message = "\nYou can configure MySQL via my.cnf with the following options in [mysqld]:\n" message << "ssl_ca=#{ssl_config.ca_cert}\n" message << "ssl_cert=#{ssl_config.server_cert}\n" message << "ssl_key=#{ssl_config.server_key}\n" message << "ssl_cipher=#{ssl_config.cipher}\n" message << "\nOr you can use the following command line options:\n" message << "--ssl-ca #{ssl_config.ca_cert} " message << "--ssl-cert #{ssl_config.server_cert} " message << "--ssl-key #{ssl_config.server_key} " message << "--ssl-cipher #{ssl_config.cipher} " message end def self.test_environment_ssl_config_errors conn = DataObjects::Connection.new(CONFIG.uri) ssl_variables = conn.create_command(<<-EOF).execute_reader SHOW VARIABLES LIKE '%ssl%' EOF ssl_config = SSLHelpers::CONFIG current_config = { } while ssl_variables.next! variable, value = ssl_variables.values current_config[variable.intern] = value end errors = [] if current_config[:have_ssl] == 'NO' errors << "SSL was not compiled" end if current_config[:have_ssl] == 'DISABLED' errors << "SSL was not enabled" end if current_config[:ssl_ca] != ssl_config.ca_cert errors << "The CA certificate is not configured (it was set to '#{current_config[:ssl_ca]}')" end if current_config[:ssl_cert] != ssl_config.server_cert errors << "The server certificate is not configured (it was set to '#{current_config[:ssl_cert]}')" end if current_config[:ssl_key] != ssl_config.server_key errors << "The server key is not configured, (it was set to '#{current_config[:ssl_key]}')" end if current_config[:ssl_cipher] != ssl_config.cipher errors << "The cipher is not configured, (it was set to '#{current_config[:ssl_cipher]}')" end errors ensure conn.close if conn end def self.test_environment_supports_ssl? test_environment_ssl_config_errors.empty? end end RSpec.configure do |config| config.include(DataObjectsSpecHelpers) config.include(DataObjects::Spec::PendingHelpers) end do_mysql-0.10.17/spec/error/0000755000004100000410000000000013305246414015624 5ustar www-datawww-datado_mysql-0.10.17/spec/error/sql_error_spec.rb0000644000004100000410000000040013305246414021165 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/error/sql_error_spec' describe 'DataObjects::Mysql raising SQLError' do it_should_behave_like 'raising a SQLError' end do_mysql-0.10.17/spec/result_spec.rb0000644000004100000410000000240513305246414017351 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper')) require 'data_objects/spec/shared/result_spec' # splitting the descibe into two separate declaration avoids # concurrent execution of the "it_should_behave_like ....." # needed by some databases (sqlite3) describe DataObjects::Mysql::Result do it_should_behave_like 'a Result' end describe DataObjects::Mysql::Result do it_should_behave_like 'a Result which returns inserted key with sequences' it_should_behave_like 'a Result which returns nil without sequences' end describe DataObjects::Mysql::Result do describe 'insert_id' do before do setup_test_environment @connection = DataObjects::Connection.new(CONFIG.uri) # set the sequence to a value larger than SQL integer command = @connection.create_command('INSERT INTO stuff (id, value) VALUES (?,?)') command.execute_non_query(3_000_000_000, 'cow') # use the sequence to generate an id command = @connection.create_command('INSERT INTO stuff (value) VALUES (?)') @result = command.execute_non_query('monkey') end after do @connection.close end it 'should return the bigint id' do @result.insert_id.should == 3_000_000_001 end end end do_mysql-0.10.17/spec/typecast/0000755000004100000410000000000013305246414016327 5ustar www-datawww-datado_mysql-0.10.17/spec/typecast/string_spec.rb0000644000004100000410000000037213305246414021176 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/string_spec' describe 'DataObjects::Mysql with String' do it_should_behave_like 'supporting String' end do_mysql-0.10.17/spec/typecast/class_spec.rb0000644000004100000410000000036713305246414021001 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/class_spec' describe 'DataObjects::Mysql with Class' do it_should_behave_like 'supporting Class' end do_mysql-0.10.17/spec/typecast/nil_spec.rb0000644000004100000410000000053213305246414020450 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/nil_spec' describe 'DataObjects::Mysql with Nil' do it_should_behave_like 'supporting Nil' it_should_behave_like 'supporting writing an Nil' it_should_behave_like 'supporting Nil autocasting' end do_mysql-0.10.17/spec/typecast/date_spec.rb0000644000004100000410000000174213305246414020607 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/date_spec' describe 'DataObjects::Mysql with Date' do it_should_behave_like 'supporting Date' it_should_behave_like 'supporting Date autocasting' describe 'reading 0000-00-00' do before do @connection = DataObjects::Connection.new(CONFIG.uri) @connection.create_command("SET SESSION sql_mode = 'ALLOW_INVALID_DATES'").execute_non_query @connection.create_command("INSERT INTO widgets (release_date) VALUES ('')").execute_non_query @command = @connection.create_command("SELECT release_date FROM widgets WHERE release_date = '0000-00-00'") @reader = @command.execute_reader @reader.next! @values = @reader.values end after do @reader.close @connection.close end it 'should return the number of created rows' do @values.first.should be_nil end end end do_mysql-0.10.17/spec/typecast/boolean_spec.rb0000644000004100000410000000046613305246414021313 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/boolean_spec' describe 'DataObjects::Mysql with Boolean' do it_should_behave_like 'supporting Boolean' it_should_behave_like 'supporting Boolean autocasting' end do_mysql-0.10.17/spec/typecast/range_spec.rb0000644000004100000410000000036713305246414020770 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/range_spec' describe 'DataObjects::Mysql with Range' do it_should_behave_like 'supporting Range' end do_mysql-0.10.17/spec/typecast/datetime_spec.rb0000644000004100000410000000202013305246414021454 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/datetime_spec' describe 'DataObjects::Mysql with DateTime' do it_should_behave_like 'supporting DateTime' it_should_behave_like 'supporting DateTime autocasting' describe 'reading 0000-00-00 00:00:00' do before do @connection = DataObjects::Connection.new(CONFIG.uri) @connection.create_command("SET SESSION sql_mode = 'ALLOW_INVALID_DATES'").execute_non_query @connection.create_command("INSERT INTO widgets (release_datetime) VALUES ('')").execute_non_query @command = @connection.create_command("SELECT release_datetime FROM widgets WHERE release_datetime = '0000-00-00 00:00:00'") @reader = @command.execute_reader @reader.next! @values = @reader.values end after do @reader.close @connection.close end it 'should return the number of created rows' do @values.first.should be_nil end end end do_mysql-0.10.17/spec/typecast/integer_spec.rb0000644000004100000410000000037513305246414021330 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/integer_spec' describe 'DataObjects::Mysql with Integer' do it_should_behave_like 'supporting Integer' end do_mysql-0.10.17/spec/typecast/other_spec.rb0000644000004100000410000000042213305246414021005 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/other_spec' describe 'DataObjects::H2 with other (unknown) type' do it_should_behave_like 'supporting other (unknown) type' end do_mysql-0.10.17/spec/typecast/byte_array_spec.rb0000644000004100000410000000040413305246414022025 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/byte_array_spec' describe 'DataObjects::Mysql with ByteArray' do it_should_behave_like 'supporting ByteArray' end do_mysql-0.10.17/spec/typecast/array_spec.rb0000644000004100000410000000036713305246414021012 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/array_spec' describe 'DataObjects::Mysql with Array' do it_should_behave_like 'supporting Array' end do_mysql-0.10.17/spec/typecast/bigdecimal_spec.rb0000644000004100000410000000050213305246414021743 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/bigdecimal_spec' describe 'DataObjects::Mysql with BigDecimal' do it_should_behave_like 'supporting BigDecimal' it_should_behave_like 'supporting BigDecimal autocasting' end do_mysql-0.10.17/spec/typecast/time_spec.rb0000644000004100000410000000036413305246414020627 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/time_spec' describe 'DataObjects::Mysql with Time' do it_should_behave_like 'supporting Time' end do_mysql-0.10.17/spec/typecast/float_spec.rb0000644000004100000410000000045613305246414021000 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) require 'data_objects/spec/shared/typecast/float_spec' describe 'DataObjects::Mysql with Float' do it_should_behave_like 'supporting Float' it_should_behave_like 'supporting Float autocasting' end do_mysql-0.10.17/spec/reader_spec.rb0000644000004100000410000000167613305246414017306 0ustar www-datawww-data# encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper')) require 'data_objects/spec/shared/reader_spec' describe DataObjects::Mysql::Reader do it_should_behave_like 'a Reader' describe 'reading database metadata' do subject { reader } let(:connection) { DataObjects::Connection.new(CONFIG.uri) } let(:command) { connection.create_command(sql) } let(:reader) { command.execute_reader } after do reader.close connection.close end describe 'showing correct column field names for a table' do let(:sql) { 'SHOW COLUMNS FROM `widgets`' } its(:fields) { should == [ "Field", "Type", "Null", "Key", "Default", "Extra" ] } end describe 'showing correct column field names for variables' do let(:sql) { "SHOW VARIABLES LIKE 'character_set_connection'" } its(:fields) { should == [ 'Variable_name', 'Value' ] } end end end do_mysql-0.10.17/LICENSE0000644000004100000410000000206713305246414014553 0ustar www-datawww-dataCopyright (c) 2007 - 2011 Yehuda Katz, Dirkjan Bussink Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. do_mysql-0.10.17/Rakefile0000644000004100000410000000201613305246414015205 0ustar www-datawww-datarequire 'pathname' require 'rubygems' require 'bundler' require 'rubygems/package_task' Bundler::GemHelper.install_tasks require 'rake' require 'rake/clean' ROOT = Pathname(__FILE__).dirname.expand_path require ROOT + 'lib/do_mysql/version' JRUBY = RUBY_PLATFORM =~ /java/ IRONRUBY = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ironruby' WINDOWS = Gem.win_platform? || (JRUBY && ENV_JAVA['os.name'] =~ /windows/i) SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS']) BINARY_VERSION = '5.1.65' CLEAN.include(%w[ {tmp,pkg}/ **/*.{o,so,bundle,jar,log,a,gem,dSYM,obj,pdb,exp,DS_Store,rbc,db} ext/do_mysql/Makefile ext-java/target ]) if JRUBY Rake::Task['build'].clear_actions if Rake::Task.task_defined?('build') Rake::Task['install'].clear_actions if Rake::Task.task_defined?('install') task :build => [ :java, :gem ] task :install do sh "#{Config::CONFIG['RUBY_INSTALL_NAME']} -S gem install pkg/do_mysql-#{DataObjects::Mysql::VERSION}-java.gem" end end FileList['tasks/**/*.rake'].each { |task| import task } do_mysql-0.10.17/lib/0000755000004100000410000000000013305246414014307 5ustar www-datawww-datado_mysql-0.10.17/lib/do_mysql/0000755000004100000410000000000013305246414016136 5ustar www-datawww-datado_mysql-0.10.17/lib/do_mysql/version.rb0000644000004100000410000000010413305246414020143 0ustar www-datawww-datamodule DataObjects module Mysql VERSION = '0.10.17' end end do_mysql-0.10.17/lib/do_mysql/encoding.rb0000644000004100000410000000224613305246414020255 0ustar www-datawww-datamodule DataObjects module Mysql module Encoding MAP = { "Big5" => "big5", "CP850" => "cp850", "KOI8-R" => "koi8r", "ISO-8859-1" => "latin1", "ISO-8859-2" => "latin2", "US-ASCII" => "ascii", "EUC-JP" => "ujis", "SJIS" => "sjis", "ISO-8859-8" => "hebrew", "TIS-620" => "tis620", "EUC-KR" => "euckr", "KOI8-U" => "koi8u", "GB2312" => "gb2312", "ISO-8859-7" => "greek", "Windows-1250" => "cp1250", "GBK" => "gbk", "ISO-8859-9" => "latin5", "UTF-8" => "utf8", "UTF-8-MB4" => "utf8mb4", "UTF-16BE" => "ucs2", "IBM866" => "cp866", "macCentEuro" => "macce", "macRoman" => "macroman", "CP852" => "cp852", "ISO-8859-13" => "latin7", "Windows-1251" => "cp1251", "Windows-1256" => "cp1256", "Windows-1257" => "cp1257", "ASCII-8BIT" => "binary", "Windows-31J" => "cp932", "eucJP-ms" => "eucjpms" } end end end do_mysql-0.10.17/lib/do_mysql/transaction.rb0000644000004100000410000000142413305246414021011 0ustar www-datawww-data module DataObjects module Mysql class Transaction < DataObjects::Transaction def begin_prepared cmd = "XA START '#{id}'" connection.create_command(cmd).execute_non_query end def commit_prepared cmd = "XA COMMIT '#{id}'" connection.create_command(cmd).execute_non_query end def rollback_prepared cmd = "XA ROLLBACK '#{id}'" connection.create_command(cmd).execute_non_query end def prepare finalize_transaction cmd = "XA PREPARE '#{id}'" connection.create_command(cmd).execute_non_query end private def finalize_transaction cmd = "XA END '#{id}'" connection.create_command(cmd).execute_non_query end end end end do_mysql-0.10.17/lib/do_mysql.rb0000644000004100000410000000264713305246414016474 0ustar www-datawww-datarequire 'data_objects' if RUBY_PLATFORM =~ /java/ require 'do_jdbc' require 'java' module DataObjects module Mysql JDBC_DRIVER = 'com.mysql.jdbc.Driver' end end begin java.lang.Thread.currentThread.getContextClassLoader().loadClass(DataObjects::Mysql::JDBC_DRIVER, true) rescue java.lang.ClassNotFoundException require 'jdbc/mysql' # the JDBC driver, packaged as a gem Jdbc::MySQL.load_driver if Jdbc::MySQL.respond_to?(:load_driver) end # Another way of loading the JDBC Class. This seems to be more reliable # than Class.forName() or # Thread.currentThread.getContextClassLoader().loadClass() within the # data_objects.Connection Java class, which is currently not working as # expected. java_import DataObjects::Mysql::JDBC_DRIVER end begin require 'do_mysql/do_mysql' rescue LoadError if RUBY_PLATFORM =~ /mingw|mswin/ RUBY_VERSION =~ /(\d+.\d+)/ require "do_mysql/#{$1}/do_mysql" else raise end end require 'do_mysql/version' require 'do_mysql/transaction' if RUBY_PLATFORM !~ /java/ require 'do_mysql/encoding' if RUBY_PLATFORM =~ /java/ DataObjects::Mysql::Connection.class_eval do def using_socket? @using_socket end def secure? false end end else module DataObjects module Mysql class Connection def secure? !(@ssl_cipher.nil? || @ssl_cipher.empty?) end end end end end do_mysql-0.10.17/do_mysql.gemspec0000644000004100000410000000743613305246414016747 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: do_mysql 0.10.17 ruby lib # stub: ext/do_mysql/extconf.rb Gem::Specification.new do |s| s.name = "do_mysql".freeze s.version = "0.10.17" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Dirkjan Bussink".freeze] s.date = "2016-01-24" s.description = "Implements the DataObjects API for MySQL".freeze s.email = "d.bussink@gmail.com".freeze s.extensions = ["ext/do_mysql/extconf.rb".freeze] s.extra_rdoc_files = ["ChangeLog.markdown".freeze, "LICENSE".freeze, "README.markdown".freeze] s.files = ["ChangeLog.markdown".freeze, "LICENSE".freeze, "README.markdown".freeze, "Rakefile".freeze, "ext/do_mysql/compat.h".freeze, "ext/do_mysql/do_common.c".freeze, "ext/do_mysql/do_common.h".freeze, "ext/do_mysql/do_mysql.c".freeze, "ext/do_mysql/error.h".freeze, "ext/do_mysql/extconf.rb".freeze, "ext/do_mysql/mysql_compat.h".freeze, "lib/do_mysql.rb".freeze, "lib/do_mysql/encoding.rb".freeze, "lib/do_mysql/transaction.rb".freeze, "lib/do_mysql/version.rb".freeze, "spec/command_spec.rb".freeze, "spec/connection_spec.rb".freeze, "spec/encoding_spec.rb".freeze, "spec/error/sql_error_spec.rb".freeze, "spec/reader_spec.rb".freeze, "spec/result_spec.rb".freeze, "spec/spec_helper.rb".freeze, "spec/typecast/array_spec.rb".freeze, "spec/typecast/bigdecimal_spec.rb".freeze, "spec/typecast/boolean_spec.rb".freeze, "spec/typecast/byte_array_spec.rb".freeze, "spec/typecast/class_spec.rb".freeze, "spec/typecast/date_spec.rb".freeze, "spec/typecast/datetime_spec.rb".freeze, "spec/typecast/float_spec.rb".freeze, "spec/typecast/integer_spec.rb".freeze, "spec/typecast/nil_spec.rb".freeze, "spec/typecast/other_spec.rb".freeze, "spec/typecast/range_spec.rb".freeze, "spec/typecast/string_spec.rb".freeze, "spec/typecast/time_spec.rb".freeze, "tasks/compile.rake".freeze, "tasks/release.rake".freeze, "tasks/retrieve.rake".freeze, "tasks/spec.rake".freeze, "tasks/ssl.rake".freeze] s.rubyforge_project = "dorb".freeze s.rubygems_version = "2.5.2.1".freeze s.summary = "DataObjects MySQL Driver".freeze s.test_files = ["spec/command_spec.rb".freeze, "spec/connection_spec.rb".freeze, "spec/encoding_spec.rb".freeze, "spec/error/sql_error_spec.rb".freeze, "spec/reader_spec.rb".freeze, "spec/result_spec.rb".freeze, "spec/spec_helper.rb".freeze, "spec/typecast/array_spec.rb".freeze, "spec/typecast/bigdecimal_spec.rb".freeze, "spec/typecast/boolean_spec.rb".freeze, "spec/typecast/byte_array_spec.rb".freeze, "spec/typecast/class_spec.rb".freeze, "spec/typecast/date_spec.rb".freeze, "spec/typecast/datetime_spec.rb".freeze, "spec/typecast/float_spec.rb".freeze, "spec/typecast/integer_spec.rb".freeze, "spec/typecast/nil_spec.rb".freeze, "spec/typecast/other_spec.rb".freeze, "spec/typecast/range_spec.rb".freeze, "spec/typecast/string_spec.rb".freeze, "spec/typecast/time_spec.rb".freeze] if s.respond_to? :specification_version then s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q.freeze, ["= 0.10.17"]) s.add_development_dependency(%q.freeze, ["~> 0.7"]) s.add_development_dependency(%q.freeze, ["~> 2.5"]) else s.add_dependency(%q.freeze, ["= 0.10.17"]) s.add_dependency(%q.freeze, ["~> 0.7"]) s.add_dependency(%q.freeze, ["~> 2.5"]) end else s.add_dependency(%q.freeze, ["= 0.10.17"]) s.add_dependency(%q.freeze, ["~> 0.7"]) s.add_dependency(%q.freeze, ["~> 2.5"]) end end do_mysql-0.10.17/README.markdown0000644000004100000410000000545313305246414016251 0ustar www-datawww-data# do_mysql * ## Description A MySQL driver for DataObjects. ## Features/Problems This driver implements the DataObjects API for the MySQL relational database. ## Synopsis An example of usage: ```ruby # default user (root, no password); default port (3306) DataObjects::Connection.new("mysql://host/database") # specified user, specified port DataObjects::Connection.new("mysql://user:pass@host:8888/database") @connection = DataObjects::Connection.new("mysql://localhost/employees") @reader = @connection.create_command('SELECT * FROM users').execute_reader @reader.next! ``` ## Requirements This driver is provided for the following platforms: * Ruby MRI (1.8.6/7), 1.9: tested on Linux, Mac OS X and Windows platforms. * JRuby 1.3.1 + (1.4+ recommended). * Rubinius (experimental). Additionally you should have the following prerequisites: * `data_objects` gem * `do_jdbc` gem (shared library), if running on JRuby. ## Install To install the gem: gem install do_mysql If installing the MRI/1.9/Rubinius extension on OS X and you install a version of MySQL that was built for only a single architecture, you will need to set `ARCHFLAGS` appropriately: sudo env ARCHFLAGS="-arch i386" gem install do_mysql To compile and install from source: * Install rake-compiler: `gem install rake-compiler`. * For MRI/Rubinius extensions: * Install the `gcc` compiler. On OS X, you should install XCode tools. On Ubuntu, run `apt-get install build-essential`. * Install Ruby and MySQL. * Install the Ruby and MySQL development headers. * On Debian-Linux distributions, you can install the following packages with `apt`: `ruby-dev` `libmysqlclient15-dev`. * If you want to cross-compile for Windows: * Install MinGW: * On Debian-Linux distributions, you can install the following package with `apt`: `mingw32`. * On OS X, this can install the following package with MacPorts: `i386-mingw32-gcc`. * Run `rake-compiler cross-ruby`. * Run `rake-compiler update-config`. * Then, install this driver with `(jruby -S) rake install`. For more information, see the MySQL driver wiki page: . ## Developers Follow the above installation instructions. Additionally, you'll need: * `rspec` gem for running specs. * `YARD` gem for generating documentation. See the DataObjects wiki for more comprehensive information on installing and contributing to the JRuby-variant of this driver: . To run specs: rake spec To run specs without compiling extensions first: rake spec_no_compile To run individual specs: rake spec SPEC=spec/connection_spec.rb ## License This code is licensed under an **MIT (X11) License**. Please see the accompanying `LICENSE` file. do_mysql-0.10.17/ChangeLog.markdown0000644000004100000410000000516013305246414017136 0ustar www-datawww-data## 0.10.17 2016-01-24 * Improve utf8mb4 support * Fix memory leak * Support for MySQL 5.7 * Fix bug with DateTime and wrong timezone offsets ## 0.10.16 2015-05-17 No changes ## 0.10.15 2015-02-15 * Ruby 2.2 support * utf8mb4 support on do\_mysql * Windows support on 2.1.x and 2.2.x ## 0.10.14 2014-02-13 * Don't do DNS lookup in transaction loading ## 0.10.13 2013-05-27 * Windows binary for Ruby 2.0 ## 0.10.12 2013-01-21 * jdbc-mysql driver loading fix * Improve compatibility for anscient MySQL versions ## 0.10.11 2012-12-29 * Rename C symbols to prevent name collitions ## 0.10.10 2012-10-11 No changes ## 0.10.9 2012-08-13 * Handle bigint insert id's * Add handling for invalid date and datetimes with value 0000-00-00 * Handle empty database names for connecting to the default database ## 0.10.8 2012-02-10 * Ruby 1.9.3 compatibility on Windows ## 0.10.7 2011-10-13 * Ruby 1.9.3 compatibility ## 0.10.6 2011-05-22 Bugfixes * Fix an issue on some platforms when multiple DO drivers are loaded ## 0.10.5 2011-05-03 No changes ## 0.10.4 2011-04-28 New features * Add save point to transactions (all) * JRuby 1.9 mode support (encodings etc.) Bugfixes * Fix bug when using nested transactions in concurrent scenarios (all) * Use column aliases instead of names (jruby) * DST calculation fixes (all) * Attempt to add better support for ancient MySQL versions (do\_mysql) Other * Refactor to DRY up the adapters (all) * Many style fixes * Switch back to RSpec ## 0.10.3 2011-01-30 * Reworked transactions * Fix a DST bug that could cause datetimes in the wrong timezone ## 0.10.2 2010-05-19 * Make sure Text is returned in the proper encoding * Make Encoding.default_internal aware * Fix insert_id if no incrementing key is used * Rework logging for making callbacks possible * Remove handling Object types directly ## 0.10.1 2010-01-08 * Support for Ruby 1.8 and 1.9 on Windows. * Switch to Jeweler for Gem building tasks (this change may be temporary). * Switch to using Bacon for running specs: This should make specs friendlier to new Ruby implementations that are not yet 100% MRI-compatible, and in turn, pave the road for our own IronRuby and MacRuby support. * Switch to the newly added rake-compiler `JavaExtensionTask` for compiling JRuby extensions, instead of our (broken) home-grown solution. ## 0.10.0 2009-09-15 * Improvements * JRuby Support (using *do_jdbc*) ## 0.9.12 2009-05-17 * Improvements * Windows support ## 0.9.11 2009-01-19 * Improvements * Ruby 1.9 support * Fixes * Reconnecting now works properly ## 0.9.9 2008-11-27 * Improvements * Added initial support for Ruby 1.9 [John Harrison] do_mysql-0.10.17/ext/0000755000004100000410000000000013305246414014341 5ustar www-datawww-datado_mysql-0.10.17/ext/do_mysql/0000755000004100000410000000000013305246414016170 5ustar www-datawww-datado_mysql-0.10.17/ext/do_mysql/do_common.h0000644000004100000410000001011213305246414020306 0ustar www-datawww-data#ifndef _DO_COMMON_H_ #define _DO_COMMON_H_ #include // Needed for defining error.h struct errcodes { int error_no; const char *error_name; const char *exception; }; #define ERRCODE(name,message) {name, #name, message} #ifdef _WIN32 typedef signed __int64 do_int64; #else typedef signed long long int do_int64; #endif #ifdef HAVE_RUBY_ENCODING_H #include #define DATA_OBJECTS_STR_NEW2(str, encoding, internal_encoding) \ ({ \ VALUE _string = rb_str_new2((const char *)str); \ if(encoding != -1) { \ rb_enc_associate_index(_string, encoding); \ } \ if(internal_encoding) { \ _string = rb_str_export_to_enc(_string, internal_encoding); \ } \ _string; \ }) #define DATA_OBJECTS_STR_NEW(str, len, encoding, internal_encoding) \ ({ \ VALUE _string = rb_str_new((const char *)str, (long)len); \ if(encoding != -1) { \ rb_enc_associate_index(_string, encoding); \ } \ if(internal_encoding) { \ _string = rb_str_export_to_enc(_string, internal_encoding); \ } \ _string; \ }) #else #define DATA_OBJECTS_STR_NEW2(str, encoding, internal_encoding) \ rb_str_new2((const char *)str) #define DATA_OBJECTS_STR_NEW(str, len, encoding, internal_encoding) \ rb_str_new((const char *)str, (long)len) #endif // To store rb_intern values extern ID DO_ID_NEW; extern ID DO_ID_NEW_DATE; extern ID DO_ID_CONST_GET; extern ID DO_ID_RATIONAL; extern ID DO_ID_ESCAPE; extern ID DO_ID_STRFTIME; extern ID DO_ID_LOG; // Reference to Extlib module extern VALUE mExtlib; extern VALUE rb_cByteArray; // References to DataObjects base classes extern VALUE mDO; extern VALUE cDO_Quoting; extern VALUE cDO_Connection; extern VALUE cDO_Command; extern VALUE cDO_Result; extern VALUE cDO_Reader; extern VALUE cDO_Logger; extern VALUE cDO_Logger_Message; extern VALUE cDO_Extension; extern VALUE eDO_ConnectionError; extern VALUE eDO_DataError; // References to Ruby classes that we'll need extern VALUE rb_cDate; extern VALUE rb_cDateTime; extern VALUE rb_cBigDecimal; extern void data_objects_debug(VALUE connection, VALUE string, struct timeval *start); extern char *data_objects_get_uri_option(VALUE query_hash, const char *key); extern void data_objects_assert_file_exists(char *file, const char *message); extern VALUE data_objects_build_query_from_args(VALUE klass, int count, VALUE *args); extern void data_objects_reduce(do_int64 *numerator, do_int64 *denominator); extern int data_objects_jd_from_date(int year, int month, int day); extern VALUE data_objects_seconds_to_offset(long seconds_offset); extern VALUE data_objects_timezone_to_offset(int hour_offset, int minute_offset); extern VALUE data_objects_parse_date(const char *date); extern VALUE data_objects_parse_time(const char *date); extern VALUE data_objects_parse_date_time(const char *date); extern VALUE data_objects_cConnection_character_set(VALUE self); extern VALUE data_objects_cConnection_is_using_socket(VALUE self); extern VALUE data_objects_cConnection_ssl_cipher(VALUE self); extern VALUE data_objects_cConnection_quote_time(VALUE self, VALUE value); extern VALUE data_objects_cConnection_quote_date_time(VALUE self, VALUE value); extern VALUE data_objects_cConnection_quote_date(VALUE self, VALUE value); extern VALUE data_objects_cCommand_set_types(int argc, VALUE *argv, VALUE self); extern VALUE data_objects_cReader_values(VALUE self); extern VALUE data_objects_cReader_fields(VALUE self); extern VALUE data_objects_cReader_field_count(VALUE self); extern void data_objects_common_init(void); extern VALUE data_objects_const_get(VALUE scope, const char *constant); static inline void data_objects_define_errors(VALUE scope, const struct errcodes *errors) { const struct errcodes *e; for (e = errors; e->error_name; e++) { rb_const_set(scope, rb_intern(e->error_name), INT2NUM(e->error_no)); } } extern void data_objects_raise_error(VALUE self, const struct errcodes *errors, int errnum, VALUE message, VALUE query, VALUE state); extern VALUE data_objects_typecast(const char *value, long length, const VALUE type, int encoding); #define RSTRING_NOT_MODIFIED #endif do_mysql-0.10.17/ext/do_mysql/do_mysql.c0000644000004100000410000005024513305246414020171 0ustar www-datawww-data#include #include #ifndef _WIN32 #include #endif #include #include #include #include #include "mysql_compat.h" #include "compat.h" #include "error.h" #include "do_common.h" #ifndef HAVE_CONST_MYSQL_TYPE_STRING #define HAVE_OLD_MYSQL_VERSION #endif #ifdef _WIN32 #define do_mysql_cCommand_execute do_mysql_cCommand_execute_sync #else #define do_mysql_cCommand_execute do_mysql_cCommand_execute_async #endif #ifndef HAVE_RB_THREAD_FD_SELECT #define rb_fdset_t fd_set #define rb_fd_isset(n, f) FD_ISSET(n, f) #define rb_fd_init(f) FD_ZERO(f) #define rb_fd_zero(f) FD_ZERO(f) #define rb_fd_set(n, f) FD_SET(n, f) #define rb_fd_clr(n, f) FD_CLR(n, f) #define rb_fd_term(f) #define rb_thread_fd_select rb_thread_select #endif #define CHECK_AND_RAISE(mysql_result_value, query) if (0 != mysql_result_value) { do_mysql_raise_error(self, db, query); } void do_mysql_full_connect(VALUE self, MYSQL *db); // Classes that we'll build in Init VALUE mDO_Mysql; VALUE mDO_MysqlEncoding; VALUE cDO_MysqlConnection; VALUE cDO_MysqlCommand; VALUE cDO_MysqlResult; VALUE cDO_MysqlReader; // Figures out what we should cast a given mysql field type to VALUE do_mysql_infer_ruby_type(const MYSQL_FIELD *field) { switch (field->type) { case MYSQL_TYPE_NULL: return Qnil; case MYSQL_TYPE_TINY: return rb_cTrueClass; #ifdef HAVE_CONST_MYSQL_TYPE_BIT case MYSQL_TYPE_BIT: #endif case MYSQL_TYPE_SHORT: case MYSQL_TYPE_LONG: case MYSQL_TYPE_INT24: case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_YEAR: return rb_cInteger; #ifdef HAVE_CONST_MYSQL_TYPE_NEWDECIMAL case MYSQL_TYPE_NEWDECIMAL: #endif case MYSQL_TYPE_DECIMAL: return rb_cBigDecimal; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: return rb_cFloat; case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATETIME: return rb_cDateTime; case MYSQL_TYPE_DATE: case MYSQL_TYPE_NEWDATE: return rb_cDate; case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: #ifdef HAVE_ST_CHARSETNR if (field->charsetnr == 63) { return rb_cByteArray; } else { return rb_cString; } #else // We assume a string here if we don't have a specific charset return rb_cString; #endif default: return rb_cString; } } // Convert C-string to a Ruby instance of Ruby type "type" VALUE do_mysql_typecast(const char *value, long length, const VALUE type, int encoding) { if (!value) { return Qnil; } if (type == rb_cTrueClass) { return (value == 0 || strcmp("0", value) == 0) ? Qfalse : Qtrue; } else if (type == rb_cByteArray) { return rb_funcall(rb_cByteArray, DO_ID_NEW, 1, rb_str_new(value, length)); } else { return data_objects_typecast(value, length, type, encoding); } } void do_mysql_raise_error(VALUE self, MYSQL *db, VALUE query) { int errnum = mysql_errno(db); VALUE message = rb_str_new2(mysql_error(db)); VALUE sql_state = Qnil; #ifdef HAVE_MYSQL_SQLSTATE sql_state = rb_str_new2(mysql_sqlstate(db)); #endif data_objects_raise_error(self, do_mysql_errors, errnum, message, query, sql_state); } #ifdef _WIN32 MYSQL_RES *do_mysql_cCommand_execute_sync(VALUE self, VALUE connection, MYSQL *db, VALUE query) { int retval; struct timeval start; const char *str = rb_str_ptr_readonly(query); long len = rb_str_len(query); if (mysql_ping(db) && mysql_errno(db) == CR_SERVER_GONE_ERROR) { // Ok, we do one more try here by doing a full connect VALUE connection = rb_iv_get(self, "@connection"); do_mysql_full_connect(connection, db); } gettimeofday(&start, NULL); retval = mysql_real_query(db, str, len); data_objects_debug(connection, query, &start); CHECK_AND_RAISE(retval, query); return mysql_store_result(db); } #else MYSQL_RES *do_mysql_cCommand_execute_async(VALUE self, VALUE connection, MYSQL *db, VALUE query) { int retval; if ((retval = mysql_ping(db)) && mysql_errno(db) == CR_SERVER_GONE_ERROR) { do_mysql_full_connect(connection, db); } struct timeval start; const char *str = rb_str_ptr_readonly(query); long len = rb_str_len(query); gettimeofday(&start, NULL); retval = mysql_send_query(db, str, len); CHECK_AND_RAISE(retval, query); int socket_fd = db->net.fd; rb_fdset_t rset; rb_fd_init(&rset); rb_fd_set(socket_fd, &rset); while (1) { retval = rb_thread_fd_select(socket_fd + 1, &rset, NULL, NULL, NULL); if (retval < 0) { rb_fd_term(&rset); rb_sys_fail(0); } if (retval == 0) { continue; } if (db->status == MYSQL_STATUS_READY) { break; } } rb_fd_term(&rset); retval = mysql_read_query_result(db); CHECK_AND_RAISE(retval, query); data_objects_debug(connection, query, &start); MYSQL_RES *result = mysql_store_result(db); if (!result) { CHECK_AND_RAISE(mysql_errno(db), query); } return result; } #endif void do_mysql_full_connect(VALUE self, MYSQL *db) { VALUE r_host = rb_iv_get(self, "@host"); const char *host = "localhost"; if (r_host != Qnil) { host = StringValuePtr(r_host); } VALUE r_user = rb_iv_get(self, "@user"); const char *user = "root"; if (r_user != Qnil) { user = StringValuePtr(r_user); } VALUE r_password = rb_iv_get(self, "@password"); char *password = NULL; if (r_password != Qnil) { password = StringValuePtr(r_password); } VALUE r_port = rb_iv_get(self, "@port"); int port = 3306; if (r_port != Qnil) { port = NUM2INT(r_port); } VALUE r_path = rb_iv_get(self, "@path"); char *path = NULL; char *database = NULL; if (r_path != Qnil) { path = StringValuePtr(r_path); database = strtok(path, "/"); // not threadsafe } if (!database || !*database) { database = NULL; } VALUE r_query = rb_iv_get(self, "@query"); char *socket = NULL; // Check to see if we're on the db machine. If so, try to use the socket if (strcasecmp(host, "localhost") == 0) { socket = data_objects_get_uri_option(r_query, "socket"); if (socket) { rb_iv_set(self, "@using_socket", Qtrue); } } #ifdef HAVE_MYSQL_SSL_SET char *ssl_client_key, *ssl_client_cert, *ssl_ca_cert, *ssl_ca_path, *ssl_cipher; VALUE r_ssl; if (rb_obj_is_kind_of(r_query, rb_cHash)) { r_ssl = rb_hash_aref(r_query, rb_str_new2("ssl")); if (rb_obj_is_kind_of(r_ssl, rb_cHash)) { ssl_client_key = data_objects_get_uri_option(r_ssl, "client_key"); ssl_client_cert = data_objects_get_uri_option(r_ssl, "client_cert"); ssl_ca_cert = data_objects_get_uri_option(r_ssl, "ca_cert"); ssl_ca_path = data_objects_get_uri_option(r_ssl, "ca_path"); ssl_cipher = data_objects_get_uri_option(r_ssl, "cipher"); data_objects_assert_file_exists(ssl_client_key, "client_key doesn't exist"); data_objects_assert_file_exists(ssl_client_cert, "client_cert doesn't exist"); data_objects_assert_file_exists(ssl_ca_cert, "ca_cert doesn't exist"); mysql_ssl_set(db, ssl_client_key, ssl_client_cert, ssl_ca_cert, ssl_ca_path, ssl_cipher); } else if (r_ssl != Qnil) { rb_raise(rb_eArgError, "ssl must be passed a hash"); } } #endif unsigned long client_flags = 0; MYSQL *result = mysql_real_connect( db, host, user, password, database, port, socket, client_flags ); if (!result) { do_mysql_raise_error(self, db, Qnil); } #ifdef HAVE_MYSQL_GET_SSL_CIPHER const char *ssl_cipher_used = mysql_get_ssl_cipher(db); if (ssl_cipher_used) { rb_iv_set(self, "@ssl_cipher", rb_str_new2(ssl_cipher_used)); } #endif #ifdef MYSQL_OPT_RECONNECT my_bool reconnect = 1; mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect); #endif // We only support encoding for MySQL versions providing mysql_set_character_set. // Without this function there are potential issues with mysql_real_escape_string // since that doesn't take the character set into consideration when setting it // using a SET CHARACTER SET query. Since we don't want to stimulate these possible // issues we simply ignore it and assume the user has configured this correctly. #ifdef HAVE_MYSQL_SET_CHARACTER_SET // Set the connections character set VALUE encoding = rb_iv_get(self, "@encoding"); VALUE my_encoding = rb_hash_aref(data_objects_const_get(mDO_MysqlEncoding, "MAP"), encoding); if (my_encoding != Qnil) { int encoding_error = mysql_set_character_set(db, rb_str_ptr_readonly(my_encoding)); if (encoding_error != 0) { do_mysql_raise_error(self, db, Qnil); } else { #ifdef HAVE_RUBY_ENCODING_H const char* ruby_encoding = rb_str_ptr_readonly(encoding); if (strcasecmp("UTF-8-MB4", ruby_encoding) == 0) { ruby_encoding = "UTF-8"; } rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(ruby_encoding))); #endif rb_iv_set(self, "@my_encoding", my_encoding); } } else { rb_warn("Encoding %s is not a known Ruby encoding for MySQL\n", rb_str_ptr_readonly(encoding)); rb_iv_set(self, "@encoding", rb_str_new2("UTF-8")); #ifdef HAVE_RUBY_ENCODING_H rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index("UTF-8"))); #endif rb_iv_set(self, "@my_encoding", rb_str_new2("utf8")); } #endif // Disable sql_auto_is_null do_mysql_cCommand_execute(Qnil, self, db, rb_str_new2("SET sql_auto_is_null = 0")); // removed NO_AUTO_VALUE_ON_ZERO because of MySQL bug http://bugs.mysql.com/bug.php?id=42270 // added NO_BACKSLASH_ESCAPES so that backslashes should not be escaped as in other databases // For really anscient MySQL versions we don't attempt any strictness #ifdef HAVE_MYSQL_GET_SERVER_VERSION //4.0 does not support sql_mode at all, while later 4.x versions do not support certain session parameters if (mysql_get_server_version(db) >= 50000) { do_mysql_cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_UNSIGNED_SUBTRACTION,TRADITIONAL'")); } else if (mysql_get_server_version(db) >= 40100) { do_mysql_cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_DIR_IN_CREATE,NO_UNSIGNED_SUBTRACTION'")); } #endif rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db)); } VALUE do_mysql_cConnection_initialize(VALUE self, VALUE uri) { rb_iv_set(self, "@using_socket", Qfalse); rb_iv_set(self, "@ssl_cipher", Qnil); VALUE r_host = rb_funcall(uri, rb_intern("host"), 0); if (r_host != Qnil) { rb_iv_set(self, "@host", r_host); } VALUE r_user = rb_funcall(uri, rb_intern("user"), 0); if (r_user != Qnil) { rb_iv_set(self, "@user", r_user); } VALUE r_password = rb_funcall(uri, rb_intern("password"), 0); if (r_password != Qnil) { rb_iv_set(self, "@password", r_password); } VALUE r_path = rb_funcall(uri, rb_intern("path"), 0); if (r_path != Qnil) { rb_iv_set(self, "@path", r_path); } VALUE r_port = rb_funcall(uri, rb_intern("port"), 0); if (r_port != Qnil) { rb_iv_set(self, "@port", r_port); } // Pull the querystring off the URI VALUE r_query = rb_funcall(uri, rb_intern("query"), 0); rb_iv_set(self, "@query", r_query); const char *encoding = data_objects_get_uri_option(r_query, "encoding"); if (!encoding) { encoding = data_objects_get_uri_option(r_query, "charset"); if (!encoding) { encoding = "UTF-8"; } } rb_iv_set(self, "@encoding", rb_str_new2(encoding)); MYSQL *db = mysql_init(NULL); do_mysql_full_connect(self, db); rb_iv_set(self, "@uri", uri); return Qtrue; } VALUE do_mysql_cConnection_dispose(VALUE self) { VALUE connection_container = rb_iv_get(self, "@connection"); MYSQL *db; if (connection_container == Qnil) { return Qfalse; } db = DATA_PTR(connection_container); if (!db) { return Qfalse; } mysql_close(db); rb_iv_set(self, "@connection", Qnil); return Qtrue; } VALUE do_mysql_cConnection_quote_string(VALUE self, VALUE string) { MYSQL *db = DATA_PTR(rb_iv_get(self, "@connection")); const char *source = rb_str_ptr_readonly(string); long source_len = rb_str_len(string); long buffer_len = source_len * 2 + 3; // Overflow check if(buffer_len <= source_len) { rb_raise(rb_eArgError, "Input string is too large to be safely quoted"); } // Allocate space for the escaped version of 'string'. Use + 3 allocate space for null term. // and the leading and trailing single-quotes. // Thanks to http://www.browardphp.com/mysql_manual_en/manual_MySQL_APIs.html#mysql_real_escape_string char *escaped = calloc(buffer_len, sizeof(char)); if (!escaped) { rb_memerror(); } unsigned long quoted_length; VALUE result; // Escape 'source' using the current encoding in use on the conection 'db' #ifdef HAVE_MYSQL_REAL_ESCAPE_STRING_QUOTE quoted_length = mysql_real_escape_string_quote(db, escaped + 1, source, source_len, '\''); #else quoted_length = mysql_real_escape_string(db, escaped + 1, source, source_len); #endif if (quoted_length == (unsigned long)-1) { free(escaped); rb_raise(rb_eArgError, "Failed to quote string. Make sure to (re)compile do_mysql against the correct libmysqlclient"); } // Wrap the escaped string in single-quotes, this is DO's convention escaped[0] = escaped[quoted_length + 1] = '\''; // We don't want to use the internal encoding, because this needs // to go into the database in the connection encoding result = DATA_OBJECTS_STR_NEW(escaped, quoted_length + 2, FIX2INT(rb_iv_get(self, "@encoding_id")), NULL); free(escaped); return result; } VALUE do_mysql_cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) { VALUE connection = rb_iv_get(self, "@connection"); VALUE mysql_connection = rb_iv_get(connection, "@connection"); if (mysql_connection == Qnil) { rb_raise(eDO_ConnectionError, "This connection has already been closed."); } MYSQL *db = DATA_PTR(mysql_connection); VALUE query = data_objects_build_query_from_args(self, argc, argv); MYSQL_RES *response = do_mysql_cCommand_execute(self, connection, db, query); my_ulonglong affected_rows = mysql_affected_rows(db); my_ulonglong insert_id = mysql_insert_id(db); mysql_free_result(response); if (((my_ulonglong)-1) == affected_rows) { return Qnil; } return rb_funcall(cDO_MysqlResult, DO_ID_NEW, 3, self, INT2NUM(affected_rows), insert_id == 0 ? Qnil : ULL2NUM(insert_id)); } VALUE do_mysql_cCommand_execute_reader(int argc, VALUE *argv, VALUE self) { VALUE connection = rb_iv_get(self, "@connection"); VALUE mysql_connection = rb_iv_get(connection, "@connection"); if (mysql_connection == Qnil) { rb_raise(eDO_ConnectionError, "This result set has already been closed."); } VALUE query = data_objects_build_query_from_args(self, argc, argv); MYSQL *db = DATA_PTR(mysql_connection); MYSQL_RES *response = do_mysql_cCommand_execute(self, connection, db, query); unsigned int field_count = mysql_field_count(db); VALUE reader = rb_funcall(cDO_MysqlReader, DO_ID_NEW, 0); rb_iv_set(reader, "@connection", connection); rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, response)); rb_iv_set(reader, "@opened", Qfalse); rb_iv_set(reader, "@field_count", INT2NUM(field_count)); VALUE field_names = rb_ary_new(); VALUE field_types = rb_iv_get(self, "@field_types"); char guess_default_field_types = 0; if (field_types == Qnil || RARRAY_LEN(field_types) == 0) { field_types = rb_ary_new(); guess_default_field_types = 1; } else if (RARRAY_LEN(field_types) != field_count) { // Whoops... wrong number of types passed to set_types. Close the reader and raise // and error rb_funcall(reader, rb_intern("close"), 0); rb_raise(rb_eArgError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count); } MYSQL_FIELD *field; unsigned int i; for(i = 0; i < field_count; i++) { field = mysql_fetch_field_direct(response, i); rb_ary_push(field_names, rb_str_new2(field->name)); if (guess_default_field_types == 1) { rb_ary_push(field_types, do_mysql_infer_ruby_type(field)); } } rb_iv_set(reader, "@fields", field_names); rb_iv_set(reader, "@field_types", field_types); if (rb_block_given_p()) { rb_yield(reader); rb_funcall(reader, rb_intern("close"), 0); } return reader; } // This should be called to ensure that the internal result reader is freed VALUE do_mysql_cReader_close(VALUE self) { // Get the reader from the instance variable, maybe refactor this? VALUE reader_container = rb_iv_get(self, "@reader"); if (reader_container == Qnil) { return Qfalse; } MYSQL_RES *reader = DATA_PTR(reader_container); // The Meat if (!reader) { return Qfalse; } mysql_free_result(reader); rb_iv_set(self, "@reader", Qnil); rb_iv_set(self, "@opened", Qfalse); return Qtrue; } // Retrieve a single row VALUE do_mysql_cReader_next(VALUE self) { // Get the reader from the instance variable, maybe refactor this? VALUE reader_container = rb_iv_get(self, "@reader"); if (reader_container == Qnil) { return Qfalse; } MYSQL_RES *reader = DATA_PTR(reader_container); if(!reader) { return Qfalse; } MYSQL_ROW result = mysql_fetch_row(reader); // The Meat VALUE field_types = rb_iv_get(self, "@field_types"); VALUE row = rb_ary_new(); unsigned long *lengths = mysql_fetch_lengths(reader); rb_iv_set(self, "@opened", result ? Qtrue : Qfalse); if (!result) { return Qfalse; } int enc = -1; #ifdef HAVE_RUBY_ENCODING_H VALUE encoding_id = rb_iv_get(rb_iv_get(self, "@connection"), "@encoding_id"); if (encoding_id != Qnil) { enc = FIX2INT(encoding_id); } #endif VALUE field_type; unsigned int i; for (i = 0; i < reader->field_count; i++) { // The field_type data could be cached in a c-array field_type = rb_ary_entry(field_types, i); rb_ary_push(row, do_mysql_typecast(result[i], lengths[i], field_type, enc)); } rb_iv_set(self, "@values", row); return Qtrue; } void Init_do_mysql() { data_objects_common_init(); // Top Level Module that all the classes live under mDO_Mysql = rb_define_module_under(mDO, "Mysql"); mDO_MysqlEncoding = rb_define_module_under(mDO_Mysql, "Encoding"); cDO_MysqlConnection = rb_define_class_under(mDO_Mysql, "Connection", cDO_Connection); rb_define_method(cDO_MysqlConnection, "initialize", do_mysql_cConnection_initialize, 1); rb_define_method(cDO_MysqlConnection, "using_socket?", data_objects_cConnection_is_using_socket, 0); rb_define_method(cDO_MysqlConnection, "ssl_cipher", data_objects_cConnection_ssl_cipher, 0); rb_define_method(cDO_MysqlConnection, "character_set", data_objects_cConnection_character_set , 0); rb_define_method(cDO_MysqlConnection, "dispose", do_mysql_cConnection_dispose, 0); rb_define_method(cDO_MysqlConnection, "quote_string", do_mysql_cConnection_quote_string, 1); rb_define_method(cDO_MysqlConnection, "quote_date", data_objects_cConnection_quote_date, 1); rb_define_method(cDO_MysqlConnection, "quote_time", data_objects_cConnection_quote_time, 1); rb_define_method(cDO_MysqlConnection, "quote_datetime", data_objects_cConnection_quote_date_time, 1); cDO_MysqlCommand = rb_define_class_under(mDO_Mysql, "Command", cDO_Command); rb_define_method(cDO_MysqlCommand, "set_types", data_objects_cCommand_set_types, -1); rb_define_method(cDO_MysqlCommand, "execute_non_query", do_mysql_cCommand_execute_non_query, -1); rb_define_method(cDO_MysqlCommand, "execute_reader", do_mysql_cCommand_execute_reader, -1); // Non-Query result cDO_MysqlResult = rb_define_class_under(mDO_Mysql, "Result", cDO_Result); // Query result cDO_MysqlReader = rb_define_class_under(mDO_Mysql, "Reader", cDO_Reader); rb_define_method(cDO_MysqlReader, "close", do_mysql_cReader_close, 0); rb_define_method(cDO_MysqlReader, "next!", do_mysql_cReader_next, 0); rb_define_method(cDO_MysqlReader, "values", data_objects_cReader_values, 0); rb_define_method(cDO_MysqlReader, "fields", data_objects_cReader_fields, 0); rb_define_method(cDO_MysqlReader, "field_count", data_objects_cReader_field_count, 0); rb_global_variable(&cDO_MysqlResult); rb_global_variable(&cDO_MysqlReader); data_objects_define_errors(mDO_Mysql, do_mysql_errors); } do_mysql-0.10.17/ext/do_mysql/mysql_compat.h0000644000004100000410000000224513305246414021054 0ustar www-datawww-data#ifdef HAVE_OLD_MYSQL_VERSION #define MYSQL_TYPE_VAR_STRING FIELD_TYPE_VAR_STRING #define MYSQL_TYPE_STRING FIELD_TYPE_STRING #define MYSQL_TYPE_NEWDECIMAL FIELD_TYPE_DECIMAL #define MYSQL_TYPE_SHORT FIELD_TYPE_SHORT #define MYSQL_TYPE_LONG FIELD_TYPE_LONG #define MYSQL_TYPE_FLOAT FIELD_TYPE_FLOAT #define MYSQL_TYPE_DOUBLE FIELD_TYPE_DOUBLE #define MYSQL_TYPE_LONGLONG FIELD_TYPE_LONGLONG #define MYSQL_TYPE_INT24 FIELD_TYPE_INT24 #define MYSQL_TYPE_YEAR FIELD_TYPE_YEAR #define MYSQL_TYPE_TINY FIELD_TYPE_TINY #define MYSQL_TYPE_TINY_BLOB FIELD_TYPE_TINY_BLOB #define MYSQL_TYPE_MEDIUM_BLOB FIELD_TYPE_MEDIUM_BLOB #define MYSQL_TYPE_LONG_BLOB FIELD_TYPE_LONG_BLOB #define MYSQL_TYPE_BLOB FIELD_TYPE_BLOB #define MYSQL_TYPE_DATE FIELD_TYPE_DATE #define MYSQL_TYPE_NEWDATE FIELD_TYPE_NEWDATE #define MYSQL_TYPE_DATETIME FIELD_TYPE_DATETIME #define MYSQL_TYPE_TIME FIELD_TYPE_TIME #define MYSQL_TYPE_TIMESTAMP FIELD_TYPE_TIMESTAMP #define MYSQL_TYPE_ENUM FIELD_TYPE_ENUM #define MYSQL_TYPE_SET FIELD_TYPE_SET #define MYSQL_TYPE_NULL FIELD_TYPE_NULL #endif do_mysql-0.10.17/ext/do_mysql/compat.h0000644000004100000410000000165313305246414017631 0ustar www-datawww-data#ifndef RUBY_COMPAT_H #define RUBY_COMPAT_H /* * Rules for better ruby C extensions: * * Never use the R macros directly, always use R_ * * Never compare with RBASIC(obj)->klass, always use * rb_obj_is_instance_of() * * Never use RHASH(obj)->tbl or RHASH_TBL(). * */ // Array #ifndef RARRAY_PTR #define RARRAY_PTR(obj) RARRAY(obj)->ptr #endif #ifndef RARRAY_LEN #define RARRAY_LEN(obj) RARRAY(obj)->len #endif // String #ifndef RSTRING_PTR #define RSTRING_PTR(obj) RSTRING(obj)->ptr #endif #ifndef RSTRING_LEN #define RSTRING_LEN(obj) RSTRING(obj)->len #endif #ifndef rb_str_ptr #define rb_str_ptr(str) RSTRING_PTR(str) #endif #ifndef rb_str_ptr_readonly #define rb_str_ptr_readonly(str) RSTRING_PTR(str) #endif #ifndef rb_str_flush #define rb_str_flush(str) #endif #ifndef rb_str_update #define rb_str_update(str) #endif #ifndef rb_str_len #define rb_str_len(str) RSTRING_LEN(str) #endif #endif do_mysql-0.10.17/ext/do_mysql/error.h0000644000004100000410000002606413305246414017502 0ustar www-datawww-data#ifndef _DO_MYSQL_ERROR_H_ #define _DO_MYSQL_ERROR_H_ #include "do_common.h" static struct errcodes do_mysql_errors[] = { #ifdef ER_ABORTING_CONNECTION ERRCODE(ER_ABORTING_CONNECTION, "ConnectionError"), #endif #ifdef ER_NET_PACKET_TOO_LARGE ERRCODE(ER_NET_PACKET_TOO_LARGE, "ConnectionError"), #endif #ifdef ER_NET_READ_ERROR_FROM_PIPE ERRCODE(ER_NET_READ_ERROR_FROM_PIPE, "ConnectionError"), #endif #ifdef ER_NET_FCNTL_ERROR ERRCODE(ER_NET_FCNTL_ERROR, "ConnectionError"), #endif #ifdef ER_NET_PACKETS_OUT_OF_ORDER ERRCODE(ER_NET_PACKETS_OUT_OF_ORDER, "ConnectionError"), #endif #ifdef ER_NET_UNCOMPRESS_ERROR ERRCODE(ER_NET_UNCOMPRESS_ERROR, "ConnectionError"), #endif #ifdef ER_NET_READ_ERROR ERRCODE(ER_NET_READ_ERROR, "ConnectionError"), #endif #ifdef ER_NET_READ_INTERRUPTED ERRCODE(ER_NET_READ_INTERRUPTED, "ConnectionError"), #endif #ifdef ER_NET_WRITE_INTERRUPTED ERRCODE(ER_NET_WRITE_INTERRUPTED, "ConnectionError"), #endif #ifdef ER_CON_COUNT_ERROR ERRCODE(ER_CON_COUNT_ERROR, "ConnectionError"), #endif #ifdef ER_BAD_HOST_ERROR ERRCODE(ER_BAD_HOST_ERROR, "ConnectionError"), #endif #ifdef ER_HANDSHAKE_ERROR ERRCODE(ER_HANDSHAKE_ERROR, "ConnectionError"), #endif #ifdef ER_DBACCESS_DENIED_ERROR ERRCODE(ER_DBACCESS_DENIED_ERROR, "ConnectionError"), #endif #ifdef ER_ACCESS_DENIED_ERROR ERRCODE(ER_ACCESS_DENIED_ERROR, "ConnectionError"), #endif #ifdef ER_UNKNOWN_COM_ERROR ERRCODE(ER_UNKNOWN_COM_ERROR, "ConnectionError"), #endif #ifdef ER_SERVER_SHUTDOWN ERRCODE(ER_SERVER_SHUTDOWN, "ConnectionError"), #endif #ifdef ER_FORCING_CLOSE ERRCODE(ER_FORCING_CLOSE, "ConnectionError"), #endif #ifdef ER_IPSOCK_ERROR ERRCODE(ER_IPSOCK_ERROR, "ConnectionError"), #endif #ifdef ER_INVALID_USE_OF_NULL ERRCODE(ER_INVALID_USE_OF_NULL, "DataError"), #endif #ifdef ER_DIVISION_BY_ZERO ERRCODE(ER_DIVISION_BY_ZERO, "DataError"), #endif #ifdef ER_ILLEGAL_VALUE_FOR_TYPE ERRCODE(ER_ILLEGAL_VALUE_FOR_TYPE, "DataError"), #endif #ifdef ER_WARN_NULL_TO_NOTNULL ERRCODE(ER_WARN_NULL_TO_NOTNULL, "DataError"), #endif #ifdef ER_WARN_DATA_OUT_OF_RANGE ERRCODE(ER_WARN_DATA_OUT_OF_RANGE, "DataError"), #endif #ifdef ER_WARN_TOO_MANY_RECORDS ERRCODE(ER_WARN_TOO_MANY_RECORDS, "DataError"), #endif #ifdef ER_WARN_TOO_FEW_RECORDS ERRCODE(ER_WARN_TOO_FEW_RECORDS, "DataError"), #endif #ifdef ER_TRUNCATED_WRONG_VALUE ERRCODE(ER_TRUNCATED_WRONG_VALUE, "DataError"), #endif #ifdef ER_DATETIME_FUNCTION_OVERFLOW ERRCODE(ER_DATETIME_FUNCTION_OVERFLOW, "DataError"), #endif #ifdef ER_DATA_TOO_LONG ERRCODE(ER_DATA_TOO_LONG, "DataError"), #endif #ifdef ER_UNKNOWN_TIME_ZONE ERRCODE(ER_UNKNOWN_TIME_ZONE, "DataError"), #endif #ifdef ER_INVALID_CHARACTER_STRING ERRCODE(ER_INVALID_CHARACTER_STRING, "DataError"), #endif #ifdef ER_WARN_INVALID_TIMESTAMP ERRCODE(ER_WARN_INVALID_TIMESTAMP, "DataError"), #endif #ifdef ER_CANT_CREATE_GEOMETRY_OBJECT ERRCODE(ER_CANT_CREATE_GEOMETRY_OBJECT, "DataError"), #endif #ifdef ER_BAD_NULL_ERROR ERRCODE(ER_BAD_NULL_ERROR, "IntegrityError"), #endif #ifdef ER_NON_UNIQ_ERROR ERRCODE(ER_NON_UNIQ_ERROR, "IntegrityError"), #endif #ifdef ER_DUP_KEY ERRCODE(ER_DUP_KEY, "IntegrityError"), #endif #ifdef ER_DUP_ENTRY ERRCODE(ER_DUP_ENTRY, "IntegrityError"), #endif #ifdef ER_DUP_UNIQUE ERRCODE(ER_DUP_UNIQUE, "IntegrityError"), #endif #ifdef ER_NO_REFERENCED_ROW ERRCODE(ER_NO_REFERENCED_ROW, "IntegrityError"), #endif #ifdef ER_NO_REFERENCED_ROW_2 ERRCODE(ER_NO_REFERENCED_ROW_2, "IntegrityError"), #endif #ifdef ER_ROW_IS_REFERENCED ERRCODE(ER_ROW_IS_REFERENCED, "IntegrityError"), #endif #ifdef ER_ROW_IS_REFERENCED_2 ERRCODE(ER_ROW_IS_REFERENCED_2, "IntegrityError"), #endif #ifdef ER_BLOB_KEY_WITHOUT_LENGTH ERRCODE(ER_BLOB_KEY_WITHOUT_LENGTH, "SyntaxError"), #endif #ifdef ER_PRIMARY_CANT_HAVE_NULL ERRCODE(ER_PRIMARY_CANT_HAVE_NULL, "SyntaxError"), #endif #ifdef ER_TOO_MANY_ROWS ERRCODE(ER_TOO_MANY_ROWS, "SyntaxError"), #endif #ifdef ER_REQUIRES_PRIMARY_KEY ERRCODE(ER_REQUIRES_PRIMARY_KEY, "SyntaxError"), #endif #ifdef ER_CHECK_NO_SUCH_TABLE ERRCODE(ER_CHECK_NO_SUCH_TABLE, "SyntaxError"), #endif #ifdef ER_CHECK_NOT_IMPLEMENTED ERRCODE(ER_CHECK_NOT_IMPLEMENTED, "SyntaxError"), #endif #ifdef ER_TOO_MANY_USER_CONNECTIONS ERRCODE(ER_TOO_MANY_USER_CONNECTIONS, "SyntaxError"), #endif #ifdef ER_NO_PERMISSION_TO_CREATE_USER ERRCODE(ER_NO_PERMISSION_TO_CREATE_USER, "SyntaxError"), #endif #ifdef ER_USER_LIMIT_REACHED ERRCODE(ER_USER_LIMIT_REACHED, "SyntaxError"), #endif #ifdef ER_SPECIFIC_ACCESS_DENIED_ERROR ERRCODE(ER_SPECIFIC_ACCESS_DENIED_ERROR, "SyntaxError"), #endif #ifdef ER_NO_DEFAULT ERRCODE(ER_NO_DEFAULT, "SyntaxError"), #endif #ifdef ER_WRONG_VALUE_FOR_VAR ERRCODE(ER_WRONG_VALUE_FOR_VAR, "SyntaxError"), #endif #ifdef ER_WRONG_TYPE_FOR_VAR ERRCODE(ER_WRONG_TYPE_FOR_VAR, "SyntaxError"), #endif #ifdef ER_CANT_USE_OPTION_HERE ERRCODE(ER_CANT_USE_OPTION_HERE, "SyntaxError"), #endif #ifdef ER_NOT_SUPPORTED_YET ERRCODE(ER_NOT_SUPPORTED_YET, "SyntaxError"), #endif #ifdef ER_WRONG_FK_DEF ERRCODE(ER_WRONG_FK_DEF, "SyntaxError"), #endif #ifdef ER_ILLEGAL_REFERENCE ERRCODE(ER_ILLEGAL_REFERENCE, "SyntaxError"), #endif #ifdef ER_DERIVED_MUST_HAVE_ALIAS ERRCODE(ER_DERIVED_MUST_HAVE_ALIAS, "SyntaxError"), #endif #ifdef ER_TABLENAME_NOT_ALLOWED_HERE ERRCODE(ER_TABLENAME_NOT_ALLOWED_HERE, "SyntaxError"), #endif #ifdef ER_SPATIAL_CANT_HAVE_NULL ERRCODE(ER_SPATIAL_CANT_HAVE_NULL, "SyntaxError"), #endif #ifdef ER_COLLATION_CHARSET_MISMATCH ERRCODE(ER_COLLATION_CHARSET_MISMATCH, "SyntaxError"), #endif #ifdef ER_WRONG_NAME_FOR_INDEX ERRCODE(ER_WRONG_NAME_FOR_INDEX, "SyntaxError"), #endif #ifdef ER_WRONG_NAME_FOR_CATALOG ERRCODE(ER_WRONG_NAME_FOR_CATALOG, "SyntaxError"), #endif #ifdef ER_UNKNOWN_STORAGE_ENGINE ERRCODE(ER_UNKNOWN_STORAGE_ENGINE, "SyntaxError"), #endif #ifdef ER_SP_ALREADY_EXISTS ERRCODE(ER_SP_ALREADY_EXISTS, "SyntaxError"), #endif #ifdef ER_SP_DOES_NOT_EXIST ERRCODE(ER_SP_DOES_NOT_EXIST, "SyntaxError"), #endif #ifdef ER_SP_LILABEL_MISMATCH ERRCODE(ER_SP_LILABEL_MISMATCH, "SyntaxError"), #endif #ifdef ER_SP_LABEL_REDEFINE ERRCODE(ER_SP_LABEL_REDEFINE, "SyntaxError"), #endif #ifdef ER_SP_LABEL_MISMATCH ERRCODE(ER_SP_LABEL_MISMATCH, "SyntaxError"), #endif #ifdef ER_SP_BADRETURN ERRCODE(ER_SP_BADRETURN, "SyntaxError"), #endif #ifdef ER_SP_WRONG_NO_OF_ARGS ERRCODE(ER_SP_WRONG_NO_OF_ARGS, "SyntaxError"), #endif #ifdef ER_SP_COND_MISMATCH ERRCODE(ER_SP_COND_MISMATCH, "SyntaxError"), #endif #ifdef ER_SP_NORETURN ERRCODE(ER_SP_NORETURN, "SyntaxError"), #endif #ifdef ER_SP_BAD_CURSOR_QUERY ERRCODE(ER_SP_BAD_CURSOR_QUERY, "SyntaxError"), #endif #ifdef ER_SP_BAD_CURSOR_SELECT ERRCODE(ER_SP_BAD_CURSOR_SELECT, "SyntaxError"), #endif #ifdef ER_SP_CURSOR_MISMATCH ERRCODE(ER_SP_CURSOR_MISMATCH, "SyntaxError"), #endif #ifdef ER_SP_UNDECLARED_VAR ERRCODE(ER_SP_UNDECLARED_VAR, "SyntaxError"), #endif #ifdef ER_SP_DUP_PARAM ERRCODE(ER_SP_DUP_PARAM, "SyntaxError"), #endif #ifdef ER_SP_DUP_VAR ERRCODE(ER_SP_DUP_VAR, "SyntaxError"), #endif #ifdef ER_SP_DUP_COND ERRCODE(ER_SP_DUP_COND, "SyntaxError"), #endif #ifdef ER_SP_DUP_CURS ERRCODE(ER_SP_DUP_CURS, "SyntaxError"), #endif #ifdef ER_SP_VARCOND_AFTER_CURSHNDLR ERRCODE(ER_SP_VARCOND_AFTER_CURSHNDLR, "SyntaxError"), #endif #ifdef ER_SP_CURSOR_AFTER_HANDLER ERRCODE(ER_SP_CURSOR_AFTER_HANDLER, "SyntaxError"), #endif #ifdef ER_SP_CASE_NOT_FOUND ERRCODE(ER_SP_CASE_NOT_FOUND, "SyntaxError"), #endif #ifdef ER_PROCACCESS_DENIED_ERROR ERRCODE(ER_PROCACCESS_DENIED_ERROR, "SyntaxError"), #endif #ifdef ER_NONEXISTING_PROC_GRANT ERRCODE(ER_NONEXISTING_PROC_GRANT, "SyntaxError"), #endif #ifdef ER_SP_BAD_SQLSTATE ERRCODE(ER_SP_BAD_SQLSTATE, "SyntaxError"), #endif #ifdef ER_CANT_CREATE_USER_WITH_GRANT ERRCODE(ER_CANT_CREATE_USER_WITH_GRANT, "SyntaxError"), #endif #ifdef ER_SP_DUP_HANDLER ERRCODE(ER_SP_DUP_HANDLER, "SyntaxError"), #endif #ifdef ER_SP_NOT_VAR_ARG ERRCODE(ER_SP_NOT_VAR_ARG, "SyntaxError"), #endif #ifdef ER_TOO_BIG_SCALE ERRCODE(ER_TOO_BIG_SCALE, "SyntaxError"), #endif #ifdef ER_TOO_BIG_PRECISION ERRCODE(ER_TOO_BIG_PRECISION, "SyntaxError"), #endif #ifdef ER_M_BIGGER_THAN_D ERRCODE(ER_M_BIGGER_THAN_D, "SyntaxError"), #endif #ifdef ER_TOO_LONG_BODY ERRCODE(ER_TOO_LONG_BODY, "SyntaxError"), #endif #ifdef ER_TOO_BIG_DISPLAYWIDTH ERRCODE(ER_TOO_BIG_DISPLAYWIDTH, "SyntaxError"), #endif #ifdef ER_SP_BAD_VAR_SHADOW ERRCODE(ER_SP_BAD_VAR_SHADOW, "SyntaxError"), #endif #ifdef ER_SP_WRONG_NAME ERRCODE(ER_SP_WRONG_NAME, "SyntaxError"), #endif #ifdef ER_SP_NO_AGGREGATE ERRCODE(ER_SP_NO_AGGREGATE, "SyntaxError"), #endif #ifdef ER_MAX_PREPARED_STMT_COUNT_REACHED ERRCODE(ER_MAX_PREPARED_STMT_COUNT_REACHED, "SyntaxError"), #endif #ifdef ER_NON_GROUPING_FIELD_USED ERRCODE(ER_NON_GROUPING_FIELD_USED, "SyntaxError"), #endif #ifdef ER_BAD_DB_ERROR ERRCODE(ER_BAD_DB_ERROR, "SyntaxError"), #endif #ifdef ER_TABLE_EXISTS_ERROR ERRCODE(ER_TABLE_EXISTS_ERROR, "SyntaxError"), #endif #ifdef ER_BAD_TABLE_ERROR ERRCODE(ER_BAD_TABLE_ERROR, "SyntaxError"), #endif #ifdef ER_NO_SUCH_TABLE ERRCODE(ER_NO_SUCH_TABLE, "SyntaxError"), #endif #ifdef ER_NONEXISTING_TABLE_GRANT ERRCODE(ER_NONEXISTING_TABLE_GRANT, "SyntaxError"), #endif #ifdef ER_GRANT_WRONG_HOST_OR_USER ERRCODE(ER_GRANT_WRONG_HOST_OR_USER, "SyntaxError"), #endif #ifdef ER_ILLEGAL_GRANT_FOR_TABLE ERRCODE(ER_ILLEGAL_GRANT_FOR_TABLE, "SyntaxError"), #endif #ifdef ER_COLUMNACCESS_DENIED_ERROR ERRCODE(ER_COLUMNACCESS_DENIED_ERROR, "SyntaxError"), #endif #ifdef ER_TABLEACCESS_DENIED_ERROR ERRCODE(ER_TABLEACCESS_DENIED_ERROR, "SyntaxError"), #endif #ifdef ER_NONEXISTING_GRANT ERRCODE(ER_NONEXISTING_GRANT, "SyntaxError"), #endif #ifdef ER_MIX_OF_GROUP_FUNC_AND_FIELDS ERRCODE(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, "SyntaxError"), #endif #ifdef ER_REGEXP_ERROR ERRCODE(ER_REGEXP_ERROR, "SyntaxError"), #endif #ifdef ER_NOT_ALLOWED_COMMAND ERRCODE(ER_NOT_ALLOWED_COMMAND, "SyntaxError"), #endif #ifdef ER_SYNTAX_ERROR ERRCODE(ER_SYNTAX_ERROR, "SyntaxError"), #endif #ifdef ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT ERRCODE(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, "SyntaxError"), #endif #ifdef ER_CANT_DO_THIS_DURING_AN_TRANSACTION ERRCODE(ER_CANT_DO_THIS_DURING_AN_TRANSACTION, "TransactionError"), #endif #ifdef ER_ERROR_DURING_COMMIT ERRCODE(ER_ERROR_DURING_COMMIT, "TransactionError"), #endif #ifdef ER_ERROR_DURING_ROLLBACK ERRCODE(ER_ERROR_DURING_ROLLBACK, "TransactionError"), #endif #ifdef ER_ERROR_DURING_CHECKPOINT ERRCODE(ER_ERROR_DURING_CHECKPOINT, "TransactionError"), #endif #ifdef ER_LOCK_DEADLOCK ERRCODE(ER_LOCK_DEADLOCK, "TransactionError"), #endif #ifdef ER_XAER_NOTA ERRCODE(ER_XAER_NOTA, "TransactionError"), #endif #ifdef ER_XAER_INVAL ERRCODE(ER_XAER_INVAL, "TransactionError"), #endif #ifdef ER_XAER_RMFAIL ERRCODE(ER_XAER_RMFAIL, "TransactionError"), #endif #ifdef ER_XAER_OUTSIDE ERRCODE(ER_XAER_OUTSIDE, "TransactionError"), #endif #ifdef ER_XAER_RMERR ERRCODE(ER_XAER_RMERR, "TransactionError"), #endif #ifdef ER_XA_RBROLLBACK ERRCODE(ER_XA_RBROLLBACK, "TransactionError"), #endif #ifdef ER_XA_RBTIMEOUT ERRCODE(ER_XA_RBTIMEOUT, "TransactionError"), #endif #ifdef ER_XA_RBDEADLOCK ERRCODE(ER_XA_RBDEADLOCK, "TransactionError"), #endif {0, NULL, NULL} }; #endif do_mysql-0.10.17/ext/do_mysql/extconf.rb0000644000004100000410000000540013305246414020162 0ustar www-datawww-dataENV["RC_ARCHS"] = "" if RUBY_PLATFORM =~ /darwin/ require 'mkmf' require 'date' # Allow for custom compiler to be specified. RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC'] # All instances of mysql_config on PATH ... def mysql_config_paths ENV['PATH'].split(File::PATH_SEPARATOR).collect do |path| [ "#{path}/mysql_config", "#{path}/mysql_config5" ]. detect { |bin| File.exist?(bin) } end end # The first mysql_config binary on PATH ... def default_mysql_config_path mysql_config_paths.compact.first end def mysql_config(type) IO.popen("#{default_mysql_config_path} --#{type}").readline.chomp rescue nil end def default_prefix if mc = default_mysql_config_path File.dirname(File.dirname(mc)) else "/usr/local" end end # Allow overriding path to mysql_config on command line using: # ruby extconf.rb --with-mysql-config=/path/to/mysql_config if RUBY_PLATFORM =~ /mswin|mingw/ dir_config('mysql') have_header 'my_global.h' have_header 'mysql.h' have_library 'libmysql' have_func('mysql_query', 'mysql.h') have_func('mysql_ssl_set', 'mysql.h') elsif mc = with_config('mysql-config', default_mysql_config_path) includes = mysql_config('include').split(/\s+/).map do |dir| dir.gsub(/^-I/, "") end.uniq libs = mysql_config('libs').split(/\s+/).select {|lib| lib =~ /^-L/}.map do |dir| dir.gsub(/^-L/, "") end.uniq linked = mysql_config('libs').split(/\s+/).select {|lib| lib =~ /^-l/}.map do |dir| dir.gsub(/^-l/, "") end.uniq dir_config('mysql', includes, libs) linked.each do |link| have_library link end else inc, lib = dir_config('mysql', default_prefix) libs = ['m', 'z', 'socket', 'nsl'] lib_dirs = [ lib, "/usr/lib", "/usr/local/lib", "/opt/local/lib" ].collect do |path| [ path, "#{path}/mysql", "#{path}/mysql5/mysql" ] end find_library('mysqlclient', 'mysql_query', *lib_dirs.flatten) || exit(1) find_header('mysql.h', *lib_dirs.flatten.map { |p| p.gsub('/lib', '/include') }) end have_func('localtime_r') have_func('gmtime_r') have_header 'mysql.h' have_const 'MYSQL_TYPE_STRING', 'mysql.h' have_const 'MYSQL_TYPE_BIT', 'mysql.h' have_const 'MYSQL_TYPE_NEWDECIMAL', 'mysql.h' have_func 'mysql_query', 'mysql.h' have_func 'mysql_ssl_set', 'mysql.h' have_func 'mysql_sqlstate', 'mysql.h' have_func 'mysql_get_ssl_cipher', 'mysql.h' have_func 'mysql_set_character_set', 'mysql.h' have_func 'mysql_get_server_version', 'mysql.h' have_func 'mysql_real_escape_string_quote', 'mysql.h' have_struct_member 'MYSQL_FIELD', 'charsetnr', 'mysql.h' have_func('rb_thread_fd_select') unless DateTime.respond_to?(:new!) $CFLAGS << ' -DHAVE_NO_DATETIME_NEWBANG' end $CFLAGS << ' -Wall ' if RUBY_VERSION < '1.8.6' $CFLAGS << ' -DRUBY_LESS_THAN_186' end create_makefile('do_mysql/do_mysql') do_mysql-0.10.17/ext/do_mysql/do_common.c0000644000004100000410000003404113305246414020310 0ustar www-datawww-data#include #include #include #include #include #ifndef _WIN32 #include #endif #include "do_common.h" /* * Common variables ("globals") */ // To store rb_intern values ID DO_ID_NEW; ID DO_ID_NEW_DATE; ID DO_ID_CONST_GET; ID DO_ID_RATIONAL; ID DO_ID_ESCAPE; ID DO_ID_STRFTIME; ID DO_ID_LOG; // Reference to Extlib module VALUE mExtlib; VALUE rb_cByteArray; // References to DataObjects base classes VALUE mDO; VALUE cDO_Quoting; VALUE cDO_Connection; VALUE cDO_Command; VALUE cDO_Result; VALUE cDO_Reader; VALUE cDO_Logger; VALUE cDO_Logger_Message; VALUE cDO_Extension; VALUE eDO_ConnectionError; VALUE eDO_DataError; // References to Ruby classes that we'll need VALUE rb_cDate; VALUE rb_cDateTime; VALUE rb_cBigDecimal; /* * Common Functions */ VALUE data_objects_const_get(VALUE scope, const char *constant) { return rb_funcall(scope, DO_ID_CONST_GET, 1, rb_str_new2(constant)); } void data_objects_debug(VALUE connection, VALUE string, struct timeval *start) { struct timeval stop; VALUE message; do_int64 duration; gettimeofday(&stop, NULL); duration = (stop.tv_sec - start->tv_sec) * 1000000 + stop.tv_usec - start->tv_usec; message = rb_funcall(cDO_Logger_Message, DO_ID_NEW, 3, string, rb_time_new(start->tv_sec, start->tv_usec), INT2NUM(duration)); rb_funcall(connection, DO_ID_LOG, 1, message); } void data_objects_raise_error(VALUE self, const struct errcodes *errors, int errnum, VALUE message, VALUE query, VALUE state) { const char *exception_type = "SQLError"; const struct errcodes *e; VALUE uri, exception; for (e = errors; e->error_name; e++) { if (e->error_no == errnum) { // return the exception type for the matching error exception_type = e->exception; break; } } uri = rb_funcall(rb_iv_get(self, "@connection"), rb_intern("to_s"), 0); exception = rb_funcall( data_objects_const_get(mDO, exception_type), DO_ID_NEW, 5, message, INT2NUM(errnum), state, query, uri ); rb_exc_raise(exception); } char *data_objects_get_uri_option(VALUE query_hash, const char *key) { VALUE query_value; char *value = NULL; if (!rb_obj_is_kind_of(query_hash, rb_cHash)) { return NULL; } query_value = rb_hash_aref(query_hash, rb_str_new2(key)); if (Qnil != query_value) { value = StringValuePtr(query_value); } return value; } void data_objects_assert_file_exists(char *file, const char *message) { if (file) { if (rb_funcall(rb_cFile, rb_intern("exist?"), 1, rb_str_new2(file)) == Qfalse) { rb_raise(rb_eArgError, "%s", message); } } } VALUE data_objects_build_query_from_args(VALUE klass, int count, VALUE *args) { int i; VALUE array = rb_ary_new(); for (i = 0; i < count; i++) { rb_ary_push(array, args[i]); } return rb_funcall(klass, DO_ID_ESCAPE, 1, array); } // Find the greatest common denominator and reduce the provided numerator and denominator. // This replaces calles to Rational.reduce! which does the same thing, but really slowly. void data_objects_reduce(do_int64 *numerator, do_int64 *denominator) { do_int64 a = *numerator, b = *denominator, c; while (a != 0) { c = a; a = b % a; b = c; } *numerator /= b; *denominator /= b; } // Generate the date integer which Date.civil_to_jd returns int data_objects_jd_from_date(int year, int month, int day) { int a, b; if (month <= 2) { year -= 1; month += 12; } a = year / 100; b = 2 - a + (a / 4); return (int)(floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524); } VALUE data_objects_seconds_to_offset(long seconds_offset) { do_int64 num = seconds_offset; do_int64 den = 86400; data_objects_reduce(&num, &den); return rb_funcall(rb_mKernel, DO_ID_RATIONAL, 2, rb_ll2inum(num), rb_ll2inum(den)); } VALUE data_objects_timezone_to_offset(int hour_offset, int minute_offset) { do_int64 seconds = 0; seconds += hour_offset * 3600; seconds += minute_offset * 60; return data_objects_seconds_to_offset(seconds); } VALUE data_objects_parse_date(const char *date) { static char const *const _fmt_date = "%4d-%2d-%2d"; int year = 0, month = 0, day = 0; switch (sscanf(date, _fmt_date, &year, &month, &day)) { case 0: case EOF: return Qnil; } if(!year && !month && !day) { return Qnil; } return rb_funcall(rb_cDate, DO_ID_NEW, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day)); } VALUE data_objects_parse_time(const char *date) { static char const* const _fmt_datetime = "%4d-%2d-%2d%*c%2d:%2d:%2d%7lf"; int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, usec = 0; double subsec = 0; switch (sscanf(date, _fmt_datetime, &year, &month, &day, &hour, &min, &sec, &subsec)) { case 0: case EOF: return Qnil; } usec = (int) (subsec * 1000000); /* Mysql TIMESTAMPS can default to 0 */ if ((year + month + day + hour + min + sec + usec) == 0) { return Qnil; } return rb_funcall(rb_cTime, rb_intern("local"), 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec)); } VALUE data_objects_parse_date_time(const char *date) { static char const* const _fmt_datetime_tz_normal = "%4d-%2d-%2d%*c%2d:%2d:%2d%3d:%2d"; static char const* const _fmt_datetime_tz_subsec = "%4d-%2d-%2d%*c%2d:%2d:%2d.%*d%3d:%2d"; int tokens_read; const char *fmt_datetime; VALUE offset; int year, month, day, hour, min, sec, hour_offset, minute_offset; struct tm timeinfo; time_t target_time; time_t gmt_offset; int dst_adjustment; if (*date == '\0') { return Qnil; } /* * We handle the following cases: * - Date (default to midnight) [3 tokens, missing 5] * - DateTime [6 tokens, missing 2] * - DateTime with hour, possibly minute TZ offset [7-8 tokens] */ fmt_datetime = strchr(date, '.') ? _fmt_datetime_tz_subsec : _fmt_datetime_tz_normal; tokens_read = sscanf(date, fmt_datetime, &year, &month, &day, &hour, &min, &sec, &hour_offset, &minute_offset); if(!year && !month && !day && !hour && !min && !sec) { return Qnil; } switch (tokens_read) { case 8: minute_offset *= hour_offset < 0 ? -1 : 1; break; case 7: /* Only got TZ hour offset, so assume 0 for minute */ minute_offset = 0; break; case 3: /* Only got Date */ hour = 0; min = 0; sec = 0; /* Fall through */ case 6: /* Only got DateTime */ /* * Interpret the DateTime from the local system TZ. If target date would * end up in DST, assume adjustment of a 1 hour shift. * * FIXME: The DST adjustment calculation won't be accurate for timezones * that observe fractional-hour shifts. But that's a real minority for * now.. */ timeinfo.tm_year = year - 1900; timeinfo.tm_mon = month - 1; // 0 - 11 timeinfo.tm_mday = day; timeinfo.tm_hour = hour; timeinfo.tm_min = min; timeinfo.tm_sec = sec; timeinfo.tm_isdst = -1; target_time = mktime(&timeinfo); dst_adjustment = timeinfo.tm_isdst ? 3600 : 0; /* * Now figure out seconds from UTC. For that we need a UTC/GMT-adjusted * time_t, which we get from mktime(gmtime(current_time)). * * NOTE: Some modern libc's have tm_gmtoff in struct tm, but we can't count * on that. */ #ifdef HAVE_GMTIME_R gmtime_r(&target_time, &timeinfo); #else timeinfo = *gmtime(&target_time); #endif gmt_offset = target_time - mktime(&timeinfo) + dst_adjustment; hour_offset = ((int)gmt_offset / 3600); minute_offset = ((int)gmt_offset % 3600 / 60); break; default: /* Any other combo of missing tokens and we can't do anything */ rb_raise(eDO_DataError, "Couldn't parse date: %s", date); } offset = data_objects_timezone_to_offset(hour_offset, minute_offset); return rb_funcall(rb_cDateTime, DO_ID_NEW, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), offset); } VALUE data_objects_cConnection_character_set(VALUE self) { return rb_iv_get(self, "@encoding"); } VALUE data_objects_cConnection_is_using_socket(VALUE self) { return rb_iv_get(self, "@using_socket"); } VALUE data_objects_cConnection_ssl_cipher(VALUE self) { return rb_iv_get(self, "@ssl_cipher"); } VALUE data_objects_cConnection_quote_time(VALUE self, VALUE value) { return rb_funcall(value, DO_ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d %H:%M:%S'")); } VALUE data_objects_cConnection_quote_date_time(VALUE self, VALUE value) { // TODO: Support non-local dates. we need to call #new_offset on the date to be // quoted and pass in the current locale's date offset (self.new_offset((hours * 3600).to_r / 86400) return rb_funcall(value, DO_ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d %H:%M:%S'")); } VALUE data_objects_cConnection_quote_date(VALUE self, VALUE value) { return rb_funcall(value, DO_ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d'")); } /* * Accepts an array of Ruby types (Fixnum, Float, String, etc...) and turns them * into Ruby-strings so we can easily typecast later */ VALUE data_objects_cCommand_set_types(int argc, VALUE *argv, VALUE self) { VALUE entry, sub_entry; int i, j; VALUE type_strings = rb_ary_new(); VALUE array = rb_ary_new(); for (i = 0; i < argc; i++) { rb_ary_push(array, argv[i]); } for (i = 0; i < RARRAY_LEN(array); i++) { entry = rb_ary_entry(array, i); if (TYPE(entry) == T_CLASS) { rb_ary_push(type_strings, entry); } else if (TYPE(entry) == T_ARRAY) { for (j = 0; j < RARRAY_LEN(entry); j++) { sub_entry = rb_ary_entry(entry, j); if (TYPE(sub_entry) == T_CLASS) { rb_ary_push(type_strings, sub_entry); } else { rb_raise(rb_eArgError, "Invalid type given"); } } } else { rb_raise(rb_eArgError, "Invalid type given"); } } rb_iv_set(self, "@field_types", type_strings); return array; } VALUE data_objects_cReader_values(VALUE self) { VALUE state = rb_iv_get(self, "@opened"); VALUE values = rb_iv_get(self, "@values"); if (state == Qnil || state == Qfalse || values == Qnil) { rb_raise(eDO_DataError, "Reader is not initialized"); } return rb_iv_get(self, "@values"); } VALUE data_objects_cReader_fields(VALUE self) { return rb_iv_get(self, "@fields"); } VALUE data_objects_cReader_field_count(VALUE self) { return rb_iv_get(self, "@field_count"); } void data_objects_common_init(void) { rb_require("bigdecimal"); rb_require("rational"); rb_require("date"); rb_require("data_objects"); // Needed by data_objects_const_get DO_ID_CONST_GET = rb_intern("const_get"); // Get references classes needed for Date/Time parsing rb_cDate = data_objects_const_get(rb_mKernel, "Date"); rb_cDateTime = data_objects_const_get(rb_mKernel, "DateTime"); rb_cBigDecimal = data_objects_const_get(rb_mKernel, "BigDecimal"); DO_ID_NEW = rb_intern("new"); #ifdef RUBY_LESS_THAN_186 DO_ID_NEW_DATE = rb_intern("new0"); #else DO_ID_NEW_DATE = rb_intern("new!"); #endif DO_ID_CONST_GET = rb_intern("const_get"); DO_ID_RATIONAL = rb_intern("Rational"); DO_ID_ESCAPE = rb_intern("escape_sql"); DO_ID_STRFTIME = rb_intern("strftime"); DO_ID_LOG = rb_intern("log"); // Get references to the Extlib module mExtlib = data_objects_const_get(rb_mKernel, "Extlib"); rb_cByteArray = data_objects_const_get(mExtlib, "ByteArray"); // Get references to the DataObjects module and its classes mDO = data_objects_const_get(rb_mKernel, "DataObjects"); cDO_Quoting = data_objects_const_get(mDO, "Quoting"); cDO_Connection = data_objects_const_get(mDO, "Connection"); cDO_Command = data_objects_const_get(mDO, "Command"); cDO_Result = data_objects_const_get(mDO, "Result"); cDO_Reader = data_objects_const_get(mDO, "Reader"); cDO_Logger = data_objects_const_get(mDO, "Logger"); cDO_Logger_Message = data_objects_const_get(cDO_Logger, "Message"); cDO_Extension = data_objects_const_get(mDO, "Extension"); eDO_ConnectionError = data_objects_const_get(mDO, "ConnectionError"); eDO_DataError = data_objects_const_get(mDO, "DataError"); rb_global_variable(&DO_ID_NEW_DATE); rb_global_variable(&DO_ID_RATIONAL); rb_global_variable(&DO_ID_CONST_GET); rb_global_variable(&DO_ID_ESCAPE); rb_global_variable(&DO_ID_LOG); rb_global_variable(&DO_ID_NEW); rb_global_variable(&rb_cDate); rb_global_variable(&rb_cDateTime); rb_global_variable(&rb_cBigDecimal); rb_global_variable(&rb_cByteArray); rb_global_variable(&mDO); rb_global_variable(&cDO_Logger_Message); rb_global_variable(&eDO_ConnectionError); rb_global_variable(&eDO_DataError); tzset(); } /* * Common typecasting logic that can be used or overriden by Adapters. */ extern VALUE data_objects_typecast(const char *value, long length, const VALUE type, int encoding) { #ifdef HAVE_RUBY_ENCODING_H rb_encoding *internal_encoding = rb_default_internal_encoding(); #else void *internal_encoding = NULL; #endif if (type == rb_cInteger) { return rb_cstr2inum(value, 10); } else if (type == rb_cString) { return DATA_OBJECTS_STR_NEW(value, length, encoding, internal_encoding); } else if (type == rb_cFloat) { return rb_float_new(rb_cstr_to_dbl(value, Qfalse)); } else if (type == rb_cBigDecimal) { return rb_funcall(rb_cBigDecimal, DO_ID_NEW, 1, rb_str_new(value, length)); } else if (type == rb_cDate) { return data_objects_parse_date(value); } else if (type == rb_cDateTime) { return data_objects_parse_date_time(value); } else if (type == rb_cTime) { return data_objects_parse_time(value); } else if (type == rb_cTrueClass) { return (!value || strcmp("0", value) == 0) ? Qfalse : Qtrue; } else if (type == rb_cByteArray) { return rb_funcall(rb_cByteArray, DO_ID_NEW, 1, rb_str_new(value, length)); } else if (type == rb_cClass) { return rb_funcall(mDO, rb_intern("full_const_get"), 1, rb_str_new(value, length)); } else if (type == rb_cNilClass) { return Qnil; } else { return DATA_OBJECTS_STR_NEW(value, length, encoding, internal_encoding); } }