From 0903b9b01972ef70cc7fc2daf6eb2a50626c023b Mon Sep 17 00:00:00 2001 From: Harin Date: Sun, 26 Jan 2025 23:35:47 +0530 Subject: [PATCH] Implemented JSON valid function --- COMPAT.md | 2 +- core/function.rs | 4 ++++ core/json/mod.rs | 14 ++++++++++++++ core/translate/expr.rs | 8 ++++++++ core/vdbe/mod.rs | 10 +++++++--- testing/json.test | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 66 insertions(+), 4 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 03798d24c..d7c8b0a2c 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -375,7 +375,7 @@ Modifiers: | jsonb_set(json,path,value,...) | | | | json_type(json) | Yes | | | json_type(json,path) | Yes | | -| json_valid(json) | | | +| json_valid(json) | Yes | | | json_valid(json,flags) | | | | json_quote(value) | | | | json_group_array(value) | | | diff --git a/core/function.rs b/core/function.rs index 6b9ca800e..1e5386696 100644 --- a/core/function.rs +++ b/core/function.rs @@ -79,6 +79,7 @@ pub enum JsonFunc { JsonObject, JsonType, JsonErrorPosition, + JsonValid, } #[cfg(feature = "json")] @@ -97,6 +98,7 @@ impl Display for JsonFunc { Self::JsonObject => "json_object".to_string(), Self::JsonType => "json_type".to_string(), Self::JsonErrorPosition => "json_error_position".to_string(), + Self::JsonValid => "json_valid".to_string(), } ) } @@ -519,6 +521,8 @@ impl Func { "json_type" => Ok(Func::Json(JsonFunc::JsonType)), #[cfg(feature = "json")] "json_error_position" => Ok(Self::Json(JsonFunc::JsonErrorPosition)), + #[cfg(feature = "json")] + "json_valid" => Ok(Self::Json(JsonFunc::JsonValid)), "unixepoch" => Ok(Self::Scalar(ScalarFunc::UnixEpoch)), "julianday" => Ok(Self::Scalar(ScalarFunc::JulianDay)), "hex" => Ok(Self::Scalar(ScalarFunc::Hex)), diff --git a/core/json/mod.rs b/core/json/mod.rs index fee87e3df..10e682148 100644 --- a/core/json/mod.rs +++ b/core/json/mod.rs @@ -984,3 +984,17 @@ mod tests { } } } +pub fn is_json_valid(json_value: &OwnedValue) -> crate::Result { + match json_value { + OwnedValue::Text(ref t) => match from_str::(&t.value) { + Ok(_) => Ok(OwnedValue::Integer(1)), + Err(_) => Ok(OwnedValue::Integer(0)), + }, + OwnedValue::Blob(b) => match jsonb::from_slice(b) { + Ok(_) => Ok(OwnedValue::Integer(1)), + Err(_) => Ok(OwnedValue::Integer(0)), + }, + OwnedValue::Null => Ok(OwnedValue::Null), + _ => Ok(OwnedValue::Integer(1)), + } +} diff --git a/core/translate/expr.rs b/core/translate/expr.rs index d1fea2ee2..9fdf5f9c2 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -929,6 +929,14 @@ pub fn translate_expr( func_ctx, ) } + JsonFunc::JsonValid => translate_function( + program, + args.as_deref().unwrap_or_default(), + referenced_tables, + resolver, + target_register, + func_ctx, + ), }, Func::Scalar(srf) => { match srf { diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index 4345aaa54..ec03f0c61 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -40,9 +40,9 @@ use crate::vdbe::builder::CursorType; use crate::vdbe::insn::Insn; #[cfg(feature = "json")] use crate::{ - function::JsonFunc, json::get_json, json::json_array, json::json_array_length, - json::json_arrow_extract, json::json_arrow_shift_extract, json::json_error_position, - json::json_extract, json::json_object, json::json_type, + function::JsonFunc, json::get_json, json::is_json_valid, json::json_array, + json::json_array_length, json::json_arrow_extract, json::json_arrow_shift_extract, + json::json_error_position, json::json_extract, json::json_object, json::json_type, }; use crate::{resolve_ext_path, Connection, Result, TransactionState, DATABASE_VERSION}; use datetime::{ @@ -1743,6 +1743,10 @@ impl Program { Err(e) => return Err(e), } } + JsonFunc::JsonValid => { + let json_value = &state.registers[*start_reg]; + state.registers[*dest] = is_json_valid(json_value)?; + } }, crate::function::Func::Scalar(scalar_func) => match scalar_func { ScalarFunc::Cast => { diff --git a/testing/json.test b/testing/json.test index ea1c9bf0f..5817a8c55 100755 --- a/testing/json.test +++ b/testing/json.test @@ -544,3 +544,35 @@ do_execsql_test json_from_json_object { #do_execsql_test json_object_duplicated_keys { # SELECT json_object('key', 'value', 'key', 'value2'); #} {{{"key":"value2"}}} +# + +do_execsql_test json_valid_1 { + SELECT json_valid('{"a":55,"b":72}'); +} {1} +do_execsql_test json_valid_2 { + SELECT json_valid('["a",55,"b",72]'); +} {1} +do_execsql_test json_valid_3 { + SELECT json_valid( CAST('{"a":1}' AS BLOB) ); +} {1} +do_execsql_test json_valid_4 { + SELECT json_valid(123); +} {1} +do_execsql_test json_valid_5 { + SELECT json_valid(12.3); +} {1} +do_execsql_test json_valid_6 { + SELECT json_valid('not a valid json'); +} {0} +do_execsql_test json_valid_7 { + SELECT json_valid('{"a":"55,"b":72}'); +} {0} +do_execsql_test json_valid_8 { + SELECT json_valid('{"a":55 "b":72}'); +} {0} +do_execsql_test json_valid_3 { + SELECT json_valid( CAST('{"a":"1}' AS BLOB) ); +} {0} +do_execsql_test json_valid_9 { + SELECT json_valid(NULL); +} {}