From 60a426c0742b3e7d8c5b557c7578df6eeeea377b Mon Sep 17 00:00:00 2001 From: brianluau Date: Wed, 5 Dec 2012 02:53:33 +0000 Subject: - Undid r16968: SVN Replaced with source:/trunk/src/@16966 (tid:74924). [16969:16991/trunk/src/] will be re-committed in the next 24 hours. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16992 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/sql.c | 1216 +++++++++++++++++++++++++++--------------------------- 1 file changed, 616 insertions(+), 600 deletions(-) (limited to 'src/common/sql.c') diff --git a/src/common/sql.c b/src/common/sql.c index 740da476d..800aa89b0 100644 --- a/src/common/sql.c +++ b/src/common/sql.c @@ -18,38 +18,41 @@ /// Sql handle -struct Sql { - StringBuf buf; - MYSQL handle; - MYSQL_RES *result; - MYSQL_ROW row; - unsigned long *lengths; - int keepalive; +struct Sql +{ + StringBuf buf; + MYSQL handle; + MYSQL_RES* result; + MYSQL_ROW row; + unsigned long* lengths; + int keepalive; }; // Column length receiver. // Takes care of the possible size missmatch between uint32 and unsigned long. -struct s_column_length { - uint32 *out_length; - unsigned long length; +struct s_column_length +{ + uint32* out_length; + unsigned long length; }; typedef struct s_column_length s_column_length; /// Sql statement -struct SqlStmt { - StringBuf buf; - MYSQL_STMT *stmt; - MYSQL_BIND *params; - MYSQL_BIND *columns; - s_column_length *column_lengths; - size_t max_params; - size_t max_columns; - bool bind_params; - bool bind_columns; +struct SqlStmt +{ + StringBuf buf; + MYSQL_STMT* stmt; + MYSQL_BIND* params; + MYSQL_BIND* columns; + s_column_length* column_lengths; + size_t max_params; + size_t max_columns; + bool bind_params; + bool bind_columns; }; @@ -61,111 +64,117 @@ struct SqlStmt { /// Allocates and initializes a new Sql handle. -Sql *Sql_Malloc(void) +Sql* Sql_Malloc(void) { - Sql *self; + Sql* self; - CREATE(self, Sql, 1); - mysql_init(&self->handle); - StringBuf_Init(&self->buf); - self->lengths = NULL; - self->result = NULL; - self->keepalive = INVALID_TIMER; + CREATE(self, Sql, 1); + mysql_init(&self->handle); + StringBuf_Init(&self->buf); + self->lengths = NULL; + self->result = NULL; + self->keepalive = INVALID_TIMER; - return self; + return self; } -static int Sql_P_Keepalive(Sql *self); +static int Sql_P_Keepalive(Sql* self); /// Establishes a connection. -int Sql_Connect(Sql *self, const char *user, const char *passwd, const char *host, uint16 port, const char *db) +int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - StringBuf_Clear(&self->buf); - if (!mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/)) { - ShowSQL("%s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } + StringBuf_Clear(&self->buf); + if( !mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/) ) + { + ShowSQL("%s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } - self->keepalive = Sql_P_Keepalive(self); - if (self->keepalive == INVALID_TIMER) { - ShowSQL("Failed to establish keepalive for DB connection!\n"); - return SQL_ERROR; - } + self->keepalive = Sql_P_Keepalive(self); + if( self->keepalive == INVALID_TIMER ) + { + ShowSQL("Failed to establish keepalive for DB connection!\n"); + return SQL_ERROR; + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Retrieves the timeout of the connection. -int Sql_GetTimeout(Sql *self, uint32 *out_timeout) +int Sql_GetTimeout(Sql* self, uint32* out_timeout) { - if (self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'")) { - char *data; - size_t len; - if (SQL_SUCCESS == Sql_NextRow(self) && - SQL_SUCCESS == Sql_GetData(self, 1, &data, &len)) { - *out_timeout = (uint32)strtoul(data, NULL, 10); - Sql_FreeResult(self); - return SQL_SUCCESS; - } - Sql_FreeResult(self); - } - return SQL_ERROR; + if( self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'") ) + { + char* data; + size_t len; + if( SQL_SUCCESS == Sql_NextRow(self) && + SQL_SUCCESS == Sql_GetData(self, 1, &data, &len) ) + { + *out_timeout = (uint32)strtoul(data, NULL, 10); + Sql_FreeResult(self); + return SQL_SUCCESS; + } + Sql_FreeResult(self); + } + return SQL_ERROR; } /// Retrieves the name of the columns of a table into out_buf, with the separator after each name. -int Sql_GetColumnNames(Sql *self, const char *table, char *out_buf, size_t buf_len, char sep) +int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_len, char sep) { - char *data; - size_t len; - size_t off = 0; + char* data; + size_t len; + size_t off = 0; - if (self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table)) - return SQL_ERROR; + if( self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table) ) + return SQL_ERROR; - out_buf[off] = '\0'; - while (SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len)) { - len = strnlen(data, len); - if (off + len + 2 > buf_len) { - ShowDebug("Sql_GetColumns: output buffer is too small\n"); - *out_buf = '\0'; - return SQL_ERROR; - } - memcpy(out_buf+off, data, len); - off += len; - out_buf[off++] = sep; - } - out_buf[off] = '\0'; - Sql_FreeResult(self); - return SQL_SUCCESS; + out_buf[off] = '\0'; + while( SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len) ) + { + len = strnlen(data, len); + if( off + len + 2 > buf_len ) + { + ShowDebug("Sql_GetColumns: output buffer is too small\n"); + *out_buf = '\0'; + return SQL_ERROR; + } + memcpy(out_buf+off, data, len); + off += len; + out_buf[off++] = sep; + } + out_buf[off] = '\0'; + Sql_FreeResult(self); + return SQL_SUCCESS; } /// Changes the encoding of the connection. -int Sql_SetEncoding(Sql *self, const char *encoding) +int Sql_SetEncoding(Sql* self, const char* encoding) { - if (self && mysql_set_character_set(&self->handle, encoding) == 0) - return SQL_SUCCESS; - return SQL_ERROR; + if( self && mysql_set_character_set(&self->handle, encoding) == 0 ) + return SQL_SUCCESS; + return SQL_ERROR; } /// Pings the connection. -int Sql_Ping(Sql *self) +int Sql_Ping(Sql* self) { - if (self && mysql_ping(&self->handle) == 0) - return SQL_SUCCESS; - return SQL_ERROR; + if( self && mysql_ping(&self->handle) == 0 ) + return SQL_SUCCESS; + return SQL_ERROR; } @@ -175,10 +184,10 @@ int Sql_Ping(Sql *self) /// @private static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t data) { - Sql *self = (Sql *)data; - ShowInfo("Pinging SQL server to keep connection alive...\n"); - Sql_Ping(self); - return 0; + Sql* self = (Sql*)data; + ShowInfo("Pinging SQL server to keep connection alive...\n"); + Sql_Ping(self); + return 0; } @@ -187,213 +196,224 @@ static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t dat /// /// @return the keepalive timer id, or INVALID_TIMER /// @private -static int Sql_P_Keepalive(Sql *self) +static int Sql_P_Keepalive(Sql* self) { - uint32 timeout, ping_interval; + uint32 timeout, ping_interval; - // set a default value first - timeout = 28800; // 8 hours + // set a default value first + timeout = 28800; // 8 hours - // request the timeout value from the mysql server - Sql_GetTimeout(self, &timeout); + // request the timeout value from the mysql server + Sql_GetTimeout(self, &timeout); - if (timeout < 60) - timeout = 60; + if( timeout < 60 ) + timeout = 60; - // establish keepalive - ping_interval = timeout - 30; // 30-second reserve - //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); - return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); + // establish keepalive + ping_interval = timeout - 30; // 30-second reserve + //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); + return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); } /// Escapes a string. -size_t Sql_EscapeString(Sql *self, char *out_to, const char *from) +size_t Sql_EscapeString(Sql* self, char *out_to, const char *from) { - if (self) - return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from)); - else - return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from)); + if( self ) + return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from)); + else + return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from)); } /// Escapes a string. -size_t Sql_EscapeStringLen(Sql *self, char *out_to, const char *from, size_t from_len) +size_t Sql_EscapeStringLen(Sql* self, char *out_to, const char *from, size_t from_len) { - if (self) - return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len); - else - return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len); + if( self ) + return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len); + else + return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len); } /// Executes a query. -int Sql_Query(Sql *self, const char *query, ...) +int Sql_Query(Sql* self, const char* query, ...) { - int res; - va_list args; + int res; + va_list args; - va_start(args, query); - res = Sql_QueryV(self, query, args); - va_end(args); + va_start(args, query); + res = Sql_QueryV(self, query, args); + va_end(args); - return res; + return res; } /// Executes a query. -int Sql_QueryV(Sql *self, const char *query, va_list args) +int Sql_QueryV(Sql* self, const char* query, va_list args) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if (mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - self->result = mysql_store_result(&self->handle); - if (mysql_errno(&self->handle) != 0) { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - return SQL_SUCCESS; + Sql_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_Vprintf(&self->buf, query, args); + if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + self->result = mysql_store_result(&self->handle); + if( mysql_errno(&self->handle) != 0 ) + { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + return SQL_SUCCESS; } /// Executes a query. -int Sql_QueryStr(Sql *self, const char *query) +int Sql_QueryStr(Sql* self, const char* query) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if (mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - self->result = mysql_store_result(&self->handle); - if (mysql_errno(&self->handle) != 0) { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - return SQL_SUCCESS; + Sql_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_AppendStr(&self->buf, query); + if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + self->result = mysql_store_result(&self->handle); + if( mysql_errno(&self->handle) != 0 ) + { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query. -uint64 Sql_LastInsertId(Sql *self) +uint64 Sql_LastInsertId(Sql* self) { - if (self) - return (uint64)mysql_insert_id(&self->handle); - else - return 0; + if( self ) + return (uint64)mysql_insert_id(&self->handle); + else + return 0; } /// Returns the number of columns in each row of the result. -uint32 Sql_NumColumns(Sql *self) +uint32 Sql_NumColumns(Sql* self) { - if (self && self->result) - return (uint32)mysql_num_fields(self->result); - return 0; + if( self && self->result ) + return (uint32)mysql_num_fields(self->result); + return 0; } /// Returns the number of rows in the result. -uint64 Sql_NumRows(Sql *self) +uint64 Sql_NumRows(Sql* self) { - if (self && self->result) - return (uint64)mysql_num_rows(self->result); - return 0; + if( self && self->result ) + return (uint64)mysql_num_rows(self->result); + return 0; } /// Fetches the next row. -int Sql_NextRow(Sql *self) +int Sql_NextRow(Sql* self) { - if (self && self->result) { - self->row = mysql_fetch_row(self->result); - if (self->row) { - self->lengths = mysql_fetch_lengths(self->result); - return SQL_SUCCESS; - } - self->lengths = NULL; - if (mysql_errno(&self->handle) == 0) - return SQL_NO_DATA; - } - return SQL_ERROR; + if( self && self->result ) + { + self->row = mysql_fetch_row(self->result); + if( self->row ) + { + self->lengths = mysql_fetch_lengths(self->result); + return SQL_SUCCESS; + } + self->lengths = NULL; + if( mysql_errno(&self->handle) == 0 ) + return SQL_NO_DATA; + } + return SQL_ERROR; } /// Gets the data of a column. -int Sql_GetData(Sql *self, size_t col, char **out_buf, size_t *out_len) +int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len) { - if (self && self->row) { - if (col < Sql_NumColumns(self)) { - if (out_buf) *out_buf = self->row[col]; - if (out_len) *out_len = (size_t)self->lengths[col]; - } else { - // out of range - ignore - if (out_buf) *out_buf = NULL; - if (out_len) *out_len = 0; - } - return SQL_SUCCESS; - } - return SQL_ERROR; + if( self && self->row ) + { + if( col < Sql_NumColumns(self) ) + { + if( out_buf ) *out_buf = self->row[col]; + if( out_len ) *out_len = (size_t)self->lengths[col]; + } + else + {// out of range - ignore + if( out_buf ) *out_buf = NULL; + if( out_len ) *out_len = 0; + } + return SQL_SUCCESS; + } + return SQL_ERROR; } /// Frees the result of the query. -void Sql_FreeResult(Sql *self) +void Sql_FreeResult(Sql* self) { - if (self && self->result) { - mysql_free_result(self->result); - self->result = NULL; - self->row = NULL; - self->lengths = NULL; - } + if( self && self->result ) + { + mysql_free_result(self->result); + self->result = NULL; + self->row = NULL; + self->lengths = NULL; + } } /// Shows debug information (last query). -void Sql_ShowDebug_(Sql *self, const char *debug_file, const unsigned long debug_line) +void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line) { - if (self == NULL) - ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if (StringBuf_Length(&self->buf) > 0) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); - else - ShowDebug("at %s:%lu\n", debug_file, debug_line); + if( self == NULL ) + ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); + else if( StringBuf_Length(&self->buf) > 0 ) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else + ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a Sql handle returned by Sql_Malloc. -void Sql_Free(Sql *self) +void Sql_Free(Sql* self) { - if (self) { - Sql_FreeResult(self); - StringBuf_Destroy(&self->buf); - if (self->keepalive != INVALID_TIMER) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); - aFree(self); - } + if( self ) + { + Sql_FreeResult(self); + StringBuf_Destroy(&self->buf); + if( self->keepalive != INVALID_TIMER ) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); + aFree(self); + } } @@ -409,19 +429,16 @@ void Sql_Free(Sql *self) /// @private static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz) { - switch (sz) { - case 1: - return MYSQL_TYPE_TINY; - case 2: - return MYSQL_TYPE_SHORT; - case 4: - return MYSQL_TYPE_LONG; - case 8: - return MYSQL_TYPE_LONGLONG; - default: - ShowDebug("SizeToMysqlIntType: unsupported size (%d)\n", sz); - return MYSQL_TYPE_NULL; - } + switch( sz ) + { + case 1: return MYSQL_TYPE_TINY; + case 2: return MYSQL_TYPE_SHORT; + case 4: return MYSQL_TYPE_LONG; + case 8: return MYSQL_TYPE_LONGLONG; + default: + ShowDebug("SizeToMysqlIntType: unsupported size (%d)\n", sz); + return MYSQL_TYPE_NULL; + } } @@ -429,96 +446,74 @@ static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz) /// Binds a parameter/result. /// /// @private -static int Sql_P_BindSqlDataType(MYSQL_BIND *bind, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, unsigned long *out_length, int8 *out_is_null) -{ - memset(bind, 0, sizeof(MYSQL_BIND)); - switch (buffer_type) { - case SQLDT_NULL: - bind->buffer_type = MYSQL_TYPE_NULL; - buffer_len = 0;// FIXME length = ? [FlavioJS] - break; - // fixed size - case SQLDT_UINT8: - bind->is_unsigned = 1; - case SQLDT_INT8: - bind->buffer_type = MYSQL_TYPE_TINY; - buffer_len = 1; - break; - case SQLDT_UINT16: - bind->is_unsigned = 1; - case SQLDT_INT16: - bind->buffer_type = MYSQL_TYPE_SHORT; - buffer_len = 2; - break; - case SQLDT_UINT32: - bind->is_unsigned = 1; - case SQLDT_INT32: - bind->buffer_type = MYSQL_TYPE_LONG; - buffer_len = 4; - break; - case SQLDT_UINT64: - bind->is_unsigned = 1; - case SQLDT_INT64: - bind->buffer_type = MYSQL_TYPE_LONGLONG; - buffer_len = 8; - break; - // platform dependent size - case SQLDT_UCHAR: - bind->is_unsigned = 1; - case SQLDT_CHAR: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); - buffer_len = sizeof(char); - break; - case SQLDT_USHORT: - bind->is_unsigned = 1; - case SQLDT_SHORT: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short)); - buffer_len = sizeof(short); - break; - case SQLDT_UINT: - bind->is_unsigned = 1; - case SQLDT_INT: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int)); - buffer_len = sizeof(int); - break; - case SQLDT_ULONG: - bind->is_unsigned = 1; - case SQLDT_LONG: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long)); - buffer_len = sizeof(long); - break; - case SQLDT_ULONGLONG: - bind->is_unsigned = 1; - case SQLDT_LONGLONG: - bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); - buffer_len = sizeof(int64); - break; - // floating point - case SQLDT_FLOAT: - bind->buffer_type = MYSQL_TYPE_FLOAT; - buffer_len = 4; - break; - case SQLDT_DOUBLE: - bind->buffer_type = MYSQL_TYPE_DOUBLE; - buffer_len = 8; - break; - // other - case SQLDT_STRING: - case SQLDT_ENUM: - bind->buffer_type = MYSQL_TYPE_STRING; - break; - case SQLDT_BLOB: - bind->buffer_type = MYSQL_TYPE_BLOB; - break; - default: - ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type); - return SQL_ERROR; - } - bind->buffer = buffer; - bind->buffer_length = (unsigned long)buffer_len; - bind->length = out_length; - bind->is_null = (my_bool *)out_is_null; - return SQL_SUCCESS; +static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, unsigned long* out_length, int8* out_is_null) +{ + memset(bind, 0, sizeof(MYSQL_BIND)); + switch( buffer_type ) + { + case SQLDT_NULL: bind->buffer_type = MYSQL_TYPE_NULL; + buffer_len = 0;// FIXME length = ? [FlavioJS] + break; + // fixed size + case SQLDT_UINT8: bind->is_unsigned = 1; + case SQLDT_INT8: bind->buffer_type = MYSQL_TYPE_TINY; + buffer_len = 1; + break; + case SQLDT_UINT16: bind->is_unsigned = 1; + case SQLDT_INT16: bind->buffer_type = MYSQL_TYPE_SHORT; + buffer_len = 2; + break; + case SQLDT_UINT32: bind->is_unsigned = 1; + case SQLDT_INT32: bind->buffer_type = MYSQL_TYPE_LONG; + buffer_len = 4; + break; + case SQLDT_UINT64: bind->is_unsigned = 1; + case SQLDT_INT64: bind->buffer_type = MYSQL_TYPE_LONGLONG; + buffer_len = 8; + break; + // platform dependent size + case SQLDT_UCHAR: bind->is_unsigned = 1; + case SQLDT_CHAR: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); + buffer_len = sizeof(char); + break; + case SQLDT_USHORT: bind->is_unsigned = 1; + case SQLDT_SHORT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short)); + buffer_len = sizeof(short); + break; + case SQLDT_UINT: bind->is_unsigned = 1; + case SQLDT_INT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int)); + buffer_len = sizeof(int); + break; + case SQLDT_ULONG: bind->is_unsigned = 1; + case SQLDT_LONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long)); + buffer_len = sizeof(long); + break; + case SQLDT_ULONGLONG: bind->is_unsigned = 1; + case SQLDT_LONGLONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); + buffer_len = sizeof(int64); + break; + // floating point + case SQLDT_FLOAT: bind->buffer_type = MYSQL_TYPE_FLOAT; + buffer_len = 4; + break; + case SQLDT_DOUBLE: bind->buffer_type = MYSQL_TYPE_DOUBLE; + buffer_len = 8; + break; + // other + case SQLDT_STRING: + case SQLDT_ENUM: bind->buffer_type = MYSQL_TYPE_STRING; + break; + case SQLDT_BLOB: bind->buffer_type = MYSQL_TYPE_BLOB; + break; + default: + ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type); + return SQL_ERROR; + } + bind->buffer = buffer; + bind->buffer_length = (unsigned long)buffer_len; + bind->length = out_length; + bind->is_null = (my_bool*)out_is_null; + return SQL_SUCCESS; } @@ -526,37 +521,38 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND *bind, enum SqlDataType buffer_type, /// Prints debug information about a field (type and length). /// /// @private -static void Sql_P_ShowDebugMysqlFieldInfo(const char *prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char *length_postfix) -{ - const char *sign = (is_unsigned ? "UNSIGNED " : ""); - const char *type_string; - switch (type) { - default: - ShowDebug("%stype=%s%u, length=%d\n", prefix, sign, type, length); - return; +static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char* length_postfix) +{ + const char* sign = (is_unsigned ? "UNSIGNED " : ""); + const char* type_string; + switch( type ) + { + default: + ShowDebug("%stype=%s%u, length=%d\n", prefix, sign, type, length); + return; #define SHOW_DEBUG_OF(x) case x: type_string = #x; break - SHOW_DEBUG_OF(MYSQL_TYPE_TINY); - SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); - SHOW_DEBUG_OF(MYSQL_TYPE_LONG); - SHOW_DEBUG_OF(MYSQL_TYPE_INT24); - SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); - SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); - SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); - SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); - SHOW_DEBUG_OF(MYSQL_TYPE_DATE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIME); - SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); - SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); - SHOW_DEBUG_OF(MYSQL_TYPE_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); - SHOW_DEBUG_OF(MYSQL_TYPE_SET); - SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); - SHOW_DEBUG_OF(MYSQL_TYPE_NULL); + SHOW_DEBUG_OF(MYSQL_TYPE_TINY); + SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); + SHOW_DEBUG_OF(MYSQL_TYPE_LONG); + SHOW_DEBUG_OF(MYSQL_TYPE_INT24); + SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); + SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); + SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); + SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); + SHOW_DEBUG_OF(MYSQL_TYPE_DATE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIME); + SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); + SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); + SHOW_DEBUG_OF(MYSQL_TYPE_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); + SHOW_DEBUG_OF(MYSQL_TYPE_SET); + SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); + SHOW_DEBUG_OF(MYSQL_TYPE_NULL); #undef SHOW_DEBUG_TYPE_OF - } - ShowDebug("%stype=%s%s, length=%d%s\n", prefix, sign, type_string, length, length_postfix); + } + ShowDebug("%stype=%s%s, length=%d%s\n", prefix, sign, type_string, length, length_postfix); } @@ -564,369 +560,389 @@ static void Sql_P_ShowDebugMysqlFieldInfo(const char *prefix, enum enum_field_ty /// Reports debug information about a truncated column. /// /// @private -static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt *self, size_t i) +static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i) { - MYSQL_RES *meta; - MYSQL_FIELD *field; - MYSQL_BIND *column; + MYSQL_RES* meta; + MYSQL_FIELD* field; + MYSQL_BIND* column; - meta = mysql_stmt_result_metadata(self->stmt); - field = mysql_fetch_field_direct(meta, (unsigned int)i); - ShowSQL("DB error - data of field '%s' was truncated.\n", field->name); - ShowDebug("column - %lu\n", (unsigned long)i); - Sql_P_ShowDebugMysqlFieldInfo("data - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, ""); - column = &self->columns[i]; - if (column->buffer_type == MYSQL_TYPE_STRING) - Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)"); - else - Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, ""); - mysql_free_result(meta); + meta = mysql_stmt_result_metadata(self->stmt); + field = mysql_fetch_field_direct(meta, (unsigned int)i); + ShowSQL("DB error - data of field '%s' was truncated.\n", field->name); + ShowDebug("column - %lu\n", (unsigned long)i); + Sql_P_ShowDebugMysqlFieldInfo("data - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, ""); + column = &self->columns[i]; + if( column->buffer_type == MYSQL_TYPE_STRING ) + Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)"); + else + Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, ""); + mysql_free_result(meta); } /// Allocates and initializes a new SqlStmt handle. -SqlStmt *SqlStmt_Malloc(Sql *sql) +SqlStmt* SqlStmt_Malloc(Sql* sql) { - SqlStmt *self; - MYSQL_STMT *stmt; + SqlStmt* self; + MYSQL_STMT* stmt; - if (sql == NULL) - return NULL; + if( sql == NULL ) + return NULL; - stmt = mysql_stmt_init(&sql->handle); - if (stmt == NULL) { - ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); - return NULL; - } - CREATE(self, SqlStmt, 1); - StringBuf_Init(&self->buf); - self->stmt = stmt; - self->params = NULL; - self->columns = NULL; - self->column_lengths = NULL; - self->max_params = 0; - self->max_columns = 0; - self->bind_params = false; - self->bind_columns = false; + stmt = mysql_stmt_init(&sql->handle); + if( stmt == NULL ) + { + ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); + return NULL; + } + CREATE(self, SqlStmt, 1); + StringBuf_Init(&self->buf); + self->stmt = stmt; + self->params = NULL; + self->columns = NULL; + self->column_lengths = NULL; + self->max_params = 0; + self->max_columns = 0; + self->bind_params = false; + self->bind_columns = false; - return self; + return self; } /// Prepares the statement. -int SqlStmt_Prepare(SqlStmt *self, const char *query, ...) +int SqlStmt_Prepare(SqlStmt* self, const char* query, ...) { - int res; - va_list args; + int res; + va_list args; - va_start(args, query); - res = SqlStmt_PrepareV(self, query, args); - va_end(args); + va_start(args, query); + res = SqlStmt_PrepareV(self, query, args); + va_end(args); - return res; + return res; } /// Prepares the statement. -int SqlStmt_PrepareV(SqlStmt *self, const char *query, va_list args) +int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if (mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_params = false; + SqlStmt_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_Vprintf(&self->buf, query, args); + if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_params = false; - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Prepares the statement. -int SqlStmt_PrepareStr(SqlStmt *self, const char *query) +int SqlStmt_PrepareStr(SqlStmt* self, const char* query) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if (mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_params = false; + SqlStmt_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_AppendStr(&self->buf, query); + if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_params = false; - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Returns the number of parameters in the prepared statement. -size_t SqlStmt_NumParams(SqlStmt *self) +size_t SqlStmt_NumParams(SqlStmt* self) { - if (self) - return (size_t)mysql_stmt_param_count(self->stmt); - else - return 0; + if( self ) + return (size_t)mysql_stmt_param_count(self->stmt); + else + return 0; } /// Binds a parameter to a buffer. -int SqlStmt_BindParam(SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len) +int SqlStmt_BindParam(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - if (!self->bind_params) { - // initialize the bindings - size_t i; - size_t count; + if( !self->bind_params ) + {// initialize the bindings + size_t i; + size_t count; - count = SqlStmt_NumParams(self); - if (self->max_params < count) { - self->max_params = count; - RECREATE(self->params, MYSQL_BIND, count); - } - memset(self->params, 0, count*sizeof(MYSQL_BIND)); - for (i = 0; i < count; ++i) - self->params[i].buffer_type = MYSQL_TYPE_NULL; - self->bind_params = true; - } - if (idx < self->max_params) - return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL); - else - return SQL_SUCCESS;// out of range - ignore + count = SqlStmt_NumParams(self); + if( self->max_params < count ) + { + self->max_params = count; + RECREATE(self->params, MYSQL_BIND, count); + } + memset(self->params, 0, count*sizeof(MYSQL_BIND)); + for( i = 0; i < count; ++i ) + self->params[i].buffer_type = MYSQL_TYPE_NULL; + self->bind_params = true; + } + if( idx < self->max_params ) + return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL); + else + return SQL_SUCCESS;// out of range - ignore } /// Executes the prepared statement. -int SqlStmt_Execute(SqlStmt *self) +int SqlStmt_Execute(SqlStmt* self) { - if (self == NULL) - return SQL_ERROR; + if( self == NULL ) + return SQL_ERROR; - SqlStmt_FreeResult(self); - if ((self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || - mysql_stmt_execute(self->stmt)) { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_columns = false; - if (mysql_stmt_store_result(self->stmt)) { // store all the data - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } + SqlStmt_FreeResult(self); + if( (self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || + mysql_stmt_execute(self->stmt) ) + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_columns = false; + if( mysql_stmt_store_result(self->stmt) )// store all the data + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. -uint64 SqlStmt_LastInsertId(SqlStmt *self) +uint64 SqlStmt_LastInsertId(SqlStmt* self) { - if (self) - return (uint64)mysql_stmt_insert_id(self->stmt); - else - return 0; + if( self ) + return (uint64)mysql_stmt_insert_id(self->stmt); + else + return 0; } /// Returns the number of columns in each row of the result. -size_t SqlStmt_NumColumns(SqlStmt *self) +size_t SqlStmt_NumColumns(SqlStmt* self) { - if (self) - return (size_t)mysql_stmt_field_count(self->stmt); - else - return 0; + if( self ) + return (size_t)mysql_stmt_field_count(self->stmt); + else + return 0; } /// Binds the result of a column to a buffer. -int SqlStmt_BindColumn(SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null) -{ - if (self == NULL) - return SQL_ERROR; - - if (buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM) { - if (buffer_len < 1) { - ShowDebug("SqlStmt_BindColumn: buffer_len(%d) is too small, no room for the nul-terminator\n", buffer_len); - return SQL_ERROR; - } - --buffer_len;// nul-terminator - } - if (!self->bind_columns) { - // initialize the bindings - size_t i; - size_t cols; - - cols = SqlStmt_NumColumns(self); - if (self->max_columns < cols) { - self->max_columns = cols; - RECREATE(self->columns, MYSQL_BIND, cols); - RECREATE(self->column_lengths, s_column_length, cols); - } - memset(self->columns, 0, cols*sizeof(MYSQL_BIND)); - memset(self->column_lengths, 0, cols*sizeof(s_column_length)); - for (i = 0; i < cols; ++i) - self->columns[i].buffer_type = MYSQL_TYPE_NULL; - self->bind_columns = true; - } - if (idx < self->max_columns) { - self->column_lengths[idx].out_length = out_length; - return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null); - } else { - return SQL_SUCCESS;// out of range - ignore - } +int SqlStmt_BindColumn(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null) +{ + if( self == NULL ) + return SQL_ERROR; + + if( buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM ) + { + if( buffer_len < 1 ) + { + ShowDebug("SqlStmt_BindColumn: buffer_len(%d) is too small, no room for the nul-terminator\n", buffer_len); + return SQL_ERROR; + } + --buffer_len;// nul-terminator + } + if( !self->bind_columns ) + {// initialize the bindings + size_t i; + size_t cols; + + cols = SqlStmt_NumColumns(self); + if( self->max_columns < cols ) + { + self->max_columns = cols; + RECREATE(self->columns, MYSQL_BIND, cols); + RECREATE(self->column_lengths, s_column_length, cols); + } + memset(self->columns, 0, cols*sizeof(MYSQL_BIND)); + memset(self->column_lengths, 0, cols*sizeof(s_column_length)); + for( i = 0; i < cols; ++i ) + self->columns[i].buffer_type = MYSQL_TYPE_NULL; + self->bind_columns = true; + } + if( idx < self->max_columns ) + { + self->column_lengths[idx].out_length = out_length; + return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null); + } + else + { + return SQL_SUCCESS;// out of range - ignore + } } /// Returns the number of rows in the result. -uint64 SqlStmt_NumRows(SqlStmt *self) +uint64 SqlStmt_NumRows(SqlStmt* self) { - if (self) - return (uint64)mysql_stmt_num_rows(self->stmt); - else - return 0; + if( self ) + return (uint64)mysql_stmt_num_rows(self->stmt); + else + return 0; } /// Fetches the next row. -int SqlStmt_NextRow(SqlStmt *self) -{ - int err; - size_t i; - size_t cols; - MYSQL_BIND *column; - unsigned long length; - - if (self == NULL) - return SQL_ERROR; - - // bind columns - if (self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns)) - err = 1;// error binding columns - else - err = mysql_stmt_fetch(self->stmt);// fetch row - - // check for errors - if (err == MYSQL_NO_DATA) - return SQL_NO_DATA; +int SqlStmt_NextRow(SqlStmt* self) +{ + int err; + size_t i; + size_t cols; + MYSQL_BIND* column; + unsigned long length; + + if( self == NULL ) + return SQL_ERROR; + + // bind columns + if( self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns) ) + err = 1;// error binding columns + else + err = mysql_stmt_fetch(self->stmt);// fetch row + + // check for errors + if( err == MYSQL_NO_DATA ) + return SQL_NO_DATA; #if defined(MYSQL_DATA_TRUNCATED) - // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS] - if (err == MYSQL_DATA_TRUNCATED) { - my_bool truncated; - - if (!self->bind_columns) { - ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n"); - return SQL_ERROR; - } - - // find truncated column - cols = SqlStmt_NumColumns(self); - for (i = 0; i < cols; ++i) { - column = &self->columns[i]; - column->error = &truncated; - mysql_stmt_fetch_column(self->stmt, column, (unsigned int)i, 0); - column->error = NULL; - if (truncated) { - // report truncated column - SqlStmt_P_ShowDebugTruncatedColumn(self, i); - return SQL_ERROR; - } - } - ShowSQL("DB error - data truncated (unknown source)\n"); - return SQL_ERROR; - } + // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS] + if( err == MYSQL_DATA_TRUNCATED ) + { + my_bool truncated; + + if( !self->bind_columns ) + { + ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n"); + return SQL_ERROR; + } + + // find truncated column + cols = SqlStmt_NumColumns(self); + for( i = 0; i < cols; ++i ) + { + column = &self->columns[i]; + column->error = &truncated; + mysql_stmt_fetch_column(self->stmt, column, (unsigned int)i, 0); + column->error = NULL; + if( truncated ) + {// report truncated column + SqlStmt_P_ShowDebugTruncatedColumn(self, i); + return SQL_ERROR; + } + } + ShowSQL("DB error - data truncated (unknown source)\n"); + return SQL_ERROR; + } #endif - if (err) { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - - // propagate column lengths and clear unused parts of string/enum/blob buffers - cols = SqlStmt_NumColumns(self); - for (i = 0; i < cols; ++i) { - length = self->column_lengths[i].length; - column = &self->columns[i]; + if( err ) + { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + + // propagate column lengths and clear unused parts of string/enum/blob buffers + cols = SqlStmt_NumColumns(self); + for( i = 0; i < cols; ++i ) + { + length = self->column_lengths[i].length; + column = &self->columns[i]; #if !defined(MYSQL_DATA_TRUNCATED) - // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS] - if (column->buffer_length < length) { - // report truncated column - if (column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB) { - // string/enum/blob column - SqlStmt_P_ShowDebugTruncatedColumn(self, i); - return SQL_ERROR; - } - // FIXME numeric types and null [FlavioJS] - } + // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS] + if( column->buffer_length < length ) + {// report truncated column + if( column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB ) + {// string/enum/blob column + SqlStmt_P_ShowDebugTruncatedColumn(self, i); + return SQL_ERROR; + } + // FIXME numeric types and null [FlavioJS] + } #endif - if (self->column_lengths[i].out_length) - *self->column_lengths[i].out_length = (uint32)length; - if (column->buffer_type == MYSQL_TYPE_STRING) { - // clear unused part of the string/enum buffer (and nul-terminate) - memset((char *)column->buffer + length, 0, column->buffer_length - length + 1); - } else if (column->buffer_type == MYSQL_TYPE_BLOB && length < column->buffer_length) { - // clear unused part of the blob buffer - memset((char *)column->buffer + length, 0, column->buffer_length - length); - } - } + if( self->column_lengths[i].out_length ) + *self->column_lengths[i].out_length = (uint32)length; + if( column->buffer_type == MYSQL_TYPE_STRING ) + {// clear unused part of the string/enum buffer (and nul-terminate) + memset((char*)column->buffer + length, 0, column->buffer_length - length + 1); + } + else if( column->buffer_type == MYSQL_TYPE_BLOB && length < column->buffer_length ) + {// clear unused part of the blob buffer + memset((char*)column->buffer + length, 0, column->buffer_length - length); + } + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Frees the result of the statement execution. -void SqlStmt_FreeResult(SqlStmt *self) +void SqlStmt_FreeResult(SqlStmt* self) { - if (self) - mysql_stmt_free_result(self->stmt); + if( self ) + mysql_stmt_free_result(self->stmt); } /// Shows debug information (with statement). -void SqlStmt_ShowDebug_(SqlStmt *self, const char *debug_file, const unsigned long debug_line) +void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line) { - if (self == NULL) - ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if (StringBuf_Length(&self->buf) > 0) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); - else - ShowDebug("at %s:%lu\n", debug_file, debug_line); + if( self == NULL ) + ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); + else if( StringBuf_Length(&self->buf) > 0 ) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else + ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a SqlStmt returned by SqlStmt_Malloc. -void SqlStmt_Free(SqlStmt *self) -{ - if (self) { - SqlStmt_FreeResult(self); - StringBuf_Destroy(&self->buf); - mysql_stmt_close(self->stmt); - if (self->params) - aFree(self->params); - if (self->columns) { - aFree(self->columns); - aFree(self->column_lengths); - } - aFree(self); - } +void SqlStmt_Free(SqlStmt* self) +{ + if( self ) + { + SqlStmt_FreeResult(self); + StringBuf_Destroy(&self->buf); + mysql_stmt_close(self->stmt); + if( self->params ) + aFree(self->params); + if( self->columns ) + { + aFree(self->columns); + aFree(self->column_lengths); + } + aFree(self); + } } -- cgit v1.2.3-70-g09d2