1use uqa_core::{DecimalValue, TemporalValue, Value};
10
11use crate::error::{Result, SQLError};
12
13use super::{hex_encode, out_of_range};
14
15mod path;
16mod production;
17#[cfg(test)]
18pub(super) use production::json_delete_with_control;
19pub(super) use production::{
20 cast_json_value_with_control, evaluate, format_core_value_as_json_with_control,
21 format_value_as_json_with_control, json_concat_with_control, json_delete_values_with_control,
22 json_extract_operator_with_control, quote_with_control, utf8_lossy_with_control,
23};
24
25pub(super) use path::{jsonpath_candidate, jsonpath_match};
26
27pub(super) fn parse_json(s: &str) -> Result<serde_json::Value> {
28 serde_json::from_str::<serde_json::Value>(s)
29 .map_err(|_| super::json_strip::invalid_json_input(s))
30}
31
32pub(super) fn format_json(value: &serde_json::Value, jsonb: bool) -> String {
35 if !jsonb {
36 return serde_json::to_string(value).expect("serializing a JSON value cannot fail");
37 }
38 match value {
39 serde_json::Value::Null => "null".to_string(),
40 serde_json::Value::Bool(value) => value.to_string(),
41 serde_json::Value::Number(value) => {
42 let text = value.to_string();
43 DecimalValue::parse(&text).map_or(text, |value| value.to_sql_string())
44 }
45 serde_json::Value::String(value) => serde_json::Value::String(value.clone()).to_string(),
46 serde_json::Value::Array(values) => {
47 let values = values
48 .iter()
49 .map(|value| format_json(value, true))
50 .collect::<Vec<_>>();
51 format!("[{}]", values.join(", "))
52 }
53 serde_json::Value::Object(values) => {
54 let mut values = values.iter().collect::<Vec<_>>();
55 values.sort_by(|(left, _), (right, _)| {
56 left.len()
57 .cmp(&right.len())
58 .then_with(|| left.as_bytes().cmp(right.as_bytes()))
59 });
60 let values = values
61 .into_iter()
62 .map(|(key, value)| {
63 let key = serde_json::Value::String(key.clone()).to_string();
64 format!("{key}: {}", format_json(value, true))
65 })
66 .collect::<Vec<_>>();
67 format!("{{{}}}", values.join(", "))
68 }
69 }
70}
71
72#[cfg(test)]
73fn format_jsonb_pretty(value: &serde_json::Value) -> String {
74 let Value::Str(text) =
75 ordinary("jsonb_pretty", &[Value::Json(value.to_string())]).expect("valid parsed JSON")
76 else {
77 unreachable!("JSON pretty text")
78 };
79 text
80}
81
82pub(super) fn typed_json_value(value: &serde_json::Value, jsonb: bool) -> Result<Value> {
83 if jsonb {
84 validate_jsonb_numbers(value)?;
85 }
86 let text = format_json(value, jsonb);
87 if jsonb {
88 Ok(Value::JsonB(text))
89 } else {
90 Ok(Value::Json(text))
91 }
92}
93
94fn validate_jsonb_numbers(value: &serde_json::Value) -> Result<()> {
95 match value {
96 serde_json::Value::Number(value) => DecimalValue::parse(&value.to_string())
97 .map(|_| ())
98 .ok_or_else(|| out_of_range("numeric")),
99 serde_json::Value::Array(values) => values.iter().try_for_each(validate_jsonb_numbers),
100 serde_json::Value::Object(values) => values.values().try_for_each(validate_jsonb_numbers),
101 _ => Ok(()),
102 }
103}
104
105pub fn value_to_json_text(value: &Value) -> Result<String> {
108 Ok(match value {
109 Value::Null => "null".to_string(),
110 Value::Void => "\"\"".to_string(),
111 Value::Bool(value) => value.to_string(),
112 Value::Int(value) => value.to_string(),
113 Value::Float(value) => match serde_json::Number::from_f64(*value) {
114 Some(number) => number.to_string(),
115 None if value.is_nan() => "\"NaN\"".to_string(),
116 None if value.is_sign_positive() => "\"Infinity\"".to_string(),
117 None => "\"-Infinity\"".to_string(),
118 },
119 Value::Decimal(value) => value.to_sql_string(),
120 Value::Str(value) => serde_json::Value::String(value.clone()).to_string(),
121 Value::FixedChar(value) => {
122 serde_json::Value::String(value.trim_end_matches(' ').to_string()).to_string()
123 }
124 Value::Bytes(value) => {
125 serde_json::Value::String(format!("0x{}", hex_encode(value))).to_string()
126 }
127 Value::Temporal(value) => serde_json::Value::String(value.to_sql_string()).to_string(),
128 Value::Json(text) | Value::JsonB(text) => text.clone(),
129 Value::Enum(value) => return Err(super::catalog_output_required(value)),
130 Value::LegacyVector(vector) => legacy_vector_json(vector).to_string(),
131 Value::Array(array) => {
132 let values = array
133 .elements()
134 .iter()
135 .map(value_to_json_text)
136 .collect::<Result<Vec<_>>>()?;
137 format!("[{}]", values.join(","))
138 }
139 Value::List(values) => {
140 let values = values
141 .iter()
142 .map(value_to_json_text)
143 .collect::<Result<Vec<_>>>()?;
144 format!("[{}]", values.join(","))
145 }
146 Value::Row(values) => record_json_text(
147 values
148 .iter()
149 .enumerate()
150 .map(|(index, value)| (format!("f{}", index + 1), value)),
151 )?,
152 Value::Record(fields) => {
153 record_json_text(fields.iter().map(|(name, value)| (name.clone(), value)))?
154 }
155 Value::Map(values) => {
156 let values = values
157 .iter()
158 .map(|(key, value)| {
159 let key = serde_json::Value::String(key.clone()).to_string();
160 Ok(format!("{key}:{}", value_to_json_text(value)?))
161 })
162 .collect::<Result<Vec<_>>>()?;
163 format!("{{{}}}", values.join(","))
164 }
165 })
166}
167
168fn legacy_vector_json(vector: &uqa_core::LegacyVectorValue) -> serde_json::Value {
169 serde_json::Value::Array(
170 vector
171 .elements()
172 .iter()
173 .map(|value| {
174 let Value::Int(value) = value else {
175 unreachable!("validated legacy vector element");
176 };
177 match vector.kind() {
178 uqa_core::LegacyVectorKind::SmallInteger => (*value).into(),
179 uqa_core::LegacyVectorKind::Oid => value.to_string().into(),
180 }
181 })
182 .collect(),
183 )
184}
185
186fn record_json_text<'a>(fields: impl IntoIterator<Item = (String, &'a Value)>) -> Result<String> {
187 let fields = fields
188 .into_iter()
189 .map(|(name, value)| {
190 let name = serde_json::Value::String(name).to_string();
191 Ok(format!("{name}:{}", value_to_json_text(value)?))
192 })
193 .collect::<Result<Vec<_>>>()?;
194 Ok(format!("{{{}}}", fields.join(",")))
195}
196
197pub(super) fn json_build_array_value(args: &[Value], jsonb: bool) -> Result<Value> {
198 let text = format!(
199 "[{}]",
200 args.iter()
201 .map(value_to_json_text)
202 .collect::<Result<Vec<_>>>()?
203 .join(", ")
204 );
205 if jsonb {
206 typed_json_value(&parse_json(&text)?, true)
207 } else {
208 Ok(Value::Json(text))
209 }
210}
211
212pub fn validate_json_object_key_type(value: &Value) -> Result<()> {
214 if matches!(
215 value,
216 Value::Array(_)
217 | Value::LegacyVector(_)
218 | Value::List(_)
219 | Value::Row(_)
220 | Value::Record(_)
221 | Value::Map(_)
222 | Value::Json(_)
223 | Value::JsonB(_)
224 ) {
225 return Err(SQLError::Routine {
226 sqlstate: "22023".into(),
227 message: "key value must be scalar, not array, composite, or json".into(),
228 });
229 }
230 Ok(())
231}
232
233pub(super) fn json_build_object_value(args: &[Value], jsonb: bool) -> Result<Value> {
234 let function = if jsonb {
235 "jsonb_build_object()"
236 } else {
237 "json_build_object()"
238 };
239 if !args.len().is_multiple_of(2) {
240 return Err(SQLError::Diagnostic {
241 sqlstate: "22023".into(),
242 message: "argument list must have even number of elements".into(),
243 detail: None,
244 hint: Some(format!(
245 "The arguments of {function} must consist of alternating keys and values."
246 )),
247 });
248 }
249 let mut fields = Vec::with_capacity(args.len() / 2);
250 for (index, pair) in args.as_chunks::<2>().0.iter().enumerate() {
251 if matches!(pair[0], Value::Null) {
252 return Err(if jsonb {
253 SQLError::Routine {
254 sqlstate: "22023".into(),
255 message: format!("argument {}: key must not be null", index * 2 + 1),
256 }
257 } else {
258 SQLError::Routine {
259 sqlstate: "22004".into(),
260 message: "null value not allowed for object key".into(),
261 }
262 });
263 }
264 validate_json_object_key_type(&pair[0])?;
265 let key = serde_json::Value::String(super::value_to_string(&pair[0])?).to_string();
266 fields.push(format!("{key} : {}", value_to_json_text(&pair[1])?));
267 }
268 let text = format!("{{{}}}", fields.join(", "));
269 if jsonb {
270 typed_json_value(&parse_json(&text)?, true)
271 } else {
272 Ok(Value::Json(text))
273 }
274}
275
276#[cfg(test)]
277pub(super) fn value_to_json(v: &Value) -> serde_json::Value {
278 match v {
279 Value::Null => serde_json::Value::Null,
280 Value::Void => serde_json::Value::String(String::new()),
281 Value::Bool(b) => serde_json::Value::Bool(*b),
282 Value::Int(i) => serde_json::Value::Number((*i).into()),
283 Value::Float(f) => serde_json::Number::from_f64(*f).map_or_else(
284 || {
285 let label = if f.is_nan() {
286 "NaN"
287 } else if f.is_sign_positive() {
288 "Infinity"
289 } else {
290 "-Infinity"
291 };
292 serde_json::Value::String(label.to_string())
293 },
294 serde_json::Value::Number,
295 ),
296 Value::Decimal(d) => {
297 if d.is_nan() || d.is_infinite() {
298 serde_json::Value::String(d.to_sql_string())
299 } else {
300 d.to_sql_string()
301 .parse::<serde_json::Number>()
302 .map(serde_json::Value::Number)
303 .unwrap_or_else(|_| serde_json::Value::String(d.to_sql_string()))
304 }
305 }
306 Value::Str(s) => serde_json::Value::String(s.clone()),
307 Value::FixedChar(s) => serde_json::Value::String(s.trim_end_matches(' ').to_string()),
308 Value::Bytes(b) => serde_json::Value::String(format!("0x{}", hex_encode(b))),
309 Value::Temporal(t) => serde_json::Value::String(t.to_sql_string()),
310 Value::Json(text) | Value::JsonB(text) => {
311 serde_json::from_str(text).unwrap_or_else(|_| serde_json::Value::String(text.clone()))
312 }
313 Value::LegacyVector(vector) => legacy_vector_json(vector),
314 Value::Array(array) => {
315 serde_json::Value::Array(array.elements().iter().map(value_to_json).collect())
316 }
317 Value::List(items) => serde_json::Value::Array(items.iter().map(value_to_json).collect()),
318 Value::Row(values) => serde_json::Value::Object(
319 values
320 .iter()
321 .enumerate()
322 .map(|(index, value)| (format!("f{}", index + 1), value_to_json(value)))
323 .collect(),
324 ),
325 Value::Record(fields) => serde_json::Value::Object(
326 fields
327 .iter()
328 .map(|(name, value)| (name.clone(), value_to_json(value)))
329 .collect(),
330 ),
331 Value::Map(map) => {
332 let mut obj = serde_json::Map::new();
333 for (k, v) in map {
334 obj.insert(k.clone(), value_to_json(v));
335 }
336 serde_json::Value::Object(obj)
337 }
338 Value::Enum(value) => panic!(
339 "test JSON has no enum label for type OID {}",
340 value.type_oid()
341 ),
342 }
343}
344
345#[allow(dead_code)]
346pub(super) fn json_to_value(json: &serde_json::Value) -> Value {
347 match json {
348 serde_json::Value::Null => Value::Null,
349 serde_json::Value::Bool(b) => Value::Bool(*b),
350 serde_json::Value::Number(n) => {
351 if let Some(i) = n.as_i64() {
352 Value::Int(i)
353 } else if let Some(d) = DecimalValue::parse(&n.to_string()) {
354 Value::Decimal(d)
355 } else if let Some(f) = n.as_f64() {
356 Value::Float(f)
357 } else {
358 Value::Null
359 }
360 }
361 serde_json::Value::String(s) => Value::Str(s.clone()),
362 serde_json::Value::Array(arr) => Value::List(arr.iter().map(json_to_value).collect()),
363 serde_json::Value::Object(obj) => {
364 if let Ok(temporal) =
365 serde_json::from_value::<TemporalValue>(serde_json::Value::Object(obj.clone()))
366 {
367 return Value::Temporal(temporal);
368 }
369 let mut map = std::collections::BTreeMap::new();
370 for (k, v) in obj {
371 map.insert(k.clone(), json_to_value(v));
372 }
373 Value::Map(map)
374 }
375 }
376}
377
378fn ordinary(name: &str, args: &[Value]) -> Result<Value> {
379 Ok(production::evaluate(
380 name,
381 args,
382 &uqa_core::memory::ProductionControl::uncontrolled(),
383 )
384 .expect("known JSON builtin")?
385 .into_uncontrolled()
386 .expect("ordinary JSON has no lease"))
387}
388
389fn json_array_index(len: usize, key: &str) -> Option<usize> {
390 let index = key.parse::<i64>().ok()?;
391 let normalized = if index < 0 { len as i64 + index } else { index };
392 usize::try_from(normalized).ok().filter(|idx| *idx < len)
393}
394
395fn json_insert_index(len: usize, key: &str, insert_after: bool) -> Option<usize> {
396 let raw = key.parse::<i64>().ok()?;
397 let len_i64 = len as i64;
398 let index = if raw >= 0 {
399 if raw >= len_i64 {
400 len_i64
401 } else if insert_after {
402 raw + 1
403 } else {
404 raw
405 }
406 } else {
407 let normalized = len_i64 + raw;
408 if normalized < 0 {
409 0
410 } else if insert_after {
411 normalized + 1
412 } else {
413 normalized
414 }
415 };
416 usize::try_from(index.clamp(0, len_i64)).ok()
417}
418
419#[cfg(test)]
420mod pretty_tests {
421 use super::{format_jsonb_pretty, parse_json, typed_json_value, DecimalValue};
422
423 #[test]
424 fn jsonb_pretty_uses_postgresql_layout_and_key_order() {
425 let value = parse_json(r#"{"zz":1,"b":[],"aa":{"long":3,"x":2}}"#).unwrap();
426 assert_eq!(
427 format_jsonb_pretty(&value),
428 "{\n \"b\": [\n ],\n \"aa\": {\n \"x\": 2,\n \"long\": 3\n },\n \"zz\": 1\n}"
429 );
430 assert_eq!(format_jsonb_pretty(&parse_json("[]").unwrap()), "[\n]");
431 assert_eq!(format_jsonb_pretty(&parse_json("{}").unwrap()), "{\n}");
432 assert_eq!(
433 format_jsonb_pretty(&parse_json("1e-1000").unwrap()),
434 DecimalValue::parse("1e-1000").unwrap().to_sql_string()
435 );
436 assert_eq!(format_jsonb_pretty(&parse_json("1.00").unwrap()), "1.00");
437 assert_eq!(format_jsonb_pretty(&parse_json("-0").unwrap()), "0");
438 }
439
440 #[test]
441 fn jsonb_rejects_numbers_outside_postgresql_numeric_range() {
442 let maximum = parse_json("1e131071").unwrap();
443 assert!(typed_json_value(&maximum, true).is_ok());
444
445 for text in ["1e131072", "1e-16384", "[1e131072]", r#"{"n":1e131072}"#] {
446 let error = typed_json_value(&parse_json(text).unwrap(), true).unwrap_err();
447 assert_eq!(error.sqlstate(), Some("22003"));
448 }
449
450 assert!(typed_json_value(&parse_json("1e200000").unwrap(), false).is_ok());
451 assert!(typed_json_value(&parse_json("0e200000").unwrap(), true).is_ok());
452 }
453}