#include #include #include #include #include /* CREATE TABLE `device` ( `id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `serial` CHAR(10) NOT NULL, `pretty` CHAR(20) DEFAULT NULL, CONSTRAINT UNIQUE KEY unique_serial (`serial`) USING HASH, INDEX pretty_index USING HASH (`pretty`) ) ENGINE = InnoDB CHARSET = utf8 COLLATE = utf8_bin; */ static MYSQL* mysql = NULL; // for convenient bailout if we encounter any errors other than the one I'm trying to demo here. :) #define REQUIRE(x) do { if ( !(x) ) { fail(#x, __FUNCTION__, __FILE__, __LINE__); } } while(0) void fail(const char* cond, const char* func, const char* file, int line) { fprintf(stderr, "failed condition %s in %s at %s:%d\n", cond, func, file, line); if (mysql && mysql_errno(mysql)) { fprintf(stderr, "mysql error #%d: '%s'\n", mysql_errno(mysql), mysql_error(mysql)); } exit(1); } int main(int argc, char** argv) { if (argc != 5) { fprintf(stderr, "usage: %s host user password db\n", argv[0]); exit(1); } mysql = mysql_init(NULL); REQUIRE(mysql); REQUIRE(mysql_real_connect(mysql, argv[1], argv[2], argv[3], argv[4], 0, NULL, 0)); MYSQL_STMT* stmt = mysql_stmt_init(mysql); REQUIRE(stmt); const char* sql = "INSERT IGNORE INTO `device` SET `serial`=?, `pretty`=?"; REQUIRE(0 == mysql_stmt_prepare(stmt, sql, strlen(sql))); MYSQL_BIND binds[2]; memset(binds, 0, sizeof(binds)); // bind the two strings char* inputs[] = {"abcdefgh", "something"}; unsigned long length[2]; for (int i=0; i<2; ++i) { binds[i].buffer_type = MYSQL_TYPE_STRING; binds[i].buffer = inputs[i]; length[i] = strlen(inputs[i]); binds[i].buffer_length = length[i]; binds[i].length = &length[i]; } REQUIRE(0 == mysql_stmt_bind_param(stmt, binds)); // execute! This is where the hang occurs. // My environment: // Computer A, running Ubuntu 16.04.1 LTS, with libmysqlclient.so.20.3.4, and mysql server 5.7.17 // Computer B, running Ubuntu 14.04.5 LTS, with libmysqlclient.so.18.0.0, and no mysql server // Both computers are connecting to the server running on Computer A. // Computer B runs fine. Computer A gets stuck down in recv() waiting for more data. // My tcpdumps show that the server has sent the "OK" message fine in both cases. // My debugger shows that Computer A has received the "OK" message, but calls recv() again. // The hang only happens if the cursor type is read-only, and looks related to the // CURSOR_TYPE_READ_ONLY check in execute() in libmysql.c // Of course, a read-only cursor should not be used for inserts (the python lib I was using was // setting it automatically for all cursors), but I'd expect an error for that, not a hang. printf("setting statement to read-only.\n"); unsigned long type = CURSOR_TYPE_READ_ONLY; REQUIRE(0 == mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &type)); printf("executing statement.\n"); REQUIRE(0 == mysql_stmt_execute(stmt)); REQUIRE(0 == mysql_stmt_close(stmt)); mysql_close(mysql); mysql = NULL; }