From ff218def1bad28622c1ae814818eb53f98171da4 Mon Sep 17 00:00:00 2001 From: avsdev-cw Date: Thu, 15 Oct 2020 12:11:51 +0100 Subject: [PATCH] Metadata Extended handling implemented --- src/modb_metadata.c | 5 +- src/modb_metadata.h | 2 +- src/modb_metadata_ext.c | 536 ++++++++++++++++++++++++++++++++++++++-- src/modb_metadata_ext.h | 83 ++++--- 4 files changed, 572 insertions(+), 54 deletions(-) diff --git a/src/modb_metadata.c b/src/modb_metadata.c index 734ad67..5d0df78 100644 --- a/src/modb_metadata.c +++ b/src/modb_metadata.c @@ -178,7 +178,7 @@ void freeMetadata(struct metadata_t **metadata_ptr) struct metadata_t *metadata = *metadata_ptr; if (metadata->ext != 0) { - freeMetadataExt(&metadata->ext); + freeMetaExt(&metadata->ext); } if (metadata->object != 0) { @@ -521,8 +521,7 @@ int64_t modbFetchMetadataObject(stored_conn *sconn, modb_ref *modb, struct metad // MODB Metadata -> MetadataExtended int64_t modbFetchMetadataExtended(stored_conn *sconn, modb_ref *modb, struct metadata_t *metadata) { - // TODO: implement - return -1; + return modbMetaExtById(sconn, modb, metadata->id, &metadata->ext); } // MODB Metadata -> Groups diff --git a/src/modb_metadata.h b/src/modb_metadata.h index 3440a67..7299752 100644 --- a/src/modb_metadata.h +++ b/src/modb_metadata.h @@ -27,7 +27,7 @@ struct metadata_t { size_t n_groups; struct object_t *object; - struct metadata_ext_t *ext; + struct meta_ext_t *ext; }; struct metadata_t *allocMetadata(void); diff --git a/src/modb_metadata_ext.c b/src/modb_metadata_ext.c index e79c738..00676de 100644 --- a/src/modb_metadata_ext.c +++ b/src/modb_metadata_ext.c @@ -3,52 +3,548 @@ #include #include +#include "database.h" #include "modb_metadata_ext.h" +#include "modb_p.h" -struct metadata_ext_t *allocMetadataExt(void) +// ##### PRIVATE +int tableRowsToMetaExtList(column_data **col_data, size_t n_cols, + struct meta_ext_t ***ext_list, size_t *n_exts) { - struct metadata_ext_t *metadata_ext; + column_data *col_id, *col; + size_t n_rows, r_idx, c_idx, v_idx; + struct meta_ext_t *ext; + struct meta_ext_value_t *ext_value; + size_t key_len; - metadata_ext = malloc(sizeof(struct metadata_ext_t)); + n_rows = (*col_data)->n_values; + if (n_rows == 0) { + return 0; + } + + col_id = findColumnByName(col_data, n_cols, "mdo_id"); + + if ((*ext_list = allocMetaExtList(n_rows)) == 0) { + fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno)); + return -errno; + } + + for (r_idx = 0; r_idx < n_rows; r_idx++) { + if ((ext = allocMetaExt()) == 0) { + freeMetaExtList(ext_list, r_idx - 1); + return -1; + } + *((*ext_list) + r_idx) = ext; + + ext->id = *(col_id->data.ptr_uint32 + r_idx); + + if (n_cols > 0) { + if ((ext->values = allocMetaExtValues(n_cols - 1, 1)) == 0) { + freeMetaExtList(ext_list, r_idx); + return -1; + } + ext->n_values = n_cols - 1; + } + + for (c_idx = 0, v_idx = 0; c_idx < n_cols; c_idx++, v_idx++) { + col = *(col_data + c_idx); + if (col == col_id) { + v_idx--; + continue; + } + ext_value = *(ext->values + v_idx); + + if (strmemcpy(col->name, col->name_len, &ext_value->key, &key_len) != 0) { + freeMetaExtList(ext_list, r_idx); + return -1; + } + ext_value->key_c = ext_value->key; + + switch(col->type) { + case TYPE_RAW: + ext_value->type = VTYPE_RAW; + if (!moveColumnBlobPointer(col, r_idx, 1, (char **)&ext_value->value.raw, &ext_value->value_len)) { + freeMetaExtList(ext_list, r_idx); + return -1; + } + break; + case TYPE_BOOL: + ext_value->type = VTYPE_BOOL; + ext_value->value.int32 = *(col->data.ptr_uint8 + r_idx); + break; + case TYPE_INT8: + ext_value->type = VTYPE_INT32; + ext_value->value.int32 = *(col->data.ptr_int8 + r_idx); + break; + case TYPE_UINT8: + ext_value->type = VTYPE_INT32; + ext_value->value.int32 = *(col->data.ptr_uint8 + r_idx); + break; + case TYPE_INT16: + ext_value->type = VTYPE_INT32; + ext_value->value.int32 = *(col->data.ptr_int16 + r_idx); + break; + case TYPE_UINT16: + ext_value->type = VTYPE_INT32; + ext_value->value.int32 = *(col->data.ptr_uint16 + r_idx); + break; + case TYPE_INT32: + ext_value->type = VTYPE_INT32; + ext_value->value.int32 = *(col->data.ptr_int32 + r_idx); + break; + case TYPE_UINT32: + ext_value->type = VTYPE_INT32; + ext_value->value.dbl = (double)*(col->data.ptr_uint32 + r_idx); + break; + case TYPE_INT64: + ext_value->type = VTYPE_INT32; + ext_value->value.dbl = (double)*(col->data.ptr_int64 + r_idx); + break; + case TYPE_UINT64: + ext_value->type = VTYPE_INT32; + ext_value->value.dbl = (double)*(col->data.ptr_uint64 + r_idx); + break; + case TYPE_FLOAT: + ext_value->type = VTYPE_INT32; + ext_value->value.dbl = (double)*(col->data.ptr_float + r_idx); + break; + case TYPE_DOUBLE: + ext_value->type = VTYPE_DOUBLE; + ext_value->value.dbl = *(col->data.ptr_double + r_idx); + break; + case TYPE_STRING: + ext_value->type = VTYPE_STRING; + if (!moveColumnStrPointer(col, r_idx, 1, &ext_value->value.str, &ext_value->value_len)) { + freeMetaExtList(ext_list, r_idx); + return -1; + } + break; + case TYPE_BLOB: + ext_value->type = VTYPE_RAW; + if (!moveColumnBlobPointer(col, r_idx, 1, (char **)&ext_value->value.raw, &ext_value->value_len)) { + freeMetaExtList(ext_list, r_idx); + return -1; + } + break; + case TYPE_TIMESTAMP: + ext_value->type = VTYPE_TIMESTAMP; + ext_value->value.ts = *(col->data.ptr_int64 + r_idx); + break; + case TYPE_ID: + ext_value->type = VTYPE_ID; + ext_value->value.id = *(col->data.ptr_uint32 + r_idx); + break; + } + } + } + + *n_exts = n_rows; + + return 1; +} +int doMetaExtListQuery(stored_conn *sconn, modb_ref *modb, where_builder *wb, + struct meta_ext_t ***ext_list, size_t *n_exts) +{ + char *tbl_meta, *tbl_ext; + size_t len_meta, len_ext; + char *qry; + size_t qry_len; + uint64_t qry_ret; + int res; + + str_builder *sb; + + column_data **col_data; + size_t n_cols; + + + if ((sb = strbld_create()) == 0) { + return -1; + } + modbTableName(&tbl_ext, &len_ext, modb, META_EXT_TABLE, strlen(META_EXT_TABLE)); + modbTableName(&tbl_meta, &len_meta, modb, METADATA_TABLE, strlen(METADATA_TABLE)); + + strbld_str(sb, "SELECT ", 0); + escapeColumnName_sb(sb, tbl_ext, len_ext, "*", 0); + strbld_str(sb, " FROM ", 0); + escapeTableName_sb(sb, tbl_ext, len_ext); + joinStr_sb(sb, " LEFT", 5, 1, tbl_meta, len_meta, "mdo_id", 6, tbl_ext, len_ext, "mdo_id", 6); + if (wb != 0) { + compileWhereBuilder_sb(sb, wb, 0); + } + strbld_str(sb, " ORDER BY ", 0); + escapeColumnName_sb(sb, tbl_meta, len_meta, "updated", 0); + strbld_str(sb, " DESC, ", 0); + escapeColumnName_sb(sb, tbl_meta, len_meta, "updated", 0); + strbld_str(sb, " DESC", 0); + + modbFreeTableName(&tbl_meta); + modbFreeTableName(&tbl_ext); + if (strbld_finalize_or_destroy(&sb, &qry, &qry_len) != 0) { + return -1; + } + + qry_ret = tableQuery(sconn, qry, qry_len, 0, &col_data, &n_cols); + free(qry); + + // Query failed + if (qry_ret == (uint64_t)-1) { + return -1; + } + + // Zero row result + if (qry_ret == 0) { + freeColumns(col_data, n_cols); + *ext_list = 0; + *n_exts = 0; + return 0; + } + + res = tableRowsToMetaExtList(col_data, n_cols, ext_list, n_exts); + freeColumns(col_data, n_cols); + + if (res <= 0) { + return res; + } + + return (int)qry_ret; +} +int doScalarMetaExtListQuery(stored_conn *sconn, modb_ref *modb, + where_builder *wb, struct meta_ext_t **meta_ext) +{ + int res; + struct meta_ext_t **meta_ext_list; + size_t n_exts; + + res = doMetaExtListQuery(sconn, modb, wb, &meta_ext_list, &n_exts); + if (res <= 0) { + return res; + } + + *meta_ext = *(meta_ext_list + 0); + *(meta_ext_list + 0) = 0; + freeMetaExtList(&meta_ext_list, n_exts); + + return res; +} + + +// ##### PUBLIC +struct meta_ext_t *allocMetaExt(void) +{ + struct meta_ext_t *metadata_ext; + + metadata_ext = malloc(sizeof(struct meta_ext_t)); if (metadata_ext == 0) { fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno)); } - memset(metadata_ext, 0, sizeof(struct metadata_ext_t)); + memset(metadata_ext, 0, sizeof(struct meta_ext_t)); return metadata_ext; } -struct metadata_ext_t **allocMetadataExts(size_t n_metadata_exts) +void freeMetaExt(struct meta_ext_t **metadata_ext_ptr) { - struct metadata_ext_t **metadata_exts; + struct meta_ext_t *metadata_ext = *metadata_ext_ptr; - metadata_exts = (struct metadata_ext_t **)malloc(sizeof(struct metadata_ext_t *) * n_metadata_exts); - if (metadata_exts == 0) { - fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno)); - return 0; + if (metadata_ext->values != 0) { + freeMetaExtValues(&metadata_ext->values, metadata_ext->n_values); } - memset(metadata_exts, 0, sizeof(struct metadata_ext_t *) * n_metadata_exts); - - return metadata_exts; -} -void freeMetadataExt(struct metadata_ext_t **metadata_ext_ptr) -{ - struct metadata_ext_t *metadata_ext = *metadata_ext_ptr; free(metadata_ext); *metadata_ext_ptr = 0; } -void freeMetadataExts(struct metadata_ext_t ***metadata_exts_ptr, size_t n_metadata_exts) +struct meta_ext_t **allocMetaExtList(size_t n_metadata_exts) +{ + struct meta_ext_t **metadata_exts; + + metadata_exts = (struct meta_ext_t **)malloc(sizeof(struct meta_ext_t *) * n_metadata_exts); + if (metadata_exts == 0) { + fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno)); + return 0; + } + memset(metadata_exts, 0, sizeof(struct meta_ext_t *) * n_metadata_exts); + + return metadata_exts; +} +void freeMetaExtList(struct meta_ext_t ***metadata_exts_ptr, size_t n_metadata_exts) { size_t idx; - struct metadata_ext_t **metadata_exts = *metadata_exts_ptr; + struct meta_ext_t **metadata_exts = *metadata_exts_ptr; for (idx = 0; idx < n_metadata_exts; idx++) { if (*(metadata_exts + idx) != 0) { - freeMetadataExt(metadata_exts + idx); + freeMetaExt(metadata_exts + idx); } } free(metadata_exts); *metadata_exts_ptr = 0; } + +struct meta_ext_value_t *allocMetaExtValue(void) +{ + struct meta_ext_value_t *ext_value; + + ext_value = malloc(sizeof(struct meta_ext_value_t)); + if (ext_value == 0) { + fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno)); + } + memset(ext_value, 0, sizeof(struct meta_ext_value_t)); + + return ext_value; +} +void freeMetaExtValue(struct meta_ext_value_t **ext_value_ptr) +{ + struct meta_ext_value_t *ext_value = *ext_value_ptr; + + if (ext_value->key != 0) { + free(ext_value->key); + ext_value->key = 0; + } + + if (!ext_value->is_null && !ext_value->is_const) { + if (ext_value->type == VTYPE_RAW && ext_value->value.raw != 0) { + free(ext_value->value.raw); + ext_value->value.raw = 0; + } + if (ext_value->type == VTYPE_STRING && ext_value->value.str != 0) { + free(ext_value->value.str); + ext_value->value.str = 0; + } + } + + free(ext_value); + *ext_value_ptr = 0; +} +struct meta_ext_value_t **allocMetaExtValues(size_t n_values, int alloc_values) +{ + struct meta_ext_value_t **ext_values; + size_t idx; + + ext_values = (struct meta_ext_value_t **)malloc(sizeof(struct meta_ext_value_t *) * n_values); + if (ext_values == 0) { + fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno)); + return 0; + } + memset(ext_values, 0, sizeof(struct meta_ext_value_t *) * n_values); + + if (alloc_values) { + for (idx = 0; idx < n_values; idx++) { + if ((*(ext_values + idx) = allocMetaExtValue()) == 0) { + freeMetaExtValues(&ext_values, idx - 1); + return 0; + } + } + } + + return ext_values; +} +void freeMetaExtValues(struct meta_ext_value_t ***ext_values_ptr, size_t n_values) +{ + size_t idx; + struct meta_ext_value_t **ext_values = *ext_values_ptr; + + for (idx = 0; idx < n_values; idx++) { + if (*(ext_values + idx) != 0) { + freeMetaExtValue(ext_values + idx); + } + } + + free(ext_values); + *ext_values_ptr = 0; +} + + + +int modbMetaExtById(stored_conn *sconn, modb_ref *modb, unsigned int id, + struct meta_ext_t **meta_ext) +{ + where_builder *wb = 0; + int res; + char *tbl_ext; + size_t len_ext; + + modbTableName(&tbl_ext, &len_ext, modb, META_EXT_TABLE, strlen(META_EXT_TABLE)); + wb = where(tbl_ext, "mdo_id", EQ, TYPE_UINT32, 1, id); + res = doScalarMetaExtListQuery(sconn, modb, wb, meta_ext); + freeWhereBuilder(&wb); + free(tbl_ext); + + return res; +} + +int modbMetaExtList(stored_conn *sconn, modb_ref *modb, int with_deleted, + struct meta_ext_t ***meta_exts, size_t *n_meta_exts) +{ + where_builder *wb = 0; + int res; + char *tbl_ext = 0; + size_t len_ext; + + if (with_deleted == 0) { + modbTableName(&tbl_ext, &len_ext, modb, META_EXT_TABLE, strlen(META_EXT_TABLE)); + wb = where(tbl_ext, "deleted", IS_NULL, TYPE_RAW, 0, 0); + } + res = doMetaExtListQuery(sconn, modb, wb, meta_exts, n_meta_exts); + if (wb != 0) { + freeWhereBuilder(&wb); + free(tbl_ext); + } + + return res; +} + + +int64_t modbMetaExtCreate(stored_conn *sconn, modb_ref *modb, struct meta_ext_t *meta_ext) +{ + str_builder *sb; + char *table; + size_t table_len; + char *qry; + size_t qry_len; + uint64_t qry_ret; + size_t idx; + struct meta_ext_value_t *ext_value; + + if ((sb = strbld_create()) == 0) { + return -1; + } + modbTableName(&table, &table_len, modb, META_EXT_TABLE, strlen(META_EXT_TABLE)); + + strbld_str(sb, "INSERT INTO ", 0); + escapeTableName_sb(sb, table, table_len); + strbld_str(sb, " (`mdo_id`", 0); + for (idx = 0; idx < meta_ext->n_values; idx++) { + ext_value = (*(meta_ext->values + idx)); + strbld_char(sb, ','); + escapeColumnName_sb(sb, 0, 0, ext_value->key_c, 0); + } + strbld_str(sb, ") VALUES (", 0); + db_value_sb(sb, TYPE_ID, 1, meta_ext->id); + for (idx = 0; idx < meta_ext->n_values; idx++) { + ext_value = *(meta_ext->values + idx); + strbld_char(sb, ','); + switch(ext_value->type) { + case VTYPE_RAW: + db_value_sb(sb, TYPE_RAW, 2, ext_value->value.raw, ext_value->value_len); + break; + case VTYPE_BOOL: + db_value_sb(sb, TYPE_BOOL, 1, ext_value->value.bool); + break; + case VTYPE_INT32: + db_value_sb(sb, TYPE_INT32, 1, ext_value->value.int32); + break; + case VTYPE_DOUBLE: + db_value_sb(sb, TYPE_DOUBLE, 1, ext_value->value.dbl); + break; + case VTYPE_STRING: + db_value_sb(sb, TYPE_STRING, 2, ext_value->value.str, ext_value->value_len); + break; + case VTYPE_TIMESTAMP: + db_value_sb(sb, TYPE_TIMESTAMP, 1, ext_value->value.ts); + break; + case VTYPE_ID: + db_value_sb(sb, TYPE_ID, 1, ext_value->value.id); + break; + } + } + strbld_char(sb, ')'); + + modbFreeTableName(&table); + if (strbld_finalize_or_destroy(&sb, &qry, &qry_len) != 0) { + return -1; + } + + qry_ret = simpleQuery(sconn, qry, qry_len); + free(qry); + + return qry_ret == 0 ? meta_ext->id : 0; +} +int64_t modbMetaExtReplace(stored_conn *sconn, modb_ref *modb, unsigned int id, + struct meta_ext_t *meta_ext); +int64_t modbMetaExtUpdate(stored_conn *sconn, modb_ref *modb, unsigned int id, + struct meta_ext_t *meta_ext) +{ + str_builder *sb; + char *table, *set; + size_t table_len, set_len; + int64_t qry_ret; + size_t idx; + struct meta_ext_value_t *ext_value; + + if ((sb = strbld_create()) == 0) { + return 0; + } + columnSetValueStr_sb(sb, "mdo_id", TYPE_ID, 1, id); + + for (idx = 0; idx < meta_ext->n_values; idx++) { + ext_value = *(meta_ext->values + idx); + strbld_char(sb, ','); + switch(ext_value->type) { + case VTYPE_RAW: + columnSetValueStr_sb( + sb, ext_value->key_c, TYPE_RAW, 2, ext_value->value.raw, ext_value->value_len + ); + break; + case VTYPE_BOOL: + columnSetValueStr_sb(sb, ext_value->key_c, TYPE_BOOL, 1, ext_value->value.bool); + break; + case VTYPE_INT32: + columnSetValueStr_sb(sb, ext_value->key_c, TYPE_INT32, 1, ext_value->value.int32); + break; + case VTYPE_DOUBLE: + columnSetValueStr_sb(sb, ext_value->key_c, TYPE_DOUBLE, 1, ext_value->value.dbl); + break; + case VTYPE_STRING: + columnSetValueStr_sb( + sb, ext_value->key_c, TYPE_STRING, 2, ext_value->value.str, ext_value->value_len + ); + break; + case VTYPE_TIMESTAMP: + columnSetValueStr_sb(sb, ext_value->key_c, TYPE_TIMESTAMP, 1, ext_value->value.ts); + break; + case VTYPE_ID: + columnSetValueStr_sb(sb, ext_value->key_c, TYPE_ID, 1, ext_value->value.id); + break; + } + } + + if (strbld_finalize_or_destroy(&sb, &set, &set_len) != 0) { + return 0; + } + + modbTableName(&table, &table_len, modb, META_EXT_TABLE, strlen(META_EXT_TABLE)); + qry_ret = updateQuery( + sconn, table, table_len, set, set_len, where(0, "mdo_id", EQ, TYPE_ID, 1, id) + ); + modbFreeTableName(&table); + + free(set); + + return qry_ret; +} +int modbMetaExtDelete(stored_conn *sconn, modb_ref *modb, unsigned int id) +{ + char *table; + size_t table_len; + int64_t qry_ret; + + modbTableName(&table, &table_len, modb, META_EXT_TABLE, STR_LEN(META_EXT_TABLE)); + qry_ret = softDeleteByIdQuery(sconn, table, table_len, "mdo_id", id); + modbFreeTableName(&table); + + return (int)qry_ret; +} +int modbMetaExtDestroy(stored_conn *sconn, modb_ref *modb, unsigned int id) +{ + char *table; + size_t table_len; + int64_t qry_ret; + + modbTableName(&table, &table_len, modb, META_EXT_TABLE, STR_LEN(META_EXT_TABLE)); + qry_ret = deleteByIdQuery(sconn, table, table_len, "mdo_id", id); + modbFreeTableName(&table); + + return (int)qry_ret; +} diff --git a/src/modb_metadata_ext.h b/src/modb_metadata_ext.h index 5176e4c..0f91bf5 100644 --- a/src/modb_metadata_ext.h +++ b/src/modb_metadata_ext.h @@ -1,48 +1,71 @@ #ifndef H__MODB_METADATA_EXT__ #define H__MODB_METADATA_EXT__ +#include + +#include "database.h" #include "modb_ref.h" -// MetadataExtended object -struct metadata_ext_t { - unsigned int id; - -// TODO: dynamic extended metadata definition -// struct metadata_ext_value_t **meta_ext; -// size_t n_meta_ext; +enum e_value_type_t { + VTYPE_RAW = 0, + VTYPE_BOOL = 1 << 0, + VTYPE_INT32 = 1 << 1, + VTYPE_DOUBLE = 1 << 2, + VTYPE_STRING = 1 << 3, + VTYPE_TIMESTAMP = 1 << 4, + VTYPE_ID = 1 << 5 }; -//struct metadata_ext_value_t { -// char *key; -// enum e_column_type_t type; -// union { -// void *vptr;_ptr +struct meta_ext_t { + unsigned int id; -// int8_t int8; -// uint8_t uint8; + struct meta_ext_value_t **values; + size_t n_values; +}; -// int16_t int16; -// uint16_t uint16; +struct meta_ext_value_t { + char *key; + const char *key_c; + enum e_value_type_t type; + union { + void *raw; + int bool; + int32_t int32; + double dbl; + char *str; + const char *str_c; + int64_t ts; + uint32_t id; + } value; + size_t value_len; -// int32_t int32; -// uint32_t uint32; + uint32_t is_null :1; + uint32_t is_const :1; +}; -// int64_t int64; -// uint64_t uint64; +struct meta_ext_t *allocMetaExt(void); +void freeMetaExt(struct meta_ext_t **meta_ext); +struct meta_ext_t **allocMetaExtList(size_t n_meta_ext_list); +void freeMetaExtList(struct meta_ext_t ***meta_ext_list_ptr, size_t n_meta_exts); -// float flt; -// double dbl; +struct meta_ext_value_t *allocMetaExtValue(void); +void freeMetaExtValue(struct meta_ext_value_t **meta_ext_value); +struct meta_ext_value_t **allocMetaExtValues(size_t n_values, int alloc_values); +void freeMetaExtValues(struct meta_ext_value_t ***value_list_ptr, size_t n_values); -// char *ptr_str; -// } value; -// size_t value_len; -//}; +// MODB Extended Metadata +int modbMetaExtById(stored_conn *sconn, modb_ref *modb, unsigned int id, + struct meta_ext_t **meta_ext); -struct metadata_ext_t *allocMetadataExt(void); -struct metadata_ext_t **allocMetadataExts(size_t n_metadata_exts); -void freeMetadataExt(struct metadata_ext_t **metadata_ext); -void freeMetadataExts(struct metadata_ext_t ***metadata_exts_ptr, size_t n_metadata_exts); +int modbMetaExtList(stored_conn *sconn, modb_ref *modb, int with_deleted, + struct meta_ext_t ***meta_exts, size_t *n_meta_exts); + +int64_t modbMetaExtCreate(stored_conn *sconn, modb_ref *modb, struct meta_ext_t *meta_ext); +int64_t modbMetaExtReplace(stored_conn *sconn, modb_ref *modb, unsigned int id, + struct meta_ext_t *meta_ext); +int modbMetaExtDelete(stored_conn *sconn, modb_ref *modb, unsigned int id); +int modbMetaExtDestroy(stored_conn *sconn, modb_ref *modb, unsigned int id); #endif // H__MODB_METADATA_EXT__