#ifndef SORM_H #define SORM_H #include "str.h" #include #include "rlib.h" #include #include #include #include #include #include sqlite3 *db; sqlite3_stmt *stmt; char *sorm_last_query = NULL; char *sorm_last_query_expanded = NULL; nsecs_t _sorm_query_start = 0; nsecs_t _sorm_query_end = 0; nsecs_t _sorm_query_duration = 0; nsecs_t _sorm_result_format_start = 0; nsecs_t _sorm_result_format_end = 0; nsecs_t _sorm_result_format_duration = 0; int64_t sorm_row_count = 0; typedef struct sorm_t { sqlite3 *conn; int current_row; int current_column; char *csv; nsecs_t time_query_start; nsecs_t time_query_end; nsecs_t time_query_duration; nsecs_t time_result_format_start; nsecs_t time_result_format_end; nsecs_t time_result_format_duration; } sorm_t; typedef char *sorm_pk; typedef char *sorm_int; typedef char *sorm_ptr; typedef unsigned char *sorm_str; typedef double sorm_double; typedef double sorm_float; typedef bool sorm_bool; int sormc(char *path); void sormd(int db); char *sormpt(char *sql, int number); unsigned int sormcq(char *sql, char *out); unsigned int sormpc(char *sql); sqlite3_stmt *sormb(sorm_t *db, char *sql, ...); sorm_ptr sormq(int db, char *sql, ...); char *sorm_csvc(int db, sqlite3_stmt *stmt); char *sorm_csvd(int db, sqlite3_stmt *stmt); char *sorm_csv(int db, sqlite3_stmt *stmt); typedef enum sorm_query_t { SORM_UNKNOWN = 0, SORM_SELECT = 1, SORM_INSERT = 2, SORM_UPDATE = 3, SORM_DELETE = 4, SORM_CREATE = 5 } sorm_query_t; const int sorm_null = -1337; sorm_t **sorm_instances = NULL; int sorm_instance_count = 0; int sormc(char *path) { // sorm connect sorm_instance_count++; sorm_instance_count++; sorm_instances = realloc(sorm_instances, sorm_instance_count * sizeof(sorm_t *) + sorm_instance_count * sizeof(sorm_t)); sorm_t *db = &sorm_instances[sorm_instance_count - 1]; db->conn = NULL; db->csv = NULL; db->current_column = 0; db->current_row = 0; db->time_query_duration = 0; db->time_query_end = 0; db->time_query_start = 0; db->time_result_format_duration = 0; db->time_result_format_end = 0; db->time_result_format_start = 0; if (sqlite3_open(path, &db->conn)) { fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db->conn)); return 0; } return sorm_instance_count; } sorm_t *sormg(int ptr) { return &sorm_instances[ptr - 1]; } char *sormgcsv(int ptr) { /* sorm get csv*/ sorm_t *db = sormg(ptr); return db->csv; } void sormd(int sorm) { sorm_t *db = sormg(sorm); if (sqlite3_close(db->conn)) { fprintf(stderr, "Error closing database: %s\n", sqlite3_errmsg(db->conn)); } if (sorm_last_query) { free(sorm_last_query); sorm_last_query = NULL; } if (sorm_last_query_expanded) { free(sorm_last_query_expanded); sorm_last_query_expanded = NULL; } } char *sormpt(char *sql, int number) { // param type char *sqlp = sql; char *result = NULL; int index = 0; while (*sqlp) { if (*sqlp == '%' || *sqlp == '?') { sqlp++; switch (*sqlp) { case 'f': result = "double"; break; case 's': result = "text"; break; case 'd': result = "int"; break; case 'b': result = "blob"; break; default: result = "?"; break; } sqlp++; index++; } if (index == number) { return result; } if (*sqlp) sqlp++; } if (number > index) { printf("RETURNED\n"); return NULL; } return NULL; } unsigned int sormcq(char *sql, char *out) { // clean query // converts %s %i parameters to ? unsigned int count = 0; while (*sql) { if (*sql != '%' && *sql != '?') *out = *sql; else { count++; sql++; *out = '?'; } out++; sql++; } *out = 0; return count; } unsigned int sormpc(char *sql) { int number = 0; while (sormpt(sql, number) != NULL) number++; printf("FOUND: %d\n", number); return number; } char *sormcts(int column_type) { if (column_type == SQLITE_INTEGER) return "integer"; else if (column_type == SQLITE_TEXT) return "text"; else if (column_type == SQLITE_FLOAT) return "float"; else if (column_type == SQLITE_NULL) return "null"; else if (column_type == SQLITE_BLOB) return "blob"; return "?"; } /* Execute 3.35s, Format: 36.77s Memory usage: 537 GB, 96.026 allocated, 96.024 freed, 2 in use. */ char *sorm_csvc(int db, sqlite3_stmt *stmt) { sormstr_t *str = sormstrn(512); unsigned int column_count = sqlite3_column_count(stmt); for (int i = 0; i < column_count; i++) { const char *column_name = sqlite3_column_name(stmt, i); sormstra(str, column_name); sormstra(str, "("); char column_type[1000] = ""; sprintf(column_type, "%s", sormcts(sqlite3_column_type(stmt, i))); sormstra(str, column_type); sormstra(str, ")"); // if(i != column_count - 1) sormstra(str, ";"); } return sormstrc(str); } char *sorm_csvd(int sorm, sqlite3_stmt *stmt) { sorm_t *db = sormg(sorm); int rc = SQLITE_ROW; int column_count = sqlite3_column_count(stmt); /* sormstrn(1) Execute 3.41s, Format: 36.77s Memory usage: 5 MB, 96.061 (re)allocated, 96.024 unqiue freed, 2 in use. sormstrn(512) Execute 3.68s, Format: 36.83s Memory usage: 537 GB, 96.026 allocated, 96.024 freed, 2 in use. sormstrn(256) xecute 3.42s, Format: 37.33s Memory usage: 6 MB, 96.052 (re)allocated, 96.024 unqiue freed, 2 in use. */ sormstr_t *str = sormstrn(512); while (rc == SQLITE_ROW) { sorm_row_count++; for (int field_index = 0; field_index < column_count; field_index++) { if (sqlite3_column_type(stmt, field_index) == SQLITE_INTEGER) { char temp[1000] = ""; sprintf(temp, "%lld", sqlite3_column_int64(stmt, field_index)); sormstra(str, temp); } else if (sqlite3_column_type(stmt, field_index) == SQLITE_FLOAT) { char temp[1000] = ""; sprintf(temp, "%f", sqlite3_column_double(stmt, field_index)); sormstra(str, temp); } else if (sqlite3_column_type(stmt, field_index) == SQLITE3_TEXT) { const char *temp = sqlite3_column_text(stmt, field_index); sormstra(str, temp); } else { // exit(1); } // if(field_index != column_count - 1) sormstra(str, ";"); } sormstra(str, "\n"); rc = sqlite3_step(stmt); } char *text = sormstrc(str); if (*text) if (text[strlen(text) - 1] == '\n') text[strlen(text) - 1] = 0; return strdup(text); } char *sorm_csv(int sorm, sqlite3_stmt *stmt) { sorm_t *db = sormg(sorm); sorm_row_count = 0; char *column_names = sorm_csvc(sorm, stmt); char *data = sorm_csvd(sorm, stmt); char *result = (char *)malloc(strlen(column_names) + strlen(data) + 2); result[0] = 0; strcat(result, column_names); if (*column_names) strcat(result, "\n"); free(column_names); strcat(result, data); free(data); return result; } sqlite3_stmt *sormb(sorm_t *db, char *sql, ...) { // Bind parameters to statement and return amount of parameters int rc = 0; sqlite3_stmt *stmt; va_list args; va_start(args, sql); unsigned int number = 0; char *clean_query = (char *)malloc(strlen(sql) + 1); unsigned int parameter_count = sormcq(sql, clean_query); free(clean_query); return stmt; } char *sormm(sorm_t *db) { /* sormmemory */ return rmalloc_stats(); } sorm_ptr sormq(int sorm, char *sql, ...) { sorm_t *db = sormg(sorm); _sorm_query_start = nsecs(); db->time_query_start = nsecs(); va_list args; va_start(args, sql); sqlite3_stmt *stmt; sorm_ptr result = NULL; char *clean_query = malloc(strlen(sql) + 1); unsigned int parameter_count = sormcq(sql, clean_query); int rc = sqlite3_prepare_v2(db->conn, clean_query, -1, &stmt, 0); if (rc != SQLITE_OK) { fprintf(stderr, "%s\n", sqlite3_errmsg(db->conn)); } free(clean_query); int number = 0; for (int i = 0; i < parameter_count; i++) { number++; char *column_type = sormpt(sql, number); int arg_index = number - 1; if (!strcmp(column_type, "int") || !strcmp(column_type, "integer") || !strcmp(column_type, "number")) { rc = sqlite3_bind_int(stmt, number, va_arg(args, int)); } else if (!strcmp(column_type, "int64")) { rc = sqlite3_bind_int64(stmt, number, va_arg(args, __uint64_t)); } else if (!strcmp(column_type, "double") || !strcmp(column_type, "dec") || !strcmp(column_type, "decimal") || !strcmp(column_type, "float")) { rc = sqlite3_bind_double(stmt, number, va_arg(args, double)); } else if (!strcmp(column_type, "blob")) { size_t size = (size_t)va_arg(args, size_t); unsigned char *data = va_arg(args, unsigned char *); rc = sqlite3_bind_blob(stmt, number, data, size, SQLITE_STATIC); } else if (!strcmp(column_type, "text") || !strcmp(column_type, "str") || !strcmp(column_type, "string")) { unsigned char *data = va_arg(args, unsigned char *); rc = sqlite3_bind_text(stmt, number, data, -1, SQLITE_STATIC); } if (rc != SQLITE_OK) { fprintf(stderr, "Failed to bind parameters: %s\n", sqlite3_errmsg(db->conn)); result = NULL; } } rc = sqlite3_step(stmt); if (rc != SQLITE_DONE && rc != SQLITE_ROW) { fprintf(stderr, "Execution failed: %s\n", sqlite3_errmsg(db->conn)); } else if (rc == SQLITE_DONE) { if (!sqlite3_strnicmp(sql, "SELECT", 6)) { result = 0; } else { result = (sorm_ptr)sqlite3_last_insert_rowid(db->conn); } } else if (rc == SQLITE_ROW) { result = sorm_csv(sorm, stmt); } else { fprintf(stderr, "Execution failed: %s\n", sqlite3_errmsg(db->conn)); } if (sorm_last_query) { free(sorm_last_query); } if (sorm_last_query) { free(sorm_last_query_expanded); } sorm_last_query = strdup(sqlite3_sql(stmt)); sorm_last_query_expanded = strdup(sqlite3_expanded_sql(stmt)); sqlite3_finalize(stmt); _sorm_query_end = nsecs(); _sorm_query_duration = _sorm_query_end - _sorm_query_start; db->time_query_end = nsecs(); db->time_query_duration = db->time_query_end - db->time_query_start; db->csv = result; return result; } char sormlc(char *sql) { // returns last char char last_char = 0; while (*sql) { if (*sql == ' ' || *sql == '\t' || *sql == '\n') continue; // printf("%c\n",*sql); last_char = *sql; sql++; } return last_char; } int sormlv(char *csv) { size_t longest = 0; while (*csv) { char *found = strstr(csv, ";"); if (found) { if (found - csv > longest) longest = found - csv; csv = csv + (found - csv) + 1; } else { break; } } return longest; } sorm_query_t sormqt(char *sql) { while (*sql && isspace(*sql)) sql++; if (!sqlite3_strnicmp(sql, "select", 6)) return SORM_SELECT; else if (!sqlite3_strnicmp(sql, "update", 6)) return SORM_UPDATE; else if (!sqlite3_strnicmp(sql, "delete", 6)) return SORM_DELETE; else if (!sqlite3_strnicmp(sql, "create", 6)) { return SORM_CREATE; } else { return SORM_UNKNOWN; } } char *sormrq(FILE *f) { static char buffer[4097]; buffer[0] = 0; char *bufferp = buffer; char c; bool in_string = false; while ((c = fgetc(f)) != EOF && strlen(buffer) != sizeof(buffer) - 2) { *bufferp = c; if (c == '"') { in_string = !in_string; } if (!in_string && c == ';') { break; } bufferp++; *bufferp = 0; } return strdup(buffer); } char *sormcsvn(char *csv) { if (!csv || !*csv) return NULL; char *pos = strstr(csv, ";"); char *pos2 = strstr(csv, "\n"); if (pos2) { if (pos > pos2) { pos = pos2; } // pos = pos > pos2 ? pos2 : pos; } if (!pos || !*pos) return strdup(csv); int length = pos - csv; char *result = malloc(length + 2); strncpy(result, csv, length); result[length] = 0; // csv += strlen(result); return result; } char *sormfmt(char *csv) { _sorm_result_format_start = nsecs(); size_t longest = sormlv(csv); char *field; /* sormstrn(1) Execute 3.77s, Format: 36.40s Memory usage: 6 MB, 96.055 (re)allocated, 96.024 unqiue freed, 2 in use. sormstrn(longest); Execute 3.27s, Format: 36.61s Memory usage: 6 MB, 96.053 (re)allocated, 96.024 unqiue freed, 2 in use. sormstrn(longest * 2); xecute 3.42s, Format: 37.33s Memory usage: 6 MB, 96.052 (re)allocated, 96.024 unqiue freed, 2 in use. sormstrn(512); Execute 3.11s, Format: 36.45s Memory usage: 6 MB, 96.048 (re)allocated, 96.024 unqiue freed, 2 in use. */ sormstr_t *str = sormstrn(longest + 2); while (*csv && (field = sormcsvn(csv))) { sormstra(str, field); for (int i = 0; i < longest - strlen(field); i++) sormstra(str, " "); csv += strlen(field); while (*csv == ';' || *csv == '\n') { if (*csv == '\n') sormstra(str, "\n"); csv++; } free(field); } _sorm_result_format_end = nsecs(); _sorm_result_format_duration = _sorm_result_format_end - _sorm_result_format_start; return sormstrc(str); } void apply_colors(char *csv) { char *end; bool even = false; while (*csv) { printf("%s\n", csv); end = strstr(csv, "\n"); char *line; if (end) { line = (char *)malloc(end - csv + 1024); strncpy(line, csv, end - csv); } else { line = (char *)malloc(strlen(csv) + 1024); strcpy(line, csv); } if (even) { printf("%s", "\033[37m"); } printf("%s\n", line); free(line); if (even) { printf("%s", "\033[0m"); } even = !even; csv += end - csv; if (*csv && *(csv + 1)) csv++; } } void sormfmtd(char *csv) { char *formatted = sormfmt(csv); printf("%s\n", formatted); free(formatted); } #endif