#include "pch_msc.hpp" #include "libaquery.h" #include #include #include "monetdb_conn.h" #include "monetdbe.h" #include "table.h" #include #ifdef _WIN32 #include "winhelper.h" #else #include #include #include #include #endif // _WIN32 #undef ERROR #undef static_assert constexpr const char* monetdbe_type_str[] = { "monetdbe_bool", "monetdbe_int8_t", "monetdbe_int16_t", "monetdbe_int32_t", "monetdbe_int64_t", #ifdef HAVE_HGE "monetdbe_int128_t", #endif "monetdbe_size_t", "monetdbe_float", "monetdbe_double", "monetdbe_str", "monetdbe_blob", "monetdbe_date", "monetdbe_time", "monetdbe_timestamp", // should be last: "monetdbe_type_unknown" } ; inline constexpr static unsigned char monetdbe_type_szs[] = { sizeof(monetdbe_column_bool::null_value), sizeof(monetdbe_column_int8_t::null_value), sizeof(monetdbe_column_int16_t::null_value), sizeof(monetdbe_column_int32_t::null_value), sizeof(monetdbe_column_int64_t::null_value), #ifdef HAVE_HGE sizeof(monetdbe_column_int128_t::null_value), #endif sizeof(monetdbe_column_size_t::null_value), sizeof(monetdbe_column_float::null_value), sizeof(monetdbe_column_double::null_value), sizeof(monetdbe_column_str::null_value), sizeof(monetdbe_column_blob::null_value), sizeof(monetdbe_data_date), sizeof(monetdbe_data_time), sizeof(monetdbe_data_timestamp), // should be last: 1 }; namespace types{ constexpr const Type_t monetdbe_type_aqtypes[] = { ABOOL, AINT8, AINT16, AINT32, AINT64, #ifdef HAVE_HGE AINT128, #endif AUINT64, AFLOAT, ADOUBLE, ASTR, // blob? AINT64, ADATE, ATIME, ATIMESTAMP, ERROR }; } Server::Server(Context* cxt){ if (cxt){ connect(cxt); } } void Server::connect(Context *cxt){ auto server = static_cast(this->server); if (cxt){ cxt->alt_server = this; this->cxt = cxt; } else{ puts("Error: Empty context."); return; } if (server){ printf("Error: Server %p already connected. Restart? (Y/n). \n", server); char c[50]; std::cin.getline(c, 49); for(int i = 0; i < 50; ++i) { if (!c[i] || c[i] == 'y' || c[i] == 'Y'){ monetdbe_close(*server); free(*server); this->server = nullptr; break; } else if(c[i]&&!(c[i] == ' ' || c[i] == '\t')) break; } } server = (monetdbe_database*)malloc(sizeof(monetdbe_database)); monetdbe_options ops; AQ_ZeroMemory(ops); ops.nr_threads = std::thread::hardware_concurrency(); auto ret = monetdbe_open(server, nullptr, &ops); if (ret == 0){ status = true; this->server = server; } else{ if(server) free(server); this->server = nullptr; status = false; puts(ret == -1 ? "Allocation Error." : "Internal Database Error."); } } void Server::exec(const char* q){ auto server = static_cast(this->server); auto _res = static_cast(this->res); monetdbe_cnt _cnt = 0; auto qresult = monetdbe_query(*server, const_cast(q), &_res, &_cnt); if (_res != 0){ this->cnt = _res->nrows; this->res = _res; } if (qresult != nullptr){ printf("Execution Failed. %s\n", qresult); last_error = qresult; } } bool Server::haserror(){ if (last_error){ last_error = nullptr; return true; } else{ return false; } } void Server::print_results(const char* sep, const char* end){ if (!haserror()){ auto _res = static_cast (res); const auto& ncols = _res->ncols; monetdbe_column** cols = static_cast(malloc(sizeof(monetdbe_column*) * ncols)); std::string* printf_string = new std::string[ncols]; const char** col_data = static_cast (malloc(sizeof(char*) * ncols)); uint8_t* szs = static_cast(alloca(ncols)); std::string header_string = ""; const char* err_msg = nullptr; for(uint32_t i = 0; i < ncols; ++i){ err_msg = monetdbe_result_fetch(_res, &cols[i], i); printf_string[i] = std::string(types::printf_str[types::monetdbe_type_aqtypes[cols[i]->type]]) + (i < ncols - 1 ? sep : ""); puts(printf_string[i].c_str()); puts(monetdbe_type_str[cols[i]->type]); col_data[i] = static_cast(cols[i]->data); szs [i] = monetdbe_type_szs[cols[i]->type]; header_string = header_string + cols[i]->name + sep + '|' + sep; } if (const size_t l_sep = strlen(sep) + 1; header_string.size() >= l_sep) header_string.resize(header_string.size() - l_sep); header_string += end + std::string(header_string.size(), '=') + end; fputs(header_string.c_str(), stdout); for(uint64_t i = 0; i < cnt; ++i){ for(uint32_t j = 0; j < ncols; ++j){ printf(printf_string[j].c_str(), *((void**)col_data[j])); col_data[j] += szs[j]; } fputs(end, stdout); } free(cols); delete[] printf_string; free(col_data); } } void Server::close(){ if(this->server){ auto server = static_cast(this->server); monetdbe_close(*(server)); free(server); this->server = nullptr; } } void* Server::getCol(int col_idx){ if(res){ auto _res = static_cast(this->res); auto err_msg = monetdbe_result_fetch(_res, reinterpret_cast(&ret_col), col_idx); if(err_msg == nullptr) { auto _ret_col = static_cast(this->ret_col); cnt = _ret_col->count; printf("Dbg: Getting col %s, type: %s\n", _ret_col->name, monetdbe_type_str[_ret_col->type]); return _ret_col->data; } else{ printf("Error fetching result: %s\n", err_msg); } } else{ puts("Error: No result."); } return nullptr; } Server::~Server(){ close(); } bool Server::havehge() { #if defined(_MONETDBE_LIB_) and defined(HAVE_HGE) // puts("true"); return HAVE_HGE; #else // puts("false"); return false; #endif } void ExecuteStoredProcedureEx(const StoredProcedure *p, Context* cxt){ auto server = static_cast(cxt->alt_server); void* handle = nullptr; uint32_t procedure_module_cursor = 0; for(uint32_t i = 0; i < p->cnt; ++i) { switch(p->queries[i][0]){ case 'Q': { server->exec(p->queries[i]); } break; case 'P': { auto c = code_snippet(dlsym(handle, p->queries[i]+1)); c(cxt); } break; case 'N': { if(procedure_module_cursor < p->postproc_modules) handle = p->__rt_loaded_modules[procedure_module_cursor++]; } break; case 'O': { uint32_t limit; memcpy(&limit, p->queries[i] + 1, sizeof(uint32_t)); if (limit == 0) continue; print_monetdb_results(server, " ", "\n", limit); } break; default: printf("Warning Q%u: unrecognized command %c.\n", i, p->queries[i][0]); } } } int execTriggerPayload(void* args) { auto spp = (StoredProcedurePayload*)(args); ExecuteStoredProcedureEx(spp->p, spp->cxt); delete spp; return 0; }