duckdb 0.2.10-dev451.0 → 0.2.10-dev468.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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb.cpp +327 -90
  3. package/src/duckdb.hpp +227 -186
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
- "version": "0.2.10-dev451.0",
4
+ "version": "0.2.10-dev468.0",
5
5
  "description": "DuckDB node.js API",
6
6
  "gypfile": true,
7
7
  "dependencies": {
package/src/duckdb.cpp CHANGED
@@ -1760,7 +1760,7 @@ public:
1760
1760
  namespace duckdb {
1761
1761
 
1762
1762
  struct CreateMacroInfo : public CreateFunctionInfo {
1763
- CreateMacroInfo() : CreateFunctionInfo(CatalogType::MACRO_ENTRY) {
1763
+ CreateMacroInfo() : CreateFunctionInfo(CatalogType::MACRO_ENTRY, INVALID_SCHEMA) {
1764
1764
  }
1765
1765
 
1766
1766
  unique_ptr<MacroFunction> function;
@@ -2025,8 +2025,8 @@ namespace duckdb {
2025
2025
 
2026
2026
  struct CreateSequenceInfo : public CreateInfo {
2027
2027
  CreateSequenceInfo()
2028
- : CreateInfo(CatalogType::SEQUENCE_ENTRY), name(string()), usage_count(0), increment(1), min_value(1),
2029
- max_value(NumericLimits<int64_t>::Maximum()), start_value(1), cycle(false) {
2028
+ : CreateInfo(CatalogType::SEQUENCE_ENTRY, INVALID_SCHEMA), name(string()), usage_count(0), increment(1),
2029
+ min_value(1), max_value(NumericLimits<int64_t>::Maximum()), start_value(1), cycle(false) {
2030
2030
  }
2031
2031
 
2032
2032
  //! Sequence name to create
@@ -2049,6 +2049,7 @@ public:
2049
2049
  auto result = make_unique<CreateSequenceInfo>();
2050
2050
  CopyProperties(*result);
2051
2051
  result->name = name;
2052
+ result->schema = schema;
2052
2053
  result->usage_count = usage_count;
2053
2054
  result->increment = increment;
2054
2055
  result->min_value = min_value;
@@ -2290,6 +2291,44 @@ private:
2290
2291
  } // namespace duckdb
2291
2292
 
2292
2293
 
2294
+ //===----------------------------------------------------------------------===//
2295
+ // DuckDB
2296
+ //
2297
+ // duckdb/catalog/catalog_search_path.hpp
2298
+ //
2299
+ //
2300
+ //===----------------------------------------------------------------------===//
2301
+
2302
+
2303
+
2304
+ #include <functional>
2305
+
2306
+
2307
+
2308
+
2309
+
2310
+ namespace duckdb {
2311
+
2312
+ class ClientContext;
2313
+
2314
+ //! The schema search path, in order by which entries are searched if no schema entry is provided
2315
+ class CatalogSearchPath {
2316
+ public:
2317
+ explicit CatalogSearchPath(ClientContext &client_p);
2318
+ CatalogSearchPath(const CatalogSearchPath &other) = delete;
2319
+
2320
+ const vector<string> &Get();
2321
+ const string &GetDefault();
2322
+
2323
+ private:
2324
+ static vector<string> ParsePaths(const string &value);
2325
+ ClientContext &context;
2326
+ string last_value;
2327
+ vector<string> paths;
2328
+ };
2329
+
2330
+ } // namespace duckdb
2331
+
2293
2332
 
2294
2333
 
2295
2334
  //===----------------------------------------------------------------------===//
@@ -2678,7 +2717,7 @@ public:
2678
2717
  namespace duckdb {
2679
2718
 
2680
2719
  struct CreateViewInfo : public CreateInfo {
2681
- CreateViewInfo() : CreateInfo(CatalogType::VIEW_ENTRY) {
2720
+ CreateViewInfo() : CreateInfo(CatalogType::VIEW_ENTRY, INVALID_SCHEMA) {
2682
2721
  }
2683
2722
  CreateViewInfo(string schema, string view_name)
2684
2723
  : CreateInfo(CatalogType::VIEW_ENTRY, schema), view_name(view_name) {
@@ -4606,6 +4645,12 @@ public:
4606
4645
 
4607
4646
  namespace duckdb {
4608
4647
 
4648
+ string SimilarCatalogEntry::GetQualifiedName() const {
4649
+ D_ASSERT(Found());
4650
+
4651
+ return name + "." + schema->name;
4652
+ }
4653
+
4609
4654
  Catalog::Catalog(DatabaseInstance &db)
4610
4655
  : db(db), schemas(make_unique<CatalogSet>(*this, make_unique<DefaultSchemaGenerator>(*this))),
4611
4656
  dependency_manager(make_unique<DependencyManager>(*this)) {
@@ -4728,23 +4773,25 @@ void Catalog::DropEntry(ClientContext &context, DropInfo *info) {
4728
4773
  if (info->type == CatalogType::SCHEMA_ENTRY) {
4729
4774
  // DROP SCHEMA
4730
4775
  DropSchema(context, info);
4731
- } else {
4732
- if (info->schema.empty()) {
4733
- info->schema = DEFAULT_SCHEMA;
4734
- }
4735
- auto schema = GetSchema(context, info->schema);
4736
- schema->DropEntry(context, info);
4776
+ return;
4777
+ }
4778
+
4779
+ auto lookup = LookupEntry(context, info->type, info->schema, info->name, info->if_exists);
4780
+ if (!lookup.Found()) {
4781
+ return;
4737
4782
  }
4783
+
4784
+ lookup.schema->DropEntry(context, info);
4738
4785
  }
4739
4786
 
4740
- SchemaCatalogEntry *Catalog::GetSchema(ClientContext &context, const string &schema_name,
4787
+ SchemaCatalogEntry *Catalog::GetSchema(ClientContext &context, const string &schema_name, bool if_exists,
4741
4788
  QueryErrorContext error_context) {
4742
4789
  D_ASSERT(!schema_name.empty());
4743
4790
  if (schema_name == TEMP_SCHEMA) {
4744
4791
  return context.temporary_objects.get();
4745
4792
  }
4746
4793
  auto entry = schemas->GetEntry(context, schema_name);
4747
- if (!entry) {
4794
+ if (!entry && !if_exists) {
4748
4795
  throw CatalogException(error_context.FormatError("Schema with name %s does not exist!", schema_name));
4749
4796
  }
4750
4797
  return (SchemaCatalogEntry *)entry;
@@ -4755,29 +4802,99 @@ void Catalog::ScanSchemas(ClientContext &context, std::function<void(CatalogEntr
4755
4802
  schemas->Scan(context, [&](CatalogEntry *entry) { callback(entry); });
4756
4803
  }
4757
4804
 
4758
- CatalogEntry *Catalog::GetEntry(ClientContext &context, CatalogType type, string schema_name, const string &name,
4759
- bool if_exists, QueryErrorContext error_context) {
4760
- if (schema_name.empty()) {
4761
- // no schema provided: check the catalog search path in order
4762
- if (context.catalog_search_path.empty()) {
4763
- throw InternalException("Empty catalog search path");
4805
+ SimilarCatalogEntry Catalog::SimilarEntryInSchemas(ClientContext &context, const string &entry_name, CatalogType type,
4806
+ const vector<SchemaCatalogEntry *> &schemas) {
4807
+
4808
+ vector<CatalogSet *> sets;
4809
+ std::transform(schemas.begin(), schemas.end(), std::back_inserter(sets),
4810
+ [type](SchemaCatalogEntry *s) -> CatalogSet * { return &s->GetCatalogSet(type); });
4811
+ pair<string, idx_t> most_similar {"", (idx_t)-1};
4812
+ SchemaCatalogEntry *schema_of_most_similar = nullptr;
4813
+ for (auto schema : schemas) {
4814
+ auto entry = schema->GetCatalogSet(type).SimilarEntry(context, entry_name);
4815
+ if (!entry.first.empty() && (most_similar.first.empty() || most_similar.second > entry.second)) {
4816
+ most_similar = entry;
4817
+ schema_of_most_similar = schema;
4764
4818
  }
4765
- schema_name = DEFAULT_SCHEMA;
4766
- for (idx_t i = 0; i < context.catalog_search_path.size(); i++) {
4767
- auto entry = GetEntry(context, type, context.catalog_search_path[i], name, true);
4768
- if (entry) {
4769
- return entry;
4819
+ }
4820
+
4821
+ return {most_similar.first, most_similar.second, schema_of_most_similar};
4822
+ }
4823
+
4824
+ CatalogException Catalog::CreateMissingEntryException(ClientContext &context, const string &entry_name,
4825
+ CatalogType type, const vector<SchemaCatalogEntry *> &schemas,
4826
+ QueryErrorContext error_context) {
4827
+ auto entry = SimilarEntryInSchemas(context, entry_name, type, schemas);
4828
+
4829
+ vector<SchemaCatalogEntry *> unseen_schemas;
4830
+ this->schemas->Scan([&schemas, &unseen_schemas](CatalogEntry *entry) {
4831
+ auto schema_entry = (SchemaCatalogEntry *)entry;
4832
+ if (std::find(schemas.begin(), schemas.end(), schema_entry) == schemas.end()) {
4833
+ unseen_schemas.emplace_back(schema_entry);
4834
+ }
4835
+ });
4836
+ auto unseen_entry = SimilarEntryInSchemas(context, entry_name, type, unseen_schemas);
4837
+
4838
+ string did_you_mean;
4839
+ if (unseen_entry.Found() && unseen_entry.distance < entry.distance) {
4840
+ did_you_mean = "\nDid you mean \"" + unseen_entry.GetQualifiedName() + "\"?";
4841
+ } else if (entry.Found()) {
4842
+ did_you_mean = "\nDid you mean \"" + entry.name + "\"?";
4843
+ }
4844
+
4845
+ return CatalogException(error_context.FormatError("%s with name %s does not exist!%s", CatalogTypeToString(type),
4846
+ entry_name, did_you_mean));
4847
+ }
4848
+
4849
+ CatalogEntryLookup Catalog::LookupEntry(ClientContext &context, CatalogType type, const string &schema_name,
4850
+ const string &name, bool if_exists, QueryErrorContext error_context) {
4851
+ if (!schema_name.empty()) {
4852
+ auto schema = GetSchema(context, schema_name, if_exists, error_context);
4853
+ if (!schema) {
4854
+ D_ASSERT(if_exists);
4855
+ return {nullptr, nullptr};
4856
+ }
4857
+
4858
+ auto entry = schema->GetCatalogSet(type).GetEntry(context, name);
4859
+ if (!entry && !if_exists) {
4860
+ throw CreateMissingEntryException(context, name, type, {schema}, error_context);
4861
+ }
4862
+
4863
+ return {schema, entry};
4864
+ }
4865
+
4866
+ const auto &paths = context.catalog_search_path->Get();
4867
+ for (const auto &path : paths) {
4868
+ auto lookup = LookupEntry(context, type, path, name, true, error_context);
4869
+ if (lookup.Found()) {
4870
+ return lookup;
4871
+ }
4872
+ }
4873
+
4874
+ if (!if_exists) {
4875
+ vector<SchemaCatalogEntry *> schemas;
4876
+ for (const auto &path : paths) {
4877
+ auto schema = GetSchema(context, path, true);
4878
+ if (schema) {
4879
+ schemas.emplace_back(schema);
4770
4880
  }
4771
4881
  }
4882
+
4883
+ throw CreateMissingEntryException(context, name, type, schemas, error_context);
4772
4884
  }
4773
- auto schema = GetSchema(context, schema_name, error_context);
4774
- return schema->GetEntry(context, type, name, if_exists, error_context);
4885
+
4886
+ return {nullptr, nullptr};
4887
+ }
4888
+
4889
+ CatalogEntry *Catalog::GetEntry(ClientContext &context, CatalogType type, const string &schema_name, const string &name,
4890
+ bool if_exists, QueryErrorContext error_context) {
4891
+ return LookupEntry(context, type, schema_name, name, if_exists, error_context).entry;
4775
4892
  }
4776
4893
 
4777
4894
  template <>
4778
- TableCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name, bool if_exists,
4779
- QueryErrorContext error_context) {
4780
- auto entry = GetEntry(context, CatalogType::TABLE_ENTRY, move(schema_name), name, if_exists);
4895
+ TableCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
4896
+ bool if_exists, QueryErrorContext error_context) {
4897
+ auto entry = GetEntry(context, CatalogType::TABLE_ENTRY, schema_name, name, if_exists);
4781
4898
  if (!entry) {
4782
4899
  return nullptr;
4783
4900
  }
@@ -4788,38 +4905,37 @@ TableCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name,
4788
4905
  }
4789
4906
 
4790
4907
  template <>
4791
- SequenceCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name, bool if_exists,
4792
- QueryErrorContext error_context) {
4793
- return (SequenceCatalogEntry *)GetEntry(context, CatalogType::SEQUENCE_ENTRY, move(schema_name), name, if_exists,
4908
+ SequenceCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
4909
+ bool if_exists, QueryErrorContext error_context) {
4910
+ return (SequenceCatalogEntry *)GetEntry(context, CatalogType::SEQUENCE_ENTRY, schema_name, name, if_exists,
4794
4911
  error_context);
4795
4912
  }
4796
4913
 
4797
4914
  template <>
4798
- TableFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name,
4915
+ TableFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
4799
4916
  bool if_exists, QueryErrorContext error_context) {
4800
- return (TableFunctionCatalogEntry *)GetEntry(context, CatalogType::TABLE_FUNCTION_ENTRY, move(schema_name), name,
4917
+ return (TableFunctionCatalogEntry *)GetEntry(context, CatalogType::TABLE_FUNCTION_ENTRY, schema_name, name,
4801
4918
  if_exists, error_context);
4802
4919
  }
4803
4920
 
4804
4921
  template <>
4805
- CopyFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name,
4922
+ CopyFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
4806
4923
  bool if_exists, QueryErrorContext error_context) {
4807
- return (CopyFunctionCatalogEntry *)GetEntry(context, CatalogType::COPY_FUNCTION_ENTRY, move(schema_name), name,
4808
- if_exists, error_context);
4924
+ return (CopyFunctionCatalogEntry *)GetEntry(context, CatalogType::COPY_FUNCTION_ENTRY, schema_name, name, if_exists,
4925
+ error_context);
4809
4926
  }
4810
4927
 
4811
4928
  template <>
4812
- PragmaFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name,
4929
+ PragmaFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
4813
4930
  bool if_exists, QueryErrorContext error_context) {
4814
- return (PragmaFunctionCatalogEntry *)GetEntry(context, CatalogType::PRAGMA_FUNCTION_ENTRY, move(schema_name), name,
4931
+ return (PragmaFunctionCatalogEntry *)GetEntry(context, CatalogType::PRAGMA_FUNCTION_ENTRY, schema_name, name,
4815
4932
  if_exists, error_context);
4816
4933
  }
4817
4934
 
4818
4935
  template <>
4819
- AggregateFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name,
4936
+ AggregateFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
4820
4937
  bool if_exists, QueryErrorContext error_context) {
4821
- auto entry =
4822
- GetEntry(context, CatalogType::AGGREGATE_FUNCTION_ENTRY, move(schema_name), name, if_exists, error_context);
4938
+ auto entry = GetEntry(context, CatalogType::AGGREGATE_FUNCTION_ENTRY, schema_name, name, if_exists, error_context);
4823
4939
  if (entry->type != CatalogType::AGGREGATE_FUNCTION_ENTRY) {
4824
4940
  throw CatalogException(error_context.FormatError("%s is not an aggregate function", name));
4825
4941
  }
@@ -4827,29 +4943,17 @@ AggregateFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, string
4827
4943
  }
4828
4944
 
4829
4945
  template <>
4830
- CollateCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name, bool if_exists,
4831
- QueryErrorContext error_context) {
4832
- return (CollateCatalogEntry *)GetEntry(context, CatalogType::COLLATION_ENTRY, move(schema_name), name, if_exists,
4946
+ CollateCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
4947
+ bool if_exists, QueryErrorContext error_context) {
4948
+ return (CollateCatalogEntry *)GetEntry(context, CatalogType::COLLATION_ENTRY, schema_name, name, if_exists,
4833
4949
  error_context);
4834
4950
  }
4835
4951
 
4836
4952
  void Catalog::Alter(ClientContext &context, AlterInfo *info) {
4837
4953
  ModifyCatalog();
4838
- if (info->schema.empty()) {
4839
- auto catalog_type = info->GetCatalogType();
4840
- // invalid schema: search the catalog search path
4841
- info->schema = DEFAULT_SCHEMA;
4842
- for (idx_t i = 0; i < context.catalog_search_path.size(); i++) {
4843
- auto entry = GetEntry(context, catalog_type, context.catalog_search_path[i], info->name, true);
4844
- if (entry) {
4845
- // entry exists in this schema: alter there
4846
- info->schema = context.catalog_search_path[i];
4847
- break;
4848
- }
4849
- }
4850
- }
4851
- auto schema = GetSchema(context, info->schema);
4852
- return schema->Alter(context, info);
4954
+ auto lookup = LookupEntry(context, info->GetCatalogType(), info->schema, info->name);
4955
+ D_ASSERT(lookup.Found()); // It must have thrown otherwise.
4956
+ return lookup.schema->Alter(context, info);
4853
4957
  }
4854
4958
 
4855
4959
  idx_t Catalog::GetCatalogVersion() {
@@ -6622,26 +6726,6 @@ void SchemaCatalogEntry::Alter(ClientContext &context, AlterInfo *info) {
6622
6726
  }
6623
6727
  }
6624
6728
 
6625
- CatalogEntry *SchemaCatalogEntry::GetEntry(ClientContext &context, CatalogType type, const string &entry_name,
6626
- bool if_exists, QueryErrorContext error_context) {
6627
- auto &set = GetCatalogSet(type);
6628
-
6629
- auto entry = set.GetEntry(context, entry_name);
6630
- if (!entry) {
6631
- if (!if_exists) {
6632
- auto entry = set.SimilarEntry(context, entry_name);
6633
- string did_you_mean;
6634
- if (!entry.empty()) {
6635
- did_you_mean = "\nDid you mean \"" + entry + "\"?";
6636
- }
6637
- throw CatalogException(error_context.FormatError("%s with name %s does not exist!%s",
6638
- CatalogTypeToString(type), entry_name, did_you_mean));
6639
- }
6640
- return nullptr;
6641
- }
6642
- return entry;
6643
- }
6644
-
6645
6729
  void SchemaCatalogEntry::Scan(ClientContext &context, CatalogType type,
6646
6730
  const std::function<void(CatalogEntry *)> &callback) {
6647
6731
  auto &set = GetCatalogSet(type);
@@ -8518,6 +8602,51 @@ string CatalogEntry::ToSQL() {
8518
8602
 
8519
8603
 
8520
8604
 
8605
+
8606
+
8607
+
8608
+ namespace duckdb {
8609
+
8610
+ CatalogSearchPath::CatalogSearchPath(ClientContext &context_p) : context(context_p), paths(ParsePaths("")) {
8611
+ }
8612
+
8613
+ const vector<string> &CatalogSearchPath::Get() {
8614
+ Value value;
8615
+ context.TryGetCurrentSetting("search_path", value);
8616
+ if (value.str_value != last_value) {
8617
+ paths = ParsePaths(value.str_value);
8618
+ last_value = value.str_value;
8619
+ }
8620
+
8621
+ return paths;
8622
+ }
8623
+
8624
+ const string &CatalogSearchPath::GetDefault() {
8625
+ const auto &paths = Get();
8626
+ D_ASSERT(paths.size() >= 2);
8627
+ D_ASSERT(paths[0] == TEMP_SCHEMA);
8628
+ return paths[1];
8629
+ }
8630
+
8631
+ vector<string> CatalogSearchPath::ParsePaths(const string &value) {
8632
+ vector<string> paths;
8633
+ paths.emplace_back(TEMP_SCHEMA);
8634
+
8635
+ auto given_paths = StringUtil::SplitWithQuote(value);
8636
+ for (const auto &p : given_paths) {
8637
+ paths.emplace_back(StringUtil::Lower(p));
8638
+ }
8639
+
8640
+ paths.emplace_back(DEFAULT_SCHEMA);
8641
+ paths.emplace_back("pg_catalog");
8642
+ return paths;
8643
+ }
8644
+
8645
+ } // namespace duckdb
8646
+
8647
+
8648
+
8649
+
8521
8650
  //===----------------------------------------------------------------------===//
8522
8651
  // DuckDB
8523
8652
  //
@@ -8919,7 +9048,7 @@ CatalogEntry *CatalogSet::GetCommittedEntry(CatalogEntry *current) {
8919
9048
  return current;
8920
9049
  }
8921
9050
 
8922
- string CatalogSet::SimilarEntry(ClientContext &context, const string &name) {
9051
+ pair<string, idx_t> CatalogSet::SimilarEntry(ClientContext &context, const string &name) {
8923
9052
  lock_guard<mutex> lock(catalog_lock);
8924
9053
 
8925
9054
  string result;
@@ -8934,7 +9063,7 @@ string CatalogSet::SimilarEntry(ClientContext &context, const string &name) {
8934
9063
  }
8935
9064
  }
8936
9065
  }
8937
- return result;
9066
+ return {result, current_score};
8938
9067
  }
8939
9068
 
8940
9069
  CatalogEntry *CatalogSet::CreateEntryInternal(ClientContext &context, unique_ptr<CatalogEntry> entry) {
@@ -9272,8 +9401,10 @@ static DefaultMacro internal_macros[] = {
9272
9401
  {"pg_catalog", "pg_ts_template_is_visible", {"template_oid", nullptr}, "true"},
9273
9402
  {"pg_catalog", "pg_type_is_visible", {"type_oid", nullptr}, "true"},
9274
9403
 
9404
+ {DEFAULT_SCHEMA, "round_even", {"x", "n", nullptr}, "CASE ((abs(x) * power(10, n+1)) % 10) WHEN 5 THEN round(x/2, n) * 2 ELSE round(x, n) END"},
9405
+ {DEFAULT_SCHEMA, "roundbankers", {"x", "n", nullptr}, "round_even(x, n)"},
9275
9406
  {DEFAULT_SCHEMA, "nullif", {"a", "b", nullptr}, "CASE WHEN a=b THEN NULL ELSE a END"},
9276
- {nullptr, nullptr, {nullptr}, nullptr}};
9407
+ {nullptr, nullptr, {nullptr}, nullptr}};
9277
9408
 
9278
9409
  static unique_ptr<CreateFunctionInfo> GetDefaultFunction(const string &schema, const string &name) {
9279
9410
  for (idx_t index = 0; internal_macros[index].name != nullptr; index++) {
@@ -31142,6 +31273,7 @@ void SortedDataScanner::Scan(DataChunk &chunk) {
31142
31273
 
31143
31274
 
31144
31275
 
31276
+
31145
31277
  #include <algorithm>
31146
31278
  #include <cctype>
31147
31279
  #include <iomanip>
@@ -31207,6 +31339,65 @@ vector<string> StringUtil::Split(const string &str, char delimiter) {
31207
31339
  return (lines);
31208
31340
  }
31209
31341
 
31342
+ namespace string_util_internal {
31343
+
31344
+ inline void SkipSpaces(const string &str, idx_t &index) {
31345
+ while (index < str.size() && std::isspace(str[index])) {
31346
+ index++;
31347
+ }
31348
+ }
31349
+
31350
+ inline void ConsumeLetter(const string &str, idx_t &index, char expected) {
31351
+ if (index >= str.size() || str[index] != expected) {
31352
+ throw ParserException("Invalid quoted list: %s", str);
31353
+ }
31354
+
31355
+ index++;
31356
+ }
31357
+
31358
+ template <typename F>
31359
+ inline void TakeWhile(const string &str, idx_t &index, const F &cond, string &taker) {
31360
+ while (index < str.size() && cond(str[index])) {
31361
+ taker.push_back(str[index]);
31362
+ index++;
31363
+ }
31364
+ }
31365
+
31366
+ inline string TakePossiblyQuotedItem(const string &str, idx_t &index, char delimiter, char quote) {
31367
+ string entry;
31368
+
31369
+ if (str[index] == quote) {
31370
+ index++;
31371
+ TakeWhile(
31372
+ str, index, [quote](char c) { return c != quote; }, entry);
31373
+ ConsumeLetter(str, index, quote);
31374
+ } else {
31375
+ TakeWhile(
31376
+ str, index, [delimiter, quote](char c) { return c != delimiter && c != quote && !std::isspace(c); }, entry);
31377
+ }
31378
+
31379
+ return entry;
31380
+ }
31381
+
31382
+ } // namespace string_util_internal
31383
+
31384
+ vector<string> StringUtil::SplitWithQuote(const string &str, char delimiter, char quote) {
31385
+ vector<string> entries;
31386
+ idx_t i = 0;
31387
+
31388
+ string_util_internal::SkipSpaces(str, i);
31389
+ while (i < str.size()) {
31390
+ if (!entries.empty()) {
31391
+ string_util_internal::ConsumeLetter(str, i, delimiter);
31392
+ }
31393
+
31394
+ entries.emplace_back(string_util_internal::TakePossiblyQuotedItem(str, i, delimiter, quote));
31395
+ string_util_internal::SkipSpaces(str, i);
31396
+ }
31397
+
31398
+ return entries;
31399
+ }
31400
+
31210
31401
  string StringUtil::Join(const vector<string> &input, const string &separator) {
31211
31402
  return StringUtil::Join(input, input.size(), separator, [](const string &s) { return s; });
31212
31403
  }
@@ -55315,7 +55506,7 @@ namespace duckdb {
55315
55506
  //! PhysicalSet represents a SET operation (e.g. SET a = 42)
55316
55507
  class PhysicalSet : public PhysicalOperator {
55317
55508
  public:
55318
- PhysicalSet(std::string name_p, Value value_p, SetScope scope_p, idx_t estimated_cardinality)
55509
+ PhysicalSet(const std::string &name_p, Value value_p, SetScope scope_p, idx_t estimated_cardinality)
55319
55510
  : PhysicalOperator(PhysicalOperatorType::SET, {LogicalType::BOOLEAN}, estimated_cardinality), name(name_p),
55320
55511
  value(value_p), scope(scope_p) {
55321
55512
  }
@@ -55324,9 +55515,13 @@ public:
55324
55515
  void GetChunkInternal(ExecutionContext &context, DataChunk &chunk, PhysicalOperatorState *state) const override;
55325
55516
 
55326
55517
  public:
55327
- std::string name;
55328
- Value value;
55329
- SetScope scope;
55518
+ const std::string name;
55519
+ const Value value;
55520
+ const SetScope scope;
55521
+
55522
+ private:
55523
+ //! Returns the normalized key name.
55524
+ string ValidateInput(ExecutionContext &context) const;
55330
55525
  };
55331
55526
 
55332
55527
  } // namespace duckdb
@@ -55334,20 +55529,47 @@ public:
55334
55529
 
55335
55530
 
55336
55531
 
55532
+
55533
+
55337
55534
  namespace duckdb {
55338
55535
 
55339
55536
  void PhysicalSet::GetChunkInternal(ExecutionContext &context, DataChunk &chunk, PhysicalOperatorState *state) const {
55340
55537
  D_ASSERT(scope == SetScope::GLOBAL || scope == SetScope::SESSION);
55341
55538
 
55539
+ auto normalized_name = ValidateInput(context);
55342
55540
  if (scope == SetScope::GLOBAL) {
55343
- context.client.db->config.set_variables[name] = value;
55541
+ context.client.db->config.set_variables[normalized_name] = value;
55344
55542
  } else {
55345
- context.client.set_variables[name] = value;
55543
+ context.client.set_variables[normalized_name] = value;
55346
55544
  }
55347
55545
 
55348
55546
  state->finished = true;
55349
55547
  }
55350
55548
 
55549
+ string PhysicalSet::ValidateInput(ExecutionContext &context) const {
55550
+ CaseInsensitiveStringEquality case_insensitive_streq;
55551
+ if (case_insensitive_streq(name, "search_path") || case_insensitive_streq(name, "schema")) {
55552
+ auto paths = StringUtil::SplitWithQuote(value.str_value, ',');
55553
+
55554
+ // The PG doc says:
55555
+ // > SET SCHEMA 'value' is an alias for SET search_path TO value.
55556
+ // > Only one schema can be specified using this syntax.
55557
+ if (case_insensitive_streq(name, "schema") && paths.size() > 1) {
55558
+ throw CatalogException("SET schema can set only 1 schema. This has %d", paths.size());
55559
+ }
55560
+
55561
+ for (const auto &path : paths) {
55562
+ if (!context.client.db->GetCatalog().GetSchema(context.client, StringUtil::Lower(path), true)) {
55563
+ throw CatalogException("SET %s: No schema named %s found.", name, path);
55564
+ }
55565
+ }
55566
+
55567
+ return "search_path";
55568
+ }
55569
+
55570
+ return name;
55571
+ }
55572
+
55351
55573
  } // namespace duckdb
55352
55574
  //===----------------------------------------------------------------------===//
55353
55575
  // DuckDB
@@ -80241,6 +80463,7 @@ bool ConstantOrNull::IsConstantOrNull(BoundFunctionExpression &expr, const Value
80241
80463
 
80242
80464
 
80243
80465
 
80466
+
80244
80467
  namespace duckdb {
80245
80468
 
80246
80469
  struct CurrentSettingBindData : public FunctionData {
@@ -80261,6 +80484,16 @@ static void CurrentSettingFunction(DataChunk &args, ExpressionState &state, Vect
80261
80484
  result.Reference(info.value);
80262
80485
  }
80263
80486
 
80487
+ static string NormalizeSettingName(const string &name) {
80488
+ if (CaseInsensitiveStringEquality()(name, "schema")) {
80489
+ // The PG doc says:
80490
+ // > SET SCHEMA 'value' is an alias for SET search_path TO value.
80491
+ return "search_path";
80492
+ }
80493
+
80494
+ return name;
80495
+ }
80496
+
80264
80497
  unique_ptr<FunctionData> CurrentSettingBind(ClientContext &context, ScalarFunction &bound_function,
80265
80498
  vector<unique_ptr<Expression>> &arguments) {
80266
80499
 
@@ -80276,7 +80509,7 @@ unique_ptr<FunctionData> CurrentSettingBind(ClientContext &context, ScalarFuncti
80276
80509
  throw ParserException("Key name for struct_extract needs to be neither NULL nor empty");
80277
80510
  }
80278
80511
 
80279
- const auto &key = key_val.str_value;
80512
+ const auto &key = NormalizeSettingName(key_val.str_value);
80280
80513
  Value val;
80281
80514
  if (!context.TryGetCurrentSetting(key, val)) {
80282
80515
  throw InvalidInputException("Variable '%s' was not SET in this context", key);
@@ -97139,6 +97372,7 @@ private:
97139
97372
 
97140
97373
 
97141
97374
 
97375
+
97142
97376
  //===----------------------------------------------------------------------===//
97143
97377
  // DuckDB
97144
97378
  //
@@ -97581,6 +97815,7 @@ ClientContext::ClientContext(shared_ptr<DatabaseInstance> database)
97581
97815
  : profiler(make_unique<QueryProfiler>()), query_profiler_history(make_unique<QueryProfilerHistory>()),
97582
97816
  db(move(database)), transaction(db->GetTransactionManager(), *this), interrupted(false), executor(*this),
97583
97817
  temporary_objects(make_unique<SchemaCatalogEntry>(&db->GetCatalog(), TEMP_SCHEMA, true)),
97818
+ catalog_search_path(make_unique<CatalogSearchPath>(*this)),
97584
97819
  file_opener(make_unique<ClientContextFileOpener>(*this)), open_result(nullptr) {
97585
97820
  std::random_device rd;
97586
97821
  random_engine.seed(rd());
@@ -129739,6 +129974,7 @@ unique_ptr<QueryNode> Transformer::TransformSelectNode(duckdb_libpgquery::PGSele
129739
129974
 
129740
129975
 
129741
129976
 
129977
+
129742
129978
  namespace duckdb {
129743
129979
 
129744
129980
  namespace {
@@ -133930,6 +134166,7 @@ BoundStatement Binder::Bind(CopyStatement &stmt) {
133930
134166
 
133931
134167
 
133932
134168
 
134169
+
133933
134170
  //===----------------------------------------------------------------------===//
133934
134171
  // DuckDB
133935
134172
  //
@@ -134030,7 +134267,7 @@ namespace duckdb {
134030
134267
 
134031
134268
  SchemaCatalogEntry *Binder::BindSchema(CreateInfo &info) {
134032
134269
  if (info.schema.empty()) {
134033
- info.schema = info.temporary ? TEMP_SCHEMA : DEFAULT_SCHEMA;
134270
+ info.schema = info.temporary ? TEMP_SCHEMA : context.catalog_search_path->GetDefault();
134034
134271
  }
134035
134272
 
134036
134273
  if (!info.temporary) {
package/src/duckdb.hpp CHANGED
@@ -10,8 +10,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
10
10
 
11
11
  #pragma once
12
12
  #define DUCKDB_AMALGAMATION 1
13
- #define DUCKDB_SOURCE_ID "0edad5d3d"
14
- #define DUCKDB_VERSION "0.2.10-dev451"
13
+ #define DUCKDB_SOURCE_ID "20ddfa846"
14
+ #define DUCKDB_VERSION "0.2.10-dev468"
15
15
  //===----------------------------------------------------------------------===//
16
16
  // DuckDB
17
17
  //
@@ -1770,7 +1770,7 @@ class FileFlags {
1770
1770
  public:
1771
1771
  //! Open file with read access
1772
1772
  static constexpr uint8_t FILE_FLAGS_READ = 1 << 0;
1773
- //! Open file with read/write access
1773
+ //! Open file with write access
1774
1774
  static constexpr uint8_t FILE_FLAGS_WRITE = 1 << 1;
1775
1775
  //! Use direct IO when reading/writing to the file
1776
1776
  static constexpr uint8_t FILE_FLAGS_DIRECT_IO = 1 << 2;
@@ -7313,6 +7313,32 @@ class CatalogSet;
7313
7313
  class DatabaseInstance;
7314
7314
  class DependencyManager;
7315
7315
 
7316
+ //! Return value of Catalog::LookupEntry
7317
+ struct CatalogEntryLookup {
7318
+ SchemaCatalogEntry *schema;
7319
+ CatalogEntry *entry;
7320
+
7321
+ bool Found() const {
7322
+ return entry;
7323
+ }
7324
+ };
7325
+
7326
+ //! Return value of SimilarEntryInSchemas
7327
+ struct SimilarCatalogEntry {
7328
+ //! The entry name. Empty if absent
7329
+ string name;
7330
+ //! The distance to the given name.
7331
+ idx_t distance;
7332
+ //! The schema of the entry.
7333
+ SchemaCatalogEntry *schema;
7334
+
7335
+ bool Found() const {
7336
+ return !name.empty();
7337
+ }
7338
+
7339
+ string GetQualifiedName() const;
7340
+ };
7341
+
7316
7342
  //! The Catalog object represents the catalog of the database.
7317
7343
  class Catalog {
7318
7344
  public:
@@ -7384,17 +7410,17 @@ public:
7384
7410
  void DropEntry(ClientContext &context, DropInfo *info);
7385
7411
 
7386
7412
  //! Returns the schema object with the specified name, or throws an exception if it does not exist
7387
- SchemaCatalogEntry *GetSchema(ClientContext &context, const string &name = DEFAULT_SCHEMA,
7413
+ SchemaCatalogEntry *GetSchema(ClientContext &context, const string &name = DEFAULT_SCHEMA, bool if_exists = false,
7388
7414
  QueryErrorContext error_context = QueryErrorContext());
7389
7415
  //! Scans all the schemas in the system one-by-one, invoking the callback for each entry
7390
7416
  void ScanSchemas(ClientContext &context, std::function<void(CatalogEntry *)> callback);
7391
7417
  //! Gets the "schema.name" entry of the specified type, if if_exists=true returns nullptr if entry does not exist,
7392
7418
  //! otherwise an exception is thrown
7393
- CatalogEntry *GetEntry(ClientContext &context, CatalogType type, string schema, const string &name,
7419
+ CatalogEntry *GetEntry(ClientContext &context, CatalogType type, const string &schema, const string &name,
7394
7420
  bool if_exists = false, QueryErrorContext error_context = QueryErrorContext());
7395
7421
 
7396
7422
  template <class T>
7397
- T *GetEntry(ClientContext &context, string schema_name, const string &name, bool if_exists = false,
7423
+ T *GetEntry(ClientContext &context, const string &schema_name, const string &name, bool if_exists = false,
7398
7424
  QueryErrorContext error_context = QueryErrorContext());
7399
7425
 
7400
7426
  //! Alter an existing entry in the catalog.
@@ -7405,30 +7431,43 @@ private:
7405
7431
  atomic<idx_t> catalog_version;
7406
7432
 
7407
7433
  private:
7434
+ //! A variation of GetEntry that returns an associated schema as well.
7435
+ CatalogEntryLookup LookupEntry(ClientContext &context, CatalogType type, const string &schema, const string &name,
7436
+ bool if_exists = false, QueryErrorContext error_context = QueryErrorContext());
7437
+
7438
+ //! Return an exception with did-you-mean suggestion.
7439
+ CatalogException CreateMissingEntryException(ClientContext &context, const string &entry_name, CatalogType type,
7440
+ const vector<SchemaCatalogEntry *> &schemas,
7441
+ QueryErrorContext error_context);
7442
+
7443
+ //! Return the close entry name, the distance and the belonging schema.
7444
+ SimilarCatalogEntry SimilarEntryInSchemas(ClientContext &context, const string &entry_name, CatalogType type,
7445
+ const vector<SchemaCatalogEntry *> &schemas);
7446
+
7408
7447
  void DropSchema(ClientContext &context, DropInfo *info);
7409
7448
  };
7410
7449
 
7411
7450
  template <>
7412
- TableCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name, bool if_exists,
7413
- QueryErrorContext error_context);
7451
+ TableCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
7452
+ bool if_exists, QueryErrorContext error_context);
7414
7453
  template <>
7415
- SequenceCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name, bool if_exists,
7416
- QueryErrorContext error_context);
7454
+ SequenceCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
7455
+ bool if_exists, QueryErrorContext error_context);
7417
7456
  template <>
7418
- TableFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name,
7457
+ TableFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
7419
7458
  bool if_exists, QueryErrorContext error_context);
7420
7459
  template <>
7421
- CopyFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name,
7460
+ CopyFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
7422
7461
  bool if_exists, QueryErrorContext error_context);
7423
7462
  template <>
7424
- PragmaFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name,
7463
+ PragmaFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
7425
7464
  bool if_exists, QueryErrorContext error_context);
7426
7465
  template <>
7427
- AggregateFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name,
7466
+ AggregateFunctionCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
7428
7467
  bool if_exists, QueryErrorContext error_context);
7429
7468
  template <>
7430
- CollateCatalogEntry *Catalog::GetEntry(ClientContext &context, string schema_name, const string &name, bool if_exists,
7431
- QueryErrorContext error_context);
7469
+ CollateCatalogEntry *Catalog::GetEntry(ClientContext &context, const string &schema_name, const string &name,
7470
+ bool if_exists, QueryErrorContext error_context);
7432
7471
 
7433
7472
  } // namespace duckdb
7434
7473
 
@@ -9654,6 +9693,166 @@ private:
9654
9693
 
9655
9694
  } // namespace duckdb
9656
9695
 
9696
+ //===----------------------------------------------------------------------===//
9697
+ // DuckDB
9698
+ //
9699
+ // duckdb/common/case_insensitive_map.hpp
9700
+ //
9701
+ //
9702
+ //===----------------------------------------------------------------------===//
9703
+
9704
+
9705
+
9706
+
9707
+
9708
+
9709
+ //===----------------------------------------------------------------------===//
9710
+ // DuckDB
9711
+ //
9712
+ // duckdb/common/string_util.hpp
9713
+ //
9714
+ //
9715
+ //===----------------------------------------------------------------------===//
9716
+
9717
+
9718
+
9719
+
9720
+
9721
+
9722
+
9723
+ namespace duckdb {
9724
+ /**
9725
+ * String Utility Functions
9726
+ * Note that these are not the most efficient implementations (i.e., they copy
9727
+ * memory) and therefore they should only be used for debug messages and other
9728
+ * such things.
9729
+ */
9730
+ class StringUtil {
9731
+ public:
9732
+ static bool CharacterIsSpace(char c) {
9733
+ return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
9734
+ }
9735
+ static bool CharacterIsNewline(char c) {
9736
+ return c == '\n' || c == '\r';
9737
+ }
9738
+ static bool CharacterIsDigit(char c) {
9739
+ return c >= '0' && c <= '9';
9740
+ }
9741
+ static char CharacterToLower(char c) {
9742
+ if (c >= 'A' && c <= 'Z') {
9743
+ return c - ('A' - 'a');
9744
+ }
9745
+ return c;
9746
+ }
9747
+
9748
+ //! Returns true if the needle string exists in the haystack
9749
+ static bool Contains(const string &haystack, const string &needle);
9750
+
9751
+ //! Returns true if the target string starts with the given prefix
9752
+ static bool StartsWith(string str, string prefix);
9753
+
9754
+ //! Returns true if the target string <b>ends</b> with the given suffix.
9755
+ static bool EndsWith(const string &str, const string &suffix);
9756
+
9757
+ //! Repeat a string multiple times
9758
+ static string Repeat(const string &str, const idx_t n);
9759
+
9760
+ //! Split the input string based on newline char
9761
+ static vector<string> Split(const string &str, char delimiter);
9762
+
9763
+ //! Split the input string allong a quote. Note that any escaping is NOT supported.
9764
+ static vector<string> SplitWithQuote(const string &str, char delimiter = ',', char quote = '"');
9765
+
9766
+ //! Join multiple strings into one string. Components are concatenated by the given separator
9767
+ static string Join(const vector<string> &input, const string &separator);
9768
+
9769
+ //! Join multiple items of container with given size, transformed to string
9770
+ //! using function, into one string using the given separator
9771
+ template <typename C, typename S, typename Func>
9772
+ static string Join(const C &input, S count, const string &separator, Func f) {
9773
+ // The result
9774
+ std::string result;
9775
+
9776
+ // If the input isn't empty, append the first element. We do this so we
9777
+ // don't need to introduce an if into the loop.
9778
+ if (count > 0) {
9779
+ result += f(input[0]);
9780
+ }
9781
+
9782
+ // Append the remaining input components, after the first
9783
+ for (size_t i = 1; i < count; i++) {
9784
+ result += separator + f(input[i]);
9785
+ }
9786
+
9787
+ return result;
9788
+ }
9789
+
9790
+ //! Return a string that formats the give number of bytes
9791
+ static string BytesToHumanReadableString(idx_t bytes);
9792
+
9793
+ //! Convert a string to uppercase
9794
+ static string Upper(const string &str);
9795
+
9796
+ //! Convert a string to lowercase
9797
+ static string Lower(const string &str);
9798
+
9799
+ //! Format a string using printf semantics
9800
+ template <typename... Args>
9801
+ static string Format(const string fmt_str, Args... params) {
9802
+ return Exception::ConstructMessage(fmt_str, params...);
9803
+ }
9804
+
9805
+ //! Split the input string into a vector of strings based on the split string
9806
+ static vector<string> Split(const string &input, const string &split);
9807
+
9808
+ //! Remove the whitespace char in the left end of the string
9809
+ static void LTrim(string &str);
9810
+ //! Remove the whitespace char in the right end of the string
9811
+ static void RTrim(string &str);
9812
+ //! Remove the whitespace char in the left and right end of the string
9813
+ static void Trim(string &str);
9814
+
9815
+ static string Replace(string source, const string &from, const string &to);
9816
+
9817
+ //! Get the levenshtein distance from two strings
9818
+ static idx_t LevenshteinDistance(const string &s1, const string &s2);
9819
+
9820
+ //! Get the top-n strings (sorted by the given score distance) from a set of scores.
9821
+ //! At least one entry is returned (if there is one).
9822
+ //! Strings are only returned if they have a score less than the threshold.
9823
+ static vector<string> TopNStrings(vector<std::pair<string, idx_t>> scores, idx_t n = 5, idx_t threshold = 5);
9824
+ //! Computes the levenshtein distance of each string in strings, and compares it to target, then returns TopNStrings
9825
+ //! with the given params.
9826
+ static vector<string> TopNLevenshtein(const vector<string> &strings, const string &target, idx_t n = 5,
9827
+ idx_t threshold = 5);
9828
+ static string CandidatesMessage(const vector<string> &candidates, const string &candidate = "Candidate bindings");
9829
+ };
9830
+ } // namespace duckdb
9831
+
9832
+
9833
+ namespace duckdb {
9834
+
9835
+ struct CaseInsensitiveStringHashFunction {
9836
+ uint64_t operator()(const string &str) const {
9837
+ std::hash<string> hasher;
9838
+ return hasher(StringUtil::Lower(str));
9839
+ }
9840
+ };
9841
+
9842
+ struct CaseInsensitiveStringEquality {
9843
+ bool operator()(const string &a, const string &b) const {
9844
+ return StringUtil::Lower(a) == StringUtil::Lower(b);
9845
+ }
9846
+ };
9847
+
9848
+ template <typename T>
9849
+ using case_insensitive_map_t =
9850
+ unordered_map<string, T, CaseInsensitiveStringHashFunction, CaseInsensitiveStringEquality>;
9851
+
9852
+ using case_insensitive_set_t = unordered_set<string, CaseInsensitiveStringHashFunction, CaseInsensitiveStringEquality>;
9853
+
9854
+ } // namespace duckdb
9855
+
9657
9856
 
9658
9857
 
9659
9858
 
@@ -9846,7 +10045,7 @@ public:
9846
10045
  //! Whether or not object cache is used
9847
10046
  bool object_cache_enable = false;
9848
10047
  //! Database configuration variables as controlled by SET
9849
- unordered_map<std::string, Value> set_variables;
10048
+ case_insensitive_map_t<Value> set_variables;
9850
10049
  //! Force checkpoint when CHECKPOINT is called or on shutdown, even if no changes have been made
9851
10050
  bool force_checkpoint = false;
9852
10051
  //! Run a checkpoint on successful shutdown and delete the WAL, to leave only a single database file behind
@@ -11747,161 +11946,22 @@ public:
11747
11946
  } // namespace duckdb
11748
11947
 
11749
11948
 
11750
- //===----------------------------------------------------------------------===//
11751
- // DuckDB
11752
- //
11753
- // duckdb/common/case_insensitive_map.hpp
11754
- //
11755
- //
11756
- //===----------------------------------------------------------------------===//
11757
-
11758
-
11759
-
11760
-
11761
-
11762
11949
 
11763
11950
  //===----------------------------------------------------------------------===//
11764
11951
  // DuckDB
11765
11952
  //
11766
- // duckdb/common/string_util.hpp
11953
+ // duckdb/common/pair.hpp
11767
11954
  //
11768
11955
  //
11769
11956
  //===----------------------------------------------------------------------===//
11770
11957
 
11771
11958
 
11772
11959
 
11773
-
11774
-
11775
-
11776
-
11777
- namespace duckdb {
11778
- /**
11779
- * String Utility Functions
11780
- * Note that these are not the most efficient implementations (i.e., they copy
11781
- * memory) and therefore they should only be used for debug messages and other
11782
- * such things.
11783
- */
11784
- class StringUtil {
11785
- public:
11786
- static bool CharacterIsSpace(char c) {
11787
- return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
11788
- }
11789
- static bool CharacterIsNewline(char c) {
11790
- return c == '\n' || c == '\r';
11791
- }
11792
- static bool CharacterIsDigit(char c) {
11793
- return c >= '0' && c <= '9';
11794
- }
11795
- static char CharacterToLower(char c) {
11796
- if (c >= 'A' && c <= 'Z') {
11797
- return c - ('A' - 'a');
11798
- }
11799
- return c;
11800
- }
11801
-
11802
- //! Returns true if the needle string exists in the haystack
11803
- static bool Contains(const string &haystack, const string &needle);
11804
-
11805
- //! Returns true if the target string starts with the given prefix
11806
- static bool StartsWith(string str, string prefix);
11807
-
11808
- //! Returns true if the target string <b>ends</b> with the given suffix.
11809
- static bool EndsWith(const string &str, const string &suffix);
11810
-
11811
- //! Repeat a string multiple times
11812
- static string Repeat(const string &str, const idx_t n);
11813
-
11814
- //! Split the input string based on newline char
11815
- static vector<string> Split(const string &str, char delimiter);
11816
-
11817
- //! Join multiple strings into one string. Components are concatenated by the given separator
11818
- static string Join(const vector<string> &input, const string &separator);
11819
-
11820
- //! Join multiple items of container with given size, transformed to string
11821
- //! using function, into one string using the given separator
11822
- template <typename C, typename S, typename Func>
11823
- static string Join(const C &input, S count, const string &separator, Func f) {
11824
- // The result
11825
- std::string result;
11826
-
11827
- // If the input isn't empty, append the first element. We do this so we
11828
- // don't need to introduce an if into the loop.
11829
- if (count > 0) {
11830
- result += f(input[0]);
11831
- }
11832
-
11833
- // Append the remaining input components, after the first
11834
- for (size_t i = 1; i < count; i++) {
11835
- result += separator + f(input[i]);
11836
- }
11837
-
11838
- return result;
11839
- }
11840
-
11841
- //! Return a string that formats the give number of bytes
11842
- static string BytesToHumanReadableString(idx_t bytes);
11843
-
11844
- //! Convert a string to uppercase
11845
- static string Upper(const string &str);
11846
-
11847
- //! Convert a string to lowercase
11848
- static string Lower(const string &str);
11849
-
11850
- //! Format a string using printf semantics
11851
- template <typename... Args>
11852
- static string Format(const string fmt_str, Args... params) {
11853
- return Exception::ConstructMessage(fmt_str, params...);
11854
- }
11855
-
11856
- //! Split the input string into a vector of strings based on the split string
11857
- static vector<string> Split(const string &input, const string &split);
11858
-
11859
- //! Remove the whitespace char in the left end of the string
11860
- static void LTrim(string &str);
11861
- //! Remove the whitespace char in the right end of the string
11862
- static void RTrim(string &str);
11863
- //! Remove the whitespace char in the left and right end of the string
11864
- static void Trim(string &str);
11865
-
11866
- static string Replace(string source, const string &from, const string &to);
11867
-
11868
- //! Get the levenshtein distance from two strings
11869
- static idx_t LevenshteinDistance(const string &s1, const string &s2);
11870
-
11871
- //! Get the top-n strings (sorted by the given score distance) from a set of scores.
11872
- //! At least one entry is returned (if there is one).
11873
- //! Strings are only returned if they have a score less than the threshold.
11874
- static vector<string> TopNStrings(vector<std::pair<string, idx_t>> scores, idx_t n = 5, idx_t threshold = 5);
11875
- //! Computes the levenshtein distance of each string in strings, and compares it to target, then returns TopNStrings
11876
- //! with the given params.
11877
- static vector<string> TopNLevenshtein(const vector<string> &strings, const string &target, idx_t n = 5,
11878
- idx_t threshold = 5);
11879
- static string CandidatesMessage(const vector<string> &candidates, const string &candidate = "Candidate bindings");
11880
- };
11881
- } // namespace duckdb
11882
-
11960
+ #include <utility>
11883
11961
 
11884
11962
  namespace duckdb {
11885
-
11886
- struct CaseInsensitiveStringHashFunction {
11887
- uint64_t operator()(const string &str) const {
11888
- std::hash<string> hasher;
11889
- return hasher(StringUtil::Lower(str));
11890
- }
11891
- };
11892
-
11893
- struct CaseInsensitiveStringEquality {
11894
- bool operator()(const string &a, const string &b) const {
11895
- return StringUtil::Lower(a) == StringUtil::Lower(b);
11896
- }
11897
- };
11898
-
11899
- template <typename T>
11900
- using case_insensitive_map_t =
11901
- unordered_map<string, T, CaseInsensitiveStringHashFunction, CaseInsensitiveStringEquality>;
11902
-
11903
- using case_insensitive_set_t = unordered_set<string, CaseInsensitiveStringHashFunction, CaseInsensitiveStringEquality>;
11904
-
11963
+ using std::make_pair;
11964
+ using std::pair;
11905
11965
  } // namespace duckdb
11906
11966
 
11907
11967
 
@@ -11950,8 +12010,8 @@ public:
11950
12010
  CatalogEntry *GetEntry(ClientContext &context, const string &name);
11951
12011
 
11952
12012
  //! Gets the entry that is most similar to the given name (i.e. smallest levenshtein distance), or empty string if
11953
- //! none is found
11954
- string SimilarEntry(ClientContext &context, const string &name);
12013
+ //! none is found. The returned pair consists of the entry name and the distance (smaller means closer).
12014
+ pair<string, idx_t> SimilarEntry(ClientContext &context, const string &name);
11955
12015
 
11956
12016
  //! Rollback <entry> to be the currently valid entry for a certain catalog
11957
12017
  //! entry
@@ -12059,10 +12119,6 @@ private:
12059
12119
  CatalogSet collations;
12060
12120
 
12061
12121
  public:
12062
- //! Gets a catalog entry from the given catalog set matching the given name
12063
- CatalogEntry *GetEntry(ClientContext &context, CatalogType type, const string &name, bool if_exists,
12064
- QueryErrorContext error_context = QueryErrorContext());
12065
-
12066
12122
  //! Scan the specified catalog set, invoking the callback method for every entry
12067
12123
  void Scan(ClientContext &context, CatalogType type, const std::function<void(CatalogEntry *)> &callback);
12068
12124
  //! Scan the specified catalog set, invoking the callback method for every committed entry
@@ -12114,6 +12170,7 @@ private:
12114
12170
  } // namespace duckdb
12115
12171
 
12116
12172
 
12173
+
12117
12174
  //===----------------------------------------------------------------------===//
12118
12175
  // DuckDB
12119
12176
  //
@@ -12147,22 +12204,6 @@ enum class ExplainOutputType : uint8_t { ALL = 0, OPTIMIZED_ONLY = 1, PHYSICAL_O
12147
12204
 
12148
12205
  } // namespace duckdb
12149
12206
 
12150
- //===----------------------------------------------------------------------===//
12151
- // DuckDB
12152
- //
12153
- // duckdb/common/pair.hpp
12154
- //
12155
- //
12156
- //===----------------------------------------------------------------------===//
12157
-
12158
-
12159
-
12160
- #include <utility>
12161
-
12162
- namespace duckdb {
12163
- using std::make_pair;
12164
- using std::pair;
12165
- } // namespace duckdb
12166
12207
 
12167
12208
  //===----------------------------------------------------------------------===//
12168
12209
  // DuckDB
@@ -13083,6 +13124,7 @@ private:
13083
13124
  namespace duckdb {
13084
13125
  class Appender;
13085
13126
  class Catalog;
13127
+ class CatalogSearchPath;
13086
13128
  class ChunkCollection;
13087
13129
  class DatabaseInstance;
13088
13130
  class FileOpener;
@@ -13132,7 +13174,7 @@ public:
13132
13174
  unique_ptr<SchemaCatalogEntry> temporary_objects;
13133
13175
  unordered_map<string, shared_ptr<PreparedStatementData>> prepared_statements;
13134
13176
 
13135
- unordered_map<string, Value> set_variables;
13177
+ case_insensitive_map_t<Value> set_variables;
13136
13178
 
13137
13179
  // Whether or not aggressive query verification is enabled
13138
13180
  bool query_verification_enabled = false;
@@ -13154,8 +13196,7 @@ public:
13154
13196
  //! The random generator used by random(). Its seed value can be set by setseed().
13155
13197
  std::mt19937 random_engine;
13156
13198
 
13157
- //! The schema search path, in order by which entries are searched if no schema entry is provided
13158
- vector<string> catalog_search_path = {TEMP_SCHEMA, DEFAULT_SCHEMA, "pg_catalog"};
13199
+ const unique_ptr<CatalogSearchPath> catalog_search_path;
13159
13200
 
13160
13201
  unique_ptr<FileOpener> file_opener;
13161
13202
 
@@ -13381,7 +13422,7 @@ public:
13381
13422
  namespace duckdb {
13382
13423
 
13383
13424
  struct CreateFunctionInfo : public CreateInfo {
13384
- explicit CreateFunctionInfo(CatalogType type) : CreateInfo(type) {
13425
+ explicit CreateFunctionInfo(CatalogType type, string schema = DEFAULT_SCHEMA) : CreateInfo(type, schema) {
13385
13426
  D_ASSERT(type == CatalogType::SCALAR_FUNCTION_ENTRY || type == CatalogType::AGGREGATE_FUNCTION_ENTRY ||
13386
13427
  type == CatalogType::TABLE_FUNCTION_ENTRY || type == CatalogType::PRAGMA_FUNCTION_ENTRY ||
13387
13428
  type == CatalogType::MACRO_ENTRY);