* Copyright (c) 2025 Huawei Device Co., Ltd.All Rights Reserved.
* 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 "database_ops.h"
#include <sstream>
#define SECUREC_ENABLE 1
#define ZERO 0
#define THREE 2
extern "C" {
time_t ParseDate(const char *dateStr)
{
struct tm tm = {0};
if (strptime(dateStr, "%Y-%m-%d", &tm) != nullptr) {
return mktime(&tm);
}
return 0;
}
DataCell CreateDataCell(DataType type, const char *value)
{
DataCell cell;
cell.type = type;
if (value == nullptr || strcasecmp(value, "NULL") == 0) {
cell.isNull = true;
return cell;
}
cell.isNull = false;
switch (type) {
case TYPE_INT:
cell.value.intVal = std::stoi(value);
break;
case TYPE_FLOAT:
cell.value.floatVal = std::stod(value);
break;
case TYPE_STRING:
std::copy_n(value, MAX_STRING_LEN - 1, cell.value.stringVal);
cell.value.stringVal[MAX_STRING_LEN - 1] = '\0';
break;
case TYPE_BOOL:
cell.value.boolVal = (strcasecmp(value, "true") == 0 || strcasecmp(value, "1") == 0);
break;
case TYPE_DATE:
cell.value.dateVal = ParseDate(value);
break;
default:
cell.isNull = true;
break;
}
return cell;
}
}
const char *DataBaseOps::DataTypeToString(DataType type)
{
switch (type) {
case TYPE_INT:
return "INT";
case TYPE_FLOAT:
return "FLOAT";
case TYPE_STRING:
return "STRING";
case TYPE_BOOL:
return "BOOL";
case TYPE_DATE:
return "DATE";
default:
return "UNKNOWN";
}
}
DataType DataBaseOps::StringToDataType(const char *str)
{
if (strcasecmp(str, "int") == 0) {
return TYPE_INT;
}
if (strcasecmp(str, "float") == 0) {
return TYPE_FLOAT;
}
if (strcasecmp(str, "string") == 0) {
return TYPE_STRING;
}
if (strcasecmp(str, "bool") == 0) {
return TYPE_BOOL;
}
if (strcasecmp(str, "date") == 0) {
return TYPE_DATE;
}
return TYPE_NULL;
}
char *DataBaseOps::FormatDate(time_t timestamp)
{
static const int dateBufferSize = 20;
static char buffer[dateBufferSize];
struct tm *tmInfo = localtime(×tamp);
size_t result = strftime(buffer, dateBufferSize, "%Y-%m-%d %H:%M:%S", tmInfo);
if (result == 0) {
buffer[0] = '\0';
return buffer;
}
return buffer;
}
void DataBaseOps::FreeDataCell(DataCell *cell)
{
if (cell) {
if (cell->type == TYPE_STRING && !cell->isNull) {
}
}
}
int DataBaseOps::CompareDataCells(const DataCell *a, const DataCell *b)
{
if (a->isNull && b->isNull) {
return 0;
}
if (a->isNull) {
return -1;
}
if (b->isNull) {
return 1;
}
if (a->type != b->type) {
return static_cast<int>(a->type) - static_cast<int>(b->type);
}
switch (a->type) {
case TYPE_INT:
return a->value.intVal - b->value.intVal;
case TYPE_FLOAT:
if (a->value.floatVal < b->value.floatVal) {
return -1;
}
if (a->value.floatVal > b->value.floatVal) {
return 1;
}
return 0;
case TYPE_STRING:
return strcmp(a->value.stringVal, b->value.stringVal);
case TYPE_BOOL:
return a->value.boolVal - b->value.boolVal;
case TYPE_DATE:
if (a->value.dateVal < b->value.dateVal) {
return -1;
}
if (a->value.dateVal > b->value.dateVal) {
return 1;
}
return 0;
default:
return 0;
}
}
SmartBPlusTreeNode *DataBaseOps::CreateBplusTreeNode(bool isLeaf, int order)
{
std::shared_ptr<SmartBPlusTreeNode> sNode = std::make_shared<SmartBPlusTreeNode>(order, isLeaf);
if (!sNode) {
return nullptr;
}
return sNode.get();
}
TableIndex *DataBaseOps::CreateTableIndex(const char *columnName)
{
const int bplusTreeOrder = 4;
if (table->indexCount >= MAX_INDEXES) {
return nullptr;
}
int colIndex = -1;
for (int i = 0; i < table->columnCount; i++) {
if (strcmp(table->columns[i].name, columnName) == 0) {
colIndex = i;
break;
}
}
if (colIndex == -1) {
return nullptr;
}
TableIndex *index = &table->indexes[table->indexCount];
std::copy_n(columnName, MAX_COLUMN_NAME - 1, index->name);
index->columnIndex = colIndex;
index->root = CreateBplusTreeNode(true, bplusTreeOrder);
index->height = 1;
index->keyCount = 0;
table->columns[colIndex].hasIndex = true;
table->indexCount++;
return index;
}
void DataBaseOps::DeleteFromIndex(TableIndex *index, int key)
{
const int formatBufferSize = 32;
char buffer[formatBufferSize];
std::ostringstream oss;
oss << "Index delete: key=" << key << "\n";
std::string message = oss.str();
std::copy(message.begin(), message.end(), buffer);
buffer[message.size()] = '\0';
printf("%s", buffer);
index->keyCount--;
}
DataBaseOps::DataBaseOps(const char *tableName, ColumnDef *columns, int columnCount)
{
const int initialRowId = 1;
table = std::make_unique<DatabaseTable>();
if (!table) {
printf("no memory for DatabaseTable pointer");
}
*table.get() = DatabaseTable{};
std::copy_n(tableName, MAX_TABLE_NAME - 1, table->name);
table->createdAt = time(nullptr);
table->nextRowId = initialRowId;
for (int i = 0; i < columnCount; i++) {
table->columns[i] = columns[i];
}
table->columnCount = columnCount;
for (int i = 0; i < MAX_ROWS; i++) {
SmartTableRow tableRow(columnCount);
table->rows[i] = tableRow;
}
}
DataBaseOps::~DataBaseOps() {}
SmartTableRow *DataBaseOps::FindTableRow(int rowId)
{
for (int i = 0; i < table->rowCount; i++) {
if (!table->rows[i].deleted && table->rows[i].rowId == rowId) {
return &table->rows[i];
}
}
return nullptr;
}
int DataBaseOps::InsertTableRow(DataCell *cells)
{
if (table->rowCount >= MAX_ROWS) {
return -1;
}
for (int i = 0; i < MAX_ROWS; i++) {
if (table->rows[i].deleted || table->rows[i].rowId == 0) {
SmartTableRow *row = &table->rows[i];
for (int j = 0; j < table->columnCount; j++) {
row->cells[j] = cells[j];
}
row->rowId = table->nextRowId++;
row->deleted = false;
row->createdAt = time(nullptr);
row->updatedAt = row->createdAt;
table->rowCount++;
return row->rowId;
}
}
return -1;
}
bool DataBaseOps::UpdateTableRow(int rowId, DataCell *newCells)
{
SmartTableRow *row = FindTableRow(rowId);
if (!row) {
return false;
}
DataCell *oldCells = static_cast<DataCell *>(malloc(sizeof(DataCell) * table->columnCount));
if (!oldCells) {
return false;
}
std::copy(row->cells.get(), row->cells.get() + table->columnCount, oldCells);
for (int i = 0; i < table->columnCount; i++) {
if (!newCells[i].isNull) {
row->cells[i] = newCells[i];
}
}
row->updatedAt = time(nullptr);
free(oldCells);
return true;
}
bool DataBaseOps::DeleteTableRow(int rowId)
{
SmartTableRow *row = FindTableRow(rowId);
if (!row) {
return false;
}
for (int i = 0; i < table->indexCount; i++) {
TableIndex *index = &table->indexes[i];
DeleteFromIndex(index, rowId);
}
row->deleted = true;
table->rowCount--;
return true;
}
bool DataBaseOps::BeginTransaction()
{
if (table->inTransaction) {
return false;
}
table->inTransaction = true;
return true;
}
bool DataBaseOps::CommitTransaction()
{
if (!table->inTransaction) {
return false;
}
table->inTransaction = false;
return true;
}
bool DataBaseOps::RollbackTransaction()
{
if (!table->inTransaction) {
return false;
}
table->inTransaction = false;
return true;
}
void DataBaseOps::PrintTableSchema()
{
int schemaColumnWidth = 20;
int schemaTypeWidth = 10;
int schemaFlagWidth = 8;
printf("\n=== 表结构: %s ===\n", table->name);
printf("创建时间: %s\n", FormatDate(table->createdAt));
printf("行数: %d\n", table->rowCount);
printf("列数: %d\n\n", table->columnCount);
printf("%-*s %-*s %-*s %-*s %-*s\n", schemaColumnWidth, "列名", schemaTypeWidth, "类型", schemaFlagWidth, "非空",
schemaFlagWidth, "主键", schemaFlagWidth, "索引");
printf("%s\n", "------------------------------------------------------------");
for (int i = 0; i < table->columnCount; i++) {
ColumnDef *col = &table->columns[i];
printf("%-*s %-*s %-*s %-*s %-*s\n", schemaColumnWidth, col->name, schemaTypeWidth, DataTypeToString(col->type),
schemaFlagWidth, col->notNull ? "YES" : "NO", schemaFlagWidth, col->isPrimary ? "YES" : "NO",
schemaFlagWidth, col->hasIndex ? "YES" : "NO");
}
}
void DataBaseOps::PrintQueryResult(SmartQueryResult *result)
{
if (!result || result->error != ERR_NONE) {
printf("查询错误: %s\n", result->errorMsg);
return;
}
printf("\n查询结果 (%d 行):\n", result->rowCount);
}
SmartQueryResult *DataBaseOps::ExecuteSelectQuery(const char *whereClause)
{
const int maxQueryResults = 100;
std::vector<std::string> colNames;
for (int i = 0; i < table->columnCount; i++) {
std::string strTemp(table->columns[i].name);
colNames.push_back(strTemp);
}
std::vector<std::vector<DataCell>> data;
int rowCount = 0;
for (int i = 0; i < maxQueryResults; i++) {
if (!table->rows[i].deleted && table->rows[i].rowId > 0) {
DataCell *pCell = table->rows[i].cells.get();
std::vector<DataCell> dataCellVec;
for (int j = 0; j < table->columnCount; j++) {
DataCell item = pCell[j];
dataCellVec.push_back(item);
}
data.push_back(dataCellVec);
rowCount++;
}
}
queryResult = std::make_unique<SmartQueryResult>(table->columnCount, colNames, data);
return queryResult.get();
}
extern "C" {
static void PrintSystemInfo(int maxTableCount)
{
printf("=== 简易关系型数据库系统启动 ===\n");
printf("版本: 1.0.0\n");
printf("最大表数: %d\n", maxTableCount);
printf("最大行数: %d\n", MAX_ROWS);
printf("最大列数: %d\n", MAX_COLUMNS);
printf("页面大小: %d bytes\n\n", PAGE_SIZE);
}
static void PrintSummary(int operationCount)
{
printf("\n数据库系统正常关闭。\n");
printf("总计执行操作: %d\n", operationCount);
}
static std::unique_ptr<DataBaseOps> CreateUserTable(int &operationCount)
{
const int userColumnCount = 8;
printf("创建示例表: users\n");
ColumnDef userColumns[] = {
{"id", TYPE_INT, 0, true, true, false, "0"}, {"username", TYPE_STRING, 50, true, false, true, ""},
{"email", TYPE_STRING, 100, true, false, true, ""}, {"age", TYPE_INT, 0, false, false, false, "0"},
{"salary", TYPE_FLOAT, 0, false, false, false, "0.0"}, {"is_active", TYPE_BOOL, 0, false, false, false, "true"},
{"created_at", TYPE_DATE, 0, false, false, false, ""}, {"updated_at", TYPE_DATE, 0, false, false, false, ""}};
std::unique_ptr<DataBaseOps> ops = std::make_unique<DataBaseOps>("users", userColumns, userColumnCount);
if (!ops) {
printf("创建表失败!\n");
return nullptr;
}
ops->CreateTableIndex("username");
ops->CreateTableIndex("email");
operationCount += THREE;
return ops;
}
static int InsertUserSampleData(DataBaseOps *ops, int &operationCount)
{
if (!ops) {
return -1;
}
printf("\n开始事务...\n");
ops->BeginTransaction();
operationCount++;
printf("\n插入示例数据...\n");
const int userColumnCount = 8;
DataCell user1[userColumnCount] = {CreateDataCell(TYPE_INT, "1"),
CreateDataCell(TYPE_STRING, "alice"),
CreateDataCell(TYPE_STRING, "alice@example.com"),
CreateDataCell(TYPE_INT, "25"),
CreateDataCell(TYPE_FLOAT, "50000.0"),
CreateDataCell(TYPE_BOOL, "true"),
CreateDataCell(TYPE_DATE, "2023-10-20"),
CreateDataCell(TYPE_DATE, "2023-10-20")};
DataCell user2[userColumnCount] = {CreateDataCell(TYPE_INT, "2"),
CreateDataCell(TYPE_STRING, "bob"),
CreateDataCell(TYPE_STRING, "bob@example.com"),
CreateDataCell(TYPE_INT, "30"),
CreateDataCell(TYPE_FLOAT, "60000.0"),
CreateDataCell(TYPE_BOOL, "true"),
CreateDataCell(TYPE_DATE, "2023-10-21"),
CreateDataCell(TYPE_DATE, "2023-10-21")};
int id1 = ops->InsertTableRow(user1);
int id2 = ops->InsertTableRow(user2);
operationCount += 3;
printf("插入完成: id1=%d, id2=%d\n", id1, id2);
printf("\n提交事务...\n");
ops->CommitTransaction();
operationCount++;
return (id1 > 0 && id2 > 0) ? 0 : -1;
}
int DatabaseOpsDemo()
{
const int maxTableCount = 50;
const int formatBufferSize = 32;
int operationCount = 0;
PrintSystemInfo(maxTableCount);
auto ops = CreateUserTable(operationCount);
if (!ops) {
return -1;
}
if (InsertUserSampleData(ops.get(), operationCount) < 0) {
printf("插入示例数据失败!\n");
return -1;
}
ops->PrintTableSchema();
printf("\n执行查询: SELECT * FROM users\n");
SmartQueryResult *result = ops->ExecuteSelectQuery("");
if (result) {
ops->PrintQueryResult(result);
}
operationCount++;
PrintSummary(operationCount);
return 0;
}
}