do_mysql-0.10.16/0000755000004100000410000000000012541410137013534 5ustar www-datawww-datado_mysql-0.10.16/Rakefile0000644000004100000410000000201612541410137015200 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.16/spec/0000755000004100000410000000000012541410137014466 5ustar www-datawww-datado_mysql-0.10.16/spec/typecast/0000755000004100000410000000000012541410137016322 5ustar www-datawww-datado_mysql-0.10.16/spec/typecast/byte_array_spec.rb0000644000004100000410000000040412541410137022020 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.16/spec/typecast/bigdecimal_spec.rb0000644000004100000410000000050212541410137021736 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.16/spec/typecast/nil_spec.rb0000644000004100000410000000053212541410137020443 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.16/spec/typecast/class_spec.rb0000644000004100000410000000036712541410137020774 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.16/spec/typecast/other_spec.rb0000644000004100000410000000042212541410137021000 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.16/spec/typecast/boolean_spec.rb0000644000004100000410000000046612541410137021306 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.16/spec/typecast/float_spec.rb0000644000004100000410000000045612541410137020773 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.16/spec/typecast/range_spec.rb0000644000004100000410000000036712541410137020763 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.16/spec/typecast/time_spec.rb0000644000004100000410000000036412541410137020622 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.16/spec/typecast/integer_spec.rb0000644000004100000410000000037512541410137021323 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.16/spec/typecast/string_spec.rb0000644000004100000410000000037212541410137021171 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.16/spec/typecast/datetime_spec.rb0000644000004100000410000000202012541410137021447 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.16/spec/typecast/date_spec.rb0000644000004100000410000000174212541410137020602 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.16/spec/typecast/array_spec.rb0000644000004100000410000000036712541410137021005 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.16/spec/encoding_spec.rb0000644000004100000410000000070112541410137017611 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' end do_mysql-0.10.16/spec/connection_spec.rb0000644000004100000410000000423112541410137020164 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.16/spec/spec_helper.rb0000644000004100000410000001741112541410137017310 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 `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 `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.16/spec/reader_spec.rb0000644000004100000410000000167612541410137017301 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.16/spec/result_spec.rb0000644000004100000410000000240512541410137017344 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.16/spec/error/0000755000004100000410000000000012541410137015617 5ustar www-datawww-datado_mysql-0.10.16/spec/error/sql_error_spec.rb0000644000004100000410000000040012541410137021160 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.16/spec/command_spec.rb0000644000004100000410000000041612541410137017444 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.16/lib/0000755000004100000410000000000012541410137014302 5ustar www-datawww-datado_mysql-0.10.16/lib/do_mysql.rb0000644000004100000410000000264712541410137016467 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.16/lib/do_mysql/0000755000004100000410000000000012541410137016131 5ustar www-datawww-datado_mysql-0.10.16/lib/do_mysql/encoding.rb0000644000004100000410000000224612541410137020250 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.16/lib/do_mysql/version.rb0000644000004100000410000000010412541410137020136 0ustar www-datawww-datamodule DataObjects module Mysql VERSION = '0.10.16' end end do_mysql-0.10.16/lib/do_mysql/transaction.rb0000644000004100000410000000142412541410137021004 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.16/README.markdown0000644000004100000410000000545312541410137016244 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.16/metadata.yml0000644000004100000410000000716712541410137016052 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: do_mysql version: !ruby/object:Gem::Version version: 0.10.16 platform: ruby authors: - Dirkjan Bussink autorequire: bindir: bin cert_chain: [] date: 2015-05-17 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: data_objects requirement: !ruby/object:Gem::Requirement requirements: - - '=' - !ruby/object:Gem::Version version: 0.10.16 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - '=' - !ruby/object:Gem::Version version: 0.10.16 - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '2.5' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '2.5' - !ruby/object:Gem::Dependency name: rake-compiler requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '0.7' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '0.7' description: Implements the DataObjects API for MySQL email: d.bussink@gmail.com executables: [] extensions: - ext/do_mysql/extconf.rb extra_rdoc_files: - ChangeLog.markdown - LICENSE - README.markdown files: - ChangeLog.markdown - LICENSE - README.markdown - Rakefile - ext/do_mysql/compat.h - ext/do_mysql/do_common.c - ext/do_mysql/do_common.h - ext/do_mysql/do_mysql.c - ext/do_mysql/error.h - ext/do_mysql/extconf.rb - ext/do_mysql/mysql_compat.h - lib/do_mysql.rb - lib/do_mysql/encoding.rb - lib/do_mysql/transaction.rb - lib/do_mysql/version.rb - spec/command_spec.rb - spec/connection_spec.rb - spec/encoding_spec.rb - spec/error/sql_error_spec.rb - spec/reader_spec.rb - spec/result_spec.rb - spec/spec_helper.rb - spec/typecast/array_spec.rb - spec/typecast/bigdecimal_spec.rb - spec/typecast/boolean_spec.rb - spec/typecast/byte_array_spec.rb - spec/typecast/class_spec.rb - spec/typecast/date_spec.rb - spec/typecast/datetime_spec.rb - spec/typecast/float_spec.rb - spec/typecast/integer_spec.rb - spec/typecast/nil_spec.rb - spec/typecast/other_spec.rb - spec/typecast/range_spec.rb - spec/typecast/string_spec.rb - spec/typecast/time_spec.rb - tasks/compile.rake - tasks/release.rake - tasks/retrieve.rake - tasks/spec.rake - tasks/ssl.rake homepage: licenses: [] metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: dorb rubygems_version: 2.0.14 signing_key: specification_version: 3 summary: DataObjects MySQL Driver test_files: - spec/command_spec.rb - spec/connection_spec.rb - spec/encoding_spec.rb - spec/error/sql_error_spec.rb - spec/reader_spec.rb - spec/result_spec.rb - spec/spec_helper.rb - spec/typecast/array_spec.rb - spec/typecast/bigdecimal_spec.rb - spec/typecast/boolean_spec.rb - spec/typecast/byte_array_spec.rb - spec/typecast/class_spec.rb - spec/typecast/date_spec.rb - spec/typecast/datetime_spec.rb - spec/typecast/float_spec.rb - spec/typecast/integer_spec.rb - spec/typecast/nil_spec.rb - spec/typecast/other_spec.rb - spec/typecast/range_spec.rb - spec/typecast/string_spec.rb - spec/typecast/time_spec.rb do_mysql-0.10.16/ChangeLog.markdown0000644000004100000410000000467512541410137017143 0ustar www-datawww-data## 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.16/tasks/0000755000004100000410000000000012541410137014661 5ustar www-datawww-datado_mysql-0.10.16/tasks/spec.rake0000644000004100000410000000052712541410137016463 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.16/tasks/ssl.rake0000644000004100000410000000153512541410137016332 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.16/tasks/release.rake0000644000004100000410000000075012541410137017147 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.5:2.2.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.16/tasks/retrieve.rake0000644000004100000410000000445112541410137017356 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.16/tasks/compile.rake0000644000004100000410000000461612541410137017164 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.16' end end rescue LoadError warn "To compile, install rake-compiler (gem install rake-compiler)" end do_mysql-0.10.16/LICENSE0000644000004100000410000000206712541410137014546 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.16/ext/0000755000004100000410000000000012541410137014334 5ustar www-datawww-datado_mysql-0.10.16/ext/do_mysql/0000755000004100000410000000000012541410137016163 5ustar www-datawww-datado_mysql-0.10.16/ext/do_mysql/do_common.c0000644000004100000410000003376512541410137020317 0ustar www-datawww-data#include #include #include #include #include #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); } } do_mysql-0.10.16/ext/do_mysql/do_common.h0000644000004100000410000001011212541410137020301 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.16/ext/do_mysql/extconf.rb0000644000004100000410000000531212541410137020157 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_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.16/ext/do_mysql/compat.h0000644000004100000410000000165312541410137017624 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.16/ext/do_mysql/error.h0000644000004100000410000002606412541410137017475 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.16/ext/do_mysql/do_mysql.c0000644000004100000410000004714712541410137020173 0ustar www-datawww-data#include #include #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; while (1) { rb_fd_init(&rset); rb_fd_set(socket_fd, &rset); retval = rb_thread_fd_select(socket_fd + 1, &rset, NULL, NULL, NULL); if (retval < 0) { rb_sys_fail(0); } if (retval == 0) { continue; } if (db->status == MYSQL_STATUS_READY) { break; } } 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 rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(rb_str_ptr_readonly(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' quoted_length = mysql_real_escape_string(db, escaped + 1, source, source_len); // 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.16/ext/do_mysql/mysql_compat.h0000644000004100000410000000224512541410137021047 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