diff --git a/backend/db/sql-generic.c b/backend/db/sql-generic.c index 87882b932..ed0964232 100644 --- a/backend/db/sql-generic.c +++ b/backend/db/sql-generic.c @@ -2145,4 +2145,157 @@ backend_iterate(gpointer _iterator, bson_t* metadata, GError** error) /*something failed very hard*/ return FALSE; } + +static +gboolean +backend_reset(gpointer _batch, GError** error) +{ + J_TRACE_FUNCTION(NULL); + + JDBType type; + JThreadVariables* thread_variables = NULL; + void* stmt1; + void* stmt2; + JSqlBatch* batch = _batch; + gboolean found1 = FALSE; + gboolean found2 = FALSE; + g_autoptr(GArray) arr_types_out1 = NULL; + g_autoptr(GArray) arr_types_out2 = NULL; + JDBTypeValue value1; + JDBTypeValue value2; + char sql_strbuf[256]; + char table_name[128]; + g_autoptr(GString) error_string = NULL; + + g_return_val_if_fail(_batch != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + if (G_UNLIKELY(!(thread_variables = thread_variables_get(error)))) + { + goto _error3; + } + if (G_UNLIKELY(!_backend_batch_execute(batch, error))) + { + //no ddl in transaction - most databases wont support that - continue without any open transaction + goto _error3; + } + arr_types_out1 = g_array_new(FALSE, FALSE, sizeof(JDBType)); + type = J_DB_TYPE_STRING; + g_array_append_val(arr_types_out1, type); + arr_types_out2 = g_array_new(FALSE, FALSE, sizeof(JDBType)); + type = J_DB_TYPE_UINT32; + g_array_append_val(arr_types_out2, type); + do + { + snprintf(sql_strbuf, sizeof(sql_strbuf), sql_get_table_names, batch->namespace); + if (G_UNLIKELY(!j_sql_prepare(thread_variables->sql_backend, sql_strbuf, &stmt1, NULL, arr_types_out1, error))) + { + goto _error3; + } + if (G_UNLIKELY(!j_sql_step(thread_variables->sql_backend, stmt1, &found1, error))) + { + goto _error2; + } + if (!found1) + { + break; + } + value1.val_string = NULL; + if (G_UNLIKELY(!j_sql_column(thread_variables->sql_backend, stmt1, 0, J_DB_TYPE_STRING, &value1, error))) + { + goto _error2; + } + strncpy(table_name, value1.val_string, sizeof(table_name)); + if (G_UNLIKELY(!j_sql_reset(thread_variables->sql_backend, stmt1, error))) + { + goto _error2; + } + if (G_UNLIKELY(!j_sql_finalize(thread_variables->sql_backend, stmt1, error))) + { + goto _error3; + } + snprintf(sql_strbuf, sizeof(sql_strbuf), "SELECT COUNT(*) FROM '%s'", table_name); + if (G_UNLIKELY(!j_sql_prepare(thread_variables->sql_backend, sql_strbuf, &stmt2, NULL, arr_types_out2, error))) + { + goto _error3; + } + if (G_UNLIKELY(!j_sql_step(thread_variables->sql_backend, stmt2, &found2, error))) + { + goto _error; + } + if (!found2) + { + g_set_error(error, J_BACKEND_DB_ERROR, 0, "reset %s count not found", table_name); + goto _error; + } + if (G_UNLIKELY(!j_sql_column(thread_variables->sql_backend, stmt2, 0, J_DB_TYPE_UINT32, &value2, error))) + { + goto _error; + } + if (value2.val_uint32 > 0) + { + if (!error_string) + error_string = g_string_new("reset -- "); + g_string_append_printf(error_string, "%s -> %d, ", table_name, value2.val_uint32); + } + if (G_UNLIKELY(!j_sql_reset(thread_variables->sql_backend, stmt2, error))) + { + goto _error; + } + if (G_UNLIKELY(!j_sql_finalize(thread_variables->sql_backend, stmt2, error))) + { + goto _error3; + } + snprintf(sql_strbuf, sizeof(sql_strbuf), "DROP TABLE '%s'", table_name); + if (G_UNLIKELY(!j_sql_exec(thread_variables->sql_backend, sql_strbuf, error))) + { + goto _error3; + } + } while (TRUE); + if (G_UNLIKELY(!j_sql_reset(thread_variables->sql_backend, stmt1, error))) + { + goto _error2; + } + if (G_UNLIKELY(!j_sql_finalize(thread_variables->sql_backend, stmt1, error))) + { + goto _error3; + } + if (error_string) + { + g_set_error(error, J_BACKEND_DB_ERROR, 0, "%s", error_string->str); + goto _error3; + } + if (G_UNLIKELY(!_backend_batch_start(batch, error))) + { + goto _error3; + } + return TRUE; +_error: + if (G_UNLIKELY(!j_sql_finalize(thread_variables->sql_backend, stmt2, NULL))) + { + goto _error2; + } + if (G_UNLIKELY(!_backend_batch_start(batch, NULL))) + { + goto _error; + } + return FALSE; +_error2: + if (G_UNLIKELY(!j_sql_finalize(thread_variables->sql_backend, stmt1, NULL))) + { + goto _error3; + } + if (G_UNLIKELY(!_backend_batch_start(batch, NULL))) + { + goto _error; + } + return FALSE; +_error3: + /*something failed very hard*/ + if (G_UNLIKELY(!_backend_batch_start(batch, NULL))) + { + goto _error; + } + return FALSE; +} #endif diff --git a/backend/db/sqlite.c b/backend/db/sqlite.c index 5339c7072..f9cc9bad8 100644 --- a/backend/db/sqlite.c +++ b/backend/db/sqlite.c @@ -40,6 +40,7 @@ #define sql_autoincrement_string " " #define sql_last_insert_id_string " SELECT last_insert_rowid() " +#define sql_get_table_names "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%s_%%'" static gchar* path; @@ -418,6 +419,7 @@ static JBackend sqlite_backend = { .type = J_BACKEND_TYPE_DB, .component = J_BACKEND_COMPONENT_SERVER, + .backend_reset = backend_reset, .db = { .backend_init = backend_init, .backend_fini = backend_fini, diff --git a/include/core/jbackend-operation.h b/include/core/jbackend-operation.h index cefd25f76..fa7444a4a 100644 --- a/include/core/jbackend-operation.h +++ b/include/core/jbackend-operation.h @@ -108,6 +108,8 @@ gboolean j_backend_operation_unwrap_db_update (JBackend*, gpointer, JBackendOper gboolean j_backend_operation_unwrap_db_delete (JBackend*, gpointer, JBackendOperation*); gboolean j_backend_operation_unwrap_db_query (JBackend*, gpointer, JBackendOperation*); +gboolean j_backend_operation_unwrap_reset(JBackend* backend, gpointer, JBackendOperation*); + gboolean j_backend_operation_to_message (JMessage* message, JBackendOperationParam* data, guint len); gboolean j_backend_operation_from_message (JMessage* message, JBackendOperationParam* data, guint len); gboolean j_backend_operation_from_message_static (JMessage* message, JBackendOperationParam* data, guint len); @@ -241,6 +243,22 @@ static const JBackendOperation j_backend_operation_db_query = { }, }; +static const JBackendOperation j_backend_operation_reset = { + .backend_func = j_backend_operation_unwrap_reset, + .in_param_count = 1, + .out_param_count = 1, + .in_param = { + { + .type = J_BACKEND_OPERATION_PARAM_TYPE_STR, + }, + }, + .out_param = { + { + .type = J_BACKEND_OPERATION_PARAM_TYPE_ERROR, + }, + }, +}; + G_END_DECLS #endif diff --git a/include/core/jbackend.h b/include/core/jbackend.h index ab5ff1084..6ae4e747f 100644 --- a/include/core/jbackend.h +++ b/include/core/jbackend.h @@ -126,6 +126,13 @@ struct JBackend JBackendType type; JBackendComponent component; + /** + * delete everything in the backend + * \param[in] which namespace to delete + * \param[out] how many "things" are deleted within the specified namespace + */ + gboolean (*backend_reset)(gpointer, GError**); + union { struct @@ -431,6 +438,7 @@ gboolean j_backend_db_delete (JBackend*, gpointer, gchar const*, bson_t const*, gboolean j_backend_db_query (JBackend*, gpointer, gchar const*, bson_t const*, gpointer*, GError**); gboolean j_backend_db_iterate (JBackend*, gpointer, bson_t*, GError**); +gboolean j_backend_reset (JBackend* backend, gpointer, GError**); G_END_DECLS #endif diff --git a/include/core/jmessage.h b/include/core/jmessage.h index ce4b352bc..e9d3d0fb0 100644 --- a/include/core/jmessage.h +++ b/include/core/jmessage.h @@ -53,7 +53,8 @@ enum JMessageType J_MESSAGE_DB_INSERT, J_MESSAGE_DB_UPDATE, J_MESSAGE_DB_DELETE, - J_MESSAGE_DB_QUERY + J_MESSAGE_DB_QUERY, + J_MESSAGE_RESET }; typedef enum JMessageType JMessageType; diff --git a/include/db/jdb-internal.h b/include/db/jdb-internal.h index 4c7e29e1b..a8d4e64f9 100644 --- a/include/db/jdb-internal.h +++ b/include/db/jdb-internal.h @@ -114,6 +114,8 @@ gboolean j_db_internal_delete (gchar const* namespace, gchar const* name, bson_t gboolean j_db_internal_query (gchar const* namespace, gchar const* name, bson_t const* selector, gpointer* iterator, JBatch* batch, GError** error); gboolean j_db_internal_iterate (gpointer iterator, bson_t* metadata, GError** error); +gboolean j_internal_reset (gchar const* namespace, JBatch* batch, GError** error); + // Client-side additional internal functions bson_t* j_db_selector_get_bson (JDBSelector* selector); diff --git a/lib/core/jbackend-operation.c b/lib/core/jbackend-operation.c index ea78ecb1d..dd8448da9 100644 --- a/lib/core/jbackend-operation.c +++ b/lib/core/jbackend-operation.c @@ -38,6 +38,15 @@ * @{ **/ +gboolean +j_backend_operation_unwrap_reset(JBackend* backend, gpointer batch, JBackendOperation* data) +{ + J_TRACE_FUNCTION(NULL); + + return j_backend_reset(backend, batch, data->out_param[0].ptr); +} + + gboolean j_backend_operation_unwrap_db_schema_create (JBackend* backend, gpointer batch, JBackendOperation* data) { diff --git a/lib/core/jbackend.c b/lib/core/jbackend.c index 519caa48a..1a7cadeea 100644 --- a/lib/core/jbackend.c +++ b/lib/core/jbackend.c @@ -897,6 +897,22 @@ j_backend_db_iterate (JBackend* backend, gpointer iterator, bson_t* metadata, GE return ret; } +gboolean +j_backend_reset(JBackend* backend, gpointer batch, GError** error) +{ + J_TRACE_FUNCTION(NULL); + + g_return_val_if_fail(backend != NULL, FALSE); + g_return_val_if_fail(batch != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + if (backend->backend_reset) + { + return backend->backend_reset(batch, error); + } + return TRUE; +} + /** * @} **/ diff --git a/lib/db/jdb-internal.c b/lib/db/jdb-internal.c index f37d4c269..e6c67de59 100644 --- a/lib/db/jdb-internal.c +++ b/lib/db/jdb-internal.c @@ -153,6 +153,36 @@ j_backend_db_func_free (gpointer _data) } } +static +gboolean +j_reset_exec(JList* operations, JSemantics* semantics) +{ + J_TRACE_FUNCTION(NULL); + + //FIXME call this on EVERY backend(type) + return j_backend_db_func_exec(operations, semantics, J_MESSAGE_RESET); +} +gboolean +j_internal_reset(gchar const* namespace, JBatch* batch, GError** error) +{ + J_TRACE_FUNCTION(NULL); + + JOperation* op; + JBackendOperation* data; + + data = g_slice_new(JBackendOperation); + memcpy(data, &j_backend_operation_reset, sizeof(JBackendOperation)); + data->in_param[0].ptr_const = namespace; + data->out_param[0].ptr_const = error; + op = j_operation_new(); + op->key = namespace; + op->data = data; + op->exec_func = j_reset_exec; + op->free_func = j_backend_db_func_free; + j_batch_add(batch, op); + return TRUE; +} + static gboolean j_db_schema_create_exec (JList* operations, JSemantics* semantics) diff --git a/server/loop.c b/server/loop.c index b370ef11c..e9cdb9c33 100644 --- a/server/loop.c +++ b/server/loop.c @@ -553,6 +553,13 @@ jd_handle_message (JMessage* message, GSocketConnection* connection, JMemoryChun j_message_send(reply, connection); } break; + case J_MESSAGE_RESET: + if (!message_matched) + { + memcpy(&backend_operation, &j_backend_operation_reset, sizeof(JBackendOperation)); + message_matched = TRUE; + } + // fallthrough case J_MESSAGE_DB_SCHEMA_CREATE: if (!message_matched) {