간단한 데이터베이스 구현 --Part2 - 세계에서 가장 간단한 SQL 컴파일러와 가상 머신

2 부 - 세계에서 가장 간단한 SQL 컴파일러와 가상 머신

우리는 재현 sqlite가 있습니다. SQLite는 프론트 엔드 (프론트 엔드) 스트링을 분석하고, 바이트 코드를 출력하는 SQL 컴파일러이다.

바이트 코드는 (파트 1에서 언급)을 처리하기 위해 가상 머신에 전달된다.

SQLite는 아키텍처

이 차트에서 봐, 우리는 가상 머신 (VM)에 전달 된 데이터 바이트 코드 후 처리 된 SQL 명령 Processer (SQL 명령 프로세서를) 볼 수 있습니다.

문제는 두 단계 (SQL 컴파일러와 가상 머신 참조)으로 나누어 져는 많은 장점을 가지고 :

  • 각 부분의 복잡성 감소 (예 : 가상 머신은 구문 오류에 대해 걱정할 필요가 없습니다, SQL 컴파일러가 처리 한)
  • 그것은 한 번만 일반적인 문의에 대한 컴파일러 (나는 당신이 효율성을 향상시킬 수 있도록 동일한 쿼리의 요구는 한 번만 컴파일 생각), 및 효율성을 향상시킬 수있는 바이트 코드 캐시를 할 수 있습니다.

그래서 우리는 주요 기능을 재구성하고, 두 개의 새로운 키워드를 지원해야합니다.

 int main(int argc, char* argv[]) {
   InputBuffer* input_buffer = new_input_buffer();
   while (true) {
     print_prompt();
     read_input(input_buffer);

-    if (strcmp(input_buffer->buffer, ".exit") == 0) {
-      exit(EXIT_SUCCESS);
-    } else {
-      printf("Unrecognized command '%s'.\n", input_buffer->buffer);

+    // SQL编译器
+ 	 // 检查是否为元命令
+    if (input_buffer->buffer[0] == '.') {
+      switch (do_meta_command(input_buffer)) {
+        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_UNRECOGNIZED_STATEMENT):
+        printf("Unrecognized keyword at start of '%s'.\n",
+               input_buffer->buffer);
+        continue;
+    }
+    // 将字节码传递给虚拟机
+    execute_statement(&statement);
+    printf("Executed.\n");
   }
 }

마찬가지로 ".exit"은 비 SQL 문은 "메타 명령"(메타 명령)했다. 그들은 점과 모든 시작은, 그래서 우리는 별도의 기능에 그들과 함께 그들과 거래를 확인합니다.

다음으로, 우리는 단계를 추가, 우리는 바이트 코드로 입력을해야합니다.

마지막으로, 우리는 우리의 가상 머신이다 바이트 코드 전송 기능을 수행 할 준비가 될 것입니다.

참고 우리는 또한 두 단계 열거 (ENUM)에서 성공과 실패를 정의 할 필요가있다.

typedef enum {
  META_COMMAND_SUCCESS,
  META_COMMAND_UNRECOGNIZED_COMMAND
} MetaCommandResult;

typedef enum {
  PREPARE_SUCCESS,
  PREPARE_UNRECOGNIZED_STATEMENT
} PrepareResult;

난 아무데도 ENUM 코드를 사용하고 있으므로 C 언어는, 예외를 지원하지 않습니다. 내가 열거의 멤버를 처리하지 않는 문을 전환하면 우리가 보장 할 수 있도록, 다음 C 컴파일러가 오류를보고 각 기능의 처리 결과가.

위안 명령 또는 전용 ".exit".

MetaCommandResult do_meta_command(InputBuffer* input_buffer) {
  if (strcmp(input_buffer->buffer, ".exit") == 0) {
    exit(EXIT_SUCCESS);
  } else {
    return META_COMMAND_UNRECOGNIZED_COMMAND;
  }
}

"준비된 문"(우리의 SQL 컴파일러는) 현재는 두 가지 값이 포함되어 있습니다.

typedef enum {
  STATEMENT_INSERT,
  STATEMENT_SELECT
} StatementType;

typedef struct {
  StatementType type;
} Statement;

"준비된 문"우리는 두 단어를 이해, SQL을 이해하지 않습니다.

PrepareResult prepare_statement(InputBuffer* input_buffer,
                                Statement* statement) {
  if (strncmp(input_buffer->buffer, "insert", 6) == 0) {
    statement->type = STATEMENT_INSERT;
    return PREPARE_SUCCESS;
  }
  if (strcmp(input_buffer->buffer, "select") == 0) {
    statement->type = STATEMENT_SELECT;
    return PREPARE_SUCCESS;
  }

  return PREPARE_UNRECOGNIZED_STATEMENT;
}

키워드 삽입 뒤 데이터를 따를 것 때문에 우리가, strncmp를 삽입 (처음 n 문자가 동일한 비교)하는 데 사용합니다.

마지막으로, execute_statement 기능은 스텁 (스텁, 내가 뭘 모르는)의 수를 포함, 진정한이 실행되지 있습니다.

void execute_statement(Statement* statement) {
  switch (statement->type) {
    case (STATEMENT_INSERT):
      printf("This is where we would do an insert.\n");
      break;
    case (STATEMENT_SELECT):
      printf("This is where we would do a select.\n");
      break;
  }
}

잘못 될 수있는 코드가 없기 때문에, 오류 코드를 반환하지 않습니다.

이러한 재건, 우리는 이제 두 개의 새로운 키워드 식별 (삽입을 선택) 할 수 있습니다

~ ./db
db > insert foo bar
This is where we would do an insert.
Executed.
db > delete foo
Unrecognized keyword at start of 'delete foo'.
db > select
This is where we would do a select.
Executed.
db > .tables
Unrecognized command '.tables'
db > .exit
~

연습 결과 :
결과
우리의 데이터베이스 프레임 워크는 데이터가 저장되어있는 경우 매우 좋지 않아, 모양을 취하고, 다음 섹션, 우리는 삽입 구현하고 선택합니다.

다음은 코드 섹션의 수정입니다 :

@@ -10,6 +10,23 @@ struct InputBuffer_t {
 } InputBuffer;
 
+typedef enum {
+  META_COMMAND_SUCCESS,
+  META_COMMAND_UNRECOGNIZED_COMMAND
+} MetaCommandResult;
+
+typedef enum { PREPARE_SUCCESS, PREPARE_UNRECOGNIZED_STATEMENT } PrepareResult;
+
+typedef enum { STATEMENT_INSERT, STATEMENT_SELECT } StatementType;
+
+typedef struct {
+  StatementType type;
+} Statement;
+
 InputBuffer* new_input_buffer() {
   InputBuffer* input_buffer = malloc(sizeof(InputBuffer));
   input_buffer->buffer = NULL;
@@ -40,17 +57,67 @@ void close_input_buffer(InputBuffer* input_buffer) {
     free(input_buffer);
 }
 
+MetaCommandResult do_meta_command(InputBuffer* input_buffer) {
+  if (strcmp(input_buffer->buffer, ".exit") == 0) {
+    close_input_buffer(input_buffer);
+    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;
+    return PREPARE_SUCCESS;
+  }
+  if (strcmp(input_buffer->buffer, "select") == 0) {
+    statement->type = STATEMENT_SELECT;
+    return PREPARE_SUCCESS;
+  }
+
+  return PREPARE_UNRECOGNIZED_STATEMENT;
+}
+
+void execute_statement(Statement* statement) {
+  switch (statement->type) {
+    case (STATEMENT_INSERT):
+      printf("This is where we would do an insert.\n");
+      break;
+    case (STATEMENT_SELECT):
+      printf("This is where we would do a select.\n");
+      break;
+  }
+}
+
 int main(int argc, char* argv[]) {
   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)) {
+        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_UNRECOGNIZED_STATEMENT):
+        printf("Unrecognized keyword at start of '%s'.\n",
+               input_buffer->buffer);
+        continue;
+    }
+
+    execute_statement(&statement);
+    printf("Executed.\n");
   }
 }
게시 된 113 개 원래 기사 · 원 찬양 30 ·은 30000 +를 볼

추천

출처blog.csdn.net/Radium_1209/article/details/104051765