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