* 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.
* -------------------------------------------------------------------------
*
* cursor_cl.c
*
*
* IDENTIFICATION
* src/ogsql/pl/parser/cursor_cl.c
*
* -------------------------------------------------------------------------
*/
#include "cursor_cl.h"
#include "base_compiler.h"
#include "decl_cl.h"
#include "pl_memory.h"
#include "pl_common.h"
#include "ogsql_parser.h"
#include "dml.h"
#include "ogsql_dependency.h"
#include "typedef_cl.h"
#include "ast_cl.h"
#include "base_compiler.h"
#include "pl_udt.h"
#include "dml_cl.h"
#include "pl_dc.h"
#include "func_parser.h"
status_t plc_compile_cursor_select(pl_compiler_t *compiler, plv_decl_t *decl, word_t *word, text_t *sql_text)
{
sql_text->len = 0;
sql_text->str = compiler->convert_buf;
OG_RETURN_IFERR(plc_concat_str(sql_text, compiler->convert_buf_size, "select "));
compiler->current_input = decl->cursor.input;
compiler->keyword_hook = plc_dmlhook_none;
OG_RETURN_IFERR(plc_compile_dml(compiler, sql_text, word, PLV_VARIANT_ALL | PLV_CUR, (void *)decl));
if (word->type != WORD_TYPE_PL_TERM && word->type != WORD_TYPE_EOF) {
OG_SRC_THROW_ERROR(decl->loc, ERR_PL_EXPECTED_FAIL_FMT, "';'", W2S(word));
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t plc_expanse_cursor_def(pl_compiler_t *compiler, plv_decl_t *decl, pl_line_open_t *line,
bool32 dynamic_check)
{
word_t word;
text_t sql_text;
source_location_t loc;
sql_context_t *cursor_ctx = NULL;
lex_t *lex = compiler->stmt->session->lex;
sql_stmt_t *stmt = compiler->stmt;
pl_entity_t *entity = (pl_entity_t *)compiler->entity;
loc = lex->loc;
OG_RETURN_IFERR(lex_expected_fetch_word(lex, "SELECT"));
PLC_RESET_WORD_LOC(lex, &word);
OG_RETURN_IFERR(plc_compile_cursor_select(compiler, decl, &word, &sql_text));
cm_trim_text(&sql_text);
CM_ASSERT(decl->cursor.ogx->context == NULL);
OGSQL_SAVE_STACK(stmt);
if (pl_compile_parse_sql(stmt, &cursor_ctx, &sql_text, &loc, &entity->sqls) != OG_SUCCESS) {
OGSQL_RESTORE_STACK(stmt);
return OG_ERROR;
}
OGSQL_RESTORE_STACK(stmt);
if (decl->cursor.ogx->is_sysref == OG_FALSE) {
decl->cursor.ogx->context = cursor_ctx;
} else {
((pl_line_open_t *)line)->context = cursor_ctx;
}
if (!cursor_ctx->cacheable) {
pl_entity_uncacheable(compiler->entity);
}
OG_RETURN_IFERR(sql_append_references(&entity->ref_list, cursor_ctx));
return OG_SUCCESS;
}
static status_t plc_copy_context_rscols(pl_compiler_t *compiler, sql_context_t *sql_ctx, plv_record_t *record)
{
uint32 col_id;
plv_record_attr_t *attr = NULL;
lex_t *lex = compiler->stmt->session->lex;
pl_entity_t *pl_entity = compiler->entity;
for (col_id = 0; col_id < sql_ctx->rs_columns->count; col_id++) {
rs_column_t *col = cm_galist_get(sql_ctx->rs_columns, col_id);
if (col->typmod.is_array) {
OG_SRC_THROW_ERROR(lex->loc, ERR_PL_UNSUPPORT);
return OG_ERROR;
}
attr = udt_record_alloc_attr(pl_entity, record);
if (attr == NULL) {
pl_check_and_set_loc(lex->loc);
return OG_ERROR;
}
OG_RETURN_IFERR(pl_copy_name_cs(pl_entity, &col->name, &attr->name, OG_FALSE));
attr->type = UDT_SCALAR;
OG_RETURN_IFERR(pl_alloc_mem(pl_entity, sizeof(field_scalar_info_t), (void **)&attr->scalar_field));
attr->scalar_field->type_mode = col->typmod;
attr->default_expr = NULL;
attr->nullable = OG_FALSE;
if (attr->scalar_field->type_mode.datatype != OG_TYPE_UNKNOWN) {
OG_RETURN_IFERR(plc_check_datatype(compiler, &attr->scalar_field->type_mode, OG_FALSE));
}
}
return OG_SUCCESS;
}
static status_t plc_expanse_cursor_defs_core(pl_compiler_t *compiler, plv_decl_t *decl, lex_t *lex)
{
if (decl->cursor.sql.len != 0) {
OG_RETURN_IFERR(lex_push(lex, &decl->cursor.sql));
if (plc_expanse_cursor_def(compiler, decl, NULL, OG_FALSE) != OG_SUCCESS) {
lex_pop(lex);
return OG_ERROR;
}
if (decl->cursor.record != NULL) {
if (plc_copy_context_rscols(compiler, decl->cursor.ogx->context, decl->cursor.record) != OG_SUCCESS) {
lex_pop(lex);
return OG_ERROR;
}
}
lex_pop(lex);
}
return OG_SUCCESS;
}
static status_t plc_compile_static_refcur(pl_compiler_t *compiler, bool32 bracketed, sql_text_t *sql, word_t *word,
plv_decl_t *decl, pl_line_open_t *line)
{
lex_t *lex = compiler->stmt->session->lex;
if (bracketed) {
OG_RETURN_IFERR(lex_push(lex, sql));
if (plc_expanse_cursor_def(compiler, decl, line, OG_TRUE) != OG_SUCCESS) {
lex_pop(lex);
return OG_ERROR;
}
lex_pop(lex);
OG_RETURN_IFERR(lex_fetch(lex, word));
if (IS_SPEC_CHAR(word, ';')) {
return OG_SUCCESS;
}
OG_SRC_THROW_ERROR(line->ctrl.loc, ERR_PL_EXPECTED_FAIL_FMT, "';'", W2S(word));
return OG_ERROR;
}
return plc_expanse_cursor_def(compiler, decl, line, OG_TRUE);
}
static status_t plc_compile_refcur_using(pl_compiler_t *compiler, word_t *word, pl_line_open_t *line)
{
expr_tree_t *expr = NULL;
bool32 result = OG_FALSE;
lex_t *lex = compiler->stmt->session->lex;
OG_RETURN_IFERR(plc_init_galist(compiler, &line->using_exprs));
while (OG_TRUE) {
OG_RETURN_IFERR(lex_try_fetch(lex, "IN", &result));
OG_RETURN_IFERR(lex_try_fetch(lex, "OUT", &result));
if (result) {
OG_SRC_THROW_ERROR(line->ctrl.loc, ERR_PLSQL_ILLEGAL_LINE_FMT,
"OUT and IN/OUT modes cannot be opened in refcursor");
return OG_ERROR;
}
OG_RETURN_IFERR(sql_create_expr_until(compiler->stmt, &expr, word));
OG_RETURN_IFERR(plc_verify_expr(compiler, expr));
OG_RETURN_IFERR(plc_clone_expr_tree(compiler, &expr));
OG_RETURN_IFERR(cm_galist_insert(line->using_exprs, expr));
if (word->text.len != 1 || word->text.str[0] != ',') {
break;
}
}
return OG_SUCCESS;
}
static status_t plc_compile_dynamic_refcur(pl_compiler_t *compiler, word_t *word, pl_line_open_t *line)
{
OG_RETURN_IFERR(sql_create_expr_until(compiler->stmt, &line->dynamic_sql, word));
OG_RETURN_IFERR(plc_verify_expr(compiler, line->dynamic_sql));
OG_RETURN_IFERR(plc_clone_expr_tree(compiler, &line->dynamic_sql));
if (IS_SPEC_CHAR(word, ';')) {
return OG_SUCCESS;
}
if (word->id != KEY_WORD_USING) {
OG_SRC_THROW_ERROR(line->ctrl.loc, ERR_SQL_SYNTAX_ERROR, "USING expected");
return OG_ERROR;
}
return plc_compile_refcur_using(compiler, word, line);
}
static status_t plc_check_same_cursor_args_name(pl_compiler_t *compiler, galist_t *args)
{
uint32 i;
uint32 j;
expr_tree_t *arg1 = NULL;
expr_tree_t *arg2 = NULL;
for (i = 0; i < args->count; i++) {
arg1 = (expr_tree_t *)cm_galist_get(args, i);
OG_CONTINUE_IFTRUE(arg1->arg_name.len == 0);
for (j = i + 1; j < args->count; j++) {
arg2 = (expr_tree_t *)cm_galist_get(args, j);
OG_CONTINUE_IFTRUE(arg2->arg_name.len == 0);
if (cm_compare_text_ins(&arg1->arg_name, &arg2->arg_name) == 0) {
OG_SRC_THROW_ERROR(arg1->loc, ERR_PL_DUP_ARG_FMT, T2S(&arg1->arg_name), "cursor");
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
status_t plc_build_open_cursor_args(pl_compiler_t *compiler, word_t *word, galist_t *expr_list)
{
expr_tree_t *arg_expr = NULL;
sql_text_t *arg_text = NULL;
sql_stmt_t *stmt = compiler->stmt;
lex_t *lex = stmt->session->lex;
bool32 assign_arg = OG_FALSE;
text_t arg_name;
text_t pl_arg_name;
arg_text = &word->text;
lex_remove_brackets(arg_text);
OG_RETURN_IFERR(lex_push(lex, arg_text));
while (OG_TRUE) {
arg_name.len = 0;
if (sql_try_fetch_func_arg(stmt, &arg_name) != OG_SUCCESS) {
lex_pop(lex);
return OG_ERROR;
}
if (pl_copy_text(compiler->entity, &arg_name, &pl_arg_name) != OG_SUCCESS) {
lex_pop(lex);
return OG_ERROR;
}
if (arg_name.len == 0 && assign_arg) {
lex_pop(lex);
OG_SRC_THROW_ERROR(word->text.loc, ERR_PL_EXPECTED_FAIL_FMT, "'=>'", "NULL");
return OG_ERROR;
}
PLC_RESET_WORD_LOC(lex, word);
if (sql_create_expr_until(stmt, &arg_expr, word) != OG_SUCCESS) {
lex_pop(lex);
return OG_ERROR;
}
if (plc_verify_expr(compiler, arg_expr) != OG_SUCCESS) {
lex_pop(lex);
return OG_ERROR;
}
if (plc_clone_expr_tree(compiler, &arg_expr) != OG_SUCCESS) {
lex_pop(lex);
return OG_ERROR;
}
if (arg_name.len > 0) {
assign_arg = OG_TRUE;
arg_expr->arg_name = pl_arg_name;
}
if (cm_galist_insert(expr_list, arg_expr) != OG_SUCCESS) {
lex_pop(lex);
return OG_ERROR;
}
if (word->type == WORD_TYPE_EOF || word->type == WORD_TYPE_OPERATOR) {
break;
}
if (!IS_SPEC_CHAR(word, ',')) {
lex_pop(lex);
OG_SRC_THROW_ERROR(word->text.loc, ERR_PL_EXPECTED_FAIL_FMT, "','", W2S(word));
return OG_ERROR;
}
}
lex_pop(lex);
return plc_check_same_cursor_args_name(compiler, expr_list);
}
* @brief implicit cursor's attribiute must equal 'SQL'
*/
static status_t plc_check_cursor_name(pl_compiler_t *compiler, source_location_t loc, text_t *name)
{
if (cm_text_str_equal_ins(name, "SQL")) {
OG_SRC_THROW_ERROR(loc, ERR_PL_SYNTAX_ERROR_FMT,
"Encountered the symbol 'SQL' when expecting one of the following:"
"<an identifier> <a double-quoted delimited-identifier>");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t plc_compile_cursor_arg(pl_compiler_t *compiler, plv_decl_t *cur, galist_t *decls, word_t *word)
{
bool32 result = OG_FALSE;
plv_decl_t *decl = NULL;
lex_t *lex = compiler->stmt->session->lex;
pl_entity_t *pl_entity = compiler->entity;
OG_RETURN_IFERR(cm_galist_new(decls, sizeof(plv_decl_t), (void **)&decl));
decl->vid.block = (int16)compiler->stack.depth;
decl->vid.id = decls->count - 1;
OG_RETURN_IFERR(lex_fetch(lex, word));
if (!IS_VARIANT(word)) {
OG_SRC_THROW_ERROR(word->loc, ERR_PL_EXPECTED_FAIL_FMT, "VARIANT", W2S(word));
return OG_ERROR;
}
OG_RETURN_IFERR(pl_copy_object_name_ci(pl_entity, word->type, (text_t *)&word->text, &decl->name));
OG_RETURN_IFERR(lex_try_fetch(lex, "in", &result));
decl->drct = PLV_DIR_IN;
OG_RETURN_IFERR(plc_compile_variant_def(compiler, word, decl, OG_TRUE, decls, OG_TRUE));
OG_RETURN_IFERR(plc_compile_default_def(compiler, word, decl, OG_TRUE));
if ((word->type != WORD_TYPE_EOF) && !(IS_SPEC_CHAR(word, ','))) {
if (word->type == WORD_TYPE_BRACKET) {
OG_SRC_THROW_ERROR(word->loc, ERR_PL_EXPECTED_FAIL_FMT, ":= or default or another arg or end of args",
"BRACKET symbol '('");
} else {
OG_SRC_THROW_ERROR(word->loc, ERR_PL_EXPECTED_FAIL_FMT, ":= or default or another arg or end of args",
W2S(word));
}
return OG_ERROR;
}
if ((decl->type & PLV_VAR) == 0) {
OG_SRC_THROW_ERROR(word->loc, ERR_PLSQL_ILLEGAL_LINE_FMT, "cursor arg should be variant.");
return OG_ERROR;
}
decl->type = PLV_VAR;
decl->arg_type = PLV_CURSOR_ARG;
if (OG_IS_VARLEN_TYPE(decl->variant.type.datatype)) {
decl->variant.type.size = OG_STRING_BUFFER_SIZE;
}
return cm_galist_insert(cur->cursor.ogx->args, decl);
}
static status_t plc_compile_cursor_args(pl_compiler_t *compiler, plv_decl_t *decl, galist_t *decls, word_t *word)
{
lex_t *lex = compiler->stmt->session->lex;
cm_trim_text((text_t *)&word->text);
if (((text_t *)&word->text)->len == 0) {
return OG_SUCCESS;
}
OG_RETURN_IFERR(plc_init_galist(compiler, &decl->cursor.ogx->args));
OG_RETURN_IFERR(lex_push(lex, &word->text));
while (OG_TRUE) {
if (plc_compile_cursor_arg(compiler, decl, decls, word) != OG_SUCCESS) {
decl->cursor.ogx->is_err = (bool8)OG_TRUE;
lex_pop(lex);
return OG_ERROR;
}
if ((word->type == WORD_TYPE_EOF) || !(IS_SPEC_CHAR(word, ','))) {
break;
}
}
lex_pop(lex);
return OG_SUCCESS;
}
status_t plc_compile_cursor_def(pl_compiler_t *compiler, galist_t *decls, word_t *word)
{
bool32 result = OG_FALSE;
plv_decl_t *decl = NULL;
lex_t *lex = compiler->stmt->session->lex;
pl_entity_t *pl_entity = compiler->entity;
OG_RETURN_IFERR(lex_fetch(lex, word));
OG_RETURN_IFERR(plc_check_cursor_name(compiler, word->loc, (text_t *)&word->text));
OG_RETURN_IFERR(plc_verify_word_as_var(compiler, word));
plc_find_decl_ex(compiler, word, PLV_CUR, NULL, &decl);
if (decl != NULL && decl->cursor.ogx->is_sysref) {
OG_SRC_THROW_ERROR_EX(word->loc, ERR_PLSQL_ILLEGAL_LINE_FMT, "%s is sys_refcursor conflict with cursor def.",
W2S(word));
return OG_ERROR;
}
OG_RETURN_IFERR(cm_galist_new(decls, sizeof(plv_decl_t), (void **)&decl));
OG_RETURN_IFERR(pl_alloc_mem(pl_entity, sizeof(plv_cursor_context_t), (void **)&decl->cursor.ogx));
OG_RETURN_IFERR(pl_copy_object_name_ci(pl_entity, word->type, (text_t *)&word->text, &decl->name));
decl->vid.block = (int16)compiler->stack.depth;
decl->vid.id = decls->count - 1;
decl->type = PLV_CUR;
decl->cursor.ogx->is_sysref = (bool8)OG_FALSE;
decl->loc = word->text.loc;
decl->cursor.ogx->is_err = (bool8)OG_FALSE;
OG_RETURN_IFERR(lex_try_fetch_bracket(lex, word, &result));
if (result) {
OG_RETURN_IFERR(plc_compile_cursor_args(compiler, decl, decls, word));
}
OG_RETURN_IFERR(lex_try_fetch(lex, "RETURN", &result));
if (result) {
OG_SRC_THROW_ERROR(lex->loc, ERR_PL_UNSUPPORT);
}
OG_RETURN_IFERR(lex_try_fetch(lex, "IS", &result));
if (result) {
OG_RETURN_IFERR(lex_try_fetch_bracket(lex, word, &result));
if (!result) {
decl->cursor.sql = *(lex->curr_text);
} else {
decl->cursor.sql = word->text;
}
OG_RETURN_IFERR(lex_fetch_to_char(lex, word, ';'));
} else {
decl->cursor.sql.value = CM_NULL_TEXT;
OG_RETURN_IFERR(lex_expected_fetch_word(lex, ";"));
word->type = WORD_TYPE_PL_TERM;
}
return plc_init_galist(compiler, &decl->cursor.input);
}
static status_t plc_compile_for_impcur(pl_compiler_t *compiler, pl_line_for_t *line, word_t *word)
{
text_t sql;
plv_decl_t *id = line->id;
plv_decl_t *imp_cur = NULL;
source_location_t loc;
lex_t *lex = compiler->stmt->session->lex;
sql_stmt_t *stmt = compiler->stmt;
pl_entity_t *entity = (pl_entity_t *)compiler->entity;
sql.str = compiler->convert_buf;
sql.len = 0;
OG_RETURN_IFERR(cm_galist_new(line->decls, sizeof(plv_decl_t), (void **)&imp_cur));
OG_RETURN_IFERR(pl_alloc_mem(entity, sizeof(plv_cursor_context_t), (void **)&imp_cur->cursor.ogx));
OG_RETURN_IFERR(plc_init_galist(compiler, &imp_cur->cursor.input));
compiler->current_input = imp_cur->cursor.input;
imp_cur->vid.block = id->vid.block;
imp_cur->vid.id = line->decls->count - 1;
imp_cur->type = PLV_IMPCUR;
line->cursor_id = imp_cur->vid;
loc = word->loc;
OG_RETURN_IFERR(lex_expected_fetch_word(lex, "SELECT"));
OG_RETURN_IFERR(plc_compile_select(compiler, &sql, word, OG_FALSE));
cm_trim_text(&sql);
OGSQL_SAVE_STACK(stmt);
if (pl_compile_parse_sql(stmt, &line->context, &sql, &loc, &entity->sqls) != OG_SUCCESS) {
OGSQL_RESTORE_STACK(stmt);
return OG_ERROR;
}
OGSQL_RESTORE_STACK(stmt);
if (!line->context->cacheable) {
pl_entity_uncacheable(entity);
}
OG_RETURN_IFERR(sql_append_references(&entity->ref_list, line->context));
OG_RETURN_IFERR(plc_copy_context_rscols(compiler, line->context, line->id->record));
OG_RETURN_IFERR(plc_init_galist(compiler, &line->into.output));
OG_RETURN_IFERR(udt_build_list_address_single(compiler->stmt, line->into.output, line->id, UDT_STACK_ADDR));
line->into.prefetch_rows = INTO_COMMON_PREFETCH_COUNT;
line->into.into_type = (uint8)INTO_AS_REC;
line->into.is_bulk = OG_FALSE;
imp_cur->cursor.sql.value = CM_NULL_TEXT;
imp_cur->drct = PLV_DIR_NONE;
imp_cur->cursor.ogx->context = line->context;
return OG_SUCCESS;
}
status_t plc_compile_for_cursor(pl_compiler_t *compiler, pl_line_for_t *line, word_t *word)
{
plv_decl_t *decl = NULL;
bool32 result = OG_FALSE;
uint32 save_flags;
plv_decl_t *id = line->id;
plv_decl_t *type_record = NULL;
lex_t *lex = compiler->stmt->session->lex;
pl_entity_t *pl_entity = compiler->entity;
id->type = PLV_RECORD;
OG_RETURN_IFERR(pl_copy_name(pl_entity, (text_t *)&word->text, &id->name));
OG_RETURN_IFERR(cm_galist_new(line->decls, sizeof(plv_decl_t), (void **)&type_record));
type_record->type = PLV_TYPE;
type_record->typdef.type = PLV_RECORD;
type_record->typdef.record.root = type_record;
type_record->typdef.record.is_anonymous = OG_TRUE;
id->record = &type_record->typdef.record;
OG_RETURN_IFERR(lex_expected_fetch_word(lex, "in"));
OG_RETURN_IFERR(lex_try_fetch_bracket(lex, word, &result));
if (result) {
line->is_impcur = OG_TRUE;
OG_RETURN_IFERR(lex_push(lex, &word->text));
status_t status = plc_compile_for_impcur(compiler, line, word);
lex_pop(lex);
return status;
}
save_flags = lex->flags;
lex->flags = LEX_WITH_OWNER;
OG_RETURN_IFERR(lex_fetch(lex, word));
if (word->type != WORD_TYPE_PARAM) {
OG_RETURN_IFERR(plc_find_decl(compiler, word, PLV_CUR, NULL, &decl));
if (cm_text_equal(&id->name, &decl->name)) {
OG_SRC_THROW_ERROR(word->loc, ERR_PL_INVALID_LOOP_INDEX, T2S(&line->id->name));
return OG_ERROR;
}
} else {
OG_SRC_THROW_ERROR(word->loc, ERR_PLSQL_ILLEGAL_LINE_FMT,
"the declaration of the cursor of this expression is incomplete or malformed");
return OG_ERROR;
}
OG_RETURN_IFERR(lex_try_fetch_bracket(lex, word, &result));
if (result) {
lex_trim(&word->text);
if (word->text.len == 0) {
result = OG_FALSE;
}
}
if (result) {
OG_RETURN_IFERR(plc_init_galist(compiler, &line->exprs));
OG_RETURN_IFERR(plc_build_open_cursor_args(compiler, word, line->exprs));
OG_RETURN_IFERR(plc_verify_cursor_args(compiler, line->exprs, decl->cursor.ogx->args, line->ctrl.loc));
} else {
line->exprs = NULL;
}
lex->flags = save_flags;
if (decl->cursor.ogx->is_sysref) {
OG_SRC_THROW_ERROR(word->loc, ERR_INVALID_CURSOR);
return OG_ERROR;
}
line->is_impcur = OG_FALSE;
line->cursor_id = decl->vid;
if (decl->cursor.ogx->context == NULL) {
OG_SRC_THROW_ERROR(word->loc, ERR_UNDEFINED_SYMBOL_FMT, W2S(word));
return OG_ERROR;
}
OG_RETURN_IFERR(plc_copy_context_rscols(compiler, decl->cursor.ogx->context, line->id->record));
OG_RETURN_IFERR(plc_init_galist(compiler, &line->into.output));
OG_RETURN_IFERR(udt_build_list_address_single(compiler->stmt, line->into.output, id, UDT_STACK_ADDR));
line->into.prefetch_rows = INTO_COMMON_PREFETCH_COUNT;
line->into.into_type = (uint8)INTO_AS_REC;
line->into.is_bulk = OG_FALSE;
return OG_SUCCESS;
}
status_t plc_compile_refcur(pl_compiler_t *compiler, word_t *word, plv_decl_t *decl, pl_line_open_t *line)
{
lex_t *lex = compiler->stmt->session->lex;
bool32 bracketed = OG_FALSE;
sql_text_t sql;
hit cursors variables scenario */
OG_RETURN_IFERR(lex_expected_fetch_word(lex, "FOR"));
OG_RETURN_IFERR(lex_try_fetch_bracket(lex, word, &bracketed));
if (bracketed) {
sql = word->text;
OG_RETURN_IFERR(lex_extract_first(&word->text, word));
} else {
OG_RETURN_IFERR(lex_extract_first(lex->curr_text, word));
}
if (word->id == KEY_WORD_SELECT) {
line->is_dynamic_sql = OG_FALSE;
OG_RETURN_IFERR(plc_init_galist(compiler, &line->input));
decl->cursor.input = line->input;
OG_RETURN_IFERR(plc_compile_static_refcur(compiler, bracketed, &sql, word, decl, line));
decl->cursor.input = NULL;
} else {
lex_back(lex, word);
line->is_dynamic_sql = OG_TRUE;
OG_RETURN_IFERR(plc_compile_dynamic_refcur(compiler, word, line));
}
return OG_SUCCESS;
}
status_t plc_diagnose_for_is_cursor(pl_compiler_t *compiler, bool8 *is_cur)
{
bool32 result = OG_FALSE;
word_t word;
lex_t *lex = compiler->stmt->session->lex;
LEX_SAVE(lex);
OG_RETURN_IFERR(lex_expected_fetch_word(lex, "in"));
OG_RETURN_IFERR(lex_try_fetch_bracket(lex, &word, &result));
OG_RETURN_IFERR(lex_fetch(lex, &word));
if (result) {
if (word.type == WORD_TYPE_PL_RANGE) {
result = OG_FALSE;
}
}
if (!result) {
OG_RETURN_IFERR(lex_try_fetch(lex, "loop", &result));
}
LEX_RESTORE(lex);
*is_cur = (bool8)result;
return OG_SUCCESS;
}
status_t plc_expanse_cursor_defs(pl_compiler_t *compiler, galist_t *decls)
{
lex_t *lex = compiler->stmt->session->lex;
plv_decl_t *decl = NULL;
uint32 i;
uint32 count = decls->count;
for (i = 0; i < count; i++) {
decl = (plv_decl_t *)cm_galist_get(decls, i);
if (decl->type == PLV_CUR) {
OG_RETURN_IFERR(plc_expanse_cursor_defs_core(compiler, decl, lex));
}
}
return OG_SUCCESS;
}
status_t plc_verify_cursor_args(pl_compiler_t *compiler, galist_t *expr_list, galist_t *args, source_location_t loc)
{
if (args == NULL) {
OG_SRC_THROW_ERROR(loc, ERR_PL_SYNTAX_ERROR_FMT, "open cursor have no args definition");
return OG_ERROR;
}
if (expr_list->count > args->count) {
OG_SRC_THROW_ERROR(loc, ERR_PL_SYNTAX_ERROR_FMT, "open cursor args no match definition");
return OG_ERROR;
}
return OG_SUCCESS;
}
* @brief compile sys_refcursor define
*/
status_t plc_compile_syscursor_def(pl_compiler_t *compiler, word_t *word, plv_decl_t *decl)
{
pl_entity_t *pl_entity = compiler->entity;
OG_RETURN_IFERR(pl_copy_object_name_ci(pl_entity, word->type, (text_t *)&word->text, &decl->name));
OG_RETURN_IFERR(pl_alloc_mem(pl_entity, sizeof(plv_cursor_context_t), (void **)&decl->cursor.ogx));
decl->type = PLV_CUR;
decl->cursor.sql.value = CM_NULL_TEXT;
decl->cursor.sql.loc = word->loc;
decl->cursor.sql.implicit = OG_FALSE;
decl->cursor.ogx->is_sysref = (bool8)OG_TRUE;
decl->cursor.ogx->is_err = (bool8)OG_FALSE;
decl->cursor.ogx->args = NULL;
decl->cursor.ogx->context = NULL;
decl->cursor.input = NULL;
decl->cursor.record = NULL;
return OG_SUCCESS;
}
status_t plc_compile_type_refcur_def(pl_compiler_t *compiler, plv_decl_t *decl, galist_t *decls, word_t *word)
{
lex_t *lex = compiler->stmt->session->lex;
bool32 result = OG_FALSE;
decl->typdef.type = PLV_CUR;
OG_RETURN_IFERR(lex_try_fetch(lex, "RETURN", &result));
if (result) {
OG_SRC_THROW_ERROR(lex->loc, ERR_PL_UNSUPPORT);
return OG_ERROR;
}
return lex_expected_fetch_word(lex, ";");
}
status_t plc_verify_cursor_setval(pl_compiler_t *compiler, expr_tree_t *expr)
{
if (expr->root->datatype != OG_TYPE_CURSOR) {
OG_SRC_THROW_ERROR(expr->loc, ERR_PL_EXPR_WRONG_TYPE);
return OG_ERROR;
}
if (expr->root->type == EXPR_NODE_USER_FUNC) {
return OG_SUCCESS;
}
if (expr->root->type != EXPR_NODE_V_ADDR || compiler->stack.depth == 0) {
OG_SRC_THROW_ERROR(expr->loc, ERR_PL_EXPR_WRONG_TYPE);
return OG_ERROR;
}
var_address_pair_t *pair = sql_get_last_addr_pair(expr->root);
if (pair == NULL || pair->type != UDT_STACK_ADDR) {
OG_SRC_THROW_ERROR(expr->loc, ERR_PL_EXPR_WRONG_TYPE);
return OG_ERROR;
}
plv_decl_t *decl = pair->stack->decl;
if (decl->cursor.ogx != NULL && (decl->cursor.ogx->is_sysref == OG_FALSE ||
(decl->cursor.ogx->args != NULL && decl->cursor.ogx->args->count != 0))) {
OG_SRC_THROW_ERROR(expr->loc, ERR_PL_EXPR_WRONG_TYPE);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t plc_verify_using_out_cursor(pl_compiler_t *compiler, expr_tree_t *expr)
{
expr_node_t *node = expr->root;
if (node->type == EXPR_NODE_V_ADDR) {
if (compiler == NULL) {
return OG_SUCCESS;
}
var_address_pair_t *pair = sql_get_last_addr_pair(node);
if (pair == NULL || pair->type != UDT_STACK_ADDR) {
return OG_SUCCESS;
}
if (pair->stack->decl != NULL && pair->stack->decl->type == PLV_CUR) {
OG_SRC_THROW_ERROR(expr->loc, ERR_PL_SYNTAX_ERROR_FMT,
"out param of using clause only support normal variable, not cursor");
return OG_ERROR;
}
}
return OG_SUCCESS;
}