Coverage Report

Created: 2026-11-11 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/duckdb/extension/json/json_extension.cpp
Line
Count
Source
1
#include "json_extension.hpp"
2
3
#include "json_common.hpp"
4
#include "json_functions.hpp"
5
6
#include "duckdb/catalog/catalog_entry/macro_catalog_entry.hpp"
7
#include "duckdb/catalog/default/default_functions.hpp"
8
#include "duckdb/function/copy_function.hpp"
9
#include "duckdb/main/database.hpp"
10
#include "duckdb/main/extension/extension_loader.hpp"
11
#include "duckdb/parser/expression/function_expression.hpp"
12
13
namespace duckdb {
14
15
static const DefaultMacro JSON_MACROS[] = {
16
    {DEFAULT_SCHEMA, "json_group_array",
17
     "(x) AS CAST('[' || string_agg(CASE WHEN x IS NULL THEN 'null'::JSON ELSE to_json(x) END, ',') || ']' AS JSON)"},
18
    {DEFAULT_SCHEMA, "json_group_object",
19
     "(n, v) AS CAST('{' || string_agg(CASE WHEN n IS NULL THEN error('json_group_object key cannot be NULL') ELSE "
20
     "to_json(n::VARCHAR) END || ':' || CASE WHEN v IS NULL THEN 'null'::JSON ELSE to_json(v) END, ',') || '}' AS "
21
     "JSON)"},
22
    {DEFAULT_SCHEMA, "json_group_structure", "(x) AS json_structure(json_group_array(x))->0"},
23
    {DEFAULT_SCHEMA, "json", "(x) AS json_extract(x, '$')"},
24
    {DEFAULT_SCHEMA, "json_copy_strftime_if_date", "(x, format) AS x, (x DATE, format) AS strftime(x, format);"},
25
    {DEFAULT_SCHEMA, "json_copy_strftime_if_timestamp",
26
     "(x, format) AS x, (x TIMESTAMP, format) AS strftime(x, format), "
27
     "(x TIMESTAMP_NS, format) AS strftime(x, format), "
28
     "(x TIMESTAMPTZ, format) AS strftime(x, format), "
29
     "(x TIMESTAMPTZ_NS, format) AS strftime(x, format);"},
30
    {nullptr, nullptr, nullptr}};
31
32
14.8k
static void LoadInternal(ExtensionLoader &loader) {
33
  // JSON settings
34
14.8k
  auto &config = DBConfig::GetConfig(loader.GetDatabaseInstance());
35
14.8k
  config.AddExtensionOption(
36
14.8k
      "json_geometry_format",
37
14.8k
      "How GEOMETRY values are written to JSON: 'wkt' for Well-Known Text, or 'geojson' for GeoJSON geometry "
38
14.8k
      "objects. COPY ... TO ... (FORMAT GEOJSON) always writes GeoJSON regardless of this setting.",
39
14.8k
      LogicalType::VARCHAR, Value("wkt"), JSONFunctions::ValidateGeometryFormat);
40
41
  // JSON type
42
14.8k
  auto json_type = LogicalType::JSON();
43
14.8k
  loader.RegisterType(LogicalType::JSON_TYPE_NAME, std::move(json_type));
44
45
  // JSON casts
46
14.8k
  JSONFunctions::RegisterSimpleCastFunctions(loader);
47
14.8k
  JSONFunctions::RegisterJSONCreateCastFunctions(loader);
48
14.8k
  JSONFunctions::RegisterJSONTransformCastFunctions(loader);
49
50
  // JSON scalar functions
51
595k
  for (auto &fun : JSONFunctions::GetScalarFunctions()) {
52
595k
    loader.RegisterFunction(fun);
53
595k
  }
54
55
  // JSON table functions
56
163k
  for (auto &fun : JSONFunctions::GetTableFunctions()) {
57
163k
    loader.RegisterFunction(fun);
58
163k
  }
59
60
  // JSON pragma functions
61
14.8k
  for (auto &fun : JSONFunctions::GetPragmaFunctions()) {
62
14.8k
    loader.RegisterFunction(fun);
63
14.8k
  }
64
65
  // JSON replacement scan
66
14.8k
  DBConfig::GetConfig(loader.GetDatabaseInstance())
67
14.8k
      .replacement_scans.emplace_back(JSONFunctions::ReadJSONReplacement);
68
69
  // JSON copy function
70
14.8k
  auto copy_fun = JSONFunctions::GetJSONCopyFunction();
71
14.8k
  loader.RegisterFunction(copy_fun);
72
14.8k
  copy_fun.extension = "ndjson";
73
14.8k
  copy_fun.SetName("ndjson");
74
14.8k
  loader.RegisterFunction(copy_fun);
75
14.8k
  copy_fun.extension = "jsonl";
76
14.8k
  copy_fun.SetName("jsonl");
77
14.8k
  loader.RegisterFunction(copy_fun);
78
79
  // GeoJSON copy function
80
14.8k
  auto geojson_copy_fun = JSONFunctions::GetGeoJSONCopyFunction();
81
14.8k
  loader.RegisterFunction(geojson_copy_fun);
82
14.8k
  geojson_copy_fun.extension = "geojsonl";
83
14.8k
  geojson_copy_fun.SetName("geojsonl");
84
14.8k
  loader.RegisterFunction(geojson_copy_fun);
85
86
104k
  for (idx_t index = 0; JSON_MACROS[index].name != nullptr; index++) {
87
89.2k
    auto info = DefaultFunctionGenerator::CreateInternalMacroInfo(JSON_MACROS[index]);
88
89.2k
    loader.RegisterFunction(*info);
89
89.2k
  }
90
14.8k
}
91
92
// LCOV_EXCL_START
93
14.8k
void JsonExtension::Load(ExtensionLoader &loader) {
94
14.8k
  LoadInternal(loader);
95
14.8k
}
96
97
1
std::string JsonExtension::Name() {
98
1
  return "json";
99
1
}
100
101
1
std::string JsonExtension::Version() const {
102
1
#ifdef EXT_VERSION_JSON
103
1
  return EXT_VERSION_JSON;
104
#else
105
  return "";
106
#endif
107
1
}
108
// LCOV_EXCL_STOP
109
110
} // namespace duckdb
111
112
extern "C" {
113
114
0
DUCKDB_CPP_EXTENSION_ENTRY(json, loader) {
115
0
  duckdb::LoadInternal(loader);
116
0
}
117
}