duckdb 0.7.2-dev3666.0 → 0.7.2-dev3710.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/package.json +1 -1
- package/src/duckdb/extension/json/json_functions/json_transform.cpp +1 -1
- package/src/duckdb/extension/json/json_functions/read_json.cpp +1 -1
- package/src/duckdb/extension/json/json_functions/read_json_objects.cpp +1 -1
- package/src/duckdb/src/common/exception.cpp +17 -0
- package/src/duckdb/src/common/exception_format_value.cpp +14 -0
- package/src/duckdb/src/common/file_system.cpp +52 -30
- package/src/duckdb/src/common/local_file_system.cpp +5 -3
- package/src/duckdb/src/common/types.cpp +1 -1
- package/src/duckdb/src/core_functions/scalar/list/list_lambdas.cpp +1 -1
- package/src/duckdb/src/execution/operator/persistent/physical_export.cpp +2 -2
- package/src/duckdb/src/function/pragma/pragma_queries.cpp +1 -1
- package/src/duckdb/src/function/table/read_csv.cpp +3 -0
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/common/exception_format_value.hpp +26 -0
- package/src/duckdb/src/include/duckdb/common/file_system.hpp +6 -0
- package/src/duckdb/src/include/duckdb/common/string_util.hpp +18 -0
- package/src/duckdb/src/include/duckdb/parser/expression/function_expression.hpp +1 -1
- package/src/duckdb/src/include/duckdb/parser/expression/operator_expression.hpp +2 -2
- package/src/duckdb/src/include/duckdb/parser/keyword_helper.hpp +5 -0
- package/src/duckdb/src/main/db_instance_cache.cpp +5 -3
- package/src/duckdb/src/main/extension/extension_install.cpp +22 -18
- package/src/duckdb/src/parser/expression/collate_expression.cpp +1 -1
- package/src/duckdb/src/parser/keyword_helper.cpp +11 -1
- package/src/duckdb/src/parser/query_node/select_node.cpp +1 -1
- package/src/duckdb/src/parser/statement/copy_statement.cpp +2 -2
- package/src/duckdb/src/parser/tableref.cpp +1 -1
- package/src/duckdb/src/storage/storage_manager.cpp +3 -0
package/package.json
CHANGED
@@ -659,7 +659,7 @@ static bool TransformObjectToMap(yyjson_val *objects[], yyjson_alc *alc, Vector
|
|
659
659
|
// Transform keys
|
660
660
|
if (!JSONTransform::Transform(keys, alc, MapVector::GetKeys(result), list_size, options)) {
|
661
661
|
throw ConversionException(
|
662
|
-
StringUtil::Format(options.error_message
|
662
|
+
StringUtil::Format(options.error_message + ". Cannot default to NULL, because map keys cannot be NULL"));
|
663
663
|
}
|
664
664
|
|
665
665
|
// Transform values
|
@@ -225,7 +225,7 @@ unique_ptr<FunctionData> ReadJSONBind(ClientContext &context, TableFunctionBindI
|
|
225
225
|
transform_options.error_unknown_key = bind_data->auto_detect && !bind_data->ignore_errors;
|
226
226
|
transform_options.delay_error = true;
|
227
227
|
|
228
|
-
return bind_data;
|
228
|
+
return std::move(bind_data);
|
229
229
|
}
|
230
230
|
|
231
231
|
static void ReadJSONFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) {
|
@@ -16,7 +16,7 @@ unique_ptr<FunctionData> ReadJSONObjectsBind(ClientContext &context, TableFuncti
|
|
16
16
|
bind_data->reader_bind =
|
17
17
|
MultiFileReader::BindOptions(bind_data->options.file_options, bind_data->files, return_types, names);
|
18
18
|
|
19
|
-
return bind_data;
|
19
|
+
return std::move(bind_data);
|
20
20
|
}
|
21
21
|
|
22
22
|
static void ReadJSONObjectsFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) {
|
@@ -59,6 +59,23 @@ string Exception::GetStackTrace(int max_depth) {
|
|
59
59
|
}
|
60
60
|
|
61
61
|
string Exception::ConstructMessageRecursive(const string &msg, std::vector<ExceptionFormatValue> &values) {
|
62
|
+
#ifdef DEBUG
|
63
|
+
// Verify that we have the required amount of values for the message
|
64
|
+
idx_t parameter_count = 0;
|
65
|
+
for (idx_t i = 0; i < msg.size(); i++) {
|
66
|
+
if (msg[i] != '%') {
|
67
|
+
continue;
|
68
|
+
}
|
69
|
+
if (i < msg.size() && msg[i + 1] == '%') {
|
70
|
+
i++;
|
71
|
+
continue;
|
72
|
+
}
|
73
|
+
parameter_count++;
|
74
|
+
}
|
75
|
+
if (parameter_count != values.size()) {
|
76
|
+
throw InternalException("Expected %d parameters, received %d", parameter_count, values.size());
|
77
|
+
}
|
78
|
+
#endif
|
62
79
|
return ExceptionFormatValue::Format(msg, values);
|
63
80
|
}
|
64
81
|
|
@@ -3,6 +3,7 @@
|
|
3
3
|
#include "fmt/format.h"
|
4
4
|
#include "fmt/printf.h"
|
5
5
|
#include "duckdb/common/types/hugeint.hpp"
|
6
|
+
#include "duckdb/parser/keyword_helper.hpp"
|
6
7
|
|
7
8
|
namespace duckdb {
|
8
9
|
|
@@ -40,6 +41,19 @@ template <>
|
|
40
41
|
ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(string value) {
|
41
42
|
return ExceptionFormatValue(std::move(value));
|
42
43
|
}
|
44
|
+
|
45
|
+
template <>
|
46
|
+
ExceptionFormatValue
|
47
|
+
ExceptionFormatValue::CreateFormatValue(SQLString value) { // NOLINT: templating requires us to copy value here
|
48
|
+
return KeywordHelper::WriteQuoted(value.raw_string, '\'');
|
49
|
+
}
|
50
|
+
|
51
|
+
template <>
|
52
|
+
ExceptionFormatValue
|
53
|
+
ExceptionFormatValue::CreateFormatValue(SQLIdentifier value) { // NOLINT: templating requires us to copy value here
|
54
|
+
return KeywordHelper::WriteOptionallyQuoted(value.raw_string, '"');
|
55
|
+
}
|
56
|
+
|
43
57
|
template <>
|
44
58
|
ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(const char *value) {
|
45
59
|
return ExceptionFormatValue(string(value));
|
@@ -11,6 +11,7 @@
|
|
11
11
|
#include "duckdb/main/client_data.hpp"
|
12
12
|
#include "duckdb/main/database.hpp"
|
13
13
|
#include "duckdb/main/extension_helper.hpp"
|
14
|
+
#include "duckdb/common/windows_util.hpp"
|
14
15
|
|
15
16
|
#include <cstdint>
|
16
17
|
#include <cstdio>
|
@@ -53,6 +54,14 @@ bool PathMatched(const string &path, const string &sub_path) {
|
|
53
54
|
|
54
55
|
#ifndef _WIN32
|
55
56
|
|
57
|
+
string FileSystem::GetEnvVariable(const string &name) {
|
58
|
+
const char *env = getenv(name.c_str());
|
59
|
+
if (!env) {
|
60
|
+
return string();
|
61
|
+
}
|
62
|
+
return env;
|
63
|
+
}
|
64
|
+
|
56
65
|
bool FileSystem::IsPathAbsolute(const string &path) {
|
57
66
|
auto path_separator = FileSystem::PathSeparator();
|
58
67
|
return PathMatched(path, path_separator);
|
@@ -85,36 +94,59 @@ string FileSystem::GetWorkingDirectory() {
|
|
85
94
|
}
|
86
95
|
return string(buffer.get());
|
87
96
|
}
|
97
|
+
|
98
|
+
string FileSystem::NormalizeAbsolutePath(const string &path) {
|
99
|
+
D_ASSERT(IsPathAbsolute(path));
|
100
|
+
return path;
|
101
|
+
}
|
102
|
+
|
88
103
|
#else
|
89
104
|
|
90
|
-
|
91
|
-
//
|
92
|
-
auto
|
93
|
-
|
94
|
-
|
105
|
+
string FileSystem::GetEnvVariable(const string &env) {
|
106
|
+
// first convert the environment variable name to the correct encoding
|
107
|
+
auto env_w = WindowsUtil::UTF8ToUnicode(env.c_str());
|
108
|
+
// use _wgetenv to get the value
|
109
|
+
auto res_w = _wgetenv(env_w.c_str());
|
110
|
+
if (!res_w) {
|
111
|
+
// no environment variable of this name found
|
112
|
+
return string();
|
95
113
|
}
|
96
|
-
|
97
|
-
|
98
|
-
|
114
|
+
return WindowsUtil::UnicodeToUTF8(res_w);
|
115
|
+
}
|
116
|
+
|
117
|
+
bool FileSystem::IsPathAbsolute(const string &path) {
|
118
|
+
// 1) A single backslash or forward-slash
|
119
|
+
if (PathMatched(path, "\\") || PathMatched(path, "/")) {
|
99
120
|
return true;
|
100
121
|
}
|
101
|
-
//
|
122
|
+
// 2) A disk designator with a backslash (e.g., C:\ or C:/)
|
102
123
|
auto path_aux = path;
|
103
124
|
path_aux.erase(0, 1);
|
104
|
-
|
105
|
-
if (PathMatched(path_aux, sub_path)) {
|
125
|
+
if (PathMatched(path_aux, ":\\") || PathMatched(path_aux, ":/")) {
|
106
126
|
return true;
|
107
127
|
}
|
108
128
|
return false;
|
109
129
|
}
|
110
130
|
|
131
|
+
string FileSystem::NormalizeAbsolutePath(const string &path) {
|
132
|
+
D_ASSERT(IsPathAbsolute(path));
|
133
|
+
auto result = StringUtil::Lower(FileSystem::ConvertSeparators(path));
|
134
|
+
if (PathMatched(result, "\\")) {
|
135
|
+
// Path starts with a single backslash or forward slash
|
136
|
+
// prepend drive letter
|
137
|
+
return GetWorkingDirectory().substr(0, 2) + result;
|
138
|
+
}
|
139
|
+
return result;
|
140
|
+
}
|
141
|
+
|
111
142
|
string FileSystem::PathSeparator() {
|
112
143
|
return "\\";
|
113
144
|
}
|
114
145
|
|
115
146
|
void FileSystem::SetWorkingDirectory(const string &path) {
|
116
|
-
|
117
|
-
|
147
|
+
auto unicode_path = WindowsUtil::UTF8ToUnicode(path.c_str());
|
148
|
+
if (!SetCurrentDirectoryW(unicode_path.c_str())) {
|
149
|
+
throw IOException("Could not change working directory to \"%s\"", path);
|
118
150
|
}
|
119
151
|
}
|
120
152
|
|
@@ -134,16 +166,16 @@ idx_t FileSystem::GetAvailableMemory() {
|
|
134
166
|
}
|
135
167
|
|
136
168
|
string FileSystem::GetWorkingDirectory() {
|
137
|
-
idx_t count =
|
169
|
+
idx_t count = GetCurrentDirectoryW(0, nullptr);
|
138
170
|
if (count == 0) {
|
139
171
|
throw IOException("Could not get working directory!");
|
140
172
|
}
|
141
|
-
auto buffer = make_unsafe_array<
|
142
|
-
idx_t ret =
|
173
|
+
auto buffer = make_unsafe_array<wchar_t>(count);
|
174
|
+
idx_t ret = GetCurrentDirectoryW(count, buffer.get());
|
143
175
|
if (count != ret + 1) {
|
144
176
|
throw IOException("Could not get working directory!");
|
145
177
|
}
|
146
|
-
return
|
178
|
+
return WindowsUtil::UnicodeToUTF8(buffer.get());
|
147
179
|
}
|
148
180
|
|
149
181
|
#endif
|
@@ -161,13 +193,7 @@ string FileSystem::ConvertSeparators(const string &path) {
|
|
161
193
|
return path;
|
162
194
|
}
|
163
195
|
// on windows-based systems we accept both
|
164
|
-
|
165
|
-
for (idx_t i = 0; i < result.size(); i++) {
|
166
|
-
if (result[i] == '/') {
|
167
|
-
result[i] = separator;
|
168
|
-
}
|
169
|
-
}
|
170
|
-
return result;
|
196
|
+
return StringUtil::Replace(path, "/", separator_str);
|
171
197
|
}
|
172
198
|
|
173
199
|
string FileSystem::ExtractName(const string &path) {
|
@@ -202,14 +228,10 @@ string FileSystem::GetHomeDirectory(optional_ptr<FileOpener> opener) {
|
|
202
228
|
}
|
203
229
|
// fallback to the default home directories for the specified system
|
204
230
|
#ifdef DUCKDB_WINDOWS
|
205
|
-
|
231
|
+
return FileSystem::GetEnvVariable("USERPROFILE");
|
206
232
|
#else
|
207
|
-
|
233
|
+
return FileSystem::GetEnvVariable("HOME");
|
208
234
|
#endif
|
209
|
-
if (homedir) {
|
210
|
-
return homedir;
|
211
|
-
}
|
212
|
-
return string();
|
213
235
|
}
|
214
236
|
|
215
237
|
string FileSystem::GetHomeDirectory() {
|
@@ -162,8 +162,9 @@ static FileType GetFileTypeInternal(int fd) { // LCOV_EXCL_START
|
|
162
162
|
}
|
163
163
|
} // LCOV_EXCL_STOP
|
164
164
|
|
165
|
-
unique_ptr<FileHandle> LocalFileSystem::OpenFile(const string &
|
165
|
+
unique_ptr<FileHandle> LocalFileSystem::OpenFile(const string &path_p, uint8_t flags, FileLockType lock_type,
|
166
166
|
FileCompressionType compression, FileOpener *opener) {
|
167
|
+
auto path = FileSystem::ExpandPath(path_p, opener);
|
167
168
|
if (compression != FileCompressionType::UNCOMPRESSED) {
|
168
169
|
throw NotImplementedException("Unsupported compression type for default file system");
|
169
170
|
}
|
@@ -506,8 +507,9 @@ public:
|
|
506
507
|
};
|
507
508
|
};
|
508
509
|
|
509
|
-
unique_ptr<FileHandle> LocalFileSystem::OpenFile(const string &
|
510
|
+
unique_ptr<FileHandle> LocalFileSystem::OpenFile(const string &path_p, uint8_t flags, FileLockType lock_type,
|
510
511
|
FileCompressionType compression, FileOpener *opener) {
|
512
|
+
auto path = FileSystem::ExpandPath(path_p, opener);
|
511
513
|
if (compression != FileCompressionType::UNCOMPRESSED) {
|
512
514
|
throw NotImplementedException("Unsupported compression type for default file system");
|
513
515
|
}
|
@@ -775,7 +777,7 @@ void LocalFileSystem::MoveFile(const string &source, const string &target) {
|
|
775
777
|
auto source_unicode = WindowsUtil::UTF8ToUnicode(source.c_str());
|
776
778
|
auto target_unicode = WindowsUtil::UTF8ToUnicode(target.c_str());
|
777
779
|
if (!MoveFileW(source_unicode.c_str(), target_unicode.c_str())) {
|
778
|
-
throw IOException("Could not move file");
|
780
|
+
throw IOException("Could not move file: %s", GetLastErrorAsString());
|
779
781
|
}
|
780
782
|
}
|
781
783
|
|
@@ -349,7 +349,7 @@ string LogicalType::ToString() const {
|
|
349
349
|
auto &child_types = StructType::GetChildTypes(*this);
|
350
350
|
string ret = "STRUCT(";
|
351
351
|
for (size_t i = 0; i < child_types.size(); i++) {
|
352
|
-
ret +=
|
352
|
+
ret += StringUtil::Format("%s %s", SQLIdentifier(child_types[i].first), child_types[i].second);
|
353
353
|
if (i < child_types.size() - 1) {
|
354
354
|
ret += ", ";
|
355
355
|
}
|
@@ -77,7 +77,7 @@ static void AppendFilteredToResult(Vector &lambda_vector, list_entry_t *result_e
|
|
77
77
|
}
|
78
78
|
|
79
79
|
// found a true value
|
80
|
-
if (lambda_validity.RowIsValid(entry) && lambda_values[entry]
|
80
|
+
if (lambda_validity.RowIsValid(entry) && lambda_values[entry]) {
|
81
81
|
true_sel.set_index(true_count++, i);
|
82
82
|
curr_list_len++;
|
83
83
|
}
|
@@ -51,8 +51,8 @@ static void WriteCopyStatement(FileSystem &fs, stringstream &ss, CopyInfo &info,
|
|
51
51
|
ss << KeywordHelper::WriteOptionallyQuoted(exported_table.schema_name) << ".";
|
52
52
|
}
|
53
53
|
|
54
|
-
ss <<
|
55
|
-
|
54
|
+
ss << StringUtil::Format("%s FROM %s (", SQLIdentifier(exported_table.table_name),
|
55
|
+
SQLString(exported_table.file_path));
|
56
56
|
|
57
57
|
// write the copy options
|
58
58
|
ss << "FORMAT '" << info.format << "'";
|
@@ -41,7 +41,7 @@ string PragmaShowTables(ClientContext &context, const FunctionParameters ¶me
|
|
41
41
|
)
|
42
42
|
SELECT "name"
|
43
43
|
FROM db_objects
|
44
|
-
ORDER BY "name";)EOF", where_clause, where_clause
|
44
|
+
ORDER BY "name";)EOF", where_clause, where_clause);
|
45
45
|
// clang-format on
|
46
46
|
|
47
47
|
return pragma_query;
|
@@ -586,6 +586,9 @@ bool LineInfo::CanItGetLine(idx_t file_idx, idx_t batch_idx) {
|
|
586
586
|
if (current_batches.empty() || done) {
|
587
587
|
return true;
|
588
588
|
}
|
589
|
+
if (file_idx >= current_batches.size() || current_batches[file_idx].empty()) {
|
590
|
+
return true;
|
591
|
+
}
|
589
592
|
auto min_value = *current_batches[file_idx].begin();
|
590
593
|
if (min_value >= batch_idx) {
|
591
594
|
return true;
|
@@ -1,8 +1,8 @@
|
|
1
1
|
#ifndef DUCKDB_VERSION
|
2
|
-
#define DUCKDB_VERSION "0.7.2-
|
2
|
+
#define DUCKDB_VERSION "0.7.2-dev3710"
|
3
3
|
#endif
|
4
4
|
#ifndef DUCKDB_SOURCE_ID
|
5
|
-
#define DUCKDB_SOURCE_ID "
|
5
|
+
#define DUCKDB_SOURCE_ID "59a4ec3adc"
|
6
6
|
#endif
|
7
7
|
#include "duckdb/function/table/system_functions.hpp"
|
8
8
|
#include "duckdb/main/database.hpp"
|
@@ -15,6 +15,28 @@
|
|
15
15
|
|
16
16
|
namespace duckdb {
|
17
17
|
|
18
|
+
// Helper class to support custom overloading
|
19
|
+
// Escaping " and quoting the value with "
|
20
|
+
class SQLIdentifier {
|
21
|
+
public:
|
22
|
+
SQLIdentifier(const string &raw_string) : raw_string(raw_string) {
|
23
|
+
}
|
24
|
+
|
25
|
+
public:
|
26
|
+
string raw_string;
|
27
|
+
};
|
28
|
+
|
29
|
+
// Helper class to support custom overloading
|
30
|
+
// Escaping ' and quoting the value with '
|
31
|
+
class SQLString {
|
32
|
+
public:
|
33
|
+
SQLString(const string &raw_string) : raw_string(raw_string) {
|
34
|
+
}
|
35
|
+
|
36
|
+
public:
|
37
|
+
string raw_string;
|
38
|
+
};
|
39
|
+
|
18
40
|
enum class PhysicalType : uint8_t;
|
19
41
|
struct LogicalType;
|
20
42
|
|
@@ -47,6 +69,10 @@ public:
|
|
47
69
|
template <>
|
48
70
|
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(PhysicalType value);
|
49
71
|
template <>
|
72
|
+
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(SQLString value);
|
73
|
+
template <>
|
74
|
+
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(SQLIdentifier value);
|
75
|
+
template <>
|
50
76
|
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(LogicalType value);
|
51
77
|
template <>
|
52
78
|
DUCKDB_API ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(float value);
|
@@ -178,6 +178,9 @@ public:
|
|
178
178
|
DUCKDB_API static string PathSeparator();
|
179
179
|
//! Checks if path is starts with separator (i.e., '/' on UNIX '\\' on Windows)
|
180
180
|
DUCKDB_API static bool IsPathAbsolute(const string &path);
|
181
|
+
//! Normalize an absolute path - the goal of normalizing is converting "\test.db" and "C:/test.db" into "C:\test.db"
|
182
|
+
//! so that the database system cache can correctly
|
183
|
+
DUCKDB_API static string NormalizeAbsolutePath(const string &path);
|
181
184
|
//! Join two paths together
|
182
185
|
DUCKDB_API static string JoinPath(const string &a, const string &path);
|
183
186
|
//! Convert separators in a path to the local separators (e.g. convert "/" into \\ on windows)
|
@@ -187,6 +190,9 @@ public:
|
|
187
190
|
//! Extract the name of a file (e.g if the input is lib/example.dll the name is 'example.dll')
|
188
191
|
DUCKDB_API static string ExtractName(const string &path);
|
189
192
|
|
193
|
+
//! Returns the value of an environment variable - or the empty string if it is not set
|
194
|
+
DUCKDB_API static string GetEnvVariable(const string &name);
|
195
|
+
|
190
196
|
//! Whether there is a glob in the string
|
191
197
|
DUCKDB_API static bool HasGlob(const string &str);
|
192
198
|
//! Runs a glob on the file system, returning a list of matching files
|
@@ -15,6 +15,7 @@
|
|
15
15
|
#include <cstring>
|
16
16
|
|
17
17
|
namespace duckdb {
|
18
|
+
|
18
19
|
/**
|
19
20
|
* String Utility Functions
|
20
21
|
* Note that these are not the most efficient implementations (i.e., they copy
|
@@ -85,6 +86,23 @@ public:
|
|
85
86
|
return false;
|
86
87
|
}
|
87
88
|
|
89
|
+
template <class TO>
|
90
|
+
static vector<TO> ConvertStrings(const vector<string> &strings) {
|
91
|
+
vector<TO> result;
|
92
|
+
for (auto &string : strings) {
|
93
|
+
result.emplace_back(string);
|
94
|
+
}
|
95
|
+
return result;
|
96
|
+
}
|
97
|
+
|
98
|
+
static vector<SQLIdentifier> ConvertToSQLIdentifiers(const vector<string> &strings) {
|
99
|
+
return ConvertStrings<SQLIdentifier>(strings);
|
100
|
+
}
|
101
|
+
|
102
|
+
static vector<SQLString> ConvertToSQLStrings(const vector<string> &strings) {
|
103
|
+
return ConvertStrings<SQLString>(strings);
|
104
|
+
}
|
105
|
+
|
88
106
|
//! Returns true if the needle string exists in the haystack
|
89
107
|
DUCKDB_API static bool Contains(const string &haystack, const string &needle);
|
90
108
|
|
@@ -92,7 +92,7 @@ public:
|
|
92
92
|
result += StringUtil::Join(entry.children, entry.children.size(), ", ", [&](const unique_ptr<BASE> &child) {
|
93
93
|
return child->alias.empty() || !add_alias
|
94
94
|
? child->ToString()
|
95
|
-
:
|
95
|
+
: StringUtil::Format("%s := %s", SQLIdentifier(child->alias), child->ToString());
|
96
96
|
});
|
97
97
|
// ordered aggregate
|
98
98
|
if (order_bys && !order_bys->orders.empty()) {
|
@@ -96,8 +96,8 @@ public:
|
|
96
96
|
auto child_string = entry.children[1]->ToString();
|
97
97
|
D_ASSERT(child_string.size() >= 3);
|
98
98
|
D_ASSERT(child_string[0] == '\'' && child_string[child_string.size() - 1] == '\'');
|
99
|
-
return "("
|
100
|
-
|
99
|
+
return StringUtil::Format("(%s).%s", entry.children[0]->ToString(),
|
100
|
+
SQLIdentifier(child_string.substr(1, child_string.size() - 2)));
|
101
101
|
}
|
102
102
|
case ExpressionType::ARRAY_CONSTRUCTOR: {
|
103
103
|
string result = "(ARRAY[";
|
@@ -17,9 +17,14 @@ public:
|
|
17
17
|
//! Returns true if the given text matches a keyword of the parser
|
18
18
|
static bool IsKeyword(const string &text);
|
19
19
|
|
20
|
+
static string EscapeQuotes(const string &text, char quote = '"');
|
21
|
+
|
20
22
|
//! Returns true if the given string needs to be quoted when written as an identifier
|
21
23
|
static bool RequiresQuotes(const string &text, bool allow_caps = true);
|
22
24
|
|
25
|
+
//! Writes a string that is quoted
|
26
|
+
static string WriteQuoted(const string &text, char quote = '\'');
|
27
|
+
|
23
28
|
//! Writes a string that is optionally quoted + escaped so it can be used as an identifier
|
24
29
|
static string WriteOptionallyQuoted(const string &text, char quote = '"', bool allow_caps = true);
|
25
30
|
};
|
@@ -1,8 +1,10 @@
|
|
1
1
|
#include "duckdb/main/db_instance_cache.hpp"
|
2
2
|
#include "duckdb/main/extension_helper.hpp"
|
3
|
+
|
3
4
|
namespace duckdb {
|
4
5
|
|
5
|
-
string GetDBAbsolutePath(const string &
|
6
|
+
string GetDBAbsolutePath(const string &database_p) {
|
7
|
+
auto database = FileSystem::ExpandPath(database_p, nullptr);
|
6
8
|
if (database.empty()) {
|
7
9
|
return ":memory:";
|
8
10
|
}
|
@@ -15,9 +17,9 @@ string GetDBAbsolutePath(const string &database) {
|
|
15
17
|
return database;
|
16
18
|
}
|
17
19
|
if (FileSystem::IsPathAbsolute(database)) {
|
18
|
-
return database;
|
20
|
+
return FileSystem::NormalizeAbsolutePath(database);
|
19
21
|
}
|
20
|
-
return FileSystem::JoinPath(FileSystem::GetWorkingDirectory(), database);
|
22
|
+
return FileSystem::NormalizeAbsolutePath(FileSystem::JoinPath(FileSystem::GetWorkingDirectory(), database));
|
21
23
|
}
|
22
24
|
|
23
25
|
shared_ptr<DuckDB> DBInstanceCache::GetInstanceInternal(const string &database, const DBConfig &config) {
|
@@ -133,6 +133,23 @@ void ExtensionHelper::InstallExtension(ClientContext &context, const string &ext
|
|
133
133
|
InstallExtensionInternal(config, &client_config, fs, local_path, extension, force_install);
|
134
134
|
}
|
135
135
|
|
136
|
+
unsafe_array_ptr<data_t> ReadExtensionFileFromDisk(FileSystem &fs, const string &path, idx_t &file_size) {
|
137
|
+
auto source_file = fs.OpenFile(path, FileFlags::FILE_FLAGS_READ);
|
138
|
+
file_size = source_file->GetFileSize();
|
139
|
+
auto in_buffer = make_unsafe_array<data_t>(file_size);
|
140
|
+
source_file->Read(in_buffer.get(), file_size);
|
141
|
+
source_file->Close();
|
142
|
+
return in_buffer;
|
143
|
+
}
|
144
|
+
|
145
|
+
void WriteExtensionFileToDisk(FileSystem &fs, const string &path, void *data, idx_t data_size) {
|
146
|
+
auto target_file = fs.OpenFile(path, FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_APPEND |
|
147
|
+
FileFlags::FILE_FLAGS_FILE_CREATE_NEW);
|
148
|
+
target_file->Write(data, data_size);
|
149
|
+
target_file->Close();
|
150
|
+
target_file.reset();
|
151
|
+
}
|
152
|
+
|
136
153
|
void ExtensionHelper::InstallExtensionInternal(DBConfig &config, ClientConfig *client_config, FileSystem &fs,
|
137
154
|
const string &local_path, const string &extension, bool force_install) {
|
138
155
|
if (!config.options.enable_external_access) {
|
@@ -152,18 +169,9 @@ void ExtensionHelper::InstallExtensionInternal(DBConfig &config, ClientConfig *c
|
|
152
169
|
}
|
153
170
|
auto is_http_url = StringUtil::Contains(extension, "http://");
|
154
171
|
if (fs.FileExists(extension)) {
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
throw IOException("Failed to read extension from \"%s\"", extension);
|
159
|
-
}
|
160
|
-
std::ofstream out(temp_path, std::ios::binary);
|
161
|
-
out << in.rdbuf();
|
162
|
-
if (out.bad()) {
|
163
|
-
throw IOException("Failed to write extension to \"%s\"", temp_path);
|
164
|
-
}
|
165
|
-
in.close();
|
166
|
-
out.close();
|
172
|
+
idx_t file_size;
|
173
|
+
auto in_buffer = ReadExtensionFileFromDisk(fs, extension, file_size);
|
174
|
+
WriteExtensionFileToDisk(fs, temp_path, in_buffer.get(), file_size);
|
167
175
|
|
168
176
|
fs.MoveFile(temp_path, local_extension_path);
|
169
177
|
return;
|
@@ -225,12 +233,8 @@ void ExtensionHelper::InstallExtensionInternal(DBConfig &config, ClientConfig *c
|
|
225
233
|
}
|
226
234
|
}
|
227
235
|
auto decompressed_body = GZipFileSystem::UncompressGZIPString(res->body);
|
228
|
-
|
229
|
-
|
230
|
-
if (out.bad()) {
|
231
|
-
throw IOException("Failed to write extension to %s", temp_path);
|
232
|
-
}
|
233
|
-
out.close();
|
236
|
+
|
237
|
+
WriteExtensionFileToDisk(fs, temp_path, (void *)decompressed_body.data(), decompressed_body.size());
|
234
238
|
fs.MoveFile(temp_path, local_extension_path);
|
235
239
|
#endif
|
236
240
|
}
|
@@ -15,7 +15,7 @@ CollateExpression::CollateExpression(string collation_p, unique_ptr<ParsedExpres
|
|
15
15
|
}
|
16
16
|
|
17
17
|
string CollateExpression::ToString() const {
|
18
|
-
return
|
18
|
+
return StringUtil::Format("%s COLLATE %s", child->ToString(), SQLIdentifier(collation));
|
19
19
|
}
|
20
20
|
|
21
21
|
bool CollateExpression::Equal(const CollateExpression *a, const CollateExpression *b) {
|
@@ -29,11 +29,21 @@ bool KeywordHelper::RequiresQuotes(const string &text, bool allow_caps) {
|
|
29
29
|
return IsKeyword(text);
|
30
30
|
}
|
31
31
|
|
32
|
+
string KeywordHelper::EscapeQuotes(const string &text, char quote) {
|
33
|
+
return StringUtil::Replace(text, string(1, quote), string(2, quote));
|
34
|
+
}
|
35
|
+
|
36
|
+
string KeywordHelper::WriteQuoted(const string &text, char quote) {
|
37
|
+
// 1. Escapes all occurences of 'quote' by doubling them (escape in SQL)
|
38
|
+
// 2. Adds quotes around the string
|
39
|
+
return string(1, quote) + EscapeQuotes(text) + string(1, quote);
|
40
|
+
}
|
41
|
+
|
32
42
|
string KeywordHelper::WriteOptionallyQuoted(const string &text, char quote, bool allow_caps) {
|
33
43
|
if (!RequiresQuotes(text, allow_caps)) {
|
34
44
|
return text;
|
35
45
|
}
|
36
|
-
return
|
46
|
+
return WriteQuoted(text, quote);
|
37
47
|
}
|
38
48
|
|
39
49
|
} // namespace duckdb
|
@@ -39,7 +39,7 @@ string SelectNode::ToString() const {
|
|
39
39
|
}
|
40
40
|
result += select_list[i]->ToString();
|
41
41
|
if (!select_list[i]->alias.empty()) {
|
42
|
-
result += " AS "
|
42
|
+
result += StringUtil::Format(" AS %s", SQLIdentifier(select_list[i]->alias));
|
43
43
|
}
|
44
44
|
}
|
45
45
|
if (from_table && from_table->type != TableReferenceType::EMPTY) {
|
@@ -86,7 +86,7 @@ string CopyStatement::ToString() const {
|
|
86
86
|
D_ASSERT(!select_statement);
|
87
87
|
result += TablePart(*info);
|
88
88
|
result += " FROM";
|
89
|
-
result += StringUtil::Format("
|
89
|
+
result += StringUtil::Format(" %s", SQLString(info->file_path));
|
90
90
|
result += CopyOptionsToString(info->format, info->options);
|
91
91
|
} else {
|
92
92
|
if (select_statement) {
|
@@ -96,7 +96,7 @@ string CopyStatement::ToString() const {
|
|
96
96
|
result += TablePart(*info);
|
97
97
|
}
|
98
98
|
result += " TO ";
|
99
|
-
result += StringUtil::Format("
|
99
|
+
result += StringUtil::Format("%s", SQLString(info->file_path));
|
100
100
|
result += CopyOptionsToString(info->format, info->options);
|
101
101
|
}
|
102
102
|
return result;
|
@@ -16,7 +16,7 @@ string TableRef::BaseToString(string result) const {
|
|
16
16
|
|
17
17
|
string TableRef::BaseToString(string result, const vector<string> &column_name_alias) const {
|
18
18
|
if (!alias.empty()) {
|
19
|
-
result += " AS "
|
19
|
+
result += StringUtil::Format(" AS %s", SQLIdentifier(alias));
|
20
20
|
}
|
21
21
|
if (!column_name_alias.empty()) {
|
22
22
|
D_ASSERT(!alias.empty());
|
@@ -19,6 +19,9 @@ StorageManager::StorageManager(AttachedDatabase &db, string path_p, bool read_on
|
|
19
19
|
: db(db), path(std::move(path_p)), read_only(read_only) {
|
20
20
|
if (path.empty()) {
|
21
21
|
path = ":memory:";
|
22
|
+
} else {
|
23
|
+
auto &fs = FileSystem::Get(db);
|
24
|
+
this->path = fs.ExpandPath(path);
|
22
25
|
}
|
23
26
|
}
|
24
27
|
|