* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "napi/native_api.h"
#include <sstream>
#include <hilog/log.h>
#include <database/data/oh_data_values.h>
#include <database/rdb/oh_cursor.h>
#include <database/rdb/relational_store.h>
#include <database/rdb/relational_store_error_code.h>
template <typename... Args> void Log(Args... args)
{
std::ostringstream oss;
std::initializer_list<int>{(oss << args << " ", 0)...};
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "vector", "%{public}s", oss.str().c_str());
}
void VectorQueryWithoutBingArgs(OH_Rdb_Store *store_)
{
OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, "select * from test where id = 1;", nullptr);
if (cursor == NULL) {
OH_LOG_ERROR(LOG_APP, "Query failed.");
return;
}
int rowCount = 0;
cursor->getRowCount(cursor, &rowCount);
while (cursor->goToNextRow(cursor) == OH_Rdb_ErrCode::RDB_OK) {
size_t count = 0;
OH_Cursor_GetFloatVectorCount(cursor, 1, &count);
float test[count];
size_t outLen;
OH_Cursor_GetFloatVector(cursor, 1, test, count, &outLen);
}
cursor->destroy(cursor);
}
void VectorQueryWithBingArgs(OH_Rdb_Store *store_)
{
char querySql[] = "select * from test where id = ?;";
OH_Data_Values *values = OH_Values_Create();
OH_Values_PutInt(values, 1);
OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, values);
if (cursor == NULL) {
OH_LOG_ERROR(LOG_APP, "Query failed.");
return;
}
int rowCount = 0;
while (cursor->goToNextRow(cursor) == OH_Rdb_ErrCode::RDB_OK) {
rowCount++;
size_t count = 0;
OH_Cursor_GetFloatVectorCount(cursor, 1, &count);
float test[count];
size_t outLen;
OH_Cursor_GetFloatVector(cursor, 1, test, count, &outLen);
}
OH_Values_Destroy(values);
cursor->destroy(cursor);
}
void VectorSubquery(OH_Rdb_Store *store_)
{
OH_Rdb_ExecuteV2(store_, "CREATE TABLE IF NOT EXISTS example(id text PRIMARY KEY);", nullptr, nullptr);
char querySql[] = "select * from test where id in (select id from example);";
OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, nullptr);
if (cursor == NULL) {
OH_LOG_ERROR(LOG_APP, "Query failed.");
return;
}
while (cursor->goToNextRow(cursor) == OH_Rdb_ErrCode::RDB_OK) {
size_t count = 0;
OH_Cursor_GetFloatVectorCount(cursor, 1, &count);
float test[count];
size_t outLen;
OH_Cursor_GetFloatVector(cursor, 1, test, count, &outLen);
}
cursor->destroy(cursor);
}
void VectorAggregateQuery(OH_Rdb_Store *store_)
{
OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_,
"select * from test where data1 <-> '[1.0, 1.0]' > 0 group by id having max(data1 <=> '[1.0, 1.0]');", nullptr);
if (cursor == NULL) {
OH_LOG_ERROR(LOG_APP, "Query failed.");
return;
}
while (cursor->goToNextRow(cursor) == OH_Rdb_ErrCode::RDB_OK) {
size_t count = 0;
OH_Cursor_GetFloatVectorCount(cursor, 1, &count);
float test[count];
size_t outLen;
OH_Cursor_GetFloatVector(cursor, 1, test, count, &outLen);
}
cursor->destroy(cursor);
}
void VectorMultiTableQuery(OH_Rdb_Store *store_)
{
OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, "select id, data1 <-> '[1.5, 5.6]' as distance from test "
"union select id, data1 <-> '[1.5, 5.6]' as distance from test order by distance limit 5;", nullptr);
if (cursor == NULL) {
OH_LOG_ERROR(LOG_APP, "Query failed.");
return;
}
while (cursor->goToNextRow(cursor) == OH_Rdb_ErrCode::RDB_OK) {
size_t count = 0;
OH_Cursor_GetFloatVectorCount(cursor, 1, &count);
float test[count];
size_t outLen;
OH_Cursor_GetFloatVector(cursor, 1, test, count, &outLen);
}
cursor->destroy(cursor);
}
void VectorQuery(OH_Rdb_Store *store_)
{
VectorQueryWithoutBingArgs(store_);
VectorQueryWithBingArgs(store_);
VectorSubquery(store_);
VectorAggregateQuery(store_);
VectorMultiTableQuery(store_);
}
void VectorCRUD(OH_Rdb_Store *store_)
{
char createTableSql[] =
"CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 floatvector(2));";
OH_Rdb_ExecuteByTrxId(store_, 0, createTableSql);
OH_Rdb_ExecuteV2(store_, "INSERT INTO test (id, data1) VALUES (0, '[3.4, 4.5]');", nullptr, nullptr);
OH_Data_Values *values = OH_Values_Create();
OH_Values_PutInt(values, 1);
float test[] = { 1.2, 2.3 };
size_t len = sizeof(test) / sizeof(test[0]);
OH_Values_PutFloatVector(values, test, len);
char insertSql[] = "INSERT INTO test (id, data1) VALUES (?, ?);";
OH_Rdb_ExecuteV2(store_, insertSql, values, nullptr);
OH_Values_Destroy(values);
OH_Rdb_ExecuteV2(store_, "update test set data1 = '[5.1, 6.1]' where id = 0;", nullptr, nullptr);
float test1[2] = { 5.5, 6.6 };
OH_Data_Values *values1 = OH_Values_Create();
size_t len1 = sizeof(test1) / sizeof(test1[0]);
OH_Values_PutFloatVector(values1, test1, len1);
OH_Values_PutInt(values1, 1);
OH_Rdb_ExecuteV2(store_, "update test set data1 = ? where id = ?", values1, nullptr);
OH_Values_Destroy(values1);
OH_Rdb_ExecuteV2(store_, "delete from test where id = 0", nullptr, nullptr);
OH_Data_Values *values2 = OH_Values_Create();
OH_Values_PutInt(values2, 1);
OH_Rdb_ExecuteV2(store_, "delete from test where id = ?", values2, nullptr);
OH_Values_Destroy(values2);
VectorQuery(store_);
}
void VectorStoreTest()
{
int numType = 0;
OH_Rdb_GetSupportedDbType(&numType);
Log("[vectorLog] isSupported ", numType);
OH_Rdb_ConfigV2 *config = OH_Rdb_CreateConfig();
OH_Rdb_SetDatabaseDir(config, "/data/storage/el2/database");
OH_Rdb_SetStoreName(config, "rdb_vector_test.db");
OH_Rdb_SetBundleName(config, "com.samples.vectorStore");
OH_Rdb_SetEncrypted(config, false);
OH_Rdb_SetSecurityLevel(config, OH_Rdb_SecurityLevel::S1);
OH_Rdb_SetArea(config, RDB_SECURITY_AREA_EL1);
OH_Rdb_SetDbType(config, RDB_CAYLEY);
int errCode = 0;
OH_Rdb_Store *store_ = OH_Rdb_CreateOrOpen(config, &errCode);
Log("[vectorLog] createOrOpen success", errCode);
VectorCRUD(store_);
Log("[vectorLog] success crud ");
OH_Rdb_ExecuteV2(store_, "CREATE VIEW v1 as select * from test where id > 0;", nullptr, nullptr);
OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, "select * from v1;", nullptr);
if (cursor == NULL) {
OH_LOG_ERROR(LOG_APP, "Query failed.");
return;
}
cursor->destroy(cursor);
OH_Rdb_ExecuteV2(store_, "CREATE INDEX diskann_l2_idx ON test USING GSDISKANN(data1 L2);", nullptr, nullptr);
OH_Rdb_ExecuteV2(store_, "DROP INDEX test.diskann_l2_idx;", nullptr, nullptr);
OH_Rdb_ExecuteV2(store_, "CREATE INDEX diskann_l2_idx ON test USING GSDISKANN(data1 L2) WITH "
"(queue_size=20, out_degree=50);", nullptr, nullptr);
OH_Rdb_ExecuteV2(store_,"CREATE TABLE test2(rec_time integer not null) WITH "
"(time_col = 'rec_time', interval = '5 minute');", nullptr, nullptr);
OH_Rdb_ExecuteV2(store_,"CREATE TABLE IF NOT EXISTS test3 (time integer not null, content text) with "
"(time_col = 'time', interval = '5 minute', compress_col = 'content');", nullptr, nullptr);
OH_Rdb_CloseStore(store_);
OH_Rdb_DeleteStoreV2(config);
}
static napi_value Add(napi_env env, napi_callback_info info)
{
VectorStoreTest();
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
napi_valuetype valuetype0;
napi_typeof(env, args[0], &valuetype0);
napi_valuetype valuetype1;
napi_typeof(env, args[1], &valuetype1);
double value0;
napi_get_value_double(env, args[0], &value0);
double value1;
napi_get_value_double(env, args[1], &value1);
napi_value sum;
napi_create_double(env, value0 + value1, &sum);
return sum;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
{ "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void*)0),
.reserved = { 0 },
};
extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
napi_module_register(&demoModule);
}