diff options
-rw-r--r-- | Docs/internals.texi | 18 | ||||
-rw-r--r-- | include/mysql.h | 5 | ||||
-rw-r--r-- | include/mysql_com.h | 17 | ||||
-rw-r--r-- | libmysql/libmysql.c | 246 | ||||
-rw-r--r-- | sql/field.cc | 2 | ||||
-rw-r--r-- | sql/field.h | 3 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/mysqld.cc | 32 | ||||
-rw-r--r-- | sql/protocol.cc | 84 | ||||
-rw-r--r-- | sql/protocol.h | 1 | ||||
-rw-r--r-- | sql/repl_failsafe.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 31 |
12 files changed, 279 insertions, 164 deletions
diff --git a/Docs/internals.texi b/Docs/internals.texi index ddaedbe5b9b..ac79724dbe5 100644 --- a/Docs/internals.texi +++ b/Docs/internals.texi @@ -1766,7 +1766,10 @@ following connection establishment sequence is followed: +--------------------------------------------------------------------+ | Header | CLIENT_xxx options supported | max_allowed_packet | | | by client | for client | -| | 2 Bytes | 3 bytes | +| | 4 Bytes | 4 bytes | +|--------------------------------------------------------------------| +| Character set | Reserved for the future | +| 1 Bytes | 23 bytes | |--------------------------------------------------------------------| | User Name | 0x00 | Crypted Password | 0x00 | Database Name | | n Bytes | 1 Byte | 8 Bytes | 1 Byte | n Bytes | @@ -2326,7 +2329,7 @@ Warnings @item Prepared statements @item -Binary protocol (will be faster than the current protocol that +Binary protocol (is be faster than the current protocol that converts everything to strings) @end itemize @@ -2335,7 +2338,7 @@ What has changed in 4.1 are: @itemize @bullet @item -A lot of new field information (database, real table name etc) +A lot of new field information (catalog, database, real table name etc) @item The 'ok' packet has more status fields @item @@ -2374,15 +2377,16 @@ The field description result set contains the meta info for a result set. @multitable @columnfractions .20 .80 @item Type @tab Comment +@item string @tab Catalog name (for 5.x) @item string @tab Database name @item string @tab Table name alias (or table name if no alias) @item string @tab Real table name @item string @tab Alias for column name (or column name if not used) -@item 11 byte @tab Fixed length fields in one field part: +@item 12 byte @tab Fixed length fields in one field part: @itemize @item 2 byte int @tab Character set number -@item 3 byte int @tab Length of column definition +@item 4 byte int @tab Length of column definition @item 1 byte int @tab Enum value for field type @item 3 byte int @tab 2 byte column flags (NOT_NULL_FLAG etc..) + 1 byte number of decimals. @item 2 byte int @tab zero (reserved for future use) @@ -2457,7 +2461,9 @@ The error packet has the following structure: @item Size @tab Comment @item 1 @tab 255 Error packet marker @item 2 @tab Error code -@item 1-255 @tab Null terminated error message +@item 1 @tab '#' marker that SQLSTATE follows +@item 6 @tab SQLSTATE code (000000 for many messages) +@item 1-512 @tab Null terminated error message @end multitable The client/server protocol is designed in such a way that a packet diff --git a/include/mysql.h b/include/mysql.h index 67dc9ae08c9..94f2152655d 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -83,6 +83,7 @@ typedef struct st_mysql_field { char *table; /* Table of column if column was a field */ char *org_table; /* Org table name, if table was an alias */ char *db; /* Database for table */ + char *catalog; /* Catalog for table */ char *def; /* Default value (set by mysql_list_fields) */ unsigned long length; /* Width of column */ unsigned long max_length; /* Max width of selected set */ @@ -91,6 +92,7 @@ typedef struct st_mysql_field { unsigned int table_length; unsigned int org_table_length; unsigned int db_length; + unsigned int catalog_length; unsigned int def_length; unsigned int flags; /* Div flags */ unsigned int decimals; /* Number of decimals in field */ @@ -346,6 +348,7 @@ my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql); my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql); unsigned int STDCALL mysql_errno(MYSQL *mysql); const char * STDCALL mysql_error(MYSQL *mysql); +const char *STDCALL mysql_sqlstate(MYSQL *mysql); unsigned int STDCALL mysql_warning_count(MYSQL *mysql); const char * STDCALL mysql_info(MYSQL *mysql); unsigned long STDCALL mysql_thread_id(MYSQL *mysql); @@ -543,6 +546,7 @@ typedef struct st_mysql_stmt unsigned int last_errno; /* error code */ enum PREP_STMT_STATE state; /* statement state */ char last_error[MYSQL_ERRMSG_SIZE]; /* error message */ + char sqlstate[SQLSTATE_LENGTH+1]; my_bool long_alloced; /* flag to indicate long alloced */ my_bool send_types_to_server; /* Types sent to server */ my_bool param_buffers; /* param bound buffers */ @@ -560,6 +564,7 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt); unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT * stmt); const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt); +const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt); my_bool STDCALL mysql_commit(MYSQL * mysql); my_bool STDCALL mysql_rollback(MYSQL * mysql); my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode); diff --git a/include/mysql_com.h b/include/mysql_com.h index bbfb869927b..e2fa30e3a18 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -25,6 +25,7 @@ #define HOSTNAME_LENGTH 60 #define USERNAME_LENGTH 16 #define SERVER_VERSION_LENGTH 60 +#define SQLSTATE_LENGTH 6 #define LOCAL_HOST "localhost" #define LOCAL_HOST_NAMEDPIPE "." @@ -100,20 +101,22 @@ enum enum_server_command #define CLIENT_ODBC 64 /* Odbc client */ #define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ #define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ +#define CLIENT_PROTOCOL_41 512 /* New 4.1 protocol */ #define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ -#define CLIENT_SSL 2048 /* Switch to SSL after handshake */ -#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ +#define CLIENT_SSL 2048 /* Switch to SSL after handshake */ +#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ #define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ -#define CLIENT_PROTOCOL_41 16384 /* New 4.1 protocol */ -#define CLIENT_SECURE_CONNECTION 32768 /* New 4.1 authentication */ -#define CLIENT_MULTI_QUERIES 65536 /* Enable/disable multi query support */ +#define CLIENT_RESERVED 16384 /* Old flag for 4.1 protocol */ +#define CLIENT_SECURE_CONNECTION 32768 /* New 4.1 authentication */ +#define CLIENT_MULTI_QUERIES 65536 /* Enable/disable multiquery support */ +#define CLIENT_MULTI_RESULTS 131072 /* Enable/disable multi-results */ #define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */ #define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ #define SERVER_STATUS_MORE_RESULTS 4 /* More results on server */ #define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */ -#define MYSQL_ERRMSG_SIZE 200 +#define MYSQL_ERRMSG_SIZE 512 #define NET_READ_TIMEOUT 30 /* Timeout on read */ #define NET_WRITE_TIMEOUT 60 /* Timeout on write */ #define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */ @@ -149,7 +152,7 @@ typedef struct st_net { queries in cache that have not stored its results yet */ #endif - char last_error[MYSQL_ERRMSG_SIZE]; + char last_error[MYSQL_ERRMSG_SIZE], sqlstate[SQLSTATE_LENGTH+1]; unsigned int last_errno; unsigned char error; gptr query_cache_query; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 34dcb7b287e..5971fda141b 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -64,6 +64,7 @@ ulong net_buffer_length=8192; ulong max_allowed_packet= 1024L*1024L*1024L; ulong net_read_timeout= NET_READ_TIMEOUT; ulong net_write_timeout= NET_WRITE_TIMEOUT; +const char *unknown_sqlstate= "000000"; #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG \ | CLIENT_LOCAL_FILES | CLIENT_TRANSACTIONS \ @@ -324,6 +325,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, if (GetLastError() != ERROR_PIPE_BUSY) { net->last_errno=CR_NAMEDPIPEOPEN_ERROR; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error,ER(net->last_errno),host, unix_socket, (ulong) GetLastError()); return INVALID_HANDLE_VALUE; @@ -332,6 +334,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, if (! WaitNamedPipe(szPipeName, connect_timeout*1000) ) { net->last_errno=CR_NAMEDPIPEWAIT_ERROR; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error,ER(net->last_errno),host, unix_socket, (ulong) GetLastError()); return INVALID_HANDLE_VALUE; @@ -340,6 +343,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, if (hPipe == INVALID_HANDLE_VALUE) { net->last_errno=CR_NAMEDPIPEOPEN_ERROR; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error,ER(net->last_errno),host, unix_socket, (ulong) GetLastError()); return INVALID_HANDLE_VALUE; @@ -349,6 +353,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, { CloseHandle( hPipe ); net->last_errno=CR_NAMEDPIPESETSTATE_ERROR; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error,ER(net->last_errno),host, unix_socket, (ulong) GetLastError()); return INVALID_HANDLE_VALUE; @@ -552,6 +557,7 @@ err: if (error_allow) { net->last_errno=error_allow; + strmov(net->sqlstate, unknown_sqlstate); if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR) sprintf(net->last_error,ER(net->last_errno),suffix_pos,error_code); else @@ -590,6 +596,7 @@ net_safe_read(MYSQL *mysql) CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST); strmov(net->last_error,ER(net->last_errno)); + strmov(net->sqlstate, unknown_sqlstate); return (packet_error); } if (net->read_pos[0] == 255) @@ -600,16 +607,22 @@ net_safe_read(MYSQL *mysql) net->last_errno=uint2korr(pos); pos+=2; len-=2; + if (protocol_41(mysql) && pos[0] == '#') + { + strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH); + pos+= SQLSTATE_LENGTH+1; + } (void) strmake(net->last_error,(char*) pos, min((uint) len,(uint) sizeof(net->last_error)-1)); } else { net->last_errno=CR_UNKNOWN_ERROR; - (void) strmov(net->last_error,ER(net->last_errno)); + strmov(net->sqlstate, unknown_sqlstate); + strmov(net->last_error, ER(net->last_errno)); } - DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno, - net->last_error)); + DBUG_PRINT("error",("Got error: %d/%s (%s)", + net->last_errno, net->sqlstate, net->last_error)); return(packet_error); } return len; @@ -645,11 +658,13 @@ advanced_command(MYSQL *mysql, enum enum_server_command command, if (mysql->status != MYSQL_STATUS_READY) { strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); + strmov(net->sqlstate, unknown_sqlstate); return 1; } - mysql->net.last_error[0]=0; - mysql->net.last_errno=0; + net->last_error[0]=0; + net->last_errno=0; + strmov(net->sqlstate, unknown_sqlstate); mysql->info=0; mysql->affected_rows= ~(my_ulonglong) 0; net_clear(&mysql->net); /* Clear receive buffer */ @@ -911,8 +926,8 @@ static const char *default_options[]= "character-sets-dir", "default-character-set", "interactive-timeout", "connect-timeout", "local-infile", "disable-local-infile", "replication-probe", "enable-reads-from-master", "repl-parse-query", - "ssl-cipher", "max-allowed-packet", - "protocol", "shared-memory-base-name", + "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name", + "multi-results", "multi-queries", NullS }; @@ -1101,6 +1116,12 @@ static void mysql_read_default_options(struct st_mysql_options *options, options->shared_memory_base_name=my_strdup(opt_arg,MYF(MY_WME)); #endif break; + case 30: + options->client_flag|= CLIENT_MULTI_RESULTS; + break; + case 31: + options->client_flag|= CLIENT_MULTI_QUERIES | CLIENT_MULTI_RESULTS; + break; default: DBUG_PRINT("warning",("unknown option: %s",option[0])); } @@ -1122,7 +1143,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, { MYSQL_ROWS *row; MYSQL_FIELD *field,*result; - ulong lengths[8]; /* Max of fields */ + ulong lengths[9]; /* Max of fields */ DBUG_ENTER("unpack_fields"); field=result=(MYSQL_FIELD*) alloc_root(alloc, @@ -1139,33 +1160,35 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, for (row=data->data; row ; row = row->next,field++) { uchar *pos; - fetch_lengths(&lengths[0], row->data, default_value ? 7 : 6); - field->db = strdup_root(alloc,(char*) row->data[0]); - field->table = strdup_root(alloc,(char*) row->data[1]); - field->org_table= strdup_root(alloc,(char*) row->data[2]); - field->name = strdup_root(alloc,(char*) row->data[3]); - field->org_name = strdup_root(alloc,(char*) row->data[4]); - - field->db_length= lengths[0]; - field->table_length= lengths[1]; - field->org_table_length= lengths[2]; - field->name_length= lengths[3]; - field->org_name_length= lengths[4]; + fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7); + field->catalog = strdup_root(alloc,(char*) row->data[0]); + field->db = strdup_root(alloc,(char*) row->data[1]); + field->table = strdup_root(alloc,(char*) row->data[2]); + field->org_table= strdup_root(alloc,(char*) row->data[3]); + field->name = strdup_root(alloc,(char*) row->data[4]); + field->org_name = strdup_root(alloc,(char*) row->data[5]); + + field->catalog_length= lengths[0]; + field->db_length= lengths[1]; + field->table_length= lengths[2]; + field->org_table_length= lengths[3]; + field->name_length= lengths[4]; + field->org_name_length= lengths[5]; /* Unpack fixed length parts */ - pos= (uchar*) row->data[5]; + pos= (uchar*) row->data[6]; field->charsetnr= uint2korr(pos); - field->length= (uint) uint3korr(pos+2); - field->type= (enum enum_field_types) pos[5]; - field->flags= uint2korr(pos+6); - field->decimals= (uint) pos[8]; + field->length= (uint) uint4korr(pos+2); + field->type= (enum enum_field_types) pos[6]; + field->flags= uint2korr(pos+7); + field->decimals= (uint) pos[9]; if (INTERNAL_NUM_FIELD(field)) field->flags|= NUM_FLAG; - if (default_value && row->data[6]) + if (default_value && row->data[7]) { - field->def=strdup_root(alloc,(char*) row->data[6]); - field->def_length= lengths[6]; + field->def=strdup_root(alloc,(char*) row->data[7]); + field->def_length= lengths[7]; } else field->def=0; @@ -1236,6 +1259,7 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, MYF(MY_WME | MY_ZEROFILL)))) { net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->sqlstate, unknown_sqlstate); strmov(net->last_error,ER(net->last_errno)); DBUG_RETURN(0); } @@ -1264,6 +1288,7 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, { free_rows(result); net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->sqlstate, unknown_sqlstate); strmov(net->last_error,ER(net->last_errno)); DBUG_RETURN(0); } @@ -1284,6 +1309,7 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, { free_rows(result); net->last_errno=CR_MALFORMED_PACKET; + strmov(net->sqlstate, unknown_sqlstate); strmov(net->last_error,ER(net->last_errno)); DBUG_RETURN(0); } @@ -1328,17 +1354,18 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) ulong pkt_len,len; uchar *pos, *end_pos; uchar *prev_pos; + NET *net= &mysql->net; if ((pkt_len=net_safe_read(mysql)) == packet_error) return -1; - if (pkt_len <= 8 && mysql->net.read_pos[0] == 254) + if (pkt_len <= 8 && net->read_pos[0] == 254) { if (pkt_len > 1) /* MySQL 4.1 protocol */ - mysql->warning_count= uint2korr(mysql->net.read_pos+1); + mysql->warning_count= uint2korr(net->read_pos+1); return 1; /* End of data */ } prev_pos= 0; /* allowed to write at packet[-1] */ - pos=mysql->net.read_pos; + pos=net->read_pos; end_pos=pos+pkt_len; for (field=0 ; field < fields ; field++) { @@ -1351,8 +1378,9 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) { if (len > (ulong) (end_pos - pos)) { - mysql->net.last_errno=CR_UNKNOWN_ERROR; - strmov(mysql->net.last_error,ER(mysql->net.last_errno)); + net->last_errno=CR_UNKNOWN_ERROR; + strmov(net->last_error,ER(net->last_errno)); + strmov(net->sqlstate, unknown_sqlstate); return -1; } row[field] = (char*) pos; @@ -1871,6 +1899,7 @@ static my_bool mysql_autenticate(MYSQL *mysql, const char *passwd) if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net)) { net->last_errno= CR_SERVER_LOST; + strmov(net->sqlstate, unknown_sqlstate); strmov(net->last_error,ER(net->last_errno)); goto error; } @@ -1945,6 +1974,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, /* Don't give sigpipe errors if the client doesn't want them */ set_sigpipe(mysql); net->vio = 0; /* If something goes wrong */ + mysql->client_flag=0; /* For handshake */ /* use default options */ if (mysql->options.my_cnf_file || mysql->options.my_cnf_group) { @@ -2025,6 +2055,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR) { net->last_errno=CR_SOCKET_CREATE_ERROR; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error,ER(net->last_errno),socket_errno); goto error; } @@ -2038,6 +2069,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, DBUG_PRINT("error",("Got error %d on connect to local server", socket_errno)); net->last_errno=CR_CONNECTION_ERROR; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error,ER(net->last_errno),unix_socket,socket_errno); goto error; } @@ -2092,6 +2124,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if ((sock = (my_socket) socket(AF_INET,SOCK_STREAM,0)) == SOCKET_ERROR) { net->last_errno=CR_IPSOCK_ERROR; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error,ER(net->last_errno),socket_errno); goto error; } @@ -2118,6 +2151,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, { my_gethostbyname_r_free(); net->last_errno=CR_UNKNOWN_HOST; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno); goto error; } @@ -2131,6 +2165,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno, host)); net->last_errno= CR_CONN_HOST_ERROR; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, socket_errno); goto error; } @@ -2139,6 +2174,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, { DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol)); net->last_errno= CR_CONN_UNKNOW_PROTOCOL; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error ,ER(CR_CONN_UNKNOW_PROTOCOL)); goto error; } @@ -2148,6 +2184,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, vio_delete(net->vio); net->vio = 0; net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->sqlstate, unknown_sqlstate); strmov(net->last_error,ER(net->last_errno)); goto error; } @@ -2159,6 +2196,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, vio_poll_read(net->vio, mysql->options.connect_timeout)) { net->last_errno= CR_SERVER_LOST; + strmov(net->sqlstate, unknown_sqlstate); strmov(net->last_error,ER(net->last_errno)); goto error; } @@ -2174,6 +2212,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if (mysql->protocol_version != PROTOCOL_VERSION) { net->last_errno= CR_VERSION_ERROR; + strmov(net->sqlstate, unknown_sqlstate); sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version, PROTOCOL_VERSION); goto error; @@ -2216,6 +2255,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if (!mysql->charset) { net->last_errno=CR_CANT_READ_CHARSET; + strmov(net->sqlstate, unknown_sqlstate); if (mysql->options.charset_dir) sprintf(net->last_error,ER(net->last_errno), charset_name ? charset_name : "unknown", @@ -2245,6 +2285,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, !(mysql->user=my_strdup(user,MYF(0))) || !(mysql->passwd=my_strdup(passwd,MYF(0)))) { + strmov(net->sqlstate, unknown_sqlstate); strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY)); goto error; } @@ -2260,6 +2301,8 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, /* Send client information for access check */ client_flag|=CLIENT_CAPABILITIES; + if (client_flag & CLIENT_MULTI_QUERIES) + client_flag|= CLIENT_MULTI_RESULTS; #ifdef HAVE_OPENSSL if (mysql->options.ssl_key || mysql->options.ssl_cert || @@ -2282,10 +2325,12 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if (client_flag & CLIENT_PROTOCOL_41) { - /* 4.1 server and 4.1 client has a 4 byte option flag */ + /* 4.1 server and 4.1 client has a 32 byte option flag */ int4store(buff,client_flag); int4store(buff+4,max_allowed_packet); - end= buff+8; + buff[8]= mysql->charset->number; + bzero(buff+9, 32-9); + end= buff+32; } else { @@ -2305,6 +2350,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, struct st_mysql_options *options= &mysql->options; if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net)) { + strmov(net->sqlstate, unknown_sqlstate); net->last_errno= CR_SERVER_LOST; strmov(net->last_error,ER(net->last_errno)); goto error; @@ -2317,6 +2363,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, options->ssl_capath, options->ssl_cipher))) { + strmov(net->sqlstate, unknown_sqlstate); net->last_errno= CR_SSL_CONNECTION_ERROR; strmov(net->last_error,ER(net->last_errno)); goto error; @@ -2325,6 +2372,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if (sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd), mysql->net.vio, (long) (mysql->options.connect_timeout))) { + strmov(net->sqlstate, unknown_sqlstate); net->last_errno= CR_SSL_CONNECTION_ERROR; strmov(net->last_error,ER(net->last_errno)); goto error; @@ -2385,6 +2433,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, /* Write authentication package */ if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net)) { + strmov(net->sqlstate, unknown_sqlstate); net->last_errno= CR_SERVER_LOST; strmov(net->last_error,ER(net->last_errno)); goto error; @@ -2434,7 +2483,8 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, error: reset_sigpipe(mysql); - DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error)); + DBUG_PRINT("error",("message: %u/%s (%s)", + net->last_errno, net->sqlstate, net->last_error)); { /* Free alloced memory */ my_bool free_me=mysql->free_me; @@ -2477,6 +2527,7 @@ static my_bool mysql_reconnect(MYSQL *mysql) { /* Allow reconnect next time */ mysql->server_status&= ~SERVER_STATUS_IN_TRANS; + strmov(mysql->net.sqlstate, unknown_sqlstate); mysql->net.last_errno=CR_SERVER_GONE_ERROR; strmov(mysql->net.last_error,ER(mysql->net.last_errno)); DBUG_RETURN(1); @@ -2491,6 +2542,7 @@ static my_bool mysql_reconnect(MYSQL *mysql) { mysql->net.last_errno= tmp_mysql.net.last_errno; strmov(mysql->net.last_error, tmp_mysql.net.last_error); + strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate); DBUG_RETURN(1); } tmp_mysql.free_me=mysql->free_me; @@ -2864,46 +2916,52 @@ send_file_to_server(MYSQL *mysql, const char *filename) my_bool result= 1; uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE); char *buf, tmp_name[FN_REFLEN]; + NET *net= &mysql->net; DBUG_ENTER("send_file_to_server"); if (!(buf=my_malloc(packet_length,MYF(0)))) { - strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY)); + strmov(net->sqlstate, unknown_sqlstate); + strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY)); DBUG_RETURN(1); } fn_format(tmp_name,filename,"","",4); /* Convert to client format */ if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0) { - my_net_write(&mysql->net,"",0); /* Server needs one packet */ - net_flush(&mysql->net); - mysql->net.last_errno=EE_FILENOTFOUND; - my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1, - EE(mysql->net.last_errno),tmp_name, errno); + my_net_write(net,"",0); /* Server needs one packet */ + net_flush(net); + strmov(net->sqlstate, unknown_sqlstate); + net->last_errno=EE_FILENOTFOUND; + my_snprintf(net->last_error,sizeof(net->last_error)-1, + EE(net->last_errno),tmp_name, errno); goto err; } while ((readcount = (int) my_read(fd,(byte*) buf,packet_length,MYF(0))) > 0) { - if (my_net_write(&mysql->net,buf,readcount)) + if (my_net_write(net,buf,readcount)) { DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file")); - mysql->net.last_errno=CR_SERVER_LOST; - strmov(mysql->net.last_error,ER(mysql->net.last_errno)); + strmov(net->sqlstate, unknown_sqlstate); + net->last_errno=CR_SERVER_LOST; + strmov(net->last_error,ER(net->last_errno)); goto err; } } /* Send empty packet to mark end of file */ - if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net)) + if (my_net_write(net,"",0) || net_flush(net)) { - mysql->net.last_errno=CR_SERVER_LOST; - sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno); + strmov(net->sqlstate, unknown_sqlstate); + net->last_errno=CR_SERVER_LOST; + sprintf(net->last_error,ER(net->last_errno),errno); goto err; } if (readcount < 0) { - mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */ - my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1, + strmov(net->sqlstate, unknown_sqlstate); + net->last_errno=EE_READ; /* the errmsg for not entire file read */ + my_snprintf(net->last_error,sizeof(net->last_error)-1, tmp_name,errno); goto err; } @@ -2935,6 +2993,7 @@ mysql_store_result(MYSQL *mysql) DBUG_RETURN(0); if (mysql->status != MYSQL_STATUS_GET_RESULT) { + strmov(mysql->net.sqlstate, unknown_sqlstate); strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); DBUG_RETURN(0); @@ -2945,6 +3004,7 @@ mysql_store_result(MYSQL *mysql) mysql->field_count), MYF(MY_WME | MY_ZEROFILL)))) { + strmov(mysql->net.sqlstate, unknown_sqlstate); mysql->net.last_errno=CR_OUT_OF_MEMORY; strmov(mysql->net.last_error, ER(mysql->net.last_errno)); DBUG_RETURN(0); @@ -2990,6 +3050,7 @@ mysql_use_result(MYSQL *mysql) DBUG_RETURN(0); if (mysql->status != MYSQL_STATUS_GET_RESULT) { + strmov(mysql->net.sqlstate, unknown_sqlstate); strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); DBUG_RETURN(0); @@ -3319,6 +3380,7 @@ mysql_stat(MYSQL *mysql) mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */ if (!mysql->net.read_pos[0]) { + strmov(mysql->net.sqlstate, unknown_sqlstate); mysql->net.last_errno=CR_WRONG_HOST_INFO; strmov(mysql->net.last_error, ER(mysql->net.last_errno)); return mysql->net.last_error; @@ -3511,6 +3573,11 @@ uint STDCALL mysql_errno(MYSQL *mysql) return mysql->net.last_errno; } +const char *STDCALL mysql_sqlstate(MYSQL *mysql) +{ + return mysql->net.sqlstate; +} + const char * STDCALL mysql_error(MYSQL *mysql) { return mysql->net.last_error; @@ -3761,7 +3828,8 @@ myodbc_remove_escape(MYSQL *mysql,char *name) Set the internal stmt error messages */ -static void set_stmt_error(MYSQL_STMT * stmt, int errcode) +static void set_stmt_error(MYSQL_STMT * stmt, int errcode, + const char *sqlstate) { DBUG_ENTER("set_stmt_error"); DBUG_PRINT("enter", ("error: %d '%s'", errcode, ER(errcode))); @@ -3769,6 +3837,7 @@ static void set_stmt_error(MYSQL_STMT * stmt, int errcode) stmt->last_errno= errcode; strmov(stmt->last_error, ER(errcode)); + strmov(stmt->sqlstate, sqlstate); DBUG_VOID_RETURN; } @@ -3778,15 +3847,17 @@ static void set_stmt_error(MYSQL_STMT * stmt, int errcode) Copy error message to statement handler */ -static void set_stmt_errmsg(MYSQL_STMT * stmt, char *err, int errcode) +static void set_stmt_errmsg(MYSQL_STMT * stmt, const char *err, int errcode, + const char *sqlstate) { DBUG_ENTER("set_stmt_error_msg"); - DBUG_PRINT("enter", ("error: %d '%s'", errcode, err)); + DBUG_PRINT("enter", ("error: %d/%s '%s'", errcode, sqlstate, err)); DBUG_ASSERT(stmt != 0); stmt->last_errno= errcode; if (err && err[0]) strmov(stmt->last_error, err); + strmov(stmt->sqlstate, sqlstate); DBUG_VOID_RETURN; } @@ -3796,7 +3867,7 @@ static void set_stmt_errmsg(MYSQL_STMT * stmt, char *err, int errcode) Set the internal error message to mysql handler */ -static void set_mysql_error(MYSQL * mysql, int errcode) +static void set_mysql_error(MYSQL * mysql, int errcode, const char *sqlstate) { DBUG_ENTER("set_mysql_error"); DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode))); @@ -3804,6 +3875,7 @@ static void set_mysql_error(MYSQL * mysql, int errcode) mysql->net.last_errno= errcode; strmov(mysql->net.last_error, ER(errcode)); + strmov(mysql->net.sqlstate, sqlstate); } @@ -3873,7 +3945,7 @@ static my_bool read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) mysql->server_status|= SERVER_STATUS_IN_TRANS; mysql->extra_info= net_field_length_ll(&pos); - if (!(fields_data= read_rows(mysql, (MYSQL_FIELD*) 0, 8))) + if (!(fields_data= read_rows(mysql, (MYSQL_FIELD*) 0, 9))) DBUG_RETURN(1); if (!(stmt->fields= unpack_fields(fields_data,&stmt->mem_root, field_count,0, @@ -3885,7 +3957,7 @@ static my_bool read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) (param_count + field_count)))) { - set_stmt_error(stmt, CR_OUT_OF_MEMORY); + set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(0); } stmt->bind= (stmt->params + param_count); @@ -3915,7 +3987,7 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length) #ifdef CHECK_EXTRA_ARGUMENTS if (!query) { - set_mysql_error(mysql, CR_NULL_POINTER); + set_mysql_error(mysql, CR_NULL_POINTER, unknown_sqlstate); DBUG_RETURN(0); } #endif @@ -3925,7 +3997,7 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length) !(stmt->query= my_strdup_with_length((byte *) query, length, MYF(0)))) { my_free((gptr) stmt, MYF(MY_ALLOW_ZERO_PTR)); - set_mysql_error(mysql, CR_OUT_OF_MEMORY); + set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(0); } if (simple_command(mysql, COM_PREPARE, query, length, 1)) @@ -4266,7 +4338,7 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) */ if ((my_realloc_str(net, 9 + *param->length))) { - set_stmt_error(stmt, CR_OUT_OF_MEMORY); + set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(1); } (*param->store_param_func)(net, param); @@ -4293,7 +4365,7 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length) length, 1) || mysql_read_query_result(mysql)) { - set_stmt_errmsg(stmt, net->last_error, net->last_errno); + set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); DBUG_RETURN(1); } stmt->state= MY_ST_EXECUTE; @@ -4315,7 +4387,7 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt) if (stmt->state == MY_ST_UNKNOWN) { - set_stmt_error(stmt, CR_NO_PREPARE_STMT); + set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate); DBUG_RETURN(1); } if (stmt->param_count) @@ -4331,7 +4403,7 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt) if (!stmt->param_buffers) { /* Parameters exists, but no bound buffers */ - set_stmt_error(stmt, CR_NOT_ALL_PARAMS_BOUND); + set_stmt_error(stmt, CR_NOT_ALL_PARAMS_BOUND, unknown_sqlstate); DBUG_RETURN(1); } #endif @@ -4366,7 +4438,7 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt) /* TODO: Look into avoding the following memdup */ if (!(param_data= my_memdup((const char*) net->buff, length, MYF(0)))) { - set_stmt_error(stmt, CR_OUT_OF_MEMORY); + set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(1); } net->write_pos= net->buff; /* Reset for net_write() */ @@ -4417,12 +4489,12 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) #ifdef CHECK_EXTRA_ARGUMENTS if (stmt->state == MY_ST_UNKNOWN) { - set_stmt_error(stmt, CR_NO_PREPARE_STMT); + set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate); DBUG_RETURN(1); } if (!stmt->param_count) { - set_stmt_error(stmt, CR_NO_PARAMETERS_EXISTS); + set_stmt_error(stmt, CR_NO_PARAMETERS_EXISTS, unknown_sqlstate); DBUG_RETURN(1); } #endif @@ -4505,6 +4577,7 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) param->store_param_func= store_param_str; break; default: + strmov(stmt->sqlstate, unknown_sqlstate); sprintf(stmt->last_error, ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE), param->buffer_type, count); @@ -4550,7 +4623,7 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, if (param_number >= stmt->param_count) { - set_stmt_error(stmt, CR_INVALID_PARAMETER_NO); + set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate); DBUG_RETURN(1); } param= stmt->params+param_number; @@ -4561,6 +4634,7 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, Long data handling should be used only for string/binary types only */ + strmov(stmt->sqlstate, unknown_sqlstate); sprintf(stmt->last_error, ER(stmt->last_errno= CR_INVALID_BUFFER_USE), param->param_number); DBUG_RETURN(1); @@ -4583,8 +4657,8 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, if (advanced_command(mysql, COM_LONG_DATA, extra_data, MYSQL_LONG_DATA_HEADER, data, length, 1)) { - set_stmt_errmsg(stmt,(char *) mysql->net.last_error, - mysql->net.last_errno); + set_stmt_errmsg(stmt, mysql->net.last_error, + mysql->net.last_errno, mysql->net.sqlstate); DBUG_RETURN(1); } } @@ -5123,12 +5197,12 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) #ifdef CHECK_EXTRA_ARGUMENTS if (stmt->state == MY_ST_UNKNOWN) { - set_stmt_error(stmt, CR_NO_PREPARE_STMT); + set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate); DBUG_RETURN(1); } if (!bind) { - set_stmt_error(stmt, CR_NULL_POINTER); + set_stmt_error(stmt, CR_NULL_POINTER, unknown_sqlstate); DBUG_RETURN(1); } #endif @@ -5208,6 +5282,7 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) param->fetch_result= fetch_result_str; break; default: + strmov(stmt->sqlstate, unknown_sqlstate); sprintf(stmt->last_error, ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE), param->buffer_type, param_count); @@ -5296,8 +5371,8 @@ int STDCALL mysql_fetch(MYSQL_STMT *stmt) { if (packet_error == net_safe_read(mysql)) { - set_stmt_errmsg(stmt,(char *)mysql->net.last_error, - mysql->net.last_errno); + set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, + mysql->net.sqlstate); DBUG_RETURN(1); } if (mysql->net.read_pos[0] == 254) @@ -5447,8 +5522,9 @@ static MYSQL_DATA *read_binary_rows(MYSQL_STMT *stmt) mysql= mysql->last_used_con; if ((pkt_len= net_safe_read(mysql)) == packet_error) { - set_stmt_errmsg(stmt,(char *)mysql->net.last_error, - mysql->net.last_errno); + set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, + mysql->net.sqlstate); + DBUG_RETURN(0); } if (mysql->net.read_pos[0] == 254) /* end of data */ @@ -5457,8 +5533,8 @@ static MYSQL_DATA *read_binary_rows(MYSQL_STMT *stmt) if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), MYF(MY_WME | MY_ZEROFILL)))) { - net->last_errno=CR_OUT_OF_MEMORY; - strmov(net->last_error,ER(net->last_errno)); + set_stmt_errmsg(stmt, ER(CR_OUT_OF_MEMORY), CR_OUT_OF_MEMORY, + unknown_sqlstate); DBUG_RETURN(0); } init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */ @@ -5474,8 +5550,8 @@ static MYSQL_DATA *read_binary_rows(MYSQL_STMT *stmt) !(cur->data= ((MYSQL_ROW) alloc_root(&result->alloc, pkt_len)))) { free_rows(result); - net->last_errno=CR_OUT_OF_MEMORY; - strmov(net->last_error,ER(net->last_errno)); + set_stmt_errmsg(stmt, ER(CR_OUT_OF_MEMORY), CR_OUT_OF_MEMORY, + unknown_sqlstate); DBUG_RETURN(0); } *prev_ptr= cur; @@ -5514,7 +5590,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) DBUG_RETURN(0); if (mysql->status != MYSQL_STATUS_GET_RESULT) { - set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC); + set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); DBUG_RETURN(1); } mysql->status= MYSQL_STATUS_READY; /* server is ready */ @@ -5523,7 +5599,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) stmt->field_count), MYF(MY_WME | MY_ZEROFILL)))) { - set_stmt_error(stmt, CR_OUT_OF_MEMORY); + set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); DBUG_RETURN(1); } stmt->result_buffered= 1; @@ -5663,7 +5739,8 @@ static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list) int4store(buff, stmt->stmt_id); if (simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1)) { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno); + set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, + mysql->net.sqlstate); stmt->mysql= NULL; /* connection isn't valid anymore */ DBUG_RETURN(1); } @@ -5694,6 +5771,12 @@ uint STDCALL mysql_stmt_errno(MYSQL_STMT * stmt) DBUG_RETURN(stmt->last_errno); } +const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt) +{ + DBUG_ENTER("mysql_stmt_sqlstate"); + DBUG_RETURN(stmt->sqlstate); +} + /* Return statement error message */ @@ -5775,6 +5858,7 @@ my_bool STDCALL mysql_next_result(MYSQL *mysql) mysql->net.last_error[0]= 0; mysql->net.last_errno= 0; + strmov(mysql->net.sqlstate, unknown_sqlstate); mysql->affected_rows= ~(my_ulonglong) 0; if (mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS) diff --git a/sql/field.cc b/sql/field.cc index 5c3961a949e..3397e9fa0ea 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5519,6 +5519,6 @@ void Field::set_warning(const uint level, const uint code) { THD *thd= current_thd; thd->cuted_fields++; - push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level)level, + push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level, code, ER(code), field_name, thd->row_count); } diff --git a/sql/field.h b/sql/field.h index cf08b1a9717..f16af9cfe0f 100644 --- a/sql/field.h +++ b/sql/field.h @@ -212,8 +212,7 @@ public: virtual bool get_time(TIME *ltime); virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } virtual void set_charset(CHARSET_INFO *charset) { } - virtual void set_warning(const unsigned int level, - const unsigned int code); + void set_warning(const unsigned int level, const unsigned int code); friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(my_string name, register TABLE *form, uint options, ulonglong auto_increment_value); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c618b6bacd3..712c8853a20 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -384,7 +384,7 @@ void table_cache_init(void); void table_cache_free(void); uint cached_tables(void); void kill_mysql(void); -void close_connection(NET *net,uint errcode=0,bool lock=1); +void close_connection(THD *thd, uint errcode, bool lock); bool check_access(THD *thd, ulong access, const char *db=0, ulong *save_priv=0, bool no_grant=0, bool no_errors=0); bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6603e4c306a..fe78c0fe27c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -597,7 +597,6 @@ static void close_connections(void) /* Force remaining threads to die by closing the connection to the client */ - (void) my_net_init(&net, (st_vio*) 0); for (;;) { DBUG_PRINT("quit",("Locking LOCK_thread_count")); @@ -609,17 +608,16 @@ static void close_connections(void) break; } #ifndef __bsdi__ // Bug in BSDI kernel - if ((net.vio=tmp->net.vio) != 0) + if (tmp->net.vio) { sql_print_error(ER(ER_FORCING_CLOSE),my_progname, tmp->thread_id,tmp->user ? tmp->user : ""); - close_connection(&net,0,0); + close_connection(tmp,0,0); } #endif DBUG_PRINT("quit",("Unlocking LOCK_thread_count")); (void) pthread_mutex_unlock(&LOCK_thread_count); } - net_end(&net); /* All threads has now been aborted */ DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); (void) pthread_mutex_lock(&LOCK_thread_count); @@ -1215,19 +1213,20 @@ void yyerror(const char *s) #ifndef EMBEDDED_LIBRARY -void close_connection(NET *net,uint errcode,bool lock) +void close_connection(THD *thd, uint errcode, bool lock) { - st_vio* vio; + st_vio *vio; DBUG_ENTER("close_connection"); DBUG_PRINT("enter",("fd: %s error: '%s'", - net->vio? vio_description(net->vio):"(not connected)", - errcode ? ER(errcode) : "")); + thd->net.vio ? vio_description(thd->net.vio) : + "(not connected)", + errcode ? ER(errcode) : "")); if (lock) (void) pthread_mutex_lock(&LOCK_thread_count); - if ((vio=net->vio) != 0) + if ((vio=thd->net.vio) != 0) { if (errcode) - net_send_error(net,errcode,ER(errcode)); /* purecov: inspected */ + send_error(thd, errcode, ER(errcode)); /* purecov: inspected */ vio_close(vio); /* vio is freed in delete thd */ } if (lock) @@ -2717,7 +2716,7 @@ static void create_new_thread(THD *thd) if (thread_count - delayed_insert_threads >= max_connections+1 || abort_loop) { DBUG_PRINT("error",("Too many connections")); - close_connection(net,ER_CON_COUNT_ERROR); + close_connection(thd, ER_CON_COUNT_ERROR, 1); delete thd; DBUG_VOID_RETURN; } @@ -2772,7 +2771,7 @@ static void create_new_thread(THD *thd) (void) pthread_mutex_unlock(&LOCK_thread_count); net_printf(thd,ER_CANT_CREATE_THREAD,error); (void) pthread_mutex_lock(&LOCK_thread_count); - close_connection(net,0,0); + close_connection(thd,0,0); delete thd; (void) pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; @@ -3093,7 +3092,7 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg) if (!(thd->net.vio = vio_new_win32pipe(hConnectedPipe)) || my_net_init(&thd->net, thd->net.vio)) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); delete thd; continue; } @@ -3294,7 +3293,7 @@ Send number of connection to client event_client_read,event_server_wrote,event_server_read)) || my_net_init(&thd->net, thd->net.vio)) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); delete thd; error_allow = TRUE; } @@ -5284,6 +5283,11 @@ static void get_options(int argc,char **argv) if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); + if (argc > 0) + { + fprintf(stderr, "%s: Too many arguments.\nUse --help to get a list of available options\n", my_progname); + exit(ho_error); + } #if defined(HAVE_BROKEN_REALPATH) my_use_symdir=0; diff --git a/sql/protocol.cc b/sql/protocol.cc index 09531f0922c..848321c1576 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -52,7 +52,7 @@ void send_error(THD *thd, uint sql_errno, const char *err) { #ifndef EMBEDDED_LIBRARY uint length; - char buff[MYSQL_ERRMSG_SIZE+2]; + char buff[MYSQL_ERRMSG_SIZE+2], *pos; #endif NET *net= &thd->net; DBUG_ENTER("send_error"); @@ -98,7 +98,14 @@ void send_error(THD *thd, uint sql_errno, const char *err) if (net->return_errno) { // new client code; Add errno before message int2store(buff,sql_errno); - length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff); + pos= buff+2; + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + /* The first # is to make the protocol backward compatible */ + strmov(buff+2, "#000000"); + pos= buff + 2 + SQLSTATE_LENGTH +1; + } + length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff); err=buff; } else @@ -113,26 +120,6 @@ void send_error(THD *thd, uint sql_errno, const char *err) DBUG_VOID_RETURN; } -/* - Send an error to the client when a connection is forced close - This is used by mysqld.cc, which doesn't have a THD -*/ - -#ifndef EMBEDDED_LIBRARY -void net_send_error(NET *net, uint sql_errno, const char *err) -{ - char buff[2]; - uint length; - DBUG_ENTER("send_net_error"); - - int2store(buff,sql_errno); - length=(uint) strlen(err); - set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); - net_write_command(net,(uchar) 255, buff, 2, err, length); - DBUG_VOID_RETURN; -} -#endif - /* Send a warning to the end user @@ -173,7 +160,7 @@ net_printf(THD *thd, uint errcode, ...) #ifndef EMBEDDED_LIBRARY const char *text_pos; #else - char text_pos[500]; + char text_pos[1024]; #endif int head_length= NET_HEADER_SIZE; NET *net= &thd->net; @@ -199,9 +186,11 @@ net_printf(THD *thd, uint errcode, ...) format=va_arg(args,char*); errcode= ER_UNKNOWN_ERROR; } - offset= net->return_errno ? 2 : 0; + offset= (net->return_errno ? + ((thd->client_capabilities & CLIENT_PROTOCOL_41) ? + 2+SQLSTATE_LENGTH+1 : 2) : 0); #ifndef EMBEDDED_LIBRARY - text_pos=(char*) net->buff+head_length+offset+1; + text_pos=(char*) net->buff + head_length + offset + 1; #endif (void) vsprintf(my_const_cast(char*) (text_pos),format,args); length=(uint) strlen((char*) text_pos); @@ -228,7 +217,15 @@ net_printf(THD *thd, uint errcode, ...) net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); net->buff[head_length]=(uchar) 255; // Error package if (offset) - int2store(text_pos-2, errcode); + { + uchar *pos= net->buff+head_length+1; + int2store(pos, errcode); + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + /* The first # is to make the protocol backward compatible */ + memcpy(pos+2, "#000000", SQLSTATE_LENGTH +1); + } + } VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset)); #else net->last_errno= errcode; @@ -502,6 +499,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag) String tmp((char*) buff,sizeof(buff),&my_charset_bin); Protocol_simple prot(thd); String *packet= prot.storage_packet(); + CHARSET_INFO *thd_charset= thd->charset(); DBUG_ENTER("send_fields"); if (flag & 1) @@ -526,36 +524,37 @@ bool Protocol::send_fields(List<Item> *list, uint flag) if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - if (prot.store(field.db_name, (uint) strlen(field.db_name), - cs, thd->charset()) || + if (prot.store("std", 3, cs, thd_charset) || + prot.store(field.db_name, (uint) strlen(field.db_name), + cs, thd_charset) || prot.store(field.table_name, (uint) strlen(field.table_name), - cs, thd->charset()) || + cs, thd_charset) || prot.store(field.org_table_name, (uint) strlen(field.org_table_name), - cs, thd->charset()) || + cs, thd_charset) || prot.store(field.col_name, (uint) strlen(field.col_name), - cs, thd->charset()) || + cs, thd_charset) || prot.store(field.org_col_name, (uint) strlen(field.org_col_name), - cs, thd->charset()) || + cs, thd_charset) || packet->realloc(packet->length()+12)) goto err; /* Store fixed length fields */ pos= (char*) packet->ptr()+packet->length(); - *pos++= 11; // Length of packed fields + *pos++= 12; // Length of packed fields int2store(pos, field.charsetnr); - int3store(pos+2, field.length); - pos[5]= field.type; - int2store(pos+6,field.flags); - pos[8]= (char) field.decimals; - pos[9]= 0; // For the future + int4store(pos+2, field.length); + pos[6]= field.type; + int2store(pos+7,field.flags); + pos[9]= (char) field.decimals; pos[10]= 0; // For the future - pos+= 11; + pos[11]= 0; // For the future + pos+= 12; } else { if (prot.store(field.table_name, (uint) strlen(field.table_name), - cs, thd->charset()) || + cs, thd_charset) || prot.store(field.col_name, (uint) strlen(field.col_name), - cs, thd->charset()) || + cs, thd_charset) || packet->realloc(packet->length()+10)) goto err; pos= (char*) packet->ptr()+packet->length(); @@ -893,9 +892,10 @@ bool Protocol_simple::store_time(TIME *tm) #endif char buff[40]; uint length; + uint day= (tm->year || tm->month) ? 0 : tm->day; length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d", tm->neg ? "-" : "", - (long) tm->day*3600L+(long) tm->hour, + (long) day*24L+(long) tm->hour, (int) tm->minute, (int) tm->second)); return net_store_data((char*) buff, length); diff --git a/sql/protocol.h b/sql/protocol.h index dd644afd335..2110f1877c2 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -162,7 +162,6 @@ void net_printf(THD *thd,uint sql_errno, ...); void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); void send_eof(THD *thd, bool no_flush=0); -void net_send_error(NET *net, uint sql_errno, const char *err); char *net_store_length(char *packet,ulonglong length); char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from, uint length); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 58769827bed..896537dfe04 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -72,7 +72,7 @@ static int init_failsafe_rpl_thread(THD* thd) if (init_thr_lock() || thd->store_globals()) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); // is this needed? + close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed? end_thread(thd,0); DBUG_RETURN(-1); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e8f028e3720..e6ffec7ef26 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -601,8 +601,8 @@ check_connections(THD *thd) { /* buff[] needs to big enough to hold the server_version variable */ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64]; - int client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | - CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); + ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | + CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); if (opt_using_transactions) client_flags|=CLIENT_TRANSACTIONS; @@ -644,11 +644,26 @@ check_connections(THD *thd) return(ER_OUT_OF_RESOURCES); thd->client_capabilities=uint2korr(net->read_pos); +#ifdef TO_BE_REMOVED_IN_4_1_RELEASE + /* + This is just a safety check against any client that would use the old + CLIENT_CHANGE_USER flag + */ + if ((thd->client_capabilities & CLIENT_PROTOCOL_41) && + !(thd->client_capabilities & (CLIENT_RESERVED | + CLIENT_SECURE_CONNECTION | + CLIENT_MULTI_RESULTS))) + thd->client_capabilities&= ~CLIENT_PROTOCOL_41; +#endif if (thd->client_capabilities & CLIENT_PROTOCOL_41) { thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; thd->max_client_packet_length= uint4korr(net->read_pos+4); - end= (char*) net->read_pos+8; + if (!(thd->variables.character_set_client= + get_charset((uint) net->read_pos[8], MYF(0)))) + thd->variables.character_set_client= + global_system_variables.character_set_client; + end= (char*) net->read_pos+32; } else { @@ -778,7 +793,7 @@ pthread_handler_decl(handle_one_connection,arg) // The following calls needs to be done before we call DBUG_ macros if (!(test_flags & TEST_NO_THREADS) & my_thread_init()) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); statistic_increment(aborted_connects,&LOCK_status); end_thread(thd,0); return 0; @@ -805,7 +820,7 @@ pthread_handler_decl(handle_one_connection,arg) #endif if (thd->store_globals()) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); statistic_increment(aborted_connects,&LOCK_status); end_thread(thd,0); return 0; @@ -863,7 +878,7 @@ pthread_handler_decl(handle_one_connection,arg) } end_thread: - close_connection(net); + close_connection(thd, 0, 1); end_thread(thd,1); /* If end_thread returns, we are either running with --one-thread @@ -889,7 +904,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg) /* The following must be called before DBUG_ENTER */ if (my_thread_init() || thd->store_globals()) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); thd->fatal_error(); goto end; } @@ -1419,7 +1434,7 @@ restore_user: #ifndef OS2 send_eof(thd); // This is for 'quit request' #endif - close_connection(net); + close_connection(thd, 0, 1); close_thread_tables(thd); // Free before kill free_root(&thd->mem_root,MYF(0)); free_root(&thd->transaction.mem_root,MYF(0)); |