feat: add capture and asset provenance v1
This commit is contained in:
parent
2ab4487f1e
commit
9f409645e3
13 changed files with 831 additions and 48 deletions
|
|
@ -25,11 +25,14 @@ persistante, enrichissable et versionnable.
|
|||
- **Project** : cycle de vie persistant, identité stable et Project Database ouverte
|
||||
- **Import** : premier task kind de production, exécuté par la file générique en lots bornés et reprenables
|
||||
- **ScanSet / Image Catalog v1** : acquisitions, images logiques, provenance et assets SHA-256 persistants et paginés
|
||||
- **Capture / Asset Provenance v1** : Captures par ScanSet, associations source/dérivé
|
||||
et sélection explicite d'une image logique — IMPLEMENTED / VALIDATION PENDING
|
||||
- **Feature Store v1/v2** : ORB U8×32, SIFT/RootSIFT F32×128 et lecture typée bornée
|
||||
- **Image View** : vues triées et filtrées pour la TUI
|
||||
- **Task** : moteur de tâches avec pause/reprise, annulation et séquences
|
||||
- **Task Checkpoint v1** : snapshot durable, fichier atomique et reprise sûre
|
||||
- **Project Database v18** : résultats v16 et payload durable typé Sparse SfM Gate F
|
||||
- **Project Database v19** : fondations v18 préservées, avec Capture / Asset
|
||||
Provenance additive
|
||||
- **Sparse SfM Gates C/D/E** : géométrie calibrée, noyau incrémental et Bundle
|
||||
Adjustment final par composante, tous PASS / FROZEN
|
||||
- **Sparse SfM Gate F** : orchestration durable, runtime gouverné et publication
|
||||
|
|
|
|||
|
|
@ -1,5 +1,24 @@
|
|||
# Base de données projet Lardon3D
|
||||
|
||||
## Capture / Asset Provenance v1 — Project DB v19
|
||||
|
||||
**IMPLEMENTED / VALIDATION PENDING.** La migration transactionnelle v18→v19
|
||||
ajoute seulement une fondation de catalogue : `captures`, `capture_images`,
|
||||
`capture_assets`, `capture_selections` et `asset_derivations`. Un `Capture`
|
||||
appartient à un seul ScanSet ; il n'est ni un `image_id` ni une nouvelle identité
|
||||
scientifique. Les assets source et dérivés peuvent lui être associés sans créer
|
||||
d'image logique. Une sélection courante optionnelle référence exactement une
|
||||
image déjà associée au Capture et ne modifie jamais cette image, son asset, ni
|
||||
les résultats scientifiques existants.
|
||||
|
||||
`asset_derivations` est volontairement limité à un parent asset et un enfant
|
||||
asset, avec kind/version et fingerprint canonique de 32 octets. Il n'est pas un
|
||||
DAG générique et ne réalise aucun développement RAW ni extraction vidéo. La
|
||||
migration crée, par `image_id` croissant, un Capture legacy indépendant pour
|
||||
chaque image v18, relie son asset comme source et rend cette même image
|
||||
sélectionnée. Aucun nom de fichier, EXIF ou rapprochement de siblings n'est
|
||||
interprété ; les IDs et la sémantique v18 restent inchangés.
|
||||
|
||||
## Phase H — décision Project DB v18
|
||||
|
||||
**PASS / FROZEN.** La migration transactionnelle v17→v18
|
||||
|
|
@ -65,7 +84,9 @@ persistée exactement ; seule une composante de graphe non reconstruite est
|
|||
omise. Les comptes et métriques globaux décrivent exclusivement la géométrie
|
||||
effectivement persistée. Aucun placeholder ni table diagnostique n'est ajouté.
|
||||
|
||||
> Version courante : **v18**. La migration transactionnelle v17→v18 ajoute le
|
||||
> Version courante : **v19**. La migration transactionnelle v18→v19 ajoute la
|
||||
> fondation Capture/Asset Provenance décrite ci-dessus sans modifier les tables
|
||||
> scientifiques historiques. La migration transactionnelle v17→v18 ajoute le
|
||||
> discriminateur générique nullable et les deux tables H minimales décrites
|
||||
> ci-dessus. La migration v16→v17 ajoute le
|
||||
> payload durable typé `sparse_sfm_tasks`. La migration transactionnelle v15→v16 ajoute
|
||||
|
|
@ -808,8 +829,8 @@ ouvert.
|
|||
|
||||
## Statut
|
||||
|
||||
**IMPLEMENTED** — SQLite système, schéma v18 et migrations séquentielles
|
||||
v1→v2→v3→v4→v5→v6→v7→v8→v9→v10→v11→v12→v13→v14→v15→v16→v17→v18, identité projet, transactions
|
||||
**IMPLEMENTED / VALIDATION PENDING** — SQLite système, schéma v19 et migrations séquentielles
|
||||
v1→v2→v3→v4→v5→v6→v7→v8→v9→v10→v11→v12→v13→v14→v15→v16→v17→v18→v19, identité projet, transactions
|
||||
tâche+checkpoint, pagination de reprise et artefacts génériques.
|
||||
|
||||
**IMPLEMENTED** — ouverture/fermeture avec le projet, identité INI/DB cohérente,
|
||||
|
|
@ -829,6 +850,12 @@ bornée à 256. Les identités sont des `INTEGER PRIMARY KEY AUTOINCREMENT` SQLi
|
|||
allouées sous transaction ; aucun `SELECT MAX()+1` n'est utilisé en
|
||||
fonctionnement normal et une identité validée n'est jamais réutilisée.
|
||||
|
||||
**IMPLEMENTED / VALIDATION PENDING** — Capture / Asset Provenance v1 :
|
||||
Capture borné par ScanSet, associations explicites asset/image, sélection
|
||||
courante optionnelle et dérivation asset à parent unique. RAW, vidéo,
|
||||
appariement automatique et toute exécution de dérivation restent hors de cette
|
||||
fondation.
|
||||
|
||||
La migration v3→v4 ne lit pas `manifest.tsv`. Elle crée le ScanSet legacy et
|
||||
positionne `metadata.legacy_image_catalog_pending=1` dès qu'une ancienne tâche
|
||||
d'import existe. Cet indicateur signifie « données legacy potentiellement non
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ l'import.
|
|||
```text
|
||||
Project
|
||||
└── ScanSet (acquisition logique)
|
||||
└── Image (observation logique)
|
||||
└── Image Asset (contenu physique géré)
|
||||
└── Capture (observation physique potentielle)
|
||||
├── Image Assets source/dérivés (contenus physiques gérés)
|
||||
├── Images (représentations logiques)
|
||||
└── zéro ou une Image sélectionnée
|
||||
```
|
||||
|
||||
- `scanset_id` identifie durablement une acquisition, indépendamment de son
|
||||
|
|
@ -25,6 +27,15 @@ Project
|
|||
chemin relatif décrivent le fichier géré par Lardon3D.
|
||||
- La provenance d'une image conserve son nom original, son chemin source, son
|
||||
instant d'import et, s'il existe, le `task_id` importeur.
|
||||
- Un `Capture` est une association de catalogue dans un unique ScanSet ; il ne
|
||||
remplace pas `image_id`. Il peut conserver par exemple les assets RAW et JPEG
|
||||
d'un même déclenchement, sans inférer ce lien à partir de leurs noms.
|
||||
- Seule une image logique explicitement sélectionnée est la représentation
|
||||
courante proposée au pipeline scientifique ultérieur. La sélection ne modifie
|
||||
ni l'image, ni son asset, ni les résultats existants.
|
||||
- Une dérivation asset bornée parent→enfant, versionnée par fingerprint, rend
|
||||
possible une future image de travail RAW ou frame vidéo sans prétendre que
|
||||
RAW ou vidéo sont déjà importés.
|
||||
|
||||
Un contenu identique n'implique pas une identité logique unique. Dans un même
|
||||
ScanSet, le couple `(scanset_id, asset_id)` est unique : réimporter le même
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ Lardon3D suit une feuille de route ordonnée qui privilégie la stabilité et la
|
|||
|
||||
### Phase 5 : Reconstruction
|
||||
- ✅ Orchestration de reconstruction incrémentale H v1 — **PASS / FROZEN**
|
||||
- 🔄 Capture / Asset Provenance v1 — **IMPLEMENTED / VALIDATION PENDING** :
|
||||
Project DB v19 ajoute les Captures par ScanSet, les associations source/dérivé
|
||||
et la sélection explicite d'une image logique, sans changer le pipeline
|
||||
scientifique. L'ingestion RAW et vidéo reste PLANNED.
|
||||
- ✅ MVS-M1 — **PASS / FROZEN** : identité dense `L3DMDID2`
|
||||
v2 (220 octets) liant reconstruction de base, jeu d'images source,
|
||||
`calibration_scope_identity` historique, binding numérique exact `L3DMCAL1` v1,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include <lardon3d/sparse_sfm_incremental.h>
|
||||
|
||||
enum {
|
||||
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 18,
|
||||
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 19,
|
||||
LARDON3D_PROJECT_DB_ID_CAPACITY = 65,
|
||||
LARDON3D_PROJECT_DB_KIND_CAPACITY = 65,
|
||||
LARDON3D_PROJECT_DB_PATH_CAPACITY = 4096,
|
||||
|
|
@ -129,6 +129,38 @@ typedef struct {
|
|||
int64_t imported_at;
|
||||
} Lardon3DProjectDbImage;
|
||||
|
||||
typedef struct {
|
||||
uint64_t capture_id;
|
||||
uint64_t scanset_id;
|
||||
int64_t created_at;
|
||||
} Lardon3DProjectDbCapture;
|
||||
|
||||
typedef enum {
|
||||
LARDON3D_DB_CAPTURE_ASSET_SOURCE = 1,
|
||||
LARDON3D_DB_CAPTURE_ASSET_DERIVED = 2,
|
||||
} Lardon3DProjectDbCaptureAssetRole;
|
||||
|
||||
typedef struct {
|
||||
uint64_t capture_id;
|
||||
uint64_t asset_id;
|
||||
Lardon3DProjectDbCaptureAssetRole role;
|
||||
} Lardon3DProjectDbCaptureAsset;
|
||||
|
||||
typedef enum {
|
||||
LARDON3D_DB_ASSET_DERIVATION_GENERIC_VERSIONED = 1,
|
||||
} Lardon3DProjectDbAssetDerivationKind;
|
||||
|
||||
typedef struct {
|
||||
uint64_t parent_asset_id;
|
||||
uint64_t child_asset_id;
|
||||
Lardon3DProjectDbAssetDerivationKind kind;
|
||||
uint32_t version;
|
||||
unsigned char parameter_fingerprint[LARDON3D_PROJECT_DB_SHA256_SIZE];
|
||||
bool has_producer_task;
|
||||
uint64_t producer_task_id;
|
||||
int64_t created_at;
|
||||
} Lardon3DProjectDbAssetDerivation;
|
||||
|
||||
typedef struct {
|
||||
uint64_t candidate_pair_id;
|
||||
uint64_t image_id_a;
|
||||
|
|
@ -469,6 +501,10 @@ Lardon3DProjectDbResult lardon3d_project_db_register_image(
|
|||
uint64_t size_bytes, const char *original_name, const char *source_path,
|
||||
uint64_t producer_task_id, int64_t imported_at, Lardon3DProjectDbImageRegisterStatus *status,
|
||||
Lardon3DProjectDbImage *image);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_register_image_asset(
|
||||
Lardon3DProjectDb *database,
|
||||
const unsigned char sha256[LARDON3D_PROJECT_DB_SHA256_SIZE], const char *asset_path,
|
||||
uint64_t size_bytes, int64_t created_at, Lardon3DProjectDbImageAsset *asset);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_image(Lardon3DProjectDb *database,
|
||||
uint64_t image_id,
|
||||
Lardon3DProjectDbImage *image,
|
||||
|
|
@ -481,6 +517,33 @@ Lardon3DProjectDbResult lardon3d_project_db_list_images(Lardon3DProjectDb *datab
|
|||
size_t capacity, size_t *count);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_count_images(Lardon3DProjectDb *database,
|
||||
uint64_t scanset_id, uint64_t *count);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_create_capture(
|
||||
Lardon3DProjectDb *database, uint64_t scanset_id, int64_t created_at,
|
||||
Lardon3DProjectDbCapture *capture);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_capture(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, Lardon3DProjectDbCapture *capture);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_list_captures(
|
||||
Lardon3DProjectDb *database, uint64_t scanset_id, uint64_t after_capture_id,
|
||||
Lardon3DProjectDbCapture *captures, size_t capacity, size_t *count);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_attach_capture_asset(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t asset_id,
|
||||
Lardon3DProjectDbCaptureAssetRole role);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_list_capture_assets(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t after_asset_id,
|
||||
Lardon3DProjectDbCaptureAsset *assets, size_t capacity, size_t *count);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_attach_capture_image(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t image_id);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_find_capture_for_image(
|
||||
Lardon3DProjectDb *database, uint64_t image_id, Lardon3DProjectDbCapture *capture);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_record_asset_derivation(
|
||||
Lardon3DProjectDb *database, const Lardon3DProjectDbAssetDerivation *derivation);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_asset_derivation(
|
||||
Lardon3DProjectDb *database, uint64_t child_asset_id,
|
||||
Lardon3DProjectDbAssetDerivation *derivation);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_set_selected_capture_image(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t image_id);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_get_selected_capture_image(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t *image_id);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_create_candidate_pair(
|
||||
Lardon3DProjectDb *database, uint64_t image_id_a, uint64_t image_id_b, int64_t created_at,
|
||||
Lardon3DProjectDbCandidatePair *pair);
|
||||
|
|
|
|||
506
src/project_db.c
506
src/project_db.c
|
|
@ -577,6 +577,36 @@ static const char schema_incremental_reconstruction_v18[] =
|
|||
"incremental_version INTEGER NOT NULL CHECK(incremental_version=1),"
|
||||
"parameter_fingerprint BLOB NOT NULL CHECK(length(parameter_fingerprint)=32));";
|
||||
|
||||
static const char schema_capture_provenance_v19[] =
|
||||
"CREATE TABLE captures("
|
||||
"capture_id INTEGER PRIMARY KEY AUTOINCREMENT CHECK(capture_id>0),"
|
||||
"scanset_id INTEGER NOT NULL REFERENCES scansets(scanset_id),"
|
||||
"created_at INTEGER NOT NULL CHECK(created_at>=0));"
|
||||
"CREATE INDEX captures_scanset_idx ON captures(scanset_id,capture_id);"
|
||||
"CREATE TABLE capture_images("
|
||||
"capture_id INTEGER NOT NULL REFERENCES captures(capture_id) ON DELETE CASCADE,"
|
||||
"image_id INTEGER NOT NULL UNIQUE REFERENCES images(image_id),"
|
||||
"PRIMARY KEY(capture_id,image_id));"
|
||||
"CREATE TABLE capture_assets("
|
||||
"capture_id INTEGER NOT NULL REFERENCES captures(capture_id) ON DELETE CASCADE,"
|
||||
"asset_id INTEGER NOT NULL REFERENCES image_assets(asset_id),"
|
||||
"role INTEGER NOT NULL CHECK(role IN(1,2)),"
|
||||
"PRIMARY KEY(capture_id,asset_id));"
|
||||
"CREATE INDEX capture_assets_page_idx ON capture_assets(capture_id,asset_id);"
|
||||
"CREATE TABLE capture_selections("
|
||||
"capture_id INTEGER PRIMARY KEY REFERENCES captures(capture_id) ON DELETE CASCADE,"
|
||||
"image_id INTEGER NOT NULL UNIQUE REFERENCES images(image_id),"
|
||||
"FOREIGN KEY(capture_id,image_id) REFERENCES capture_images(capture_id,image_id));"
|
||||
"CREATE TABLE asset_derivations("
|
||||
"child_asset_id INTEGER PRIMARY KEY REFERENCES image_assets(asset_id),"
|
||||
"parent_asset_id INTEGER NOT NULL REFERENCES image_assets(asset_id),"
|
||||
"derivation_kind INTEGER NOT NULL CHECK(derivation_kind=1),"
|
||||
"derivation_version INTEGER NOT NULL CHECK(derivation_version>0),"
|
||||
"parameter_fingerprint BLOB NOT NULL CHECK(length(parameter_fingerprint)=32),"
|
||||
"producer_task_id INTEGER REFERENCES tasks(task_id),"
|
||||
"created_at INTEGER NOT NULL CHECK(created_at>=0),"
|
||||
"CHECK(parent_asset_id!=child_asset_id));";
|
||||
|
||||
static void copy_error(char destination[LARDON3D_PROJECT_DB_ERROR_CAPACITY], const char *text) {
|
||||
if (destination) {
|
||||
(void)snprintf(destination, LARDON3D_PROJECT_DB_ERROR_CAPACITY, "%s", text ? text : "");
|
||||
|
|
@ -668,7 +698,7 @@ static Lardon3DProjectDbResult migrate(Lardon3DProjectDb *database, unsigned int
|
|||
from_version != 4 && from_version != 5 && from_version != 6 && from_version != 7 &&
|
||||
from_version != 8 && from_version != 9 && from_version != 10 && from_version != 11 &&
|
||||
from_version != 12 && from_version != 13 && from_version != 14 &&
|
||||
from_version != 15 && from_version != 16 && from_version != 17) {
|
||||
from_version != 15 && from_version != 16 && from_version != 17 && from_version != 18) {
|
||||
return LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
Lardon3DProjectDbResult result = execute(database, "BEGIN IMMEDIATE", "begin migration");
|
||||
|
|
@ -1033,6 +1063,36 @@ static Lardon3DProjectDbResult migrate(Lardon3DProjectDb *database, unsigned int
|
|||
"finish schema v18 migration");
|
||||
}
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK && from_version < 19) {
|
||||
result = execute(database, schema_capture_provenance_v19,
|
||||
"migrate image catalog capture provenance v18 to v19");
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = execute(
|
||||
database,
|
||||
"INSERT INTO captures(capture_id,scanset_id,created_at) "
|
||||
"SELECT image_id,scanset_id,imported_at FROM images ORDER BY image_id;"
|
||||
"INSERT INTO capture_images(capture_id,image_id) "
|
||||
"SELECT image_id,image_id FROM images ORDER BY image_id;"
|
||||
"INSERT INTO capture_assets(capture_id,asset_id,role) "
|
||||
"SELECT image_id,asset_id,1 FROM images ORDER BY image_id;"
|
||||
"INSERT INTO capture_selections(capture_id,image_id) "
|
||||
"SELECT image_id,image_id FROM images ORDER BY image_id;",
|
||||
"migrate legacy images to independent captures");
|
||||
}
|
||||
#ifdef LARDON3D_PROJECT_DB_TESTING
|
||||
if (result == LARDON3D_PROJECT_DB_OK &&
|
||||
getenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V19")) {
|
||||
result = execute(database, "INSERT INTO missing_v19_test_table VALUES(1)",
|
||||
"forced migration v19 failure");
|
||||
}
|
||||
#endif
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = execute(
|
||||
database,
|
||||
"UPDATE metadata SET value=19 WHERE key='schema_version' AND value=18",
|
||||
"finish schema v19 migration");
|
||||
}
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = execute(database, "COMMIT", "commit migration");
|
||||
}
|
||||
|
|
@ -1163,7 +1223,12 @@ Lardon3DProjectDbResult lardon3d_project_db_open(const char *path, Lardon3DProje
|
|||
"sparse_landmarks",
|
||||
"sparse_landmark_observations",
|
||||
"incremental_reconstructions",
|
||||
"incremental_reconstruction_tasks"};
|
||||
"incremental_reconstruction_tasks",
|
||||
"captures",
|
||||
"capture_images",
|
||||
"capture_assets",
|
||||
"capture_selections",
|
||||
"asset_derivations"};
|
||||
for (size_t index = 0; index < sizeof(required) / sizeof(required[0]) &&
|
||||
result == LARDON3D_PROJECT_DB_OK;
|
||||
++index) {
|
||||
|
|
@ -2445,6 +2510,77 @@ static const char image_select[] =
|
|||
"a.state,a.created_at,i.producer_task_id,i.imported_at FROM images i JOIN image_assets a ON "
|
||||
"a.asset_id=i.asset_id ";
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_register_image_asset(
|
||||
Lardon3DProjectDb *database,
|
||||
const unsigned char sha256[LARDON3D_PROJECT_DB_SHA256_SIZE], const char *asset_path,
|
||||
uint64_t size_bytes, int64_t created_at, Lardon3DProjectDbImageAsset *asset) {
|
||||
if (!database || !sha256 || !valid_relative_asset_path(asset_path) ||
|
||||
!canonical_asset_path(sha256, asset_path) || size_bytes > INT64_MAX || created_at < 0 ||
|
||||
!asset) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
memset(asset, 0, sizeof(*asset));
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
Lardon3DProjectDbResult result = execute(database, "BEGIN IMMEDIATE", "begin image asset register");
|
||||
sqlite3_stmt *statement = NULL;
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = prepare(database, "INSERT INTO image_assets(sha256,path,size_bytes,state,created_at) "
|
||||
"VALUES(?1,?2,?3,1,?4) ON CONFLICT(sha256) DO NOTHING",
|
||||
&statement);
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_blob(statement, 1, sha256, LARDON3D_PROJECT_DB_SHA256_SIZE,
|
||||
SQLITE_TRANSIENT);
|
||||
(void)sqlite3_bind_text(statement, 2, asset_path, -1, SQLITE_TRANSIENT);
|
||||
(void)sqlite3_bind_int64(statement, 3, (sqlite3_int64)size_bytes);
|
||||
(void)sqlite3_bind_int64(statement, 4, created_at);
|
||||
result = step_done(database, statement, "insert image asset");
|
||||
statement = NULL;
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = prepare(database, "SELECT asset_id,sha256,path,size_bytes,state,created_at FROM "
|
||||
"image_assets WHERE sha256=?1", &statement);
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_blob(statement, 1, sha256, LARDON3D_PROJECT_DB_SHA256_SIZE,
|
||||
SQLITE_TRANSIENT);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
} else if (code != SQLITE_ROW) {
|
||||
result = sqlite_result(database, code, "load registered image asset");
|
||||
} else {
|
||||
sqlite3_int64 id = sqlite3_column_int64(statement, 0);
|
||||
sqlite3_int64 stored_size = sqlite3_column_int64(statement, 3);
|
||||
sqlite3_int64 stored_created = sqlite3_column_int64(statement, 5);
|
||||
const void *stored_hash = sqlite3_column_blob(statement, 1);
|
||||
if (id <= 0 || stored_size < 0 || stored_created < 0 ||
|
||||
sqlite3_column_bytes(statement, 1) != LARDON3D_PROJECT_DB_SHA256_SIZE || !stored_hash ||
|
||||
!copy_column(statement, 2, asset->path, sizeof(asset->path)) ||
|
||||
strcmp(asset->path, asset_path) != 0 || stored_size != (sqlite3_int64)size_bytes ||
|
||||
sqlite3_column_int(statement, 4) != LARDON3D_DB_IMAGE_ASSET_READY) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
} else {
|
||||
asset->asset_id = (uint64_t)id;
|
||||
memcpy(asset->sha256, stored_hash, LARDON3D_PROJECT_DB_SHA256_SIZE);
|
||||
asset->size_bytes = (uint64_t)stored_size;
|
||||
asset->state = LARDON3D_DB_IMAGE_ASSET_READY;
|
||||
asset->created_at = stored_created;
|
||||
}
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
statement = NULL;
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = execute(database, "COMMIT", "commit image asset register");
|
||||
}
|
||||
if (result != LARDON3D_PROJECT_DB_OK) {
|
||||
(void)execute(database, "ROLLBACK", "rollback image asset register");
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_register_image(
|
||||
Lardon3DProjectDb *database, uint64_t scanset_id,
|
||||
const unsigned char sha256[LARDON3D_PROJECT_DB_SHA256_SIZE], const char *asset_path,
|
||||
|
|
@ -2670,6 +2806,372 @@ Lardon3DProjectDbResult lardon3d_project_db_count_images(Lardon3DProjectDb *data
|
|||
return result;
|
||||
}
|
||||
|
||||
static bool valid_capture_asset_role(Lardon3DProjectDbCaptureAssetRole role) {
|
||||
return role == LARDON3D_DB_CAPTURE_ASSET_SOURCE || role == LARDON3D_DB_CAPTURE_ASSET_DERIVED;
|
||||
}
|
||||
|
||||
static bool valid_asset_derivation_kind(Lardon3DProjectDbAssetDerivationKind kind) {
|
||||
return kind == LARDON3D_DB_ASSET_DERIVATION_GENERIC_VERSIONED;
|
||||
}
|
||||
|
||||
static bool read_capture(sqlite3_stmt *statement, Lardon3DProjectDbCapture *capture) {
|
||||
sqlite3_int64 capture_id = sqlite3_column_int64(statement, 0);
|
||||
sqlite3_int64 scanset_id = sqlite3_column_int64(statement, 1);
|
||||
sqlite3_int64 created_at = sqlite3_column_int64(statement, 2);
|
||||
if (capture_id <= 0 || scanset_id <= 0 || created_at < 0) {
|
||||
return false;
|
||||
}
|
||||
capture->capture_id = (uint64_t)capture_id;
|
||||
capture->scanset_id = (uint64_t)scanset_id;
|
||||
capture->created_at = created_at;
|
||||
return true;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_create_capture(
|
||||
Lardon3DProjectDb *database, uint64_t scanset_id, int64_t created_at,
|
||||
Lardon3DProjectDbCapture *capture) {
|
||||
if (!database || !valid_catalog_id(scanset_id) || created_at < 0 || !capture) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
memset(capture, 0, sizeof(*capture));
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "INSERT INTO captures(scanset_id,created_at) VALUES(?1,?2)", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)scanset_id);
|
||||
(void)sqlite3_bind_int64(statement, 2, created_at);
|
||||
result = step_done(database, statement, "create capture");
|
||||
}
|
||||
sqlite3_int64 capture_id = sqlite3_last_insert_rowid(database->connection);
|
||||
if (result == LARDON3D_PROJECT_DB_OK && capture_id <= 0) {
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
capture->capture_id = (uint64_t)capture_id;
|
||||
capture->scanset_id = scanset_id;
|
||||
capture->created_at = created_at;
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_capture(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, Lardon3DProjectDbCapture *capture) {
|
||||
if (!database || !valid_catalog_id(capture_id) || !capture) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
memset(capture, 0, sizeof(*capture));
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "SELECT capture_id,scanset_id,created_at FROM captures WHERE capture_id=?1",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE) {
|
||||
result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
} else if (code != SQLITE_ROW || !read_capture(statement, capture)) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_list_captures(
|
||||
Lardon3DProjectDb *database, uint64_t scanset_id, uint64_t after_capture_id,
|
||||
Lardon3DProjectDbCapture *captures, size_t capacity, size_t *count) {
|
||||
if (count) {
|
||||
*count = 0;
|
||||
}
|
||||
if (!database || !valid_catalog_id(scanset_id) || after_capture_id > INT64_MAX || !captures ||
|
||||
!count || capacity == 0 || capacity > LARDON3D_PROJECT_DB_CATALOG_PAGE_MAX) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "SELECT capture_id,scanset_id,created_at FROM captures WHERE scanset_id=?1 "
|
||||
"AND capture_id>?2 ORDER BY capture_id LIMIT ?3", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)scanset_id);
|
||||
(void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)after_capture_id);
|
||||
(void)sqlite3_bind_int64(statement, 3, (sqlite3_int64)capacity);
|
||||
int code = SQLITE_DONE;
|
||||
while (*count < capacity && (code = sqlite3_step(statement)) == SQLITE_ROW) {
|
||||
if (!read_capture(statement, &captures[*count])) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
break;
|
||||
}
|
||||
++*count;
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK && *count < capacity && code != SQLITE_DONE) {
|
||||
result = sqlite_result(database, code, "list captures");
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_attach_capture_asset(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t asset_id,
|
||||
Lardon3DProjectDbCaptureAssetRole role) {
|
||||
if (!database || !valid_catalog_id(capture_id) || !valid_catalog_id(asset_id) ||
|
||||
!valid_capture_asset_role(role)) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "INSERT INTO capture_assets(capture_id,asset_id,role) VALUES(?1,?2,?3)",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
(void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)asset_id);
|
||||
(void)sqlite3_bind_int(statement, 3, (int)role);
|
||||
result = step_done(database, statement, "attach capture asset");
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_list_capture_assets(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t after_asset_id,
|
||||
Lardon3DProjectDbCaptureAsset *assets, size_t capacity, size_t *count) {
|
||||
if (count) {
|
||||
*count = 0;
|
||||
}
|
||||
if (!database || !valid_catalog_id(capture_id) || after_asset_id > INT64_MAX || !assets ||
|
||||
!count || capacity == 0 || capacity > LARDON3D_PROJECT_DB_CATALOG_PAGE_MAX) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "SELECT capture_id,asset_id,role FROM capture_assets WHERE capture_id=?1 "
|
||||
"AND asset_id>?2 ORDER BY asset_id LIMIT ?3", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
(void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)after_asset_id);
|
||||
(void)sqlite3_bind_int64(statement, 3, (sqlite3_int64)capacity);
|
||||
int code = SQLITE_DONE;
|
||||
while (*count < capacity && (code = sqlite3_step(statement)) == SQLITE_ROW) {
|
||||
sqlite3_int64 stored_capture = sqlite3_column_int64(statement, 0);
|
||||
sqlite3_int64 stored_asset = sqlite3_column_int64(statement, 1);
|
||||
int stored_role = sqlite3_column_int(statement, 2);
|
||||
if (stored_capture <= 0 || stored_asset <= 0 ||
|
||||
!valid_capture_asset_role((Lardon3DProjectDbCaptureAssetRole)stored_role)) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
break;
|
||||
}
|
||||
assets[*count] = (Lardon3DProjectDbCaptureAsset){
|
||||
.capture_id = (uint64_t)stored_capture,
|
||||
.asset_id = (uint64_t)stored_asset,
|
||||
.role = (Lardon3DProjectDbCaptureAssetRole)stored_role};
|
||||
++*count;
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK && *count < capacity && code != SQLITE_DONE) {
|
||||
result = sqlite_result(database, code, "list capture assets");
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_attach_capture_image(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t image_id) {
|
||||
if (!database || !valid_catalog_id(capture_id) || !valid_catalog_id(image_id)) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "INSERT INTO capture_images(capture_id,image_id) "
|
||||
"SELECT ?1,?2 WHERE EXISTS(SELECT 1 FROM captures c JOIN images i "
|
||||
"ON i.scanset_id=c.scanset_id WHERE c.capture_id=?1 AND i.image_id=?2)",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
(void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)image_id);
|
||||
result = step_done(database, statement, "attach capture image");
|
||||
if (result == LARDON3D_PROJECT_DB_OK && sqlite3_changes(database->connection) != 1) {
|
||||
result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_find_capture_for_image(
|
||||
Lardon3DProjectDb *database, uint64_t image_id, Lardon3DProjectDbCapture *capture) {
|
||||
if (!database || !valid_catalog_id(image_id) || !capture) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
memset(capture, 0, sizeof(*capture));
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "SELECT c.capture_id,c.scanset_id,c.created_at FROM captures c JOIN "
|
||||
"capture_images ci ON ci.capture_id=c.capture_id WHERE ci.image_id=?1",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)image_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE) {
|
||||
result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
} else if (code != SQLITE_ROW || !read_capture(statement, capture)) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_record_asset_derivation(
|
||||
Lardon3DProjectDb *database, const Lardon3DProjectDbAssetDerivation *derivation) {
|
||||
if (!database || !derivation || !valid_catalog_id(derivation->parent_asset_id) ||
|
||||
!valid_catalog_id(derivation->child_asset_id) ||
|
||||
derivation->parent_asset_id == derivation->child_asset_id ||
|
||||
!valid_asset_derivation_kind(derivation->kind) || derivation->version == 0 ||
|
||||
derivation->created_at < 0 ||
|
||||
(derivation->has_producer_task && !valid_task_id(derivation->producer_task_id))) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "INSERT INTO asset_derivations(child_asset_id,parent_asset_id,derivation_kind,"
|
||||
"derivation_version,parameter_fingerprint,producer_task_id,created_at) "
|
||||
"VALUES(?1,?2,?3,?4,?5,?6,?7)", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)derivation->child_asset_id);
|
||||
(void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)derivation->parent_asset_id);
|
||||
(void)sqlite3_bind_int(statement, 3, (int)derivation->kind);
|
||||
(void)sqlite3_bind_int64(statement, 4, (sqlite3_int64)derivation->version);
|
||||
(void)sqlite3_bind_blob(statement, 5, derivation->parameter_fingerprint,
|
||||
LARDON3D_PROJECT_DB_SHA256_SIZE, SQLITE_TRANSIENT);
|
||||
if (derivation->has_producer_task) {
|
||||
(void)sqlite3_bind_int64(statement, 6, (sqlite3_int64)derivation->producer_task_id);
|
||||
} else {
|
||||
(void)sqlite3_bind_null(statement, 6);
|
||||
}
|
||||
(void)sqlite3_bind_int64(statement, 7, derivation->created_at);
|
||||
result = step_done(database, statement, "record asset derivation");
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_asset_derivation(
|
||||
Lardon3DProjectDb *database, uint64_t child_asset_id,
|
||||
Lardon3DProjectDbAssetDerivation *derivation) {
|
||||
if (!database || !valid_catalog_id(child_asset_id) || !derivation) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
memset(derivation, 0, sizeof(*derivation));
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "SELECT parent_asset_id,child_asset_id,derivation_kind,derivation_version,"
|
||||
"parameter_fingerprint,producer_task_id,created_at FROM asset_derivations "
|
||||
"WHERE child_asset_id=?1", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)child_asset_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE) {
|
||||
result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
} else if (code != SQLITE_ROW) {
|
||||
result = sqlite_result(database, code, "load asset derivation");
|
||||
} else {
|
||||
sqlite3_int64 parent = sqlite3_column_int64(statement, 0);
|
||||
sqlite3_int64 child = sqlite3_column_int64(statement, 1);
|
||||
sqlite3_int64 version = sqlite3_column_int64(statement, 3);
|
||||
sqlite3_int64 producer = sqlite3_column_int64(statement, 5);
|
||||
sqlite3_int64 created_at = sqlite3_column_int64(statement, 6);
|
||||
const void *fingerprint = sqlite3_column_blob(statement, 4);
|
||||
if (parent <= 0 || child <= 0 || parent == child || version <= 0 || version > UINT32_MAX ||
|
||||
created_at < 0 ||
|
||||
!valid_asset_derivation_kind((Lardon3DProjectDbAssetDerivationKind)
|
||||
sqlite3_column_int(statement, 2)) ||
|
||||
sqlite3_column_bytes(statement, 4) != LARDON3D_PROJECT_DB_SHA256_SIZE || !fingerprint ||
|
||||
(sqlite3_column_type(statement, 5) != SQLITE_NULL && producer <= 0)) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
} else {
|
||||
derivation->parent_asset_id = (uint64_t)parent;
|
||||
derivation->child_asset_id = (uint64_t)child;
|
||||
derivation->kind = (Lardon3DProjectDbAssetDerivationKind)sqlite3_column_int(statement, 2);
|
||||
derivation->version = (uint32_t)version;
|
||||
memcpy(derivation->parameter_fingerprint, fingerprint,
|
||||
LARDON3D_PROJECT_DB_SHA256_SIZE);
|
||||
derivation->has_producer_task = sqlite3_column_type(statement, 5) != SQLITE_NULL;
|
||||
derivation->producer_task_id = derivation->has_producer_task ? (uint64_t)producer : 0;
|
||||
derivation->created_at = created_at;
|
||||
}
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_set_selected_capture_image(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t image_id) {
|
||||
if (!database || !valid_catalog_id(capture_id) || !valid_catalog_id(image_id)) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "INSERT INTO capture_selections(capture_id,image_id) VALUES(?1,?2) "
|
||||
"ON CONFLICT(capture_id) DO UPDATE SET image_id=excluded.image_id", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
(void)sqlite3_bind_int64(statement, 2, (sqlite3_int64)image_id);
|
||||
result = step_done(database, statement, "set selected capture image");
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_get_selected_capture_image(
|
||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t *image_id) {
|
||||
if (image_id) {
|
||||
*image_id = 0;
|
||||
}
|
||||
if (!database || !valid_catalog_id(capture_id) || !image_id) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(
|
||||
database, "SELECT image_id FROM capture_selections WHERE capture_id=?1", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
(void)sqlite3_bind_int64(statement, 1, (sqlite3_int64)capture_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE) {
|
||||
result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
} else if (code != SQLITE_ROW) {
|
||||
result = sqlite_result(database, code, "get selected capture image");
|
||||
} else {
|
||||
sqlite3_int64 selected = sqlite3_column_int64(statement, 0);
|
||||
if (selected <= 0) {
|
||||
result = LARDON3D_PROJECT_DB_CORRUPT;
|
||||
} else {
|
||||
*image_id = (uint64_t)selected;
|
||||
}
|
||||
}
|
||||
(void)sqlite3_finalize(statement);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult
|
||||
lardon3d_project_db_create_artifact(Lardon3DProjectDb *database,
|
||||
const Lardon3DProjectDbArtifact *artifact) {
|
||||
|
|
|
|||
|
|
@ -172,6 +172,11 @@ static bool create_v11_database(const char *path) {
|
|||
lardon3d_project_db_close(database);
|
||||
return execute_sql(path,
|
||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE IF EXISTS asset_derivations;"
|
||||
"DROP TABLE IF EXISTS capture_selections;"
|
||||
"DROP TABLE IF EXISTS capture_assets;"
|
||||
"DROP TABLE IF EXISTS capture_images;"
|
||||
"DROP TABLE IF EXISTS captures;"
|
||||
"DROP TABLE IF EXISTS incremental_reconstruction_tasks;"
|
||||
"DROP TABLE IF EXISTS incremental_reconstructions;"
|
||||
"DROP TABLE IF EXISTS sparse_sfm_tasks;"
|
||||
|
|
@ -197,7 +202,7 @@ static bool test_model_api(const char *path) {
|
|||
Lardon3DProjectDb *database = NULL;
|
||||
CHECK(lardon3d_project_db_open(path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
Parents parents;
|
||||
CHECK(create_parents(database, &parents));
|
||||
|
||||
|
|
@ -481,7 +486,7 @@ static bool test_migration(const char *v11_path, const char *failed_path) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(v11_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
Parents parents;
|
||||
CHECK(create_parents(database, &parents));
|
||||
unsigned char fingerprint[32] = {0x91};
|
||||
|
|
@ -496,7 +501,7 @@ static bool test_migration(const char *v11_path, const char *failed_path) {
|
|||
migrated_result.geometric_verification_result_id;
|
||||
lardon3d_project_db_close(database);
|
||||
CHECK(query_integer(
|
||||
v11_path, "SELECT value FROM metadata WHERE key='schema_version'", 18));
|
||||
v11_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
CHECK(
|
||||
query_integer(v11_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='index' AND "
|
||||
|
|
@ -525,7 +530,7 @@ static bool test_migration(const char *v11_path, const char *failed_path) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -332,6 +332,11 @@ static bool run_task_test(void) {
|
|||
CHECK(exec_sql(
|
||||
database_path,
|
||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE IF EXISTS asset_derivations;"
|
||||
"DROP TABLE IF EXISTS capture_selections;"
|
||||
"DROP TABLE IF EXISTS capture_assets;"
|
||||
"DROP TABLE IF EXISTS capture_images;"
|
||||
"DROP TABLE IF EXISTS captures;"
|
||||
"DROP TABLE IF EXISTS incremental_reconstruction_tasks;"
|
||||
"DROP TABLE IF EXISTS incremental_reconstructions;"
|
||||
"DROP TABLE IF EXISTS sparse_sfm_tasks;"
|
||||
|
|
@ -364,7 +369,7 @@ static bool run_task_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
CHECK(remove_tree(root));
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@ static bool create_v9_database(const char *path) {
|
|||
return false;
|
||||
static const char sql[] =
|
||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE IF EXISTS asset_derivations;"
|
||||
"DROP TABLE IF EXISTS capture_selections;"
|
||||
"DROP TABLE IF EXISTS capture_assets;"
|
||||
"DROP TABLE IF EXISTS capture_images;"
|
||||
"DROP TABLE IF EXISTS captures;"
|
||||
"DROP TABLE IF EXISTS incremental_reconstruction_tasks;"
|
||||
"DROP TABLE IF EXISTS incremental_reconstructions;"
|
||||
"DROP TABLE IF EXISTS sparse_sfm_tasks;"
|
||||
|
|
@ -119,7 +124,7 @@ static bool run_test(void) {
|
|||
Lardon3DProjectDb *database = NULL;
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(database && lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(database && lardon3d_project_db_schema_version(database) == 19);
|
||||
|
||||
Lardon3DProjectDbScanSet scanset;
|
||||
CHECK(lardon3d_project_db_create_scanset(database, "Match-test", &scanset) ==
|
||||
|
|
@ -496,7 +501,7 @@ static bool run_test(void) {
|
|||
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
|
||||
/* Verify persistence: load previously created results */
|
||||
CHECK(lardon3d_project_db_load_match_result(database, first_id, &loaded) ==
|
||||
|
|
@ -539,11 +544,11 @@ static bool run_test(void) {
|
|||
v9_path, "SELECT value FROM metadata WHERE key='schema_version'", 9));
|
||||
CHECK(lardon3d_project_db_open(v9_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v9_path, "SELECT value FROM metadata WHERE key='schema_version'", 18));
|
||||
v9_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
CHECK(
|
||||
query_integer(v9_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||
|
|
@ -571,7 +576,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_v10_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 18);
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,11 @@ static bool downgrade_project_to_historical_v10(const char *database_path) {
|
|||
}
|
||||
static const char sql[] =
|
||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE IF EXISTS asset_derivations;"
|
||||
"DROP TABLE IF EXISTS capture_selections;"
|
||||
"DROP TABLE IF EXISTS capture_assets;"
|
||||
"DROP TABLE IF EXISTS capture_images;"
|
||||
"DROP TABLE IF EXISTS captures;"
|
||||
"DROP TABLE IF EXISTS incremental_reconstruction_tasks;"
|
||||
"DROP TABLE IF EXISTS incremental_reconstructions;"
|
||||
"DROP TABLE IF EXISTS sparse_sfm_tasks;"
|
||||
|
|
@ -368,7 +373,7 @@ static bool run_test(void) {
|
|||
"name='matcher_tasks'",
|
||||
0));
|
||||
CHECK(reopen_runtime(&fixture));
|
||||
CHECK(lardon3d_project_db_schema_version(fixture.state.project_db) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(fixture.state.project_db) == 19);
|
||||
CHECK(
|
||||
query_integer(database_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ static bool create_future_database(const char *path) {
|
|||
sqlite3_exec(
|
||||
connection,
|
||||
"CREATE TABLE metadata(key TEXT PRIMARY KEY,value INTEGER NOT NULL);"
|
||||
"INSERT INTO metadata VALUES('schema_version',19);",
|
||||
"INSERT INTO metadata VALUES('schema_version',20);",
|
||||
NULL, NULL, NULL) == SQLITE_OK;
|
||||
return sqlite3_close(connection) == SQLITE_OK && ok;
|
||||
}
|
||||
|
|
@ -133,6 +133,8 @@ static bool create_v7_database(const char *path) {
|
|||
return false;
|
||||
static const char sql[] =
|
||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"DROP TABLE incremental_reconstruction_tasks;"
|
||||
"DROP TABLE incremental_reconstructions;"
|
||||
"DROP TABLE sparse_sfm_tasks;"
|
||||
|
|
@ -172,6 +174,8 @@ static bool create_v6_database(const char *path) {
|
|||
return false;
|
||||
static const char sql[] =
|
||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"DROP TABLE incremental_reconstruction_tasks;"
|
||||
"DROP TABLE incremental_reconstructions;"
|
||||
"DROP TABLE sparse_sfm_tasks;"
|
||||
|
|
@ -219,6 +223,8 @@ static bool create_v10_database(const char *path) {
|
|||
}
|
||||
static const char sql[] =
|
||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"DROP TABLE incremental_reconstruction_tasks;"
|
||||
"DROP TABLE incremental_reconstructions;"
|
||||
"DROP TABLE sparse_sfm_tasks;"
|
||||
|
|
@ -255,6 +261,8 @@ static bool create_v13_database(const char *path) {
|
|||
return false;
|
||||
static const char sql[] =
|
||||
"PRAGMA foreign_keys=OFF;BEGIN IMMEDIATE;"
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"DROP TABLE incremental_reconstruction_tasks;"
|
||||
"DROP TABLE incremental_reconstructions;"
|
||||
"DROP TABLE sparse_sfm_tasks;"
|
||||
|
|
@ -879,7 +887,7 @@ static bool run_test(void) {
|
|||
char v10_path[512], failed_v11_path[512];
|
||||
char v13_path[512], true_v14_path[512], failed_v14_path[512],
|
||||
failed_v15_path[512], true_v15_path[512], v17_path[512],
|
||||
failed_v18_path[512];
|
||||
failed_v18_path[512], failed_v19_path[512];
|
||||
CHECK(snprintf(database_path, sizeof(database_path), "%s/project.db",
|
||||
directory) > 0);
|
||||
CHECK(snprintf(artifact_path, sizeof(artifact_path), "%s/artifact.bin",
|
||||
|
|
@ -925,12 +933,14 @@ static bool run_test(void) {
|
|||
CHECK(snprintf(v17_path, sizeof(v17_path), "%s/v17.db", directory) > 0);
|
||||
CHECK(snprintf(failed_v18_path, sizeof(failed_v18_path),
|
||||
"%s/failed-v18.db", directory) > 0);
|
||||
CHECK(snprintf(failed_v19_path, sizeof(failed_v19_path),
|
||||
"%s/failed-v19.db", directory) > 0);
|
||||
|
||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY];
|
||||
Lardon3DProjectDb *database = NULL;
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(database && lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(database && lardon3d_project_db_schema_version(database) == 19);
|
||||
bool legacy_pending = true;
|
||||
CHECK(lardon3d_project_db_legacy_catalog_pending(database, &legacy_pending) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
|
|
@ -1054,6 +1064,106 @@ static bool run_test(void) {
|
|||
LARDON3D_PROJECT_DB_CANDIDATE_PAIR_PAGE_MAX + 1,
|
||||
&pair_count) == LARDON3D_PROJECT_DB_INVALID_ARGUMENT);
|
||||
|
||||
/* S1: Capture is a catalog policy layer; image_id and asset_id stay immutable. */
|
||||
Lardon3DProjectDbCapture capture, other_capture, mapped_capture;
|
||||
CHECK(lardon3d_project_db_create_capture(database, replacement_scanset.scanset_id, 20,
|
||||
&capture) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_create_capture(database, replacement_scanset.scanset_id, 21,
|
||||
&other_capture) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_create_capture(database, UINT64_C(999999), 22, &mapped_capture) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
Lardon3DProjectDbCapture capture_page[2];
|
||||
size_t capture_count = 0;
|
||||
CHECK(lardon3d_project_db_list_captures(database, replacement_scanset.scanset_id, 0,
|
||||
capture_page, 1, &capture_count) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
capture_count == 1 && capture_page[0].capture_id == capture.capture_id);
|
||||
uint64_t selected_image = 0;
|
||||
CHECK(lardon3d_project_db_get_selected_capture_image(database, capture.capture_id,
|
||||
&selected_image) ==
|
||||
LARDON3D_PROJECT_DB_NOT_FOUND);
|
||||
unsigned char raw_hash[LARDON3D_PROJECT_DB_SHA256_SIZE] = {5};
|
||||
char raw_asset_path[LARDON3D_PROJECT_DB_PATH_CAPACITY];
|
||||
asset_path_for_hash(raw_hash, raw_asset_path);
|
||||
Lardon3DProjectDbImageAsset raw_asset;
|
||||
CHECK(lardon3d_project_db_register_image_asset(database, raw_hash, raw_asset_path, 2, 22,
|
||||
&raw_asset) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_attach_capture_asset(
|
||||
database, capture.capture_id, raw_asset.asset_id,
|
||||
LARDON3D_DB_CAPTURE_ASSET_SOURCE) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_attach_capture_asset(
|
||||
database, capture.capture_id, pair_image.asset_id,
|
||||
LARDON3D_DB_CAPTURE_ASSET_SOURCE) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_attach_capture_asset(
|
||||
database, capture.capture_id, raw_asset.asset_id,
|
||||
(Lardon3DProjectDbCaptureAssetRole)99) == LARDON3D_PROJECT_DB_INVALID_ARGUMENT);
|
||||
CHECK(lardon3d_project_db_attach_capture_asset(
|
||||
database, capture.capture_id, raw_asset.asset_id,
|
||||
LARDON3D_DB_CAPTURE_ASSET_SOURCE) == LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
unsigned char developed_hash[LARDON3D_PROJECT_DB_SHA256_SIZE] = {6};
|
||||
char developed_asset_path[LARDON3D_PROJECT_DB_PATH_CAPACITY];
|
||||
asset_path_for_hash(developed_hash, developed_asset_path);
|
||||
Lardon3DProjectDbImage developed_image;
|
||||
CHECK(lardon3d_project_db_register_image(
|
||||
database, replacement_scanset.scanset_id, developed_hash, developed_asset_path, 3,
|
||||
"developed.png", "/source/developed.png", 0, 23, &identity_status,
|
||||
&developed_image) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_attach_capture_asset(
|
||||
database, capture.capture_id, developed_image.asset_id,
|
||||
LARDON3D_DB_CAPTURE_ASSET_DERIVED) == LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DProjectDbCaptureAsset capture_assets[3];
|
||||
size_t capture_asset_count = 0;
|
||||
CHECK(lardon3d_project_db_list_capture_assets(database, capture.capture_id, 0, capture_assets,
|
||||
3, &capture_asset_count) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
capture_asset_count == 3);
|
||||
CHECK(lardon3d_project_db_attach_capture_image(database, capture.capture_id,
|
||||
pair_image.image_id) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_attach_capture_image(database, other_capture.capture_id,
|
||||
pair_image.image_id) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
CHECK(lardon3d_project_db_attach_capture_image(database, capture.capture_id,
|
||||
developed_image.image_id) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_find_capture_for_image(database, pair_image.image_id,
|
||||
&mapped_capture) == LARDON3D_PROJECT_DB_OK &&
|
||||
mapped_capture.capture_id == capture.capture_id);
|
||||
CHECK(lardon3d_project_db_set_selected_capture_image(database, capture.capture_id,
|
||||
pair_image.image_id) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_set_selected_capture_image(database, other_capture.capture_id,
|
||||
developed_image.image_id) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
CHECK(lardon3d_project_db_set_selected_capture_image(database, capture.capture_id,
|
||||
developed_image.image_id) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_get_selected_capture_image(database, capture.capture_id,
|
||||
&selected_image) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
selected_image == developed_image.image_id && pair_image.image_id != developed_image.image_id);
|
||||
Lardon3DProjectDbAssetDerivation derivation = {
|
||||
.parent_asset_id = raw_asset.asset_id,
|
||||
.child_asset_id = developed_image.asset_id,
|
||||
.kind = LARDON3D_DB_ASSET_DERIVATION_GENERIC_VERSIONED,
|
||||
.version = 1,
|
||||
.created_at = 24};
|
||||
memset(derivation.parameter_fingerprint, 0xA5, sizeof(derivation.parameter_fingerprint));
|
||||
CHECK(lardon3d_project_db_record_asset_derivation(database, &derivation) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DProjectDbAssetDerivation loaded_derivation;
|
||||
CHECK(lardon3d_project_db_load_asset_derivation(database, developed_image.asset_id,
|
||||
&loaded_derivation) == LARDON3D_PROJECT_DB_OK &&
|
||||
loaded_derivation.parent_asset_id == raw_asset.asset_id &&
|
||||
loaded_derivation.version == 1 &&
|
||||
memcmp(loaded_derivation.parameter_fingerprint, derivation.parameter_fingerprint,
|
||||
sizeof(derivation.parameter_fingerprint)) == 0);
|
||||
derivation.parent_asset_id = pair_image.asset_id;
|
||||
CHECK(lardon3d_project_db_record_asset_derivation(database, &derivation) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
derivation.parent_asset_id = developed_image.asset_id;
|
||||
CHECK(lardon3d_project_db_record_asset_derivation(database, &derivation) ==
|
||||
LARDON3D_PROJECT_DB_INVALID_ARGUMENT);
|
||||
|
||||
Lardon3DProjectDbProject project = {.created_at = 100, .updated_at = 100};
|
||||
(void)snprintf(project.stable_id, sizeof(project.stable_id), "project-0001");
|
||||
(void)snprintf(project.name, sizeof(project.name), "Projet test");
|
||||
|
|
@ -1248,7 +1358,7 @@ static bool run_test(void) {
|
|||
database = NULL;
|
||||
CHECK(query_integer(database_path,
|
||||
"SELECT value FROM metadata WHERE key='schema_version'",
|
||||
18));
|
||||
19));
|
||||
CHECK(query_integer(database_path,
|
||||
"SELECT count(*) FROM tasks WHERE task_id=1", 1));
|
||||
|
||||
|
|
@ -1270,10 +1380,12 @@ static bool run_test(void) {
|
|||
"created_at) VALUES(1,1,1,1,1,zeroblob(32),1,2,1,0,0,1);"
|
||||
"DROP TABLE incremental_reconstruction_tasks;"
|
||||
"DROP TABLE incremental_reconstructions;"
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"UPDATE metadata SET value=17 WHERE key='schema_version';"));
|
||||
CHECK(lardon3d_project_db_open(v17_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(v17_path,
|
||||
|
|
@ -1290,10 +1402,36 @@ static bool run_test(void) {
|
|||
LARDON3D_PROJECT_DB_OK);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
CHECK(lardon3d_project_db_open(failed_v19_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(execute_test_sql(
|
||||
failed_v19_path,
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"UPDATE metadata SET value=18 WHERE key='schema_version';"));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V19", "1", 1) == 0);
|
||||
CHECK(lardon3d_project_db_open(failed_v19_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_IO_ERROR);
|
||||
CHECK(unsetenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V19") == 0);
|
||||
CHECK(query_integer(failed_v19_path,
|
||||
"SELECT value FROM metadata WHERE key='schema_version'", 18));
|
||||
CHECK(query_integer(failed_v19_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||
"name='captures'", 0));
|
||||
CHECK(lardon3d_project_db_open(failed_v19_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(execute_test_sql(
|
||||
failed_v18_path,
|
||||
"DROP TABLE incremental_reconstruction_tasks;"
|
||||
"DROP TABLE incremental_reconstructions;"
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"UPDATE metadata SET value=17 WHERE key='schema_version';"));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V18", "1", 1) == 0);
|
||||
CHECK(lardon3d_project_db_open(failed_v18_path, &database, error) ==
|
||||
|
|
@ -1336,7 +1474,7 @@ static bool run_test(void) {
|
|||
CHECK(create_v1_database(legacy_path));
|
||||
CHECK(lardon3d_project_db_open(legacy_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_get_project(database, &loaded_project) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
strcmp(loaded_project.stable_id, "legacy-project") == 0);
|
||||
|
|
@ -1351,7 +1489,7 @@ static bool run_test(void) {
|
|||
database = NULL;
|
||||
CHECK(query_integer(legacy_path,
|
||||
"SELECT value FROM metadata WHERE key='schema_version'",
|
||||
18));
|
||||
19));
|
||||
|
||||
CHECK(create_v1_database(failed_migration_path));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V2", "1", 1) == 0);
|
||||
|
|
@ -1382,7 +1520,7 @@ static bool run_test(void) {
|
|||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v2_path, "SELECT value FROM metadata WHERE key='schema_version'", 18));
|
||||
v2_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
|
||||
CHECK(create_v2_database(failed_v3_migration_path));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V3", "1", 1) == 0);
|
||||
|
|
@ -1416,7 +1554,7 @@ static bool run_test(void) {
|
|||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v3_path, "SELECT value FROM metadata WHERE key='schema_version'", 18));
|
||||
v3_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
|
||||
CHECK(create_v3_database(failed_v4_path));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V4", "1", 1) == 0);
|
||||
|
|
@ -1438,7 +1576,7 @@ static bool run_test(void) {
|
|||
fprintf(stderr, "Migration v4 (%d): %s\n", (int)v4_result, error);
|
||||
}
|
||||
CHECK(v4_result == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_load_task(database, 9, &task) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_load_artifact(database, "legacy-artifact",
|
||||
|
|
@ -1493,7 +1631,7 @@ static bool run_test(void) {
|
|||
error);
|
||||
}
|
||||
CHECK(retry_v7 == LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 18);
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1503,7 +1641,7 @@ static bool run_test(void) {
|
|||
5));
|
||||
CHECK(lardon3d_project_db_open(direct_v5_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 18);
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1512,11 +1650,11 @@ static bool run_test(void) {
|
|||
v8_path, "SELECT value FROM metadata WHERE key='schema_version'", 7));
|
||||
CHECK(lardon3d_project_db_open(v8_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v8_path, "SELECT value FROM metadata WHERE key='schema_version'", 18));
|
||||
v8_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
|
||||
CHECK(create_v7_database(failed_v8_path));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V8", "1", 1) == 0);
|
||||
|
|
@ -1533,7 +1671,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_v8_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 18);
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1552,11 +1690,11 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(v10_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 18);
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v10_path, "SELECT value FROM metadata WHERE key='schema_version'", 18));
|
||||
v10_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
CHECK(
|
||||
query_integer(v10_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||
|
|
@ -1583,7 +1721,7 @@ static bool run_test(void) {
|
|||
1));
|
||||
CHECK(lardon3d_project_db_open(failed_v11_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1597,11 +1735,11 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(v13_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 18);
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v13_path, "SELECT value FROM metadata WHERE key='schema_version'", 18));
|
||||
v13_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
CHECK(
|
||||
query_integer(v13_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||
|
|
@ -1624,7 +1762,7 @@ static bool run_test(void) {
|
|||
true_v14_path);
|
||||
}
|
||||
CHECK(true_v14_result == LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 18);
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(
|
||||
|
|
@ -1739,7 +1877,7 @@ static bool run_test(void) {
|
|||
if (true_v15_result != LARDON3D_PROJECT_DB_OK)
|
||||
fprintf(stderr, "true v15 upgrade: %d %s\n", true_v15_result, error);
|
||||
CHECK(true_v15_result == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
Lardon3DProjectDbProject migrated_project;
|
||||
CHECK(lardon3d_project_db_get_project(database, &migrated_project) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
|
|
@ -1757,6 +1895,20 @@ static bool run_test(void) {
|
|||
".lardon3d/checkpoints/legacy.scope") == 0);
|
||||
CHECK(query_integer(true_v15_path, "SELECT count(*) FROM scansets", 1));
|
||||
CHECK(query_integer(true_v15_path, "SELECT count(*) FROM images", 2));
|
||||
CHECK(query_integer(true_v15_path, "SELECT count(*) FROM captures", 2));
|
||||
CHECK(query_integer(true_v15_path, "SELECT count(*) FROM capture_images", 2));
|
||||
CHECK(query_integer(true_v15_path, "SELECT count(*) FROM capture_assets WHERE role=1", 2));
|
||||
CHECK(query_integer(true_v15_path, "SELECT count(*) FROM capture_selections", 2));
|
||||
CHECK(query_integer(
|
||||
true_v15_path,
|
||||
"SELECT count(*) FROM captures c JOIN capture_images ci ON ci.capture_id=c.capture_id "
|
||||
"JOIN images i ON i.image_id=ci.image_id WHERE c.scanset_id=i.scanset_id "
|
||||
"AND c.capture_id=i.image_id",
|
||||
2));
|
||||
Lardon3DProjectDbCapture post_migration_capture;
|
||||
CHECK(lardon3d_project_db_create_capture(database, 1, 2, &post_migration_capture) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(post_migration_capture.capture_id > 2);
|
||||
CHECK(query_integer(true_v15_path, "SELECT count(*) FROM feature_sets", 2));
|
||||
CHECK(query_integer(true_v15_path, "SELECT count(*) FROM track_sets", 1));
|
||||
CHECK(query_integer(true_v15_path, "SELECT count(*) FROM tracks", 1));
|
||||
|
|
@ -1771,7 +1923,7 @@ static bool run_test(void) {
|
|||
database = NULL;
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(schema_compare(database_path, true_v15_path, true));
|
||||
|
|
@ -1806,7 +1958,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(true_v15_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1825,7 +1977,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_v14_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 18);
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1844,7 +1996,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_v15_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 18);
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -2315,6 +2467,7 @@ static bool run_test(void) {
|
|||
CHECK(unlink(failed_v15_path) == 0);
|
||||
CHECK(unlink(v17_path) == 0);
|
||||
CHECK(unlink(failed_v18_path) == 0);
|
||||
CHECK(unlink(failed_v19_path) == 0);
|
||||
CHECK(rmdir(directory) == 0);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ static bool run_test(void) {
|
|||
Lardon3DProjectDb *db = NULL;
|
||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY];
|
||||
CHECK(lardon3d_project_db_open(path, &db, error) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(db) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(db) == 19);
|
||||
|
||||
Lardon3DProjectDbScanSet scanset;
|
||||
CHECK(lardon3d_project_db_create_scanset(db, "Sparse model", &scanset) ==
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ int main() {
|
|||
Lardon3DProjectDb *database = nullptr;
|
||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY]{};
|
||||
CHECK(lardon3d_project_db_open(path.c_str(), &database, error) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 18);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
|
||||
sqlite3 *raw = nullptr;
|
||||
CHECK(sqlite3_open(path.c_str(), &raw) == SQLITE_OK);
|
||||
|
|
|
|||
Loading…
Reference in a new issue