From db045dbbf60b53dbe013ef25554fd013baf88134 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 24 Nov 2004 01:04:44 +0000 Subject: Initial git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/lib/active_record/vendor/mysql.rb | 1117 ++++++++++++++++++++++++ 1 file changed, 1117 insertions(+) create mode 100644 activerecord/lib/active_record/vendor/mysql.rb (limited to 'activerecord/lib/active_record/vendor/mysql.rb') 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 -- cgit v1.2.3