Skip to content

Commit

Permalink
Add C API bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
mewim committed Apr 19, 2023
1 parent a5e9793 commit dac5477
Show file tree
Hide file tree
Showing 27 changed files with 3,025 additions and 45 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_subdirectory(binder)
add_subdirectory(c_api)
add_subdirectory(catalog)
add_subdirectory(common)
add_subdirectory(expression_evaluator)
Expand Down
14 changes: 14 additions & 0 deletions src/c_api/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
add_library(kuzu_c_api
OBJECT
connection.cpp
database.cpp
data_type.cpp
flat_tuple.cpp
prepared_statement.cpp
query_result.cpp
query_summary.cpp
value.cpp)

set(ALL_OBJECT_FILES
${ALL_OBJECT_FILES} $<TARGET_OBJECTS:kuzu_c_api>
PARENT_SCOPE)
135 changes: 135 additions & 0 deletions src/c_api/connection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include "binder/bound_statement_result.h"
#include "c_api/kuzu.h"
#include "common/types/value.h"
#include "main/kuzu.h"
#include "planner/logical_plan/logical_plan.h"

using namespace kuzu::common;
using namespace kuzu::main;

kuzu_connection* kuzu_connection_init(kuzu_database* database) {
if (database == nullptr || database->_database == nullptr) {
return nullptr;
}
auto connection = (kuzu_connection*)malloc(sizeof(kuzu_connection));
try {
connection->_connection = new Connection(static_cast<Database*>(database->_database));
} catch (std::exception& e) {
free(connection);
return nullptr;
}
return connection;
}

void kuzu_connection_destroy(kuzu_connection* connection) {
if (connection == nullptr) {
return;
}
if (connection->_connection != nullptr) {
delete static_cast<Connection*>(connection->_connection);
}
free(connection);
}

void kuzu_connection_begin_read_only_transaction(kuzu_connection* connection) {
static_cast<Connection*>(connection->_connection)->beginReadOnlyTransaction();
}

void kuzu_connection_begin_write_transaction(kuzu_connection* connection) {
static_cast<Connection*>(connection->_connection)->beginWriteTransaction();
}

void kuzu_connection_commit(kuzu_connection* connection) {
static_cast<Connection*>(connection->_connection)->commit();
}

void kuzu_connection_rollback(kuzu_connection* connection) {
static_cast<Connection*>(connection->_connection)->rollback();
}

void kuzu_connection_set_max_num_thread_for_exec(
kuzu_connection* connection, uint64_t num_threads) {
static_cast<Connection*>(connection->_connection)->setMaxNumThreadForExec(num_threads);
}

uint64_t kuzu_connection_get_max_num_thread_for_exec(kuzu_connection* connection) {
return static_cast<Connection*>(connection->_connection)->getMaxNumThreadForExec();
}

kuzu_query_result* kuzu_connection_query(kuzu_connection* connection, const char* query) {
auto query_result = static_cast<Connection*>(connection->_connection)->query(query).release();
if (query_result == nullptr) {
return nullptr;
}
auto* c_query_result = new kuzu_query_result;
c_query_result->_query_result = query_result;
return c_query_result;
}

kuzu_prepared_statement* kuzu_connection_prepare(kuzu_connection* connection, const char* query) {
auto prepared_statement =
static_cast<Connection*>(connection->_connection)->prepare(query).release();
if (prepared_statement == nullptr) {
return nullptr;
}
auto* c_prepared_statement = new kuzu_prepared_statement;
c_prepared_statement->_prepared_statement = prepared_statement;
c_prepared_statement->_bound_values =
new std::unordered_map<std::string, std::shared_ptr<Value>>;
return c_prepared_statement;
}

kuzu_query_result* kuzu_connection_execute(
kuzu_connection* connection, kuzu_prepared_statement* prepared_statement) {
auto prepared_statement_ptr =
static_cast<PreparedStatement*>(prepared_statement->_prepared_statement);
auto bound_values = static_cast<std::unordered_map<std::string, std::shared_ptr<Value>>*>(
prepared_statement->_bound_values);
auto query_result = static_cast<Connection*>(connection->_connection)
->executeWithParams(prepared_statement_ptr, *bound_values)
.release();
if (query_result == nullptr) {
return nullptr;
}
auto* c_query_result = new kuzu_query_result;
c_query_result->_query_result = query_result;
return c_query_result;
}

char* kuzu_connection_get_node_table_names(kuzu_connection* connection) {
auto node_table_names = static_cast<Connection*>(connection->_connection)->getNodeTableNames();
char* node_table_names_c = (char*)malloc(node_table_names.size() + 1);
strcpy(node_table_names_c, node_table_names.c_str());
return node_table_names_c;
}

char* kuzu_connection_get_rel_table_names(kuzu_connection* connection) {
auto rel_table_names = static_cast<Connection*>(connection->_connection)->getRelTableNames();
char* rel_table_names_c = (char*)malloc(rel_table_names.size() + 1);
strcpy(rel_table_names_c, rel_table_names.c_str());
return rel_table_names_c;
}

char* kuzu_connection_get_node_property_names(kuzu_connection* connection, const char* table_name) {
auto node_property_names =
static_cast<Connection*>(connection->_connection)->getNodePropertyNames(table_name);
char* node_property_names_c = (char*)malloc(node_property_names.size() + 1);
strcpy(node_property_names_c, node_property_names.c_str());
return node_property_names_c;
}

char* kuzu_connection_get_rel_property_names(kuzu_connection* connection, const char* table_name) {
auto rel_property_names =
static_cast<Connection*>(connection->_connection)->getRelPropertyNames(table_name);
char* rel_property_names_c = (char*)malloc(rel_property_names.size() + 1);
strcpy(rel_property_names_c, rel_property_names.c_str());
return rel_property_names_c;
}

void kuzu_connection_interrupt(kuzu_connection* connection) {
static_cast<Connection*>(connection->_connection)->interrupt();
}

void kuzu_connection_set_query_timeout(kuzu_connection* connection, uint64_t timeout_in_ms) {
static_cast<Connection*>(connection->_connection)->setQueryTimeOut(timeout_in_ms);
}
81 changes: 81 additions & 0 deletions src/c_api/data_type.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "c_api/kuzu.h"
#include "common/types/types.h"
#include "main/kuzu.h"

using namespace kuzu::main;
using namespace kuzu::common;

kuzu_data_type* kuzu_data_type_create(
kuzu_data_type_id id, kuzu_data_type* child_type, uint64_t fixed_num_elements_in_list) {
auto* c_data_type = (kuzu_data_type*)malloc(sizeof(kuzu_data_type));
uint8_t data_type_id_u8 = id;
DataType* data_type;
if (child_type == nullptr) {
data_type = new DataType(static_cast<DataTypeID>(data_type_id_u8));
} else {
auto child_type_pty =
std::make_unique<DataType>(*static_cast<DataType*>(child_type->_data_type));
data_type =
fixed_num_elements_in_list > 0 ?
new DataType(static_cast<DataTypeID>(data_type_id_u8), std::move(child_type_pty),
fixed_num_elements_in_list) :
new DataType(static_cast<DataTypeID>(data_type_id_u8), std::move(child_type_pty));
}
c_data_type->_data_type = data_type;
return c_data_type;
}

kuzu_data_type* kuzu_data_type_clone(kuzu_data_type* data_type) {
auto* c_data_type = (kuzu_data_type*)malloc(sizeof(kuzu_data_type));
c_data_type->_data_type = new DataType(*static_cast<DataType*>(data_type->_data_type));
return c_data_type;
}

void kuzu_data_type_destroy(kuzu_data_type* data_type) {
if (data_type == nullptr) {
return;
}
if (data_type->_data_type != nullptr) {
delete static_cast<DataType*>(data_type->_data_type);
}
free(data_type);
}

bool kuzu_data_type_equals(kuzu_data_type* data_type1, kuzu_data_type* data_type2) {
return *static_cast<DataType*>(data_type1->_data_type) ==
*static_cast<DataType*>(data_type2->_data_type);
}

kuzu_data_type_id kuzu_data_type_get_id(kuzu_data_type* data_type) {
auto data_type_id_u8 =
static_cast<uint8_t>(static_cast<DataType*>(data_type->_data_type)->getTypeID());
return static_cast<kuzu_data_type_id>(data_type_id_u8);
}

kuzu_data_type* kuzu_data_type_get_child_type(kuzu_data_type* data_type) {
auto parent_type = static_cast<DataType*>(data_type->_data_type);
if (parent_type->getTypeID() != DataTypeID::FIXED_LIST &&
parent_type->getTypeID() != DataTypeID::VAR_LIST) {
return nullptr;
}
auto child_type = static_cast<DataType*>(data_type->_data_type)->getChildType();
if (child_type == nullptr) {
return nullptr;
}
auto* child_type_c = (kuzu_data_type*)malloc(sizeof(kuzu_data_type));
child_type_c->_data_type = new DataType(*child_type);
return child_type_c;
}

uint64_t kuzu_data_type_get_fixed_num_elements_in_list(kuzu_data_type* data_type) {
auto parent_type = static_cast<DataType*>(data_type->_data_type);
if (parent_type->getTypeID() != DataTypeID::FIXED_LIST) {
return 0;
}
auto extra_info = static_cast<DataType*>(data_type->_data_type)->getExtraTypeInfo();
if (extra_info == nullptr) {
return 0;
}
auto fixed_list_info = dynamic_cast<FixedListTypeInfo*>(extra_info);
return fixed_list_info->getFixedNumElementsInList();
}
31 changes: 31 additions & 0 deletions src/c_api/database.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "c_api/kuzu.h"
#include "main/kuzu.h"

using namespace kuzu::main;
kuzu_database* kuzu_database_init(const char* database_path, uint64_t buffer_pool_size) {
auto database = (kuzu_database*)malloc(sizeof(kuzu_database));
std::string database_path_str = database_path;
try {
database->_database = buffer_pool_size == 0 ?
new Database(database_path_str) :
new Database(database_path_str, SystemConfig(buffer_pool_size));
} catch (std::exception& e) {
free(database);
return nullptr;
}
return database;
}

void kuzu_database_destroy(kuzu_database* database) {
if (database == nullptr) {
return;
}
if (database->_database != nullptr) {
delete static_cast<Database*>(database->_database);
}
free(database);
}

void kuzu_database_set_logging_level(const char* logging_level) {
Database::setLoggingLevel(logging_level);
}
46 changes: 46 additions & 0 deletions src/c_api/flat_tuple.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "processor/result/flat_tuple.h"

#include "c_api/kuzu.h"

using namespace kuzu::common;
using namespace kuzu::processor;

void kuzu_flat_tuple_destroy(kuzu_flat_tuple* flat_tuple) {
if (flat_tuple == nullptr) {
return;
}
if (flat_tuple->_flat_tuple != nullptr) {
auto flat_tuple_shared_ptr =
static_cast<std::shared_ptr<FlatTuple>*>(flat_tuple->_flat_tuple);
flat_tuple_shared_ptr->reset();
delete flat_tuple_shared_ptr;
}
free(flat_tuple);
}

kuzu_value* kuzu_flat_tuple_get_value(kuzu_flat_tuple* flat_tuple, uint64_t index) {
auto flat_tuple_shared_ptr = static_cast<std::shared_ptr<FlatTuple>*>(flat_tuple->_flat_tuple);
Value* _value;
try {
_value = (*flat_tuple_shared_ptr)->getValue(index);
} catch (Exception& e) { return nullptr; }
auto* value = (kuzu_value*)malloc(sizeof(kuzu_value));
value->_value = _value;
// We set the ownership of the value to C++, so it will not be deleted if the value is destroyed
// in C.
value->_is_owned_by_cpp = true;
return value;
}

char* kuzu_flat_tuple_to_string(kuzu_flat_tuple* flat_tuple, const uint32_t* columns_width,
uint64_t columns_width_length, const char* delimiter, uint32_t max_width) {
auto flat_tuple_shared_ptr = static_cast<std::shared_ptr<FlatTuple>*>(flat_tuple->_flat_tuple);
std::vector<uint32_t> columns_width_vector;
for (uint64_t i = 0; i < columns_width_length; i++) {
columns_width_vector.push_back(columns_width[i]);
}
auto string = (*flat_tuple_shared_ptr)->toString(columns_width_vector, delimiter, max_width);
char* string_c = (char*)malloc(string.size() + 1);
strcpy(string_c, string.c_str());
return string_c;
}
Loading

0 comments on commit dac5477

Please sign in to comment.