* 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_select_verifier.c
*
*
* IDENTIFICATION
* src/ogsql/verifier/ogsql_select_verifier.c
*
* -------------------------------------------------------------------------
*/
#include "ogsql_select_verifier.h"
#include "ogsql_table_verifier.h"
#include "ogsql_func.h"
#include "srv_instance.h"
#include "ogsql_select_parser.h"
#include "base_compiler.h"
#include "expr_parser.h"
#include "ogsql_limit.h"
#include "ogsql_hint_verifier.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline status_t sql_try_match_distinct_node(sql_stmt_t *stmt, sql_query_t *query, expr_node_t *node);
static void sql_try_delete_parent_ref(sql_query_t *query, expr_node_t *expr)
{
if (expr->type == EXPR_NODE_COLUMN && NODE_ANCESTOR(expr) > 0) {
query = sql_get_ancestor_query(query, NODE_ANCESTOR(expr) - 1);
if (query != NULL && query->owner != NULL) {
sql_del_parent_refs(query->owner->parent_refs, NODE_TAB(expr), expr);
}
}
}
static status_t sql_try_match_distinct_node_full(sql_stmt_t *stmt, sql_query_t *query, expr_node_t *node,
bool32 *result)
{
rs_column_t *rs_col = NULL;
*result = OG_FALSE;
expr_node_t *origin_ref = sql_get_origin_ref(node);
for (uint32 i = 0; i < query->rs_columns->count; i++) {
rs_col = (rs_column_t *)cm_galist_get(query->rs_columns, i);
if (rs_col->type == RS_COL_CALC) {
if (sql_expr_node_equal(stmt, origin_ref, rs_col->expr->root, NULL)) {
*result = OG_TRUE;
sql_try_delete_parent_ref(query, node);
return sql_set_group_expr_node(stmt, node, i, 0, 0, sql_get_origin_ref(rs_col->expr->root));
}
}
}
return OG_SUCCESS;
}
static inline status_t sql_match_distinct_cond_node(sql_stmt_t *stmt, sql_query_t *query, cond_node_t *cond)
{
if (sql_stack_safe(stmt) != OG_SUCCESS) {
return OG_ERROR;
}
if (cond == NULL) {
return OG_SUCCESS;
}
switch (cond->type) {
case COND_NODE_COMPARE:
OG_RETURN_IFERR(sql_match_distinct_expr(stmt, query, cond->cmp->left));
OG_RETURN_IFERR(sql_match_distinct_expr(stmt, query, cond->cmp->right));
break;
case COND_NODE_TRUE:
case COND_NODE_FALSE:
break;
default:
OG_RETURN_IFERR(sql_match_distinct_cond_node(stmt, query, cond->left));
OG_RETURN_IFERR(sql_match_distinct_cond_node(stmt, query, cond->right));
break;
}
return OG_SUCCESS;
}
static status_t sql_try_match_distinct_func(sql_stmt_t *stmt, sql_query_t *query, expr_node_t *node)
{
expr_tree_t *arg = NULL;
sql_func_t *func = sql_get_func(&node->value.v_func);
if ((func->builtin_func_id == ID_FUNC_ITEM_IF || func->builtin_func_id == ID_FUNC_ITEM_LNNVL) &&
node->cond_arg != NULL) {
OG_RETURN_IFERR(sql_match_distinct_cond_node(stmt, query, node->cond_arg->root));
}
arg = node->argument;
while (arg != NULL) {
OG_RETURN_IFERR(sql_try_match_distinct_node(stmt, query, arg->root));
arg = arg->next;
}
return OG_SUCCESS;
}
static inline status_t sql_try_match_distinct_node(sql_stmt_t *stmt, sql_query_t *query, expr_node_t *node)
{
if (sql_stack_safe(stmt) != OG_SUCCESS) {
return OG_ERROR;
}
bool32 result = OG_FALSE;
OG_RETURN_IFERR(sql_try_match_distinct_node_full(stmt, query, node, &result));
if (result) {
return OG_SUCCESS;
}
switch (node->type) {
case EXPR_NODE_ADD:
case EXPR_NODE_SUB:
case EXPR_NODE_MUL:
case EXPR_NODE_DIV:
case EXPR_NODE_BITAND:
case EXPR_NODE_BITOR:
case EXPR_NODE_BITXOR:
case EXPR_NODE_CAT:
case EXPR_NODE_MOD:
case EXPR_NODE_LSHIFT:
case EXPR_NODE_RSHIFT:
case EXPR_NODE_OPCEIL:
OG_RETURN_IFERR(sql_try_match_distinct_node(stmt, query, node->left));
return sql_try_match_distinct_node(stmt, query, node->right);
case EXPR_NODE_FUNC:
return sql_try_match_distinct_func(stmt, query, node);
case EXPR_NODE_NEGATIVE:
return sql_try_match_distinct_node(stmt, query, node->right);
case EXPR_NODE_CONST:
case EXPR_NODE_SELECT:
return OG_SUCCESS;
default:
return OG_ERROR;
}
}
status_t sql_match_distinct_expr(sql_stmt_t *statement, sql_query_t *sql_qry, expr_tree_t *exprtr)
{
for (; exprtr != NULL; exprtr = exprtr->next) {
if (sql_try_match_distinct_node(statement, sql_qry, exprtr->root) != OG_SUCCESS) {
OG_SRC_THROW_ERROR(exprtr->loc, ERR_SQL_SYNTAX_ERROR, "expression not in distinct list");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static bool32 sql_rs_column_is_array(rs_column_t *rs_col)
{
if (rs_col->datatype == OG_TYPE_ARRAY) {
return OG_TRUE;
}
if (rs_col->type == RS_COL_COLUMN) {
return (bool32)rs_col->v_col.is_array;
} else if (rs_col->type == RS_COL_CALC) {
return (bool32)rs_col->expr->root->typmod.is_array;
} else {
return OG_FALSE;
}
}
status_t sql_verify_query_distinct(sql_verifier_t *verif, sql_query_t *query)
{
uint32 i;
expr_tree_t *expr = NULL;
rs_column_t *rs_cols = NULL;
rs_column_t *rs_col = NULL;
expr_node_t *node = NULL;
expr_node_t *origin_ref = NULL;
if (!query->has_distinct) {
return OG_SUCCESS;
}
if (if_query_distinct_can_eliminate(verif, query)) {
query->has_distinct = OG_FALSE;
return OG_SUCCESS;
}
galist_t *emp_rs_columns = query->distinct_columns;
query->distinct_columns = query->rs_columns;
query->rs_columns = emp_rs_columns;
for (i = 0; i < query->distinct_columns->count; i++) {
rs_cols = (rs_column_t *)cm_galist_get(query->distinct_columns, i);
if (sql_rs_column_is_array(rs_cols)) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "unexpected array expression");
return OG_ERROR;
}
OG_RETURN_IFERR(cm_galist_new(query->rs_columns, sizeof(rs_column_t), (pointer_t *)&rs_col));
OG_RETURN_IFERR(sql_alloc_mem(verif->context, sizeof(expr_tree_t), (void **)&expr));
OG_RETURN_IFERR(sql_alloc_mem(verif->context, sizeof(expr_node_t), (void **)&node));
node->owner = expr;
node->unary = expr->unary;
node->typmod = rs_cols->typmod;
OG_RETURN_IFERR(sql_generate_origin_ref(verif->stmt, rs_cols, &origin_ref));
OG_RETURN_IFERR(sql_set_group_expr_node(verif->stmt, node, i, 0, 0, origin_ref));
expr->root = node;
expr->owner = verif->context;
rs_col->type = RS_COL_CALC;
rs_col->name = rs_cols->name;
rs_col->z_alias = rs_cols->z_alias;
rs_col->typmod = rs_cols->typmod;
rs_col->expr = expr;
rs_col->rs_flag = rs_cols->rs_flag;
}
return OG_SUCCESS;
}
static void og_sql_combine_str_type_mod_func(rs_column_t *rs_column_slct, rs_column_t *rs_column_qry)
{
if (rs_column_slct->datatype != rs_column_qry->datatype) {
rs_column_slct->datatype = OG_TYPE_STRING;
}
if (!rs_column_slct->typmod.is_char && rs_column_qry->typmod.is_char) {
rs_column_slct->size = MAX(rs_column_slct->size,
MIN(rs_column_qry->size * OG_CHAR_TO_BYTES_RATIO, OG_MAX_COLUMN_SIZE));
return;
}
rs_column_slct->size = MAX(rs_column_slct->size, rs_column_qry->size);
return;
}
static void og_verify_slect_rs_string_type(rs_column_t *rs_column_slct, rs_column_t *rs_column_qry)
{
uint16 res_size = 0;
uint16 qry_rs_size = 0;
uint16 selct_rs_size = 0;
if (OG_IS_STRING_TYPE(rs_column_qry->datatype) && rs_column_qry->typmod.is_char) {
selct_rs_size = (uint16)cm_get_datatype_strlen(rs_column_slct->datatype, rs_column_slct->size);
res_size = MAX(MIN(rs_column_qry->size * OG_CHAR_TO_BYTES_RATIO, OG_MAX_COLUMN_SIZE), selct_rs_size);
} else if (OG_IS_STRING_TYPE(rs_column_slct->datatype) && rs_column_slct->typmod.is_char) {
qry_rs_size = (uint16)cm_get_datatype_strlen(rs_column_qry->datatype, rs_column_qry->size);
res_size = ((rs_column_slct->size * OG_CHAR_TO_BYTES_RATIO) > qry_rs_size) ? rs_column_slct->size : qry_rs_size;
} else {
qry_rs_size = (uint16)cm_get_datatype_strlen(rs_column_qry->datatype, rs_column_qry->size);
selct_rs_size = (uint16)cm_get_datatype_strlen(rs_column_slct->datatype, rs_column_slct->size);
res_size = MAX(selct_rs_size, qry_rs_size);
}
(!OG_IS_STRING_TYPE(rs_column_slct->datatype)) && (rs_column_slct->typmod.mode = 0);
rs_column_slct->size = MAX(rs_column_slct->size, res_size);
rs_column_slct->datatype = OG_TYPE_STRING;
return;
}
static void og_verify_slect_rs_binary_size(rs_column_t *rs_column_slct, rs_column_t *rs_column_qry)
{
if (OG_IS_STRING_TYPE(rs_column_slct->datatype) && rs_column_slct->typmod.is_char) {
uint16 size = MIN(rs_column_slct->size * OG_CHAR_TO_BYTES_RATIO, OG_MAX_COLUMN_SIZE);
rs_column_slct->size = MAX(size, rs_column_qry->size);
return;
}
if (OG_IS_STRING_TYPE(rs_column_qry->datatype) && rs_column_qry->typmod.is_char) {
uint16 size = MIN(rs_column_qry->size * OG_CHAR_TO_BYTES_RATIO, OG_MAX_COLUMN_SIZE);
rs_column_slct->size = MAX(size, rs_column_slct->size);
return;
}
uint16 qry_rs_size = (uint16)cm_get_datatype_strlen(rs_column_qry->datatype, rs_column_qry->size);
uint16 selct_rs_size = (uint16)cm_get_datatype_strlen(rs_column_slct->datatype, rs_column_slct->size);
rs_column_slct->size = MAX(qry_rs_size, selct_rs_size);
return;
}
static inline bool32 is_varlen_str_type(og_type_t datatype)
{
return datatype == OG_TYPE_VARCHAR || datatype == OG_TYPE_STRING;
}
static void og_verify_slect_rs_binary_type(rs_column_t *rs_column_slct, rs_column_t *rs_column_qry)
{
og_verify_slect_rs_binary_size(rs_column_slct, rs_column_qry);
if (is_varlen_str_type(rs_column_slct->datatype) || is_varlen_str_type(rs_column_qry->datatype)) {
rs_column_slct->datatype = OG_TYPE_VARBINARY;
return;
}
if (OG_IS_BINARY_TYPE(rs_column_qry->datatype)) {
rs_column_slct->datatype = rs_column_qry->datatype;
return;
}
return;
}
static void og_verify_slect_rs_raw_type(rs_column_t *rs_column_slct, rs_column_t *rs_column_qry)
{
og_verify_slect_rs_binary_size(rs_column_slct, rs_column_qry);
rs_column_slct->datatype = OG_TYPE_RAW;
return;
}
static void og_verify_select_rs_typmod(rs_column_t *rs_column_slct, rs_column_t *rs_column_qry)
{
typmode_t combined_typemod = {0};
bool32 is_select_null = RS_COLUMN_IS_RESERVED_NULL(rs_column_slct);
bool32 is_query_null = RS_COLUMN_IS_RESERVED_NULL(rs_column_qry);
if (is_select_null) {
rs_column_slct->typmod = rs_column_qry->typmod;
return;
}
OG_RETVOID_IFTRUE(is_query_null);
if (OG_IS_STRING_TYPE2(rs_column_slct->datatype, rs_column_qry->datatype)) {
og_sql_combine_str_type_mod_func(rs_column_slct, rs_column_qry);
return;
}
if (OG_SUCCESS != cm_combine_typmode(rs_column_slct->typmod, is_select_null, rs_column_qry->typmod,
is_query_null, &combined_typemod)) {
cm_reset_error();
} else {
rs_column_slct->typmod = combined_typemod;
return;
}
bool32 slct_is_lob = OG_IS_LOB_TYPE(rs_column_slct->datatype);
bool32 qry_is_lob = OG_IS_LOB_TYPE(rs_column_qry->datatype);
if (slct_is_lob || qry_is_lob) {
rs_column_slct->datatype = qry_is_lob ? rs_column_qry->datatype : rs_column_slct->datatype;
return;
}
bool32 slct_is_raw = OG_IS_RAW_TYPE(rs_column_slct->datatype);
bool32 qry_is_raw = OG_IS_RAW_TYPE(rs_column_qry->datatype);
if (slct_is_raw || qry_is_raw) {
og_verify_slect_rs_raw_type(rs_column_slct, rs_column_qry);
return;
}
bool32 slct_is_bin = OG_IS_BINARY_TYPE(rs_column_slct->datatype);
bool32 qry_is_bin = OG_IS_BINARY_TYPE(rs_column_qry->datatype);
if (slct_is_bin || qry_is_bin) {
og_verify_slect_rs_binary_type(rs_column_slct, rs_column_qry);
return;
}
bool32 slct_is_str = OG_IS_STRING_TYPE(rs_column_slct->datatype);
bool32 qry_is_str = OG_IS_STRING_TYPE(rs_column_qry->datatype);
if (slct_is_str || qry_is_str) {
og_verify_slect_rs_string_type(rs_column_slct, rs_column_qry);
return;
}
bool32 slct_is_bool = OG_IS_BOOLEAN_TYPE(rs_column_slct->datatype);
bool32 qry_is_bool = OG_IS_BOOLEAN_TYPE(rs_column_qry->datatype);
if (slct_is_bool || qry_is_bool) {
rs_column_slct->size = OG_MAX_BOOL_STRLEN;
rs_column_slct->datatype = OG_TYPE_BOOLEAN;
}
return;
}
static bool32 og_selct_rs_datatype_matched(const typmode_t *select_rs_typmod, const typmode_t *query_rs_typmod)
{
OG_RETVALUE_IFTRUE(select_rs_typmod->is_array != query_rs_typmod->is_array, OG_FALSE);
OG_RETVALUE_IFTRUE(!var_datatype_matched(select_rs_typmod->datatype, query_rs_typmod->datatype) &&
!var_datatype_matched(query_rs_typmod->datatype, select_rs_typmod->datatype), OG_FALSE);
OG_RETVALUE_IFTRUE(OG_IS_LOB_TYPE(select_rs_typmod->datatype) && OG_IS_LOB_TYPE(query_rs_typmod->datatype) &&
select_rs_typmod->datatype != query_rs_typmod->datatype, OG_FALSE);
return OG_TRUE;
}
static status_t sql_verify_slect_rs_col(sql_verifier_t *verif, sql_query_t *query, uint32 col_idx)
{
rs_column_t *rs_column_qry = (rs_column_t *)cm_galist_get(query->rs_columns, col_idx);
rs_column_t *rs_column_slct = (rs_column_t *)cm_galist_get(query->owner->rs_columns, col_idx);
if (!og_selct_rs_datatype_matched(&rs_column_slct->typmod, &rs_column_qry->typmod)) {
if (rs_column_slct->datatype == OG_TYPE_CURSOR || rs_column_qry->datatype == OG_TYPE_CURSOR) {
OG_SRC_THROW_ERROR(query->loc, ERR_SQL_SYNTAX_ERROR, "unexpected cursor expression");
return OG_ERROR;
}
OG_SRC_THROW_ERROR(query->loc, ERR_SQL_SYNTAX_ERROR,
"expression must have same datatype as corresponding expression");
return OG_ERROR;
}
if (verif->has_union || verif->has_minus || verif->has_except_intersect) {
if (rs_column_slct->typmod.is_array) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "unexpected array expression");
return OG_ERROR;
}
}
og_verify_select_rs_typmod(rs_column_slct, rs_column_qry);
return OG_SUCCESS;
}
static status_t sql_verify_select_rs_columns(sql_verifier_t *verif, sql_query_t *query)
{
if (query->owner->type == SELECT_AS_RESULT) {
if (verif->context->rs_columns == NULL) {
verif->context->rs_columns = query->rs_columns;
}
}
if (query->owner->rs_columns == NULL) {
query->owner->rs_columns = query->rs_columns;
return OG_SUCCESS;
}
if (query->owner->rs_columns->count != query->rs_columns->count) {
OG_SRC_THROW_ERROR(query->loc, ERR_SQL_SYNTAX_ERROR, "query block has incorrect number of result columns");
return OG_ERROR;
}
for (uint32 i = 0; i < query->owner->rs_columns->count; ++i) {
OG_RETURN_IFERR(sql_verify_slect_rs_col(verif, query, i));
}
if (query->owner->type == SELECT_AS_RESULT) {
verif->context->rs_columns = query->owner->rs_columns;
}
return OG_SUCCESS;
}
status_t sql_verify_query_limit(sql_verifier_t *verif, sql_query_t *query)
{
variant_t limit_offset_var;
variant_t limit_count_var;
OG_RETURN_IFERR(sql_verify_limit_offset(verif->stmt, &query->limit));
if (query->limit.offset != NULL && ((expr_tree_t *)(query->limit.offset))->root->type == EXPR_NODE_CONST) {
OG_RETURN_IFERR(sql_exec_expr(verif->stmt, (expr_tree_t *)query->limit.offset, &limit_offset_var));
if (limit_offset_var.is_null) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "offset must not be null");
return OG_ERROR;
}
OG_RETURN_IFERR(sql_convert_limit_num(&limit_offset_var));
if (limit_offset_var.v_bigint < 0) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "offset must not be negative");
return OG_ERROR;
}
}
if (query->limit.count != NULL && ((expr_tree_t *)(query->limit.count))->root->type == EXPR_NODE_CONST) {
OG_RETURN_IFERR(sql_exec_expr(verif->stmt, (expr_tree_t *)query->limit.count, &limit_count_var));
if (limit_count_var.is_null) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "limit must not be null");
return OG_ERROR;
}
OG_RETURN_IFERR(sql_convert_limit_num(&limit_count_var));
if (limit_count_var.v_bigint < 0) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "limit must not be negative");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static inline status_t sql_set_cbo_flag_4_subselect(sql_query_t *query)
{
sql_table_t *table = NULL;
sql_select_t *select_ctx = query->owner;
if (select_ctx == NULL) {
return OG_SUCCESS;
}
if (!select_ctx->is_update_value || (select_ctx->parent_refs->count == 0 && select_ctx->has_ancestor == 0)) {
return OG_SUCCESS;
}
select_ctx->can_sub_opt = OG_FALSE;
for (uint32 i = 0; i < query->tables.count; ++i) {
table = (sql_table_t *)sql_array_get(&query->tables, i);
TABLE_CBO_SET_FLAG(table, SELTION_NO_HASH_JOIN);
}
return OG_SUCCESS;
}
static status_t sql_add_table_for_update_cols(sql_stmt_t *stmt, sql_table_t *table, uint32 col)
{
uint32 *new_col = NULL;
if (col == OG_INVALID_ID32) {
return OG_SUCCESS;
}
if (table->for_update_cols == NULL) {
OG_RETURN_IFERR(sql_create_list(stmt, &table->for_update_cols));
}
OG_RETURN_IFERR(sql_alloc_mem(stmt->context, sizeof(uint32), (void **)&new_col));
*new_col = col;
OG_RETURN_IFERR(cm_galist_insert(table->for_update_cols, new_col));
return OG_SUCCESS;
}
static inline status_t sql_verify_for_update_rs_col(sql_query_t *query, uint32 col, sql_table_t **sub_table,
uint32 *sub_col)
{
rs_column_t *rs_col = (rs_column_t *)cm_galist_get(query->rs_columns, col);
if (rs_col->type == RS_COL_COLUMN) {
*sub_col = rs_col->v_col.col;
*sub_table = (sql_table_t *)sql_array_get(&query->tables, rs_col->v_col.tab);
} else if (rs_col->expr->next == NULL && NODE_IS_RES_ROWID(rs_col->expr->root)) {
*sub_col = OG_INVALID_ID32;
*sub_table = (sql_table_t *)sql_array_get(&query->tables, ROWID_NODE_TAB(rs_col->expr->root));
} else {
OG_SRC_THROW_ERROR(rs_col->expr->loc, ERR_CALC_COLUMN_NOT_ALLOWED);
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t sql_verify_table_for_update(sql_stmt_t *stmt, sql_table_t *table, uint32 col)
{
OG_RETURN_IFERR(sql_stack_safe(stmt));
if (table->type == NORMAL_TABLE) {
table->for_update = OG_TRUE;
if (table->entry->dc.type == DICT_TYPE_DYNAMIC_VIEW) {
OG_THROW_ERROR(ERR_FOR_UPDATE_NOT_ALLOWED);
return OG_ERROR;
}
OG_RETURN_IFERR(sql_add_table_for_update_cols(stmt, table, col));
return OG_SUCCESS;
}
if (!OG_IS_SUBSELECT_TABLE(table->type)) {
OG_THROW_ERROR(ERR_FOR_UPDATE_NOT_ALLOWED);
return OG_ERROR;
}
uint32 sub_col;
sql_table_t *sub_table = NULL;
sql_select_t *select_ctx = table->select_ctx;
sql_query_t *query = select_ctx->first_query;
if (select_ctx->root->type != SELECT_NODE_QUERY || query->distinct_columns->count != 0 ||
query->group_sets->count != 0 || query->aggrs->count != 0 || query->cntdis_columns->count != 0 ||
query->connect_by_cond != NULL || query->winsort_list->count != 0 || ROWNUM_COND_OCCUR(query->cond) ||
LIMIT_CLAUSE_OCCUR(&query->limit)) {
OG_THROW_ERROR(ERR_FOR_UPDATE_FROM_VIEW);
return OG_ERROR;
}
if (col == OG_INVALID_ID32) {
for (uint32 i = 0; i < query->tables.count; i++) {
sub_table = (sql_table_t *)sql_array_get(&query->tables, i);
OG_RETURN_IFERR(sql_verify_table_for_update(stmt, sub_table, OG_INVALID_ID32));
}
table->for_update = OG_TRUE;
select_ctx->for_update = OG_TRUE;
return OG_SUCCESS;
}
OG_RETURN_IFERR(sql_verify_for_update_rs_col(query, col, &sub_table, &sub_col));
OG_RETURN_IFERR(sql_verify_table_for_update(stmt, sub_table, sub_col));
table->for_update = OG_TRUE;
select_ctx->for_update = OG_TRUE;
return OG_SUCCESS;
}
static status_t sql_verify_for_update_columns(sql_verifier_t *verif, sql_query_t *query)
{
expr_tree_t *expr = NULL;
sql_table_t *table = NULL;
galist_t *for_update_cols = verif->select_ctx->for_update_cols;
if (!query->for_update) {
return OG_SUCCESS;
}
verif->excl_flags = SQL_FOR_UPDATE_EXCL;
if (for_update_cols == NULL) {
for (uint32 i = 0; i < query->tables.count; i++) {
table = (sql_table_t *)sql_array_get(&query->tables, i);
OG_RETURN_IFERR(sql_verify_table_for_update(verif->stmt, table, OG_INVALID_ID32));
}
return OG_SUCCESS;
}
for (uint32 i = 0; i < for_update_cols->count; i++) {
expr = (expr_tree_t *)cm_galist_get(for_update_cols, i);
if (sql_verify_expr(verif, expr) != OG_SUCCESS) {
return OG_ERROR;
}
if (expr->root->type != EXPR_NODE_COLUMN) {
OG_SRC_THROW_ERROR(expr->loc, ERR_EXPECT_COLUMN_HERE);
return OG_ERROR;
}
if (NODE_ANCESTOR(expr->root) != 0) {
OG_SRC_THROW_ERROR(expr->loc, ERR_FOR_UPDATE_NOT_ALLOWED);
return OG_ERROR;
}
table = (sql_table_t *)sql_array_get(&query->tables, NODE_TAB(expr->root));
OG_RETURN_IFERR(sql_verify_table_for_update(verif->stmt, table, NODE_COL(expr->root)));
}
return OG_SUCCESS;
}
static inline void sql_organize_group_sets(sql_query_t *query)
{
group_set_t *group_set = NULL;
for (uint32 i = 0; i < query->group_sets->count; i++) {
group_set = (group_set_t *)cm_galist_get(query->group_sets, i);
group_set->group_id = i;
}
}
static status_t sql_create_specified_expr(sql_stmt_t *stmt, expr_tree_t **expr, expr_node_type_t type,
og_type_t datatype, variant_t value)
{
expr_node_t *node = NULL;
OG_RETURN_IFERR(sql_create_expr(stmt, expr));
OG_RETURN_IFERR(sql_alloc_mem((void *)stmt->context, sizeof(expr_node_t), (void **)&node));
node->type = type;
node->datatype = datatype;
node->value = value;
(*expr)->root = node;
return OG_SUCCESS;
}
static status_t sql_create_null_expr(sql_stmt_t *stmt, expr_tree_t **expr)
{
variant_t value;
value.is_null = OG_FALSE;
value.type = OG_TYPE_INTEGER;
value.v_int = RES_WORD_NULL;
return sql_create_specified_expr(stmt, expr, EXPR_NODE_RESERVED, OG_TYPE_VARCHAR, value);
}
static status_t sql_create_const_number_expr(sql_stmt_t *stmt, expr_tree_t **expr, int val)
{
variant_t value;
value.v_int = val;
value.is_null = OG_FALSE;
value.type = OG_TYPE_INTEGER;
return sql_create_specified_expr(stmt, expr, EXPR_NODE_CONST, OG_TYPE_INTEGER, value);
}
static status_t sql_build_decode_4_count(sql_stmt_t *stmt, expr_node_t *node)
{
node->type = EXPR_NODE_FUNC;
node->value.v_func.func_id = ID_FUNC_ITEM_DECODE;
node->value.v_func.pack_id = OG_INVALID_ID32;
node->typmod.datatype = OG_TYPE_INTEGER;
OG_RETURN_IFERR(sql_create_null_expr(stmt, &node->argument->next));
OG_RETURN_IFERR(sql_create_const_number_expr(stmt, &node->argument->next->next, 0));
OG_RETURN_IFERR(sql_create_const_number_expr(stmt, &node->argument->next->next->next, 1));
return OG_SUCCESS;
}
static status_t sql_build_decode_4_stddev(sql_stmt_t *stmt, expr_node_t *node)
{
node->type = EXPR_NODE_FUNC;
node->value.v_func.func_id = ID_FUNC_ITEM_DECODE;
node->value.v_func.pack_id = OG_INVALID_ID32;
node->typmod.datatype = OG_TYPE_INTEGER;
OG_RETURN_IFERR(sql_create_null_expr(stmt, &node->argument->next));
OG_RETURN_IFERR(sql_create_null_expr(stmt, &node->argument->next->next));
OG_RETURN_IFERR(sql_create_const_number_expr(stmt, &node->argument->next->next->next, 0));
return OG_SUCCESS;
}
static status_t sql_build_decode_4_covar_pop(sql_stmt_t *stmt, expr_node_t *node)
{
expr_node_t *arg_node = NULL;
node->type = EXPR_NODE_FUNC;
node->value.v_func.func_id = ID_FUNC_ITEM_DECODE;
node->value.v_func.pack_id = OG_INVALID_ID32;
node->typmod.datatype = OG_TYPE_INTEGER;
OG_RETURN_IFERR(sql_alloc_mem(stmt->context, sizeof(expr_node_t), (void **)&arg_node));
arg_node->argument = node->argument->next;
OG_RETURN_IFERR(sql_create_null_expr(stmt, &node->argument->next));
OG_RETURN_IFERR(sql_create_null_expr(stmt, &node->argument->next->next));
OG_RETURN_IFERR(sql_create_expr(stmt, &node->argument->next->next->next));
arg_node->type = EXPR_NODE_FUNC;
arg_node->value.v_func.func_id = ID_FUNC_ITEM_DECODE;
arg_node->value.v_func.pack_id = OG_INVALID_ID32;
arg_node->typmod.datatype = OG_TYPE_INTEGER;
OG_RETURN_IFERR(sql_create_null_expr(stmt, &arg_node->argument->next));
OG_RETURN_IFERR(sql_create_null_expr(stmt, &arg_node->argument->next->next));
OG_RETURN_IFERR(sql_create_const_number_expr(stmt, &arg_node->argument->next->next->next, 0));
node->argument->next->next->next->root = arg_node;
return OG_SUCCESS;
}
static status_t sql_rewrite_aggr_node(sql_stmt_t *stmt, sql_func_t *func, expr_node_t *node)
{
switch (func->builtin_func_id) {
case ID_FUNC_ITEM_AVG:
case ID_FUNC_ITEM_SUM:
case ID_FUNC_ITEM_MIN:
case ID_FUNC_ITEM_MAX:
case ID_FUNC_ITEM_MEDIAN:
*node = *node->argument->root;
break;
case ID_FUNC_ITEM_COUNT:
if (node->argument->root->type == EXPR_NODE_STAR || node->argument->root->type == EXPR_NODE_CONST) {
node->type = EXPR_NODE_CONST;
node->value.type = OG_TYPE_INTEGER;
node->value.v_int = 1;
node->value.is_null = OG_FALSE;
break;
} else {
return sql_build_decode_4_count(stmt, node);
}
case ID_FUNC_ITEM_STDDEV:
case ID_FUNC_ITEM_STDDEV_POP:
case ID_FUNC_ITEM_VAR_POP:
case ID_FUNC_ITEM_VARIANCE:
return sql_build_decode_4_stddev(stmt, node);
case ID_FUNC_ITEM_COVAR_POP:
return sql_build_decode_4_covar_pop(stmt, node);
case ID_FUNC_ITEM_STDDEV_SAMP:
case ID_FUNC_ITEM_CORR:
case ID_FUNC_ITEM_COVAR_SAMP:
case ID_FUNC_ITEM_VAR_SAMP:
node->type = EXPR_NODE_RESERVED;
node->value.type = OG_TYPE_VARCHAR;
node->value.v_int = RES_WORD_NULL;
node->value.is_null = OG_FALSE;
break;
case ID_FUNC_ITEM_LISTAGG:
*node = *node->argument->next->root;
break;
default:
break;
}
return OG_SUCCESS;
}
static status_t modify_aggr_node_4_eliminate(visit_assist_t *va, expr_node_t **node)
{
expr_node_t *aggr_node = NULL;
sql_func_t *func = NULL;
if ((*node)->type == EXPR_NODE_AGGR) {
aggr_node = (expr_node_t *)cm_galist_get(va->query->aggrs, (*node)->value.v_int);
func = sql_get_func(&aggr_node->value.v_func);
OG_RETURN_IFERR(sql_rewrite_aggr_node(va->stmt, func, *node));
}
if ((*node)->type == EXPR_NODE_GROUP) {
expr_node_t *origin_ref = sql_get_origin_ref(*node);
**node = *origin_ref;
}
return OG_SUCCESS;
}
static status_t sql_regen_rs_column(sql_stmt_t *stmt, expr_tree_t *expr, rs_column_t *rs_col)
{
if (expr->root->type == EXPR_NODE_COLUMN) {
rs_col->type = RS_COL_COLUMN;
rs_col->v_col = *VALUE_PTR(var_column_t, &expr->root->value);
} else {
rs_col->expr = expr;
}
return OG_SUCCESS;
}
static inline void sql_reset_rs_col_flags(rs_column_t *rs_col)
{
cols_used_t cols_used;
if (rs_col->type == RS_COL_COLUMN) {
OG_BIT_RESET(rs_col->rs_flag, RS_COND_UNABLE);
return;
}
if (rs_col->type == RS_COL_CALC && rs_col->expr->root->type == EXPR_NODE_AGGR) {
return;
}
init_cols_used(&cols_used);
sql_collect_cols_in_expr_node(rs_col->expr->root, &cols_used);
if (!HAS_ROWNUM(&cols_used)) {
OG_BIT_RESET(rs_col->rs_flag, RS_COND_UNABLE);
}
}
static status_t sql_eliminate_group_set(sql_stmt_t *stmt, sql_query_t *query)
{
uint32 i;
bool32 need_reset_flag = OG_FALSE;
rs_column_t *rs_col = NULL;
sort_item_t *item = NULL;
visit_assist_t va;
sql_init_visit_assist(&va, stmt, query);
for (i = 0; i < query->rs_columns->count; i++) {
rs_col = (rs_column_t *)cm_galist_get(query->rs_columns, i);
need_reset_flag = (rs_col->type == RS_COL_CALC && rs_col->expr->root->type == EXPR_NODE_AGGR);
OG_RETURN_IFERR(visit_expr_tree(&va, rs_col->expr, modify_aggr_node_4_eliminate));
OG_RETURN_IFERR(sql_regen_rs_column(stmt, rs_col->expr, rs_col));
if (need_reset_flag) {
sql_reset_rs_col_flags(rs_col);
}
}
if (query->having_cond != NULL) {
OG_RETURN_IFERR(visit_cond_node(&va, query->having_cond->root, modify_aggr_node_4_eliminate));
if (query->cond != NULL) {
OG_RETURN_IFERR(sql_add_cond_node(query->cond, query->having_cond->root));
} else {
query->cond = query->having_cond;
}
query->having_cond = NULL;
}
for (i = 0; i < query->sort_items->count; i++) {
item = (sort_item_t *)cm_galist_get(query->sort_items, i);
OG_RETURN_IFERR(visit_expr_tree(&va, item->expr, modify_aggr_node_4_eliminate));
}
cm_galist_reset(query->aggrs);
cm_galist_reset(query->group_sets);
return OG_SUCCESS;
}
static bool32 chk_aggr_node_name(uint32 builtin_func_id)
{
switch (builtin_func_id) {
case ID_FUNC_ITEM_AVG:
case ID_FUNC_ITEM_MIN:
case ID_FUNC_ITEM_SUM:
case ID_FUNC_ITEM_MAX:
case ID_FUNC_ITEM_MEDIAN:
case ID_FUNC_ITEM_COUNT:
case ID_FUNC_ITEM_STDDEV:
case ID_FUNC_ITEM_STDDEV_POP:
case ID_FUNC_ITEM_COVAR_POP:
case ID_FUNC_ITEM_VAR_POP:
case ID_FUNC_ITEM_VARIANCE:
case ID_FUNC_ITEM_STDDEV_SAMP:
case ID_FUNC_ITEM_CORR:
case ID_FUNC_ITEM_COVAR_SAMP:
case ID_FUNC_ITEM_VAR_SAMP:
case ID_FUNC_ITEM_LISTAGG:
return OG_TRUE;
default:
break;
}
return OG_FALSE;
}
static bool32 chk_aggr_node_args(sql_stmt_t *stmt, expr_node_t *node)
{
if (sql_stack_safe(stmt) != OG_SUCCESS) {
return OG_FALSE;
}
expr_tree_t *arg = NULL;
switch (node->type) {
case EXPR_NODE_COLUMN:
case EXPR_NODE_CONST:
case EXPR_NODE_STAR:
case EXPR_NODE_GROUP:
return OG_TRUE;
case EXPR_NODE_ADD:
case EXPR_NODE_SUB:
case EXPR_NODE_MOD:
case EXPR_NODE_DIV:
case EXPR_NODE_MUL:
case EXPR_NODE_BITAND:
case EXPR_NODE_BITOR:
case EXPR_NODE_BITXOR:
case EXPR_NODE_LSHIFT:
case EXPR_NODE_RSHIFT:
case EXPR_NODE_NEGATIVE:
if (node->left != NULL && !chk_aggr_node_args(stmt, node->left)) {
return OG_FALSE;
}
if (node->right != NULL && !chk_aggr_node_args(stmt, node->right)) {
return OG_FALSE;
}
return OG_TRUE;
case EXPR_NODE_FUNC:
if (node->value.v_func.func_id == ID_FUNC_ITEM_LNNVL || node->value.v_func.func_id == ID_FUNC_ITEM_IF) {
return OG_FALSE;
}
arg = node->argument;
while (arg != NULL) {
if (!chk_aggr_node_args(stmt, arg->root)) {
return OG_FALSE;
}
arg = arg->next;
}
return OG_TRUE;
default:
return OG_FALSE;
}
}
static bool32 chk_aggr_node_can_rewrite(sql_stmt_t *stmt, expr_node_t *aggr_node)
{
sql_func_t *func = NULL;
expr_tree_t *args = aggr_node->argument;
while (args != NULL) {
if (!chk_aggr_node_args(stmt, args->root)) {
return OG_FALSE;
}
args = args->next;
}
func = sql_get_func(&aggr_node->value.v_func);
return chk_aggr_node_name(func->builtin_func_id);
}
static bool32 chk_aggrs_can_rewrite(sql_stmt_t *stmt, sql_query_t *query)
{
uint32 i;
expr_node_t *aggr_node = NULL;
for (i = 0; i < query->aggrs->count; i++) {
aggr_node = (expr_node_t *)cm_galist_get(query->aggrs, i);
if (!chk_aggr_node_can_rewrite(stmt, aggr_node)) {
return OG_FALSE;
}
}
return OG_TRUE;
}
static bool32 chk_having_cond_has_subslct(sql_stmt_t *stmt, sql_query_t *query)
{
if (query->having_cond != NULL) {
cols_used_t cols_used;
init_cols_used(&cols_used);
sql_collect_cols_in_cond(query->having_cond->root, &cols_used);
return HAS_SUBSLCT(&cols_used);
}
return OG_FALSE;
}
static bool32 chk_rs_cols_has_subslect(sql_stmt_t *stmt, sql_query_t *query)
{
cols_used_t cols_used;
init_cols_used(&cols_used);
for (uint32 i = 0; i < query->rs_columns->count; i++) {
rs_column_t *rs_col = (rs_column_t *)cm_galist_get(query->rs_columns, i);
sql_collect_cols_in_expr_node(rs_col->expr->root, &cols_used);
if (HAS_DYNAMIC_SUBSLCT(&cols_used)) {
return OG_TRUE;
}
}
return OG_FALSE;
}
static bool32 if_eliminate_group_set(sql_stmt_t *stmt, sql_query_t *query)
{
uint32 i;
expr_tree_t *group_expr = NULL;
if (query->group_sets->count != 1 || query->tables.count > 1 || query->winsort_list->count > 0 ||
query->has_distinct || query->connect_by_cond != NULL) {
return OG_FALSE;
}
sql_array_t *tables = &query->tables;
sql_table_t *table = (sql_table_t *)sql_array_get(tables, 0);
if (table->type != NORMAL_TABLE) {
return OG_FALSE;
}
group_set_t *group_set = (group_set_t *)cm_galist_get(query->group_sets, 0);
for (i = 0; i < group_set->items->count; i++) {
group_expr = (expr_tree_t *)cm_galist_get(group_set->items, i);
if (group_expr->root->type != EXPR_NODE_COLUMN || EXPR_ANCESTOR(group_expr) > 0) {
return OG_FALSE;
}
}
if (!chk_rs_cols_has_subslect(stmt, query) && chk_aggrs_can_rewrite(stmt, query) &&
!chk_having_cond_has_subslct(stmt, query) && if_unqiue_idx_in_list(query, table, group_set->items)) {
return OG_TRUE;
}
return OG_FALSE;
}
static status_t sql_try_eliminate_group_set(sql_stmt_t *stmt, sql_query_t *query)
{
if (if_eliminate_group_set(stmt, query)) {
OG_RETURN_IFERR(sql_eliminate_group_set(stmt, query));
}
return OG_SUCCESS;
}
static status_t sql_verify_query(sql_verifier_t *verif, sql_query_t *query)
{
CM_POINTER2(verif, query);
query->for_update = verif->for_update;
query->owner = verif->select_ctx;
SET_NODE_STACK_CURR_QUERY(verif->stmt, query);
OG_RETURN_IFERR(sql_verify_tables(verif, query));
OG_RETURN_IFERR(sql_verify_query_group(verif, query));
OG_RETURN_IFERR(sql_verify_query_columns(verif, query));
OG_RETURN_IFERR(sql_verify_query_pivot(verif, query));
OG_RETURN_IFERR(sql_verify_query_unpivot(verif, query));
OG_RETURN_IFERR(sql_verify_query_distinct(verif, query));
OG_RETURN_IFERR(sql_verify_query_where(verif, query));
OG_RETURN_IFERR(sql_set_cbo_flag_4_subselect(query));
OG_RETURN_IFERR(sql_verify_query_joins(verif, query));
OG_RETURN_IFERR(sql_verify_query_connect(verif, query));
OG_RETURN_IFERR(sql_verify_query_having(verif, query));
OG_RETURN_IFERR(sql_verify_query_order(verif, query, query->sort_items, OG_TRUE));
OG_RETURN_IFERR(sql_verify_select_rs_columns(verif, query));
OG_RETURN_IFERR(sql_verify_query_limit(verif, query));
OG_RETURN_IFERR(sql_verify_for_update_columns(verif, query));
OG_RETURN_IFERR(sql_try_eliminate_group_set(verif->stmt, query));
query->hint_info = verif->stmt->context->hint_info;
og_hint_verify(verif->stmt, OGSQL_TYPE_SELECT, (void *)query);
sql_organize_group_sets(query);
SQL_RESTORE_NODE_STACK(verif->stmt);
return OG_SUCCESS;
}
static status_t sql_verify_select_node(sql_verifier_t *verif, select_node_t *node)
{
OG_RETURN_IFERR(sql_stack_safe(verif->stmt));
switch (node->type) {
case SELECT_NODE_QUERY:
return sql_verify_query(verif, node->query);
case SELECT_NODE_UNION:
if (verif->has_union) {
node->type = SELECT_NODE_UNION_ALL;
} else {
verif->has_union = OG_TRUE;
}
OG_RETURN_IFERR(sql_verify_select_node(verif, node->left));
OG_RETURN_IFERR(sql_verify_select_node(verif, node->right));
if (node->type == SELECT_NODE_UNION) {
verif->has_union = OG_FALSE;
}
return OG_SUCCESS;
case SELECT_NODE_UNION_ALL:
OG_RETURN_IFERR(sql_verify_select_node(verif, node->left));
return sql_verify_select_node(verif, node->right);
case SELECT_NODE_MINUS:
case SELECT_NODE_EXCEPT:
verif->has_minus = OG_TRUE;
OG_RETURN_IFERR(sql_verify_select_node(verif, node->left));
OG_RETURN_IFERR(sql_verify_select_node(verif, node->right));
verif->has_minus = OG_FALSE;
return OG_SUCCESS;
case SELECT_NODE_INTERSECT:
case SELECT_NODE_INTERSECT_ALL:
case SELECT_NODE_EXCEPT_ALL:
verif->has_except_intersect = OG_TRUE;
OG_RETURN_IFERR(sql_verify_select_node(verif, node->left));
OG_RETURN_IFERR(sql_verify_select_node(verif, node->right));
verif->has_except_intersect = OG_FALSE;
return OG_SUCCESS;
default:
OG_THROW_ERROR(ERR_UNSUPPORT_OPER_TYPE, "set", node->type);
return OG_ERROR;
}
}
static inline bool32 og_array_col_is_equal(const var_column_t *col1, const var_column_t *col2)
{
CM_POINTER2(col1, col2);
OG_RETVALUE_IFTRUE(col1->is_array != col2->is_array, OG_FALSE);
OG_RETVALUE_IFTRUE(col1->is_array,
col1->ss_start == col2->ss_start && col1->ss_end == col2->ss_end);
OG_RETVALUE_IFTRUE(VAR_COL_IS_ARRAY_ELEMENT(col1) && VAR_COL_IS_ARRAY_ELEMENT(col2),
col1->ss_start == col2->ss_start);
return OG_TRUE;
}
static bool32 sql_rs_col_equal_sort_col(sql_stmt_t *stmt, rs_column_t *rs_col, sort_item_t *sort_item)
{
expr_node_t *sort_expr_node = NULL;
if (rs_col->type == RS_COL_COLUMN) {
sort_expr_node = sort_item->expr->root;
if (sort_expr_node->unary == UNARY_OPER_ROOT) {
return OG_FALSE;
}
if (sort_expr_node->type == EXPR_NODE_COLUMN && rs_col->v_col.tab == VAR_TAB(&sort_expr_node->value) &&
rs_col->v_col.col == VAR_COL(&sort_expr_node->value) &&
og_array_col_is_equal(&rs_col->v_col, &sort_expr_node->value.v_col)) {
return OG_TRUE;
}
} else if (rs_col->type == RS_COL_CALC) {
if (rs_col->expr->root->unary == UNARY_OPER_ROOT && sort_item->expr->root->unary != UNARY_OPER_ROOT) {
return OG_FALSE;
}
if (rs_col->expr->root->unary != UNARY_OPER_ROOT && sort_item->expr->root->unary == UNARY_OPER_ROOT) {
return OG_FALSE;
}
if (sql_expr_node_equal(stmt, rs_col->expr->root, sort_item->expr->root, NULL)) {
return OG_TRUE;
}
}
return OG_FALSE;
}
static status_t sql_create_select_sort_items(sql_verifier_t *verif, sql_select_t *select_ctx)
{
galist_t *rs_columns = select_ctx->first_query->rs_columns;
galist_t *sort_items = select_ctx->sort_items;
uint32 i;
uint32 j;
rs_column_t *rs_col = NULL;
sort_item_t *sort_item = NULL;
select_sort_item_t *select_sort_item = NULL;
bool32 is_found = OG_FALSE;
if (sql_create_list(verif->stmt, &select_ctx->select_sort_items) != OG_SUCCESS) {
return OG_ERROR;
}
for (i = 0; i < sort_items->count; ++i) {
sort_item = (sort_item_t *)cm_galist_get(sort_items, i);
is_found = OG_FALSE;
if (cm_galist_new(select_ctx->select_sort_items, sizeof(select_sort_item_t), (void **)&select_sort_item) !=
OG_SUCCESS) {
return OG_ERROR;
}
for (j = 0; j < rs_columns->count; ++j) {
rs_col = (rs_column_t *)cm_galist_get(rs_columns, j);
if (sql_rs_col_equal_sort_col(verif->stmt, rs_col, sort_item)) {
select_sort_item->rs_columns_id = j;
select_sort_item->datatype = rs_col->datatype;
select_sort_item->sort_mode = sort_item->sort_mode;
is_found = OG_TRUE;
break;
}
}
if (!is_found) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "ORDER BY item must be the number of a SELECT-list expression");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t sql_verify_select_order(sql_verifier_t *verif, sql_select_t *select_ctx)
{
SET_NODE_STACK_CURR_QUERY(verif->stmt, select_ctx->first_query);
if (sql_verify_query_order(verif, select_ctx->first_query, select_ctx->sort_items, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
SQL_RESTORE_NODE_STACK(verif->stmt);
return sql_create_select_sort_items(verif, select_ctx);
}
static void sql_set_query_rs_datatype(galist_t *select_rs_cols, select_node_t *node)
{
uint32 i;
rs_column_t *select_col = NULL;
rs_column_t *query_rs_col = NULL;
switch (node->type) {
case SELECT_NODE_QUERY: {
if (select_rs_cols == node->query->rs_columns) {
return;
}
for (i = 0; i < select_rs_cols->count; ++i) {
select_col = (rs_column_t *)cm_galist_get(select_rs_cols, i);
query_rs_col = (rs_column_t *)cm_galist_get(node->query->rs_columns, i);
query_rs_col->typmod = select_col->typmod;
if (select_col->type == RS_COL_CALC && select_col->expr != NULL &&
select_col->expr->root->type == EXPR_NODE_ARRAY) {
select_col->expr->root->datatype = select_col->datatype;
query_rs_col->expr->root->datatype = select_col->datatype;
}
}
return;
}
default:
sql_set_query_rs_datatype(select_rs_cols, node->left);
sql_set_query_rs_datatype(select_rs_cols, node->right);
return;
}
}
static void sql_record_pending_column(sql_select_t *select_ctx)
{
rs_column_t *rs_column = NULL;
uint32 i;
select_ctx->pending_col_count = 0;
for (i = 0; i < select_ctx->rs_columns->count; ++i) {
rs_column = (rs_column_t *)cm_galist_get(select_ctx->rs_columns, i);
if (rs_column->datatype == OG_TYPE_UNKNOWN) {
select_ctx->pending_col_count++;
}
}
}
static inline void sql_try_optmz_select_type(sql_verifier_t *verif, sql_select_t *select_ctx)
{
sql_query_t *query = NULL;
if (select_ctx->type != SELECT_AS_LIST) {
return;
}
if (select_ctx->root->type != SELECT_NODE_QUERY) {
return;
}
query = select_ctx->first_query;
if (query->group_sets->count != 0 || query->winsort_list->count != 0) {
return;
}
if (query->aggrs->count == 1 && query->rs_columns->count == 1) {
select_ctx->type = SELECT_AS_VARIANT;
}
}
static status_t sql_verify_withas_ctx(sql_stmt_t *stmt, galist_t *withas_ctx)
{
sql_verifier_t verif = { 0 };
sql_withas_factor_t *factor = NULL;
sql_select_t *select_ctx = NULL;
uint32 i;
verif.stmt = stmt;
verif.context = stmt->context;
for (i = 0; i < withas_ctx->count; i++) {
factor = (sql_withas_factor_t *)cm_galist_get(withas_ctx, i);
select_ctx = (sql_select_t *)factor->subquery_ctx;
verif.select_ctx = select_ctx;
verif.for_update = select_ctx->for_update;
verif.excl_flags = SQL_EXCL_DEFAULT;
verif.do_expr_optmz = OG_TRUE;
verif.parent = NULL;
OG_RETURN_IFERR(sql_verify_select_context(&verif, select_ctx));
}
return OG_SUCCESS;
}
status_t sql_verify_select_context(sql_verifier_t *verif, sql_select_t *select_ctx)
{
verif->select_ctx = select_ctx;
if (select_ctx->withass != NULL) {
OG_RETURN_IFERR(sql_verify_withas_ctx(verif->stmt, select_ctx->withass));
}
OG_RETURN_IFERR(sql_verify_select_node(verif, select_ctx->root));
sql_set_query_rs_datatype(select_ctx->rs_columns, select_ctx->root);
sql_record_pending_column(select_ctx);
OG_RETURN_IFERR(sql_verify_select_order(verif, select_ctx));
sql_try_optmz_select_type(verif, select_ctx);
return OG_SUCCESS;
}
status_t sql_verify_sub_select(sql_stmt_t *stmt, sql_select_t *select_ctx, sql_verifier_t *parent)
{
sql_verifier_t verif = { 0 };
verif.stmt = stmt;
verif.context = stmt->context;
verif.select_ctx = select_ctx;
verif.pl_dc_lst = select_ctx->pl_dc_lst;
verif.for_update = select_ctx->for_update;
verif.excl_flags = SQL_EXCL_DEFAULT;
verif.do_expr_optmz = OG_TRUE;
verif.parent = parent;
#ifdef OG_RAC_ING
OG_RETURN_IFERR(shd_verfity_excl_user_function(&verif, stmt));
#endif
return sql_verify_select_context(&verif, select_ctx);
}
status_t sql_verify_select(sql_stmt_t *stmt, sql_select_t *select_ctx)
{
sql_verifier_t verif = { 0 };
verif.stmt = stmt;
verif.context = stmt->context;
verif.select_ctx = select_ctx;
verif.pl_dc_lst = select_ctx->pl_dc_lst;
verif.for_update = select_ctx->for_update;
verif.excl_flags = SQL_EXCL_DEFAULT;
verif.do_expr_optmz = OG_TRUE;
verif.parent = NULL;
plc_get_verify_obj(stmt, &verif);
#ifdef OG_RAC_ING
OG_RETURN_IFERR(shd_verfity_excl_user_function(&verif, stmt));
#endif
OG_RETURN_IFERR(sql_verify_select_context(&verif, select_ctx));
if ((verif.has_ddm_col == OG_TRUE) && (stmt->context->type == OGSQL_TYPE_CREATE_TABLE)) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", the command references a redacted object");
return OG_ERROR;
}
return OG_SUCCESS;
}
#ifdef __cplusplus
}
#endif