bool DbUtil::runQuery(const char* sql, const Properties& args, SqlResultSet& rows){ clear_error(); rows.clear(); if (!isConnected()) return false; assert(m_mysql); g_debug << "runQuery: " << endl << " sql: '" << sql << "'" << endl; MYSQL_STMT *stmt= mysql_stmt_init(m_mysql); if (mysql_stmt_prepare(stmt, sql, (unsigned long)strlen(sql))) { report_error("Failed to prepare: ", m_mysql); return false; } uint params= mysql_stmt_param_count(stmt); MYSQL_BIND *bind_param = new MYSQL_BIND[params]; NdbAutoObjArrayPtr<MYSQL_BIND> _guard(bind_param); memset(bind_param, 0, params * sizeof(MYSQL_BIND)); for(uint i= 0; i < mysql_stmt_param_count(stmt); i++) { BaseString name; name.assfmt("%d", i); // Parameters are named 0, 1, 2... if (!args.contains(name.c_str())) { g_err << "param " << i << " missing" << endl; assert(false); } PropertiesType t; Uint32 val_i; const char* val_s; args.getTypeOf(name.c_str(), &t); switch(t) { case PropertiesType_Uint32: args.get(name.c_str(), &val_i); bind_param[i].buffer_type= MYSQL_TYPE_LONG; bind_param[i].buffer= (char*)&val_i; g_debug << " param" << name.c_str() << ": " << val_i << endl; break; case PropertiesType_char: args.get(name.c_str(), &val_s); bind_param[i].buffer_type= MYSQL_TYPE_STRING; bind_param[i].buffer= (char*)val_s; bind_param[i].buffer_length= (unsigned long)strlen(val_s); g_debug << " param" << name.c_str() << ": " << val_s << endl; break; default: assert(false); break; } } if (mysql_stmt_bind_param(stmt, bind_param)) { report_error("Failed to bind param: ", m_mysql); mysql_stmt_close(stmt); return false; } if (mysql_stmt_execute(stmt)) { report_error("Failed to execute: ", m_mysql); mysql_stmt_close(stmt); return false; } /* Update max_length, making it possible to know how big buffers to allocate */ my_bool one= 1; mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one); if (mysql_stmt_store_result(stmt)) { report_error("Failed to store result: ", m_mysql); mysql_stmt_close(stmt); return false; } uint row= 0; MYSQL_RES* res= mysql_stmt_result_metadata(stmt); if (res != NULL) { MYSQL_FIELD *fields= mysql_fetch_fields(res); uint num_fields= mysql_num_fields(res); MYSQL_BIND *bind_result = new MYSQL_BIND[num_fields]; NdbAutoObjArrayPtr<MYSQL_BIND> _guard1(bind_result); memset(bind_result, 0, num_fields * sizeof(MYSQL_BIND)); for (uint i= 0; i < num_fields; i++) { unsigned long buf_len= sizeof(int); switch(fields[i].type){ case MYSQL_TYPE_STRING: buf_len = fields[i].length + 1; break; case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: buf_len= fields[i].max_length + 1; break; case MYSQL_TYPE_LONGLONG: buf_len= sizeof(long long); break; case MYSQL_TYPE_LONG: buf_len = sizeof(long); break; default: break; } bind_result[i].buffer_type= fields[i].type; bind_result[i].buffer= malloc(buf_len); bind_result[i].buffer_length= buf_len; bind_result[i].is_null = (my_bool*)malloc(sizeof(my_bool)); * bind_result[i].is_null = 0; } if (mysql_stmt_bind_result(stmt, bind_result)){ report_error("Failed to bind result: ", m_mysql); mysql_stmt_close(stmt); return false; } while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) { Properties curr(true); for (uint i= 0; i < num_fields; i++){ if (* bind_result[i].is_null) continue; switch(fields[i].type){ case MYSQL_TYPE_STRING: ((char*)bind_result[i].buffer)[fields[i].max_length] = 0; case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: curr.put(fields[i].name, (char*)bind_result[i].buffer); break; case MYSQL_TYPE_LONGLONG: curr.put64(fields[i].name, *(unsigned long long*)bind_result[i].buffer); break; default: curr.put(fields[i].name, *(int*)bind_result[i].buffer); break; } } rows.put("row", row++, &curr); } mysql_free_result(res); for (uint i= 0; i < num_fields; i++) { free(bind_result[i].buffer); free(bind_result[i].is_null); } } // Save stats in result set rows.put("rows", row); rows.put64("affected_rows", mysql_affected_rows(m_mysql)); rows.put("mysql_errno", mysql_errno(m_mysql)); rows.put("mysql_error", mysql_error(m_mysql)); rows.put("mysql_sqlstate", mysql_sqlstate(m_mysql)); rows.put64("insert_id", mysql_insert_id(m_mysql)); mysql_stmt_close(stmt); return true; }
bool DbUtil::runQuery(const char* sql, const Properties& args, SqlResultSet& rows){ rows.clear(); if (!isConnected()) return false; g_debug << "runQuery: " << endl << " sql: '" << sql << "'" << endl; MYSQL_STMT *stmt= mysql_stmt_init(m_mysql); if (mysql_stmt_prepare(stmt, sql, strlen(sql))) { g_err << "Failed to prepare: " << mysql_error(m_mysql) << endl; return false; } uint params= mysql_stmt_param_count(stmt); MYSQL_BIND bind_param[params]; bzero(bind_param, sizeof(bind_param)); for(uint i= 0; i < mysql_stmt_param_count(stmt); i++) { BaseString name; name.assfmt("%d", i); // Parameters are named 0, 1, 2... if (!args.contains(name.c_str())) { g_err << "param " << i << " missing" << endl; assert(false); } PropertiesType t; Uint32 val_i; const char* val_s; args.getTypeOf(name.c_str(), &t); switch(t) { case PropertiesType_Uint32: args.get(name.c_str(), &val_i); bind_param[i].buffer_type= MYSQL_TYPE_LONG; bind_param[i].buffer= (char*)&val_i; g_debug << " param" << name.c_str() << ": " << val_i << endl; break; case PropertiesType_char: args.get(name.c_str(), &val_s); bind_param[i].buffer_type= MYSQL_TYPE_STRING; bind_param[i].buffer= (char*)val_s; bind_param[i].buffer_length= strlen(val_s); g_debug << " param" << name.c_str() << ": " << val_s << endl; break; default: assert(false); break; } } if (mysql_stmt_bind_param(stmt, bind_param)) { g_err << "Failed to bind param: " << mysql_error(m_mysql) << endl; mysql_stmt_close(stmt); return false; } if (mysql_stmt_execute(stmt)) { g_err << "Failed to execute: " << mysql_error(m_mysql) << endl; mysql_stmt_close(stmt); return false; } /* Update max_length, making it possible to know how big buffers to allocate */ my_bool one= 1; mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one); if (mysql_stmt_store_result(stmt)) { g_err << "Failed to store result: " << mysql_error(m_mysql) << endl; mysql_stmt_close(stmt); return false; } uint row= 0; MYSQL_RES* res= mysql_stmt_result_metadata(stmt); if (res != NULL) { MYSQL_FIELD *fields= mysql_fetch_fields(res); uint num_fields= mysql_num_fields(res); MYSQL_BIND bind_result[num_fields]; bzero(bind_result, sizeof(bind_result)); for (uint i= 0; i < num_fields; i++) { if (is_int_type(fields[i].type)){ bind_result[i].buffer_type= MYSQL_TYPE_LONG; bind_result[i].buffer= malloc(sizeof(int)); } else { uint max_length= fields[i].max_length + 1; bind_result[i].buffer_type= MYSQL_TYPE_STRING; bind_result[i].buffer= malloc(max_length); bind_result[i].buffer_length= max_length; } } if (mysql_stmt_bind_result(stmt, bind_result)){ g_err << "Failed to bind result: " << mysql_error(m_mysql) << endl; mysql_stmt_close(stmt); return false; } while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) { Properties curr(true); for (uint i= 0; i < num_fields; i++){ if (is_int_type(fields[i].type)) curr.put(fields[i].name, *(int*)bind_result[i].buffer); else curr.put(fields[i].name, (char*)bind_result[i].buffer); } rows.put("row", row++, &curr); } mysql_free_result(res); for (uint i= 0; i < num_fields; i++) free(bind_result[i].buffer); } // Save stats in result set rows.put("rows", row); rows.put("affected_rows", mysql_affected_rows(m_mysql)); rows.put("mysql_errno", mysql_errno(m_mysql)); rows.put("mysql_error", mysql_error(m_mysql)); rows.put("mysql_sqlstate", mysql_sqlstate(m_mysql)); rows.put("insert_id", mysql_insert_id(m_mysql)); mysql_stmt_close(stmt); return true; }