lbug 0.12.3-dev.9 → 0.13.0
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.
- package/lbug-source/.github/workflows/ci-workflow.yml +9 -2
- package/lbug-source/CMakeLists.txt +16 -7
- package/lbug-source/Makefile +15 -4
- package/lbug-source/benchmark/serializer.py +24 -3
- package/lbug-source/dataset/demo-db/csv/copy.cypher +4 -4
- package/lbug-source/dataset/demo-db/graph-std/demo_indices_follows.parquet +0 -0
- package/lbug-source/dataset/demo-db/graph-std/demo_indices_livesin.parquet +0 -0
- package/lbug-source/dataset/demo-db/graph-std/demo_indptr_follows.parquet +0 -0
- package/lbug-source/dataset/demo-db/graph-std/demo_indptr_livesin.parquet +0 -0
- package/lbug-source/dataset/demo-db/graph-std/demo_mapping_city.parquet +0 -0
- package/lbug-source/dataset/demo-db/graph-std/demo_mapping_user.parquet +0 -0
- package/lbug-source/dataset/demo-db/graph-std/demo_metadata.parquet +0 -0
- package/lbug-source/dataset/demo-db/graph-std/demo_nodes_city.parquet +0 -0
- package/lbug-source/dataset/demo-db/graph-std/demo_nodes_user.parquet +0 -0
- package/lbug-source/dataset/demo-db/graph-std/schema.cypher +4 -0
- package/lbug-source/dataset/demo-db/parquet/copy.cypher +4 -4
- package/lbug-source/extension/duckdb/src/catalog/duckdb_catalog.cpp +1 -1
- package/lbug-source/extension/duckdb/src/catalog/duckdb_table_catalog_entry.cpp +43 -4
- package/lbug-source/extension/duckdb/src/connector/duckdb_result_converter.cpp +6 -0
- package/lbug-source/extension/duckdb/src/connector/duckdb_secret_manager.cpp +1 -1
- package/lbug-source/extension/duckdb/src/function/duckdb_scan.cpp +49 -4
- package/lbug-source/extension/duckdb/src/include/catalog/duckdb_table_catalog_entry.h +6 -1
- package/lbug-source/extension/duckdb/src/include/function/duckdb_scan.h +2 -0
- package/lbug-source/extension/duckdb/test/test_files/duckdb.test +28 -0
- package/lbug-source/extension/extension_config.cmake +3 -2
- package/lbug-source/extension/httpfs/test/test_files/http.test +1 -0
- package/lbug-source/scripts/antlr4/Cypher.g4 +4 -4
- package/lbug-source/scripts/antlr4/hash.md5 +1 -1
- package/lbug-source/scripts/generate_binary_demo.sh +1 -1
- package/lbug-source/src/antlr4/Cypher.g4 +4 -4
- package/lbug-source/src/binder/bind/bind_ddl.cpp +97 -15
- package/lbug-source/src/binder/bind/bind_graph_pattern.cpp +30 -3
- package/lbug-source/src/catalog/catalog.cpp +6 -4
- package/lbug-source/src/catalog/catalog_entry/node_table_catalog_entry.cpp +8 -1
- package/lbug-source/src/catalog/catalog_entry/rel_group_catalog_entry.cpp +46 -7
- package/lbug-source/src/catalog/catalog_set.cpp +1 -0
- package/lbug-source/src/function/function_collection.cpp +2 -1
- package/lbug-source/src/function/table/CMakeLists.txt +1 -0
- package/lbug-source/src/function/table/disk_size_info.cpp +322 -0
- package/lbug-source/src/function/table/show_connection.cpp +6 -1
- package/lbug-source/src/function/table/show_tables.cpp +10 -2
- package/lbug-source/src/function/table/table_function.cpp +11 -2
- package/lbug-source/src/include/binder/ddl/bound_create_table_info.h +23 -6
- package/lbug-source/src/include/catalog/catalog_entry/node_table_catalog_entry.h +5 -3
- package/lbug-source/src/include/catalog/catalog_entry/rel_group_catalog_entry.h +21 -2
- package/lbug-source/src/include/catalog/catalog_entry/table_catalog_entry.h +7 -0
- package/lbug-source/src/include/common/constants.h +1 -0
- package/lbug-source/src/include/common/string_format.h +2 -2
- package/lbug-source/src/include/common/types/types.h +1 -0
- package/lbug-source/src/include/function/table/bind_data.h +12 -1
- package/lbug-source/src/include/function/table/simple_table_function.h +6 -0
- package/lbug-source/src/include/function/table/table_function.h +2 -0
- package/lbug-source/src/include/optimizer/count_rel_table_optimizer.h +49 -0
- package/lbug-source/src/include/optimizer/logical_operator_visitor.h +6 -0
- package/lbug-source/src/include/optimizer/order_by_push_down_optimizer.h +21 -0
- package/lbug-source/src/include/parser/ddl/create_table_info.h +3 -1
- package/lbug-source/src/include/planner/operator/logical_operator.h +1 -0
- package/lbug-source/src/include/planner/operator/logical_table_function_call.h +14 -1
- package/lbug-source/src/include/planner/operator/scan/logical_count_rel_table.h +84 -0
- package/lbug-source/src/include/processor/operator/physical_operator.h +1 -0
- package/lbug-source/src/include/processor/operator/scan/count_rel_table.h +62 -0
- package/lbug-source/src/include/processor/operator/scan/scan_node_table.h +2 -2
- package/lbug-source/src/include/processor/plan_mapper.h +2 -0
- package/lbug-source/src/include/storage/storage_manager.h +1 -0
- package/lbug-source/src/include/storage/storage_version_info.h +1 -1
- package/lbug-source/src/include/storage/table/foreign_rel_table.h +56 -0
- package/lbug-source/src/include/storage/table/node_table.h +6 -1
- package/lbug-source/src/include/storage/table/parquet_node_table.h +103 -0
- package/lbug-source/src/include/storage/table/parquet_rel_table.h +91 -0
- package/lbug-source/src/include/storage/table/rel_table.h +2 -2
- package/lbug-source/src/include/transaction/transaction.h +2 -0
- package/lbug-source/src/optimizer/CMakeLists.txt +3 -1
- package/lbug-source/src/optimizer/count_rel_table_optimizer.cpp +217 -0
- package/lbug-source/src/optimizer/limit_push_down_optimizer.cpp +12 -0
- package/lbug-source/src/optimizer/logical_operator_visitor.cpp +6 -0
- package/lbug-source/src/optimizer/optimizer.cpp +10 -0
- package/lbug-source/src/optimizer/order_by_push_down_optimizer.cpp +123 -0
- package/lbug-source/src/optimizer/projection_push_down_optimizer.cpp +5 -1
- package/lbug-source/src/parser/transform/transform_ddl.cpp +6 -1
- package/lbug-source/src/parser/transform/transform_expression.cpp +1 -1
- package/lbug-source/src/parser/transform/transform_graph_pattern.cpp +6 -1
- package/lbug-source/src/parser/transformer.cpp +7 -1
- package/lbug-source/src/planner/join_order/cardinality_estimator.cpp +11 -2
- package/lbug-source/src/planner/operator/logical_operator.cpp +2 -0
- package/lbug-source/src/planner/operator/logical_table_function_call.cpp +4 -0
- package/lbug-source/src/planner/operator/scan/CMakeLists.txt +1 -0
- package/lbug-source/src/planner/operator/scan/logical_count_rel_table.cpp +24 -0
- package/lbug-source/src/planner/plan/plan_join_order.cpp +16 -1
- package/lbug-source/src/processor/map/CMakeLists.txt +1 -0
- package/lbug-source/src/processor/map/map_count_rel_table.cpp +55 -0
- package/lbug-source/src/processor/map/plan_mapper.cpp +3 -0
- package/lbug-source/src/processor/operator/index_lookup.cpp +31 -23
- package/lbug-source/src/processor/operator/persistent/reader/parquet/parquet_reader.cpp +4 -0
- package/lbug-source/src/processor/operator/physical_operator.cpp +2 -0
- package/lbug-source/src/processor/operator/scan/CMakeLists.txt +1 -0
- package/lbug-source/src/processor/operator/scan/count_rel_table.cpp +137 -0
- package/lbug-source/src/processor/operator/scan/scan_multi_rel_tables.cpp +24 -2
- package/lbug-source/src/processor/operator/scan/scan_node_table.cpp +44 -8
- package/lbug-source/src/processor/operator/scan/scan_rel_table.cpp +18 -2
- package/lbug-source/src/storage/storage_manager.cpp +43 -6
- package/lbug-source/src/storage/table/CMakeLists.txt +3 -0
- package/lbug-source/src/storage/table/foreign_rel_table.cpp +63 -0
- package/lbug-source/src/storage/table/parquet_node_table.cpp +338 -0
- package/lbug-source/src/storage/table/parquet_rel_table.cpp +388 -0
- package/lbug-source/test/common/string_format.cpp +9 -1
- package/lbug-source/test/copy/copy_test.cpp +4 -4
- package/lbug-source/test/graph_test/CMakeLists.txt +1 -1
- package/lbug-source/test/include/test_runner/test_group.h +11 -1
- package/lbug-source/test/optimizer/optimizer_test.cpp +46 -0
- package/lbug-source/test/runner/e2e_test.cpp +7 -1
- package/lbug-source/test/test_files/demo_db/demo_db_graph_std.test +77 -0
- package/lbug-source/test/test_helper/CMakeLists.txt +1 -1
- package/lbug-source/test/test_helper/test_helper.cpp +33 -1
- package/lbug-source/test/test_runner/CMakeLists.txt +1 -1
- package/lbug-source/test/test_runner/insert_by_row.cpp +6 -8
- package/lbug-source/test/test_runner/multi_copy_split.cpp +2 -4
- package/lbug-source/test/test_runner/test_parser.cpp +3 -0
- package/lbug-source/test/transaction/checkpoint_test.cpp +1 -1
- package/lbug-source/test/transaction/transaction_test.cpp +19 -15
- package/lbug-source/third_party/antlr4_cypher/cypher_parser.cpp +2805 -2708
- package/lbug-source/third_party/antlr4_cypher/include/cypher_parser.h +7 -3
- package/lbug-source/tools/benchmark/count_rel_table.benchmark +5 -0
- package/lbug-source/tools/nodejs_api/package.json +4 -2
- package/lbug-source/tools/shell/embedded_shell.cpp +78 -3
- package/lbug-source/tools/shell/include/embedded_shell.h +2 -0
- package/lbug-source/tools/shell/linenoise.cpp +3 -3
- package/lbug-source/tools/shell/test/test_helper.py +1 -1
- package/lbug-source/tools/shell/test/test_shell_basics.py +12 -0
- package/lbug-source/tools/shell/test/test_shell_commands.py +19 -0
- package/package.json +9 -2
- package/prebuilt/lbugjs-darwin-arm64.node +0 -0
- package/prebuilt/lbugjs-linux-arm64.node +0 -0
- package/prebuilt/lbugjs-linux-x64.node +0 -0
- package/prebuilt/lbugjs-win32-x64.node +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
#include <optional>
|
|
2
|
+
|
|
1
3
|
#include "binder/binder.h"
|
|
2
4
|
#include "binder/ddl/bound_alter.h"
|
|
3
5
|
#include "binder/ddl/bound_create_sequence.h"
|
|
@@ -16,7 +18,9 @@
|
|
|
16
18
|
#include "common/types/types.h"
|
|
17
19
|
#include "function/cast/functions/cast_from_string_functions.h"
|
|
18
20
|
#include "function/sequence/sequence_functions.h"
|
|
21
|
+
#include "function/table/table_function.h"
|
|
19
22
|
#include "main/client_context.h"
|
|
23
|
+
#include "main/database_manager.h"
|
|
20
24
|
#include "parser/ddl/alter.h"
|
|
21
25
|
#include "parser/ddl/create_sequence.h"
|
|
22
26
|
#include "parser/ddl/create_table.h"
|
|
@@ -136,18 +140,9 @@ BoundCreateTableInfo Binder::bindCreateTableInfo(const CreateTableInfo* info) {
|
|
|
136
140
|
}
|
|
137
141
|
}
|
|
138
142
|
|
|
139
|
-
BoundCreateTableInfo Binder::bindCreateNodeTableInfo(const CreateTableInfo* info) {
|
|
140
|
-
auto propertyDefinitions = bindPropertyDefinitions(info->propertyDefinitions, info->tableName);
|
|
141
|
-
auto& extraInfo = info->extraInfo->constCast<ExtraCreateNodeTableInfo>();
|
|
142
|
-
validatePrimaryKey(extraInfo.pKName, propertyDefinitions);
|
|
143
|
-
auto boundExtraInfo = std::make_unique<BoundExtraCreateNodeTableInfo>(extraInfo.pKName,
|
|
144
|
-
std::move(propertyDefinitions));
|
|
145
|
-
return BoundCreateTableInfo(CatalogEntryType::NODE_TABLE_ENTRY, info->tableName,
|
|
146
|
-
info->onConflict, std::move(boundExtraInfo), clientContext->useInternalCatalogEntry());
|
|
147
|
-
}
|
|
148
|
-
|
|
149
143
|
void Binder::validateNodeTableType(const TableCatalogEntry* entry) {
|
|
150
|
-
if (entry->getType() != CatalogEntryType::NODE_TABLE_ENTRY
|
|
144
|
+
if (entry->getType() != CatalogEntryType::NODE_TABLE_ENTRY &&
|
|
145
|
+
entry->getType() != CatalogEntryType::FOREIGN_TABLE_ENTRY) {
|
|
151
146
|
throw BinderException(stringFormat("{} is not of type NODE.", entry->getName()));
|
|
152
147
|
}
|
|
153
148
|
}
|
|
@@ -168,6 +163,13 @@ void Binder::validateColumnExistence(const TableCatalogEntry* entry,
|
|
|
168
163
|
}
|
|
169
164
|
}
|
|
170
165
|
|
|
166
|
+
static std::string getStorage(const case_insensitive_map_t<Value>& options) {
|
|
167
|
+
if (options.contains(TableOptionConstants::REL_STORAGE_OPTION)) {
|
|
168
|
+
return options.at(TableOptionConstants::REL_STORAGE_OPTION).toString();
|
|
169
|
+
}
|
|
170
|
+
return "";
|
|
171
|
+
}
|
|
172
|
+
|
|
171
173
|
static ExtendDirection getStorageDirection(const case_insensitive_map_t<Value>& options) {
|
|
172
174
|
if (options.contains(TableOptionConstants::REL_STORAGE_DIRECTION_OPTION)) {
|
|
173
175
|
return ExtendDirectionUtil::fromString(
|
|
@@ -176,6 +178,18 @@ static ExtendDirection getStorageDirection(const case_insensitive_map_t<Value>&
|
|
|
176
178
|
return DEFAULT_EXTEND_DIRECTION;
|
|
177
179
|
}
|
|
178
180
|
|
|
181
|
+
BoundCreateTableInfo Binder::bindCreateNodeTableInfo(const CreateTableInfo* info) {
|
|
182
|
+
auto propertyDefinitions = bindPropertyDefinitions(info->propertyDefinitions, info->tableName);
|
|
183
|
+
auto& extraInfo = info->extraInfo->constCast<ExtraCreateNodeTableInfo>();
|
|
184
|
+
validatePrimaryKey(extraInfo.pKName, propertyDefinitions);
|
|
185
|
+
auto boundOptions = bindParsingOptions(extraInfo.options);
|
|
186
|
+
auto storage = getStorage(boundOptions);
|
|
187
|
+
auto boundExtraInfo = std::make_unique<BoundExtraCreateNodeTableInfo>(extraInfo.pKName,
|
|
188
|
+
std::move(propertyDefinitions), std::move(storage));
|
|
189
|
+
return BoundCreateTableInfo(CatalogEntryType::NODE_TABLE_ENTRY, info->tableName,
|
|
190
|
+
info->onConflict, std::move(boundExtraInfo), clientContext->useInternalCatalogEntry());
|
|
191
|
+
}
|
|
192
|
+
|
|
179
193
|
std::vector<PropertyDefinition> Binder::bindRelPropertyDefinitions(const CreateTableInfo& info) {
|
|
180
194
|
std::vector<PropertyDefinition> propertyDefinitions;
|
|
181
195
|
propertyDefinitions.emplace_back(
|
|
@@ -193,15 +207,82 @@ BoundCreateTableInfo Binder::bindCreateRelTableGroupInfo(const CreateTableInfo*
|
|
|
193
207
|
auto dstMultiplicity = RelMultiplicityUtils::getBwd(extraInfo.relMultiplicity);
|
|
194
208
|
auto boundOptions = bindParsingOptions(extraInfo.options);
|
|
195
209
|
auto storageDirection = getStorageDirection(boundOptions);
|
|
210
|
+
auto storage = getStorage(boundOptions);
|
|
211
|
+
std::optional<function::TableFunction> scanFunction = std::nullopt;
|
|
212
|
+
std::optional<std::unique_ptr<function::TableFuncBindData>> scanBindData = std::nullopt;
|
|
213
|
+
if (!storage.empty()) {
|
|
214
|
+
auto dotPos = storage.find('.');
|
|
215
|
+
if (dotPos != std::string::npos) {
|
|
216
|
+
// schema.table format, check if it's a foreign table
|
|
217
|
+
std::string dbName = storage.substr(0, dotPos);
|
|
218
|
+
std::string tableName = storage.substr(dotPos + 1);
|
|
219
|
+
auto transaction = transaction::Transaction::Get(*clientContext);
|
|
220
|
+
if (!dbName.empty()) {
|
|
221
|
+
auto attachedDB =
|
|
222
|
+
main::DatabaseManager::Get(*clientContext)->getAttachedDatabase(dbName);
|
|
223
|
+
if (attachedDB && attachedDB->getCatalog()->containsTable(transaction, tableName,
|
|
224
|
+
clientContext->useInternalCatalogEntry())) {
|
|
225
|
+
auto tableEntry = attachedDB->getCatalog()->getTableCatalogEntry(transaction,
|
|
226
|
+
tableName, clientContext->useInternalCatalogEntry());
|
|
227
|
+
if (tableEntry->getType() == CatalogEntryType::FOREIGN_TABLE_ENTRY) {
|
|
228
|
+
scanFunction = tableEntry->getScanFunction();
|
|
229
|
+
auto boundScanInfo =
|
|
230
|
+
tableEntry->getBoundScanInfo(clientContext, "" /* nodeUniqueName */);
|
|
231
|
+
scanBindData = std::move(boundScanInfo->bindData);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
196
237
|
// Bind from to pairs
|
|
197
238
|
node_table_id_pair_set_t nodePairsSet;
|
|
198
239
|
std::vector<NodeTableIDPair> nodePairs;
|
|
240
|
+
std::string foreignDatabaseName;
|
|
241
|
+
std::string foreignDatabaseType;
|
|
199
242
|
for (auto& [srcTableName, dstTableName] : extraInfo.srcDstTablePairs) {
|
|
200
243
|
auto srcEntry = bindNodeTableEntry(srcTableName);
|
|
201
244
|
validateNodeTableType(srcEntry);
|
|
202
245
|
auto dstEntry = bindNodeTableEntry(dstTableName);
|
|
203
246
|
validateNodeTableType(dstEntry);
|
|
204
|
-
|
|
247
|
+
|
|
248
|
+
// For foreign-backed rel tables, validate that FROM and TO are from same database
|
|
249
|
+
if (scanFunction.has_value()) {
|
|
250
|
+
// Both must be foreign tables
|
|
251
|
+
if (srcEntry->getType() != CatalogEntryType::FOREIGN_TABLE_ENTRY ||
|
|
252
|
+
dstEntry->getType() != CatalogEntryType::FOREIGN_TABLE_ENTRY) {
|
|
253
|
+
throw BinderException("Foreign-backed rel tables require both FROM and TO tables "
|
|
254
|
+
"to be foreign tables.");
|
|
255
|
+
}
|
|
256
|
+
// Extract database names from qualified table names
|
|
257
|
+
auto srcDotPos = srcTableName.find('.');
|
|
258
|
+
auto dstDotPos = dstTableName.find('.');
|
|
259
|
+
if (srcDotPos == std::string::npos || dstDotPos == std::string::npos) {
|
|
260
|
+
throw BinderException(
|
|
261
|
+
"Foreign-backed rel tables require qualified table names (database.table).");
|
|
262
|
+
}
|
|
263
|
+
auto srcDbName = srcTableName.substr(0, srcDotPos);
|
|
264
|
+
auto dstDbName = dstTableName.substr(0, dstDotPos);
|
|
265
|
+
if (srcDbName != dstDbName) {
|
|
266
|
+
throw BinderException(
|
|
267
|
+
stringFormat("Cannot create rel table with FROM and TO tables from different "
|
|
268
|
+
"databases. FROM is from '{}', TO is from '{}'.",
|
|
269
|
+
srcDbName, dstDbName));
|
|
270
|
+
}
|
|
271
|
+
// Get database type for display
|
|
272
|
+
auto attachedDB =
|
|
273
|
+
main::DatabaseManager::Get(*clientContext)->getAttachedDatabase(srcDbName);
|
|
274
|
+
if (attachedDB) {
|
|
275
|
+
foreignDatabaseName = stringFormat("{}({})", srcDbName, attachedDB->getDBType());
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// For foreign-backed rel tables, use FOREIGN_TABLE_ID since we don't reference local node
|
|
280
|
+
// tables
|
|
281
|
+
auto srcTableID =
|
|
282
|
+
scanFunction.has_value() ? common::FOREIGN_TABLE_ID : srcEntry->getTableID();
|
|
283
|
+
auto dstTableID =
|
|
284
|
+
scanFunction.has_value() ? common::FOREIGN_TABLE_ID : dstEntry->getTableID();
|
|
285
|
+
NodeTableIDPair pair{srcTableID, dstTableID};
|
|
205
286
|
if (nodePairsSet.contains(pair)) {
|
|
206
287
|
throw BinderException(
|
|
207
288
|
stringFormat("Found duplicate FROM-TO {}-{} pairs.", srcTableName, dstTableName));
|
|
@@ -209,9 +290,10 @@ BoundCreateTableInfo Binder::bindCreateRelTableGroupInfo(const CreateTableInfo*
|
|
|
209
290
|
nodePairsSet.insert(pair);
|
|
210
291
|
nodePairs.emplace_back(pair);
|
|
211
292
|
}
|
|
212
|
-
auto boundExtraInfo =
|
|
213
|
-
std::
|
|
214
|
-
|
|
293
|
+
auto boundExtraInfo = std::make_unique<BoundExtraCreateRelTableGroupInfo>(
|
|
294
|
+
std::move(propertyDefinitions), srcMultiplicity, dstMultiplicity, storageDirection,
|
|
295
|
+
std::move(nodePairs), std::move(storage), std::move(scanFunction), std::move(scanBindData),
|
|
296
|
+
std::move(foreignDatabaseName));
|
|
215
297
|
return BoundCreateTableInfo(CatalogEntryType::REL_GROUP_ENTRY, info->tableName,
|
|
216
298
|
info->onConflict, std::move(boundExtraInfo), clientContext->useInternalCatalogEntry());
|
|
217
299
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
#include "function/rewrite_function.h"
|
|
16
16
|
#include "function/schema/vector_node_rel_functions.h"
|
|
17
17
|
#include "main/client_context.h"
|
|
18
|
+
#include "main/database_manager.h"
|
|
18
19
|
#include "transaction/transaction.h"
|
|
19
20
|
|
|
20
21
|
using namespace lbug::common;
|
|
@@ -644,7 +645,8 @@ std::vector<TableCatalogEntry*> Binder::bindNodeTableEntries(
|
|
|
644
645
|
} else {
|
|
645
646
|
for (auto& name : tableNames) {
|
|
646
647
|
auto entry = bindNodeTableEntry(name);
|
|
647
|
-
if (entry->getType() != CatalogEntryType::NODE_TABLE_ENTRY
|
|
648
|
+
if (entry->getType() != CatalogEntryType::NODE_TABLE_ENTRY &&
|
|
649
|
+
entry->getType() != CatalogEntryType::FOREIGN_TABLE_ENTRY) {
|
|
648
650
|
throw BinderException(
|
|
649
651
|
stringFormat("Cannot bind {} as a node pattern label.", entry->getName()));
|
|
650
652
|
}
|
|
@@ -658,10 +660,35 @@ TableCatalogEntry* Binder::bindNodeTableEntry(const std::string& name) const {
|
|
|
658
660
|
auto transaction = transaction::Transaction::Get(*clientContext);
|
|
659
661
|
auto catalog = Catalog::Get(*clientContext);
|
|
660
662
|
auto useInternal = clientContext->useInternalCatalogEntry();
|
|
661
|
-
|
|
663
|
+
|
|
664
|
+
std::string dbName;
|
|
665
|
+
std::string tableName = name;
|
|
666
|
+
auto dotPos = name.find('.');
|
|
667
|
+
if (dotPos != std::string::npos) {
|
|
668
|
+
dbName = name.substr(0, dotPos);
|
|
669
|
+
tableName = name.substr(dotPos + 1);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (!dbName.empty()) {
|
|
673
|
+
// Qualified name: db.table
|
|
674
|
+
auto attachedDB = main::DatabaseManager::Get(*clientContext)->getAttachedDatabase(dbName);
|
|
675
|
+
if (!attachedDB) {
|
|
676
|
+
throw BinderException(stringFormat("Attached database {} does not exist.", dbName));
|
|
677
|
+
}
|
|
678
|
+
auto attachedCatalog = attachedDB->getCatalog();
|
|
679
|
+
if (!attachedCatalog->containsTable(transaction, tableName, useInternal)) {
|
|
680
|
+
throw BinderException(stringFormat("Table {} does not exist in attached database {}.",
|
|
681
|
+
tableName, dbName));
|
|
682
|
+
}
|
|
683
|
+
return attachedCatalog->getTableCatalogEntry(transaction, tableName, useInternal);
|
|
684
|
+
} else {
|
|
685
|
+
// Unqualified name: only search main catalog
|
|
686
|
+
// Foreign tables require qualified names (db.table) to avoid ambiguity
|
|
687
|
+
if (catalog->containsTable(transaction, name, useInternal)) {
|
|
688
|
+
return catalog->getTableCatalogEntry(transaction, name, useInternal);
|
|
689
|
+
}
|
|
662
690
|
throw BinderException(stringFormat("Table {} does not exist.", name));
|
|
663
691
|
}
|
|
664
|
-
return catalog->getTableCatalogEntry(transaction, name, useInternal);
|
|
665
692
|
}
|
|
666
693
|
|
|
667
694
|
std::vector<TableCatalogEntry*> Binder::bindRelGroupEntries(
|
|
@@ -190,9 +190,10 @@ CatalogEntry* Catalog::createRelGroupEntry(Transaction* transaction,
|
|
|
190
190
|
for (auto& nodePair : extraInfo->nodePairs) {
|
|
191
191
|
relTableInfos.emplace_back(nodePair, tables->getNextOID());
|
|
192
192
|
}
|
|
193
|
-
auto relGroupEntry =
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
auto relGroupEntry = std::make_unique<RelGroupCatalogEntry>(info.tableName,
|
|
194
|
+
extraInfo->srcMultiplicity, extraInfo->dstMultiplicity, extraInfo->storageDirection,
|
|
195
|
+
std::move(relTableInfos), extraInfo->storage, extraInfo->scanFunction,
|
|
196
|
+
std::move(extraInfo->scanBindData), extraInfo->foreignDatabaseName);
|
|
196
197
|
for (auto& definition : extraInfo->propertyDefinitions) {
|
|
197
198
|
relGroupEntry->addProperty(definition);
|
|
198
199
|
}
|
|
@@ -541,7 +542,8 @@ CatalogEntry* Catalog::createTableEntry(Transaction* transaction,
|
|
|
541
542
|
CatalogEntry* Catalog::createNodeTableEntry(Transaction* transaction,
|
|
542
543
|
const BoundCreateTableInfo& info) {
|
|
543
544
|
const auto extraInfo = info.extraInfo->constPtrCast<BoundExtraCreateNodeTableInfo>();
|
|
544
|
-
auto entry = std::make_unique<NodeTableCatalogEntry>(info.tableName, extraInfo->primaryKeyName
|
|
545
|
+
auto entry = std::make_unique<NodeTableCatalogEntry>(info.tableName, extraInfo->primaryKeyName,
|
|
546
|
+
extraInfo->storage);
|
|
545
547
|
for (auto& definition : extraInfo->propertyDefinitions) {
|
|
546
548
|
entry->addProperty(definition);
|
|
547
549
|
}
|
|
@@ -21,16 +21,22 @@ void NodeTableCatalogEntry::serialize(common::Serializer& serializer) const {
|
|
|
21
21
|
TableCatalogEntry::serialize(serializer);
|
|
22
22
|
serializer.writeDebuggingInfo("primaryKeyName");
|
|
23
23
|
serializer.write(primaryKeyName);
|
|
24
|
+
serializer.writeDebuggingInfo("storage");
|
|
25
|
+
serializer.write(storage);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
std::unique_ptr<NodeTableCatalogEntry> NodeTableCatalogEntry::deserialize(
|
|
27
29
|
common::Deserializer& deserializer) {
|
|
28
30
|
std::string debuggingInfo;
|
|
29
31
|
std::string primaryKeyName;
|
|
32
|
+
std::string storage;
|
|
30
33
|
deserializer.validateDebuggingInfo(debuggingInfo, "primaryKeyName");
|
|
31
34
|
deserializer.deserializeValue(primaryKeyName);
|
|
35
|
+
deserializer.validateDebuggingInfo(debuggingInfo, "storage");
|
|
36
|
+
deserializer.deserializeValue(storage);
|
|
32
37
|
auto nodeTableEntry = std::make_unique<NodeTableCatalogEntry>();
|
|
33
38
|
nodeTableEntry->primaryKeyName = primaryKeyName;
|
|
39
|
+
nodeTableEntry->storage = storage;
|
|
34
40
|
return nodeTableEntry;
|
|
35
41
|
}
|
|
36
42
|
|
|
@@ -42,6 +48,7 @@ std::string NodeTableCatalogEntry::toCypher(const ToCypherInfo& /*info*/) const
|
|
|
42
48
|
std::unique_ptr<TableCatalogEntry> NodeTableCatalogEntry::copy() const {
|
|
43
49
|
auto other = std::make_unique<NodeTableCatalogEntry>();
|
|
44
50
|
other->primaryKeyName = primaryKeyName;
|
|
51
|
+
other->storage = storage;
|
|
45
52
|
other->copyFrom(*this);
|
|
46
53
|
return other;
|
|
47
54
|
}
|
|
@@ -49,7 +56,7 @@ std::unique_ptr<TableCatalogEntry> NodeTableCatalogEntry::copy() const {
|
|
|
49
56
|
std::unique_ptr<BoundExtraCreateCatalogEntryInfo> NodeTableCatalogEntry::getBoundExtraCreateInfo(
|
|
50
57
|
transaction::Transaction*) const {
|
|
51
58
|
return std::make_unique<BoundExtraCreateNodeTableInfo>(primaryKeyName,
|
|
52
|
-
copyVector(getProperties()));
|
|
59
|
+
copyVector(getProperties()), storage);
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
} // namespace catalog
|
|
@@ -74,7 +74,10 @@ const RelTableCatalogInfo* RelGroupCatalogEntry::getRelEntryInfo(table_id_t srcT
|
|
|
74
74
|
std::unordered_set<table_id_t> RelGroupCatalogEntry::getSrcNodeTableIDSet() const {
|
|
75
75
|
std::unordered_set<table_id_t> result;
|
|
76
76
|
for (auto& info : relTableInfos) {
|
|
77
|
-
|
|
77
|
+
// Skip FOREIGN_TABLE_ID for foreign-backed rel tables
|
|
78
|
+
if (info.nodePair.srcTableID != FOREIGN_TABLE_ID) {
|
|
79
|
+
result.insert(info.nodePair.srcTableID);
|
|
80
|
+
}
|
|
78
81
|
}
|
|
79
82
|
return result;
|
|
80
83
|
}
|
|
@@ -82,7 +85,10 @@ std::unordered_set<table_id_t> RelGroupCatalogEntry::getSrcNodeTableIDSet() cons
|
|
|
82
85
|
std::unordered_set<table_id_t> RelGroupCatalogEntry::getDstNodeTableIDSet() const {
|
|
83
86
|
std::unordered_set<table_id_t> result;
|
|
84
87
|
for (auto& info : relTableInfos) {
|
|
85
|
-
|
|
88
|
+
// Skip FOREIGN_TABLE_ID for foreign-backed rel tables
|
|
89
|
+
if (info.nodePair.dstTableID != FOREIGN_TABLE_ID) {
|
|
90
|
+
result.insert(info.nodePair.dstTableID);
|
|
91
|
+
}
|
|
86
92
|
}
|
|
87
93
|
return result;
|
|
88
94
|
}
|
|
@@ -95,6 +101,13 @@ void RelGroupCatalogEntry::serialize(Serializer& serializer) const {
|
|
|
95
101
|
serializer.serializeValue(dstMultiplicity);
|
|
96
102
|
serializer.writeDebuggingInfo("storageDirection");
|
|
97
103
|
serializer.serializeValue(storageDirection);
|
|
104
|
+
serializer.writeDebuggingInfo("storage");
|
|
105
|
+
serializer.serializeValue(storage);
|
|
106
|
+
serializer.writeDebuggingInfo("scanFunction");
|
|
107
|
+
serializer.serializeValue(scanFunction.has_value());
|
|
108
|
+
if (scanFunction.has_value()) {
|
|
109
|
+
// TODO: serialize TableFunction
|
|
110
|
+
}
|
|
98
111
|
serializer.writeDebuggingInfo("relTableInfos");
|
|
99
112
|
serializer.serializeVector(relTableInfos);
|
|
100
113
|
}
|
|
@@ -105,6 +118,7 @@ std::unique_ptr<RelGroupCatalogEntry> RelGroupCatalogEntry::deserialize(
|
|
|
105
118
|
auto srcMultiplicity = RelMultiplicity::MANY;
|
|
106
119
|
auto dstMultiplicity = RelMultiplicity::MANY;
|
|
107
120
|
auto storageDirection = ExtendDirection::BOTH;
|
|
121
|
+
std::string storage;
|
|
108
122
|
std::vector<RelTableCatalogInfo> relTableInfos;
|
|
109
123
|
deserializer.validateDebuggingInfo(debuggingInfo, "srcMultiplicity");
|
|
110
124
|
deserializer.deserializeValue(srcMultiplicity);
|
|
@@ -112,20 +126,40 @@ std::unique_ptr<RelGroupCatalogEntry> RelGroupCatalogEntry::deserialize(
|
|
|
112
126
|
deserializer.deserializeValue(dstMultiplicity);
|
|
113
127
|
deserializer.validateDebuggingInfo(debuggingInfo, "storageDirection");
|
|
114
128
|
deserializer.deserializeValue(storageDirection);
|
|
129
|
+
deserializer.validateDebuggingInfo(debuggingInfo, "storage");
|
|
130
|
+
deserializer.deserializeValue(storage);
|
|
131
|
+
deserializer.validateDebuggingInfo(debuggingInfo, "scanFunction");
|
|
132
|
+
bool hasScanFunction;
|
|
133
|
+
deserializer.deserializeValue(hasScanFunction);
|
|
134
|
+
std::optional<function::TableFunction> scanFunction = std::nullopt;
|
|
135
|
+
if (hasScanFunction) {
|
|
136
|
+
// TODO: deserialize TableFunction
|
|
137
|
+
}
|
|
115
138
|
deserializer.validateDebuggingInfo(debuggingInfo, "relTableInfos");
|
|
116
139
|
deserializer.deserializeVector(relTableInfos);
|
|
117
140
|
auto relGroupEntry = std::make_unique<RelGroupCatalogEntry>();
|
|
118
141
|
relGroupEntry->srcMultiplicity = srcMultiplicity;
|
|
119
142
|
relGroupEntry->dstMultiplicity = dstMultiplicity;
|
|
120
143
|
relGroupEntry->storageDirection = storageDirection;
|
|
144
|
+
relGroupEntry->storage = storage;
|
|
145
|
+
relGroupEntry->scanFunction = scanFunction;
|
|
121
146
|
relGroupEntry->relTableInfos = relTableInfos;
|
|
122
147
|
return relGroupEntry;
|
|
123
148
|
}
|
|
124
149
|
|
|
125
150
|
static std::string getFromToStr(const NodeTableIDPair& pair, const Catalog* catalog,
|
|
126
|
-
const transaction::Transaction* transaction) {
|
|
127
|
-
|
|
128
|
-
|
|
151
|
+
const transaction::Transaction* transaction, const std::string& storage) {
|
|
152
|
+
std::string srcTableName, dstTableName;
|
|
153
|
+
// For foreign-backed rel tables, node table IDs are FOREIGN_TABLE_ID
|
|
154
|
+
if (pair.srcTableID == common::FOREIGN_TABLE_ID && !storage.empty()) {
|
|
155
|
+
auto dotPos = storage.find('.');
|
|
156
|
+
srcTableName =
|
|
157
|
+
dotPos != std::string::npos ? storage.substr(0, dotPos) + ".nodes" : "foreign_table";
|
|
158
|
+
dstTableName = srcTableName;
|
|
159
|
+
} else {
|
|
160
|
+
srcTableName = catalog->getTableCatalogEntry(transaction, pair.srcTableID)->getName();
|
|
161
|
+
dstTableName = catalog->getTableCatalogEntry(transaction, pair.dstTableID)->getName();
|
|
162
|
+
}
|
|
129
163
|
return stringFormat("FROM `{}` TO `{}`", srcTableName, dstTableName);
|
|
130
164
|
}
|
|
131
165
|
|
|
@@ -136,9 +170,10 @@ std::string RelGroupCatalogEntry::toCypher(const ToCypherInfo& info) const {
|
|
|
136
170
|
std::stringstream ss;
|
|
137
171
|
ss << stringFormat("CREATE REL TABLE `{}` (", getName());
|
|
138
172
|
KU_ASSERT(!relTableInfos.empty());
|
|
139
|
-
ss << getFromToStr(relTableInfos[0].nodePair, catalog, transaction);
|
|
173
|
+
ss << getFromToStr(relTableInfos[0].nodePair, catalog, transaction, storage);
|
|
140
174
|
for (auto i = 1u; i < relTableInfos.size(); ++i) {
|
|
141
|
-
ss << stringFormat(", {}",
|
|
175
|
+
ss << stringFormat(", {}",
|
|
176
|
+
getFromToStr(relTableInfos[i].nodePair, catalog, transaction, storage));
|
|
142
177
|
}
|
|
143
178
|
ss << ", " << propertyCollection.toCypher() << RelMultiplicityUtils::toString(srcMultiplicity)
|
|
144
179
|
<< "_" << RelMultiplicityUtils::toString(dstMultiplicity) << ");";
|
|
@@ -167,6 +202,10 @@ std::unique_ptr<TableCatalogEntry> RelGroupCatalogEntry::copy() const {
|
|
|
167
202
|
other->srcMultiplicity = srcMultiplicity;
|
|
168
203
|
other->dstMultiplicity = dstMultiplicity;
|
|
169
204
|
other->storageDirection = storageDirection;
|
|
205
|
+
other->storage = storage;
|
|
206
|
+
other->scanFunction = scanFunction;
|
|
207
|
+
other->scanBindData = std::nullopt; // TODO: implement copy for bindData if needed
|
|
208
|
+
other->foreignDatabaseName = foreignDatabaseName;
|
|
170
209
|
other->relTableInfos = relTableInfos;
|
|
171
210
|
other->copyFrom(*this);
|
|
172
211
|
return other;
|
|
@@ -246,6 +246,7 @@ void CatalogSet::serialize(Serializer serializer) const {
|
|
|
246
246
|
case CatalogEntryType::COPY_FUNCTION_ENTRY:
|
|
247
247
|
case CatalogEntryType::TABLE_FUNCTION_ENTRY:
|
|
248
248
|
case CatalogEntryType::STANDALONE_TABLE_FUNCTION_ENTRY:
|
|
249
|
+
case CatalogEntryType::FOREIGN_TABLE_ENTRY:
|
|
249
250
|
continue;
|
|
250
251
|
default: {
|
|
251
252
|
auto committedEntry = getCommittedEntryNoLock(entry.get());
|
|
@@ -228,7 +228,8 @@ FunctionCollection* FunctionCollection::getFunctions() {
|
|
|
228
228
|
TABLE_FUNCTION(StatsInfoFunction), TABLE_FUNCTION(StorageInfoFunction),
|
|
229
229
|
TABLE_FUNCTION(ShowAttachedDatabasesFunction), TABLE_FUNCTION(ShowSequencesFunction),
|
|
230
230
|
TABLE_FUNCTION(ShowFunctionsFunction), TABLE_FUNCTION(BMInfoFunction),
|
|
231
|
-
TABLE_FUNCTION(FileInfoFunction), TABLE_FUNCTION(
|
|
231
|
+
TABLE_FUNCTION(FileInfoFunction), TABLE_FUNCTION(DiskSizeInfoFunction),
|
|
232
|
+
TABLE_FUNCTION(ShowLoadedExtensionsFunction),
|
|
232
233
|
TABLE_FUNCTION(ShowOfficialExtensionsFunction), TABLE_FUNCTION(ShowIndexesFunction),
|
|
233
234
|
TABLE_FUNCTION(ShowProjectedGraphsFunction), TABLE_FUNCTION(ProjectedGraphInfoFunction),
|
|
234
235
|
TABLE_FUNCTION(ShowMacrosFunction),
|