/* * returns: * -EINVAL: invalid arg, cid is not set * OSD_ERROR: in case of any error, cid is not set * OSD_OK: success, cid is set to proper collection id */ int coll_get_cid(void *ohandle, uint64_t pid, uint64_t oid, uint32_t number, uint64_t *cid) { struct db_context *dbc = ((struct handle*)ohandle)->dbc; int ret = 0; int bound = 0; assert(dbc && dbc->db && dbc->coll && dbc->coll->getcid); repeat: ret = 0; ret |= sqlite3_bind_int64(dbc->coll->getcid, 1, pid); ret |= sqlite3_bind_int64(dbc->coll->getcid, 2, oid); ret |= sqlite3_bind_int64(dbc->coll->getcid, 3, number); bound = (ret == SQLITE_OK); if (!bound) { error_sql(dbc->db, "%s: bind failed", __func__); goto out_reset; } while ((ret = sqlite3_step(dbc->coll->getcid)) == SQLITE_BUSY); if (ret == SQLITE_ROW) *cid = sqlite3_column_int64(dbc->coll->getcid, 0); out_reset: ret = db_reset_stmt(dbc, dbc->coll->getcid, bound, __func__); if (ret == OSD_REPEAT) goto repeat; out: return ret; }
/* * tests whether partition is empty. * * returns: * -EINVAL: invalid arg * OSD_ERROR: in case of other errors, ignore value of *isempty * OSD_OK: success, *isempty set to: * ==1: if partition is empty or absent or in case of sqlite error * ==0: if partition is not empty */ int obj_isempty_pid(void *ohandle, char *root, uint64_t pid, int *isempty) { struct db_context *dbc = ((struct handle*)ohandle)->dbc; int ret = 0; int bound = 0; *isempty = 0; assert(dbc && dbc->db && dbc->obj && dbc->obj->emptypid); repeat: ret = sqlite3_bind_int64(dbc->obj->emptypid, 1, pid); bound = (ret == SQLITE_OK); if (!bound) { error_sql(dbc->db, "%s: bind failed", __func__); goto out_reset; } while ((ret = sqlite3_step(dbc->obj->emptypid)) == SQLITE_BUSY); if (ret == SQLITE_ROW) *isempty = (0 == sqlite3_column_int(dbc->obj->emptypid, 0)); out_reset: ret = db_reset_stmt(dbc, dbc->obj->emptypid, bound, __func__); if (ret == OSD_REPEAT) goto repeat; out: return ret; }
/* * return the type of the object * * returns: * -EINVAL: invalid arg, ignore value of obj_type * OSD_ERROR: any other error, ignore value of obj_type * OSD_OK: success in determining the type, either valid or invalid. * obj_types set to the determined type. */ int obj_get_type(void *ohandle, uint64_t pid, uint64_t oid, uint8_t *obj_type) { struct db_context *dbc = ((struct handle*)ohandle)->dbc; int ret = 0; int bound = 0; *obj_type = ILLEGAL_OBJ; assert(dbc && dbc->db && dbc->obj && dbc->obj->gettype); repeat: ret = 0; ret |= sqlite3_bind_int64(dbc->obj->gettype, 1, pid); ret |= sqlite3_bind_int64(dbc->obj->gettype, 2, oid); bound = (ret == SQLITE_OK); if (!bound) { error_sql(dbc->db, "%s: bind failed", __func__); goto out_reset; } while ((ret = sqlite3_step(dbc->obj->gettype)) == SQLITE_BUSY); if (ret == SQLITE_ROW) { *obj_type = sqlite3_column_int(dbc->obj->gettype, 0); } else if (ret == SQLITE_DONE) { osd_debug("%s: object (%llu %llu) doesn't exist", __func__, llu(pid), llu(oid)); } out_reset: ret = db_reset_stmt(dbc, dbc->obj->gettype, bound, __func__); if (ret == OSD_REPEAT) goto repeat; out: return ret; }
/* * return the max object pointer for a particular pid,cid * * returns: * -EINVAL: invalid arg, ignore value of isempty * OSD_ERROR: in case of other errors, ignore value of isempty * OSD_OK: success, isempty is set to: * ==1: if collection is empty or absent * ==0: if not empty */ int coll_max_pointer(struct db_context *dbc, uint64_t pid, uint64_t cid, uint32_t *number) { int ret = 0; int bound = 0; *number = 0; assert(dbc && dbc->db && dbc->coll && dbc->coll->max); repeat: ret = 0; ret |= sqlite3_bind_int64(dbc->coll->max, 1, pid); ret |= sqlite3_bind_int64(dbc->coll->max, 2, cid); bound = (ret == SQLITE_OK); if (!bound) { error_sql(dbc->db, "%s: bind failed", __func__); goto out_reset; } while ((ret = sqlite3_step(dbc->coll->max)) == SQLITE_BUSY); if (ret == SQLITE_ROW) *number = (0 == sqlite3_column_int(dbc->coll->max, 0)); out_reset: ret = db_reset_stmt(dbc, dbc->coll->max, bound, __func__); if (ret == OSD_REPEAT) goto repeat; out: return ret; }
/* * tests whether collection is empty. * * returns: * -EINVAL: invalid arg, ignore value of isempty * OSD_ERROR: in case of other errors, ignore value of isempty * OSD_OK: success, isempty is set to: * ==1: if collection is empty or absent * ==0: if not empty */ int coll_isempty_cid(struct db_context *dbc, uint64_t pid, uint64_t cid, int *isempty) { int ret = 0; int bound = 0; *isempty = 0; assert(dbc && dbc->db && dbc->coll && dbc->coll->emptycid); repeat: ret = 0; ret |= sqlite3_bind_int64(dbc->coll->emptycid, 1, pid); ret |= sqlite3_bind_int64(dbc->coll->emptycid, 2, cid); bound = (ret == SQLITE_OK); if (!bound) { error_sql(dbc->db, "%s: bind failed", __func__); goto out_reset; } while ((ret = sqlite3_step(dbc->coll->emptycid)) == SQLITE_BUSY); if (ret == SQLITE_ROW) *isempty = (0 == sqlite3_column_int(dbc->coll->emptycid, 0)); out_reset: ret = db_reset_stmt(dbc, dbc->coll->emptycid, bound, __func__); if (ret == OSD_REPEAT) goto repeat; out: return ret; }
/* * this function executes id retrieval statement. Only the functions * retireiving a list of oids, cids or pids may use this function * * returns: * OSD_ERROR: in case of any error * OSD_OK: on success * OSD_REPEAT: in case of sqlite_schema error, statements are prepared again, * hence values need to be bound again. */ int db_exec_id_rtrvl_stmt(struct db_context *dbc, sqlite3_stmt *stmt, int ret, const char *func, uint64_t alloc_len, uint8_t *outdata, uint64_t *used_outlen, uint64_t *add_len, uint64_t *cont_id) { uint64_t len = 0; int bound = (ret == SQLITE_OK); if (!bound) { error_sql(dbc->db, "%s: bind failed", func); goto out_reset; } len = 0; *add_len = 0; *cont_id = 0; *used_outlen = 0; while (1) { ret = sqlite3_step(stmt); if (ret == SQLITE_ROW) { if ((alloc_len - len) >= 8) { set_htonll(outdata, sqlite3_column_int64(stmt, 0)); outdata += 8; len += 8; } else if (*cont_id == 0) { *cont_id = sqlite3_column_int64(stmt, 0); } /* handle overflow: osd2r01 Sec 6.14.2 */ if (*add_len + 8 > *add_len) { *add_len += 8; } else { /* terminate since add_len overflew */ *add_len = (uint64_t) -1; break; } } else if (ret == SQLITE_BUSY) { continue; } else { break; } } out_reset: ret = db_reset_stmt(dbc, stmt, bound, func); if (ret == OSD_OK) *used_outlen = len; return ret; }
/* * return values * -EINVAL: invalid args * OSD_ERROR: some other sqlite error * OSD_OK: success * pid = next pid if OSD has some pids * pid = 1 if pid not in db. caller must assign correct pid. */ int obj_get_nextpid(void *ohandle, uint64_t *pid) { struct db_context *dbc = ((struct handle*)ohandle)->dbc; int ret = 0; assert(dbc && dbc->db && dbc->obj && dbc->obj->nextpid); repeat: while ((ret = sqlite3_step(dbc->obj->nextpid)) == SQLITE_BUSY); if (ret == SQLITE_ROW) *pid = sqlite3_column_int64(dbc->obj->nextpid, 0) + 1; out_reset: ret = db_reset_stmt(dbc, dbc->obj->nextpid, 1, __func__); if (ret == OSD_REPEAT) goto repeat; out: return ret; }
/* * exec_dms: executes prior prepared and bound data manipulation statement. * Only SQL statements with 'insert' or 'delete' may call this helper * function. * * returns: * OSD_ERROR: in case of error * OSD_OK: on success * OSD_REPEAT: in case of sqlite_schema error, statements are prepared again, * hence values need to be bound again. */ int db_exec_dms(struct db_context *dbc, sqlite3_stmt *stmt, int ret, const char *func) { int bound; TICK_TRACE(db_exec_dms); bound = (ret == SQLITE_OK); if (!bound) { error_sql(dbc->db, "%s: bind failed", func); goto out_reset; } do { TICK_TRACE(sqlite3_step); ret = sqlite3_step(stmt); } while (ret == SQLITE_BUSY); out_reset: ret = db_reset_stmt(dbc, stmt, bound, func); TICK_TRACE(db_exec_dms); return ret; }
/* * returns: * -EINVAL: invalid arg or misaligned buffer * -ENOENT: empty result set * OSD_ERROR: some other error * OSD_OK: success, used_outlen modified */ static int exec_attr_rtrvl_stmt(struct db_context *dbc, sqlite3_stmt *stmt, int ret, const char *func, uint64_t oid, uint64_t page, int rtrvl_type, uint64_t outlen, uint8_t *outdata, uint8_t listfmt, uint32_t *used_outlen) { uint32_t len = 0; uint8_t found = 0; uint8_t bound = (ret == SQLITE_OK); uint8_t inval = 0; if (!bound) { error_sql(dbc->db, "%s: bind failed", func); goto out_reset; } *used_outlen = 0; while (1) { ret = sqlite3_step(stmt); if (ret == SQLITE_ROW) { if (rtrvl_type == GATHER_VAL) { ret = attr_gather_val(stmt, outdata, outlen); } else if (rtrvl_type == GATHER_ATTR) { ret = attr_gather_attr(stmt, outdata, outlen, oid, listfmt); } else if (rtrvl_type == GATHER_DIR_PAGE) { ret = attr_gather_dir_page(stmt, outlen, outdata, oid, page, listfmt); } else { ret = -EINVAL; } if (ret > 0) { len += ret; outlen -= ret; outdata += ret; if (!found) found = 1; } else { if (ret == -EINVAL) inval = 1; break; } } else if (ret == SQLITE_BUSY) { continue; } else { break; } } out_reset: ret = db_reset_stmt(dbc, stmt, bound, func); if (inval) { ret = -EINVAL; } else if (ret == OSD_OK) { *used_outlen = len; if (!found) ret = -ENOENT; } return ret; }