lbug 0.12.3-dev.2 → 0.12.3-dev.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +2 -6
  2. package/lbug-source/.github/workflows/ci-workflow.yml +9 -2
  3. package/lbug-source/CMakeLists.txt +15 -6
  4. package/lbug-source/Makefile +1 -2
  5. package/lbug-source/README.md +2 -6
  6. package/lbug-source/benchmark/serializer.py +24 -3
  7. package/lbug-source/dataset/demo-db/csv/copy.cypher +4 -4
  8. package/lbug-source/dataset/demo-db/graph-std/demo_indices_follows.parquet +0 -0
  9. package/lbug-source/dataset/demo-db/graph-std/demo_indices_livesin.parquet +0 -0
  10. package/lbug-source/dataset/demo-db/graph-std/demo_indptr_follows.parquet +0 -0
  11. package/lbug-source/dataset/demo-db/graph-std/demo_indptr_livesin.parquet +0 -0
  12. package/lbug-source/dataset/demo-db/graph-std/demo_mapping_city.parquet +0 -0
  13. package/lbug-source/dataset/demo-db/graph-std/demo_mapping_user.parquet +0 -0
  14. package/lbug-source/dataset/demo-db/graph-std/demo_metadata.parquet +0 -0
  15. package/lbug-source/dataset/demo-db/graph-std/demo_nodes_city.parquet +0 -0
  16. package/lbug-source/dataset/demo-db/graph-std/demo_nodes_user.parquet +0 -0
  17. package/lbug-source/dataset/demo-db/graph-std/schema.cypher +4 -0
  18. package/lbug-source/dataset/demo-db/parquet/copy.cypher +4 -4
  19. package/lbug-source/extension/httpfs/test/test_files/http.test +1 -0
  20. package/lbug-source/scripts/antlr4/Cypher.g4 +1 -1
  21. package/lbug-source/scripts/antlr4/hash.md5 +1 -1
  22. package/lbug-source/scripts/generate_binary_demo.sh +1 -1
  23. package/lbug-source/src/antlr4/Cypher.g4 +1 -1
  24. package/lbug-source/src/binder/bind/bind_ddl.cpp +23 -13
  25. package/lbug-source/src/catalog/catalog.cpp +5 -4
  26. package/lbug-source/src/catalog/catalog_entry/node_table_catalog_entry.cpp +8 -1
  27. package/lbug-source/src/catalog/catalog_entry/rel_group_catalog_entry.cpp +7 -0
  28. package/lbug-source/src/function/function_collection.cpp +2 -1
  29. package/lbug-source/src/function/table/CMakeLists.txt +1 -0
  30. package/lbug-source/src/function/table/disk_size_info.cpp +322 -0
  31. package/lbug-source/src/include/binder/ddl/bound_create_table_info.h +10 -6
  32. package/lbug-source/src/include/catalog/catalog_entry/node_table_catalog_entry.h +5 -3
  33. package/lbug-source/src/include/catalog/catalog_entry/rel_group_catalog_entry.h +4 -2
  34. package/lbug-source/src/include/common/constants.h +1 -0
  35. package/lbug-source/src/include/function/table/simple_table_function.h +6 -0
  36. package/lbug-source/src/include/optimizer/count_rel_table_optimizer.h +49 -0
  37. package/lbug-source/src/include/optimizer/logical_operator_visitor.h +6 -0
  38. package/lbug-source/src/include/parser/ddl/create_table_info.h +3 -1
  39. package/lbug-source/src/include/planner/operator/logical_operator.h +1 -0
  40. package/lbug-source/src/include/planner/operator/scan/logical_count_rel_table.h +84 -0
  41. package/lbug-source/src/include/processor/operator/physical_operator.h +1 -0
  42. package/lbug-source/src/include/processor/operator/scan/count_rel_table.h +62 -0
  43. package/lbug-source/src/include/processor/operator/scan/scan_node_table.h +2 -2
  44. package/lbug-source/src/include/processor/plan_mapper.h +2 -0
  45. package/lbug-source/src/include/storage/storage_manager.h +1 -0
  46. package/lbug-source/src/include/storage/storage_version_info.h +1 -7
  47. package/lbug-source/src/include/storage/table/node_table.h +6 -1
  48. package/lbug-source/src/include/storage/table/parquet_node_table.h +103 -0
  49. package/lbug-source/src/include/storage/table/parquet_rel_table.h +91 -0
  50. package/lbug-source/src/include/storage/table/rel_table.h +2 -2
  51. package/lbug-source/src/include/transaction/transaction.h +2 -0
  52. package/lbug-source/src/main/query_result/materialized_query_result.cpp +2 -2
  53. package/lbug-source/src/optimizer/CMakeLists.txt +1 -0
  54. package/lbug-source/src/optimizer/count_rel_table_optimizer.cpp +217 -0
  55. package/lbug-source/src/optimizer/logical_operator_visitor.cpp +6 -0
  56. package/lbug-source/src/optimizer/optimizer.cpp +6 -0
  57. package/lbug-source/src/parser/transform/transform_ddl.cpp +6 -1
  58. package/lbug-source/src/planner/operator/logical_operator.cpp +2 -0
  59. package/lbug-source/src/planner/operator/scan/CMakeLists.txt +1 -0
  60. package/lbug-source/src/planner/operator/scan/logical_count_rel_table.cpp +24 -0
  61. package/lbug-source/src/processor/map/CMakeLists.txt +1 -0
  62. package/lbug-source/src/processor/map/map_count_rel_table.cpp +55 -0
  63. package/lbug-source/src/processor/map/plan_mapper.cpp +3 -0
  64. package/lbug-source/src/processor/operator/persistent/reader/parquet/parquet_reader.cpp +4 -0
  65. package/lbug-source/src/processor/operator/physical_operator.cpp +2 -0
  66. package/lbug-source/src/processor/operator/scan/CMakeLists.txt +1 -0
  67. package/lbug-source/src/processor/operator/scan/count_rel_table.cpp +137 -0
  68. package/lbug-source/src/processor/operator/scan/scan_multi_rel_tables.cpp +24 -2
  69. package/lbug-source/src/processor/operator/scan/scan_node_table.cpp +44 -8
  70. package/lbug-source/src/processor/operator/scan/scan_rel_table.cpp +12 -2
  71. package/lbug-source/src/storage/storage_manager.cpp +37 -6
  72. package/lbug-source/src/storage/table/CMakeLists.txt +2 -0
  73. package/lbug-source/src/storage/table/parquet_node_table.cpp +338 -0
  74. package/lbug-source/src/storage/table/parquet_rel_table.cpp +388 -0
  75. package/lbug-source/test/api/api_test.cpp +18 -0
  76. package/lbug-source/test/common/string_format.cpp +9 -1
  77. package/lbug-source/test/copy/copy_test.cpp +4 -4
  78. package/lbug-source/test/graph_test/CMakeLists.txt +1 -1
  79. package/lbug-source/test/include/test_runner/test_group.h +11 -1
  80. package/lbug-source/test/optimizer/optimizer_test.cpp +46 -0
  81. package/lbug-source/test/runner/e2e_test.cpp +7 -1
  82. package/lbug-source/test/test_files/demo_db/demo_db_graph_std.test +77 -0
  83. package/lbug-source/test/test_helper/CMakeLists.txt +1 -1
  84. package/lbug-source/test/test_helper/test_helper.cpp +33 -1
  85. package/lbug-source/test/test_runner/CMakeLists.txt +1 -1
  86. package/lbug-source/test/test_runner/insert_by_row.cpp +6 -8
  87. package/lbug-source/test/test_runner/multi_copy_split.cpp +2 -4
  88. package/lbug-source/test/test_runner/test_parser.cpp +3 -0
  89. package/lbug-source/test/transaction/checkpoint_test.cpp +1 -1
  90. package/lbug-source/test/transaction/transaction_test.cpp +19 -15
  91. package/lbug-source/third_party/antlr4_cypher/cypher_parser.cpp +2761 -2701
  92. package/lbug-source/third_party/antlr4_cypher/include/cypher_parser.h +2 -0
  93. package/lbug-source/tools/benchmark/count_rel_table.benchmark +5 -0
  94. package/lbug-source/tools/shell/embedded_shell.cpp +78 -3
  95. package/lbug-source/tools/shell/include/embedded_shell.h +2 -0
  96. package/lbug-source/tools/shell/linenoise.cpp +3 -3
  97. package/lbug-source/tools/shell/test/test_helper.py +1 -1
  98. package/lbug-source/tools/shell/test/test_shell_basics.py +12 -0
  99. package/lbug-source/tools/shell/test/test_shell_commands.py +19 -0
  100. package/package.json +1 -1
  101. package/prebuilt/lbugjs-darwin-arm64.node +0 -0
  102. package/prebuilt/lbugjs-linux-arm64.node +0 -0
  103. package/prebuilt/lbugjs-linux-x64.node +0 -0
  104. package/prebuilt/lbugjs-win32-x64.node +0 -0
@@ -687,6 +687,8 @@ public:
687
687
  antlr4::tree::TerminalNode *AS();
688
688
  OC_QueryContext *oC_Query();
689
689
  KU_IfNotExistsContext *kU_IfNotExists();
690
+ antlr4::tree::TerminalNode *WITH();
691
+ KU_OptionsContext *kU_Options();
690
692
  KU_CreateNodeConstraintContext *kU_CreateNodeConstraint();
691
693
 
692
694
 
@@ -0,0 +1,5 @@
1
+ -NAME count_rel_table
2
+ -PRERUN CREATE NODE TABLE account(ID INT64 PRIMARY KEY); CREATE REL TABLE follows(FROM account TO account); COPY account FROM "dataset/snap/amazon0601/parquet/amazon-nodes.parquet"; COPY follows FROM "dataset/snap/amazon0601/parquet/amazon-edges.parquet";
3
+ -QUERY MATCH ()-[r:follows]->() RETURN COUNT(*)
4
+ ---- 1
5
+ 3387388
@@ -17,7 +17,14 @@
17
17
 
18
18
  #include "binder/binder.h"
19
19
  #include "catalog/catalog.h"
20
+ #include "catalog/catalog_entry/catalog_entry.h"
21
+ #include "catalog/catalog_entry/index_catalog_entry.h"
22
+ #include "catalog/catalog_entry/node_table_catalog_entry.h"
23
+ #include "catalog/catalog_entry/rel_group_catalog_entry.h"
24
+ #include "catalog/catalog_entry/scalar_macro_catalog_entry.h"
25
+ #include "catalog/catalog_entry/sequence_catalog_entry.h"
20
26
  #include "common/exception/parser.h"
27
+ #include "extension/extension_manager.h"
21
28
  #include "keywords.h"
22
29
  #include "parser/parser.h"
23
30
  #include "printer/json_printer.h"
@@ -62,8 +69,9 @@ struct ShellCommand {
62
69
  const char* HIGHLIGHT = ":highlight";
63
70
  const char* ERRORS = ":render_errors";
64
71
  const char* COMPLETE = ":render_completion";
65
- const std::array<const char*, 12> commandList = {HELP, CLEAR, QUIT, MAX_ROWS, MAX_WIDTH, MODE,
66
- STATS, MULTI, SINGLE, HIGHLIGHT, ERRORS, COMPLETE};
72
+ const char* SCHEMA = ":schema";
73
+ const std::array<const char*, 13> commandList = {HELP, CLEAR, QUIT, MAX_ROWS, MAX_WIDTH, MODE,
74
+ STATS, MULTI, SINGLE, HIGHLIGHT, ERRORS, COMPLETE, SCHEMA};
67
75
  } shellCommand;
68
76
 
69
77
  const char* TAB = " ";
@@ -263,6 +271,22 @@ void completion(const char* buffer, linenoiseCompletions* lc) {
263
271
  return;
264
272
  }
265
273
 
274
+ // RETURN *; completion for MATCH and CALL queries.
275
+ // Trigger when buffer ends with ')' or ') ' after a MATCH pattern or CALL function.
276
+ if (regex_search(buf, std::regex(R"(\)\s*$)"))) {
277
+ // Check for MATCH pattern: MATCH(var:Table) or MATCH (var:Table)
278
+ bool isMatchQuery =
279
+ regex_search(buf, std::regex(R"(^\s*MATCH\s*\()", std::regex_constants::icase));
280
+ // Check for CALL function: CALL func_name(...) or CALL func_name (...)
281
+ bool isCallFunction =
282
+ regex_search(buf, std::regex(R"(^\s*CALL\s+\w+\s*\()", std::regex_constants::icase));
283
+ if (isMatchQuery || isCallFunction) {
284
+ std::string suffix = buf.back() == ')' ? " RETURN *;" : "RETURN *;";
285
+ linenoiseAddCompletion(lc, (buf + suffix).c_str());
286
+ return;
287
+ }
288
+ }
289
+
266
290
  // Node table name completion. Match patterns that include an open bracket `(` with no closing
267
291
  // bracket `)`, and a colon `:` sometime after the open bracket.
268
292
  if (regex_search(buf, std::regex("^[^]*\\([^\\)]*:[^\\)]*$"))) {
@@ -413,6 +437,8 @@ int EmbeddedShell::processShellCommands(std::string lineStr) {
413
437
  setErrors(arg);
414
438
  } else if (command == shellCommand.COMPLETE) {
415
439
  setComplete(arg);
440
+ } else if (command == shellCommand.SCHEMA) {
441
+ printSchema();
416
442
  } else {
417
443
  printf("Error: Unknown command: \"%s\". Enter \":help\" for help\n", lineStr.c_str());
418
444
  printf("Did you mean: \"%s\"?\n", findClosestCommand(lineStr).c_str());
@@ -533,6 +559,17 @@ std::vector<std::unique_ptr<QueryResult>> EmbeddedShell::processInput(std::strin
533
559
  historyLine = input;
534
560
  return queryResults;
535
561
  }
562
+ // Normalize trailing semicolons
563
+ if (!unicodeInput.empty() && unicodeInput.back() == ';') {
564
+ // trim trailing ;
565
+ while (!unicodeInput.empty() && unicodeInput.back() == ';') {
566
+ unicodeInput.pop_back();
567
+ }
568
+ if (unicodeInput.empty()) {
569
+ return queryResults;
570
+ }
571
+ unicodeInput += ';';
572
+ }
536
573
  // process shell commands
537
574
  if (!continueLine && unicodeInput[0] == ':') {
538
575
  processShellCommands(unicodeInput);
@@ -811,7 +848,6 @@ void EmbeddedShell::setComplete(const std::string& completeString) {
811
848
  } else {
812
849
  printf("Cannot parse '%s' to toggle completion highlighting. Expect 'on' or 'off'.\n",
813
850
  completeStringLower.c_str());
814
- return;
815
851
  }
816
852
  }
817
853
 
@@ -832,6 +868,7 @@ void EmbeddedShell::printHelp() {
832
868
  printf("%s%s [on|off] %stoggle error highlighting on or off\n", TAB, shellCommand.ERRORS, TAB);
833
869
  printf("%s%s [on|off] %stoggle completion highlighting on or off\n", TAB, shellCommand.COMPLETE,
834
870
  TAB);
871
+ printf("%s%s %sprint database schema\n", TAB, shellCommand.SCHEMA, TAB);
835
872
  printf("\n");
836
873
  printf("%sNote: you can change and see several system configurations, such as num-threads, \n",
837
874
  TAB);
@@ -1561,5 +1598,43 @@ void EmbeddedShell::printTruncatedExecutionResult(QueryResult& queryResult) cons
1561
1598
  }
1562
1599
  }
1563
1600
 
1601
+ void EmbeddedShell::printSchema() {
1602
+ std::stringstream ss;
1603
+ auto clientContext = conn->getClientContext();
1604
+ bool transactionStarted = false;
1605
+ if (transaction::Transaction::Get(*clientContext) == NULL) {
1606
+ transaction::TransactionContext::Get(*clientContext)
1607
+ ->beginReadTransaction(); // start transaction to get schema
1608
+ transactionStarted = true;
1609
+ }
1610
+ auto extensionCypher = extension::ExtensionManager::Get(*clientContext)->toCypher();
1611
+ if (!extensionCypher.empty()) {
1612
+ ss << extensionCypher << std::endl;
1613
+ }
1614
+ const auto catalog = catalog::Catalog::Get(*clientContext);
1615
+ auto transaction = transaction::Transaction::Get(*clientContext);
1616
+ catalog::ToCypherInfo toCypherInfo;
1617
+ for (const auto& nodeTableEntry :
1618
+ catalog->getNodeTableEntries(transaction, false /* useInternal */)) {
1619
+ ss << nodeTableEntry->toCypher(toCypherInfo) << std::endl;
1620
+ }
1621
+ catalog::RelGroupToCypherInfo relTableToCypherInfo(clientContext);
1622
+ for (const auto& entry : catalog->getRelGroupEntries(transaction, false /* useInternal */)) {
1623
+ ss << entry->toCypher(relTableToCypherInfo) << std::endl;
1624
+ }
1625
+ catalog::RelGroupToCypherInfo relGroupToCypherInfo(clientContext);
1626
+ for (const auto sequenceEntry : catalog->getSequenceEntries(transaction)) {
1627
+ ss << sequenceEntry->toCypher(relGroupToCypherInfo) << std::endl;
1628
+ }
1629
+ for (auto macroName : catalog->getMacroNames(transaction)) {
1630
+ ss << catalog->getScalarMacroFunction(transaction, macroName)->toCypher(macroName)
1631
+ << std::endl;
1632
+ }
1633
+ if (transactionStarted) {
1634
+ transaction::TransactionContext::Get(*clientContext)->commit();
1635
+ }
1636
+ printf("%s", ss.str().c_str());
1637
+ }
1638
+
1564
1639
  } // namespace main
1565
1640
  } // namespace lbug
@@ -71,6 +71,8 @@ private:
71
71
 
72
72
  void setComplete(const std::string& completeString);
73
73
 
74
+ void printSchema();
75
+
74
76
  void checkConfidentialStatement(const std::string& query, QueryResult* queryResult,
75
77
  std::string& input);
76
78
 
@@ -3306,7 +3306,7 @@ bool cypherComplete(const char* z) {
3306
3306
  /* Token: */
3307
3307
  /* State: ** SEMI WS OTHER */
3308
3308
  /* 0 INVALID: */ {
3309
- 1,
3309
+ 2,
3310
3310
  0,
3311
3311
  2,
3312
3312
  },
@@ -3553,8 +3553,8 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char* buf, size_t buflen,
3553
3553
  // check if this forms a complete Cypher statement or not or if enter is pressed in
3554
3554
  // the middle of a line
3555
3555
  l.buf[l.len] = '\0';
3556
- if (l.buf[0] != ':' &&
3557
- (l.pos != l.len || linenoiseAllWhitespace(l.buf) || !cypherComplete(l.buf))) {
3556
+ if (l.buf[0] != ':' && l.pos == l.len && !linenoiseAllWhitespace(l.buf) &&
3557
+ !cypherComplete(l.buf)) {
3558
3558
  if (linenoiseEditInsertMulti(&l, "\r\n")) {
3559
3559
  return -1;
3560
3560
  }
@@ -11,7 +11,7 @@ if sys.platform == "win32":
11
11
  LBUG_EXEC_PATH = os.path.join(
12
12
  LBUG_ROOT,
13
13
  "build",
14
- "release",
14
+ "relwithdebinfo",
15
15
  "tools",
16
16
  "shell",
17
17
  "lbug",
@@ -289,6 +289,18 @@ def test_shell_auto_completion(temp_db) -> None:
289
289
  assert test.shell_process.expect_exact(["(0 tuples)", pexpect.EOF]) == 0
290
290
 
291
291
 
292
+ def test_double_semicolon(temp_db) -> None:
293
+ test = (
294
+ ShellTest()
295
+ .add_argument(temp_db)
296
+ .statement("CREATE NODE TABLE User(name STRING, PRIMARY KEY(name));")
297
+ .statement("CREATE REL TABLE Follows(FROM User TO User, since INT64);")
298
+ .statement('MATCH (a:User)-[f:Follows]->(b:User) RETURN a.name, b.name, f.since;;')
299
+ )
300
+ result = test.run()
301
+ result.check_stdout("(0 tuples)")
302
+
303
+
292
304
  def test_shell_unicode_input(temp_db) -> None:
293
305
  test = (
294
306
  ShellTest()
@@ -18,6 +18,7 @@ def test_help(temp_db) -> None:
18
18
  " :highlight [on|off] toggle syntax highlighting on or off",
19
19
  " :render_errors [on|off] toggle error highlighting on or off",
20
20
  " :render_completion [on|off] toggle completion highlighting on or off",
21
+ " :schema print database schema",
21
22
  "",
22
23
  " Note: you can change and see several system configurations, such as num-threads, ",
23
24
  " timeout, and progress_bar using Cypher CALL statements.",
@@ -636,6 +637,24 @@ def test_completion_highlighting(temp_db) -> None:
636
637
  )
637
638
 
638
639
 
640
+ def test_schema_with_tables(temp_db) -> None:
641
+ test = (
642
+ ShellTest()
643
+ .add_argument(temp_db)
644
+ .statement("CREATE NODE TABLE User(name STRING, age INT64, PRIMARY KEY (name));")
645
+ .statement("CREATE NODE TABLE City(name STRING, population INT64, PRIMARY KEY (name));")
646
+ .statement("CREATE REL TABLE Follows(FROM User TO User, since INT64);")
647
+ .statement("CREATE REL TABLE LivesIn(FROM User TO City);")
648
+ .statement(":schema")
649
+ )
650
+ result = test.run()
651
+ # Check that the schema output includes the created tables
652
+ result.check_stdout("CREATE NODE TABLE `User` (`name` STRING,`age` INT64, PRIMARY KEY(`name`));")
653
+ result.check_stdout("CREATE NODE TABLE `City` (`name` STRING,`population` INT64, PRIMARY KEY(`name`));")
654
+ result.check_stdout("CREATE REL TABLE `Follows` (FROM `User` TO `User`, `since` INT64,MANY_MANY);")
655
+ result.check_stdout("CREATE REL TABLE `LivesIn` (FROM `User` TO `City`, MANY_MANY);")
656
+
657
+
639
658
  def test_bad_command(temp_db) -> None:
640
659
  test = (
641
660
  ShellTest()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lbug",
3
- "version": "0.12.3-dev.2",
3
+ "version": "0.12.3-dev.21",
4
4
  "description": "An in-process property graph database management system built for query speed and scalability.",
5
5
  "main": "index.js",
6
6
  "module": "./index.mjs",
Binary file
Binary file
Binary file
Binary file