Skip to content

Commit cee22ca

Browse files
committed
Merge remote-tracking branch 'origin/main' into empty_stubs_improvements
# Conflicts: # test/CMakeLists.txt
2 parents af58ece + d89b73f commit cee22ca

File tree

230 files changed

+25042
-20290
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

230 files changed

+25042
-20290
lines changed

.github/workflows/ODBC.yml

+7-7
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ jobs:
351351

352352
odbc-merge-vendoring-pr:
353353
name: Merge vendoring PR
354-
if: ${{ github.repository == 'duckdb/duckdb-odbc' && github.event_name == 'pull_request' && github.head_ref == format('vendoring-{0}', github.ref_name) }}
354+
if: ${{ github.repository == 'duckdb/duckdb-odbc' && github.event_name == 'pull_request' && github.head_ref == format('vendoring-{0}', github.base_ref) }}
355355
needs:
356356
- odbc-linux-amd64
357357
- odbc-linux-aarch64
@@ -368,8 +368,8 @@ jobs:
368368
env:
369369
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
370370
run: |
371-
# echo "Merging PR number: ${{ github.event.pull_request.number }} with message: ${{ github.event.pull_request.title }}"
372-
gh pr merge vendoring-${{ github.ref_name }} \
371+
echo "Merging PR number: ${{ github.event.pull_request.number }} with message: ${{ github.event.pull_request.title }}"
372+
gh pr merge vendoring-${{ github.base_ref }} \
373373
--rebase \
374374
--subject "${{ github.event.pull_request.title }}" \
375375
--body ""
@@ -378,9 +378,9 @@ jobs:
378378
id: update_vendoring_branch
379379
if: ${{ steps.merge_vendoring_pr.outcome == 'success' }}
380380
run: |
381-
# Delete vendoring-${{ github.ref_name }} branch and re-create it for future PRs
382-
git push --delete origin vendoring-${{ github.ref_name }}
381+
# Delete vendoring-${{ github.base_ref }} branch and re-create it for future PRs
382+
git push --delete origin vendoring-${{ github.base_ref }}
383383
git checkout --track origin/main
384384
git pull --ff-only
385-
git branch vendoring-${{ github.ref_name }}
386-
git push origin vendoring-${{ github.ref_name }}
385+
git branch vendoring-${{ github.base_ref }}
386+
git push origin vendoring-${{ github.base_ref }}

.github/workflows/Vendor.yml

+2-6
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ jobs:
5151
git checkout ${{ inputs.duckdb-sha }}
5252
5353
- name: Vendor sources
54-
if: ${{ steps.checkout_engine_rev.outcome == 'success' }}
5554
id: vendor
5655
run: |
5756
REV=$(cd .git/duckdb && git rev-parse --short HEAD && cd ../..)
@@ -73,7 +72,6 @@ jobs:
7372
7473
- name: Commit and push the changes
7574
id: commit_and_push
76-
if: ${{ steps.vendor.outcome == 'success' }}
7775
run: |
7876
MSG="Update vendored DuckDB sources to ${{ steps.vendor.outputs.vendor_rev }}"
7977
git commit -m "${MSG}"
@@ -89,7 +87,6 @@ jobs:
8987
9088
- name: Check PR exists
9189
id: check_pr_exists
92-
if: ${{ steps.commit_and_push.outcome == 'success' }}
9390
env:
9491
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
9592
run: |
@@ -105,7 +102,6 @@ jobs:
105102
106103
- name: Prepare PR message
107104
id: prepare_pr_message
108-
if: ${{ steps.check_pr_exists.outcome == 'success' }}
109105
run: |
110106
DATE="$(date +"%Y-%m-%d %H:%M:%S")"
111107
CHANGE_LABEL="duckdb/duckdb#${{ steps.vendor.outputs.vendor_rev }}"
@@ -116,7 +112,7 @@ jobs:
116112
117113
- name: Create PR
118114
id: create_pr
119-
if: ${{ steps.prepare_pr_message.outcome == 'success' && steps.check_pr_exists.outputs.pr_exists == 'false' }}
115+
if: ${{ steps.check_pr_exists.outputs.pr_exists == 'false' }}
120116
env:
121117
# We cannot use default workflow's GITHUB_TOKEN here, because
122118
# it is restricted to not trigger 'pull_request' event that
@@ -136,7 +132,7 @@ jobs:
136132
137133
- name: Update PR
138134
id: update_pr
139-
if: ${{ steps.prepare_pr_message.outcome == 'success' && steps.check_pr_exists.outputs.pr_exists == 'true' }}
135+
if: ${{ steps.check_pr_exists.outputs.pr_exists == 'true' }}
140136
env:
141137
# We cannot use default workflow's GITHUB_TOKEN here, because
142138
# it is restricted to not trigger 'pull_request' event that

CMakeLists.txt

+1-1
Large diffs are not rendered by default.

src/connect/connect.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "connect.hpp"
22
#include "duckdb/main/db_instance_cache.hpp"
3+
#include "duckdb/common/virtual_file_system.hpp"
34
#include <iostream>
45
#include <utility>
56

@@ -129,6 +130,18 @@ SQLRETURN Connect::ReadFromIniFile() {
129130
return SQL_SUCCESS;
130131
}
131132

133+
static void NormalizeWindowsPathSeparators(case_insensitive_map_t<duckdb::Value> &config_map,
134+
const std::string &option_name) {
135+
auto it = config_map.find(option_name);
136+
if (it == config_map.end()) {
137+
return;
138+
}
139+
auto value_str = it->second.GetValue<std::string>();
140+
auto value_str_norm = duckdb::StringUtil::Replace(value_str, "\\", "/");
141+
config_map.erase(option_name);
142+
config_map.emplace(option_name, std::move(value_str_norm));
143+
}
144+
132145
SQLRETURN Connect::SetConnection() {
133146
#if defined ODBC_LINK_ODBCINST || defined WIN32
134147
ReadFromIniFile();
@@ -141,8 +154,30 @@ SQLRETURN Connect::SetConnection() {
141154
config_map.erase("dsn");
142155

143156
config.SetOptionByName("duckdb_api", "odbc");
157+
158+
// When 'enable_external_access' is set to 'false' then it is not allowed to change
159+
// 'allowed_paths' or 'allowed_directories' options, so we are setting 'enable_external_access'
160+
// after all other options
161+
std::string enable_external_access;
162+
auto it = config_map.find("enable_external_access");
163+
if (it != config_map.end()) {
164+
enable_external_access = it->second.GetValue<std::string>();
165+
config_map.erase(it);
166+
}
167+
168+
#ifdef _WIN32
169+
// Back slashes are not accepted for 'allowed_paths' or 'allowed_directories' options
170+
NormalizeWindowsPathSeparators(config_map, "allowed_paths");
171+
NormalizeWindowsPathSeparators(config_map, "allowed_directories");
172+
#endif // _WIN32
173+
174+
// Validate and set all options
144175
config.SetOptionsByName(config_map);
145176

177+
if (!enable_external_access.empty()) {
178+
config.SetOptionByName("enable_external_access", duckdb::Value(enable_external_access));
179+
}
180+
146181
bool cache_instance = database != IN_MEMORY_PATH;
147182

148183
try {
@@ -168,4 +203,8 @@ Connect::Connect(OdbcHandleDbc *dbc_p, string input_str_p) : dbc(dbc_p), input_s
168203
}
169204
seen_config_options["dsn"] = false;
170205
seen_config_options["database"] = false;
206+
207+
// Required for settings like 'allowed_directories' that use
208+
// file separator when checking the property value.
209+
config.file_system = duckdb::make_uniq<duckdb::VirtualFileSystem>();
171210
}

src/duckdb/extension/core_functions/include/core_functions/scalar/string_functions.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ struct FormatFun {
100100
struct FormatBytesFun {
101101
static constexpr const char *Name = "format_bytes";
102102
static constexpr const char *Parameters = "bytes";
103-
static constexpr const char *Description = "Converts bytes to a human-readable presentation (e.g. 16000 -> 15.6 KiB)";
103+
static constexpr const char *Description = "Converts bytes to a human-readable presentation (e.g., 16000 -> 15.6 KiB)";
104104
static constexpr const char *Example = "format_bytes(1000 * 16)";
105105
static constexpr const char *Categories = "";
106106

@@ -116,7 +116,7 @@ struct FormatreadablesizeFun {
116116
struct FormatreadabledecimalsizeFun {
117117
static constexpr const char *Name = "formatReadableDecimalSize";
118118
static constexpr const char *Parameters = "bytes";
119-
static constexpr const char *Description = "Converts bytes to a human-readable presentation (e.g. 16000 -> 16.0 KB)";
119+
static constexpr const char *Description = "Converts bytes to a human-readable presentation (e.g., 16000 -> 16.0 KB)";
120120
static constexpr const char *Example = "format_bytes(1000 * 16)";
121121
static constexpr const char *Categories = "";
122122

src/duckdb/extension/core_functions/scalar/map/map_extract.cpp

+3-4
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static void MapExtractValueFunc(DataChunk &args, ExpressionState &state, Vector
5757

5858
// Collect the matching positions
5959
Vector pos_vec(LogicalType::INTEGER, count);
60-
ListSearchOp<true>(map_vec, key_vec, arg_vec, pos_vec, args.size());
60+
ListSearchOp<int32_t>(map_vec, key_vec, arg_vec, pos_vec, args.size());
6161

6262
UnifiedVectorFormat pos_format;
6363
UnifiedVectorFormat lst_format;
@@ -68,7 +68,6 @@ static void MapExtractValueFunc(DataChunk &args, ExpressionState &state, Vector
6868
const auto pos_data = UnifiedVectorFormat::GetData<int32_t>(pos_format);
6969
const auto inc_list_data = ListVector::GetData(map_vec);
7070

71-
auto &result_validity = FlatVector::Validity(result);
7271
for (idx_t row_idx = 0; row_idx < count; row_idx++) {
7372
auto lst_idx = lst_format.sel->get_index(row_idx);
7473
if (!lst_format.validity.RowIsValid(lst_idx)) {
@@ -79,7 +78,7 @@ static void MapExtractValueFunc(DataChunk &args, ExpressionState &state, Vector
7978
const auto pos_idx = pos_format.sel->get_index(row_idx);
8079
if (!pos_format.validity.RowIsValid(pos_idx)) {
8180
// We didnt find the key in the map, so return NULL
82-
result_validity.SetInvalid(row_idx);
81+
FlatVector::SetNull(result, row_idx, true);
8382
continue;
8483
}
8584

@@ -118,7 +117,7 @@ static void MapExtractListFunc(DataChunk &args, ExpressionState &state, Vector &
118117

119118
// Collect the matching positions
120119
Vector pos_vec(LogicalType::INTEGER, count);
121-
ListSearchOp<true>(map_vec, key_vec, arg_vec, pos_vec, args.size());
120+
ListSearchOp<int32_t>(map_vec, key_vec, arg_vec, pos_vec, args.size());
122121

123122
UnifiedVectorFormat val_format;
124123
UnifiedVectorFormat pos_format;

src/duckdb/extension/core_functions/scalar/math/numeric.cpp

+53-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "duckdb/common/operator/decimal_cast_operators.hpp"
12
#include "duckdb/common/vector_operations/vector_operations.hpp"
23
#include "duckdb/common/algorithm.hpp"
34
#include "duckdb/common/likely.hpp"
@@ -566,6 +567,34 @@ struct RoundDecimalOperator {
566567
}
567568
};
568569

570+
struct RoundIntegerOperator {
571+
template <class TA, class TB, class TR>
572+
static inline TR Operation(TA input, TB precision) {
573+
if (precision < 0) {
574+
// Do all the arithmetic at higher precision
575+
using POWERS_OF_TEN_CLASS = typename DecimalCastTraits<TA>::POWERS_OF_TEN_CLASS;
576+
if (precision <= -POWERS_OF_TEN_CLASS::CACHED_POWERS_OF_TEN) {
577+
return 0;
578+
}
579+
const auto power_of_ten = POWERS_OF_TEN_CLASS::POWERS_OF_TEN[-precision];
580+
auto addition = power_of_ten / 2;
581+
if (input < 0) {
582+
addition = -addition;
583+
}
584+
addition += input;
585+
addition /= power_of_ten;
586+
if (addition) {
587+
return UnsafeNumericCast<TR>(addition * power_of_ten);
588+
} else {
589+
return 0;
590+
}
591+
} else {
592+
// Rounding integers to higher precision is a NOP
593+
return input;
594+
}
595+
}
596+
};
597+
569598
struct RoundPrecisionFunctionData : public FunctionData {
570599
explicit RoundPrecisionFunctionData(int32_t target_scale) : target_scale(target_scale) {
571600
}
@@ -698,10 +727,6 @@ ScalarFunctionSet RoundFun::GetFunctions() {
698727
scalar_function_t round_func = nullptr;
699728
bind_scalar_function_t bind_func = nullptr;
700729
bind_scalar_function_t bind_prec_func = nullptr;
701-
if (type.IsIntegral()) {
702-
// no round for integral numbers
703-
continue;
704-
}
705730
switch (type.id()) {
706731
case LogicalTypeId::FLOAT:
707732
round_func = ScalarFunction::UnaryFunction<float, float, RoundOperator>;
@@ -715,7 +740,31 @@ ScalarFunctionSet RoundFun::GetFunctions() {
715740
bind_func = BindGenericRoundFunctionDecimal<RoundDecimalOperator>;
716741
bind_prec_func = BindDecimalRoundPrecision;
717742
break;
743+
case LogicalTypeId::TINYINT:
744+
round_func = ScalarFunction::NopFunction;
745+
round_prec_func = ScalarFunction::BinaryFunction<int8_t, int32_t, int8_t, RoundIntegerOperator>;
746+
break;
747+
case LogicalTypeId::SMALLINT:
748+
round_func = ScalarFunction::NopFunction;
749+
round_prec_func = ScalarFunction::BinaryFunction<int16_t, int32_t, int16_t, RoundIntegerOperator>;
750+
break;
751+
case LogicalTypeId::INTEGER:
752+
round_func = ScalarFunction::NopFunction;
753+
round_prec_func = ScalarFunction::BinaryFunction<int32_t, int32_t, int32_t, RoundIntegerOperator>;
754+
break;
755+
case LogicalTypeId::BIGINT:
756+
round_func = ScalarFunction::NopFunction;
757+
round_prec_func = ScalarFunction::BinaryFunction<int64_t, int32_t, int64_t, RoundIntegerOperator>;
758+
break;
759+
case LogicalTypeId::HUGEINT:
760+
round_func = ScalarFunction::NopFunction;
761+
round_prec_func = ScalarFunction::BinaryFunction<hugeint_t, int32_t, hugeint_t, RoundIntegerOperator>;
762+
break;
718763
default:
764+
if (type.IsIntegral()) {
765+
// no round for integral numbers
766+
continue;
767+
}
719768
throw InternalException("Unimplemented numeric type for function \"floor\"");
720769
}
721770
round.AddFunction(ScalarFunction({type}, type, round_func, bind_func));

src/duckdb/extension/icu/icu-table-range.cpp

+39-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
#include "duckdb/common/exception.hpp"
2+
#include "duckdb/common/operator/subtract.hpp"
23
#include "duckdb/common/types/interval.hpp"
34
#include "duckdb/common/types/timestamp.hpp"
45
#include "duckdb/main/extension_util.hpp"
56
#include "duckdb/function/function_set.hpp"
67
#include "duckdb/function/table_function.hpp"
7-
#include "duckdb/parser/parsed_data/create_table_function_info.hpp"
88
#include "include/icu-datefunc.hpp"
99
#include "unicode/calendar.h"
1010
#include "tz_calendar.hpp"
@@ -17,10 +17,10 @@ struct ICUTableRange {
1717
struct ICURangeBindData : public TableFunctionData {
1818
ICURangeBindData(const ICURangeBindData &other)
1919
: TableFunctionData(other), tz_setting(other.tz_setting), cal_setting(other.cal_setting),
20-
calendar(other.calendar->clone()) {
20+
calendar(other.calendar->clone()), cardinality(other.cardinality) {
2121
}
2222

23-
explicit ICURangeBindData(ClientContext &context) {
23+
explicit ICURangeBindData(ClientContext &context, const vector<Value> &inputs) {
2424
Value tz_value;
2525
if (context.TryGetCurrentSetting("TimeZone", tz_value)) {
2626
tz_setting = tz_value.ToString();
@@ -43,11 +43,36 @@ struct ICUTableRange {
4343
if (U_FAILURE(success)) {
4444
throw InternalException("Unable to create ICU calendar.");
4545
}
46+
47+
timestamp_tz_t bounds[2];
48+
interval_t step;
49+
for (idx_t i = 0; i < inputs.size(); i++) {
50+
if (inputs[i].IsNull()) {
51+
return;
52+
}
53+
if (i >= 2) {
54+
step = inputs[i].GetValue<interval_t>();
55+
} else {
56+
bounds[i] = inputs[i].GetValue<timestamp_tz_t>();
57+
}
58+
}
59+
// Estimate cardinality using micros.
60+
int64_t increment = 0;
61+
if (!Interval::TryGetMicro(step, increment) || !increment) {
62+
return;
63+
}
64+
int64_t delta = 0;
65+
if (!TrySubtractOperator::Operation(bounds[1].value, bounds[0].value, delta)) {
66+
return;
67+
}
68+
69+
cardinality = idx_t(delta / increment);
4670
}
4771

4872
string tz_setting;
4973
string cal_setting;
5074
CalendarPtr calendar;
75+
idx_t cardinality;
5176
};
5277

5378
struct ICURangeLocalState : public LocalTableFunctionState {
@@ -130,7 +155,7 @@ struct ICUTableRange {
130155
template <bool GENERATE_SERIES>
131156
static unique_ptr<FunctionData> Bind(ClientContext &context, TableFunctionBindInput &input,
132157
vector<LogicalType> &return_types, vector<string> &names) {
133-
auto result = make_uniq<ICURangeBindData>(context);
158+
auto result = make_uniq<ICURangeBindData>(context, input.inputs);
134159

135160
return_types.push_back(LogicalType::TIMESTAMP_TZ);
136161
if (GENERATE_SERIES) {
@@ -147,6 +172,14 @@ struct ICUTableRange {
147172
return make_uniq<ICURangeLocalState>();
148173
}
149174

175+
static unique_ptr<NodeStatistics> Cardinality(ClientContext &context, const FunctionData *bind_data_p) {
176+
if (!bind_data_p) {
177+
return nullptr;
178+
}
179+
auto &bind_data = bind_data_p->Cast<ICURangeBindData>();
180+
return make_uniq<NodeStatistics>(bind_data.cardinality, bind_data.cardinality);
181+
}
182+
150183
template <bool GENERATE_SERIES>
151184
static OperatorResultType ICUTableRangeFunction(ExecutionContext &context, TableFunctionInput &data_p,
152185
DataChunk &input, DataChunk &output) {
@@ -201,6 +234,7 @@ struct ICUTableRange {
201234
TableFunction range_function({LogicalType::TIMESTAMP_TZ, LogicalType::TIMESTAMP_TZ, LogicalType::INTERVAL},
202235
nullptr, Bind<false>, nullptr, RangeDateTimeLocalInit);
203236
range_function.in_out_function = ICUTableRangeFunction<false>;
237+
range_function.cardinality = Cardinality;
204238
range.AddFunction(range_function);
205239
ExtensionUtil::RegisterFunction(db, range);
206240

@@ -210,6 +244,7 @@ struct ICUTableRange {
210244
{LogicalType::TIMESTAMP_TZ, LogicalType::TIMESTAMP_TZ, LogicalType::INTERVAL}, nullptr, Bind<true>, nullptr,
211245
RangeDateTimeLocalInit);
212246
generate_series_function.in_out_function = ICUTableRangeFunction<true>;
247+
generate_series_function.cardinality = Cardinality;
213248
generate_series.AddFunction(generate_series_function);
214249
ExtensionUtil::RegisterFunction(db, generate_series);
215250
}

0 commit comments

Comments
 (0)