aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/vendor/mysql.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/vendor/mysql.rb')
-rw-r--r--activerecord/lib/active_record/vendor/mysql.rb1117
1 files changed, 1117 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/vendor/mysql.rb b/activerecord/lib/active_record/vendor/mysql.rb
new file mode 100644
index 0000000000..4970f77bd3
--- /dev/null
+++ b/activerecord/lib/active_record/vendor/mysql.rb
@@ -0,0 +1,1117 @@
+# $Id: mysql.rb,v 1.1 2004/02/24 15:42:29 webster132 Exp $
+#
+# Copyright (C) 2003 TOMITA Masahiro
+# tommy@tmtm.org
+#
+
+class Mysql
+
+ VERSION = "4.0-ruby-0.2.4"
+
+ require "socket"
+
+ 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
+
+ # 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_INTERACTIVE = 1 << 10
+ CLIENT_SSL = 1 << 11
+ CLIENT_IGNORE_SIGPIPE = 1 << 12
+ CLIENT_TRANSACTIONS = 1 << 13
+ CLIENT_CAPABILITIES = CLIENT_LONG_PASSWORD|CLIENT_LONG_FLAG|CLIENT_TRANSACTIONS
+
+ # 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.unpack("cv")
+ end
+
+ flag = 0 if flag == nil
+ flag |= @client_flag | CLIENT_CAPABILITIES
+ flag |= CLIENT_CONNECT_WITH_DB if db
+ data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+(user||"")+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)
+ if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0 then
+ data << "\0"+db
+ @db = db.dup
+ end
+ write data
+ read
+ self
+ end
+ alias :connect :real_connect
+
+ 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="")
+ data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db
+ command COM_CHANGE_USER, data
+ @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
+ f = read_rows 6
+ 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
+ fields = read_rows 5
+ @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
+ return if data[0] == 254 and data.length == 1
+ 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)
+ fields = read_rows 5
+ @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|
+ 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
+ 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
+ rnd = Random::new hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]
+ to = []
+ 1.upto(message.length) 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 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
+ GC::start
+ 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
+ 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
+ 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 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