Bug #21562 | simple select "connection lost during query" | ||
---|---|---|---|
Submitted: | 10 Aug 2006 10:09 | Modified: | 18 Sep 2006 13:53 |
Reporter: | [ name withheld ] | Email Updates: | |
Status: | Not a Bug | Impact on me: | |
Category: | MySQL Server: C API (client library) | Severity: | S1 (Critical) |
Version: | 5.0.22 | OS: | Linux (Fedora Core 5) |
Assigned to: | Magnus Blåudd | CPU Architecture: | Any |
[10 Aug 2006 10:09]
[ name withheld ]
[11 Aug 2006 19:23]
roger andrews
I see the same on windwos selecting just a few rows when using a stored procedure - no ryhme or reason - no timeout being exceeded.
[12 Aug 2006 10:53]
[ name withheld ]
Hi Andrew, while trying to solve my problem I read somewhere a workaround for your problem. Continue searching the bug list. I hope you find it. It had something to do about a stored procedure returning more data than expected so an extra read must be done... Something like that. Good luck! Anybody has any clues on my bug? Thanks
[26 Aug 2006 11:39]
Valeriy Kravchuk
Thank you for a problem report. Please, try to repeat with a newer version, 5.0.24, and inform about the results.
[3 Sep 2006 9:42]
[ name withheld ]
There is no rpm for the 5.0.24 on FC5 yet. So can't upgrade. How is it that you don't provide rpms for FC5. I think it's quite widely used? Anyway, I will report once 5.0.24 is available. Am I the only one with that problem?
[14 Sep 2006 17:34]
Magnus Blåudd
Loading a table with 50000 records and then running the supplied testprogram reproduces the problem.
[14 Sep 2006 17:36]
Magnus Blåudd
Counter: 6859 Counter: 6860 Counter: 6861 Counter: 6862 Counter: 6863 Counter: 6864 Counter: 6865 Counter: 6866 Error: Lost connection to MySQL server during query Counter: 6867
[14 Sep 2006 18:15]
Magnus Blåudd
T@-1296610: | | | | | | | <_mi_read_rnd_dynamic_record T@-1296610: | | | | | | | info: select cond 0x0 T@-1296610: | | | | | | | >end_send T@-1296610: | | | | | | | | >select_send::send_data T@-1296610: | | | | | | | | <select_send::send_data T@-1296610: | | | | | | | | >Protocol::write T@-1296610: | | | | | | | | <Protocol::write T@-1296610: | | | | | | | | packet_header: Memory: 0xb2b72cb0 Bytes: (4) 1B 00 00 A7 T@-1296610: | | | | | | | | >vio_is_blocking T@-1296610: | | | | | | | | | exit: 0 T@-1296610: | | | | | | | | <vio_is_blocking T@-1296610: | | | | | | | | >net_real_write T@-1296610: | | | | | | | | | >query_cache_insert T@-1296610: | | | | | | | | | <query_cache_insert T@-1296610: | | | | | | | | | >vio_write T@-1296610: | | | | | | | | | | enter: sd: 32, buf: 0x0x9e2ffb8, size: 16384 T@-1296610: | | | | | | | | | | vio_error: Got error on write: 11 T@-1296610: | | | | | | | | | | exit: -1 T@-1296610: | | | | | | | | | <vio_write T@-1296610: | | | | | | | | | >thr_alarm T@-1296610: | | | | | | | | | | enter: thread: T@-1296610 sec: 60 T@-1296610: | | | | | | | | | | info: reschedule T@-1296610: | | | | | | | | | <thr_alarm T@-1296208: | >process_alarm T@-1296208: | | info: sig: 14 active alarms: 2 T@-1296610: | | | | | | | | | >vio_blocking T@-1296610: | | | | | | | | | | enter: set_blocking_mode: 1 old_mode: 0 T@-1296208: | <process_alarm T@-1296610: | | | | | | | | | | exit: 0 T@-1296610: | | | | | | | | | <vio_blocking T@-1296610: | | | | | | | | | >vio_write T@-1296610: | | | | | | | | | | enter: sd: 32, buf: 0x0x9e2ffb8, size: 16384 T@-1296208: | >process_alarm T@-1296208: | | info: sig: 14 active alarms: 2 T@-1296208: | | info: sending signal to waiting thread T@-1296208: | <process_alarm T@-1296610: | | | | | | | | | | vio_error: Got error on write: 4 T@-1296610: | | | | | | | | | | exit: -1 T@-1296610: | | | | | | | | | <vio_write T@-1296610: | | | | | | | | | >thr_end_alarm T@-1296610: | | | | | | | | | <thr_end_alarm T@-1296610: | | | | | | | | | >vio_blocking T@-1296610: | | | | | | | | | | enter: set_blocking_mode: 0 old_mode: 1 T@-1296610: | | | | | | | | | | exit: 0 T@-1296610: | | | | | | | | | <vio_blocking T@-1296610: | | | | | | | | <net_real_write It appears that first error 11 and then error 4 is returnd when net_real_write tries to write a 16k buffer to the socket. It has written several times before during the query but now it's most likely full since the client hasn't been reading more than a few records during this time. [msvensson@host mysql-test]$ ../extra/perror 11 OS error code 11: Resource temporarily unavailable [msvensson@host mysql-test]$ ../extra/perror 4 OS error code 4: Interrupted system call
[18 Sep 2006 12:18]
Magnus Blåudd
Hi, I have now looked carefully at the trace files and the code in 'net_real_write' and it looks like this is the expected behaviour. When the server get the order to execute the SELECT it will do that and start sending the rows out onto the network. Since the client is not reading much from the network on the other side, the send and rececive buffers will be full and eventually the MySQL server cant' write anymore. At this point it can't start to sleep and wait for the netwaork buffers to become writeable again since that would mean other threads working with the same table(s) would block. It will however retry the write a number of times before giving up and disconnecting this client, which potentially could have crashed. To workaround you can do one of trhe following solutions. 1. Call the 'mysql_store_result' function instead of 'mysql_use_result' before you start the record processing loop. The 'mysql_store_result' will then buffer all the rows of the query in memory allocated in the client and read. The loop will then read the records from memory. To avoid allocating too much client side memory do a select only of the primary keys for each record. 2. Create a temporary table that holds all the records you want to process. Then read just a couple of records from that table at a time with "SELECT * FROM tmp_table LIMIT 1000", process those records and then delete the proicessed records from the temporary table. When there are no more records in the temporary table all rows has been processed. 3. You could use a cursor from the MySQL Prepared Statement API, that would allow you to tell the server to send you records one by one. See http://dev.mysql.com/doc/refman/5.0/en/mysql-stmt-attr-set.html There are other ways this can be done too. Good Luck! Regards Magnus
[18 Sep 2006 12:37]
Magnus Blåudd
C++ file for reproducing test
Attachment: bug21562.cc (text/x-c++src), 2.09 KiB.
[18 Sep 2006 12:38]
Magnus Blåudd
Test file for running test case from mysql-test-run.pl
Attachment: bug21562.test (application/octet-stream, text), 266 bytes.
[18 Sep 2006 13:53]
[ name withheld ]
Thanks for your reply. I thought MySQL claimed to be capable of handling BIG databases: gigs or even teras big. Solutions 1 & 2 clearly can't be used for a 1 Tera database i.e. Solution 3 requires changes in code. I think MySQL should give this scenario further thought to compare to the big ones: I didn't have this problem on Informix. Thanks for your time and answer anyway.
[18 Sep 2006 14:00]
Magnus Blåudd
Fully agree, will have a look around to see what else can be found.
[18 Sep 2006 17:09]
roger andrews
THis post shows that its nothing to do with large tables of data - and prepared statements dont fix the problem. We need a MySQL engineer looking at this. #include <mysql.h> #include <mysqld_error.h> #define al_mem(S) malloc(S) #define NULL (char *)0 #define nil 0 #define false 0 #define true 1 #define call_db_null(RP,FUNC) { RP = FUNC; if (!RP) goto errexit; } #define call_db(FUNC) { rc = FUNC; if (rc) goto errexit; } #define call_db_void(FUNC) { FUNC; } #define allign8(off) off = ((off + 7) / 8) * 8 typedef struct { my_bool nul; unsigned int len; } ils; int main(argc,argv) int argc; char **argv; { MYSQL *cnp = 0; /* connection handle */ char **cpa[3]; int rc; MYSQL_STMT *stp = 0; MYSQL_STMT *st2p = 0; MYSQL_STMT *st3p = 0; MYSQL_STMT *erp = 0; MYSQL_BIND *pdp,*pd2p,*bdp,*bd2p; MYSQL_RES *rsp = 0; MYSQL_FIELD *fldp; ils *ilp,*il2p,*il3p,*il4p; char buf[100]; char buf2[100]; char buf3[100]; char buf4[32767]; int id; int off; int i; int cnt; char *stnp = nil; if (argc < 4) { printf("Expected uid pwd dbn [svr]\n"); exit(1); } if (!(cnp=mysql_init(cnp))) { printf("mysql_init failed\n"); exit(1); } if (!mysql_real_connect(cnp,(argc > 4 ? argv[4] : NULL), argv[1],argv[2],argv[3], 0,NULL,CLIENT_MULTI_STATEMENTS)) goto errexit; call_db(mysql_autocommit(cnp,false)) /******************************************************************************/ /* Initialize all the statement handles */ /******************************************************************************/ call_db_null(stp, mysql_stmt_init(cnp)) call_db_null(st2p,mysql_stmt_init(cnp)) call_db_null(st3p,mysql_stmt_init(cnp)) if ((pdp = (MYSQL_BIND *)al_mem(3*sizeof(MYSQL_BIND))) == nil) goto mem_err; if ((ilp = (ils *)al_mem(3*sizeof(ils))) == nil) goto mem_err; /******************************************************************************/ /* Send down the stored procedure variables */ /******************************************************************************/ erp = stp; strcpy(buf,"set @v3=?,@v2=?,@v1=?"); call_db(mysql_stmt_prepare(stp,buf,strlen(buf))) id = 1; pd2p = pdp; il2p = ilp; pd2p->buffer_type = MYSQL_TYPE_LONG; pd2p->buffer = (char *)&id; pd2p->buffer_length = 4; pd2p->length = (unsigned long *)&(il2p->len); pd2p->is_null = &(il2p->nul); il2p->len = 4; il2p->nul = false; pd2p++; il2p++; pd2p->buffer_type = FIELD_TYPE_STRING; pd2p->buffer = 0; pd2p->buffer_length = 0; pd2p->length = (unsigned long *)&(il2p->len); pd2p->is_null = &(il2p->nul); il2p->nul = true; pd2p++; il2p++; pd2p->buffer_type = FIELD_TYPE_STRING; pd2p->buffer = 0; pd2p->buffer_length = 0; pd2p->length = (unsigned long *)&(il2p->len); pd2p->is_null = &(il2p->nul); il2p->nul = true; call_db(mysql_stmt_bind_param(stp,pdp)) call_db(mysql_stmt_execute(stp)) /******************************************************************************/ /* Execute the stored procedure */ /******************************************************************************/ strcpy(buf2,"CALL read_salary(@v3,@v2,@v1)"); erp = st2p; printf("Prepare/execute the CALL statement\n"); call_db(mysql_stmt_prepare(st2p,buf2,strlen(buf2))) call_db(mysql_stmt_execute(st2p)) call_db(mysql_stmt_store_result(st2p)) /* otherwise only one open rs */ /******************************************************************************/ /* Fetch the results */ /******************************************************************************/ strcpy(buf3,"select @v2,@v1"); erp = st3p; printf("Prepare/execute the select statement\n"); call_db(mysql_stmt_prepare(st3p,buf3,strlen(buf3))) printf("Get the result metadata\n"); call_db_null(rsp,mysql_stmt_result_metadata(st3p)) printf("%d result columns\n",mysql_num_fields(rsp)); call_db(mysql_stmt_execute(st3p)) if ((bdp=(MYSQL_BIND *)al_mem(2*sizeof(MYSQL_BIND))) == nil) goto mem_err; if ((il3p = (ils *)al_mem(3*sizeof(ils))) == nil) goto mem_err; memset(bdp, 0,2*sizeof(MYSQL_BIND)); memset(il3p,0,3*sizeof(ils)); bd2p = bdp; il4p = il3p; for (i=off=0;i<2;i++,bd2p++,il4p++) { call_db_null(fldp,mysql_fetch_field_direct(rsp,0)) bd2p->buffer_type = fldp->type; bd2p->buffer = buf4 + off; bd2p->buffer_length = fldp->length; bd2p->length = (unsigned long *)&(il4p->len); bd2p->is_null = &(il4p->nul); off += fldp->length; allign8(off); } call_db(mysql_stmt_bind_result(st3p,bdp)) rc = mysql_stmt_fetch(st3p); mysql_free_result(rsp); while ((rc=mysql_stmt_fetch(st3p)) != MYSQL_NO_DATA) if (rc && rc != MYSQL_DATA_TRUNCATED) goto errexit; /******************************************************************************/ /* Now repeat 1000 times */ /******************************************************************************/ for (cnt=1000;cnt;cnt--) { if (!(cnt % 50)) printf("cnt: %d\n",cnt); erp = stp; stnp = "mysql_stmt_bind_param"; call_db(mysql_stmt_bind_param(stp,pdp)) stnp = "mysql_stmt_execute"; call_db(mysql_stmt_execute(stp)) erp = st2p; stnp = "mysql_stmt_execute(2)"; call_db(mysql_stmt_execute(st2p)) stnp = "mysql_stmt_store_result"; call_db(mysql_stmt_store_result(st2p)) /* otherwise only one open rs */ erp = st3p; stnp = "mysql_stmt_bind_result"; call_db(mysql_stmt_bind_result(st3p,bdp)) stnp = "mysql_stmt_execute(3)"; call_db(mysql_stmt_execute(st3p)) stnp = "mysql_stmt_fetch"; rc = mysql_stmt_fetch(st3p); while ((rc=mysql_stmt_fetch(st3p)) != MYSQL_NO_DATA) if (rc && rc != MYSQL_DATA_TRUNCATED) goto errexit; } mysql_close(cnp); exit(0); errexit:; printf("Error!!\n"); if (mysql_stmt_errno(erp)) printf("Errno: %d, %s\n",mysql_stmt_errno(erp),mysql_stmt_error(erp)); if (stnp) printf("Statement was %s\n",stnp); exit(1); mem_err:; printf("Memory error\n"); exit(1); }
[19 Sep 2006 13:16]
Magnus Blåudd
Roger, could you please open a separate bug report for your problem. "2013 Lost connection to server" is a symptom of many various problems. If I understand you correctly there are no sleeps involved in your problem and you are using windows?
[19 Sep 2006 16:50]
roger andrews
magnus I filled 22483 but for this. howewver the suymptons are the same - using stored procedures...
[28 Mar 2007 14:46]
Martin Marinov
Hello I have also some problem with the connection. The query returns 271 rows as result. The data base is small, but when I try to fetch rows, connection is lost. I use Eclipse Version: 3.2.2 MySQL 5.0.37 mingw32 3.80.0-3 to build the project for Windows. Here is the problem code vector< string > executeQuery(mysql_params params, string query) { vector< string > vecDocs; MYSQL conn; MYSQL_RES *res; MYSQL_ROW row; mysql_init(&conn); if (!mysql_real_connect(&conn, params.server, params.user, params.pass, params.sid, params.port, NULL, 0)) { cout << "Failed 1 - Cant connect to database!" << endl; fprintf(stderr, "%s\n", mysql_error(&conn)); exit(0); } // string query = "SELECT doc_parsed_name FROM opt_documents"; /* execute SQL query */ if (mysql_real_query(&conn, query.c_str(), strlen(query.c_str()))) { cout << "Failed 2 - Query is not executed!" << endl; fprintf(stderr, "%s\n", mysql_error(&conn)); exit(0); } res = mysql_use_result(&conn); while (row = mysql_fetch_row(res)) { //here the connection is lost! vecDocs.push_back(row[0]); } /* Release memory used to store results */ mysql_free_result(res); mysql_close(&conn); return vecDocs; } It passes 3 or 4 iterations and thats all. I am not sure if the problem is in mySQL or in MingW. When the program is in debug mode evrything seems to be OK until mysql_fetch_row(res) appears. It returns at best five rows of 271 and the program crushes. When I use mysql_store_result(), the number of the rows is proper, so mysql_num_rows() returns the right value, but mysql_fetch_row(res) fails again after several iterations. Does anyone suggest what could be the problem? Thanks in advance! M.C.