ladybug 0.22.0.dev20261017__tar.gz → 0.22.0.dev20261024__tar.gz
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.
- sdist/PKG-INFO +1 -1
- sdist/ladybug-source/CMakeLists.txt +1 -1
- sdist/ladybug-source/scripts/choco-install.ps1 +26 -0
- sdist/ladybug-source/src/binder/bind/bind_projection_clause.cpp +6 -0
- sdist/ladybug-source/src/binder/bind_expression/bind_function_expression.cpp +95 -0
- sdist/ladybug-source/src/binder/bind_expression/bind_lambda_expression.cpp +7 -0
- sdist/ladybug-source/src/binder/ddl/property_definition.cpp +10 -0
- sdist/ladybug-source/src/binder/expression_binder.cpp +13 -8
- sdist/ladybug-source/src/c_api/database.cpp +3 -1
- sdist/ladybug-source/src/c_api/value.cpp +87 -15
- sdist/ladybug-source/src/catalog/catalog.cpp +6 -4
- sdist/ladybug-source/src/catalog/property_definition_collection.cpp +5 -1
- sdist/ladybug-source/src/common/task_system/task_scheduler.cpp +87 -11
- sdist/ladybug-source/src/common/types/types.cpp +5 -8
- sdist/ladybug-source/src/common/vector/value_vector.cpp +6 -0
- sdist/ladybug-source/src/function/gds/gds_utils.cpp +7 -7
- sdist/ladybug-source/src/function/table/cache_column.cpp +3 -1
- sdist/ladybug-source/src/graph/on_disk_graph.cpp +63 -0
- sdist/ladybug-source/src/include/binder/binder_scope.h +6 -0
- sdist/ladybug-source/src/include/binder/ddl/property_definition.h +1 -0
- sdist/ladybug-source/src/include/binder/expression_binder.h +5 -0
- sdist/ladybug-source/src/include/c_api/lbug.h +3 -0
- sdist/ladybug-source/src/include/catalog/catalog.h +4 -1
- sdist/ladybug-source/src/include/common/constants.h +10 -0
- sdist/ladybug-source/src/include/common/task_system/task.h +3 -2
- sdist/ladybug-source/src/include/common/task_system/task_scheduler.h +18 -4
- sdist/ladybug-source/src/include/graph/on_disk_graph.h +8 -0
- sdist/ladybug-source/src/include/main/attached_database.h +2 -3
- sdist/ladybug-source/src/include/main/database.h +4 -1
- sdist/ladybug-source/src/include/main/db_config.h +1 -0
- sdist/ladybug-source/src/include/main/prepared_statement.h +24 -0
- sdist/ladybug-source/src/include/main/settings.h +10 -0
- sdist/ladybug-source/src/include/optimizer/remove_unnecessary_join_optimizer.h +2 -1
- sdist/ladybug-source/src/include/planner/join_order/cost_model.h +4 -0
- sdist/ladybug-source/src/include/planner/operator/logical_hash_join.h +1 -1
- sdist/ladybug-source/src/include/planner/operator/logical_plan_util.h +2 -0
- sdist/ladybug-source/src/include/planner/operator/schema.h +4 -2
- sdist/ladybug-source/src/include/planner/planner.h +12 -0
- sdist/ladybug-source/src/include/processor/operator/ddl/drop.h +3 -1
- sdist/ladybug-source/src/include/processor/operator/persistent/reader/parquet/parquet_reader.h +5 -0
- sdist/ladybug-source/src/include/processor/processor_task.h +4 -0
- sdist/ladybug-source/src/include/processor/result/factorized_table.h +20 -1
- sdist/ladybug-source/src/include/storage/predicate/column_predicate.h +10 -0
- sdist/ladybug-source/src/include/storage/predicate/constant_predicate.h +5 -1
- sdist/ladybug-source/src/include/storage/predicate/filter_selection.h +32 -0
- sdist/ladybug-source/src/include/storage/predicate/null_predicate.h +2 -0
- sdist/ladybug-source/src/include/storage/table/chunked_node_group.h +1 -1
- sdist/ladybug-source/src/include/storage/table/column_chunk_data.h +8 -11
- sdist/ladybug-source/src/include/storage/table/csr_chunked_node_group.h +14 -0
- sdist/ladybug-source/src/include/storage/table/csr_node_group.h +12 -4
- sdist/ladybug-source/src/include/storage/table/ice_disk_node_table.h +2 -0
- sdist/ladybug-source/src/include/storage/table/node_group.h +11 -1
- sdist/ladybug-source/src/include/storage/table/node_table.h +2 -3
- sdist/ladybug-source/src/include/storage/table/rel_table.h +7 -0
- sdist/ladybug-source/src/include/storage/table/rel_table_data.h +17 -3
- sdist/ladybug-source/src/include/storage/table/version_info.h +8 -0
- sdist/ladybug-source/src/include/transaction/transaction.h +2 -1
- sdist/ladybug-source/src/main/attached_database.cpp +1 -1
- sdist/ladybug-source/src/main/client_context.cpp +103 -5
- sdist/ladybug-source/src/main/database.cpp +3 -2
- sdist/ladybug-source/src/main/db_config.cpp +4 -2
- sdist/ladybug-source/src/main/settings.cpp +15 -0
- sdist/ladybug-source/src/optimizer/count_rel_table_optimizer.cpp +3 -1
- sdist/ladybug-source/src/optimizer/remove_unnecessary_join_optimizer.cpp +83 -2
- sdist/ladybug-source/src/parser/transform/transform_expression.cpp +4 -4
- sdist/ladybug-source/src/planner/join_order/cost_model.cpp +4 -0
- sdist/ladybug-source/src/planner/operator/logical_plan_util.cpp +11 -0
- sdist/ladybug-source/src/planner/operator/scan/logical_query_primary_key_lookup.cpp +7 -4
- sdist/ladybug-source/src/planner/plan/plan_join_order.cpp +286 -0
- sdist/ladybug-source/src/processor/operator/aggregate/base_aggregate.cpp +1 -0
- sdist/ladybug-source/src/processor/operator/aggregate/base_aggregate_scan.cpp +1 -0
- sdist/ladybug-source/src/processor/operator/aggregate/hash_aggregate.cpp +4 -0
- sdist/ladybug-source/src/processor/operator/aggregate/hash_aggregate_scan.cpp +1 -0
- sdist/ladybug-source/src/processor/operator/aggregate/packed_filtered_count.cpp +4 -0
- sdist/ladybug-source/src/processor/operator/aggregate/simple_aggregate.cpp +2 -0
- sdist/ladybug-source/src/processor/operator/cross_product.cpp +1 -0
- sdist/ladybug-source/src/processor/operator/ddl/drop.cpp +9 -3
- sdist/ladybug-source/src/processor/operator/hash_join/hash_join_build.cpp +5 -0
- sdist/ladybug-source/src/processor/operator/hash_join/hash_join_probe.cpp +3 -0
- sdist/ladybug-source/src/processor/operator/intersect/intersect.cpp +6 -0
- sdist/ladybug-source/src/processor/operator/order_by/order_by.cpp +2 -0
- sdist/ladybug-source/src/processor/operator/order_by/order_by_scan.cpp +2 -0
- sdist/ladybug-source/src/processor/operator/order_by/top_k.cpp +2 -0
- sdist/ladybug-source/src/processor/operator/order_by/top_k_scanner.cpp +2 -0
- sdist/ladybug-source/src/processor/operator/path_property_probe.cpp +3 -0
- sdist/ladybug-source/src/processor/operator/persistent/copy_to.cpp +2 -0
- sdist/ladybug-source/src/processor/operator/persistent/merge.cpp +2 -0
- sdist/ladybug-source/src/processor/operator/persistent/node_batch_insert.cpp +59 -0
- sdist/ladybug-source/src/processor/operator/persistent/reader/parquet/column_reader.cpp +1 -1
- sdist/ladybug-source/src/processor/operator/persistent/reader/parquet/list_column_reader.cpp +4 -1
- sdist/ladybug-source/src/processor/operator/persistent/reader/parquet/parquet_reader.cpp +4 -0
- sdist/ladybug-source/src/processor/operator/persistent/rel_batch_insert.cpp +17 -5
- sdist/ladybug-source/src/processor/operator/persistent/writer/parquet/parquet_writer.cpp +8 -4
- sdist/ladybug-source/src/processor/operator/physical_operator.cpp +15 -0
- sdist/ladybug-source/src/processor/operator/query_primary_key_lookup.cpp +2 -0
- sdist/ladybug-source/src/processor/operator/result_collector.cpp +5 -0
- sdist/ladybug-source/src/processor/operator/scan/count_rel_table.cpp +3 -87
- sdist/ladybug-source/src/processor/operator/scan/grouped_reachable_count.cpp +3 -0
- sdist/ladybug-source/src/processor/operator/scan/reachable_count.cpp +2 -0
- sdist/ladybug-source/src/processor/operator/scan/scan_table.cpp +1 -0
- sdist/ladybug-source/src/processor/operator/table_scan/union_all_scan.cpp +2 -0
- sdist/ladybug-source/src/processor/processor.cpp +11 -1
- sdist/ladybug-source/src/processor/processor_task.cpp +22 -0
- sdist/ladybug-source/src/processor/result/factorized_table.cpp +35 -14
- sdist/ladybug-source/src/storage/predicate/column_predicate.cpp +56 -1
- sdist/ladybug-source/src/storage/predicate/constant_predicate.cpp +42 -0
- sdist/ladybug-source/src/storage/predicate/null_predicate.cpp +8 -0
- sdist/ladybug-source/src/storage/table/arrow_node_table.cpp +16 -0
- sdist/ladybug-source/src/storage/table/chunked_node_group.cpp +114 -20
- sdist/ladybug-source/src/storage/table/column_chunk.cpp +2 -2
- sdist/ladybug-source/src/storage/table/column_chunk_data.cpp +19 -13
- sdist/ladybug-source/src/storage/table/csr_chunked_node_group.cpp +23 -4
- sdist/ladybug-source/src/storage/table/csr_node_group.cpp +297 -112
- sdist/ladybug-source/src/storage/table/ice_disk_node_table.cpp +22 -0
- sdist/ladybug-source/src/storage/table/node_group.cpp +10 -1
- sdist/ladybug-source/src/storage/table/node_table.cpp +46 -2
- sdist/ladybug-source/src/storage/table/rel_table.cpp +323 -56
- sdist/ladybug-source/src/storage/table/rel_table_data.cpp +17 -13
- sdist/ladybug-source/src/storage/table/version_info.cpp +83 -20
- sdist/ladybug-source/third_party/antlr4_runtime/src/misc/IntervalSet.cpp +8 -0
- sdist/ladybug-source/third_party/ports/antlr4_runtime/Makefile +14 -0
- sdist/ladybug-source/third_party/ports/antlr4_runtime/patches/antlr4-common-chrono.patch +13 -0
- sdist/ladybug-source/third_party/ports/antlr4_runtime/patches/interval-set-append.patch +22 -0
- sdist/ladybug-source/third_party/ports/antlr4_runtime/patches/parse-tree-equality.patch +14 -0
- sdist/ladybug-source/third_party/ports/antlr4_runtime/patches/vocabulary-deprecation.patch +29 -0
- sdist/ladybug-source/tools/python_api/src_cpp/include/cached_import/py_cached_import.h +2 -0
- sdist/ladybug-source/tools/python_api/src_cpp/include/cached_import/py_cached_modules.h +18 -0
- sdist/ladybug-source/tools/python_api/src_cpp/py_connection.cpp +146 -5
- sdist/ladybug-source/tools/python_api/src_py/_backend.py +26 -2
- sdist/ladybug-source/tools/python_api/src_py/_lbug_capi.py +3 -6
- sdist/ladybug-source/tools/python_api/src_py/connection.py +63 -7
- sdist/ladybug-source/tools/python_api/test/capi_xfails.py +7 -0
- sdist/ladybug-source/tools/python_api/test/test_backend_errors.py +34 -0
- sdist/ladybug-source/tools/python_api/test/test_connection_close.py +22 -2
- sdist/ladybug-source/tools/python_api/test/test_keyboard_interrupt.py +125 -0
- sdist/ladybug-source/tools/python_api/test/test_timeout.py +91 -0
- sdist/ladybug-source/tools/shell/test/test_shell_esc_edit.py +5 -1
- sdist/ladybug.egg-info/PKG-INFO +1 -1
- sdist/ladybug.egg-info/SOURCES.txt +2 -0
- sdist/pyproject.toml +1 -1
- sdist/src_py/_backend.py +26 -2
- sdist/src_py/_lbug_capi.py +3 -6
- sdist/src_py/connection.py +63 -7
- sdist/test/capi_xfails.py +7 -0
- sdist/test/test_backend_errors.py +34 -0
- sdist/test/test_connection_close.py +22 -2
- sdist/test/test_keyboard_interrupt.py +125 -0
- sdist/test/test_timeout.py +91 -0
sdist/PKG-INFO
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Installs a Chocolatey package, retrying while the community feed is unavailable.
|
|
2
|
+
# choco can exit 0 after "Unable to find package", so success also requires the
|
|
3
|
+
# package to be listed as installed.
|
|
4
|
+
param(
|
|
5
|
+
[Parameter(Mandatory = $true)][string]$Package,
|
|
6
|
+
[string]$Version,
|
|
7
|
+
[string]$PackageParameters
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
$chocoArgs = @('install', $Package, '-y')
|
|
11
|
+
if ($Version) { $chocoArgs += "--version=$Version" }
|
|
12
|
+
if ($PackageParameters) { $chocoArgs += "--params=$PackageParameters" }
|
|
13
|
+
|
|
14
|
+
$attempts = 3
|
|
15
|
+
for ($attempt = 1; $attempt -le $attempts; $attempt++) {
|
|
16
|
+
& choco @chocoArgs
|
|
17
|
+
if ($LASTEXITCODE -eq 0 -and (choco list --exact $Package --limit-output)) {
|
|
18
|
+
exit 0
|
|
19
|
+
}
|
|
20
|
+
if ($attempt -lt $attempts) {
|
|
21
|
+
Write-Host "choco install $Package failed (attempt $attempt of $attempts), retrying in 60s"
|
|
22
|
+
Start-Sleep -Seconds 60
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
Write-Host "choco install $Package failed after $attempts attempts"
|
|
26
|
+
exit 1
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include <algorithm>
|
|
2
2
|
#include <unordered_set>
|
|
3
|
+
#include <utility>
|
|
3
4
|
|
|
4
5
|
#include "binder/binder.h"
|
|
5
6
|
#include "binder/expression/expression_util.h"
|
|
@@ -124,6 +125,9 @@ static expression_vector getAggregateExpressions(const std::shared_ptr<Expressio
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
BoundProjectionList Binder::bindProjectionList(const ProjectionBody& projectionBody) {
|
|
128
|
+
auto& config = expressionBinder.config;
|
|
129
|
+
auto outerAggregateNames = std::exchange(config.projectionAggregateNames, {});
|
|
130
|
+
auto outerBindingProjectionList = std::exchange(config.bindingProjectionList, true);
|
|
127
131
|
expression_vector projectionExprs;
|
|
128
132
|
std::vector<std::string> aliases;
|
|
129
133
|
std::vector<const ParsedExpression*> parsedItems;
|
|
@@ -162,6 +166,8 @@ BoundProjectionList Binder::bindProjectionList(const ProjectionBody& projectionB
|
|
|
162
166
|
parsedItems.push_back(parsedExpr.get());
|
|
163
167
|
}
|
|
164
168
|
}
|
|
169
|
+
config.bindingProjectionList = outerBindingProjectionList;
|
|
170
|
+
config.projectionAggregateNames = std::move(outerAggregateNames);
|
|
165
171
|
return {std::move(projectionExprs), std::move(aliases), std::move(parsedItems)};
|
|
166
172
|
}
|
|
167
173
|
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
#include <algorithm>
|
|
2
|
+
|
|
1
3
|
#include "binder/binder.h"
|
|
2
4
|
#include "binder/expression/aggregate_function_expression.h"
|
|
5
|
+
#include "binder/expression/expression_util.h"
|
|
6
|
+
#include "binder/expression/node_expression.h"
|
|
7
|
+
#include "binder/expression/property_expression.h"
|
|
3
8
|
#include "binder/expression/scalar_function_expression.h"
|
|
4
9
|
#include "binder/expression_binder.h"
|
|
10
|
+
#include "binder/expression_visitor.h"
|
|
5
11
|
#include "catalog/catalog.h"
|
|
12
|
+
#include "catalog/catalog_entry/node_table_catalog_entry.h"
|
|
13
|
+
#include "common/enums/storage_format.h"
|
|
6
14
|
#include "common/exception/binder.h"
|
|
15
|
+
#include "function/aggregate/count.h"
|
|
7
16
|
#include "function/arithmetic/vector_arithmetic_functions.h"
|
|
8
17
|
#include "function/built_in_function_utils.h"
|
|
9
18
|
#include "function/cast/vector_cast_functions.h"
|
|
@@ -12,6 +21,8 @@
|
|
|
12
21
|
#include "function/uuid/vector_uuid_functions.h"
|
|
13
22
|
#include "parser/expression/parsed_expression_visitor.h"
|
|
14
23
|
#include "parser/expression/parsed_function_expression.h"
|
|
24
|
+
#include "storage/storage_manager.h"
|
|
25
|
+
#include "storage/table/node_table.h"
|
|
15
26
|
#include "transaction/transaction.h"
|
|
16
27
|
#include <format>
|
|
17
28
|
|
|
@@ -23,6 +34,14 @@ using namespace lbug::catalog;
|
|
|
23
34
|
namespace lbug {
|
|
24
35
|
namespace binder {
|
|
25
36
|
|
|
37
|
+
static bool containsExpressionNamed(const Expression& expression, const std::string& uniqueName) {
|
|
38
|
+
if (expression.getUniqueName() == uniqueName) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return std::ranges::any_of(ExpressionChildrenCollector::collectChildren(expression),
|
|
42
|
+
[&](const auto& child) { return containsExpressionNamed(*child, uniqueName); });
|
|
43
|
+
}
|
|
44
|
+
|
|
26
45
|
std::shared_ptr<Expression> ExpressionBinder::bindFunctionExpression(const ParsedExpression& expr) {
|
|
27
46
|
auto funcExpr = expr.constPtrCast<ParsedFunctionExpression>();
|
|
28
47
|
auto functionName = funcExpr->getNormalizedFunctionName();
|
|
@@ -154,12 +173,76 @@ std::shared_ptr<Expression> ExpressionBinder::bindRewriteFunctionExpression(
|
|
|
154
173
|
return function->rewriteFunc(input);
|
|
155
174
|
}
|
|
156
175
|
|
|
176
|
+
// A primary key enforced by the table's primary-key index is unique, never null, and null exactly
|
|
177
|
+
// when the node is unbound, so COUNT over it equals COUNT over the internal ID. Counting the
|
|
178
|
+
// internal ID keeps the planner from scanning the node table only to read the key.
|
|
179
|
+
static std::shared_ptr<Expression> rewritePrimaryKeyToInternalID(const Expression& expr,
|
|
180
|
+
const BinderScope& scope, main::ClientContext* context) {
|
|
181
|
+
if (expr.expressionType != ExpressionType::PROPERTY) {
|
|
182
|
+
return nullptr;
|
|
183
|
+
}
|
|
184
|
+
auto& property = expr.constCast<PropertyExpression>();
|
|
185
|
+
if (!property.isSingleLabel() || !property.isPrimaryKey() ||
|
|
186
|
+
!scope.contains(property.getRawVariableName())) {
|
|
187
|
+
return nullptr;
|
|
188
|
+
}
|
|
189
|
+
auto variable = scope.getExpression(property.getRawVariableName());
|
|
190
|
+
if (!ExpressionUtil::isNodePattern(*variable) ||
|
|
191
|
+
variable->getUniqueName() != property.getVariableName()) {
|
|
192
|
+
return nullptr;
|
|
193
|
+
}
|
|
194
|
+
auto& node = variable->constCast<NodeExpression>();
|
|
195
|
+
if (node.getNumEntries() != 1) {
|
|
196
|
+
return nullptr;
|
|
197
|
+
}
|
|
198
|
+
auto* entry = node.getEntry(0);
|
|
199
|
+
const auto tableID = entry->getTableID();
|
|
200
|
+
if (entry->getType() != CatalogEntryType::NODE_TABLE_ENTRY ||
|
|
201
|
+
tableID != property.getSingleTableID()) {
|
|
202
|
+
return nullptr;
|
|
203
|
+
}
|
|
204
|
+
// Storage is found by table ID, and IDs repeat across attached databases, so only an entry
|
|
205
|
+
// of the active catalog backed by the active storage manager can be checked. Attached tables
|
|
206
|
+
// and partition children keep the property.
|
|
207
|
+
auto transaction = transaction::Transaction::Get(*context);
|
|
208
|
+
auto catalog = Catalog::Get(*context);
|
|
209
|
+
if (!catalog->containsTable(transaction, tableID) ||
|
|
210
|
+
catalog->getTableCatalogEntry(transaction, tableID) != entry) {
|
|
211
|
+
return nullptr;
|
|
212
|
+
}
|
|
213
|
+
// Icebug-disk and Arrow tables carry a default hash index that does not enforce the key of
|
|
214
|
+
// their files.
|
|
215
|
+
auto* nodeEntry = entry->ptrCast<NodeTableCatalogEntry>();
|
|
216
|
+
if (nodeEntry->getScanFunction().has_value() || nodeEntry->getReferencedEntry() != nullptr ||
|
|
217
|
+
!nodeEntry->getForeignDatabaseName().empty() || !nodeEntry->getStorage().empty() ||
|
|
218
|
+
nodeEntry->getStorageFormat() != StorageFormat::NONE) {
|
|
219
|
+
return nullptr;
|
|
220
|
+
}
|
|
221
|
+
auto* storageManager = storage::StorageManager::Get(*context);
|
|
222
|
+
if (!storageManager->containsTable(tableID)) {
|
|
223
|
+
return nullptr;
|
|
224
|
+
}
|
|
225
|
+
auto* table = dynamic_cast<storage::NodeTable*>(storageManager->getTable(tableID));
|
|
226
|
+
if (table == nullptr || table->tryGetPrimaryKeyIndex() == nullptr) {
|
|
227
|
+
return nullptr;
|
|
228
|
+
}
|
|
229
|
+
// The alias keeps the key in the aggregate's text, which names an unaliased result column.
|
|
230
|
+
std::shared_ptr<Expression> internalID = node.getInternalID()->copy();
|
|
231
|
+
internalID->setAlias(property.toString());
|
|
232
|
+
return internalID;
|
|
233
|
+
}
|
|
234
|
+
|
|
157
235
|
std::shared_ptr<Expression> ExpressionBinder::bindAggregateFunctionExpression(
|
|
158
236
|
const ParsedExpression& parsedExpression, const std::string& functionName, bool isDistinct) {
|
|
159
237
|
std::vector<LogicalType> childrenTypes;
|
|
160
238
|
expression_vector children;
|
|
161
239
|
for (auto i = 0u; i < parsedExpression.getNumChildren(); ++i) {
|
|
162
240
|
auto child = bindExpression(*parsedExpression.getChild(i));
|
|
241
|
+
if (functionName == CountFunction::name) {
|
|
242
|
+
if (auto internalID = rewritePrimaryKeyToInternalID(*child, binder->scope, context)) {
|
|
243
|
+
child = std::move(internalID);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
163
246
|
childrenTypes.push_back(child->dataType.copy());
|
|
164
247
|
children.push_back(std::move(child));
|
|
165
248
|
}
|
|
@@ -180,6 +263,18 @@ std::shared_ptr<Expression> ExpressionBinder::bindAggregateFunctionExpression(
|
|
|
180
263
|
AggregateFunctionExpression::getUniqueName(function.name, children, function.isDistinct);
|
|
181
264
|
if (children.empty()) {
|
|
182
265
|
uniqueExpressionName = binder->getUniqueExpressionName(uniqueExpressionName);
|
|
266
|
+
} else if (config.bindingProjectionList &&
|
|
267
|
+
std::ranges::any_of(binder->scope.getExpressions(), [&](const auto& expr) {
|
|
268
|
+
return containsExpressionNamed(*expr, uniqueExpressionName);
|
|
269
|
+
})) {
|
|
270
|
+
// The name is structural, so this aggregate would share it, and its column, with the
|
|
271
|
+
// earlier clause's result, e.g. the group key c in WITH x, count(x) AS c RETURN c,
|
|
272
|
+
// count(x), or count(x) inside c in WITH x, count(x) + x AS c RETURN c, count(x) + x.
|
|
273
|
+
auto [entry, isNew] = config.projectionAggregateNames.try_emplace(uniqueExpressionName);
|
|
274
|
+
if (isNew) {
|
|
275
|
+
entry->second = binder->getUniqueExpressionName(uniqueExpressionName);
|
|
276
|
+
}
|
|
277
|
+
uniqueExpressionName = entry->second;
|
|
183
278
|
}
|
|
184
279
|
std::unique_ptr<FunctionBindData> bindData;
|
|
185
280
|
if (function.bindFunc) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
#include <utility>
|
|
2
|
+
|
|
1
3
|
#include "binder/binder.h"
|
|
2
4
|
#include "binder/expression/expression_util.h"
|
|
3
5
|
#include "binder/expression/lambda_expression.h"
|
|
@@ -20,8 +22,13 @@ void ExpressionBinder::bindLambdaExpression(const Expression& lambdaInput,
|
|
|
20
22
|
for (auto& varName : parsedLambdaExpr.getVarNames()) {
|
|
21
23
|
binder->createVariable(varName, listChildType);
|
|
22
24
|
}
|
|
25
|
+
// The projection does not compute aggregates inside a lambda body, so they keep their
|
|
26
|
+
// structural names and read the earlier clause's column, as before.
|
|
27
|
+
auto& config = binder->getExpressionBinder()->config;
|
|
28
|
+
auto bindingProjectionList = std::exchange(config.bindingProjectionList, false);
|
|
23
29
|
auto funcExpr =
|
|
24
30
|
binder->getExpressionBinder()->bindExpression(*parsedLambdaExpr.getFunctionExpr());
|
|
31
|
+
config.bindingProjectionList = bindingProjectionList;
|
|
25
32
|
binder->restoreScope(std::move(prevScope));
|
|
26
33
|
boundLambdaExpr.cast(funcExpr->getDataType().copy());
|
|
27
34
|
boundLambdaExpr.setFunctionExpr(std::move(funcExpr));
|
|
@@ -15,6 +15,16 @@ PropertyDefinition::PropertyDefinition(ColumnDefinition columnDefinition)
|
|
|
15
15
|
defaultExpr = std::make_unique<ParsedLiteralExpression>(Value::createNullValue(), "NULL");
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
bool PropertyDefinition::hasDefault() const {
|
|
19
|
+
if (defaultExpr == nullptr) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (defaultExpr->getExpressionType() == common::ExpressionType::LITERAL) {
|
|
23
|
+
return !defaultExpr->constCast<parser::ParsedLiteralExpression>().getValue().isNull();
|
|
24
|
+
}
|
|
25
|
+
return !defaultExpr->getRawName().empty();
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
void PropertyDefinition::serialize(Serializer& serializer) const {
|
|
19
29
|
serializer.serializeValue(columnDefinition.name);
|
|
20
30
|
columnDefinition.type.serialize(serializer);
|
|
@@ -183,13 +183,7 @@ std::shared_ptr<Expression> ExpressionBinder::bindExpression(
|
|
|
183
183
|
throw NotImplementedException(
|
|
184
184
|
"bindExpression(" + ExpressionTypeUtil::toString(expressionType) + ").");
|
|
185
185
|
}
|
|
186
|
-
|
|
187
|
-
// it was bound; it is not simplified again, as a new object would escape the binder's identity
|
|
188
|
-
// check for expressions an earlier clause computed. References nested in a larger expression
|
|
189
|
-
// rely on each simplifier returning an already simplified input unchanged.
|
|
190
|
-
if (expressionType != ExpressionType::VARIABLE) {
|
|
191
|
-
expression = simplifyExpression(expression);
|
|
192
|
-
}
|
|
186
|
+
expression = simplifyExpression(expression);
|
|
193
187
|
if (ConstantExpressionVisitor::needFold(*expression)) {
|
|
194
188
|
return tryFoldExpression(expression);
|
|
195
189
|
}
|
|
@@ -198,6 +192,11 @@ std::shared_ptr<Expression> ExpressionBinder::bindExpression(
|
|
|
198
192
|
|
|
199
193
|
std::shared_ptr<Expression> ExpressionBinder::simplifyExpression(
|
|
200
194
|
const std::shared_ptr<Expression>& expression) {
|
|
195
|
+
// Earlier clauses' expressions are recognised by identity, so a scope expression is never
|
|
196
|
+
// simplified again, and no simplifier returns a part of one in place of its parent.
|
|
197
|
+
if (binder->scope.contains(*expression)) {
|
|
198
|
+
return expression;
|
|
199
|
+
}
|
|
201
200
|
switch (expression->expressionType) {
|
|
202
201
|
case ExpressionType::AND:
|
|
203
202
|
case ExpressionType::OR:
|
|
@@ -263,6 +262,12 @@ std::shared_ptr<Expression> ExpressionBinder::simplifyArithmeticExpression(
|
|
|
263
262
|
if (expression->dataType != survivor->dataType) {
|
|
264
263
|
return expression;
|
|
265
264
|
}
|
|
265
|
+
// A projection names its item by setting the alias on the expression, so an identity over a
|
|
266
|
+
// scope expression stays as written: returning the operand would let the alias rename the
|
|
267
|
+
// variable, e.g. x in WITH x + 0 AS y, x.
|
|
268
|
+
if (binder->scope.contains(*survivor)) {
|
|
269
|
+
return expression;
|
|
270
|
+
}
|
|
266
271
|
// Preserve the original expression name, mirroring foldExpression: without this,
|
|
267
272
|
// e.g. RETURN t.age, t.age + 0 would produce two identically-named columns.
|
|
268
273
|
if (expression->hasAlias()) {
|
|
@@ -286,7 +291,7 @@ std::shared_ptr<Expression> ExpressionBinder::simplifyBooleanExpression(
|
|
|
286
291
|
if (isBoolLiteral(*child, false)) {
|
|
287
292
|
return createLiteralExpression(Value(true));
|
|
288
293
|
}
|
|
289
|
-
if (child->expressionType == ExpressionType::NOT) {
|
|
294
|
+
if (child->expressionType == ExpressionType::NOT && !binder->scope.contains(*child)) {
|
|
290
295
|
return child->getChild(0);
|
|
291
296
|
}
|
|
292
297
|
if (child != expression->getChild(0)) {
|
|
@@ -15,7 +15,8 @@ lbug_state lbug_database_init(const char* database_path, lbug_system_config conf
|
|
|
15
15
|
auto systemConfig = SystemConfig(config.buffer_pool_size, config.max_num_threads,
|
|
16
16
|
config.enable_compression, config.read_only, config.max_db_size, config.auto_checkpoint,
|
|
17
17
|
config.checkpoint_threshold, true, config.throw_on_wal_replay_failure,
|
|
18
|
-
config.enable_checksums, config.enable_multi_writes, config.enable_default_hash_index
|
|
18
|
+
config.enable_checksums, config.enable_multi_writes, config.enable_default_hash_index,
|
|
19
|
+
config.physical_plan_pool_per_thread);
|
|
19
20
|
|
|
20
21
|
#if defined(__APPLE__)
|
|
21
22
|
systemConfig.threadQos = config.thread_qos;
|
|
@@ -54,6 +55,7 @@ lbug_system_config lbug_default_system_config() {
|
|
|
54
55
|
cSystemConfig.enable_checksums = config.enableChecksums;
|
|
55
56
|
cSystemConfig.enable_multi_writes = config.enableMultiWrites;
|
|
56
57
|
cSystemConfig.enable_default_hash_index = config.enableDefaultHashIndex;
|
|
58
|
+
cSystemConfig.physical_plan_pool_per_thread = config.physicalPlanPoolPerThread;
|
|
57
59
|
#if defined(__APPLE__)
|
|
58
60
|
cSystemConfig.thread_qos = config.threadQos;
|
|
59
61
|
#endif
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include "c_api/helpers.h"
|
|
4
4
|
#include "c_api/lbug.h"
|
|
5
5
|
#include "common/constants.h"
|
|
6
|
+
#include "common/type_utils.h"
|
|
6
7
|
#include "common/types/types.h"
|
|
7
8
|
#include "common/types/value/nested.h"
|
|
8
9
|
#include "common/types/value/node.h"
|
|
@@ -40,7 +41,7 @@ static bool canCopyValueForNested(const Value& value, const LogicalType& targetT
|
|
|
40
41
|
if (value.getDataType() == targetType) {
|
|
41
42
|
return true;
|
|
42
43
|
}
|
|
43
|
-
if (value.isNull()
|
|
44
|
+
if (value.isNull()) {
|
|
44
45
|
return true;
|
|
45
46
|
}
|
|
46
47
|
if (isEmptyNestedWithAny(value)) {
|
|
@@ -51,8 +52,45 @@ static bool canCopyValueForNested(const Value& value, const LogicalType& targetT
|
|
|
51
52
|
targetType.getLogicalTypeID() == LogicalTypeID::FLOAT) {
|
|
52
53
|
return true;
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
if (LogicalTypeUtils::isIntegral(value.getDataType()) &&
|
|
56
|
+
LogicalTypeUtils::isIntegral(targetType)) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (value.getDataType().getLogicalTypeID() != targetType.getLogicalTypeID()) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const auto* nested = &value;
|
|
63
|
+
if (targetType.getLogicalTypeID() == LogicalTypeID::LIST) {
|
|
64
|
+
const auto& childType = ListType::getChildType(targetType);
|
|
65
|
+
for (auto i = 0u; i < NestedVal::getChildrenSize(nested); ++i) {
|
|
66
|
+
if (!canCopyValueForNested(*NestedVal::getChildVal(nested, i), childType)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if (targetType.getLogicalTypeID() == LogicalTypeID::MAP) {
|
|
73
|
+
const auto& keyType = MapType::getKeyType(targetType);
|
|
74
|
+
const auto& valueType = MapType::getValueType(targetType);
|
|
75
|
+
for (auto i = 0u; i < NestedVal::getChildrenSize(nested); ++i) {
|
|
76
|
+
auto* mapEntry = NestedVal::getChildVal(nested, i);
|
|
77
|
+
if (!canCopyValueForNested(*NestedVal::getChildVal(mapEntry, 0), keyType) ||
|
|
78
|
+
!canCopyValueForNested(*NestedVal::getChildVal(mapEntry, 1), valueType)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
if (targetType.getLogicalTypeID() == LogicalTypeID::STRUCT) {
|
|
85
|
+
for (auto i = 0u; i < NestedVal::getChildrenSize(nested); ++i) {
|
|
86
|
+
if (!canCopyValueForNested(*NestedVal::getChildVal(nested, i),
|
|
87
|
+
StructType::getFieldType(targetType, static_cast<struct_field_idx_t>(i)))) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return value.getDataType().containsAny();
|
|
56
94
|
}
|
|
57
95
|
|
|
58
96
|
static std::string incompatibleParameterTypeMessage(const LogicalType& left,
|
|
@@ -69,28 +107,54 @@ static lbug_value* createCAPIValue(std::unique_ptr<Value> value) {
|
|
|
69
107
|
return c_value;
|
|
70
108
|
}
|
|
71
109
|
|
|
110
|
+
// The target comes from LogicalTypeUtils::tryGetMaxLogicalType, which joins two integer types only
|
|
111
|
+
// into one that holds both: implicit integer casts only widen, and a signed/unsigned pair becomes a
|
|
112
|
+
// wider signed type. So the cast below is exact. CreateListAllIntegerPairs pins this.
|
|
113
|
+
static std::unique_ptr<Value> castIntegerForNested(const Value& value,
|
|
114
|
+
const LogicalType& targetType) {
|
|
115
|
+
// A null of the target type keeps its exact type: SERIAL's default value is an INT64.
|
|
116
|
+
auto result = std::make_unique<Value>(Value::createNullValue(targetType));
|
|
117
|
+
result->setNull(false);
|
|
118
|
+
TypeUtils::visit(
|
|
119
|
+
value.getDataType(),
|
|
120
|
+
[&]<IntegerTypes SRC>(SRC) {
|
|
121
|
+
TypeUtils::visit(
|
|
122
|
+
targetType,
|
|
123
|
+
[&]<IntegerTypes DST>(DST) {
|
|
124
|
+
auto castValue = static_cast<DST>(value.getValue<SRC>());
|
|
125
|
+
result->copyFromRowLayout(reinterpret_cast<const uint8_t*>(&castValue));
|
|
126
|
+
},
|
|
127
|
+
[](auto) { UNREACHABLE_CODE; });
|
|
128
|
+
},
|
|
129
|
+
[](auto) { UNREACHABLE_CODE; });
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
|
|
72
133
|
static std::unique_ptr<Value> copyValueForNested(const Value& value,
|
|
73
134
|
const LogicalType& targetType) {
|
|
74
|
-
if (value.
|
|
135
|
+
if (value.getDataType() == targetType) {
|
|
136
|
+
return value.copy();
|
|
137
|
+
}
|
|
138
|
+
if (value.isNull()) {
|
|
75
139
|
return std::make_unique<Value>(Value::createNullValue(targetType));
|
|
76
140
|
}
|
|
77
|
-
if (
|
|
141
|
+
if (isEmptyNestedWithAny(value)) {
|
|
78
142
|
return std::make_unique<Value>(Value::createDefaultValue(targetType));
|
|
79
143
|
}
|
|
80
|
-
if (
|
|
81
|
-
targetType.getLogicalTypeID() == LogicalTypeID::STRING) {
|
|
144
|
+
if (targetType.getLogicalTypeID() == LogicalTypeID::STRING) {
|
|
82
145
|
return std::make_unique<Value>(Value::createValue<std::string>(value.toString()));
|
|
83
146
|
}
|
|
84
|
-
if (
|
|
85
|
-
targetType.getLogicalTypeID() == LogicalTypeID::DOUBLE) {
|
|
147
|
+
if (targetType.getLogicalTypeID() == LogicalTypeID::DOUBLE) {
|
|
86
148
|
return std::make_unique<Value>(std::stod(value.toString()));
|
|
87
149
|
}
|
|
88
|
-
if (
|
|
89
|
-
targetType.getLogicalTypeID() == LogicalTypeID::FLOAT) {
|
|
150
|
+
if (targetType.getLogicalTypeID() == LogicalTypeID::FLOAT) {
|
|
90
151
|
return std::make_unique<Value>(static_cast<float>(std::stof(value.toString())));
|
|
91
152
|
}
|
|
92
|
-
if (value.getDataType()
|
|
93
|
-
|
|
153
|
+
if (LogicalTypeUtils::isIntegral(value.getDataType()) &&
|
|
154
|
+
LogicalTypeUtils::isIntegral(targetType)) {
|
|
155
|
+
return castIntegerForNested(value, targetType);
|
|
156
|
+
}
|
|
157
|
+
if (value.getDataType().getLogicalTypeID() == LogicalTypeID::LIST &&
|
|
94
158
|
targetType.getLogicalTypeID() == LogicalTypeID::LIST) {
|
|
95
159
|
std::vector<std::unique_ptr<Value>> children;
|
|
96
160
|
const auto& childType = ListType::getChildType(targetType);
|
|
@@ -100,8 +164,7 @@ static std::unique_ptr<Value> copyValueForNested(const Value& value,
|
|
|
100
164
|
}
|
|
101
165
|
return std::make_unique<Value>(targetType.copy(), std::move(children));
|
|
102
166
|
}
|
|
103
|
-
if (value.getDataType()
|
|
104
|
-
value.getDataType().getLogicalTypeID() == LogicalTypeID::MAP &&
|
|
167
|
+
if (value.getDataType().getLogicalTypeID() == LogicalTypeID::MAP &&
|
|
105
168
|
targetType.getLogicalTypeID() == LogicalTypeID::MAP) {
|
|
106
169
|
std::vector<std::unique_ptr<Value>> children;
|
|
107
170
|
const auto& keyType = MapType::getKeyType(targetType);
|
|
@@ -121,6 +184,15 @@ static std::unique_ptr<Value> copyValueForNested(const Value& value,
|
|
|
121
184
|
}
|
|
122
185
|
return std::make_unique<Value>(targetType.copy(), std::move(children));
|
|
123
186
|
}
|
|
187
|
+
if (value.getDataType().getLogicalTypeID() == LogicalTypeID::STRUCT &&
|
|
188
|
+
targetType.getLogicalTypeID() == LogicalTypeID::STRUCT) {
|
|
189
|
+
std::vector<std::unique_ptr<Value>> children;
|
|
190
|
+
for (auto i = 0u; i < NestedVal::getChildrenSize(&value); ++i) {
|
|
191
|
+
children.push_back(copyValueForNested(*NestedVal::getChildVal(&value, i),
|
|
192
|
+
StructType::getFieldType(targetType, static_cast<struct_field_idx_t>(i))));
|
|
193
|
+
}
|
|
194
|
+
return std::make_unique<Value>(targetType.copy(), std::move(children));
|
|
195
|
+
}
|
|
124
196
|
return value.copy();
|
|
125
197
|
}
|
|
126
198
|
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
#include "common/partition_routing_hook.h"
|
|
16
16
|
#include "common/serializer/deserializer.h"
|
|
17
17
|
#include "common/serializer/serializer.h"
|
|
18
|
+
#include "common/string_utils.h"
|
|
18
19
|
#include "extension/extension_manager.h"
|
|
19
20
|
#include "function/function_collection.h"
|
|
20
21
|
#include "main/client_context.h"
|
|
@@ -587,7 +588,7 @@ std::vector<FunctionCatalogEntry*> Catalog::getFunctionEntries(
|
|
|
587
588
|
}
|
|
588
589
|
|
|
589
590
|
bool Catalog::containsMacro(const Transaction* transaction, const std::string& macroName) const {
|
|
590
|
-
return macros->containsEntry(transaction, macroName);
|
|
591
|
+
return macros->containsEntry(transaction, StringUtils::getUpper(macroName));
|
|
591
592
|
}
|
|
592
593
|
|
|
593
594
|
function::ScalarMacroFunction* Catalog::getScalarMacroFunction(const Transaction* transaction,
|
|
@@ -627,11 +628,12 @@ std::vector<std::string> Catalog::getMacroNames(const Transaction* transaction)
|
|
|
627
628
|
}
|
|
628
629
|
|
|
629
630
|
void Catalog::dropMacro(Transaction* transaction, std::string& name) {
|
|
630
|
-
|
|
631
|
+
auto macroName = StringUtils::getUpper(name);
|
|
632
|
+
if (!macros->containsEntry(transaction, macroName)) {
|
|
631
633
|
throw CatalogException{std::format("Macro {} doesn't exist.", name)};
|
|
632
634
|
}
|
|
633
|
-
auto entry =
|
|
634
|
-
macros->dropEntry(transaction,
|
|
635
|
+
auto entry = macros->getEntry(transaction, macroName);
|
|
636
|
+
macros->dropEntry(transaction, macroName, entry->getOID());
|
|
635
637
|
}
|
|
636
638
|
|
|
637
639
|
void Catalog::registerBuiltInFunctions() {
|
|
@@ -134,7 +134,11 @@ std::string PropertyDefinitionCollection::toCypher() const {
|
|
|
134
134
|
if (typeStr.find("MAP") != std::string::npos) {
|
|
135
135
|
StringUtils::replaceAll(typeStr, " ", ",");
|
|
136
136
|
}
|
|
137
|
-
ss << common::StringUtils::quoteIdentifier(def.getName()) << " " << typeStr
|
|
137
|
+
ss << common::StringUtils::quoteIdentifier(def.getName()) << " " << typeStr;
|
|
138
|
+
if (dataType.getLogicalTypeID() != LogicalTypeID::SERIAL && def.hasDefault()) {
|
|
139
|
+
ss << " DEFAULT " << def.getDefaultExpressionName();
|
|
140
|
+
}
|
|
141
|
+
ss << ",";
|
|
138
142
|
}
|
|
139
143
|
return ss.str();
|
|
140
144
|
}
|