* 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.
* -------------------------------------------------------------------------
*
* func_group.c
*
*
* IDENTIFICATION
* src/ogsql/function/func_group.c
*
* -------------------------------------------------------------------------
*/
#include "func_group.h"
#include "dml_executor.h"
status_t sql_func_grouping(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
expr_tree_t *arg = func->argument;
sql_cursor_t *cur = OGSQL_CURR_CURSOR(stmt);
cur = sql_get_group_cursor(cur);
group_set_t *group_set = NULL;
expr_tree_t *group_expr = NULL;
group_data_t *group_data = NULL;
CM_POINTER3(stmt, func, res);
OG_RETURN_IFERR(sql_get_ancestor_cursor(cur, NODE_VM_ANCESTOR(arg->root), &cur));
group_data = cur->exec_data.group;
if (group_data == NULL) {
OG_SRC_THROW_ERROR(func->loc, ERR_GROUPING_NOT_ALLOWED);
return OG_ERROR;
}
group_set = (group_set_t *)cm_galist_get(group_data->group_p->sets, group_data->curr_group);
group_expr = (expr_tree_t *)cm_galist_get(group_set->items, NODE_VM_ID(arg->root));
if (SECUREC_UNLIKELY(group_expr == NULL)) {
OG_THROW_ERROR(ERR_ASSERT_ERROR, "group_expr is not null");
return OG_ERROR;
}
if (NODE_IS_RES_DUMMY(group_expr->root)) {
res->v_int = 1;
} else {
res->v_int = 0;
}
res->type = OG_TYPE_INTEGER;
res->is_null = OG_FALSE;
return OG_SUCCESS;
}
status_t sql_verify_grouping(sql_verifier_t *verf, expr_node_t *func)
{
CM_POINTER2(verf, func);
if (verf->excl_flags & SQL_EXCL_GROUPING) {
OG_SRC_THROW_ERROR(func->loc, ERR_GROUPING_NOT_ALLOWED);
return OG_ERROR;
}
if (verf->curr_query == NULL || verf->curr_query->group_sets->count == 0) {
OG_THROW_ERROR(ERR_GROUPING_NO_GROUPBY);
return OG_ERROR;
}
verf->incl_flags |= SQL_INCL_GROUPING;
OG_RETURN_IFERR(sql_verify_func_node(verf, func, 1, 1, OG_INVALID_ID32));
func->datatype = OG_TYPE_INTEGER;
func->size = OG_INTEGER_SIZE;
return OG_SUCCESS;
}
status_t sql_func_grouping_id(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
expr_tree_t *arg = func->argument;
sql_cursor_t *cur = OGSQL_CURR_CURSOR(stmt);
cur = sql_get_group_cursor(cur);
group_set_t *group_set = NULL;
expr_tree_t *group_expr = NULL;
group_data_t *group_data = NULL;
CM_POINTER3(stmt, func, res);
OG_RETURN_IFERR(sql_get_ancestor_cursor(cur, NODE_VM_ANCESTOR(arg->root), &cur));
group_data = cur->exec_data.group;
if (group_data == NULL) {
OG_SRC_THROW_ERROR(func->loc, ERR_GROUPING_NOT_ALLOWED);
return OG_ERROR;
}
group_set = (group_set_t *)cm_galist_get(group_data->group_p->sets, group_data->curr_group);
uint64 group_val = 0;
while (arg != NULL) {
group_val <<= 1;
group_expr = (expr_tree_t *)cm_galist_get(group_set->items, NODE_VM_ID(arg->root));
if (SECUREC_UNLIKELY(group_expr == NULL)) {
OG_THROW_ERROR(ERR_ASSERT_ERROR, "group_expr is not null");
return OG_ERROR;
}
if (NODE_IS_RES_DUMMY(group_expr->root)) {
group_val += 1;
}
arg = arg->next;
}
res->v_bigint = (int64)group_val;
res->type = OG_TYPE_BIGINT;
res->is_null = OG_FALSE;
return OG_SUCCESS;
}
status_t sql_verify_grouping_id(sql_verifier_t *verf, expr_node_t *func)
{
CM_POINTER2(verf, func);
if (verf->curr_query == NULL || verf->curr_query->group_sets->count == 0) {
OG_THROW_ERROR(ERR_GROUPING_NO_GROUPBY);
return OG_ERROR;
}
if (verf->excl_flags & SQL_EXCL_GROUPING) {
OG_SRC_THROW_ERROR(func->loc, ERR_GROUPING_NOT_ALLOWED);
return OG_ERROR;
}
verf->incl_flags |= SQL_INCL_GROUPING;
OG_RETURN_IFERR(sql_verify_func_node(verf, func, 1, OG_MAX_FUNC_ARGUMENTS - 1, OG_INVALID_ID32));
func->datatype = OG_TYPE_BIGINT;
func->size = OG_BIGINT_SIZE;
return OG_SUCCESS;
}
status_t sql_verify_group_concat(sql_verifier_t *verf, expr_node_t *func)
{
if (func->argument == NULL || func->argument->next == NULL) {
OG_SRC_THROW_ERROR(func->loc, ERR_INVALID_FUNC_PARAM_COUNT, T2S(&func->word.func.name), 1,
OG_MAX_FUNC_ARGUMENTS);
return OG_ERROR;
}
if (sql_is_single_const_or_param(func->argument->root) != OG_TRUE) {
OG_SRC_THROW_ERROR_EX(func->argument->loc, ERR_SQL_SYNTAX_ERROR,
"separator specified in %s must be a const or a binding paramter", T2S(&func->word.func.name));
return OG_ERROR;
}
OG_RETURN_IFERR(sql_verify_func_node(verf, func, 1, OG_MAX_FUNC_ARGUMENTS, OG_INVALID_ID32));
if (func->sort_items != NULL) {
OG_RETURN_IFERR(sql_verify_group_concat_order(verf, func, func->sort_items));
}
func->datatype = OG_TYPE_STRING;
func->size = OG_MAX_ROW_SIZE;
return OG_SUCCESS;
}
status_t sql_func_group_concat(sql_stmt_t *stmt, expr_node_t *func, variant_t *res)
{
uint32 row_len;
uint32 remain_len;
variant_t arg_var;
char *buf = NULL;
CM_POINTER3(stmt, func, res);
res->type = OG_TYPE_STRING;
OG_RETURN_IFERR(sql_push(stmt, OG_MAX_ROW_SIZE, (void **)&buf));
res->v_text.str = buf;
res->v_text.len = row_len = 0;
remain_len = OG_MAX_ROW_SIZE;
OGSQL_SAVE_STACK(stmt);
expr_tree_t *arg = func->argument->next;
while (arg != NULL) {
SQL_EXEC_FUNC_ARG_EX(arg, &arg_var, res);
if (!OG_IS_STRING_TYPE(arg_var.type)) {
if (sql_var_as_string(stmt, &arg_var) != OG_SUCCESS) {
OGSQL_RESTORE_STACK(stmt);
return OG_ERROR;
}
}
if ((row_len + arg_var.v_text.len) > OG_MAX_ROW_SIZE) {
OGSQL_RESTORE_STACK(stmt);
OG_THROW_ERROR(ERR_EXCEED_MAX_ROW_SIZE, (row_len + arg_var.v_text.len), OG_MAX_ROW_SIZE);
return OG_ERROR;
}
if (arg_var.v_text.len > 0) {
errno_t errcode =
memcpy_s(res->v_text.str + row_len, remain_len, arg_var.v_text.str, arg_var.v_text.len);
if (errcode != EOK) {
OGSQL_RESTORE_STACK(stmt);
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
row_len += arg_var.v_text.len;
remain_len -= arg_var.v_text.len;
}
arg = arg->next;
OGSQL_RESTORE_STACK(stmt);
}
res->is_null = OG_FALSE;
res->v_text.len = row_len;
return OG_SUCCESS;
}