aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
authorrick <technoweenie@gmail.com>2008-06-19 09:59:36 -0700
committerrick <technoweenie@gmail.com>2008-06-19 09:59:36 -0700
commit10c581a6deed66e8b62de6e7a3621a63de90baad (patch)
tree588ceb1118761602caa8ccf248dd08d59f33896c /activerecord/lib/active_record
parent64637da284ed4685591c178202ee103e6bee71cf (diff)
parent81025b5808886289f54d698f73f4199c99223e7e (diff)
downloadrails-10c581a6deed66e8b62de6e7a3621a63de90baad.tar.gz
rails-10c581a6deed66e8b62de6e7a3621a63de90baad.tar.bz2
rails-10c581a6deed66e8b62de6e7a3621a63de90baad.zip
fix merge
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r--activerecord/lib/active_record/association_preload.rb4
-rwxr-xr-xactiverecord/lib/active_record/associations.rb28
-rwxr-xr-xactiverecord/lib/active_record/base.rb38
-rw-r--r--activerecord/lib/active_record/calculations.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb4
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/mysql_adapter.rb79
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb71
-rwxr-xr-xactiverecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/observer.rb2
-rw-r--r--activerecord/lib/active_record/vendor/db2.rb362
-rw-r--r--activerecord/lib/active_record/vendor/mysql.rb1214
11 files changed, 146 insertions, 1670 deletions
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index a3d1f12b03..49f5270396 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -103,10 +103,10 @@ module ActiveRecord
associated_records = reflection.klass.find(:all, :conditions => [conditions, ids],
:include => options[:include],
:joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} as t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}",
- :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as _parent_record_id",
+ :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id",
:order => options[:order])
- set_association_collection_records(id_to_record_map, reflection.name, associated_records, '_parent_record_id')
+ set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id')
end
def preload_has_one_association(records, reflection, preload_options={})
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index f32b217326..db99b7165d 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -690,6 +690,7 @@ module ActiveRecord
# association is a polymorphic +belongs_to+.
# * <tt>:uniq</tt> - If true, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>.
# * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association.
+ # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. true by default.
#
# Option examples:
# has_many :comments, :order => "posted_on"
@@ -710,7 +711,7 @@ module ActiveRecord
configure_dependency_for_has_many(reflection)
- add_multiple_associated_save_callbacks(reflection.name)
+ add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false
add_association_callbacks(reflection.name, reflection.options)
if options[:through]
@@ -769,6 +770,7 @@ module ActiveRecord
# * <tt>:source_type</tt> - Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
# association is a polymorphic +belongs_to+.
# * <tt>:readonly</tt> - If true, the associated object is readonly through the association.
+ # * <tt>:validate</tt> - If false, don't validate the associated object when saving the parent object. +false+ by default.
#
# Option examples:
# has_one :credit_card, :dependent => :destroy # destroys the associated credit card
@@ -799,7 +801,7 @@ module ActiveRecord
end
after_save method_name
- add_single_associated_save_callbacks(reflection.name)
+ add_single_associated_save_callbacks(reflection.name) if options[:validate] == true
association_accessor_methods(reflection, HasOneAssociation)
association_constructor_method(:build, reflection, HasOneAssociation)
association_constructor_method(:create, reflection, HasOneAssociation)
@@ -857,6 +859,7 @@ module ActiveRecord
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
# * <tt>:readonly</tt> - If true, the associated object is readonly through the association.
+ # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. +false+ by default.
#
# Option examples:
# belongs_to :firm, :foreign_key => "client_of"
@@ -937,6 +940,8 @@ module ActiveRecord
)
end
+ add_single_associated_save_callbacks(reflection.name) if options[:validate] == true
+
configure_dependency_for_belongs_to(reflection)
end
@@ -1025,6 +1030,7 @@ module ActiveRecord
# * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join
# but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
# * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association.
+ # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. +true+ by default.
#
# Option examples:
# has_and_belongs_to_many :projects
@@ -1037,7 +1043,7 @@ module ActiveRecord
def has_and_belongs_to_many(association_id, options = {}, &extension)
reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension)
- add_multiple_associated_save_callbacks(reflection.name)
+ add_multiple_associated_save_callbacks(reflection.name) unless options[:validate] == false
collection_accessor_methods(reflection, HasAndBelongsToManyAssociation)
# Don't use a before_destroy callback since users' before_destroy
@@ -1343,7 +1349,8 @@ module ActiveRecord
:uniq,
:finder_sql, :counter_sql,
:before_add, :after_add, :before_remove, :after_remove,
- :extend, :readonly
+ :extend, :readonly,
+ :validate
)
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
@@ -1353,7 +1360,7 @@ module ActiveRecord
def create_has_one_reflection(association_id, options)
options.assert_valid_keys(
- :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly
+ :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate
)
create_reflection(:has_one, association_id, options, self)
@@ -1361,7 +1368,7 @@ module ActiveRecord
def create_has_one_through_reflection(association_id, options)
options.assert_valid_keys(
- :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type
+ :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type, :validate
)
create_reflection(:has_one, association_id, options, self)
end
@@ -1369,7 +1376,7 @@ module ActiveRecord
def create_belongs_to_reflection(association_id, options)
options.assert_valid_keys(
:class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent,
- :counter_cache, :extend, :polymorphic, :readonly
+ :counter_cache, :extend, :polymorphic, :readonly, :validate
)
reflection = create_reflection(:belongs_to, association_id, options, self)
@@ -1388,7 +1395,8 @@ module ActiveRecord
:uniq,
:finder_sql, :delete_sql, :insert_sql,
:before_add, :after_add, :before_remove, :after_remove,
- :extend, :readonly
+ :extend, :readonly,
+ :validate
)
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
@@ -1638,7 +1646,9 @@ module ActiveRecord
end
def join_for_table_name(table_name)
- @joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil
+ join = (@joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first) rescue nil
+ return join unless join.nil?
+ @joins.select{|j|j.is_a?(JoinAssociation) && j.aliased_join_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil
end
def joins_for_table_name(table_name)
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 450ea5cb33..8fca34e524 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1297,6 +1297,20 @@ module ActiveRecord #:nodoc:
store_full_sti_class ? name : name.demodulize
end
+ # Merges conditions so that the result is a valid +condition+
+ def merge_conditions(*conditions)
+ segments = []
+
+ conditions.each do |condition|
+ unless condition.blank?
+ sql = sanitize_sql(condition)
+ segments << sql unless sql.blank?
+ end
+ end
+
+ "(#{segments.join(') AND (')})" unless segments.empty?
+ end
+
private
def find_initial(options)
options.update(:limit => 1)
@@ -1484,20 +1498,6 @@ module ActiveRecord #:nodoc:
(safe_to_array(first) + safe_to_array(second)).uniq
end
- # Merges conditions so that the result is a valid +condition+
- def merge_conditions(*conditions)
- segments = []
-
- conditions.each do |condition|
- unless condition.blank?
- sql = sanitize_sql(condition)
- segments << sql unless sql.blank?
- end
- end
-
- "(#{segments.join(') AND (')})" unless segments.empty?
- end
-
# Object#to_a is deprecated, though it does have the desired behavior
def safe_to_array(o)
case o
@@ -1903,10 +1903,12 @@ module ActiveRecord #:nodoc:
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
def compute_type(type_name)
modularized_name = type_name_with_module(type_name)
- begin
- class_eval(modularized_name, __FILE__, __LINE__)
- rescue NameError
- class_eval(type_name, __FILE__, __LINE__)
+ silence_warnings do
+ begin
+ class_eval(modularized_name, __FILE__, __LINE__)
+ rescue NameError
+ class_eval(type_name, __FILE__, __LINE__)
+ end
end
end
diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb
index caa8c539d5..2ca1a0aaa3 100644
--- a/activerecord/lib/active_record/calculations.rb
+++ b/activerecord/lib/active_record/calculations.rb
@@ -1,6 +1,6 @@
module ActiveRecord
module Calculations #:nodoc:
- CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include]
+ CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from]
def self.included(base)
base.extend(ClassMethods)
end
@@ -27,6 +27,8 @@ module ActiveRecord
# * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not
# include the joined columns.
# * <tt>:distinct</tt>: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ...
+ # * <tt>:from</tt> - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name
+ # of a database view).
#
# Examples for counting all:
# Person.count # returns the total count of all people
@@ -178,8 +180,12 @@ module ActiveRecord
sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group]
- sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
- sql << " FROM #{connection.quote_table_name(table_name)} "
+ if options[:from]
+ sql << " FROM #{options[:from]} "
+ else
+ sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
+ sql << " FROM #{connection.quote_table_name(table_name)} "
+ end
if merged_includes.any?
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 55f67995d1..7d8530ebef 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -356,7 +356,7 @@ module ActiveRecord
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
if native = native_database_types[type]
- column_type_sql = native.is_a?(Hash) ? native[:name] : native
+ column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
if type == :decimal # ignore limit, use precision and scale
scale ||= native[:scale]
@@ -371,7 +371,7 @@ module ActiveRecord
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified"
end
- elsif limit ||= native.is_a?(Hash) && native[:limit]
+ elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
column_type_sql << "(#{limit})"
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 653b45021d..93aafaaad1 100755
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -42,30 +42,6 @@ end
module ActiveRecord
class Base
- def self.require_mysql
- # Include the MySQL driver if one hasn't already been loaded
- unless defined? Mysql
- begin
- require_library_or_gem 'mysql'
- rescue LoadError => cannot_require_mysql
- # Use the bundled Ruby/MySQL driver if no driver is already in place
- begin
- ActiveRecord::Base.logger.info(
- "WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library is not suited for production. " +
- "Please install the C-based MySQL library instead (gem install mysql)."
- ) if ActiveRecord::Base.logger
-
- require 'active_record/vendor/mysql'
- rescue LoadError
- raise cannot_require_mysql
- end
- end
- end
-
- # Define Mysql::Result.all_hashes
- MysqlCompat.define_all_hashes_method!
- end
-
# Establishes a connection to the database that's used by all Active Record objects.
def self.mysql_connection(config) # :nodoc:
config = config.symbolize_keys
@@ -81,7 +57,17 @@ module ActiveRecord
raise ArgumentError, "No database specified. Missing argument: database."
end
- require_mysql
+ # Require the MySQL driver and define Mysql::Result.all_hashes
+ unless defined? Mysql
+ begin
+ require_library_or_gem('mysql')
+ rescue LoadError
+ $stderr.puts '!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.'
+ raise
+ end
+ end
+ MysqlCompat.define_all_hashes_method!
+
mysql = Mysql.init
mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslkey]
@@ -165,8 +151,10 @@ module ActiveRecord
#
# ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false
class MysqlAdapter < AbstractAdapter
- @@emulate_booleans = true
cattr_accessor :emulate_booleans
+ self.emulate_booleans = true
+
+ ADAPTER_NAME = 'MySQL'.freeze
LOST_CONNECTION_ERROR_MESSAGES = [
"Server shutdown in progress",
@@ -174,7 +162,22 @@ module ActiveRecord
"Lost connection to MySQL server during query",
"MySQL server has gone away" ]
- QUOTED_TRUE, QUOTED_FALSE = '1', '0'
+ QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze
+
+ NATIVE_DATABASE_TYPES = {
+ :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze,
+ :string => { :name => "varchar", :limit => 255 },
+ :text => { :name => "text" },
+ :integer => { :name => "int"},
+ :float => { :name => "float" },
+ :decimal => { :name => "decimal" },
+ :datetime => { :name => "datetime" },
+ :timestamp => { :name => "datetime" },
+ :time => { :name => "time" },
+ :date => { :name => "date" },
+ :binary => { :name => "blob" },
+ :boolean => { :name => "tinyint", :limit => 1 }
+ }
def initialize(connection, logger, connection_options, config)
super(connection, logger)
@@ -184,7 +187,7 @@ module ActiveRecord
end
def adapter_name #:nodoc:
- 'MySQL'
+ ADAPTER_NAME
end
def supports_migrations? #:nodoc:
@@ -192,20 +195,7 @@ module ActiveRecord
end
def native_database_types #:nodoc:
- {
- :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY",
- :string => { :name => "varchar", :limit => 255 },
- :text => { :name => "text" },
- :integer => { :name => "int"},
- :float => { :name => "float" },
- :decimal => { :name => "decimal" },
- :datetime => { :name => "datetime" },
- :timestamp => { :name => "datetime" },
- :time => { :name => "time" },
- :date => { :name => "date" },
- :binary => { :name => "blob" },
- :boolean => { :name => "tinyint", :limit => 1 }
- }
+ NATIVE_DATABASE_TYPES
end
@@ -498,12 +488,17 @@ module ActiveRecord
private
def connect
+ @connection.reconnect = true if @connection.respond_to?(:reconnect=)
+
encoding = @config[:encoding]
if encoding
@connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil
end
+
@connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) if @config[:sslkey]
+
@connection.real_connect(*@connection_options)
+
execute("SET NAMES '#{encoding}'") if encoding
# By default, MySQL 'where id is null' selects the last inserted id.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 049e6f61de..294f4c1929 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -238,9 +238,26 @@ module ActiveRecord
# * <tt>:min_messages</tt> - An optional client min messages that is used in a <tt>SET client_min_messages TO <min_messages></tt> call on the connection.
# * <tt>:allow_concurrency</tt> - If true, use async query methods so Ruby threads don't deadlock; otherwise, use blocking query methods.
class PostgreSQLAdapter < AbstractAdapter
+ ADAPTER_NAME = 'PostgreSQL'.freeze
+
+ NATIVE_DATABASE_TYPES = {
+ :primary_key => "serial primary key".freeze,
+ :string => { :name => "character varying", :limit => 255 },
+ :text => { :name => "text" },
+ :integer => { :name => "integer" },
+ :float => { :name => "float" },
+ :decimal => { :name => "decimal" },
+ :datetime => { :name => "timestamp" },
+ :timestamp => { :name => "timestamp" },
+ :time => { :name => "time" },
+ :date => { :name => "date" },
+ :binary => { :name => "bytea" },
+ :boolean => { :name => "boolean" }
+ }
+
# Returns 'PostgreSQL' as adapter name for identification purposes.
def adapter_name
- 'PostgreSQL'
+ ADAPTER_NAME
end
# Initializes and connects a PostgreSQL adapter.
@@ -282,20 +299,7 @@ module ActiveRecord
end
def native_database_types #:nodoc:
- {
- :primary_key => "serial primary key",
- :string => { :name => "character varying", :limit => 255 },
- :text => { :name => "text" },
- :integer => { :name => "integer" },
- :float => { :name => "float" },
- :decimal => { :name => "decimal" },
- :datetime => { :name => "timestamp" },
- :timestamp => { :name => "timestamp" },
- :time => { :name => "time" },
- :date => { :name => "date" },
- :binary => { :name => "bytea" },
- :boolean => { :name => "boolean" }
- }
+ NATIVE_DATABASE_TYPES
end
# Does PostgreSQL support migrations?
@@ -319,6 +323,15 @@ module ActiveRecord
has_support
end
+ def supports_insert_with_returning?
+ unless defined? @supports_insert_with_returning
+ @supports_insert_with_returning =
+ @connection.respond_to?(:server_version) &&
+ @connection.server_version >= 80200
+ end
+ @supports_insert_with_returning
+ end
+
# Returns the configured supported identifier length supported by PostgreSQL,
# or report the default of 63 on PostgreSQL 7.x.
def table_alias_length
@@ -411,8 +424,34 @@ module ActiveRecord
# Executes an INSERT query and returns the new record's ID
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
+ # Extract the table from the insert sql. Yuck.
table = sql.split(" ", 4)[2].gsub('"', '')
- super || pk && last_insert_id(table, sequence_name || default_sequence_name(table, pk))
+
+ # Try an insert with 'returning id' if available (PG >= 8.2)
+ if supports_insert_with_returning?
+ pk, sequence_name = *pk_and_sequence_for(table) unless pk
+ if pk
+ id = select_value("#{sql} RETURNING #{quote_column_name(pk)}")
+ clear_query_cache
+ return id
+ end
+ end
+
+ # Otherwise, insert then grab last_insert_id.
+ if insert_id = super
+ insert_id
+ else
+ # If neither pk nor sequence name is given, look them up.
+ unless pk || sequence_name
+ pk, sequence_name = *pk_and_sequence_for(table)
+ end
+
+ # If a pk is given, fallback to default sequence name.
+ # Don't fetch last insert id for a table without a pk.
+ if pk && sequence_name ||= default_sequence_name(table, pk)
+ last_insert_id(table, sequence_name)
+ end
+ end
end
# create a 2D array representing the result set
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index c4cbe5d52f..e19614e31f 100755
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -547,7 +547,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
@connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter
@class_name = class_name ||
(ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
- @table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix
+ @table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}"
@table_name = class_name.table_name if class_name.respond_to?(:table_name)
@connection = class_name.connection if class_name.respond_to?(:connection)
read_fixture_files
diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb
index 6e55e36b7d..25e0e61c69 100644
--- a/activerecord/lib/active_record/observer.rb
+++ b/activerecord/lib/active_record/observer.rb
@@ -189,7 +189,7 @@ module ActiveRecord
def add_observer!(klass)
klass.add_observer(self)
- klass.class_eval 'def after_find() end' unless klass.respond_to?(:after_find)
+ klass.class_eval 'def after_find() end' unless klass.method_defined?(:after_find)
end
end
end
diff --git a/activerecord/lib/active_record/vendor/db2.rb b/activerecord/lib/active_record/vendor/db2.rb
deleted file mode 100644
index 812c8cc517..0000000000
--- a/activerecord/lib/active_record/vendor/db2.rb
+++ /dev/null
@@ -1,362 +0,0 @@
-require 'db2/db2cli.rb'
-
-module DB2
- module DB2Util
- include DB2CLI
-
- def free() SQLFreeHandle(@handle_type, @handle); end
- def handle() @handle; end
-
- def check_rc(rc)
- if ![SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA_FOUND].include?(rc)
- rec = 1
- msg = ''
- loop do
- a = SQLGetDiagRec(@handle_type, @handle, rec, 500)
- break if a[0] != SQL_SUCCESS
- msg << a[3] if !a[3].nil? and a[3] != '' # Create message.
- rec += 1
- end
- raise "DB2 error: #{msg}"
- end
- end
- end
-
- class Environment
- include DB2Util
-
- def initialize
- @handle_type = SQL_HANDLE_ENV
- rc, @handle = SQLAllocHandle(@handle_type, SQL_NULL_HANDLE)
- check_rc(rc)
- end
-
- def data_sources(buffer_length = 1024)
- retval = []
- max_buffer_length = buffer_length
-
- a = SQLDataSources(@handle, SQL_FETCH_FIRST, SQL_MAX_DSN_LENGTH + 1, buffer_length)
- retval << [a[1], a[3]]
- max_buffer_length = [max_buffer_length, a[4]].max
-
- loop do
- a = SQLDataSources(@handle, SQL_FETCH_NEXT, SQL_MAX_DSN_LENGTH + 1, buffer_length)
- break if a[0] == SQL_NO_DATA_FOUND
-
- retval << [a[1], a[3]]
- max_buffer_length = [max_buffer_length, a[4]].max
- end
-
- if max_buffer_length > buffer_length
- get_data_sources(max_buffer_length)
- else
- retval
- end
- end
- end
-
- class Connection
- include DB2Util
-
- def initialize(environment)
- @env = environment
- @handle_type = SQL_HANDLE_DBC
- rc, @handle = SQLAllocHandle(@handle_type, @env.handle)
- check_rc(rc)
- end
-
- def connect(server_name, user_name = '', auth = '')
- check_rc(SQLConnect(@handle, server_name, user_name.to_s, auth.to_s))
- end
-
- def set_connect_attr(attr, value)
- value += "\0" if value.class == String
- check_rc(SQLSetConnectAttr(@handle, attr, value))
- end
-
- def set_auto_commit_on
- set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON)
- end
-
- def set_auto_commit_off
- set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF)
- end
-
- def disconnect
- check_rc(SQLDisconnect(@handle))
- end
-
- def rollback
- check_rc(SQLEndTran(@handle_type, @handle, SQL_ROLLBACK))
- end
-
- def commit
- check_rc(SQLEndTran(@handle_type, @handle, SQL_COMMIT))
- end
- end
-
- class Statement
- include DB2Util
-
- def initialize(connection)
- @conn = connection
- @handle_type = SQL_HANDLE_STMT
- @parms = [] #yun
- @sql = '' #yun
- @numParms = 0 #yun
- @prepared = false #yun
- @parmArray = [] #yun. attributes of the parameter markers
- rc, @handle = SQLAllocHandle(@handle_type, @conn.handle)
- check_rc(rc)
- end
-
- def columns(table_name, schema_name = '%')
- check_rc(SQLColumns(@handle, '', schema_name.upcase, table_name.upcase, '%'))
- fetch_all
- end
-
- def tables(schema_name = '%')
- check_rc(SQLTables(@handle, '', schema_name.upcase, '%', 'TABLE'))
- fetch_all
- end
-
- def indexes(table_name, schema_name = '')
- check_rc(SQLStatistics(@handle, '', schema_name.upcase, table_name.upcase, SQL_INDEX_ALL, SQL_ENSURE))
- fetch_all
- end
-
- def prepare(sql)
- @sql = sql
- check_rc(SQLPrepare(@handle, sql))
- rc, @numParms = SQLNumParams(@handle) #number of question marks
- check_rc(rc)
- #--------------------------------------------------------------------------
- # parameter attributes are stored in instance variable @parmArray so that
- # they are available when execute method is called.
- #--------------------------------------------------------------------------
- if @numParms > 0 # get parameter marker attributes
- 1.upto(@numParms) do |i| # parameter number starts from 1
- rc, type, size, decimalDigits = SQLDescribeParam(@handle, i)
- check_rc(rc)
- @parmArray << Parameter.new(type, size, decimalDigits)
- end
- end
- @prepared = true
- self
- end
-
- def execute(*parms)
- raise "The statement was not prepared" if @prepared == false
-
- if parms.size == 1 and parms[0].class == Array
- parms = parms[0]
- end
-
- if @numParms != parms.size
- raise "Number of parameters supplied does not match with the SQL statement"
- end
-
- if @numParms > 0 #need to bind parameters
- #--------------------------------------------------------------------
- #calling bindParms may not be safe. Look comment below.
- #--------------------------------------------------------------------
- #bindParms(parms)
-
- valueArray = []
- 1.upto(@numParms) do |i| # parameter number starts from 1
- type = @parmArray[i - 1].class
- size = @parmArray[i - 1].size
- decimalDigits = @parmArray[i - 1].decimalDigits
-
- if parms[i - 1].class == String
- valueArray << parms[i - 1]
- else
- valueArray << parms[i - 1].to_s
- end
-
- rc = SQLBindParameter(@handle, i, type, size, decimalDigits, valueArray[i - 1])
- check_rc(rc)
- end
- end
-
- check_rc(SQLExecute(@handle))
-
- if @numParms != 0
- check_rc(SQLFreeStmt(@handle, SQL_RESET_PARAMS)) # Reset parameters
- end
-
- self
- end
-
- #-------------------------------------------------------------------------------
- # The last argument(value) to SQLBindParameter is a deferred argument, that is,
- # it should be available when SQLExecute is called. Even though "value" is
- # local to bindParms method, it seems that it is available when SQLExecute
- # is called. I am not sure whether it would still work if garbage collection
- # is done between bindParms call and SQLExecute call inside the execute method
- # above.
- #-------------------------------------------------------------------------------
- def bindParms(parms) # This is the real thing. It uses SQLBindParms
- 1.upto(@numParms) do |i| # parameter number starts from 1
- rc, dataType, parmSize, decimalDigits = SQLDescribeParam(@handle, i)
- check_rc(rc)
- if parms[i - 1].class == String
- value = parms[i - 1]
- else
- value = parms[i - 1].to_s
- end
- rc = SQLBindParameter(@handle, i, dataType, parmSize, decimalDigits, value)
- check_rc(rc)
- end
- end
-
- #------------------------------------------------------------------------------
- # bind method does not use DB2's SQLBindParams, but replaces "?" in the
- # SQL statement with the value before passing the SQL statement to DB2.
- # It is not efficient and can handle only strings since it puts everything in
- # quotes.
- #------------------------------------------------------------------------------
- def bind(sql, args) #does not use SQLBindParams
- arg_index = 0
- result = ""
- tokens(sql).each do |part|
- case part
- when '?'
- result << "'" + (args[arg_index]) + "'" #put it into quotes
- arg_index += 1
- when '??'
- result << "?"
- else
- result << part
- end
- end
- if arg_index < args.size
- raise "Too many SQL parameters"
- elsif arg_index > args.size
- raise "Not enough SQL parameters"
- end
- result
- end
-
- ## Break the sql string into parts.
- #
- # This is NOT a full lexer for SQL. It just breaks up the SQL
- # string enough so that question marks, double question marks and
- # quoted strings are separated. This is used when binding
- # arguments to "?" in the SQL string. Note: comments are not
- # handled.
- #
- def tokens(sql)
- toks = sql.scan(/('([^'\\]|''|\\.)*'|"([^"\\]|""|\\.)*"|\?\??|[^'"?]+)/)
- toks.collect { |t| t[0] }
- end
-
- def exec_direct(sql)
- check_rc(SQLExecDirect(@handle, sql))
- self
- end
-
- def set_cursor_name(name)
- check_rc(SQLSetCursorName(@handle, name))
- self
- end
-
- def get_cursor_name
- rc, name = SQLGetCursorName(@handle)
- check_rc(rc)
- name
- end
-
- def row_count
- rc, rowcount = SQLRowCount(@handle)
- check_rc(rc)
- rowcount
- end
-
- def num_result_cols
- rc, cols = SQLNumResultCols(@handle)
- check_rc(rc)
- cols
- end
-
- def fetch_all
- if block_given?
- while row = fetch do
- yield row
- end
- else
- res = []
- while row = fetch do
- res << row
- end
- res
- end
- end
-
- def fetch
- cols = get_col_desc
- rc = SQLFetch(@handle)
- if rc == SQL_NO_DATA_FOUND
- SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
- SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
- return nil
- end
- raise "ERROR" unless rc == SQL_SUCCESS
-
- retval = []
- cols.each_with_index do |c, i|
- rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
- retval << adjust_content(content)
- end
- retval
- end
-
- def fetch_as_hash
- cols = get_col_desc
- rc = SQLFetch(@handle)
- if rc == SQL_NO_DATA_FOUND
- SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
- SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
- return nil
- end
- raise "ERROR" unless rc == SQL_SUCCESS
-
- retval = {}
- cols.each_with_index do |c, i|
- rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
- retval[c[0]] = adjust_content(content)
- end
- retval
- end
-
- def get_col_desc
- rc, nr_cols = SQLNumResultCols(@handle)
- cols = (1..nr_cols).collect do |c|
- rc, name, bl, type, col_sz = SQLDescribeCol(@handle, c, 1024)
- [name.downcase, type, col_sz]
- end
- end
-
- def adjust_content(c)
- case c.class.to_s
- when 'DB2CLI::NullClass'
- return nil
- when 'DB2CLI::Time'
- "%02d:%02d:%02d" % [c.hour, c.minute, c.second]
- when 'DB2CLI::Date'
- "%04d-%02d-%02d" % [c.year, c.month, c.day]
- when 'DB2CLI::Timestamp'
- "%04d-%02d-%02d %02d:%02d:%02d" % [c.year, c.month, c.day, c.hour, c.minute, c.second]
- else
- return c
- end
- end
- end
-
- class Parameter
- attr_reader :type, :size, :decimalDigits
- def initialize(type, size, decimalDigits)
- @type, @size, @decimalDigits = type, size, decimalDigits
- end
- end
-end
diff --git a/activerecord/lib/active_record/vendor/mysql.rb b/activerecord/lib/active_record/vendor/mysql.rb
deleted file mode 100644
index 1c3294c719..0000000000
--- a/activerecord/lib/active_record/vendor/mysql.rb
+++ /dev/null
@@ -1,1214 +0,0 @@
-# $Id: mysql.rb,v 1.24 2005/02/12 11:37:15 tommy Exp $
-#
-# Copyright (C) 2003-2005 TOMITA Masahiro
-# tommy@tmtm.org
-#
-
-class Mysql
-
- VERSION = "4.0-ruby-0.2.6-plus-changes"
-
- require "socket"
- require "digest/sha1"
-
- MAX_PACKET_LENGTH = 256*256*256-1
- MAX_ALLOWED_PACKET = 1024*1024*1024
-
- MYSQL_UNIX_ADDR = "/tmp/mysql.sock"
- MYSQL_PORT = 3306
- PROTOCOL_VERSION = 10
-
- SCRAMBLE_LENGTH = 20
- SCRAMBLE_LENGTH_323 = 8
-
- # Command
- COM_SLEEP = 0
- COM_QUIT = 1
- COM_INIT_DB = 2
- COM_QUERY = 3
- COM_FIELD_LIST = 4
- COM_CREATE_DB = 5
- COM_DROP_DB = 6
- COM_REFRESH = 7
- COM_SHUTDOWN = 8
- COM_STATISTICS = 9
- COM_PROCESS_INFO = 10
- COM_CONNECT = 11
- COM_PROCESS_KILL = 12
- COM_DEBUG = 13
- COM_PING = 14
- COM_TIME = 15
- COM_DELAYED_INSERT = 16
- COM_CHANGE_USER = 17
- COM_BINLOG_DUMP = 18
- COM_TABLE_DUMP = 19
- COM_CONNECT_OUT = 20
- COM_REGISTER_SLAVE = 21
-
- # Client flag
- CLIENT_LONG_PASSWORD = 1
- CLIENT_FOUND_ROWS = 1 << 1
- CLIENT_LONG_FLAG = 1 << 2
- CLIENT_CONNECT_WITH_DB= 1 << 3
- CLIENT_NO_SCHEMA = 1 << 4
- CLIENT_COMPRESS = 1 << 5
- CLIENT_ODBC = 1 << 6
- CLIENT_LOCAL_FILES = 1 << 7
- CLIENT_IGNORE_SPACE = 1 << 8
- CLIENT_PROTOCOL_41 = 1 << 9
- CLIENT_INTERACTIVE = 1 << 10
- CLIENT_SSL = 1 << 11
- CLIENT_IGNORE_SIGPIPE = 1 << 12
- CLIENT_TRANSACTIONS = 1 << 13
- CLIENT_RESERVED = 1 << 14
- CLIENT_SECURE_CONNECTION = 1 << 15
- CLIENT_CAPABILITIES = CLIENT_LONG_PASSWORD|CLIENT_LONG_FLAG|CLIENT_TRANSACTIONS
- PROTO_AUTH41 = CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION
-
- # Connection Option
- OPT_CONNECT_TIMEOUT = 0
- OPT_COMPRESS = 1
- OPT_NAMED_PIPE = 2
- INIT_COMMAND = 3
- READ_DEFAULT_FILE = 4
- READ_DEFAULT_GROUP = 5
- SET_CHARSET_DIR = 6
- SET_CHARSET_NAME = 7
- OPT_LOCAL_INFILE = 8
-
- # Server Status
- SERVER_STATUS_IN_TRANS = 1
- SERVER_STATUS_AUTOCOMMIT = 2
-
- # Refresh parameter
- REFRESH_GRANT = 1
- REFRESH_LOG = 2
- REFRESH_TABLES = 4
- REFRESH_HOSTS = 8
- REFRESH_STATUS = 16
- REFRESH_THREADS = 32
- REFRESH_SLAVE = 64
- REFRESH_MASTER = 128
-
- def initialize(*args)
- @client_flag = 0
- @max_allowed_packet = MAX_ALLOWED_PACKET
- @query_with_result = true
- @status = :STATUS_READY
- if args[0] != :INIT then
- real_connect(*args)
- end
- end
-
- def real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=nil)
- @server_status = SERVER_STATUS_AUTOCOMMIT
- if (host == nil or host == "localhost") and defined? UNIXSocket then
- unix_socket = socket || ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_ADDR
- sock = UNIXSocket::new(unix_socket)
- @host_info = Error::err(Error::CR_LOCALHOST_CONNECTION)
- @unix_socket = unix_socket
- else
- sock = TCPSocket::new(host, port||ENV["MYSQL_TCP_PORT"]||(Socket::getservbyname("mysql","tcp") rescue MYSQL_PORT))
- @host_info = sprintf Error::err(Error::CR_TCP_CONNECTION), host
- end
- @host = host ? host.dup : nil
- sock.setsockopt Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true
- @net = Net::new sock
-
- a = read
- @protocol_version = a.slice!(0)
- @server_version, a = a.split(/\0/,2)
- @thread_id, @scramble_buff = a.slice!(0,13).unpack("La8")
- if a.size >= 2 then
- @server_capabilities, = a.slice!(0,2).unpack("v")
- end
- if a.size >= 16 then
- @server_language, @server_status = a.slice!(0,3).unpack("cv")
- end
-
- flag = 0 if flag == nil
- flag |= @client_flag | CLIENT_CAPABILITIES
- flag |= CLIENT_CONNECT_WITH_DB if db
-
- @pre_411 = (0 == @server_capabilities & PROTO_AUTH41)
- if @pre_411
- data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+
- (user||"")+"\0"+
- scramble(passwd, @scramble_buff, @protocol_version==9)
- else
- dummy, @salt2 = a.unpack("a13a12")
- @scramble_buff += @salt2
- flag |= PROTO_AUTH41
- data = Net::int4str(flag) + Net::int4str(@max_allowed_packet) +
- ([8] + Array.new(23, 0)).pack("c24") + (user||"")+"\0"+
- scramble41(passwd, @scramble_buff)
- end
-
- if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0
- data << "\0" if @pre_411
- data << db
- @db = db.dup
- end
- write data
- pkt = read
- handle_auth_fallback(pkt, passwd)
- ObjectSpace.define_finalizer(self, Mysql.finalizer(@net))
- self
- end
- alias :connect :real_connect
-
- def handle_auth_fallback(pkt, passwd)
- # A packet like this means that we need to send an old-format password
- if pkt.size == 1 and pkt[0] == 254 and
- @server_capabilities & CLIENT_SECURE_CONNECTION != 0 then
- data = scramble(passwd, @scramble_buff, @protocol_version == 9)
- write data + "\0"
- read
- end
- end
-
- def escape_string(str)
- Mysql::escape_string str
- end
- alias :quote :escape_string
-
- def get_client_info()
- VERSION
- end
- alias :client_info :get_client_info
-
- def options(option, arg=nil)
- if option == OPT_LOCAL_INFILE then
- if arg == false or arg == 0 then
- @client_flag &= ~CLIENT_LOCAL_FILES
- else
- @client_flag |= CLIENT_LOCAL_FILES
- end
- else
- raise "not implemented"
- end
- end
-
- def real_query(query)
- command COM_QUERY, query, true
- read_query_result
- self
- end
-
- def use_result()
- if @status != :STATUS_GET_RESULT then
- error Error::CR_COMMANDS_OUT_OF_SYNC
- end
- res = Result::new self, @fields, @field_count
- @status = :STATUS_USE_RESULT
- res
- end
-
- def store_result()
- if @status != :STATUS_GET_RESULT then
- error Error::CR_COMMANDS_OUT_OF_SYNC
- end
- @status = :STATUS_READY
- data = read_rows @field_count
- res = Result::new self, @fields, @field_count, data
- @fields = nil
- @affected_rows = data.length
- res
- end
-
- def change_user(user="", passwd="", db="")
- if @pre_411
- data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db
- else
- data = user+"\0"+scramble41(passwd, @scramble_buff)+db
- end
- pkt = command COM_CHANGE_USER, data
- handle_auth_fallback(pkt, passwd)
- @user = user
- @passwd = passwd
- @db = db
- end
-
- def character_set_name()
- raise "not implemented"
- end
-
- def close()
- @status = :STATUS_READY
- command COM_QUIT, nil, true
- @net.close
- self
- end
-
- def create_db(db)
- command COM_CREATE_DB, db
- self
- end
-
- def drop_db(db)
- command COM_DROP_DB, db
- self
- end
-
- def dump_debug_info()
- command COM_DEBUG
- self
- end
-
- def get_host_info()
- @host_info
- end
- alias :host_info :get_host_info
-
- def get_proto_info()
- @protocol_version
- end
- alias :proto_info :get_proto_info
-
- def get_server_info()
- @server_version
- end
- alias :server_info :get_server_info
-
- def kill(id)
- command COM_PROCESS_KILL, Net::int4str(id)
- self
- end
-
- def list_dbs(db=nil)
- real_query "show databases #{db}"
- @status = :STATUS_READY
- read_rows(1).flatten
- end
-
- def list_fields(table, field=nil)
- command COM_FIELD_LIST, "#{table}\0#{field}", true
- if @pre_411
- f = read_rows 6
- else
- f = read_rows 7
- end
- fields = unpack_fields(f, @server_capabilities & CLIENT_LONG_FLAG != 0)
- res = Result::new self, fields, f.length
- res.eof = true
- res
- end
-
- def list_processes()
- data = command COM_PROCESS_INFO
- @field_count = get_length data
- if @pre_411
- fields = read_rows 5
- else
- fields = read_rows 7
- end
- @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
- @status = :STATUS_GET_RESULT
- store_result
- end
-
- def list_tables(table=nil)
- real_query "show tables #{table}"
- @status = :STATUS_READY
- read_rows(1).flatten
- end
-
- def ping()
- command COM_PING
- self
- end
-
- def query(query)
- real_query query
- if not @query_with_result then
- return self
- end
- if @field_count == 0 then
- return nil
- end
- store_result
- end
-
- def refresh(r)
- command COM_REFRESH, r.chr
- self
- end
-
- def reload()
- refresh REFRESH_GRANT
- self
- end
-
- def select_db(db)
- command COM_INIT_DB, db
- @db = db
- self
- end
-
- def shutdown()
- command COM_SHUTDOWN
- self
- end
-
- def stat()
- command COM_STATISTICS
- end
-
- attr_reader :info, :insert_id, :affected_rows, :field_count, :thread_id
- attr_accessor :query_with_result, :status
-
- def read_one_row(field_count)
- data = read
- if data[0] == 254 and data.length == 1 ## EOF
- return
- elsif data[0] == 254 and data.length == 5
- return
- end
- rec = []
- field_count.times do
- len = get_length data
- if len == nil then
- rec << len
- else
- rec << data.slice!(0,len)
- end
- end
- rec
- end
-
- def skip_result()
- if @status == :STATUS_USE_RESULT then
- loop do
- data = read
- break if data[0] == 254 and data.length == 1
- end
- @status = :STATUS_READY
- end
- end
-
- def inspect()
- "#<#{self.class}>"
- end
-
- private
-
- def read_query_result()
- data = read
- @field_count = get_length(data)
- if @field_count == nil then # LOAD DATA LOCAL INFILE
- File::open(data) do |f|
- write f.read
- end
- write "" # mark EOF
- data = read
- @field_count = get_length(data)
- end
- if @field_count == 0 then
- @affected_rows = get_length(data, true)
- @insert_id = get_length(data, true)
- if @server_capabilities & CLIENT_TRANSACTIONS != 0 then
- a = data.slice!(0,2)
- @server_status = a[0]+a[1]*256
- end
- if data.size > 0 and get_length(data) then
- @info = data
- end
- else
- @extra_info = get_length(data, true)
- if @pre_411
- fields = read_rows(5)
- else
- fields = read_rows(7)
- end
- @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
- @status = :STATUS_GET_RESULT
- end
- self
- end
-
- def unpack_fields(data, long_flag_protocol)
- ret = []
- data.each do |f|
- if @pre_411
- table = org_table = f[0]
- name = f[1]
- length = f[2][0]+f[2][1]*256+f[2][2]*256*256
- type = f[3][0]
- if long_flag_protocol then
- flags = f[4][0]+f[4][1]*256
- decimals = f[4][2]
- else
- flags = f[4][0]
- decimals = f[4][1]
- end
- def_value = f[5]
- max_length = 0
- else
- catalog = f[0]
- db = f[1]
- table = f[2]
- org_table = f[3]
- name = f[4]
- org_name = f[5]
- length = f[6][2]+f[6][3]*256+f[6][4]*256*256
- type = f[6][6]
- flags = f[6][7]+f[6][8]*256
- decimals = f[6][9]
- def_value = ""
- max_length = 0
- end
- ret << Field::new(table, org_table, name, length, type, flags, decimals, def_value, max_length)
- end
- ret
- end
-
- def read_rows(field_count)
- ret = []
- while rec = read_one_row(field_count) do
- ret << rec
- end
- ret
- end
-
- def get_length(data, longlong=nil)
- return if data.length == 0
- c = data.slice!(0)
- case c
- when 251
- return nil
- when 252
- a = data.slice!(0,2)
- return a[0]+a[1]*256
- when 253
- a = data.slice!(0,3)
- return a[0]+a[1]*256+a[2]*256**2
- when 254
- a = data.slice!(0,8)
- if longlong then
- return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3+
- a[4]*256**4+a[5]*256**5+a[6]*256**6+a[7]*256**7
- else
- return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3
- end
- else
- c
- end
- end
-
- def command(cmd, arg=nil, skip_check=nil)
- unless @net then
- error Error::CR_SERVER_GONE_ERROR
- end
- if @status != :STATUS_READY then
- error Error::CR_COMMANDS_OUT_OF_SYNC
- end
- @net.clear
- write cmd.chr+(arg||"")
- read unless skip_check
- end
-
- def read()
- unless @net then
- error Error::CR_SERVER_GONE_ERROR
- end
- a = @net.read
- if a[0] == 255 then
- if a.length > 3 then
- @errno = a[1]+a[2]*256
- @error = a[3 .. -1]
- else
- @errno = Error::CR_UNKNOWN_ERROR
- @error = Error::err @errno
- end
- raise Error::new(@errno, @error)
- end
- a
- end
-
- def write(arg)
- unless @net then
- error Error::CR_SERVER_GONE_ERROR
- end
- @net.write arg
- end
-
- def hash_password(password)
- nr = 1345345333
- add = 7
- nr2 = 0x12345671
- password.each_byte do |i|
- next if i == 0x20 or i == 9
- nr ^= (((nr & 63) + add) * i) + (nr << 8)
- nr2 += (nr2 << 8) ^ nr
- add += i
- end
- [nr & ((1 << 31) - 1), nr2 & ((1 << 31) - 1)]
- end
-
- def scramble(password, message, old_ver)
- return "" if password == nil or password == ""
- raise "old version password is not implemented" if old_ver
- hash_pass = hash_password password
- hash_message = hash_password message.slice(0,SCRAMBLE_LENGTH_323)
- rnd = Random::new hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]
- to = []
- 1.upto(SCRAMBLE_LENGTH_323) do
- to << ((rnd.rnd*31)+64).floor
- end
- extra = (rnd.rnd*31).floor
- to.map! do |t| (t ^ extra).chr end
- to.join
- end
-
- def scramble41(password, message)
- return 0x00.chr if password.nil? or password.empty?
- buf = [0x14]
- s1 = Digest::SHA1.digest(password)
- s2 = Digest::SHA1.digest(s1)
- x = Digest::SHA1.digest(message + s2)
- (0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])}
- buf.pack("C*")
- end
-
- def error(errno)
- @errno = errno
- @error = Error::err errno
- raise Error::new(@errno, @error)
- end
-
- class Result
- def initialize(mysql, fields, field_count, data=nil)
- @handle = mysql
- @fields = fields
- @field_count = field_count
- @data = data
- @current_field = 0
- @current_row = 0
- @eof = false
- @row_count = 0
- end
- attr_accessor :eof
-
- def data_seek(n)
- @current_row = n
- end
-
- def fetch_field()
- return if @current_field >= @field_count
- f = @fields[@current_field]
- @current_field += 1
- f
- end
-
- def fetch_fields()
- @fields
- end
-
- def fetch_field_direct(n)
- @fields[n]
- end
-
- def fetch_lengths()
- @data ? @data[@current_row].map{|i| i ? i.length : 0} : @lengths
- end
-
- def fetch_row()
- if @data then
- if @current_row >= @data.length then
- @handle.status = :STATUS_READY
- return
- end
- ret = @data[@current_row]
- @current_row += 1
- else
- return if @eof
- ret = @handle.read_one_row @field_count
- if ret == nil then
- @eof = true
- return
- end
- @lengths = ret.map{|i| i ? i.length : 0}
- @row_count += 1
- end
- ret
- end
-
- def fetch_hash(with_table=nil)
- row = fetch_row
- return if row == nil
- hash = {}
- @fields.each_index do |i|
- f = with_table ? @fields[i].table+"."+@fields[i].name : @fields[i].name
- hash[f] = row[i]
- end
- hash
- end
-
- def field_seek(n)
- @current_field = n
- end
-
- def field_tell()
- @current_field
- end
-
- def free()
- @handle.skip_result
- @handle = @fields = @data = nil
- end
-
- def num_fields()
- @field_count
- end
-
- def num_rows()
- @data ? @data.length : @row_count
- end
-
- def row_seek(n)
- @current_row = n
- end
-
- def row_tell()
- @current_row
- end
-
- def each()
- while row = fetch_row do
- yield row
- end
- end
-
- def each_hash(with_table=nil)
- while hash = fetch_hash(with_table) do
- yield hash
- end
- end
-
- def inspect()
- "#<#{self.class}>"
- end
-
- end
-
- class Field
- # Field type
- TYPE_DECIMAL = 0
- TYPE_TINY = 1
- TYPE_SHORT = 2
- TYPE_LONG = 3
- TYPE_FLOAT = 4
- TYPE_DOUBLE = 5
- TYPE_NULL = 6
- TYPE_TIMESTAMP = 7
- TYPE_LONGLONG = 8
- TYPE_INT24 = 9
- TYPE_DATE = 10
- TYPE_TIME = 11
- TYPE_DATETIME = 12
- TYPE_YEAR = 13
- TYPE_NEWDATE = 14
- TYPE_ENUM = 247
- TYPE_SET = 248
- TYPE_TINY_BLOB = 249
- TYPE_MEDIUM_BLOB = 250
- TYPE_LONG_BLOB = 251
- TYPE_BLOB = 252
- TYPE_VAR_STRING = 253
- TYPE_STRING = 254
- TYPE_GEOMETRY = 255
- TYPE_CHAR = TYPE_TINY
- TYPE_INTERVAL = TYPE_ENUM
-
- # Flag
- NOT_NULL_FLAG = 1
- PRI_KEY_FLAG = 2
- UNIQUE_KEY_FLAG = 4
- MULTIPLE_KEY_FLAG = 8
- BLOB_FLAG = 16
- UNSIGNED_FLAG = 32
- ZEROFILL_FLAG = 64
- BINARY_FLAG = 128
- ENUM_FLAG = 256
- AUTO_INCREMENT_FLAG = 512
- TIMESTAMP_FLAG = 1024
- SET_FLAG = 2048
- NUM_FLAG = 32768
- PART_KEY_FLAG = 16384
- GROUP_FLAG = 32768
- UNIQUE_FLAG = 65536
-
- def initialize(table, org_table, name, length, type, flags, decimals, def_value, max_length)
- @table = table
- @org_table = org_table
- @name = name
- @length = length
- @type = type
- @flags = flags
- @decimals = decimals
- @def = def_value
- @max_length = max_length
- if (type <= TYPE_INT24 and (type != TYPE_TIMESTAMP or length == 14 or length == 8)) or type == TYPE_YEAR then
- @flags |= NUM_FLAG
- end
- end
- attr_reader :table, :org_table, :name, :length, :type, :flags, :decimals, :def, :max_length
-
- def inspect()
- "#<#{self.class}:#{@name}>"
- end
- end
-
- class Error < StandardError
- # Server Error
- ER_HASHCHK = 1000
- ER_NISAMCHK = 1001
- ER_NO = 1002
- ER_YES = 1003
- ER_CANT_CREATE_FILE = 1004
- ER_CANT_CREATE_TABLE = 1005
- ER_CANT_CREATE_DB = 1006
- ER_DB_CREATE_EXISTS = 1007
- ER_DB_DROP_EXISTS = 1008
- ER_DB_DROP_DELETE = 1009
- ER_DB_DROP_RMDIR = 1010
- ER_CANT_DELETE_FILE = 1011
- ER_CANT_FIND_SYSTEM_REC = 1012
- ER_CANT_GET_STAT = 1013
- ER_CANT_GET_WD = 1014
- ER_CANT_LOCK = 1015
- ER_CANT_OPEN_FILE = 1016
- ER_FILE_NOT_FOUND = 1017
- ER_CANT_READ_DIR = 1018
- ER_CANT_SET_WD = 1019
- ER_CHECKREAD = 1020
- ER_DISK_FULL = 1021
- ER_DUP_KEY = 1022
- ER_ERROR_ON_CLOSE = 1023
- ER_ERROR_ON_READ = 1024
- ER_ERROR_ON_RENAME = 1025
- ER_ERROR_ON_WRITE = 1026
- ER_FILE_USED = 1027
- ER_FILSORT_ABORT = 1028
- ER_FORM_NOT_FOUND = 1029
- ER_GET_ERRNO = 1030
- ER_ILLEGAL_HA = 1031
- ER_KEY_NOT_FOUND = 1032
- ER_NOT_FORM_FILE = 1033
- ER_NOT_KEYFILE = 1034
- ER_OLD_KEYFILE = 1035
- ER_OPEN_AS_READONLY = 1036
- ER_OUTOFMEMORY = 1037
- ER_OUT_OF_SORTMEMORY = 1038
- ER_UNEXPECTED_EOF = 1039
- ER_CON_COUNT_ERROR = 1040
- ER_OUT_OF_RESOURCES = 1041
- ER_BAD_HOST_ERROR = 1042
- ER_HANDSHAKE_ERROR = 1043
- ER_DBACCESS_DENIED_ERROR = 1044
- ER_ACCESS_DENIED_ERROR = 1045
- ER_NO_DB_ERROR = 1046
- ER_UNKNOWN_COM_ERROR = 1047
- ER_BAD_NULL_ERROR = 1048
- ER_BAD_DB_ERROR = 1049
- ER_TABLE_EXISTS_ERROR = 1050
- ER_BAD_TABLE_ERROR = 1051
- ER_NON_UNIQ_ERROR = 1052
- ER_SERVER_SHUTDOWN = 1053
- ER_BAD_FIELD_ERROR = 1054
- ER_WRONG_FIELD_WITH_GROUP = 1055
- ER_WRONG_GROUP_FIELD = 1056
- ER_WRONG_SUM_SELECT = 1057
- ER_WRONG_VALUE_COUNT = 1058
- ER_TOO_LONG_IDENT = 1059
- ER_DUP_FIELDNAME = 1060
- ER_DUP_KEYNAME = 1061
- ER_DUP_ENTRY = 1062
- ER_WRONG_FIELD_SPEC = 1063
- ER_PARSE_ERROR = 1064
- ER_EMPTY_QUERY = 1065
- ER_NONUNIQ_TABLE = 1066
- ER_INVALID_DEFAULT = 1067
- ER_MULTIPLE_PRI_KEY = 1068
- ER_TOO_MANY_KEYS = 1069
- ER_TOO_MANY_KEY_PARTS = 1070
- ER_TOO_LONG_KEY = 1071
- ER_KEY_COLUMN_DOES_NOT_EXITS = 1072
- ER_BLOB_USED_AS_KEY = 1073
- ER_TOO_BIG_FIELDLENGTH = 1074
- ER_WRONG_AUTO_KEY = 1075
- ER_READY = 1076
- ER_NORMAL_SHUTDOWN = 1077
- ER_GOT_SIGNAL = 1078
- ER_SHUTDOWN_COMPLETE = 1079
- ER_FORCING_CLOSE = 1080
- ER_IPSOCK_ERROR = 1081
- ER_NO_SUCH_INDEX = 1082
- ER_WRONG_FIELD_TERMINATORS = 1083
- ER_BLOBS_AND_NO_TERMINATED = 1084
- ER_TEXTFILE_NOT_READABLE = 1085
- ER_FILE_EXISTS_ERROR = 1086
- ER_LOAD_INFO = 1087
- ER_ALTER_INFO = 1088
- ER_WRONG_SUB_KEY = 1089
- ER_CANT_REMOVE_ALL_FIELDS = 1090
- ER_CANT_DROP_FIELD_OR_KEY = 1091
- ER_INSERT_INFO = 1092
- ER_INSERT_TABLE_USED = 1093
- ER_NO_SUCH_THREAD = 1094
- ER_KILL_DENIED_ERROR = 1095
- ER_NO_TABLES_USED = 1096
- ER_TOO_BIG_SET = 1097
- ER_NO_UNIQUE_LOGFILE = 1098
- ER_TABLE_NOT_LOCKED_FOR_WRITE = 1099
- ER_TABLE_NOT_LOCKED = 1100
- ER_BLOB_CANT_HAVE_DEFAULT = 1101
- ER_WRONG_DB_NAME = 1102
- ER_WRONG_TABLE_NAME = 1103
- ER_TOO_BIG_SELECT = 1104
- ER_UNKNOWN_ERROR = 1105
- ER_UNKNOWN_PROCEDURE = 1106
- ER_WRONG_PARAMCOUNT_TO_PROCEDURE = 1107
- ER_WRONG_PARAMETERS_TO_PROCEDURE = 1108
- ER_UNKNOWN_TABLE = 1109
- ER_FIELD_SPECIFIED_TWICE = 1110
- ER_INVALID_GROUP_FUNC_USE = 1111
- ER_UNSUPPORTED_EXTENSION = 1112
- ER_TABLE_MUST_HAVE_COLUMNS = 1113
- ER_RECORD_FILE_FULL = 1114
- ER_UNKNOWN_CHARACTER_SET = 1115
- ER_TOO_MANY_TABLES = 1116
- ER_TOO_MANY_FIELDS = 1117
- ER_TOO_BIG_ROWSIZE = 1118
- ER_STACK_OVERRUN = 1119
- ER_WRONG_OUTER_JOIN = 1120
- ER_NULL_COLUMN_IN_INDEX = 1121
- ER_CANT_FIND_UDF = 1122
- ER_CANT_INITIALIZE_UDF = 1123
- ER_UDF_NO_PATHS = 1124
- ER_UDF_EXISTS = 1125
- ER_CANT_OPEN_LIBRARY = 1126
- ER_CANT_FIND_DL_ENTRY = 1127
- ER_FUNCTION_NOT_DEFINED = 1128
- ER_HOST_IS_BLOCKED = 1129
- ER_HOST_NOT_PRIVILEGED = 1130
- ER_PASSWORD_ANONYMOUS_USER = 1131
- ER_PASSWORD_NOT_ALLOWED = 1132
- ER_PASSWORD_NO_MATCH = 1133
- ER_UPDATE_INFO = 1134
- ER_CANT_CREATE_THREAD = 1135
- ER_WRONG_VALUE_COUNT_ON_ROW = 1136
- ER_CANT_REOPEN_TABLE = 1137
- ER_INVALID_USE_OF_NULL = 1138
- ER_REGEXP_ERROR = 1139
- ER_MIX_OF_GROUP_FUNC_AND_FIELDS = 1140
- ER_NONEXISTING_GRANT = 1141
- ER_TABLEACCESS_DENIED_ERROR = 1142
- ER_COLUMNACCESS_DENIED_ERROR = 1143
- ER_ILLEGAL_GRANT_FOR_TABLE = 1144
- ER_GRANT_WRONG_HOST_OR_USER = 1145
- ER_NO_SUCH_TABLE = 1146
- ER_NONEXISTING_TABLE_GRANT = 1147
- ER_NOT_ALLOWED_COMMAND = 1148
- ER_SYNTAX_ERROR = 1149
- ER_DELAYED_CANT_CHANGE_LOCK = 1150
- ER_TOO_MANY_DELAYED_THREADS = 1151
- ER_ABORTING_CONNECTION = 1152
- ER_NET_PACKET_TOO_LARGE = 1153
- ER_NET_READ_ERROR_FROM_PIPE = 1154
- ER_NET_FCNTL_ERROR = 1155
- ER_NET_PACKETS_OUT_OF_ORDER = 1156
- ER_NET_UNCOMPRESS_ERROR = 1157
- ER_NET_READ_ERROR = 1158
- ER_NET_READ_INTERRUPTED = 1159
- ER_NET_ERROR_ON_WRITE = 1160
- ER_NET_WRITE_INTERRUPTED = 1161
- ER_TOO_LONG_STRING = 1162
- ER_TABLE_CANT_HANDLE_BLOB = 1163
- ER_TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164
- ER_DELAYED_INSERT_TABLE_LOCKED = 1165
- ER_WRONG_COLUMN_NAME = 1166
- ER_WRONG_KEY_COLUMN = 1167
- ER_WRONG_MRG_TABLE = 1168
- ER_DUP_UNIQUE = 1169
- ER_BLOB_KEY_WITHOUT_LENGTH = 1170
- ER_PRIMARY_CANT_HAVE_NULL = 1171
- ER_TOO_MANY_ROWS = 1172
- ER_REQUIRES_PRIMARY_KEY = 1173
- ER_NO_RAID_COMPILED = 1174
- ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175
- ER_KEY_DOES_NOT_EXITS = 1176
- ER_CHECK_NO_SUCH_TABLE = 1177
- ER_CHECK_NOT_IMPLEMENTED = 1178
- ER_CANT_DO_THIS_DURING_AN_TRANSACTION = 1179
- ER_ERROR_DURING_COMMIT = 1180
- ER_ERROR_DURING_ROLLBACK = 1181
- ER_ERROR_DURING_FLUSH_LOGS = 1182
- ER_ERROR_DURING_CHECKPOINT = 1183
- ER_NEW_ABORTING_CONNECTION = 1184
- ER_DUMP_NOT_IMPLEMENTED = 1185
- ER_FLUSH_MASTER_BINLOG_CLOSED = 1186
- ER_INDEX_REBUILD = 1187
- ER_MASTER = 1188
- ER_MASTER_NET_READ = 1189
- ER_MASTER_NET_WRITE = 1190
- ER_FT_MATCHING_KEY_NOT_FOUND = 1191
- ER_LOCK_OR_ACTIVE_TRANSACTION = 1192
- ER_UNKNOWN_SYSTEM_VARIABLE = 1193
- ER_CRASHED_ON_USAGE = 1194
- ER_CRASHED_ON_REPAIR = 1195
- ER_WARNING_NOT_COMPLETE_ROLLBACK = 1196
- ER_TRANS_CACHE_FULL = 1197
- ER_SLAVE_MUST_STOP = 1198
- ER_SLAVE_NOT_RUNNING = 1199
- ER_BAD_SLAVE = 1200
- ER_MASTER_INFO = 1201
- ER_SLAVE_THREAD = 1202
- ER_TOO_MANY_USER_CONNECTIONS = 1203
- ER_SET_CONSTANTS_ONLY = 1204
- ER_LOCK_WAIT_TIMEOUT = 1205
- ER_LOCK_TABLE_FULL = 1206
- ER_READ_ONLY_TRANSACTION = 1207
- ER_DROP_DB_WITH_READ_LOCK = 1208
- ER_CREATE_DB_WITH_READ_LOCK = 1209
- ER_WRONG_ARGUMENTS = 1210
- ER_NO_PERMISSION_TO_CREATE_USER = 1211
- ER_UNION_TABLES_IN_DIFFERENT_DIR = 1212
- ER_LOCK_DEADLOCK = 1213
- ER_TABLE_CANT_HANDLE_FULLTEXT = 1214
- ER_CANNOT_ADD_FOREIGN = 1215
- ER_NO_REFERENCED_ROW = 1216
- ER_ROW_IS_REFERENCED = 1217
- ER_CONNECT_TO_MASTER = 1218
- ER_QUERY_ON_MASTER = 1219
- ER_ERROR_WHEN_EXECUTING_COMMAND = 1220
- ER_WRONG_USAGE = 1221
- ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222
- ER_CANT_UPDATE_WITH_READLOCK = 1223
- ER_MIXING_NOT_ALLOWED = 1224
- ER_DUP_ARGUMENT = 1225
- ER_USER_LIMIT_REACHED = 1226
- ER_SPECIFIC_ACCESS_DENIED_ERROR = 1227
- ER_LOCAL_VARIABLE = 1228
- ER_GLOBAL_VARIABLE = 1229
- ER_NO_DEFAULT = 1230
- ER_WRONG_VALUE_FOR_VAR = 1231
- ER_WRONG_TYPE_FOR_VAR = 1232
- ER_VAR_CANT_BE_READ = 1233
- ER_CANT_USE_OPTION_HERE = 1234
- ER_NOT_SUPPORTED_YET = 1235
- ER_MASTER_FATAL_ERROR_READING_BINLOG = 1236
- ER_SLAVE_IGNORED_TABLE = 1237
- ER_ERROR_MESSAGES = 238
-
- # Client Error
- CR_MIN_ERROR = 2000
- CR_MAX_ERROR = 2999
- CR_UNKNOWN_ERROR = 2000
- CR_SOCKET_CREATE_ERROR = 2001
- CR_CONNECTION_ERROR = 2002
- CR_CONN_HOST_ERROR = 2003
- CR_IPSOCK_ERROR = 2004
- CR_UNKNOWN_HOST = 2005
- CR_SERVER_GONE_ERROR = 2006
- CR_VERSION_ERROR = 2007
- CR_OUT_OF_MEMORY = 2008
- CR_WRONG_HOST_INFO = 2009
- CR_LOCALHOST_CONNECTION = 2010
- CR_TCP_CONNECTION = 2011
- CR_SERVER_HANDSHAKE_ERR = 2012
- CR_SERVER_LOST = 2013
- CR_COMMANDS_OUT_OF_SYNC = 2014
- CR_NAMEDPIPE_CONNECTION = 2015
- CR_NAMEDPIPEWAIT_ERROR = 2016
- CR_NAMEDPIPEOPEN_ERROR = 2017
- CR_NAMEDPIPESETSTATE_ERROR = 2018
- CR_CANT_READ_CHARSET = 2019
- CR_NET_PACKET_TOO_LARGE = 2020
- CR_EMBEDDED_CONNECTION = 2021
- CR_PROBE_SLAVE_STATUS = 2022
- CR_PROBE_SLAVE_HOSTS = 2023
- CR_PROBE_SLAVE_CONNECT = 2024
- CR_PROBE_MASTER_CONNECT = 2025
- CR_SSL_CONNECTION_ERROR = 2026
- CR_MALFORMED_PACKET = 2027
-
- CLIENT_ERRORS = [
- "Unknown MySQL error",
- "Can't create UNIX socket (%d)",
- "Can't connect to local MySQL server through socket '%-.64s' (%d)",
- "Can't connect to MySQL server on '%-.64s' (%d)",
- "Can't create TCP/IP socket (%d)",
- "Unknown MySQL Server Host '%-.64s' (%d)",
- "MySQL server has gone away",
- "Protocol mismatch. Server Version = %d Client Version = %d",
- "MySQL client run out of memory",
- "Wrong host info",
- "Localhost via UNIX socket",
- "%-.64s via TCP/IP",
- "Error in server handshake",
- "Lost connection to MySQL server during query",
- "Commands out of sync; You can't run this command now",
- "%-.64s via named pipe",
- "Can't wait for named pipe to host: %-.64s pipe: %-.32s (%lu)",
- "Can't open named pipe to host: %-.64s pipe: %-.32s (%lu)",
- "Can't set state of named pipe to host: %-.64s pipe: %-.32s (%lu)",
- "Can't initialize character set %-.64s (path: %-.64s)",
- "Got packet bigger than 'max_allowed_packet'",
- "Embedded server",
- "Error on SHOW SLAVE STATUS:",
- "Error on SHOW SLAVE HOSTS:",
- "Error connecting to slave:",
- "Error connecting to master:",
- "SSL connection error",
- "Malformed packet"
- ]
-
- def initialize(errno, error)
- @errno = errno
- @error = error
- super error
- end
- attr_reader :errno, :error
-
- def Error::err(errno)
- CLIENT_ERRORS[errno - Error::CR_MIN_ERROR]
- end
- end
-
- class Net
- def initialize(sock)
- @sock = sock
- @pkt_nr = 0
- end
-
- def clear()
- @pkt_nr = 0
- end
-
- def read()
- buf = []
- len = nil
- @sock.sync = false
- while len == nil or len == MAX_PACKET_LENGTH do
- a = @sock.read(4)
- len = a[0]+a[1]*256+a[2]*256*256
- pkt_nr = a[3]
- if @pkt_nr != pkt_nr then
- raise "Packets out of order: #{@pkt_nr}<>#{pkt_nr}"
- end
- @pkt_nr = @pkt_nr + 1 & 0xff
- buf << @sock.read(len)
- end
- @sock.sync = true
- buf.join
- rescue
- errno = Error::CR_SERVER_LOST
- raise Error::new(errno, Error::err(errno))
- end
-
- def write(data)
- if data.is_a? Array then
- data = data.join
- end
- @sock.sync = false
- ptr = 0
- while data.length >= MAX_PACKET_LENGTH do
- @sock.write Net::int3str(MAX_PACKET_LENGTH)+@pkt_nr.chr+data[ptr, MAX_PACKET_LENGTH]
- @pkt_nr = @pkt_nr + 1 & 0xff
- ptr += MAX_PACKET_LENGTH
- end
- @sock.write Net::int3str(data.length-ptr)+@pkt_nr.chr+data[ptr .. -1]
- @pkt_nr = @pkt_nr + 1 & 0xff
- @sock.sync = true
- @sock.flush
- rescue
- errno = Error::CR_SERVER_LOST
- raise Error::new(errno, Error::err(errno))
- end
-
- def close()
- @sock.close
- end
-
- def Net::int2str(n)
- [n].pack("v")
- end
-
- def Net::int3str(n)
- [n%256, n>>8].pack("cv")
- end
-
- def Net::int4str(n)
- [n].pack("V")
- end
-
- end
-
- class Random
- def initialize(seed1, seed2)
- @max_value = 0x3FFFFFFF
- @seed1 = seed1 % @max_value
- @seed2 = seed2 % @max_value
- end
-
- def rnd()
- @seed1 = (@seed1*3+@seed2) % @max_value
- @seed2 = (@seed1+@seed2+33) % @max_value
- @seed1.to_f / @max_value
- end
- end
-
-end
-
-class << Mysql
- def init()
- Mysql::new :INIT
- end
-
- def real_connect(*args)
- Mysql::new(*args)
- end
- alias :connect :real_connect
-
- def finalizer(net)
- proc {
- net.clear
- begin
- net.write(Mysql::COM_QUIT.chr)
- net.close
- rescue # Ignore IOError if socket is already closed.
- end
- }
- end
-
- def escape_string(str)
- str.gsub(/([\0\n\r\032\'\"\\])/) do
- case $1
- when "\0" then "\\0"
- when "\n" then "\\n"
- when "\r" then "\\r"
- when "\032" then "\\Z"
- else "\\"+$1
- end
- end
- end
- alias :quote :escape_string
-
- def get_client_info()
- Mysql::VERSION
- end
- alias :client_info :get_client_info
-
- def debug(str)
- raise "not implemented"
- end
-end
-
-#
-# for compatibility
-#
-
-MysqlRes = Mysql::Result
-MysqlField = Mysql::Field
-MysqlError = Mysql::Error