/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 | | } |