duckdb 0.6.2-dev1736.0 → 0.6.2-dev1746.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/src/catalog/default/default_functions.cpp +1 -0
- package/src/duckdb/src/common/file_system.cpp +17 -2
- package/src/duckdb/src/function/pragma/pragma_queries.cpp +22 -4
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/common/file_system.hpp +5 -1
- package/src/duckdb/src/include/duckdb/parser/parsed_data/copy_info.hpp +2 -2
- package/src/duckdb/src/include/duckdb/parser/statement/copy_statement.hpp +4 -0
- package/src/duckdb/src/main/client_context.cpp +1 -0
- package/src/duckdb/src/parser/statement/copy_statement.cpp +102 -0
- package/src/duckdb/src/planner/binder/statement/bind_export.cpp +16 -13
package/package.json
CHANGED
|
@@ -93,6 +93,7 @@ static DefaultMacro internal_macros[] = {
|
|
|
93
93
|
{DEFAULT_SCHEMA, "generate_subscripts", {"arr", "dim", nullptr}, "unnest(generate_series(1, array_length(arr, dim)))"},
|
|
94
94
|
{DEFAULT_SCHEMA, "fdiv", {"x", "y", nullptr}, "floor(x/y)"},
|
|
95
95
|
{DEFAULT_SCHEMA, "fmod", {"x", "y", nullptr}, "(x-y*floor(x/y))"},
|
|
96
|
+
{DEFAULT_SCHEMA, "count_if", {"l", nullptr}, "sum(if(l, 1, 0))"},
|
|
96
97
|
|
|
97
98
|
// algebraic list aggregates
|
|
98
99
|
{DEFAULT_SCHEMA, "list_avg", {"l", nullptr}, "list_aggr(l, 'avg')"},
|
|
@@ -172,7 +172,7 @@ string FileSystem::ConvertSeparators(const string &path) {
|
|
|
172
172
|
return result;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
string FileSystem::
|
|
175
|
+
string FileSystem::ExtractName(const string &path) {
|
|
176
176
|
if (path.empty()) {
|
|
177
177
|
return string();
|
|
178
178
|
}
|
|
@@ -180,7 +180,14 @@ string FileSystem::ExtractBaseName(const string &path) {
|
|
|
180
180
|
auto sep = PathSeparator();
|
|
181
181
|
auto splits = StringUtil::Split(normalized_path, sep);
|
|
182
182
|
D_ASSERT(!splits.empty());
|
|
183
|
-
|
|
183
|
+
return splits.back();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
string FileSystem::ExtractBaseName(const string &path) {
|
|
187
|
+
if (path.empty()) {
|
|
188
|
+
return string();
|
|
189
|
+
}
|
|
190
|
+
auto vec = StringUtil::Split(ExtractName(path), ".");
|
|
184
191
|
D_ASSERT(!vec.empty());
|
|
185
192
|
return vec[0];
|
|
186
193
|
}
|
|
@@ -239,6 +246,14 @@ int64_t FileSystem::Write(FileHandle &handle, void *buffer, int64_t nr_bytes) {
|
|
|
239
246
|
throw NotImplementedException("%s: Write is not implemented!", GetName());
|
|
240
247
|
}
|
|
241
248
|
|
|
249
|
+
string FileSystem::GetFileExtension(FileHandle &handle) {
|
|
250
|
+
auto dot_location = handle.path.rfind('.');
|
|
251
|
+
if (dot_location != std::string::npos) {
|
|
252
|
+
return handle.path.substr(dot_location + 1, std::string::npos);
|
|
253
|
+
}
|
|
254
|
+
return string();
|
|
255
|
+
}
|
|
256
|
+
|
|
242
257
|
int64_t FileSystem::GetFileSize(FileHandle &handle) {
|
|
243
258
|
throw NotImplementedException("%s: GetFileSize is not implemented!", GetName());
|
|
244
259
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#include "duckdb/function/pragma/pragma_functions.hpp"
|
|
2
2
|
#include "duckdb/common/string_util.hpp"
|
|
3
3
|
#include "duckdb/common/file_system.hpp"
|
|
4
|
+
#include "duckdb/parser/statement/export_statement.hpp"
|
|
5
|
+
#include "duckdb/parser/statement/copy_statement.hpp"
|
|
6
|
+
#include "duckdb/parser/parser.hpp"
|
|
4
7
|
#include "duckdb/main/config.hpp"
|
|
5
8
|
|
|
6
9
|
namespace duckdb {
|
|
@@ -73,7 +76,7 @@ string PragmaImportDatabase(ClientContext &context, const FunctionParameters &pa
|
|
|
73
76
|
auto &fs = FileSystem::GetFileSystem(context);
|
|
74
77
|
auto *opener = FileSystem::GetFileOpener(context);
|
|
75
78
|
|
|
76
|
-
string
|
|
79
|
+
string final_query;
|
|
77
80
|
// read the "shema.sql" and "load.sql" files
|
|
78
81
|
vector<string> files = {"schema.sql", "load.sql"};
|
|
79
82
|
for (auto &file : files) {
|
|
@@ -83,10 +86,25 @@ string PragmaImportDatabase(ClientContext &context, const FunctionParameters &pa
|
|
|
83
86
|
auto fsize = fs.GetFileSize(*handle);
|
|
84
87
|
auto buffer = unique_ptr<char[]>(new char[fsize]);
|
|
85
88
|
fs.Read(*handle, buffer.get(), fsize);
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
auto query = string(buffer.get(), fsize);
|
|
90
|
+
// Replace the placeholder with the path provided to IMPORT
|
|
91
|
+
if (file == "load.sql") {
|
|
92
|
+
Parser parser;
|
|
93
|
+
parser.ParseQuery(query);
|
|
94
|
+
auto copy_statements = move(parser.statements);
|
|
95
|
+
query.clear();
|
|
96
|
+
for (auto &statement_p : copy_statements) {
|
|
97
|
+
D_ASSERT(statement_p->type == StatementType::COPY_STATEMENT);
|
|
98
|
+
auto &statement = (CopyStatement &)*statement_p;
|
|
99
|
+
auto &info = *statement.info;
|
|
100
|
+
auto file_name = fs.ExtractName(info.file_path);
|
|
101
|
+
info.file_path = fs.JoinPath(parameters.values[0].ToString(), file_name);
|
|
102
|
+
query += statement.ToString() + ";";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
final_query += query;
|
|
88
106
|
}
|
|
89
|
-
return
|
|
107
|
+
return final_query;
|
|
90
108
|
}
|
|
91
109
|
|
|
92
110
|
string PragmaDatabaseSize(ClientContext &context, const FunctionParameters ¶meters) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#ifndef DUCKDB_VERSION
|
|
2
|
-
#define DUCKDB_VERSION "0.6.2-
|
|
2
|
+
#define DUCKDB_VERSION "0.6.2-dev1746"
|
|
3
3
|
#endif
|
|
4
4
|
#ifndef DUCKDB_SOURCE_ID
|
|
5
|
-
#define DUCKDB_SOURCE_ID "
|
|
5
|
+
#define DUCKDB_SOURCE_ID "6137998b60"
|
|
6
6
|
#endif
|
|
7
7
|
#include "duckdb/function/table/system_functions.hpp"
|
|
8
8
|
#include "duckdb/main/database.hpp"
|
|
@@ -128,6 +128,8 @@ public:
|
|
|
128
128
|
//! Write nr_bytes from the buffer into the file, moving the file pointer forward by nr_bytes.
|
|
129
129
|
DUCKDB_API virtual int64_t Write(FileHandle &handle, void *buffer, int64_t nr_bytes);
|
|
130
130
|
|
|
131
|
+
//! Returns the extension of the file, or empty string if no extension was found.
|
|
132
|
+
DUCKDB_API string GetFileExtension(FileHandle &handle);
|
|
131
133
|
//! Returns the file size of a file handle, returns -1 on error
|
|
132
134
|
DUCKDB_API virtual int64_t GetFileSize(FileHandle &handle);
|
|
133
135
|
//! Returns the file last modified time of a file handle, returns timespec with zero on all attributes on error
|
|
@@ -176,8 +178,10 @@ public:
|
|
|
176
178
|
DUCKDB_API static string JoinPath(const string &a, const string &path);
|
|
177
179
|
//! Convert separators in a path to the local separators (e.g. convert "/" into \\ on windows)
|
|
178
180
|
DUCKDB_API static string ConvertSeparators(const string &path);
|
|
179
|
-
//! Extract the base name of a file (e.g. if the input is lib/example.dll the base name is example)
|
|
181
|
+
//! Extract the base name of a file (e.g. if the input is lib/example.dll the base name is 'example')
|
|
180
182
|
DUCKDB_API static string ExtractBaseName(const string &path);
|
|
183
|
+
//! Extract the name of a file (e.g if the input is lib/example.dll the name is 'example.dll')
|
|
184
|
+
DUCKDB_API static string ExtractName(const string &path);
|
|
181
185
|
|
|
182
186
|
//! Runs a glob on the file system, returning a list of matching files
|
|
183
187
|
DUCKDB_API virtual vector<string> Glob(const string &path, FileOpener *opener = nullptr);
|
|
@@ -27,12 +27,12 @@ struct CopyInfo : public ParseInfo {
|
|
|
27
27
|
string table;
|
|
28
28
|
//! List of columns to copy to/from
|
|
29
29
|
vector<string> select_list;
|
|
30
|
-
//! The file path to copy to/from
|
|
31
|
-
string file_path;
|
|
32
30
|
//! Whether or not this is a copy to file (false) or copy from a file (true)
|
|
33
31
|
bool is_from;
|
|
34
32
|
//! The file format of the external file
|
|
35
33
|
string format;
|
|
34
|
+
//! The file path to copy to/from
|
|
35
|
+
string file_path;
|
|
36
36
|
//! Set of (key, value) options
|
|
37
37
|
unordered_map<string, vector<Value>> options;
|
|
38
38
|
|
|
@@ -21,11 +21,15 @@ public:
|
|
|
21
21
|
unique_ptr<CopyInfo> info;
|
|
22
22
|
// The SQL statement used instead of a table when copying data out to a file
|
|
23
23
|
unique_ptr<QueryNode> select_statement;
|
|
24
|
+
string ToString() const override;
|
|
25
|
+
string CopyOptionsToString(const string &format, const unordered_map<string, vector<Value>> &options) const;
|
|
24
26
|
|
|
25
27
|
protected:
|
|
26
28
|
CopyStatement(const CopyStatement &other);
|
|
27
29
|
|
|
28
30
|
public:
|
|
29
31
|
unique_ptr<SQLStatement> Copy() const override;
|
|
32
|
+
|
|
33
|
+
private:
|
|
30
34
|
};
|
|
31
35
|
} // namespace duckdb
|
|
@@ -665,6 +665,7 @@ unique_ptr<PendingQueryResult> ClientContext::PendingStatementOrPreparedStatemen
|
|
|
665
665
|
statement = std::move(copied_statement);
|
|
666
666
|
break;
|
|
667
667
|
}
|
|
668
|
+
case StatementType::COPY_STATEMENT:
|
|
668
669
|
case StatementType::INSERT_STATEMENT:
|
|
669
670
|
case StatementType::DELETE_STATEMENT:
|
|
670
671
|
case StatementType::UPDATE_STATEMENT: {
|
|
@@ -11,6 +11,108 @@ CopyStatement::CopyStatement(const CopyStatement &other) : SQLStatement(other),
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
string ConvertOptionValueToString(const Value &val) {
|
|
15
|
+
auto type = val.type().id();
|
|
16
|
+
switch (type) {
|
|
17
|
+
case LogicalTypeId::VARCHAR:
|
|
18
|
+
return KeywordHelper::WriteOptionallyQuoted(val.ToString());
|
|
19
|
+
default:
|
|
20
|
+
return val.ToString();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
string CopyStatement::CopyOptionsToString(const string &format,
|
|
25
|
+
const unordered_map<string, vector<Value>> &options) const {
|
|
26
|
+
if (format.empty() && options.empty()) {
|
|
27
|
+
return string();
|
|
28
|
+
}
|
|
29
|
+
string result;
|
|
30
|
+
|
|
31
|
+
result += " (";
|
|
32
|
+
if (!format.empty()) {
|
|
33
|
+
result += " FORMAT ";
|
|
34
|
+
result += format;
|
|
35
|
+
}
|
|
36
|
+
for (auto it = options.begin(); it != options.end(); it++) {
|
|
37
|
+
if (!format.empty() || it != options.begin()) {
|
|
38
|
+
result += ", ";
|
|
39
|
+
}
|
|
40
|
+
auto &name = it->first;
|
|
41
|
+
auto &values = it->second;
|
|
42
|
+
|
|
43
|
+
result += name + " ";
|
|
44
|
+
if (values.empty()) {
|
|
45
|
+
// Options like HEADER don't need an explicit value
|
|
46
|
+
// just providing the name already sets it to true
|
|
47
|
+
} else if (values.size() == 1) {
|
|
48
|
+
result += ConvertOptionValueToString(values[0]);
|
|
49
|
+
} else {
|
|
50
|
+
result += "( ";
|
|
51
|
+
for (idx_t i = 0; i < values.size(); i++) {
|
|
52
|
+
auto &value = values[i];
|
|
53
|
+
if (i) {
|
|
54
|
+
result += ", ";
|
|
55
|
+
}
|
|
56
|
+
result += KeywordHelper::WriteOptionallyQuoted(value.ToString());
|
|
57
|
+
}
|
|
58
|
+
result += " )";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
result += " )";
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// COPY table-name (c1, c2, ..)
|
|
66
|
+
string TablePart(const CopyInfo &info) {
|
|
67
|
+
string result;
|
|
68
|
+
|
|
69
|
+
if (!info.catalog.empty()) {
|
|
70
|
+
result += KeywordHelper::WriteOptionallyQuoted(info.catalog) + ".";
|
|
71
|
+
}
|
|
72
|
+
if (!info.schema.empty()) {
|
|
73
|
+
result += KeywordHelper::WriteOptionallyQuoted(info.schema) + ".";
|
|
74
|
+
}
|
|
75
|
+
D_ASSERT(!info.table.empty());
|
|
76
|
+
result += KeywordHelper::WriteOptionallyQuoted(info.table);
|
|
77
|
+
|
|
78
|
+
// (c1, c2, ..)
|
|
79
|
+
if (!info.select_list.empty()) {
|
|
80
|
+
result += " (";
|
|
81
|
+
for (idx_t i = 0; i < info.select_list.size(); i++) {
|
|
82
|
+
if (i > 0) {
|
|
83
|
+
result += ", ";
|
|
84
|
+
}
|
|
85
|
+
result += KeywordHelper::WriteOptionallyQuoted(info.select_list[i]);
|
|
86
|
+
}
|
|
87
|
+
result += " )";
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
string CopyStatement::ToString() const {
|
|
93
|
+
string result;
|
|
94
|
+
|
|
95
|
+
result += "COPY ";
|
|
96
|
+
if (info->is_from) {
|
|
97
|
+
D_ASSERT(!select_statement);
|
|
98
|
+
result += TablePart(*info);
|
|
99
|
+
result += " FROM";
|
|
100
|
+
result += StringUtil::Format(" '%s'", info->file_path);
|
|
101
|
+
result += CopyOptionsToString(info->format, info->options);
|
|
102
|
+
} else {
|
|
103
|
+
if (select_statement) {
|
|
104
|
+
// COPY (select-node) TO ...
|
|
105
|
+
result += "(" + select_statement->ToString() + ")";
|
|
106
|
+
} else {
|
|
107
|
+
result += TablePart(*info);
|
|
108
|
+
}
|
|
109
|
+
result += " TO";
|
|
110
|
+
result += StringUtil::Format("'%s'", info->file_path);
|
|
111
|
+
result += CopyOptionsToString(info->format, info->options);
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
|
|
14
116
|
unique_ptr<SQLStatement> CopyStatement::Copy() const {
|
|
15
117
|
return unique_ptr<CopyStatement>(new CopyStatement(*this));
|
|
16
118
|
}
|
|
@@ -85,6 +85,15 @@ void ReorderTableEntries(vector<TableCatalogEntry *> &tables) {
|
|
|
85
85
|
tables = ordered;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
string CreateFileName(const string &id_suffix, TableCatalogEntry *table, const string &extension) {
|
|
89
|
+
auto name = SanitizeExportIdentifier(table->name);
|
|
90
|
+
if (table->schema->name == DEFAULT_SCHEMA) {
|
|
91
|
+
return StringUtil::Format("%s%s.%s", name, id_suffix, extension);
|
|
92
|
+
}
|
|
93
|
+
auto schema = SanitizeExportIdentifier(table->schema->name);
|
|
94
|
+
return StringUtil::Format("%s_%s%s.%s", schema, name, id_suffix, extension);
|
|
95
|
+
}
|
|
96
|
+
|
|
88
97
|
BoundStatement Binder::Bind(ExportStatement &stmt) {
|
|
89
98
|
// COPY TO a file
|
|
90
99
|
auto &config = DBConfig::GetConfig(context);
|
|
@@ -135,20 +144,13 @@ BoundStatement Binder::Bind(ExportStatement &stmt) {
|
|
|
135
144
|
idx_t id = 0;
|
|
136
145
|
while (true) {
|
|
137
146
|
string id_suffix = id == 0 ? string() : "_" + to_string(id);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
fs.JoinPath(stmt.info->file_path,
|
|
145
|
-
StringUtil::Format("%s_%s%s.%s", SanitizeExportIdentifier(table->schema->name),
|
|
146
|
-
SanitizeExportIdentifier(table->name), id_suffix,
|
|
147
|
-
copy_function->function.extension));
|
|
148
|
-
}
|
|
149
|
-
if (table_name_index.find(info->file_path) == table_name_index.end()) {
|
|
147
|
+
auto name = CreateFileName(id_suffix, table, copy_function->function.extension);
|
|
148
|
+
auto directory = stmt.info->file_path;
|
|
149
|
+
auto full_path = fs.JoinPath(directory, name);
|
|
150
|
+
info->file_path = full_path;
|
|
151
|
+
auto insert_result = table_name_index.insert(info->file_path);
|
|
152
|
+
if (insert_result.second == true) {
|
|
150
153
|
// this name was not yet taken: take it
|
|
151
|
-
table_name_index.insert(info->file_path);
|
|
152
154
|
break;
|
|
153
155
|
}
|
|
154
156
|
id++;
|
|
@@ -166,6 +168,7 @@ BoundStatement Binder::Bind(ExportStatement &stmt) {
|
|
|
166
168
|
exported_data.database_name = catalog;
|
|
167
169
|
exported_data.table_name = info->table;
|
|
168
170
|
exported_data.schema_name = info->schema;
|
|
171
|
+
|
|
169
172
|
exported_data.file_path = info->file_path;
|
|
170
173
|
|
|
171
174
|
ExportedTableInfo table_info;
|