MySQL: Avoid allocating the full column size to receive results, for variable-length types check result size before allocation (thanks Florob)

Fri, 29 Jun 2012 17:45:37 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Fri, 29 Jun 2012 17:45:37 +0100
changeset 45
7c968f66bccd
parent 44
aab3ed7d93fe
child 46
5ba1dd988961

MySQL: Avoid allocating the full column size to receive results, for variable-length types check result size before allocation (thanks Florob)

dbd/mysql/statement.c file | annotate | diff | comparison | revisions
--- a/dbd/mysql/statement.c	Fri Dec 24 00:34:04 2010 +0000
+++ b/dbd/mysql/statement.c	Fri Jun 29 17:45:37 2012 +0100
@@ -286,8 +286,9 @@
 }
 
 static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) {
-    int column_count;
+    int column_count, fetch_result_ok;
     MYSQL_BIND *bind = NULL;
+    unsigned long *real_length = NULL;
     const char *error_message = NULL;
 
     if (!statement->stmt) {
@@ -306,6 +307,8 @@
 	int i;
 	MYSQL_FIELD *fields;
 
+	real_length = calloc(column_count, sizeof(unsigned long));
+
         bind = malloc(sizeof(MYSQL_BIND) * column_count);
         memset(bind, 0, sizeof(MYSQL_BIND) * column_count);
 
@@ -313,12 +316,19 @@
 
 	for (i = 0; i < column_count; i++) {
 	    unsigned int length = mysql_buffer_size(&fields[i]);
-	    char *buffer = (char *)malloc(length);
-	    memset(buffer, 0, length);
+	    if (length > sizeof(MYSQL_TIME)) {
+		bind[i].buffer = NULL;
+		bind[i].buffer_length = 0;
+	    } else {
+		char *buffer = (char *)malloc(length);
+		memset(buffer, 0, length);
+
+		bind[i].buffer = buffer;
+		bind[i].buffer_length = length;
+	    }
 
 	    bind[i].buffer_type = fields[i].type; 
-	    bind[i].buffer = buffer;
-	    bind[i].buffer_length = length;
+	    bind[i].length = &real_length[i];
 	}
 
 	if (mysql_stmt_bind_result(statement->stmt, bind)) {
@@ -326,7 +336,8 @@
 	    goto cleanup;
 	}
 
-	if (!mysql_stmt_fetch(statement->stmt)) {
+	fetch_result_ok = mysql_stmt_fetch(statement->stmt);
+	if (fetch_result_ok == 0 || fetch_result_ok == MYSQL_DATA_TRUNCATED) {
 	    int d = 1;
 
 	    lua_newtable(L);
@@ -334,6 +345,15 @@
 		lua_push_type_t lua_push = mysql_to_lua_push(fields[i].type);
 		const char *name = fields[i].name;
 
+		if (bind[i].buffer == NULL) {
+		    char *buffer = (char *)malloc(real_length[i]);
+		    memset(buffer, 0, real_length[i]);
+
+		    bind[i].buffer = buffer;
+		    bind[i].buffer_length = real_length[i];
+		    mysql_stmt_fetch_column(statement->stmt, bind, i, 0);
+		}
+
 		if (lua_push == LUA_PUSH_NIL) {
 		    if (named_columns) {
 			LUA_PUSH_ATTRIB_NIL(name);
@@ -425,6 +445,8 @@
     }
 
 cleanup:
+    free(real_length);
+
     if (bind) {
 	int i;
 

mercurial