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 CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
4
  "types": "./lib/duckdb.d.ts",
5
- "version": "0.6.2-dev1736.0",
5
+ "version": "0.6.2-dev1746.0",
6
6
  "description": "DuckDB node.js API",
7
7
  "gypfile": true,
8
8
  "dependencies": {
@@ -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::ExtractBaseName(const string &path) {
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
- auto vec = StringUtil::Split(splits.back(), ".");
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 query;
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
- query += string(buffer.get(), fsize);
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 query;
107
+ return final_query;
90
108
  }
91
109
 
92
110
  string PragmaDatabaseSize(ClientContext &context, const FunctionParameters &parameters) {
@@ -1,8 +1,8 @@
1
1
  #ifndef DUCKDB_VERSION
2
- #define DUCKDB_VERSION "0.6.2-dev1736"
2
+ #define DUCKDB_VERSION "0.6.2-dev1746"
3
3
  #endif
4
4
  #ifndef DUCKDB_SOURCE_ID
5
- #define DUCKDB_SOURCE_ID "424848838c"
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
- if (table->schema->name == DEFAULT_SCHEMA) {
139
- info->file_path = fs.JoinPath(stmt.info->file_path,
140
- StringUtil::Format("%s%s.%s", SanitizeExportIdentifier(table->name),
141
- id_suffix, copy_function->function.extension));
142
- } else {
143
- info->file_path =
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;