0
0
mirror of https://github.com/tursodatabase/libsql.git synced 2025-07-13 19:05:19 +00:00
Files
libsql/libsql-sqlite3/ext/crr/src/rows-impacted.test.c
2023-12-12 09:46:49 -05:00

380 lines
12 KiB
C

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "crsqlite.h"
int crsql_close(sqlite3 *db);
static sqlite3 *createDb() {
int rc = SQLITE_OK;
sqlite3 *db;
rc = sqlite3_open(":memory:", &db);
rc +=
sqlite3_exec(db, "CREATE TABLE foo (a primary key not null, b)", 0, 0, 0);
rc += sqlite3_exec(db, "SELECT crsql_as_crr('foo')", 0, 0, 0);
assert(rc == SQLITE_OK);
return db;
}
static void testSingleInsertSingleTx() {
printf("SingleInsertSingleTx\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010901', 'b', "
"2, 1, 1, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
// creation + setting of column
assert(sqlite3_column_int(pStmt, 0) == 1);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
// rows impacted gets reset
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
int impacted = sqlite3_column_int(pStmt, 0);
assert(impacted == 0);
sqlite3_finalize(pStmt);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
static void testManyInsertsInATx() {
printf("ManyInsertsInATx\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010901', 'b', "
"2, 1, 1, NULL, 1, 1)",
0, 0, &err);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010902', 'b', "
"2, 1, 1, NULL, 1, 1)",
0, 0, &err);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010903', 'b', "
"2, 1, 1, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 3);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
// rows impacted gets reset
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 0);
sqlite3_finalize(pStmt);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
static void testMultipartInsertInTx() {
printf("MultipartInsertInTx\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010901', 'b', "
"2, 1, 1, NULL, 1, 1), "
"('foo', X'010902', 'b', 2, 1, 1, NULL, 1, 1), ('foo', "
"X'010903', 'b', 2, 1, 1, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 3);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
// rows impacted gets reset
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 0);
sqlite3_finalize(pStmt);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
// count should reset between transactions
static void testManyTxns() {
printf("ManyTxns\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010901', 'b', "
"2, 1, 1, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 1);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010902', 'b', "
"2, 1, 1, NULL, 1, 1)",
0, 0, &err);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010903', 'b', "
"2, 1, 1, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
int impacted = sqlite3_column_int(pStmt, 0);
assert(impacted == 2);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
// You can't do this. `crsql_rows_impacted` is evaulated before the insert is
// run thus the right value can never be returned by `RETURNING` in this setup.
// static void testReturningInTx() {
// printf("RetruningInTx\n");
// int rc = SQLITE_OK;
// char *err = 0;
// sqlite3 *db = createDb();
// sqlite3_stmt *pStmt = 0;
// rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
// rc += sqlite3_prepare_v2(
// db,
// "INSERT INTO crsql_changes VALUES ('foo', 1, 'b', 2, 1, 1, NULL), "
// "('foo', 2, 'b', 2, 1, 1, NULL), ('foo', 3, 'b', 2, 1, 1, NULL) "
// "RETURNING crsql_rows_impacted()",
// -1, &pStmt, 0);
// rc += sqlite3_step(pStmt);
// int impacted = sqlite3_column_int(pStmt, 0);
// printf("impacted: %d\n", impacted);
// assert(impacted == 3);
// sqlite3_finalize(pStmt);
// rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
// assert(rc == SQLITE_OK);
// crsql_close(db);
// printf("\t\e[0;32mSuccess\e[0m\n");
// }
static void testUpdateThatDoesNotChangeAnything() {
printf("UpdateThatDoesNotChangeAnything\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "INSERT INTO foo VALUES (1, 2)", 0, 0, 0);
rc += sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', "
"crsql_pack_columns(1), 'b', 2, 1, 1, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 0);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
// now test value <
rc += sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', "
"crsql_pack_columns(1), 'b', 0, 1, 1, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 0);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
// now test clock <
rc += sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', "
"crsql_pack_columns(1), 'b', 2, 0, 0, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 0);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
static void testDeleteThatDoesNotChangeAnything() {
printf("DeleteThatDoesNotChangeAnything\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "INSERT INTO foo VALUES (1, 2)", 0, 0, 0);
rc = sqlite3_exec(db, "DELETE FROM foo", 0, 0, 0);
rc += sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(
db,
"INSERT INTO crsql_changes VALUES ('foo', crsql_pack_columns(1), "
"'-1', NULL, 2, 2, NULL, 1, 1)", //__crsql_del
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 0);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
static void testDelete() {
printf("Delete\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "INSERT INTO foo VALUES (1, 2)", 0, 0, 0);
rc += sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010901', "
"'-1', NULL, 2, 2, NULL, 2, 1)", //__crsql_del
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 1);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
static void testCreateThatDoesNotChangeAnything() {
printf("UpdateThatDoesNotChangeAnything\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "INSERT INTO foo VALUES (1, 2)", 0, 0, 0);
rc += sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010901', 'b', "
"2, 1, 1, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 0);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
static void testValueWin() {
printf("ValueWin\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "INSERT INTO foo VALUES (1, 2)", 0, 0, 0);
rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010901', 'b', "
"3, 1, 1, X'00000000000000000000000000000000', 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 1);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
static void testClockWin() {
printf("ClockWin\n");
int rc = SQLITE_OK;
char *err = 0;
sqlite3 *db = createDb();
sqlite3_stmt *pStmt = 0;
rc = sqlite3_exec(db, "INSERT INTO foo VALUES (1, 2)", 0, 0, 0);
rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
rc += sqlite3_exec(db,
"INSERT INTO crsql_changes VALUES ('foo', X'010901', 'b', "
"2, 2, 2, NULL, 1, 1)",
0, 0, &err);
sqlite3_prepare_v2(db, "SELECT crsql_rows_impacted()", -1, &pStmt, 0);
sqlite3_step(pStmt);
assert(sqlite3_column_int(pStmt, 0) == 1);
sqlite3_finalize(pStmt);
rc += sqlite3_exec(db, "COMMIT", 0, 0, 0);
assert(rc == SQLITE_OK);
crsql_close(db);
printf("\t\e[0;32mSuccess\e[0m\n");
}
void rowsImpactedTestSuite() {
printf("\e[47m\e[1;30mSuite: rows_impacted\e[0m\n");
testSingleInsertSingleTx();
testManyInsertsInATx();
testMultipartInsertInTx();
testManyTxns();
testUpdateThatDoesNotChangeAnything();
testDeleteThatDoesNotChangeAnything();
testCreateThatDoesNotChangeAnything();
testValueWin();
testClockWin();
testDelete();
}