实现一个简单的Database3(译文)

计算机英语第二版译文与答案大全 计算机英语教材的核心内容之一是专业术语和定义。这些术语通常分为不同的类别,如编程语言、软件工程、网络技术、数据库管理等。每一类术语都有其独特的语境和应用领域。例如,编程语言类别的术语可能包括”variable”(变量)、”function”(函数)、”object”(对象)等。这些术语不仅需要被记住和理解,还需要在编程实践或相关文档阅读中被准确使用。在学习这些术语时,应注重其在实际代码或文档中的应用,这有助于加深记忆并理解术语背后的逻辑。 阅读详情

前文回顾

实现一个简单的Database3(译文)

译注:cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第三篇,主要是实现数据库的实现内存中的数据结构并存储数据

Part 3 在内存中,只追加的单表数据库

我们从一个小型的,有许多限制的数据库开始。现在数据库将:

  • 支持两个操作:插入一行并打印所有行
  • 数据驻留在内存中(没有持久化到磁盘)
  • 支持单个、硬编码的表

我们的硬编码表将用来存储用户数据,看起来就行下面展示的这样:

columntype
idinteger
usernamevarchar(32)
emailvarchar(255)

这是一个简单的方案,但是它将让我们的数据库能够支持不同的数据类型和不同大小的文本数据类型。插入语句现在看起来像下面这样:

    insert 1 cstack foo@bar.com

这意味我们需要升级prepare_statement()函数来解析参数:

if (strncmp(input_buffer->buffer, "insert", 6) == 0) {
      statement->type = STATEMENT_INSERT;
    +    int args_assigned = sscanf(
    +        input_buffer->buffer, "insert %d %s %s", &(statement->row_to_insert.id),
    +        statement->row_to_insert.username, statement->row_to_insert.email);
    +    if (args_assigned < 3) {
    +      return PREPARE_SYNTAX_ERROR;
    +    }
      return PREPARE_SUCCESS;
    }
    if (strcmp(input_buffer->buffer, "select") == 0) {

我们把这些解析出的的参数存储到Statement对象中的一个新的数据结构Row中。

+#define COLUMN_USERNAME_SIZE 32
    +#define COLUMN_EMAIL_SIZE 255
    +typedef struct {
    +  uint32_t id;
    +  char username[COLUMN_USERNAME_SIZE];
    +  char email[COLUMN_EMAIL_SIZE];
    +} Row;
    +
     typedef struct {
       StatementType type;
    +  Row row_to_insert;  // only used by insert statement
     } Statement;

现在我们需要copy这些数据到其他一些代表table的数据结构中。SQLite为了支持快速查找、插入和删除操作而使用B-tree。我们将从一些简单的开始。像B-tree,它把行数据分组成页(pages),但是为了替换把这些页(pages)组织成一颗树的这种方法,这里我们把页来组织成数组(array)。

这是我的计划:

  • 存储行数据到叫做页(pages)的内存块中
  • 每页尽量多的去存储适合他的大小的数据(在页的大小范围内,尽量多的存储数据)
  • 在每页中行数据将被序列化为紧凑表示(compact representation)
  • 页只有在需要时候才会被分配
  • 保持固定大小的指针数组指向页

首先我们定义一个紧凑表示的行(row):

 +#define size_of_attribute(Struct, Attribute) sizeof(((Struct*)0)->Attribute)
    +
    +const uint32_t ID_SIZE = size_of_attribute(Row, id);
    +const uint32_t USERNAME_SIZE = size_of_attribute(Row, username);
    +const uint32_t EMAIL_SIZE = size_of_attribute(Row, email);
    +const uint32_t ID_OFFSET = 0;
    +const uint32_t USERNAME_OFFSET = ID_OFFSET + ID_SIZE;
    +const uint32_t EMAIL_OFFSET = USERNAME_OFFSET + USERNAME_SIZE;
    +const uint32_t ROW_SIZE = ID_SIZE + USERNAME_SIZE + EMAIL_SIZE;

这意味着一个序列化的行的布局看起来就像下面这样:

columnsize (bytes)offset
id40
username324
email25536
total291

译注:画个图来直观的看一下这个行数据存储格式

我们还需要编码来转换紧凑表示。(即把数据序列化与反序列化)

+void serialize_row(Row* source, void* destination) {
    +  memcpy(destination + ID_OFFSET, &(source->id), ID_SIZE);
    +  memcpy(destination + USERNAME_OFFSET, &(source->username), USERNAME_SIZE);
    +  memcpy(destination + EMAIL_OFFSET, &(source->email), EMAIL_SIZE);
    +}
    +
    +void deserialize_row(void* source, Row* destination) {
    +  memcpy(&(destination->id), source + ID_OFFSET, ID_SIZE);
    +  memcpy(&(destination->username), source + USERNAME_OFFSET, USERNAME_SIZE);
    +  memcpy(&(destination->email), source + EMAIL_OFFSET, EMAIL_SIZE);
    +}

接下来,实现一个表的结构指向存储行的页并跟踪页中有多少行:

+const uint32_t PAGE_SIZE = 4096;
    +#define TABLE_MAX_PAGES 100
    +const uint32_t ROWS_PER_PAGE = PAGE_SIZE / ROW_SIZE;
    +const uint32_t TABLE_MAX_ROWS = ROWS_PER_PAGE * TABLE_MAX_PAGES;
    +
    +typedef struct {
    +  uint32_t num_rows;
    +  void* pages[TABLE_MAX_PAGES];
    +} Table;

我把数据页大小设定为4KB,因为它与大多数计算机架构的虚拟内存系统中使用数据页大小相同。这意味着数据库中的一个数据页的大小和系统中的一页大小正好相同。操作系统在把数据页移入或者移出内存的时候会作为一个完整的单位来操作,而不会拆散他们。

在分配page时我设置了一个很随意的限制,限制分配100个page。当切换到一个tree结构时,我们数据库的最大限制就只是受到系统文件的大小限制了(尽管我仍然是限制在内存中一次可以有多少page可以保持)。

行不能超出page的边界。由于page在内存中可能不会彼此相邻,这个假设可以让读/写行数据更简单。

说到这一点,下面是我们如何弄清楚在内存中去哪里读/写特定行。

+void* row_slot(Table* table, uint32_t row_num) {
    +  uint32_t page_num = row_num / ROWS_PER_PAGE;
    +  void* page = table->pages[page_num];
    +  if (page == NULL) {
    +    // Allocate memory only when we try to access page
    +    page = table->pages[page_num] = malloc(PAGE_SIZE);
    +  }
    +  uint32_t row_offset = row_num % ROWS_PER_PAGE;
    +  uint32_t byte_offset = row_offset * ROW_SIZE;
    +  return page + byte_offset;
    +}

现在我们通过execute_statement()函数可以从表结构中读/写了。

-void execute_statement(Statement* statement) {
    +ExecuteResult execute_insert(Statement* statement, Table* table) {
    +  if (table->num_rows >= TABLE_MAX_ROWS) {
    +    return EXECUTE_TABLE_FULL;
    +  }
    +
    +  Row* row_to_insert = &(statement->row_to_insert);
    +
    +  serialize_row(row_to_insert, row_slot(table, table->num_rows));
    +  table->num_rows += 1;
    +
    +  return EXECUTE_SUCCESS;
    +}
    +
    +ExecuteResult execute_select(Statement* statement, Table* table) {
    +  Row row;
    +  for (uint32_t i = 0; i < table->num_rows; i++) {
    +    deserialize_row(row_slot(table, i), &row);
    +    print_row(&row);
    +  }
    +  return EXECUTE_SUCCESS;
    +}
    +
    +ExecuteResult execute_statement(Statement* statement, Table* table) {
       switch (statement->type) {
         case (STATEMENT_INSERT):
    -      printf("This is where we would do an insert.\n");
    -      break;
    +      return execute_insert(statement, table);
         case (STATEMENT_SELECT):
    -      printf("This is where we would do a select.\n");
    -      break;
    +      return execute_select(statement, table);
       }
     }

最后,我们需要初始化table,创建各自的内存释放函数并且需要处理一些报错情况:

 + Table* new_table() {
    +  Table* table = (Table*)malloc(sizeof(Table));
    +  table->num_rows = 0;
    +  for (uint32_t i = 0; i < TABLE_MAX_PAGES; i++) {
    +     table->pages[i] = NULL;
    +  }
    +  return table;
    +}
    +
    +void free_table(Table* table) {
    +    for (int i = 0; table->pages[i]; i++) {
    +    free(table->pages[i]);
    +    }
    +    free(table);
    +}

在主函数中调用table初始化,并处理报错:

int main(int argc, char* argv[]) {
    +  Table* table = new_table();
      InputBuffer* input_buffer = new_input_buffer();
      while (true) {
        print_prompt();
    @@ -105,13 +203,22 @@ int main(int argc, char* argv[]) {
        switch (prepare_statement(input_buffer, &statement)) {
          case (PREPARE_SUCCESS):
            break;
    +      case (PREPARE_SYNTAX_ERROR):
    +        printf("Syntax error. Could not parse statement.\n");
    +        continue;
          case (PREPARE_UNRECOGNIZED_STATEMENT):
            printf("Unrecognized keyword at start of '%s'.\n",
                   input_buffer->buffer);
            continue;
        }
    
    -    execute_statement(&statement);
    -    printf("Executed.\n");
    +    switch (execute_statement(&statement, table)) {
    +      case (EXECUTE_SUCCESS):
    +        printf("Executed.\n");
    +        break;
    +      case (EXECUTE_TABLE_FULL):
    +        printf("Error: Table full.\n");
    +        break;
    +    }
      }
    }

做了这些修改后我们就能实际保存数据到数据库了。

~ ./db
    db > insert 1 cstack foo@bar.com
    Executed.
    db > insert 2 bob bob@example.com
    Executed.
    db > select
    (1, cstack, foo@bar.com)
    (2, bob, bob@example.com)
    Executed.
    db > insert foo bar 1
    Syntax error. Could not parse statement.
    db > .exit
    ~

现在是写一些测试的好时机,有几个原因:

  • 我们计划大幅度修改存储表的数据结构,并且测试是可捕获回归
  • 还有一些边界条件我们没有手动测试(例如填满一张表)

我们将在下一部分中解决这些问题。现在,看一下这一部分完整的区别(与上一部分对比,行开头“+”为新增,“-”为删除):

@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>

 typedef struct {
   char* buffer;
@@ -10,6 +11,105 @@ typedef struct {
 } InputBuffer;

+typedef enum { EXECUTE_SUCCESS, EXECUTE_TABLE_FULL } ExecuteResult;
+
+typedef enum {
+  META_COMMAND_SUCCESS,
+  META_COMMAND_UNRECOGNIZED_COMMAND
+} MetaCommandResult;
+
+typedef enum {
+  PREPARE_SUCCESS,
+  PREPARE_SYNTAX_ERROR,
+  PREPARE_UNRECOGNIZED_STATEMENT
+ } PrepareResult;
+
+typedef enum { STATEMENT_INSERT, STATEMENT_SELECT } StatementType;
+
+#define COLUMN_USERNAME_SIZE 32
+#define COLUMN_EMAIL_SIZE 255
+typedef struct {
+  uint32_t id;
+  char username[COLUMN_USERNAME_SIZE];
+  char email[COLUMN_EMAIL_SIZE];
+} Row;
+
+typedef struct {
+  StatementType type;
+  Row row_to_insert; //only used by insert statement
+} Statement;
+
+#define size_of_attribute(Struct, Attribute) sizeof(((Struct*)0)->Attribute)
+
+const uint32_t ID_SIZE = size_of_attribute(Row, id);
+const uint32_t USERNAME_SIZE = size_of_attribute(Row, username);
+const uint32_t EMAIL_SIZE = size_of_attribute(Row, email);
+const uint32_t ID_OFFSET = 0;
+const uint32_t USERNAME_OFFSET = ID_OFFSET + ID_SIZE;
+const uint32_t EMAIL_OFFSET = USERNAME_OFFSET + USERNAME_SIZE;
+const uint32_t ROW_SIZE = ID_SIZE + USERNAME_SIZE + EMAIL_SIZE;
+
+const uint32_t PAGE_SIZE = 4096;
+#define TABLE_MAX_PAGES 100
+const uint32_t ROWS_PER_PAGE = PAGE_SIZE / ROW_SIZE;
+const uint32_t TABLE_MAX_ROWS = ROWS_PER_PAGE * TABLE_MAX_PAGES;
+
+typedef struct {
+  uint32_t num_rows;
+  void* pages[TABLE_MAX_PAGES];
+} Table;
+
+void print_row(Row* row) {
+  printf("(%d, %s, %s)\n", row->id, row->username, row->email);
+}
+
+void serialize_row(Row* source, void* destination) {
+  memcpy(destination + ID_OFFSET, &(source->id), ID_SIZE);
+  memcpy(destination + USERNAME_OFFSET, &(source->username), USERNAME_SIZE);
+  memcpy(destination + EMAIL_OFFSET, &(source->email), EMAIL_SIZE);
+}
+
+void deserialize_row(void *source, Row* destination) {
+  memcpy(&(destination->id), source + ID_OFFSET, ID_SIZE);
+  memcpy(&(destination->username), source + USERNAME_OFFSET, USERNAME_SIZE);
+  memcpy(&(destination->email), source + EMAIL_OFFSET, EMAIL_SIZE);
+}
+
+void* row_slot(Table* table, uint32_t row_num) {
+  uint32_t page_num = row_num / ROWS_PER_PAGE;
+  void *page = table->pages[page_num];
+  if (page == NULL) {
+     // Allocate memory only when we try to access page
+     page = table->pages[page_num] = malloc(PAGE_SIZE);
+  }
+  uint32_t row_offset = row_num % ROWS_PER_PAGE;
+  uint32_t byte_offset = row_offset * ROW_SIZE;
+  return page + byte_offset;
+}
+
+Table* new_table() {
+  Table* table = (Table*)malloc(sizeof(Table));
+  table->num_rows = 0;
+  for (uint32_t i = 0; i < TABLE_MAX_PAGES; i++) {
+     table->pages[i] = NULL;
+  }
+  return table;
+}
+
+void free_table(Table* table) {
+  for (int i = 0; table->pages[i]; i++) {
+     free(table->pages[i]);
+  }
+  free(table);
+}
+
 InputBuffer* new_input_buffer() {
   InputBuffer* input_buffer = (InputBuffer*)malloc(sizeof(InputBuffer));
   input_buffer->buffer = NULL;
@@ -40,17 +140,105 @@ void close_input_buffer(InputBuffer* input_buffer) {
     free(input_buffer);
 }

+MetaCommandResult do_meta_command(InputBuffer* input_buffer, Table *table) {
+  if (strcmp(input_buffer->buffer, ".exit") == 0) {
+    close_input_buffer(input_buffer);
+    free_table(table);
+    exit(EXIT_SUCCESS);
+  } else {
+    return META_COMMAND_UNRECOGNIZED_COMMAND;
+  }
+}
+
+PrepareResult prepare_statement(InputBuffer* input_buffer,
+                                Statement* statement) {
+  if (strncmp(input_buffer->buffer, "insert", 6) == 0) {
+    statement->type = STATEMENT_INSERT;
+    int args_assigned = sscanf(
+    input_buffer->buffer, "insert %d %s %s", &(statement->row_to_insert.id),
+    statement->row_to_insert.username, statement->row_to_insert.email
+    );
+    if (args_assigned < 3) {
+    return PREPARE_SYNTAX_ERROR;
+    }
+    return PREPARE_SUCCESS;
+  }
+  if (strcmp(input_buffer->buffer, "select") == 0) {
+    statement->type = STATEMENT_SELECT;
+    return PREPARE_SUCCESS;
+  }
+
+  return PREPARE_UNRECOGNIZED_STATEMENT;
+}
+
+ExecuteResult execute_insert(Statement* statement, Table* table) {
+  if (table->num_rows >= TABLE_MAX_ROWS) {
+     return EXECUTE_TABLE_FULL;
+  }
+
+  Row* row_to_insert = &(statement->row_to_insert);
+
+  serialize_row(row_to_insert, row_slot(table, table->num_rows));
+  table->num_rows += 1;
+
+  return EXECUTE_SUCCESS;
+}
+
+ExecuteResult execute_select(Statement* statement, Table* table) {
+  Row row;
+  for (uint32_t i = 0; i < table->num_rows; i++) {
+     deserialize_row(row_slot(table, i), &row);
+     print_row(&row);
+  }
+  return EXECUTE_SUCCESS;
+}
+
+ExecuteResult execute_statement(Statement* statement, Table *table) {
+  switch (statement->type) {
+    case (STATEMENT_INSERT):
+           return execute_insert(statement, table);
+    case (STATEMENT_SELECT):
+    return execute_select(statement, table);
+  }
+}
+
 int main(int argc, char* argv[]) {
+  Table* table = new_table();
   InputBuffer* input_buffer = new_input_buffer();
   while (true) {
     print_prompt();
     read_input(input_buffer);

-    if (strcmp(input_buffer->buffer, ".exit") == 0) {
-      close_input_buffer(input_buffer);
-      exit(EXIT_SUCCESS);
-    } else {
-      printf("Unrecognized command '%s'.\n", input_buffer->buffer);
+    if (input_buffer->buffer[0] == '.') {
+      switch (do_meta_command(input_buffer, table)) {
+        case (META_COMMAND_SUCCESS):
+          continue;
+        case (META_COMMAND_UNRECOGNIZED_COMMAND):
+          printf("Unrecognized command '%s'\n", input_buffer->buffer);
+          continue;
+      }
+    }
+
+    Statement statement;
+    switch (prepare_statement(input_buffer, &statement)) {
+      case (PREPARE_SUCCESS):
+        break;
+      case (PREPARE_SYNTAX_ERROR):
+    printf("Syntax error. Could not parse statement.\n");
+    continue;
+      case (PREPARE_UNRECOGNIZED_STATEMENT):
+        printf("Unrecognized keyword at start of '%s'.\n",
+               input_buffer->buffer);
+        continue;
+    }
+
+    switch (execute_statement(&statement, table)) {
+    case (EXECUTE_SUCCESS):
+        printf("Executed.\n");
+        break;
+    case (EXECUTE_TABLE_FULL):
+        printf("Error: Table full.\n");
+        break;
     }
   }

Enjoy GreatSQL 😃

关于 GreatSQL

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

Solidworks曲面建模学习(三)——样条曲线 本文主要演示平面的空间样条曲线的一些绘制。 阅读详情

相关推荐

Fluent温度超限调试:从能量方程到网格优化的实战指南

本文深入解析Fluent中温度超限问题的诊断与解决方法,从能量方程机制到网格优化策略,提供实战指南。通过分析温度与焓的换算关系,探讨典型场景如能量方程发散、局部网格质量差等,并给出五步调试法及高级命令应用,帮助工程师有效解决温度计算异常问题。

weixin_29045585的博客 530

实现一个简单的Database5(译文)

GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。 GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。 前文回顾 实现一个简单的Database1(译文) 实现一个简单的Database2(译文) 实现一个简单的Database3(译文) 实现一个简单的Database4(译文) 译注:cstsck在github维护了一个简单的、类似SQLite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第五篇,主要是实现数据持久化 Part

GreatSQL2021的博客 460

积木报表导出数据量太大报错

‌性能问题‌:‌当数据量非常大时,‌积木报表在导出过程中可能会遇到性能瓶颈,‌导致导出过程缓慢甚至失败。‌解决这一问题的方法包括优化SQL查询、‌调整分页大小、‌使用更适合处理大量数据的库(‌如阿里巴巴的EasyExcel)‌进行导出,‌或者采用异步处理的方式来避免接口超时1。‌内存溢出‌:‌如果报表工具或其依赖的库不支持流式(‌分批)‌导出,‌大量数据的处理可能会导致内存溢出。‌数据处理方式‌:‌如果待导出的数据包含特殊字符,‌如英文双引号或等号,‌这可能导致JSON反序列化报错。

Activiti工作流 1906

实现一个简单的Database4(译文)

cstsck在github维护了一个简单的、类似SQLite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第四篇,主要是使用rspec对目前实现的功能进行测试并解决测试出现BUG 译注:cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第四篇,主要是使用r

GreatSQL2021的博客 300

自定义css属性实现渐变边框动画

自定义cs属性实现渐变边框动画

lemon的博客 1875

嵌入式SD/TF卡通用协议-SDIO协议

为了驱动SD卡,首先的第一步就是观察SD卡引脚接线情况,通常我们在画原理图时,都是使用的SD卡卡槽与MCU进行接线。SD卡可以使用SDIO协议和SPI协议进行通信,这里我们主要介绍SDIO协议。下图中的TF卡只是容量小一点的SD卡。以F1C100S为例,接线图如下所示:我们发现上图中的TF卡使用的协议为SDIO协议,主要有4根数据线,1根命令线,1根时钟线组合而成。为了驱动这个SD/TF卡我们就需要去了解SDIO协议的时序。

qq_1033275663的博客 3052

实现一个简单的Database2(译文)

前文回顾:实现一个简单的Database1(译文) 译注:cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第二篇,主要是实现数据库的前端组件,编译器与虚拟机部分功能 Part 2 世界上最简单的SQL编译器与虚拟机 我们正在实现一个sqlite的克隆版本。sqlite的前端是SQL编译器,编译器用来解析字符串并输出一个内部的表示,叫做字节码。 这些字节码被传到虚拟机(virtual machine),在虚拟机中,字节码将被

GreatSQL2021的博客 486

PC网站实现微信扫码登录功能(二)

上篇我们介绍了怎么申请账号以及最后拿到appId和appSecret,如果有不清楚的可以看一下 PC网站实现微信扫码登录功能(一) 下面我就来说一下怎样在PC端怎么实现扫码登录功能。 一、进入官方文档网站 https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html 其实官网对过程描述的已经非常细致了。并且提供了两种扫码方式。一种是跳转二维码扫描页面,另一种是内嵌式二维码。大家可以

qq_35771266的博客 3万+

实现一个简单的Database1(译文)

cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第四篇,主要是使用rspec对目前实现的功能进行测试并解决测试出现BUG_

GreatSQL2021的博客 243

Centos7.6操作系统安装+Bond配置(600GB磁盘版本)

1.安装前准备工作 准备centos7.6操作系统镜像 CentOS-7-x86_64-DVD-1810.iso 服务器安装一般都是在BMC界面操作,所以安装前需要在BMC界面挂载好操作系统镜像 重启服务器后自动进入安装界面。 华为大数据集群安装操作系统配置

小时光 6010

AI Agent开发第82课-手把手教你把paddleocr-vl做成mcp使其在DIFY里运行

本文详解如何将国产顶尖多模态 OCR 模型 PaddleOCR-VL 封装为标准 MCP(Model Calling Protocol)服务,并通过自研的 HTTP-based MCP Client 接入 Dify 1.10,实现 AI Agent 在对话中自动识别并调用 OCR 能力。该方案已在某头部保险公司真实业务流程中落地,使用了当前最先进的“Agentic AI 原生”设计思想。

打造全国最全的AI Agent开发知识领域的博客 1625

实现一个简单的Database12(译文)

GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。 GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。 作者: 花家舍 文章来源:GreatSQL社区原创 前文回顾 实现一个简单的Database系列 译注:cstack在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第十一篇,主要是实现递归搜索B-Tree Part 11 递归搜索B-Tree 上次我们在插入第15行数据报错的时

GreatSQL2021的博客 136

解锁IPG Photonics SmartWeld系统,开启焊接新时代

SmartWeld 系统是 IPG Photonics 研发的一款先进的激光焊接解决方案,它隶属于自动化激光焊接系统类别 ,但却凭借一系列创新技术和独特设计,在众多同类产品中脱颖而出。该系统基于 IPG 在光纤激光技术领域的深厚积累,融合了先进的光束控制、智能监测和自动化控制等技术,旨在为工业制造提供高效、精准且稳定的焊接工艺。与传统激光焊接系统相比,SmartWeld 系统的独特之处首先体现在其光束控制技术上。它能够精确地调整激光束的能量分布、光斑大小和形状 ,以适应不同材料和焊接工艺的需求。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 1430

实现一个简单的Database10(译文)

GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。 GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。 作者: 花家舍 文章来源:GreatSQL社区原创 前文回顾 实现一个简单的Database系列 译注:cstack在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第十篇,主要是实现B-tree中叶子节点分裂 Part 10 叶子节点分裂 我们 B-Tree 只有一个节点,这看

GreatSQL2021的博客 626

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

实现一个简单的Database9(译文)

cstack在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第九篇,主要是实现B-tree的二叉搜索并解决主键重复问题

GreatSQL2021的博客 124

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

实现一个简单Database8(译文)

前文回顾 实现一个简单的Database系列 译注:cstack在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第八篇,主要是对B-tree的叶子节点格式的实现 Part 8 B-Tree叶子节点格式 我们准备把表的格式从非排序的数组格式行(rows)改成B-Tree。这是一个相当大变化,需要多个篇幅才能实现。在本文结束时,我们将定义叶子节点的布局,支持插入键值对儿到单节点的B-Tree。但是首先,来回顾一下把数据结构(从数组a

GreatSQL2021的博客 171

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

实现一个简单Database6

GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。 GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。 前文回顾 实现一个简单的Database1(译文) 实现一个简单的Database2(译文) 实现一个简单的Database3(译文) 实现一个简单的Database4(译文) 实现一个简单的Database5(译文) 译注:cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本

GreatSQL2021的博客 382

实现一个简单Database7

GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。 GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。 前文回顾 实现一个简单的Database1(译文) 实现一个简单的Database2(译文) 实现一个简单的Database3(译文) 实现一个简单的Database4(译文) 实现一个简单的Database5(译文) 实现一个简单的Database6(译文) 译注:cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的

GreatSQL2021的博客 342

php create database,CREATE DATABASE语句解释

本文为mariadb官方手册:CREATE DATABASE的译文。语法CREATE [OR REPLACE] {DATABASE | SCHEMA} [IF NOT EXISTS] db_name[create_specification] ...create_specification:[DEFAULT] CHARACTER SET [=] charset_name| [DEFAULT] CO...

weixin_36073392的博客 457

官宣:Cloudberry Database 正式加入 Apache 孵化器

Cloudberry 由 Greenplum Database 原始开发者创建,是一款领先且成熟的开源大规模并行处理(Massively Parallel Processing,MPP)数据库。它基于开源版的 Pivotal Greenplum Database® 衍生而来,但采用了更新的 PostgreSQL 内核,并具备更先进的企业级功能。Cloudberry 可以作为数据仓库使用,也可用于大规模分析和 AI/ML 工作负载。

m0_54979897的博客 1078

基于PaddleOCR的漫画自动翻译工具:从文字检测到译文渲染完整实现

OCR(光学字符识别)技术通过计算机视觉方法将图像中的文字转换为可编辑文本,其核心原理涉及文字区域检测和字符识别两个关键环节。在自然语言处理领域,机器翻译技术基于深度学习模型实现跨语言语义转换,为多语言内容理解提供技术支撑。漫画自动翻译结合OCR与机器翻译,解决了外语漫画阅读的语言障碍问题,通过文字检测、识别、翻译和译文渲染的完整流水线,实现翻页即译的流畅体验。该技术特别适用于日文、韩文漫画的本地化处理,其中PaddleOCR凭借对漫画版面的优化检测能力,配合离线翻译模型,可在无网络环境下完成高质量翻译任务

weixin_30432579的博客 430

H2 数据库的 .db 数据库 文件 存放位置 修改

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33868027的博客 4308

linux 下查看sqlite的 .db 数据库文件

转载▼ sqlite的.db文件打开:    在windows可以用firefox浏览器插件 sqlite manager。    在linux(本示例用centos)下:      1、先去sqlite主页http://www.sqlite.org/.跳转到下载页http://www.sqlite.org/download.html,下载linux版本的sqlite安装文件。

Sam 的专栏 1万+

ggkegg帮助文档 | 译文二

使用 ggkegg 的一个优点是使用 ggplot2和 ggraph 的能力有效地可视化全局地图。在这里,我提出了一个例子,可视化 log2倍变化值从一些微生物组实验中获得的全球地图。首先,我们加载必要的数据,这些数据可以从调查 KO 的数据集中获得,也可以从管道中获得,比如 HUMANN3。

BioinfoDu 1050

用 C# 实现一个简单的日志框架

译文链接: https://www.infoworld.com/article/2980677/implement-a-simple-logger-in-csharp.html 在你的 .NET 程序中经常会记录一些日志或者错误,为了实现这个功能,你可能会使用市面上那些现成的日志框架(log4net,nlog ...),当然你也可以设计并开发一个自己的日志框架,在这篇文章中,我将会带你一起如何轻松愉快的创建一个自定义日志框架,并且一步一步的构建这个简单的 logger。 首先,你要知道什么叫 log t.

一线码农的专栏 2571

[开源作品] 译文管理系统

译文管理平台 Author Sure Yu E-mail yusureyes@163.com 项目介绍   这是一个用于管理多语言资源的译文管理系统,由于用户分布于全球各地,公司的 App 需要显示多语言,Android 和 iOS 有大量的译文需要管理,手工维护极其麻烦,于是这个系统诞生了,方便 translator 在平台...

weixin_33908217的博客 309
上一篇: 实现一个简单的Database2(译文)
下一篇: 实现一个简单的Database4(译文)
GreatSQL社区
博客等级 码龄5年 1210粉丝 390原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值