* 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_expr_verifier.c
*
*
* IDENTIFICATION
* src/ogsql/verifier/ogsql_expr_verifier.c
*
* -------------------------------------------------------------------------
*/
#include "ogsql_expr_verifier.h"
#include "ogsql_select_verifier.h"
#include "ogsql_table_verifier.h"
#include "ogsql_func.h"
#include "ogsql_package.h"
#include "srv_instance.h"
#include "pl_compiler.h"
#include "pl_executor.h"
#include "expr_parser.h"
#include "ogsql_winsort.h"
#include "pl_udt.h"
#include "decl_cl.h"
#include "ogsql_dependency.h"
#ifdef __cplusplus
extern "C" {
#endif
static text_t g_nextval = { "NEXTVAL", 7 };
static text_t g_currval = { "CURRVAL", 7 };
static text_t g_rowid = { "ROWID", 5 };
static text_t g_rowscn = { "ROWSCN", 6 };
static bool32 reserved_has_single_column(expr_node_t *node)
{
switch (VALUE(int32, &node->value)) {
case RES_WORD_ROWID:
return ROWID_NODE_ANCESTOR(node) == 0;
case RES_WORD_LEVEL:
case RES_WORD_ROWNUM:
case RES_WORD_CONNECT_BY_ISCYCLE:
case RES_WORD_CONNECT_BY_ISLEAF:
return OG_TRUE;
default:
return OG_FALSE;
}
}
static status_t check_single_column(visit_assist_t *visit_ass, expr_node_t **node)
{
if (visit_ass->result0) {
return OG_SUCCESS;
}
sql_select_t *slct_ctx = NULL;
switch ((*node)->type) {
case EXPR_NODE_COLUMN:
visit_ass->result0 = VAR_ANCESTOR(&(*node)->value) == 0;
break;
case EXPR_NODE_RESERVED:
visit_ass->result0 = reserved_has_single_column(*node);
break;
case EXPR_NODE_PRIOR:
visit_ass->result0 = OG_TRUE;
break;
case EXPR_NODE_SELECT:
slct_ctx = (sql_select_t *)((*node)->value.v_obj.ptr);
visit_ass->result0 = (slct_ctx->parent_refs != NULL && slct_ctx->parent_refs->count > 0);
break;
case EXPR_NODE_AGGR:
default:
break;
}
return OG_SUCCESS;
}
bool32 sql_check_has_single_column(sql_verifier_t *verif, expr_node_t *node)
{
visit_assist_t visit_ass;
sql_init_visit_assist(&visit_ass, NULL, NULL);
visit_ass.excl_flags = VA_EXCL_PRIOR;
visit_ass.param0 = (void *)verif;
visit_ass.result0 = OG_FALSE;
(void)visit_expr_node(&visit_ass, &node, check_single_column);
return visit_ass.result0;
}
static status_t check_table_column_exists(visit_assist_t *visit_ass, expr_node_t **node)
{
if (visit_ass->result0 == OG_TRUE) {
return OG_SUCCESS;
}
switch ((*node)->type) {
case EXPR_NODE_SELECT:
if (((sql_select_t *)(*node)->value.v_obj.ptr)->parent_refs->count > 0) {
visit_ass->result0 = OG_TRUE;
}
break;
case EXPR_NODE_COLUMN:
if (NODE_ANCESTOR(*node) == 0) {
visit_ass->result0 = OG_TRUE;
}
break;
case EXPR_NODE_RESERVED:
if (!sql_check_reserved_is_const(*node)) {
visit_ass->result0 = OG_TRUE;
}
break;
case EXPR_NODE_CONST:
case EXPR_NODE_PARAM:
case EXPR_NODE_V_ADDR:
case EXPR_NODE_PROC:
case EXPR_NODE_NEW_COL:
case EXPR_NODE_OLD_COL:
case EXPR_NODE_PL_ATTR:
break;
default:
visit_ass->result0 = OG_TRUE;
break;
}
return OG_SUCCESS;
}
bool32 sql_check_table_column_exists(sql_stmt_t *stmt, sql_query_t *query, expr_node_t *node)
{
visit_assist_t visit_ass;
sql_init_visit_assist(&visit_ass, stmt, query);
visit_ass.excl_flags = VA_EXCL_PRIOR;
visit_ass.result0 = OG_FALSE;
if (visit_expr_node(&visit_ass, &node, check_table_column_exists) == OG_SUCCESS && visit_ass.result0 == OG_FALSE) {
return OG_FALSE;
}
return OG_TRUE;
}
status_t sql_verify_expr_array_attr(expr_node_t *node, expr_tree_t *expr)
{
if (node->typmod.is_array == OG_TRUE && expr->root->typmod.is_array != OG_TRUE) {
if (!var_datatype_matched(OG_TYPE_ARRAY, expr->root->datatype)) {
OG_SRC_ERROR_MISMATCH(TREE_LOC(expr), OG_TYPE_ARRAY, expr->root->datatype);
return OG_ERROR;
}
}
if (node->typmod.is_array != OG_TRUE && expr->root->typmod.is_array == OG_TRUE) {
if (!var_datatype_matched(OG_TYPE_ARRAY, node->datatype)) {
OG_SRC_ERROR_MISMATCH(NODE_LOC(node), OG_TYPE_ARRAY, node->datatype);
return OG_ERROR;
}
node->typmod.is_array = OG_TRUE;
node->datatype = expr->root->datatype;
}
if (!var_datatype_matched(node->datatype, expr->root->datatype)) {
OG_SRC_ERROR_MISMATCH(TREE_LOC(expr), node->datatype, expr->root->datatype);
return OG_ERROR;
}
return OG_SUCCESS;
}
og_type_t sql_get_case_expr_compatible_datatype(og_type_t case_datatype, og_type_t expr_datatype)
{
if (!g_instance->sql.strict_case_datatype) {
if ((OG_IS_BINSTR_TYPE(case_datatype) && OG_IS_NUMERIC_TYPE(expr_datatype)) ||
(OG_IS_NUMERIC_TYPE(case_datatype) && OG_IS_BINSTR_TYPE(expr_datatype))) {
return (OG_IS_STRING_TYPE(case_datatype) || OG_IS_STRING_TYPE(expr_datatype)) ? OG_TYPE_STRING :
OG_TYPE_VARBINARY;
}
}
return get_cmp_datatype(case_datatype, expr_datatype);
}
static status_t sql_verify_update_case_expr_node(expr_node_t *node, expr_tree_t *expr, bool32 *is_null_value)
{
if (TREE_IS_RES_NULL(expr)) {
return OG_SUCCESS;
}
*is_null_value = OG_FALSE;
if (TREE_DATATYPE(expr) == OG_TYPE_UNKNOWN) {
return OG_SUCCESS;
}
if (node->datatype == OG_TYPE_UNKNOWN) {
node->datatype = expr->root->datatype;
node->precision = expr->root->precision;
node->scale = expr->root->scale;
node->typmod.is_array = expr->root->typmod.is_array;
} else {
if (node->typmod.is_array || expr->root->typmod.is_array) {
OG_RETURN_IFERR(sql_verify_expr_array_attr(node, expr));
} else if (!var_datatype_matched(node->datatype, expr->root->datatype)) {
OG_SRC_ERROR_MISMATCH(TREE_LOC(expr), node->datatype, expr->root->datatype);
return OG_ERROR;
}
og_type_t datatype = sql_get_case_expr_compatible_datatype(node->datatype, TREE_DATATYPE(expr));
if (datatype == INVALID_CMP_DATATYPE) {
OG_SET_ERROR_MISMATCH(node->datatype, TREE_DATATYPE(expr));
return OG_ERROR;
}
if (node->datatype != TREE_DATATYPE(expr) && node->typmod.is_array == expr->root->typmod.is_array) {
node->datatype = datatype;
} else if (expr->root->typmod.is_array) {
node->datatype = TREE_DATATYPE(expr);
node->typmod.is_array = expr->root->typmod.is_array;
}
}
uint32 size = cm_get_datatype_strlen(expr->root->datatype, expr->root->size);
size = MIN(expr->root->size, size);
node->size = MAX(node->size, size);
if (OG_IS_NUMBER_TYPE(node->datatype) &&
(expr->root->precision != node->precision || expr->root->scale != node->scale)) {
node->precision = OG_UNSPECIFIED_NUM_PREC;
node->scale = OG_UNSPECIFIED_NUM_SCALE;
} else {
node->precision = MAX(node->precision, expr->root->precision);
node->scale = MAX(node->scale, expr->root->scale);
}
return OG_SUCCESS;
}
static void og_case_node_optmz_mode(expr_node_t *exprn, const expr_node_t *case_exprn,
optmz_mode_t *opt_mode, bool32 *early_return)
{
*early_return = OG_FALSE;
*opt_mode = case_exprn->optmz_info.mode;
if (*opt_mode != OPTIMIZE_AS_CONST && *opt_mode != OPTIMIZE_AS_PARAM) {
SQL_SET_OPTMZ_MODE(exprn, OPTIMIZE_NONE);
*early_return = OG_TRUE;
}
}
static void sql_infer_case_when_optmz_mode(sql_verifier_t *verif, expr_node_t *node)
{
case_expr_t *case_expr = (case_expr_t *)node->value.v_pointer;
case_pair_t *case_pair = NULL;
optmz_mode_t mode = OPTMZ_INVAILD;
bool32 early_return = OG_FALSE;
optmz_mode_t tmp_opt_mode = OPTMZ_INVAILD;
if (case_expr->expr != NULL) {
og_case_node_optmz_mode(node, case_expr->expr->root, &tmp_opt_mode, &early_return);
OG_RETVOID_IFTRUE(early_return);
mode = tmp_opt_mode;
}
for (uint32 i = 0; i < case_expr->pairs.count; i++) {
case_pair = (case_pair_t *)cm_galist_get(&case_expr->pairs, i);
if (case_expr->is_cond) {
if (case_pair->when_cond->root->type != COND_NODE_TRUE &&
case_pair->when_cond->root->type != COND_NODE_FALSE) {
return;
}
} else {
og_case_node_optmz_mode(node, case_pair->when_expr->root, &tmp_opt_mode, &early_return);
OG_RETVOID_IFTRUE(early_return);
mode = MIN(mode, tmp_opt_mode);
}
og_case_node_optmz_mode(node, case_pair->value->root, &tmp_opt_mode, &early_return);
OG_RETVOID_IFTRUE(early_return);
mode = MIN(mode, tmp_opt_mode);
}
if (case_expr->default_expr != NULL) {
og_case_node_optmz_mode(node, case_expr->default_expr->root, &tmp_opt_mode, &early_return);
OG_RETVOID_IFTRUE(early_return);
mode = MIN(mode, tmp_opt_mode);
}
SQL_SET_OPTMZ_MODE(node, mode);
return;
}
static status_t sql_verify_case_expr(sql_verifier_t *verif, expr_node_t *node)
{
case_expr_t *case_expr = (case_expr_t *)node->value.v_pointer;
case_pair_t *case_pair = NULL;
bool32 is_null_value = OG_TRUE;
uint32 old_excl_flags = verif->excl_flags;
uint32 new_excl_flags = verif->excl_flags & (SQL_EXCL_LOB_COL ^ 0xffffffff);
node->size = 0;
node->datatype = OG_TYPE_UNKNOWN;
if (!case_expr->is_cond) {
verif->excl_flags = new_excl_flags;
OG_RETURN_IFERR(sql_verify_expr(verif, case_expr->expr));
verif->excl_flags = old_excl_flags;
}
bool32 has_unknown = OG_FALSE;
for (uint32 i = 0; i < case_expr->pairs.count; i++) {
verif->excl_flags = new_excl_flags;
case_pair = (case_pair_t *)cm_galist_get(&case_expr->pairs, i);
if (case_expr->is_cond) {
OG_RETURN_IFERR(sql_verify_cond(verif, case_pair->when_cond));
} else {
OG_RETURN_IFERR(sql_verify_expr(verif, case_pair->when_expr));
}
verif->excl_flags = old_excl_flags;
OG_RETURN_IFERR(sql_verify_expr(verif, case_pair->value));
OG_RETURN_IFERR(sql_verify_update_case_expr_node(node, case_pair->value, &is_null_value));
has_unknown |= OG_IS_UNKNOWN_TYPE(TREE_DATATYPE(case_pair->value));
}
if (case_expr->default_expr != NULL) {
OG_RETURN_IFERR(sql_verify_expr(verif, case_expr->default_expr));
OG_RETURN_IFERR(sql_verify_update_case_expr_node(node, case_expr->default_expr, &is_null_value));
has_unknown |= OG_IS_UNKNOWN_TYPE(TREE_DATATYPE(case_expr->default_expr));
}
if (is_null_value) {
node->datatype = OG_DATATYPE_OF_NULL;
node->size = OG_SIZE_OF_NULL;
}
if (OG_IS_NUMERIC_TYPE(node->datatype) && node->datatype != OG_TYPE_REAL && has_unknown) {
node->precision = OG_UNSPECIFIED_NUM_PREC;
node->scale = OG_UNSPECIFIED_NUM_SCALE;
node->datatype = OG_TYPE_NUMBER;
}
sql_infer_case_when_optmz_mode(verif, node);
return sql_try_optimize_const_expr(verif->stmt, node);
}
status_t sql_gen_winsort_rs_column(sql_stmt_t *stmt, sql_query_t *query, rs_column_t *rs_column);
static inline status_t sql_append_rowid_rs_column(sql_verifier_t *verif, sql_query_t *subquery, expr_node_t *rid_node)
{
rs_column_t *rs_col = NULL;
OG_RETURN_IFERR(cm_galist_new(subquery->rs_columns, sizeof(rs_column_t), (pointer_t *)&rs_col));
OG_RETURN_IFERR(sql_alloc_mem(verif->stmt->context, sizeof(expr_tree_t), (void **)&rs_col->expr));
rs_col->name = g_rowid;
rs_col->expr->owner = verif->stmt->context;
rs_col->expr->root = rid_node;
rs_col->typmod = rid_node->typmod;
rs_col->type = RS_COL_CALC;
OG_BIT_RESET(rs_col->rs_flag, RS_EXIST_ALIAS);
if (subquery->winsort_list->count > 0) {
sql_query_t *curr_query = verif->curr_query;
verif->curr_query = subquery;
OG_RETURN_IFERR(sql_gen_winsort_rs_column(verif->stmt, verif->curr_query, rs_col));
verif->curr_query = curr_query;
}
return OG_SUCCESS;
}
void sql_make_rowid_column_node(expr_node_t *node, uint32 col_id, uint32 tab_id, uint32 ancestor)
{
node->type = EXPR_NODE_COLUMN;
node->value.v_col.col = col_id;
node->value.v_col.tab = tab_id;
node->value.v_col.ancestor = ancestor;
node->value.v_col.datatype = OG_TYPE_STRING;
node->value.v_col.is_rowid = OG_TRUE;
}
static inline status_t sql_find_rowid_in_query(sql_table_t *table, sql_query_t *query, expr_node_t *node,
uint32 ancestor, bool32 *has_rowid_column)
{
rs_column_t *rs_col = NULL;
expr_node_t *col_node = NULL;
uint32 i;
for (i = 0; i < query->rs_columns->count; i++) {
rs_col = (rs_column_t *)cm_galist_get(query->rs_columns, i);
if (!OG_BIT_TEST(rs_col->rs_flag, RS_EXIST_ALIAS) && cm_text_equal(&rs_col->name, &g_rowid)) {
sql_make_rowid_column_node(node, i, table->id, ancestor);
*has_rowid_column = OG_TRUE;
continue;
}
if (rs_col->type == RS_COL_COLUMN) {
if (rs_col->v_col.is_rowid == OG_TRUE) {
sql_make_rowid_column_node(node, i, table->id, ancestor);
*has_rowid_column = OG_TRUE;
}
continue;
}
col_node = rs_col->expr->root;
if (col_node->type == EXPR_NODE_RESERVED) {
if (col_node->value.v_res.res_id == RES_WORD_ROWNUM) {
OG_SRC_THROW_ERROR(node->loc, ERR_SELECT_ROWID);
return OG_ERROR;
}
if (col_node->value.v_res.res_id == RES_WORD_ROWID) {
sql_make_rowid_column_node(node, i, table->id, ancestor);
*has_rowid_column = OG_TRUE;
}
}
}
return OG_SUCCESS;
}
static status_t sql_verify_table_rowid(sql_verifier_t *verif, sql_table_t *table, expr_node_t *node, uint32 ancestor);
static inline status_t sql_verify_subselect_rowid(sql_verifier_t *verif, expr_node_t *node, sql_table_t *table,
uint32 ancestor)
{
query_field_t query_field;
sql_query_t *query = NULL;
sql_table_t *sub_table = NULL;
bool32 has_rowid_column = OG_FALSE;
expr_node_t *rid_node = NULL;
uint32 col_id;
if (table->select_ctx->root->type != SELECT_NODE_QUERY) {
OG_SRC_THROW_ERROR(node->loc, ERR_SELECT_ROWID);
return OG_ERROR;
}
query = table->select_ctx->root->query;
if (query->group_sets->count > 0 || query->aggrs->count > 0) {
OG_SRC_THROW_ERROR(node->loc, ERR_SELECT_ROWID);
return OG_ERROR;
}
OG_RETURN_IFERR(sql_find_rowid_in_query(table, query, node, ancestor, &has_rowid_column));
if (has_rowid_column) {
return OG_SUCCESS;
}
if (query->has_distinct || query->tables.count > 1) {
OG_SRC_THROW_ERROR(node->loc, ERR_SELECT_ROWID);
return OG_ERROR;
}
sub_table = (sql_table_t *)sql_array_get(&query->tables, 0);
OG_RETURN_IFERR(sql_alloc_mem(verif->stmt->context, sizeof(expr_node_t), (void **)&rid_node));
rid_node->loc = node->loc;
rid_node->type = EXPR_NODE_RESERVED;
rid_node->datatype = OG_TYPE_STRING;
rid_node->size = ROWID_LENGTH;
rid_node->value.type = OG_TYPE_INTEGER;
rid_node->value.v_rid.res_id = RES_WORD_ROWID;
OG_RETURN_IFERR(sql_verify_table_rowid(verif, sub_table, rid_node, 0));
LOC_RETURN_IFERR(sql_append_rowid_rs_column(verif, query, rid_node), node->loc);
col_id = query->rs_columns->count - 1;
SQL_SET_QUERY_FIELD_INFO(&query_field, OG_TYPE_STRING, col_id, OG_FALSE, OG_INVALID_ID32, OG_INVALID_ID32);
LOC_RETURN_IFERR(sql_table_cache_query_field(verif->stmt, table, &query_field), node->loc);
sql_make_rowid_column_node(node, col_id, table->id, ancestor);
return OG_SUCCESS;
}
static status_t sql_verify_table_rowid(sql_verifier_t *verif, sql_table_t *table, expr_node_t *node, uint32 ancestor)
{
if (ancestor > 0) {
verif->has_acstor_col = OG_TRUE;
}
switch (table->type) {
case NORMAL_TABLE:
node->value.v_rid.tab_id = table->id;
node->value.v_rid.ancestor = ancestor;
table->rowid_exists = OG_TRUE;
return OG_SUCCESS;
case VIEW_AS_TABLE:
case SUBSELECT_AS_TABLE:
case WITH_AS_TABLE:
return sql_verify_subselect_rowid(verif, node, table, ancestor);
default:
OG_SRC_THROW_ERROR(node->loc, ERR_SELECT_ROWID);
return OG_ERROR;
}
}
static inline void sql_make_rownodeid_column_node(expr_node_t *node, uint32 col_id, uint32 tab_id, uint32 ancestor)
{
node->type = EXPR_NODE_COLUMN;
node->value.v_col.col = col_id;
node->value.v_col.tab = tab_id;
node->value.v_col.ancestor = ancestor;
node->value.v_col.datatype = OG_TYPE_UINT32;
node->value.v_col.is_rownodeid = OG_TRUE;
}
static status_t sql_verify_rowid(sql_verifier_t *verif, expr_node_t *node)
{
uint32 ancestor = 0;
column_word_t *col = NULL;
sql_table_t *table = NULL;
if (verif->excl_flags & SQL_EXCL_ROWID) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected rowid occurs");
return OG_ERROR;
}
verif->incl_flags |= SQL_INCL_ROWID;
col = &node->word.column;
node->datatype = OG_TYPE_STRING;
node->size = ROWID_LENGTH;
if (col->table.len == 0) {
if (verif->tables == NULL) {
table = verif->table;
} else {
if (verif->tables->count > 1) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "rowid ambiguously defined at");
return OG_ERROR;
}
table = (sql_table_t *)sql_array_get(verif->tables, 0);
}
return sql_verify_table_rowid(verif, table, node, 0);
}
if (sql_search_table(verif, node, (text_t *)&col->user, (text_t *)&col->table, &table, &ancestor) != OG_SUCCESS) {
return OG_ERROR;
}
return sql_verify_table_rowid(verif, table, node, ancestor);
}
static inline status_t sql_verify_rowscn(sql_verifier_t *verif, expr_node_t *node)
{
uint32 level = 0;
column_word_t *col = NULL;
sql_table_t *table = NULL;
if (verif->excl_flags & SQL_EXCL_ROWSCN) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected rowscn occurs");
return OG_ERROR;
}
col = &node->word.column;
node->datatype = OG_TYPE_BIGINT;
node->size = sizeof(int64);
if (col->table.len == 0) {
if (verif->tables == NULL) {
table = verif->table;
} else {
if (verif->tables->count > 1) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "rowscn ambiguously defined at");
return OG_ERROR;
}
table = (sql_table_t *)sql_array_get(verif->tables, 0);
}
node->value.v_rid.tab_id = 0;
if (table->type != NORMAL_TABLE) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "Unable to use clause to select ROWSCN from view.");
return OG_ERROR;
}
return OG_SUCCESS;
}
if (sql_search_table(verif, node, (text_t *)&col->user, (text_t *)&col->table, &table, &level) != OG_SUCCESS) {
return OG_ERROR;
}
node->value.v_rid.tab_id = table->id;
node->value.v_rid.ancestor = level;
if (table->type != NORMAL_TABLE) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "Unable to use clause to select ROWSCN from view.");
return OG_ERROR;
}
return OG_SUCCESS;
}
static inline status_t sql_verify_trig_res(sql_verifier_t *verif, expr_node_t *node)
{
if (verif->context == NULL || verif->context->type != OGSQL_TYPE_CREATE_TRIG) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR,
"'DELETING' or 'UPDATING' or 'INSERTING' must be in a trigger");
return OG_ERROR;
}
node->datatype = OG_TYPE_BOOLEAN;
node->size = sizeof(bool32);
node->optmz_info.mode = OPTIMIZE_NONE;
return OG_SUCCESS;
}
static status_t sql_verify_connect_pseudocolumn(sql_verifier_t *verif, expr_node_t *node, uint32 excl_flag)
{
if (verif->curr_query == NULL || verif->curr_query->connect_by_cond == NULL) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "CONNECT BY clause required in this query block");
return OG_ERROR;
}
if (verif->excl_flags & excl_flag) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "CONNECT BY pseudocolumn not allowed here");
return OG_ERROR;
}
verif->incl_flags |= SQL_INCL_CONNECTBY_ATTR;
node->datatype = OG_TYPE_INTEGER;
node->size = sizeof(int32);
return OG_SUCCESS;
}
* node->value->rowid */
static inline status_t sql_verify_reserved_value(sql_verifier_t *verif, expr_node_t *node)
{
status_t status = OG_SUCCESS;
switch (VALUE(uint32, &node->value)) {
case RES_WORD_ROWNUM:
if (verif->excl_flags & SQL_EXCL_ROWNUM) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected rownum occurs");
return OG_ERROR;
}
if (verif->curr_query != NULL) {
verif->curr_query->incl_flags |=
verif->incl_flags & SQL_INCL_COND_COL ? COND_INCL_ROWNUM : EXPR_INCL_ROWNUM;
}
node->datatype = OG_TYPE_INTEGER;
node->size = OG_BIGINT_SIZE;
verif->incl_flags |= SQL_INCL_ROWNUM;
break;
case RES_WORD_ROWID:
status = sql_verify_rowid(verif, node);
break;
case RES_WORD_ROWSCN:
node->datatype = OG_TYPE_BIGINT;
node->size = sizeof(int64);
status = sql_verify_rowscn(verif, node);
break;
case RES_WORD_CURDATE:
node->datatype = OG_TYPE_DATE;
node->size = sizeof(date_t);
sql_add_first_exec_node(verif, node);
break;
case RES_WORD_SYSDATE:
node->datatype = OG_TYPE_DATE;
node->size = sizeof(date_t);
sql_add_first_exec_node(verif, node);
break;
case RES_WORD_CURTIMESTAMP:
if (verif->stmt->session->call_version >= CS_VERSION_8) {
node->datatype = OG_TYPE_TIMESTAMP_TZ;
node->size = sizeof(timestamp_tz_t);
} else {
node->datatype = OG_TYPE_TIMESTAMP_TZ_FAKE;
node->size = sizeof(timestamp_t);
}
node->precision = OG_DEFAULT_DATETIME_PRECISION;
sql_add_first_exec_node(verif, node);
break;
case RES_WORD_SYSTIMESTAMP:
if (verif->stmt->session->call_version >= CS_VERSION_8) {
node->datatype = OG_TYPE_TIMESTAMP_TZ;
node->size = sizeof(timestamp_tz_t);
} else {
node->datatype = OG_TYPE_TIMESTAMP_TZ_FAKE;
node->size = sizeof(timestamp_t);
}
node->precision = OG_DEFAULT_DATETIME_PRECISION;
sql_add_first_exec_node(verif, node);
break;
case RES_WORD_LOCALTIMESTAMP:
node->datatype = OG_TYPE_TIMESTAMP;
node->size = sizeof(timestamp_t);
node->precision = OG_DEFAULT_DATETIME_PRECISION;
sql_add_first_exec_node(verif, node);
break;
case RES_WORD_UTCTIMESTAMP:
node->datatype = OG_TYPE_DATE;
node->size = sizeof(timestamp_t);
sql_add_first_exec_node(verif, node);
break;
case RES_WORD_DEFAULT:
if (verif->excl_flags & SQL_EXCL_DEFAULT) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected DEFAULT occurs");
return OG_ERROR;
}
node->datatype = OG_TYPE_UNKNOWN;
node->size = 0;
break;
case RES_WORD_NULL:
if (node->owner->root->type == EXPR_NODE_NEGATIVE) {
node->datatype = OG_TYPE_NUMBER;
} else {
node->datatype = OG_DATATYPE_OF_NULL;
}
node->size = OG_SIZE_OF_NULL;
node->optmz_info.mode = OPTIMIZE_AS_CONST;
break;
case RES_WORD_TRUE:
case RES_WORD_FALSE:
node->datatype = OG_TYPE_BOOLEAN;
node->size = sizeof(bool32);
node->optmz_info.mode = OPTIMIZE_AS_CONST;
break;
case RES_WORD_DELETING:
case RES_WORD_INSERTING:
case RES_WORD_UPDATING:
status = sql_verify_trig_res(verif, node);
break;
case RES_WORD_LEVEL:
status = sql_verify_connect_pseudocolumn(verif, node, SQL_EXCL_LEVEL);
break;
case RES_WORD_CONNECT_BY_ISLEAF:
status = sql_verify_connect_pseudocolumn(verif, node, SQL_EXCL_CONNECTBY_ATTR);
break;
case RES_WORD_CONNECT_BY_ISCYCLE:
OG_RETURN_IFERR(sql_verify_connect_pseudocolumn(verif, node, SQL_EXCL_CONNECTBY_ATTR));
if (!verif->curr_query->connect_by_nocycle) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR,
"NOCYCLE keyword is required with CONNECT_BY_ISCYCLE pseudocolumn");
return OG_ERROR;
}
verif->curr_query->connect_by_iscycle = OG_TRUE;
break;
case RES_WORD_USER:
node->datatype = OG_TYPE_STRING;
node->size = OG_NAME_BUFFER_SIZE;
break;
case RES_WORD_DATABASETZ:
node->datatype = OG_TYPE_STRING;
node->size = TIMEZONE_OFFSET_STRLEN;
break;
case RES_WORD_SESSIONTZ:
node->datatype = OG_TYPE_STRING;
node->size = TIMEZONE_OFFSET_STRLEN;
break;
case RES_WORD_COLUMN_VALUE:
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "invalid column name 'column_value'");
return OG_ERROR;
default:
break;
}
return status;
}
static inline status_t sql_verify_oper_node(sql_verifier_t *verif, expr_node_t *node)
{
if (sql_verify_expr_node(verif, node->left) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_verify_expr_node(verif, node->right) != OG_SUCCESS) {
return OG_ERROR;
}
sql_infer_oper_optmz_mode(verif, node);
return OG_SUCCESS;
}
static inline status_t sql_verify_unary_oper_node(sql_verifier_t *verif, expr_node_t *node)
{
if (node->right == NULL) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "missing expression");
return OG_ERROR;
}
if (sql_verify_expr_node(verif, node->right) != OG_SUCCESS) {
return OG_ERROR;
}
sql_infer_unary_oper_optmz_mode(verif, node);
return OG_SUCCESS;
}
static inline status_t sql_verify_prior_node(sql_verifier_t *verif, expr_node_t *node)
{
if (verif->excl_flags & SQL_EXCL_PRIOR) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "'prior' operator not allowed here");
return OG_ERROR;
}
if (verif->curr_query == NULL || verif->curr_query->connect_by_cond == NULL) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "If there is no 'connect by', 'prior' is not allowed");
return OG_ERROR;
}
if (node->right == NULL) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "missing expression");
return OG_ERROR;
}
uint32 saved_flags = verif->excl_flags;
verif->excl_flags |= SQL_PRIOR_EXCL;
if (sql_verify_expr_node(verif, node->right) != OG_SUCCESS) {
return OG_ERROR;
}
verif->excl_flags = saved_flags;
verif->curr_query->connect_by_prior = OG_TRUE;
SQL_SET_OPTMZ_MODE(node, OPTIMIZE_NONE);
node->typmod = node->right->typmod;
return OG_SUCCESS;
}
static inline status_t sql_verify_cat(sql_verifier_t *verif, expr_node_t *node)
{
uint32 concat_len;
if (sql_verify_expr_node(verif, node->left) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_verify_expr_node(verif, node->right) != OG_SUCCESS) {
return OG_ERROR;
}
if (OG_IS_BLOB_TYPE(NODE_DATATYPE(node->left)) || OG_IS_BLOB_TYPE(NODE_DATATYPE(node->right))) {
OPR_THROW_ERROR("||", NODE_DATATYPE(node->left), NODE_DATATYPE(node->right));
return OG_ERROR;
}
if (OG_IS_CLOB_TYPE(NODE_DATATYPE(node->left)) || OG_IS_CLOB_TYPE(NODE_DATATYPE(node->right))) {
node->datatype = OG_TYPE_CLOB;
} else {
node->datatype = OG_TYPE_STRING;
}
sql_infer_oper_optmz_mode(verif, node);
concat_len = cm_get_datatype_strlen(node->left->datatype, node->left->size) +
cm_get_datatype_strlen(node->right->datatype, node->right->size);
node->size = (uint16)MIN(concat_len, OG_MAX_STRING_LEN);
node->typmod.is_char = node->left->typmod.is_char || node->right->typmod.is_char;
if (NODE_IS_OPTMZ_CONST(node)) {
if (node->size > SQL_MAX_OPTMZ_CONCAT_LEN) {
sql_add_first_exec_node(verif, node);
}
} else if (NODE_IS_FIRST_EXECUTABLE(node)) {
verif->context->fexec_vars_bytes += node->size;
}
return OG_SUCCESS;
}
static status_t sql_verify_select_expr(sql_verifier_t *verif, expr_node_t *node)
{
sql_select_t *select_ctx = (sql_select_t *)node->value.v_obj.ptr;
rs_column_t *rs_column = NULL;
if (verif->excl_flags & SQL_EXCL_SUBSELECT) {
OG_SRC_THROW_ERROR(node->loc, ERR_UNEXPECTED_KEY, "SUBSELECT");
return OG_ERROR;
}
if (sql_verify_sub_select(verif->stmt, select_ctx, verif) != OG_SUCCESS) {
return OG_ERROR;
}
rs_column = (rs_column_t *)cm_galist_get(select_ctx->first_query->rs_columns, 0);
node->typmod = rs_column->typmod;
if (select_ctx->has_ancestor == 0 && select_ctx->type == SELECT_AS_VARIANT) {
sql_add_first_exec_node(verif, node);
}
return OG_SUCCESS;
}
static void sql_infer_neg_type(og_type_t right_type, og_type_t *result)
{
switch (right_type) {
case OG_TYPE_UINT32:
case OG_TYPE_INTEGER:
case OG_TYPE_BIGINT:
case OG_TYPE_UINT64:
*result = OG_TYPE_BIGINT;
break;
case OG_TYPE_REAL:
case OG_TYPE_FLOAT:
*result = OG_TYPE_REAL;
break;
case OG_TYPE_NUMBER:
case OG_TYPE_DECIMAL:
case OG_TYPE_CHAR:
case OG_TYPE_VARCHAR:
case OG_TYPE_STRING:
case OG_TYPE_BINARY:
case OG_TYPE_VARBINARY:
*result = OG_TYPE_NUMBER;
break;
case OG_TYPE_NUMBER2:
*result = OG_TYPE_NUMBER2;
break;
default:
*result = right_type;
break;
}
return;
}
static status_t sql_adjust_node_datatype(sql_verifier_t *verif, expr_node_t *node)
{
if (node->type == EXPR_NODE_NEGATIVE) {
sql_infer_neg_type(node->right->datatype, &node->datatype);
node->typmod.is_array = node->right->typmod.is_array;
} else {
if (opr_infer_type((operator_type_t)node->type, node->left->datatype, node->right->datatype, &node->datatype) !=
OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t sql_adjust_oper_node(sql_verifier_t *verif, expr_node_t *node)
{
OG_RETURN_IFERR(sql_adjust_node_datatype(verif, node));
switch (node->datatype) {
case OG_TYPE_UINT32:
case OG_TYPE_INTEGER:
case OG_TYPE_BOOLEAN:
node->size = sizeof(int32);
break;
case OG_TYPE_UINT64:
case OG_TYPE_BIGINT:
case OG_TYPE_REAL:
node->size = sizeof(int64);
break;
case OG_TYPE_NUMBER:
case OG_TYPE_DECIMAL:
case OG_TYPE_NUMBER2:
node->size = OG_MAX_DEC_OUTPUT_ALL_PREC;
break;
case OG_TYPE_DATE:
case OG_TYPE_TIMESTAMP:
case OG_TYPE_TIMESTAMP_TZ_FAKE:
case OG_TYPE_TIMESTAMP_LTZ:
node->size = sizeof(timestamp_t);
node->precision = OG_MAX_DATETIME_PRECISION;
break;
case OG_TYPE_TIMESTAMP_TZ:
node->size = sizeof(timestamp_tz_t);
node->precision = OG_MAX_DATETIME_PRECISION;
break;
case OG_TYPE_INTERVAL_DS:
node->size = sizeof(interval_ds_t);
node->typmod.day_prec = ITVL_MAX_DAY_PREC;
node->typmod.frac_prec = ITVL_MAX_SECOND_PREC;
break;
case OG_TYPE_INTERVAL_YM:
node->size = sizeof(interval_ym_t);
node->typmod.year_prec = ITVL_MAX_YEAR_PREC;
break;
case OG_TYPE_BINARY:
case OG_TYPE_VARBINARY:
case OG_TYPE_CHAR:
case OG_TYPE_VARCHAR:
case OG_TYPE_STRING:
case OG_TYPE_UNKNOWN:
break;
default:
OG_THROW_ERROR(ERR_CONVERT_TYPE, get_datatype_name_str((int32)node->datatype), "NUMERIC");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t sql_verify_windowing_expr_type(winsort_args_t *win_args, expr_tree_t *expr, bool32 is_range)
{
if (is_range) {
if (win_args->sort_items->count > 1) {
OG_SRC_THROW_ERROR_EX(expr->loc, ERR_SQL_SYNTAX_ERROR,
"only one expression is allowed when RANGE value is specified in windowing clause");
return OG_ERROR;
}
sort_item_t *sort_item = (sort_item_t *)cm_galist_get(win_args->sort_items, 0);
if (OG_IS_DATETIME_TYPE(sort_item->expr->root->datatype)) {
if (OG_IS_DSITVL_TYPE(expr->root->datatype) || OG_IS_YMITVL_TYPE(expr->root->datatype)) {
return OG_SUCCESS;
}
} else if (!OG_IS_NUMERIC_TYPE(sort_item->expr->root->datatype)) {
OG_SRC_THROW_ERROR(expr->loc, ERR_INVALID_DATA_TYPE, "order by expression when RANGE is specified");
return OG_ERROR;
}
}
if (TREE_IS_CONST(expr)) {
if (expr->root->value.is_null) {
OG_SRC_THROW_ERROR_EX(expr->loc, ERR_SQL_SYNTAX_ERROR, "windowing border value cannot be NULL");
return OG_ERROR;
}
OG_RETURN_IFERR(var_as_num(&expr->root->value));
if (var_is_negative(&expr->root->value)) {
OG_SRC_THROW_ERROR_EX(expr->loc, ERR_SQL_SYNTAX_ERROR, "windowing border value cannot be negative");
return OG_ERROR;
}
} else if (TREE_IS_RES_NULL(expr)) {
OG_SRC_THROW_ERROR_EX(expr->loc, ERR_SQL_SYNTAX_ERROR, "windowing border value cannot be NULL");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t sql_verify_windowing_exprs(sql_verifier_t *verif, expr_node_t *winsort)
{
windowing_args_t *args = winsort->win_args->windowing;
verif->excl_flags |= SQL_EXCL_ROWID | SQL_EXCL_ROWSCN;
OG_RETURN_IFERR(sql_verify_expr(verif, args->l_expr));
OG_RETURN_IFERR(sql_verify_expr(verif, args->r_expr));
if (args->l_expr != NULL) {
OG_RETURN_IFERR(sql_verify_windowing_expr_type(winsort->win_args, args->l_expr, args->is_range));
if (!TREE_IS_CONST(args->l_expr)) {
winsort->win_args->sort_columns++;
}
}
if (args->r_expr != NULL) {
OG_RETURN_IFERR(sql_verify_windowing_expr_type(winsort->win_args, args->r_expr, args->is_range));
if (!TREE_IS_CONST(args->r_expr)) {
winsort->win_args->sort_columns++;
}
}
return OG_SUCCESS;
}
static status_t sql_verify_windowing_clause(sql_verifier_t *verif, expr_node_t *winsort)
{
windowing_args_t *args = winsort->win_args->windowing;
if (args->l_type > args->r_type) {
OG_SRC_THROW_ERROR_EX(winsort->argument->root->loc, ERR_SQL_SYNTAX_ERROR,
"left border must be less than right border in windowing clause");
return OG_ERROR;
}
if (args->r_type == WB_TYPE_UNBOUNDED_PRECED) {
OG_SRC_THROW_ERROR_EX(winsort->argument->root->loc, ERR_SQL_SYNTAX_ERROR,
"UNBOUNED PRECEDING cannot be the right border in windowing clause");
return OG_ERROR;
}
if (args->l_type == WB_TYPE_UNBOUNDED_FOLLOW) {
OG_SRC_THROW_ERROR_EX(winsort->argument->root->loc, ERR_SQL_SYNTAX_ERROR,
"UNBOUNED FOLLOWING cannot be the left border in windowing clause");
return OG_ERROR;
}
OG_RETURN_IFERR(sql_verify_windowing_exprs(verif, winsort));
if (args->l_type != args->r_type) {
if (args->l_expr != NULL && TREE_IS_CONST(args->l_expr) && var_is_zero(&args->l_expr->root->value)) {
args->l_expr = NULL;
args->l_type = WB_TYPE_CURRENT_ROW;
}
if (args->r_expr != NULL && TREE_IS_CONST(args->r_expr) && var_is_zero(&args->r_expr->root->value)) {
args->r_expr = NULL;
args->r_type = WB_TYPE_CURRENT_ROW;
}
}
return OG_SUCCESS;
}
static status_t sql_verify_winsort(sql_verifier_t *verif, expr_node_t *node)
{
expr_tree_t *expr = NULL;
sort_item_t *item = NULL;
expr_node_t *func_node = node->argument->root;
winsort_func_t *func = NULL;
uint32 excl_flags = verif->excl_flags;
if (verif->excl_flags & SQL_EXCL_WIN_SORT) {
OG_SRC_THROW_ERROR(node->loc, ERR_UNEXPECTED_KEY, "windows sort analytic function");
return OG_ERROR;
}
OG_BIT_SET(verif->incl_flags, SQL_INCL_WINSORT);
OG_BIT_SET(verif->excl_flags, SQL_EXCL_WIN_SORT | SQL_EXCL_SEQUENCE | SQL_EXCL_STAR);
OG_RETURN_IFERR(cm_galist_insert(verif->curr_query->winsort_list, node));
if (node->win_args->group_exprs != NULL) {
for (uint32 i = 0; i < node->win_args->group_exprs->count; i++) {
expr = (expr_tree_t *)cm_galist_get(node->win_args->group_exprs, i);
OG_RETURN_IFERR(sql_verify_expr(verif, expr));
if (expr->root->type == EXPR_NODE_ARRAY || expr->root->typmod.is_array) {
OG_SRC_THROW_ERROR(expr->loc, ERR_INVALID_DATA_TYPE, "comparision");
return OG_ERROR;
}
node->win_args->sort_columns++;
}
}
if (node->win_args->sort_items != NULL) {
if (func_node->dis_info.need_distinct) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "ORDER BY not allowed OVER function, when has DISTINCT");
return OG_ERROR;
}
for (uint32 i = 0; i < node->win_args->sort_items->count; i++) {
item = (sort_item_t *)cm_galist_get(node->win_args->sort_items, i);
OG_RETURN_IFERR(sql_verify_expr(verif, item->expr));
if (item->expr->root->type == EXPR_NODE_ARRAY || item->expr->root->typmod.is_array) {
OG_SRC_THROW_ERROR(item->expr->loc, ERR_INVALID_DATA_TYPE, "comparision");
return OG_ERROR;
}
node->win_args->sort_columns++;
}
if (node->win_args->windowing != NULL) {
OG_RETURN_IFERR(sql_verify_windowing_clause(verif, node));
}
}
OG_RETURN_IFERR(sql_get_winsort_func_id(&func_node->word.func.name, &func_node->value.v_func));
func = sql_get_winsort_func(&func_node->value.v_func);
OG_RETURN_IFERR(func->verify(verif, node));
verif->excl_flags = excl_flags;
return OG_SUCCESS;
}
static status_t sql_verify_array_type(expr_node_t *array_node, expr_node_t *expr_node)
{
typmode_t tmr;
uint32 max_str_size;
uint32 datatype_len;
og_type_t node_type = NODE_DATATYPE(expr_node);
og_type_t array_type = NODE_DATATYPE(array_node);
if (!cm_datatype_arrayable(node_type)) {
OG_SRC_THROW_ERROR(NODE_LOC(expr_node), ERR_DATATYPE_NOT_SUPPORT_ARRAY, get_datatype_name_str(node_type));
return OG_ERROR;
}
if (expr_node->typmod.is_array) {
OG_SRC_THROW_ERROR(NODE_LOC(expr_node), ERR_DATATYPE_NOT_SUPPORT_ARRAY, get_datatype_name_str(OG_TYPE_ARRAY));
return OG_ERROR;
}
if (NODE_IS_RES_NULL(expr_node)) {
return OG_SUCCESS;
}
if (array_type == OG_TYPE_UNKNOWN) {
NODE_TYPMODE(array_node) = NODE_TYPMODE(expr_node);
return OG_SUCCESS;
}
if (!var_datatype_matched(array_type, node_type)) {
OG_SRC_ERROR_MISMATCH(NODE_LOC(expr_node), array_type, node_type);
return OG_ERROR;
}
if (OG_IS_STRING_TYPE(array_type) && !OG_IS_STRING_TYPE(node_type)) {
datatype_len = cm_get_datatype_strlen(node_type, array_node->typmod.size);
max_str_size = MAX(datatype_len, array_node->typmod.size);
array_node->typmod.size = max_str_size;
return OG_SUCCESS;
}
if (!OG_IS_STRING_TYPE(array_type) && OG_IS_STRING_TYPE(node_type)) {
NODE_TYPMODE(array_node) = NODE_TYPMODE(expr_node);
datatype_len = cm_get_datatype_strlen(array_type, expr_node->typmod.size);
max_str_size = MAX(datatype_len, array_node->typmod.size);
array_node->typmod.size = max_str_size;
return OG_SUCCESS;
}
if (OG_IS_BOOLEAN_TYPE2(array_type, node_type)) {
return OG_SUCCESS;
}
if (cm_combine_typmode(NODE_TYPMODE(array_node), OG_FALSE, NODE_TYPMODE(expr_node), NODE_IS_VALUE_NULL(expr_node),
&tmr) != OG_SUCCESS) {
return OG_ERROR;
}
NODE_TYPMODE(array_node) = tmr;
return OG_SUCCESS;
}
static status_t sql_verify_array(sql_verifier_t *verif, expr_node_t *node)
{
expr_tree_t *expr = node->argument;
if (verif->excl_flags & SQL_EXCL_ARRAY) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected array expression");
return OG_ERROR;
}
verif->incl_flags |= SQL_INCL_ARRAY;
node->datatype = OG_TYPE_UNKNOWN;
while (expr != NULL) {
if (expr->root->type == EXPR_NODE_PARAM) {
OG_SRC_THROW_ERROR(expr->loc, ERR_SQL_SYNTAX_ERROR, "unexpected bind parameter in array");
return OG_ERROR;
}
if (sql_verify_expr_node(verif, expr->root) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_verify_array_type(node, expr->root) != OG_SUCCESS) {
return OG_ERROR;
}
expr = expr->next;
}
if (node->datatype == OG_TYPE_UNKNOWN) {
node->datatype = OG_TYPE_VARCHAR;
node->size = 0;
}
node->typmod.is_array = OG_TRUE;
return OG_SUCCESS;
}
static inline status_t sql_verify_connect_by_oper(sql_verifier_t *verif, expr_node_t *node)
{
if (node->unary == UNARY_OPER_ROOT) {
if (verif->curr_query == NULL || verif->curr_query->connect_by_cond == NULL) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "CONNECT BY clause required in this query block");
return OG_ERROR;
}
if (verif->excl_flags & SQL_EXCL_ROOT) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR,
"CONNECT BY ROOT operator"
" is not supported in the START WITH or in the CONNECT BY condition");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static inline status_t sql_verify_unary(sql_verifier_t *verif, expr_node_t *node)
{
if (node->type != EXPR_NODE_NEGATIVE) {
return OG_SUCCESS;
}
if (OG_IS_UNSIGNED_INTEGER_TYPE(node->datatype)) {
node->datatype = OG_TYPE_BIGINT;
return OG_SUCCESS;
}
if (OG_IS_NUMERIC_TYPE(node->datatype) || OG_IS_UNKNOWN_TYPE(node->datatype)) {
return OG_SUCCESS;
}
if (OG_IS_STRING_TYPE(node->datatype) || OG_IS_BINARY_TYPE(node->datatype)) {
node->datatype = OG_TYPE_NUMBER;
node->precision = OG_UNSPECIFIED_NUM_PREC;
node->scale = OG_UNSPECIFIED_NUM_SCALE;
node->size = MAX_DEC_BYTE_SZ;
return OG_SUCCESS;
}
OG_SRC_THROW_ERROR(node->loc, ERR_TYPE_MISMATCH, "NUMERIC", get_datatype_name_str((int32)(node->datatype)));
return OG_ERROR;
}
static inline status_t pl_check_forline_core(pl_line_for_t *line, plv_id_t vid, source_location_t loc)
{
if (PL_VID_EQUAL(line->id->vid, vid)) {
OG_SRC_THROW_ERROR(loc, ERR_PL_INVALID_LOOP_INDEX, T2S(&line->id->name));
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t pl_check_forline(pl_line_ctrl_t *line, plv_id_t vid, source_location_t loc)
{
if ((line != NULL) && (line->type == LINE_FOR)) {
return pl_check_forline_core((pl_line_for_t *)line, vid, loc);
}
return OG_SUCCESS;
}
static status_t pl_verify_expr_param_node(sql_verifier_t *verif, expr_node_t *node)
{
expr_node_t *input_node = NULL;
pl_compiler_t *compiler = (pl_compiler_t *)verif->stmt->pl_compiler;
if (compiler == NULL) {
node->datatype = OG_TYPE_UNKNOWN;
return OG_SUCCESS;
}
pl_line_ctrl_t *last_line = compiler->last_line;
input_node = plc_get_param_vid(compiler, VALUE(uint32, &node->value));
if (input_node == NULL) {
node->datatype = OG_TYPE_UNKNOWN;
return OG_SUCCESS;
}
var_address_pair_t *pair = sql_get_last_addr_pair(input_node);
if (pair == NULL) {
OG_THROW_ERROR(ERR_PLSQL_ILLEGAL_LINE_FMT, "unexpected param");
return OG_ERROR;
}
if (pair->type == UDT_STACK_ADDR) {
if ((pair->stack->decl->type == PLV_COLLECTION) && (verif->excl_flags & SQL_EXCL_COLL)) {
OG_THROW_ERROR(ERR_PL_NOT_ALLOW_COLL);
return OG_ERROR;
}
OG_RETURN_IFERR(pl_check_forline(last_line, pair->stack->decl->vid, node->loc));
} else {
OG_RETURN_IFERR(udt_get_addr_node_type(verif, input_node));
if ((input_node->datatype == OG_TYPE_COLLECTION) && (verif->excl_flags & SQL_EXCL_COLL)) {
OG_THROW_ERROR(ERR_PL_NOT_ALLOW_COLL);
return OG_ERROR;
}
}
node->datatype = OG_TYPE_UNKNOWN;
return OG_SUCCESS;
}
static status_t pl_verify_expr_in_fetch(sql_verifier_t *verif, expr_node_t *node)
{
uint32 param_id = VALUE(uint32, &node->value);
if (param_id >= verif->stmt->context->params->count) {
OG_SRC_THROW_ERROR(node->loc, ERR_INVALID_PARAMETER);
return OG_ERROR;
}
sql_param_t *param = &verif->stmt->param_info.params[param_id];
node->datatype = param->value.type;
node->size = var_get_size(¶m->value);
if (OG_IS_DATETIME_TYPE(param->value.type)) {
node->precision = OG_MAX_DATETIME_PRECISION;
node->scale = 0;
node->size = sizeof(timestamp_t);
} else if (OG_IS_NUMBER_TYPE(param->value.type)) {
node->precision = 0;
node->scale = 0;
node->size = sizeof(dec8_t);
}
return OG_SUCCESS;
}
static inline status_t sql_verify_column_nodetype(sql_verifier_t *verif, expr_node_t *node)
{
if ((verif->excl_flags & SQL_EXCL_ARRAY) && node->typmod.is_array == OG_TRUE) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected array expression");
return OG_ERROR;
}
if ((verif->excl_flags & SQL_EXCL_COLUMN) &&
(node->type == EXPR_NODE_COLUMN || node->type == EXPR_NODE_DIRECT_COLUMN)) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected column expression");
return OG_ERROR;
}
if ((verif->excl_flags & SQL_EXCL_AGGR) && node->type == EXPR_NODE_AGGR) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected aggr expression");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t sql_verify_pl_attr(sql_verifier_t *verif, expr_node_t *node)
{
switch (node->value.v_plattr.type) {
case PLV_ATTR_ISOPEN:
case PLV_ATTR_FOUND:
case PLV_ATTR_NOTFOUND:
node->datatype = OG_TYPE_BOOLEAN;
node->size = sizeof(bool32);
break;
case PLV_ATTR_ROWCOUNT:
node->datatype = OG_TYPE_INTEGER;
node->size = sizeof(bool32);
break;
default:
OG_THROW_ERROR(ERR_PL_INVALID_ATTR_FMT);
return OG_ERROR;
}
return OG_SUCCESS;
}
static inline status_t sql_verify_pl_decl(sql_verifier_t *verif, pl_compiler_t *compiler, plv_decl_t *decl,
expr_node_t *node, plv_id_t vid)
{
switch (decl->type) {
case PLV_VAR:
OG_RETURN_IFERR(pl_check_forline(compiler->last_line, vid, node->loc));
node->typmod = decl->variant.type;
break;
case PLV_ARRAY:
OG_RETURN_IFERR(pl_check_forline(compiler->last_line, vid, node->loc));
node->typmod = decl->array.type;
break;
case PLV_CUR:
if (decl->cursor.ogx != NULL && !decl->cursor.ogx->is_sysref) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected cursor type");
return OG_ERROR;
}
node->datatype = OG_TYPE_CURSOR;
break;
case PLV_RECORD:
node->datatype = OG_TYPE_RECORD;
node->udt_type = (void *)decl->record;
break;
case PLV_OBJECT:
node->datatype = OG_TYPE_OBJECT;
node->udt_type = (void *)decl->object;
break;
case PLV_COLLECTION:
node->datatype = OG_TYPE_COLLECTION;
node->udt_type = (void *)decl->collection;
break;
case PLV_PARAM:
if (verif->excl_flags & SQL_EXCL_BIND_PARAM) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected param occurs");
return OG_ERROR;
}
default:
node->datatype = OG_TYPE_UNKNOWN;
break;
}
return OG_SUCCESS;
}
static inline status_t sql_verify_pl_param(sql_verifier_t *verif, pl_compiler_t *compiler, plv_decl_t *decl,
expr_node_t *node)
{
pl_using_expr_t *using_expr = NULL;
if (verif->excl_flags & SQL_EXCL_BIND_PARAM) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected param occurs");
return OG_ERROR;
}
sql_stmt_t *parent = (sql_stmt_t *)compiler->stmt;
if (parent == NULL || (parent->plsql_mode != PLSQL_DYNSQL && parent->plsql_mode != PLSQL_DYNBLK)) {
node->datatype = OG_TYPE_UNKNOWN;
return OG_SUCCESS;
}
if (ple_get_dynsql_parent(compiler->stmt, &parent) != OG_SUCCESS) {
return OG_ERROR;
}
if (ple_get_dynsql_using_expr(parent, decl->pnid, &using_expr) != OG_SUCCESS) {
return OG_ERROR;
}
node->datatype = OG_TYPE_UNKNOWN;
return OG_SUCCESS;
}
status_t sql_verify_pl_var(sql_verifier_t *verif, plv_id_t vid, expr_node_t *node)
{
pl_compiler_t *compiler = (pl_compiler_t *)verif->stmt->pl_compiler;
plv_decl_t *decl = NULL;
OG_RETSUC_IFTRUE(compiler == NULL);
decl = plc_find_decl_by_id(compiler, vid);
OG_RETSUC_IFTRUE(decl == NULL);
return sql_verify_pl_decl(verif, compiler, decl, node, vid);
}
static status_t sql_verify_expr_node_core(sql_verifier_t *verif, expr_node_t *node)
{
status_t status;
CM_POINTER2(node, verif);
cm_reset_error_loc();
OG_RETURN_IFERR(sql_verify_connect_by_oper(verif, node));
switch (node->type) {
case EXPR_NODE_CONST:
node->datatype = node->value.type;
node->size = (uint16)var_get_size(&node->value);
node->optmz_info.mode = OPTIMIZE_AS_CONST;
if (OG_IS_STRING_TYPE(node->datatype)) {
node->typmod.is_char = OG_FALSE;
}
return OG_SUCCESS;
case EXPR_NODE_PARAM:
if ((verif->excl_flags & SQL_EXCL_BIND_PARAM) != 0) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected param occurs");
return OG_ERROR;
}
if (verif->incl_flags & SQL_INCL_COND_COL) {
verif->stmt->context->need_vpeek = OG_TRUE;
}
node->optmz_info.mode = OPTIMIZE_AS_PARAM;
if (verif->stmt->pl_compiler != NULL) {
return pl_verify_expr_param_node(verif, node);
}
if (verif->stmt->cursor_info.reverify_in_fetch) {
return pl_verify_expr_in_fetch(verif, node);
}
node->datatype = OG_TYPE_UNKNOWN;
return OG_SUCCESS;
case EXPR_NODE_RESERVED:
if (node->value.v_res.namable) {
cm_set_ignore_log(OG_TRUE);
if (sql_verify_column_expr(verif, node) == OG_SUCCESS) {
node->type = EXPR_NODE_COLUMN;
cm_set_ignore_log(OG_FALSE);
return OG_SUCCESS;
}
cm_set_ignore_log(OG_FALSE);
cm_reset_error();
node->value.type = OG_TYPE_INTEGER;
}
return sql_verify_reserved_value(verif, node);
case EXPR_NODE_COLUMN:
case EXPR_NODE_DIRECT_COLUMN:
OG_RETURN_IFERR(sql_verify_column_expr(verif, node));
status = sql_verify_column_nodetype(verif, node);
break;
case EXPR_NODE_CASE:
if ((verif->excl_flags & SQL_EXCL_CASE) != 0) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected case when occurs");
return OG_ERROR;
}
return sql_verify_case_expr(verif, node);
case EXPR_NODE_JOIN:
if (verif->excl_flags & SQL_EXCL_JOIN) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "invalid usage outer join symbol");
return OG_ERROR;
}
verif->incl_flags |= SQL_INCL_JOIN;
node->type = EXPR_NODE_COLUMN;
OG_RETURN_IFERR(sql_verify_column_expr(verif, node));
return sql_verify_column_nodetype(verif, node);
case EXPR_NODE_SELECT:
verif->incl_flags |= SQL_INCL_SUBSLCT;
return sql_verify_select_expr(verif, node);
case EXPR_NODE_CAT:
status = sql_verify_cat(verif, node);
break;
case EXPR_NODE_ADD:
case EXPR_NODE_SUB:
case EXPR_NODE_MUL:
case EXPR_NODE_DIV:
case EXPR_NODE_MOD: {
OG_RETURN_IFERR(sql_verify_oper_node(verif, node));
status = sql_adjust_oper_node(verif, node);
break;
}
case EXPR_NODE_NEGATIVE: {
OG_RETURN_IFERR(sql_verify_unary_oper_node(verif, node));
status = sql_adjust_oper_node(verif, node);
break;
}
case EXPR_NODE_PRIOR: {
status = sql_verify_prior_node(verif, node);
break;
}
case EXPR_NODE_BITAND:
case EXPR_NODE_BITOR:
case EXPR_NODE_BITXOR:
case EXPR_NODE_LSHIFT:
case EXPR_NODE_RSHIFT:
OG_RETURN_IFERR(sql_verify_oper_node(verif, node));
node->datatype = OG_TYPE_BIGINT;
node->size = sizeof(int64);
status = OG_SUCCESS;
break;
case EXPR_NODE_FUNC:
case EXPR_NODE_PROC:
case EXPR_NODE_USER_FUNC:
case EXPR_NODE_USER_PROC:
OG_RETURN_IFERR(sql_verify_func(verif, node));
status = sql_add_ref_func_node(verif, node);
break;
case EXPR_NODE_STAR:
if ((verif->excl_flags & SQL_EXCL_STAR) != 0) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected '*'");
return OG_ERROR;
}
status = OG_SUCCESS;
break;
case EXPR_NODE_AGGR:
case EXPR_NODE_GROUP:
return OG_SUCCESS;
case EXPR_NODE_V_ADDR:
return udt_verify_v_address(verif, node);
case EXPR_NODE_V_METHOD:
return udt_verify_v_method(verif, node);
case EXPR_NODE_V_CONSTRUCT:
return udt_verify_v_construct(verif, node);
case EXPR_NODE_PL_ATTR:
return sql_verify_pl_attr(verif, node);
case EXPR_NODE_OVER:
return sql_verify_winsort(verif, node);
case EXPR_NODE_ARRAY:
return sql_verify_array(verif, node);
default:
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unknown expr node type");
return OG_ERROR;
}
if (status != OG_SUCCESS) {
return OG_ERROR;
}
return sql_try_optimize_const_expr(verif->stmt, node);
}
status_t sql_verify_expr_node(sql_verifier_t *verif, expr_node_t *node)
{
if (node->has_verified) {
return OG_SUCCESS;
}
OG_RETURN_IFERR(sql_stack_safe(verif->stmt));
OG_RETURN_IFERR(sql_verify_expr_node_core(verif, node));
return sql_verify_unary(verif, node);
}
status_t sql_verify_current_expr(sql_verifier_t *verif, expr_tree_t *verf_expr)
{
if (sql_verify_expr_node(verif, verf_expr->root) != OG_SUCCESS) {
cm_try_set_error_loc(verf_expr->root->loc);
return OG_ERROR;
}
if ((OG_IS_LOB_TYPE(verf_expr->root->datatype)) && ((verif->excl_flags & SQL_EXCL_LOB_COL) != 0)) {
OG_SRC_THROW_ERROR(verf_expr->loc, ERR_SQL_SYNTAX_ERROR, "unexpected lob column occurs");
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t sql_verify_expr(sql_verifier_t *verif, expr_tree_t *expr)
{
expr_tree_t *verf_expr = expr;
while (verf_expr != NULL) {
OG_RETURN_IFERR(sql_verify_current_expr(verif, verf_expr));
verf_expr = verf_expr->next;
}
return OG_SUCCESS;
}
status_t sql_try_verify_dbmsconst(sql_verifier_t *verif, expr_node_t *node, bool32 *result)
{
sql_func_t *func = NULL;
var_func_t v;
column_word_t *col;
col = &node->word.column;
*result = OG_FALSE;
sql_convert_pack_func(&col->table.value, &col->name.value, &v);
if (v.func_id == OG_INVALID_ID32) {
return OG_SUCCESS;
}
func = sql_get_pack_func(&v);
OG_RETURN_IFERR(func->verify(verif, node));
node->type = EXPR_NODE_FUNC;
node->value.type = OG_TYPE_INTEGER;
node->value.v_func.pack_id = v.pack_id;
node->value.v_func.func_id = v.func_id;
node->value.v_func.orig_func_id = v.orig_func_id;
*result = OG_TRUE;
return OG_SUCCESS;
}
static status_t sql_append_dependency_sequences(sql_verifier_t *verif, expr_node_t *node)
{
object_address_t ref;
dc_sequence_t *sequence = NULL;
sequence_entry_t *entry = NULL;
int32 errcode;
if (verif->stmt->context->ref_objects != NULL) {
knl_dictionary_t dc_seq;
if (dc_seq_open(KNL_SESSION(verif->stmt), &node->value.v_seq.user, &node->value.v_seq.name, &dc_seq) ==
OG_SUCCESS) {
sequence = (dc_sequence_t *)dc_seq.handle;
entry = sequence->entry;
ref.tid = OBJ_TYPE_SEQUENCE;
ref.oid = dc_seq.oid;
ref.uid = dc_seq.uid;
ref.scn = entry->chg_scn;
errcode = strcpy_s(ref.name, OG_NAME_BUFFER_SIZE, entry->name);
dc_seq_close(&dc_seq);
MEMS_RETURN_IFERR(errcode);
if (!sql_check_ref_exists(verif->stmt->context->ref_objects, &ref)) {
OG_RETURN_IFERR(
cm_galist_copy_append(verif->stmt->context->ref_objects, sizeof(object_address_t), &ref));
}
} else {
sql_check_user_priv(verif->stmt, &node->value.v_seq.user);
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t sql_try_verify_sequence(sql_verifier_t *verif, expr_node_t *node, bool32 *result)
{
column_word_t *col = &node->word.column;
seq_mode_t mode;
text_t schema;
*result = OG_FALSE;
if (cm_text_equal_ins((text_t *)&col->name, &g_nextval)) {
mode = SEQ_NEXT_VALUE;
} else if (cm_text_equal_ins((text_t *)&col->name, &g_currval)) {
mode = SEQ_CURR_VALUE;
} else {
return OG_SUCCESS;
}
if (verif->excl_flags & SQL_EXCL_SEQUENCE) {
OG_SRC_THROW_ERROR(node->loc, ERR_SQL_SYNTAX_ERROR, "unexpected sequence occurs");
return OG_ERROR;
}
node->datatype = OG_TYPE_BIGINT;
node->size = sizeof(int64);
node->value.v_seq.mode = mode;
node->value.v_seq.name = col->table.value;
if (col->user.value.len == 0) {
cm_str2text(verif->stmt->session->curr_schema, &schema);
if (sql_copy_name(verif->stmt->context, &schema, &node->value.v_seq.user) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (sql_copy_prefix_tenant(verif->stmt, &col->user.value, &node->value.v_seq.user, sql_copy_name) !=
OG_SUCCESS) {
return OG_ERROR;
}
}
if (node->value.v_seq.name.len == 0) {
return OG_SUCCESS;
}
OG_RETURN_IFERR(sql_append_dependency_sequences(verif, node));
node->type = EXPR_NODE_SEQUENCE;
*result = OG_TRUE;
OG_RETURN_IFERR(sql_add_sequence_node(verif->stmt, node));
return OG_SUCCESS;
}
status_t sql_try_verify_rowid(sql_verifier_t *verif, expr_node_t *node, bool32 *result)
{
column_word_t *col = &node->word.column;
*result = OG_FALSE;
if (!cm_text_equal((text_t *)&col->name, &g_rowid)) {
return OG_SUCCESS;
}
node->type = EXPR_NODE_RESERVED;
node->value.v_int = RES_WORD_ROWID;
*result = OG_TRUE;
return sql_verify_rowid(verif, node);
}
status_t sql_try_verify_rowscn(sql_verifier_t *verif, expr_node_t *node, bool32 *result)
{
column_word_t *col = &node->word.column;
*result = OG_FALSE;
if (!cm_text_equal((text_t *)&col->name, &g_rowscn)) {
return OG_SUCCESS;
}
node->type = EXPR_NODE_RESERVED;
node->value.v_int = RES_WORD_ROWSCN;
*result = OG_TRUE;
return sql_verify_rowscn(verif, node);
}
#ifdef __cplusplus
}
#endif