* This file is part of the oGRAC project.
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
*
* oGRAC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* ogsql_jsonb.c
*
*
* IDENTIFICATION
* src/ogsql/json/ogsql_jsonb.c
*
* -------------------------------------------------------------------------
*/
#include "ogsql_jsonb.h"
#include "ogsql_json_utils.h"
#include "ogsql_jsonb_utils.h"
#include "ogsql_func.h"
#ifdef __cplusplus
extern "C" {
#endif
#define JSONB_VERIFY_RETURNING_VARCHAR2(func, json_func_attr) \
do { \
(func)->datatype = OG_TYPE_STRING; \
(func)->size = (json_func_attr).return_size; \
(func)->typmod.is_char = OG_TRUE; \
} while (0)
#define JSONB_VERIFY_RETURNING_CLOB(func) \
do { \
(func)->datatype = OG_TYPE_CLOB; \
(func)->size = OG_MAX_EXEC_LOB_SIZE; \
(func)->typmod.is_char = OG_FALSE; \
} while (0)
#define JSONB_VERIFY_RETURNING_BLOB(func) \
do { \
(func)->datatype = OG_TYPE_BLOB; \
(func)->size = OG_MAX_EXEC_LOB_SIZE; \
(func)->typmod.is_char = OG_FALSE; \
} while (0)
#define JSONB_VERIFY_RETURNING_CLAUSE(func, json_func_attr) \
do { \
if (!JSON_FUNC_ATT_HAS_RETURNING((json_func_attr).ids) || \
(JSON_FUNC_ATT_GET_RETURNING((json_func_attr).ids) == JSON_FUNC_ATT_RETURNING_VARCHAR2)) { \
JSONB_VERIFY_RETURNING_VARCHAR2(func, json_func_attr); \
} else if (JSON_FUNC_ATT_GET_RETURNING((json_func_attr).ids) == JSON_FUNC_ATT_RETURNING_CLOB) { \
JSONB_VERIFY_RETURNING_CLOB(func); \
} else if (JSON_FUNC_ATT_GET_RETURNING((json_func_attr).ids) == JSON_FUNC_ATT_RETURNING_JSONB) { \
JSONB_VERIFY_RETURNING_BLOB(func); \
} \
} while (0)
static void set_default_for_jsonb_func_attr(expr_node_t *func, json_func_attr_t json_func_attr, bool32 is_error,
bool32 is_array_null, bool32 is_object_null)
{
if (!JSON_FUNC_ATT_HAS_RETURNING(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_RETURNING_VARCHAR2;
func->json_func_attr.return_size = JSON_FUNC_LEN_DEFAULT;
}
if (is_error && !JSON_FUNC_ATT_HAS_ON_ERROR(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_NULL_ON_ERROR;
}
if (is_array_null && !JSON_FUNC_ATT_HAS_ON_NULL(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_ABSENT_ON_NULL;
}
if (is_object_null && !JSON_FUNC_ATT_HAS_ON_NULL(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_NULL_ON_NULL;
}
}
status_t sql_verify_jsonb_value(sql_verifier_t *verf, expr_node_t *func)
{
json_func_attr_t json_func_attr;
CM_POINTER2(verf, func);
if (sql_verify_func_node(verf, func, 2, 2, OG_INVALID_ID32) != OG_SUCCESS) {
return OG_ERROR;
}
json_func_attr = func->json_func_attr;
JSONB_VERIFY_RETURNING_CLAUSE(func, json_func_attr);
if ((json_func_attr.ids & ~(JSON_FUNC_ATT_RETURNING_MASK | JSON_FUNC_ATT_ON_ERROR_MASK |
JSON_FUNC_ATT_ON_EMPTY_MASK)) ||
(JSON_FUNC_ATT_HAS_RETURNING(json_func_attr.ids) &&
JSON_FUNC_ATT_GET_RETURNING(json_func_attr.ids) == JSON_FUNC_ATT_RETURNING_JSONB) ||
(JSON_FUNC_ATT_HAS_ON_ERROR(json_func_attr.ids) &&
JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) != JSON_FUNC_ATT_NULL_ON_ERROR &&
JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) != JSON_FUNC_ATT_ERROR_ON_ERROR) ||
(JSON_FUNC_ATT_HAS_ON_EMPTY(json_func_attr.ids) &&
JSON_FUNC_ATT_GET_ON_EMPTY(json_func_attr.ids) != JSON_FUNC_ATT_NULL_ON_EMPTY &&
JSON_FUNC_ATT_GET_ON_EMPTY(json_func_attr.ids) != JSON_FUNC_ATT_ERROR_ON_EMPTY)) {
OG_THROW_ERROR(ERR_JSON_INVLID_CLAUSE, "RETURNING/ON ERROR/ON EMPTY", "");
return OG_ERROR;
}
set_default_for_jsonb_func_attr(func, json_func_attr, OG_TRUE, OG_FALSE, OG_FALSE);
return OG_SUCCESS;
}
static status_t jsonb_retrive(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
json_assist_t json_ass;
CM_POINTER3(stmt, func, res);
JSON_ASSIST_INIT(&json_ass, stmt);
status_t ret = jsonb_retrieve_core(&json_ass, func, res);
JSON_ASSIST_DESTORY(&json_ass);
return ret;
}
status_t sql_func_jsonb_value(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
return jsonb_retrive(stmt, func, res);
}
status_t sql_verify_jsonb_query(sql_verifier_t *verf, expr_node_t *func)
{
json_func_attr_t json_func_attr;
CM_POINTER2(verf, func);
if (sql_verify_func_node(verf, func, 2, 2, OG_INVALID_ID32) != OG_SUCCESS) {
return OG_ERROR;
}
json_func_attr = func->json_func_attr;
JSONB_VERIFY_RETURNING_CLAUSE(func, json_func_attr);
if ((json_func_attr.ids &
~(JSON_FUNC_ATT_RETURNING_MASK | JSON_FUNC_ATT_ON_ERROR_MASK | JSON_FUNC_ATT_ON_EMPTY_MASK |
JSON_FUNC_ATT_WRAPPER_MASK)) ||
(JSON_FUNC_ATT_HAS_ON_ERROR(json_func_attr.ids) &&
(JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) == JSON_FUNC_ATT_TRUE_ON_ERROR ||
JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) == JSON_FUNC_ATT_FALSE_ON_ERROR))) {
OG_THROW_ERROR(ERR_JSON_INVLID_CLAUSE, "RETURNING/ON ERROR/ON EMPTY/WITH WRAPPER", "");
return OG_ERROR;
}
if (!JSON_FUNC_ATT_HAS_RETURNING(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_RETURNING_VARCHAR2;
func->json_func_attr.return_size = JSON_FUNC_LEN_DEFAULT;
}
if (!JSON_FUNC_ATT_HAS_ON_ERROR(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_NULL_ON_ERROR;
}
if (!JSON_FUNC_ATT_HAS_WRAPPER(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_WITHOUT_WRAPPER;
}
return OG_SUCCESS;
}
status_t sql_func_jsonb_query(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
return jsonb_retrive(stmt, func, res);
}
status_t sql_verify_jsonb_exists(sql_verifier_t *verf, expr_node_t *func)
{
json_func_attr_t json_func_attr;
CM_POINTER2(verf, func);
OG_RETURN_IFERR(sql_verify_func_node(verf, func, 1, 2, OG_INVALID_ID32));
json_func_attr = func->json_func_attr;
if (verf->incl_flags & SQL_INCL_JSON_TABLE) {
if (JSON_FUNC_ATT_HAS_RETURNING(json_func_attr.ids) &&
JSON_FUNC_ATT_GET_RETURNING(json_func_attr.ids) == JSON_FUNC_ATT_RETURNING_JSONB) {
OG_THROW_ERROR(ERR_JSON_INVLID_CLAUSE, "ON RETURNING", "");
return OG_ERROR;
}
JSONB_VERIFY_RETURNING_CLAUSE(func, json_func_attr);
json_func_attr.ids &= (~JSON_FUNC_ATT_RETURNING_MASK);
} else {
func->datatype = OG_TYPE_BOOLEAN;
func->size = sizeof(bool32);
}
if ((json_func_attr.ids & ~(JSON_FUNC_ATT_ON_ERROR_MASK)) || (JSON_FUNC_ATT_HAS_ON_ERROR(json_func_attr.ids) &&
(JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) != JSON_FUNC_ATT_TRUE_ON_ERROR) &&
(JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) != JSON_FUNC_ATT_FALSE_ON_ERROR) &&
(JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) != JSON_FUNC_ATT_ERROR_ON_ERROR))) {
OG_THROW_ERROR(ERR_JSON_INVLID_CLAUSE, "ON ERROR", "");
return OG_ERROR;
}
if (!JSON_FUNC_ATT_HAS_ON_ERROR(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_FALSE_ON_ERROR;
}
return OG_SUCCESS;
}
status_t sql_func_jsonb_exists(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
return jsonb_retrive(stmt, func, res);
}
status_t sql_verify_jsonb_mergepatch(sql_verifier_t *verf, expr_node_t *func)
{
json_func_attr_t json_func_attr;
CM_POINTER2(verf, func);
OG_RETURN_IFERR(sql_verify_func_node(verf, func, 2, 2, OG_INVALID_ID32));
json_func_attr = func->json_func_attr;
JSONB_VERIFY_RETURNING_CLAUSE(func, json_func_attr);
if ((json_func_attr.ids & ~(JSON_FUNC_ATT_RETURNING_MASK | JSON_FUNC_ATT_ON_ERROR_MASK)) ||
(JSON_FUNC_ATT_HAS_ON_ERROR(json_func_attr.ids) &&
JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) != JSON_FUNC_ATT_NULL_ON_ERROR &&
JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) != JSON_FUNC_ATT_ERROR_ON_ERROR)) {
OG_THROW_ERROR(ERR_JSON_INVLID_CLAUSE, "ON ERROR",
"JSON_MERGEPATCH ONLY SUPPORT \"NULL ON ERROR\" or \"ERROR ON ERROR\"");
return OG_ERROR;
}
set_default_for_jsonb_func_attr(func, json_func_attr, OG_TRUE, OG_FALSE, OG_FALSE);
return OG_SUCCESS;
}
status_t sql_func_jsonb_mergepatch(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
json_assist_t json_ass;
CM_POINTER3(stmt, func, res);
JSON_ASSIST_INIT(&json_ass, stmt);
status_t ret = jsonb_mergepatch_core(&json_ass, func, res);
JSON_ASSIST_DESTORY(&json_ass);
return ret;
}
status_t sql_verify_jsonb_set(sql_verifier_t *verf, expr_node_t *func)
{
json_func_attr_t json_func_attr;
CM_POINTER2(verf, func);
if (sql_verify_func_node(verf, func, 2, 4, OG_INVALID_ID32) != OG_SUCCESS) {
return OG_ERROR;
}
json_func_attr = func->json_func_attr;
JSONB_VERIFY_RETURNING_CLAUSE(func, json_func_attr);
if ((json_func_attr.ids & ~(JSON_FUNC_ATT_RETURNING_MASK | JSON_FUNC_ATT_ON_ERROR_MASK)) ||
(JSON_FUNC_ATT_HAS_ON_ERROR(json_func_attr.ids) &&
JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) != JSON_FUNC_ATT_NULL_ON_ERROR &&
JSON_FUNC_ATT_GET_ON_ERROR(json_func_attr.ids) != JSON_FUNC_ATT_ERROR_ON_ERROR)) {
OG_THROW_ERROR(ERR_JSON_INVLID_CLAUSE, "RETURNING/ON ERROR", "");
return OG_ERROR;
}
if (!JSON_FUNC_ATT_HAS_RETURNING(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_RETURNING_VARCHAR2;
func->json_func_attr.return_size = JSON_FUNC_LEN_DEFAULT;
}
if (!JSON_FUNC_ATT_HAS_ON_ERROR(json_func_attr.ids)) {
func->json_func_attr.ids |= JSON_FUNC_ATT_NULL_ON_ERROR;
}
return OG_SUCCESS;
}
status_t sql_func_jsonb_set(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
json_assist_t json_ass;
CM_POINTER3(stmt, func, res);
JSON_ASSIST_INIT(&json_ass, stmt);
status_t ret = jsonb_set(&json_ass, func, res);
JSON_ASSIST_DESTORY(&json_ass);
return ret;
}
status_t sql_verify_jsonb_array_length(sql_verifier_t *verf, expr_node_t *func)
{
CM_POINTER2(verf, func);
if (OG_SUCCESS != sql_verify_func_node(verf, func, 1, 1, OG_INVALID_ID32)) {
return OG_ERROR;
}
func->datatype = OG_TYPE_BIGINT;
func->size = OG_BIGINT_SIZE;
return OG_SUCCESS;
}
status_t sql_func_jsonb_array_length(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
json_assist_t json_ass;
CM_POINTER3(stmt, func, res);
JSON_ASSIST_INIT(&json_ass, stmt);
status_t ret = jsonb_array_length_core(&json_ass, func, res);
JSON_ASSIST_DESTORY(&json_ass);
return ret;
}
static status_t jsonb_convert_core(json_assist_t *json_ass, variant_t *value)
{
json_value_t jv;
source_location_t loc = { 0 };
json_analyse_t analyse = { 0 };
OG_RETURN_IFERR(sql_exec_flatten_to_varchar(json_ass, value));
cm_trim_text(&value->v_text);
if (value->v_text.len == 0 || (value->v_text.str[0] != '{' && value->v_text.str[0] != '[')) {
OG_THROW_ERROR(ERR_JSON_SYNTAX_ERROR, "input data is not valid JSON");
return OG_ERROR;
}
OG_RETURN_IFERR(json_parse(json_ass, &value->v_text, &jv, loc));
OG_RETURN_IFERR(json_analyse(json_ass, &jv, &analyse));
json_ass->janalys = &analyse;
OG_RETURN_IFERR(get_jsonb_from_jsonvalue(json_ass, &jv, value, OG_TRUE));
return OG_SUCCESS;
}
status_t sql_convert_variant_to_jsonb(sql_stmt_t *stmt, variant_t *value)
{
json_assist_t json_ass;
CM_POINTER2(stmt, value);
JSON_ASSIST_INIT(&json_ass, stmt);
status_t ret = jsonb_convert_core(&json_ass, value);
JSON_ASSIST_DESTORY(&json_ass);
return ret;
}
status_t sql_valiate_jsonb_format(sql_stmt_t *stmt, variant_t *value)
{
json_assist_t json_ass;
CM_POINTER2(stmt, value);
variant_t va = *value;
JSON_ASSIST_INIT(&json_ass, stmt);
OG_RETURN_IFERR(sql_exec_flatten_to_binary(&json_ass, &va));
OG_RETURN_IFERR(jsonb_format_valiate_core(&json_ass, &va));
JSON_ASSIST_DESTORY(&json_ass);
return OG_SUCCESS;
}
#ifdef __cplusplus
}
#endif