/* * returns: * -EINVAL: invalid arg * OSD_ERROR: some other error * OSD_OK: success */ int obj_delete_pid(void *ohandle, uint64_t pid) { struct db_context *dbc = ((struct handle*)ohandle)->dbc; int ret = 0; assert(dbc && dbc->db && dbc->obj && dbc->obj->delpid); repeat: ret = sqlite3_bind_int64(dbc->obj->delpid, 1, pid); ret = db_exec_dms(dbc, dbc->obj->delpid, ret, __func__); if (ret == OSD_REPEAT) goto repeat; return ret; }
/* * returns: * -EINVAL: invalid arg * OSD_ERROR: some other error * OSD_OK: success */ int attr_delete_all(struct db_context *dbc, uint64_t pid, uint64_t oid) { int ret = 0; assert(dbc && dbc->db && dbc->attr && dbc->attr->delall); repeat: ret = 0; ret |= sqlite3_bind_int64(dbc->attr->delall, 1, pid); ret |= sqlite3_bind_int64(dbc->attr->delall, 2, oid); ret = db_exec_dms(dbc, dbc->attr->delall, ret, __func__); if (ret == OSD_REPEAT) goto repeat; return ret; }
/* * returns: * -EINVAL: invalid arg * OSD_ERROR: some other error * OSD_OK: success */ int coll_delete_oid(struct db_context *dbc, uint64_t pid, uint64_t oid) { int ret = 0; assert(dbc && dbc->db && dbc->coll && dbc->coll->deloid); repeat: ret = 0; ret |= sqlite3_bind_int64(dbc->coll->deloid, 1, pid); ret |= sqlite3_bind_int64(dbc->coll->deloid, 2, oid); ret = db_exec_dms(dbc, dbc->coll->deloid, ret, __func__); if (ret == OSD_REPEAT) goto repeat; return ret; }
/* * @pid: partition id * @dest_cid: destination collection id (typically user tracking collection) * @source_cid: source collection id (whose objects will be tracked) * * returns: * -EINVAL: invalid arg * OSD_ERROR: some other error * OSD_OK: success */ int coll_copyoids(struct db_context *dbc, uint64_t pid, uint64_t dest_cid, uint64_t source_cid) { int ret = 0; assert(dbc && dbc->db && dbc->coll && dbc->coll->copyoids); repeat: ret = 0; ret |= sqlite3_bind_int64(dbc->coll->copyoids, 1, pid); ret |= sqlite3_bind_int64(dbc->coll->copyoids, 2, dest_cid); ret |= sqlite3_bind_int64(dbc->coll->copyoids, 3, pid); ret |= sqlite3_bind_int64(dbc->coll->copyoids, 4, source_cid); ret = db_exec_dms(dbc, dbc->coll->copyoids, ret, __func__); if (ret == OSD_REPEAT) goto repeat; return ret; }
/* * @pid: partition id * @cid: collection id * @oid: userobject id * @number: attribute number of cid in CAP of oid * * returns: * -EINVAL: invalid arg * OSD_ERROR: some other error * OSD_OK: success */ int coll_insert(struct db_context *dbc, uint64_t pid, uint64_t cid, uint64_t oid, uint32_t number) { int ret = 0; assert(dbc && dbc->db && dbc->coll && dbc->coll->insert); repeat: ret = 0; ret |= sqlite3_bind_int64(dbc->coll->insert, 1, pid); ret |= sqlite3_bind_int64(dbc->coll->insert, 2, cid); ret |= sqlite3_bind_int64(dbc->coll->insert, 3, oid); ret |= sqlite3_bind_int(dbc->coll->insert, 4, number); ret = db_exec_dms(dbc, dbc->coll->insert, ret, __func__); if (ret == OSD_REPEAT) goto repeat; return ret; }
/* * returns: * -EINVAL: invalid arg * OSD_ERROR: some other error * OSD_OK: success */ int attr_delete_attr(struct db_context *dbc, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number) { int ret = 0; sqlite3_stmt *stmt = NULL; assert(dbc && dbc->db && dbc->attr && dbc->attr->delattr); repeat: ret = 0; stmt = dbc->attr->delattr; ret |= sqlite3_bind_int64(stmt, 1, pid); ret |= sqlite3_bind_int64(stmt, 2, oid); ret |= sqlite3_bind_int(stmt, 3, page); ret |= sqlite3_bind_int(stmt, 4, number); ret = db_exec_dms(dbc, stmt, ret, __func__); if (ret == OSD_REPEAT) goto repeat; return ret; }
/* * returns: * -EINVAL: invalid arg * OSD_ERROR: some other error * OSD_OK: success */ int obj_insert(void *ohandle, uint64_t pid, uint64_t oid, uint32_t type) { struct db_context *dbc = ((struct handle*)ohandle)->dbc; int ret = 0; TICK_TRACE(obj_insert); assert(dbc && dbc->db && dbc->obj && dbc->obj->insert); repeat: ret = 0; ret |= sqlite3_bind_int64(dbc->obj->insert, 1, pid); ret |= sqlite3_bind_int64(dbc->obj->insert, 2, oid); ret |= sqlite3_bind_int(dbc->obj->insert, 3, type); ret = db_exec_dms(dbc, dbc->obj->insert, ret, __func__); if (ret == OSD_REPEAT) goto repeat; TICK_TRACE(obj_insert); return ret; }
/* * Note: Current SQLITE INSERT syntax does not support bulk inserts in a * single INSERT SQL statement. Therefore this function needs to be called * for each table insert. * * returns: * -EINVAL: invalid arg * OSD_ERROR: some other error * OSD_OK: success */ int attr_set_attr(struct db_context *dbc, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number, const void *val, uint16_t len) { int ret = 0; sqlite3_stmt *stmt = NULL; assert(dbc && dbc->db && dbc->attr && dbc->attr->setattr); repeat: ret = 0; stmt = dbc->attr->setattr; ret |= sqlite3_bind_int64(stmt, 1, pid); ret |= sqlite3_bind_int64(stmt, 2, oid); ret |= sqlite3_bind_int(stmt, 3, page); ret |= sqlite3_bind_int(stmt, 4, number); ret |= sqlite3_bind_blob(stmt, 5, val, len, SQLITE_TRANSIENT); ret = db_exec_dms(dbc, stmt, ret, __func__); if (ret == OSD_REPEAT) goto repeat; return ret; }
/* * return values: * -EINVAL: invalid argument * -EIO: prepare or some other sqlite function failed * OSD_ERROR: some other error * OSD_OK: success */ int mtq_run_query(struct db_context *dbc, uint64_t pid, uint64_t cid, struct query_criteria *qc, void *outdata, uint32_t alloc_len, uint64_t *used_outlen, uint64_t matches_cid) { int ret = 0; int pos = 0; char *cp = NULL; char *SQL = NULL; uint8_t *p = NULL; uint32_t i = 0; uint32_t sqlen = 0; uint32_t number; uint32_t factor = 2; /* this query fills space quickly */ uint64_t len = 0; const char *op = NULL; sqlite3_stmt *stmt = NULL; char select_stmt[MAXSQLEN]; const char *coll = coll_getname(dbc); const char *attr = attr_getname(dbc); assert(dbc && dbc->db && qc && outdata && used_outlen && coll && attr); if (qc->query_type == 0) { op = " UNION "; } else if (qc->query_type == 1) { op = " INTERSECT "; } else { ret = -EINVAL; goto out; } SQL = Malloc(MAXSQLEN*factor); if (SQL == NULL) { ret = -ENOMEM; goto out; } cp = SQL; sqlen = 0; /* * XXX:SD the spec does not mention whether min or max values have to * in tested with '<' or '<='. We assume the tests are inclusive of * boundaries, i.e. use '<=' for comparison. */ /* build the SQL statment */ if (matches_cid != 0) { ret = coll_max_pointer(dbc, pid, cid, &number); if (ret != SQLITE_OK) { goto out; } sprintf(select_stmt, "SELECT coll.pid, %llu, attr.oid, %d " "FROM %s AS coll, %s AS attr WHERE " "coll.pid=coll.pid AND coll.oid=attr.oid " "AND coll.pid = %llu AND coll.cid = %llu ", llu(matches_cid), number, coll, attr, llu(pid), llu(cid)); } else { sprintf(select_stmt, "SELECT attr.oid FROM %s AS coll, " "%s AS attr WHERE coll.pid = coll.pid AND " "coll.oid = attr.oid AND coll.pid = %llu " "AND coll.cid = %llu ", coll, attr, llu(pid), llu(cid)); } strncpy(cp, select_stmt, MAXSQLEN*factor); sqlen += strlen(cp); cp += sqlen; for (i = 0; i < qc->qc_cnt; i++) { sprintf(cp, " AND attr.page = %u AND attr.number = %u ", qc->page[i], qc->number[i]); if (qc->min_len[i] > 0) cp = strcat(cp, " AND ? <= attr.value "); if (qc->max_len[i] > 0) cp = strcat(cp, " AND attr.value <= ? "); if ((i+1) < qc->qc_cnt) { cp = strcat(cp, op); cp = strcat(cp, select_stmt); } sqlen += strlen(cp); if (sqlen >= (MAXSQLEN*factor - 400)) { factor *= 2; SQL = realloc(SQL, MAXSQLEN*factor); if (!SQL) { ret = -ENOMEM; goto out; } } cp = SQL + sqlen; } cp = strcat(cp, " GROUP BY attr.oid ORDER BY 1;"); if (matches_cid != 0) { char *SQL2 = Malloc(strlen(SQL) + 100); if (SQL2 == NULL) { ret = -ENOMEM; goto out; } sprintf(SQL2, "INSERT INTO %s %s", coll, SQL); free(SQL); SQL = SQL2; } ret = sqlite3_prepare(dbc->db, SQL, strlen(SQL)+1, &stmt, NULL); if (ret != SQLITE_OK) { error_sql(dbc->db, "%s: sqlite3_prepare", __func__); ret = -EIO; goto out; } repeat: /* bind the values */ pos = 1; for (i = 0; i < qc->qc_cnt; i++) { if (qc->min_len[i] > 0) { ret = sqlite3_bind_blob(stmt, pos, qc->min_val[i], qc->min_len[i], SQLITE_TRANSIENT); if (ret != SQLITE_OK) { ret = -EIO; error_sql(dbc->db, "%s: bind min_val @ %d", __func__, pos); goto out_finalize; } pos++; } if (qc->max_len[i] > 0) { ret = sqlite3_bind_blob(stmt, pos, qc->max_val[i], qc->max_len[i], SQLITE_TRANSIENT); if (ret != SQLITE_OK) { ret = -EIO; error_sql(dbc->db, "%s: bind max_val @ %d", __func__, pos); goto out_finalize; } pos++; } } if (matches_cid != 0) { ret = db_exec_dms(dbc, stmt, ret, __func__); if (ret == OSD_REPEAT) goto repeat; goto out_finalize; } /* execute the query */ p = outdata; p += ML_ODL_OFF; len = ML_ODL_OFF - 8; /* subtract len of addition_len */ *used_outlen = ML_ODL_OFF; while ((ret = sqlite3_step(stmt)) == SQLITE_ROW) { if ((alloc_len - len) > 8) { /* * TODO: query is a multi-object command, so delete * the objects from the collection, once they are * selected */ set_htonll(p, sqlite3_column_int64(stmt, 0)); *used_outlen += 8; } p += 8; /* handle overflow: osd2r01 Sec 6.18.3 */ if (len != (uint64_t) -1 && (len + 8) > len) { len += 8; } else { len = (uint64_t) -1; } } if (ret != SQLITE_DONE) { error_sql(dbc->db, "%s: sqlite3_step", __func__); ret = -EIO; goto out_finalize; } set_htonll(outdata, len); ret = OSD_OK; out_finalize: if (sqlite3_finalize(stmt) != SQLITE_OK) error_sql(dbc->db, "%s: finalize", __func__); out: free(SQL); return ret; }