* 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.
* -------------------------------------------------------------------------
*
* ddl_sequence_parser.c
*
*
* IDENTIFICATION
* src/ogsql/parser_ddl/ddl_sequence_parser.c
*
* -------------------------------------------------------------------------
*/
#include "ddl_sequence_parser.h"
#include "ddl_parser_common.h"
#include "ddl_parser.h"
#include "dtc_dls.h"
#include "dml_parser.h"
#include "scanner.h"
static void sql_init_create_sequence(sql_stmt_t *stmt, knl_sequence_def_t *seq_def)
{
CM_POINTER(seq_def);
seq_def->name.len = 0;
seq_def->start = 1;
seq_def->step = DDL_SEQUENCE_DEFAULT_INCREMENT;
seq_def->min_value = 1;
seq_def->max_value = DDL_ASC_SEQUENCE_DEFAULT_MAX_VALUE;
seq_def->cache = DDL_SEQUENCE_DEFAULT_CACHE;
seq_def->is_cycle = OG_FALSE;
seq_def->nocache = OG_FALSE;
seq_def->nominval = OG_TRUE;
seq_def->nomaxval = OG_TRUE;
seq_def->is_order = OG_FALSE;
seq_def->is_option_set = (uint32)0;
}
Description : check sequence max/min value is valid or not according to the
grammar
Input : knl_sequence_def_t * stmt
Output : None
Modification : Create function
Date : 2017-02-23
**************************************************************************** */
static status_t sql_check_sequence_scop_value_valid(knl_sequence_def_t *sequence_def)
{
if (sequence_def->max_value <= sequence_def->min_value) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "MINVALUE must less than MAXVALUE");
return OG_ERROR;
}
int64 next;
if (sequence_def->step > 0) {
if ((opr_int64add_overflow(sequence_def->min_value, sequence_def->step, &next)) ||
(sequence_def->max_value < next)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "INCREMENT must be less than MAX value minus MIN value");
return OG_ERROR;
}
}
if (sequence_def->step < 0) {
if ((opr_int64add_overflow(sequence_def->max_value, sequence_def->step, &next)) ||
(sequence_def->min_value > next)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "INCREMENT must be less than MAX value minus MIN value");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
Description : format sequence max/min value according to the grammar
Input : knl_sequence_def_t * stmt
Output : None
Modification : Create function
Date : 2017-02-23
**************************************************************************** */
static status_t sql_format_sequence_scop_value(knl_sequence_def_t *sequence_def)
{
sequence_def->nominval = sequence_def->is_minval_set ? OG_FALSE : OG_TRUE;
sequence_def->nomaxval = sequence_def->is_maxval_set ? OG_FALSE : OG_TRUE;
assign the ascending or descending sequence's default min value */
if (sequence_def->nominval) {
sequence_def->min_value =
sequence_def->step < 0 ? DDL_DESC_SEQUENCE_DEFAULT_MIN_VALUE : DDL_ASC_SEQUENCE_DEFAULT_MIN_VALUE;
sequence_def->is_minval_set = sequence_def->is_nominval_set ? 1 : 0;
}
assign the ascending or descending sequence's default max value */
if (sequence_def->nomaxval) {
sequence_def->max_value =
sequence_def->step < 0 ? DDL_DESC_SEQUENCE_DEFAULT_MAX_VALUE : DDL_ASC_SEQUENCE_DEFAULT_MAX_VALUE;
sequence_def->is_maxval_set = sequence_def->is_nomaxval_set ? 1 : 0;
}
return sql_check_sequence_scop_value_valid(sequence_def);
}
Description : check sequence start with value is valid or not according to
the grammar
Input : knl_sequence_def_t * stmt
Output : None
Modification : Create function
Date : 2017-02-23
**************************************************************************** */
static status_t sql_check_sequence_start_value(knl_sequence_def_t *sequence_def)
{
if (sequence_def->step > 0) {
if (sequence_def->start - sequence_def->step > sequence_def->max_value) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "start value cannot be greater than max value plus increment");
return OG_ERROR;
}
if (sequence_def->start < sequence_def->min_value) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "start value cannot be less than min value");
return OG_ERROR;
}
} else {
if (sequence_def->start - sequence_def->step < sequence_def->min_value) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "start value cannot be less than min value plus increment");
return OG_ERROR;
}
if (sequence_def->start > sequence_def->max_value) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "start value cannot be greater than max value");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
Description : format sequence start with value according to the grammar
Input : knl_sequence_def_t * stmt
Output : None
Modification : Create function
Date : 2017-02-23
**************************************************************************** */
static status_t sql_format_sequence_start_value(knl_sequence_def_t *sequence_def)
{
if (!sequence_def->is_start_set) {
sequence_def->start = sequence_def->step > 0 ? sequence_def->min_value : sequence_def->max_value;
}
return sql_check_sequence_start_value(sequence_def);
}
static status_t sql_check_sequence_cache_value(knl_sequence_def_t *sequence_def)
{
int64 step = cm_abs64(sequence_def->step);
if (sequence_def->cache <= 1) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "CACHE value must be larger than 1");
return OG_ERROR;
}
if (sequence_def->is_nocache_set) {
sequence_def->cache = 0;
sequence_def->is_cache_set = 1;
}
if (!sequence_def->nocache && sequence_def->cache < 2) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "number to CACHE must be more than 1");
return OG_ERROR;
}
if (sequence_def->is_cycle && ((uint64)sequence_def->cache >
ceil((double)((uint64)sequence_def->max_value - sequence_def->min_value) / step))) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "number to CACHE must be less than one cycle");
return OG_ERROR;
}
if (sequence_def->step >= 1 &&
(sequence_def->cache > (DDL_ASC_SEQUENCE_DEFAULT_MAX_VALUE / cm_abs64(sequence_def->step)))) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "CACHE multiply abs of STEP must be less than DEFAULT MAXVALUE");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t sql_format_sequence(sql_stmt_t *stmt, knl_sequence_def_t *sequence_def)
{
if (sql_format_sequence_scop_value(sequence_def) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_format_sequence_start_value(sequence_def) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_check_sequence_cache_value(sequence_def) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t sql_parse_increment(lex_t *lex, knl_sequence_def_t *sequence_def)
{
int64 increment = 0;
if (lex_expected_fetch_word(lex, "BY") != OG_SUCCESS) {
return OG_ERROR;
}
if (lex_expected_fetch_seqval(lex, &increment) != OG_SUCCESS) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "sequence INCREMENT must be a bigint");
return OG_ERROR;
}
if (increment == 0) {
OG_SRC_THROW_ERROR(lex->loc, ERR_SEQ_INVALID, "sequence INCREMENT must be a non-zero integer");
return OG_ERROR;
}
sequence_def->step = increment;
return OG_SUCCESS;
}
static status_t sql_parse_start_with(lex_t *lex, knl_sequence_def_t *sequence_def)
{
if (lex_expected_fetch_word(lex, "WITH") != OG_SUCCESS) {
return OG_ERROR;
}
if (lex_expected_fetch_seqval(lex, &sequence_def->start) != OG_SUCCESS) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "sequence START WITH must be a bigint");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t sql_parse_sequence_parameters(sql_stmt_t *stmt, knl_sequence_def_t *seq_def, word_t *word,
bool32 allow_groupid)
{
status_t status;
lex_t *lex = stmt->session->lex;
for (;;) {
status = lex_fetch(stmt->session->lex, word);
OG_RETURN_IFERR(status);
if (word->type == WORD_TYPE_EOF) {
break;
}
switch (word->id) {
case (uint32)KEY_WORD_RESTART:
if (seq_def->is_restart_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "duplicate RESTART specifications");
return OG_ERROR;
}
seq_def->is_restart_set = OG_TRUE;
break;
case (uint32)KEY_WORD_INCREMENT:
if (seq_def->is_step_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "duplicate INCREMENT specifications");
return OG_ERROR;
}
status = sql_parse_increment(lex, seq_def);
OG_RETURN_IFERR(status);
seq_def->is_step_set = 1;
break;
case (uint32)KEY_WORD_MINVALUE:
if (seq_def->is_minval_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "duplicate MINVALUE specifications");
return OG_ERROR;
}
if (lex_expected_fetch_seqval(lex, &seq_def->min_value) != OG_SUCCESS) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "sequence MINVALUE must be a bigint");
return OG_ERROR;
}
seq_def->nominval = OG_FALSE;
seq_def->is_minval_set = 1;
break;
case (uint32)KEY_WORD_NO_MINVALUE:
if (seq_def->is_nominval_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "duplicate NO_MINVALUE specifications");
return OG_ERROR;
}
seq_def->nominval = OG_TRUE;
seq_def->is_nominval_set = 1;
break;
case (uint32)KEY_WORD_MAXVALUE:
if (seq_def->is_maxval_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "duplicate MAXVALUE specifications");
return OG_ERROR;
}
if (lex_expected_fetch_seqval(lex, &seq_def->max_value) != OG_SUCCESS) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "sequence MAXVALUE must be a bigint");
return OG_ERROR;
}
seq_def->nomaxval = OG_FALSE;
seq_def->is_maxval_set = 1;
break;
case (uint32)KEY_WORD_NO_MAXVALUE:
if (seq_def->is_nomaxval_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "duplicate NO_MAXVALUE specifications");
return OG_ERROR;
}
seq_def->nomaxval = OG_TRUE;
seq_def->is_nomaxval_set = 1;
break;
case (uint32)KEY_WORD_START:
if (seq_def->is_start_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "duplicate START specifications");
return OG_ERROR;
}
status = sql_parse_start_with(lex, seq_def);
OG_RETURN_IFERR(status);
seq_def->is_start_set = OG_TRUE;
break;
case (uint32)KEY_WORD_CACHE:
if (seq_def->is_cache_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "duplicate CACHE specifications");
return OG_ERROR;
}
if (lex_expected_fetch_seqval(lex, &seq_def->cache) != OG_SUCCESS) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "sequence CACHE must be a bigint");
return OG_ERROR;
}
seq_def->is_cache_set = 1;
break;
case (uint32)KEY_WORD_NO_CACHE:
if (seq_def->is_nocache_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR, "duplicate NO_CACHE specifications");
return OG_ERROR;
}
seq_def->nocache = OG_TRUE;
seq_def->is_nocache_set = 1;
break;
case (uint32)KEY_WORD_CYCLE:
if (seq_def->is_cycle_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR,
"duplicate or conflicting CYCLE/NOCYCLE specifications");
return OG_ERROR;
}
seq_def->is_cycle = OG_TRUE;
seq_def->is_cycle_set = 1;
break;
case (uint32)KEY_WORD_NO_CYCLE:
if (seq_def->is_cycle_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR,
"duplicate or conflicting CYCLE/NOCYCLE specifications");
return OG_ERROR;
}
seq_def->is_cycle = OG_FALSE;
seq_def->is_cycle_set = 1;
break;
case (uint32)KEY_WORD_ORDER:
if (seq_def->is_order_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR,
"duplicate or conflicting ORDER/NOORDER specifications");
return OG_ERROR;
}
seq_def->is_order = OG_TRUE;
seq_def->is_order_set = 1;
break;
case (uint32)KEY_WORD_NO_ORDER:
if (seq_def->is_order_set == OG_TRUE) {
OG_SRC_THROW_ERROR_EX(lex->loc, ERR_SQL_SYNTAX_ERROR,
"duplicate or conflicting ORDER/NOORDER specifications");
return OG_ERROR;
}
seq_def->is_order = OG_FALSE;
seq_def->is_order_set = 1;
break;
default:
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "syntax error in sequence statement");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t sql_check_sequence_conflict_parameters(sql_stmt_t *stmt, knl_sequence_def_t *def)
{
bool32 result;
result = (def->is_minval_set && def->is_nominval_set);
if (result) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate or conflicting MINVAL/NOMINVAL specifications");
return OG_ERROR;
}
result = (def->is_maxval_set && def->is_nomaxval_set);
if (result) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate or conflicting MAX/NOMAXVAL specifications");
return OG_ERROR;
}
result = (def->is_cache_set && def->is_nocache_set);
if (result) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate or conflicting CACHE/NOCACHE specifications");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t sql_check_sequence_parameters_relation(sql_stmt_t *stmt, knl_sequence_def_t *def)
{
bool32 result;
OG_RETURN_IFERR(sql_check_sequence_conflict_parameters(stmt, def));
result = (!def->is_maxval_set && def->is_cycle && (def->step > 0));
if (result) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "ascending sequences that CYCLE must specify MAXVALUE");
return OG_ERROR;
}
result = (!def->is_minval_set && def->is_cycle && (def->step < 0));
if (result) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "descending sequences that CYCLE must specify MINVALUE");
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t sql_parse_create_sequence(sql_stmt_t *stmt)
{
status_t status;
knl_sequence_def_t *sequence_def = NULL;
word_t word;
lex_t *lex = stmt->session->lex;
lex->flags |= LEX_WITH_OWNER;
status = sql_alloc_mem(stmt->context, sizeof(knl_sequence_def_t), (void **)&sequence_def);
OG_RETURN_IFERR(status);
sql_init_create_sequence(stmt, sequence_def);
stmt->context->entry = sequence_def;
stmt->context->type = OGSQL_TYPE_CREATE_SEQUENCE;
status = lex_expected_fetch_variant(stmt->session->lex, &word);
OG_RETURN_IFERR(status);
status = sql_convert_object_name(stmt, &word, &sequence_def->user, NULL, &sequence_def->name);
OG_RETURN_IFERR(status);
status = sql_parse_sequence_parameters(stmt, sequence_def, &word, OG_TRUE);
OG_RETURN_IFERR(status);
status = sql_check_sequence_parameters_relation(stmt, sequence_def);
OG_RETURN_IFERR(status);
return sql_format_sequence(stmt, sequence_def);
}
static void sql_parse_alter_sequence_get_param(knl_sequence_def_t *def, dc_sequence_t *seq)
{
if (def->is_nocache_set) {
def->cache = 0;
def->is_cache_set = 1;
}
if (def->is_nominval_set) {
def->min_value = def->step < 0 ? DDL_DESC_SEQUENCE_DEFAULT_MIN_VALUE : DDL_ASC_SEQUENCE_DEFAULT_MIN_VALUE;
def->is_minval_set = def->is_nominval_set;
}
if (def->is_nomaxval_set) {
def->max_value = def->step < 0 ? DDL_DESC_SEQUENCE_DEFAULT_MAX_VALUE : DDL_ASC_SEQUENCE_DEFAULT_MAX_VALUE;
def->is_maxval_set = def->is_nomaxval_set;
}
return;
}
* merge param in dc when alter sequence
* @param[in] def - sequence defination
* @param[in] seq - sequence in dc
* @return void
*/
static void seq_merge_alter_param(knl_sequence_def_t *seq_def, dc_sequence_t *seq)
{
seq_def->step = seq_def->is_step_set ? seq_def->step : seq->step;
seq_def->cache = seq_def->is_cache_set ? seq_def->cache : seq->cache_size;
seq_def->min_value = seq_def->is_minval_set ? seq_def->min_value : seq->minval;
seq_def->max_value = seq_def->is_maxval_set ? seq_def->max_value : seq->maxval;
seq_def->is_cycle = seq_def->is_cycle_set ? seq_def->is_cycle : seq->is_cyclable;
seq_def->nocache = seq_def->is_nocache_set ? 1 : (seq->is_cache ? 0 : 1);
}
* check the parameter when alter sequence
* @param[in] session - user session
* @param[in] def - sequence defination
* @param[in] sequence - sequence in dc
* @return
* - OG_SUCCESS
* - OG_ERROR
*/
static status_t seq_check_alter_param(sql_stmt_t *stmt, knl_sequence_def_t *def, dc_sequence_t *sequence)
{
int64 step = cm_abs64(def->step);
int64 curr_value = sequence->rsv_nextval;
int64 next;
if (!def->is_option_set) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "no options specified for alter sequence");
return OG_ERROR;
}
if (def->is_start_set && !def->is_restart_set) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "cannot alter starting sequence number ");
return OG_ERROR;
}
if (def->max_value <= def->min_value) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "MINVALUE must less than MAXVALUE");
return OG_ERROR;
}
if (def->step > 0) {
if ((opr_int64add_overflow(def->min_value, def->step, &next)) || (def->max_value < next)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "INCREMENT must be less than MAX value minus MIN value");
return OG_ERROR;
}
}
if (def->step < 0) {
if ((opr_int64add_overflow(def->max_value, def->step, &next)) || (def->min_value > next)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "INCREMENT must be less than MAX value minus MIN value");
return OG_ERROR;
}
}
if (def->is_restart_set) {
if (def->is_start_set && (def->start < def->min_value || def->start > def->max_value)) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "restart value must be between MINVALUE and MAXVALUE");
return OG_ERROR;
}
curr_value = def->start;
}
if (!IS_COORDINATOR || (IS_COORDINATOR && IS_APP_CONN(stmt->session))) {
if (def->min_value > curr_value) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "MINVALUE cannot be made to exceed the current value");
return OG_ERROR;
}
if (def->max_value < curr_value) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "MAXVALUE cannot be made to below the current value");
return OG_ERROR;
}
}
if (def->is_cycle && def->step > 0 && def->is_nomaxval_set) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "cycle must specify maxvalue");
return OG_ERROR;
}
if (def->is_cycle && def->step < 0 && def->is_nominval_set) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "cycle must specify minvalue");
return OG_ERROR;
}
if (def->is_cycle && ((uint64)def->cache > ceil((double)((uint64)def->max_value - def->min_value) / step))) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "number to CACHE must be less than one cycle");
return OG_ERROR;
}
if ((def->is_nocache_set == 0) && (def->is_cache_set == 1) && (def->cache <= 1)) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "CACHE value must be larger than 1");
return OG_ERROR;
}
if (def->is_cycle && ((uint64)def->cache > ceil((double)((uint64)def->max_value - def->min_value) / step))) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "number to CACHE must be less than one cycle");
return OG_ERROR;
}
if (def->step >= 1 && (def->cache > (DDL_ASC_SEQUENCE_DEFAULT_MAX_VALUE / cm_abs64(def->step)))) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "CACHE multiply abs of STEP must be less than DEFAULT MAXVALUE");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t sql_parse_check_param(sql_stmt_t *stmt, knl_sequence_def_t *def)
{
knl_dictionary_t dc_seq;
dc_sequence_t *sequence = NULL;
status_t ret;
if (OG_SUCCESS != dc_seq_open(&stmt->session->knl_session, &def->user, &def->name, &dc_seq)) {
return OG_ERROR;
}
sequence = (dc_sequence_t *)dc_seq.handle;
dls_spin_lock(&stmt->session->knl_session, &sequence->entry->lock, NULL);
if (!sequence->valid || sequence->entry->org_scn > DB_CURR_SCN(KNL_SESSION(stmt))) {
dls_spin_unlock(&stmt->session->knl_session, &sequence->entry->lock);
dc_seq_close(&dc_seq);
OG_THROW_ERROR(ERR_SEQ_NOT_EXIST, T2S(&def->user), T2S_EX(&def->name));
return OG_ERROR;
}
def->step = def->is_step_set ? def->step : sequence->step;
sql_parse_alter_sequence_get_param(def, sequence);
seq_merge_alter_param(def, sequence);
if (def->is_restart_set && !def->is_start_set) {
def->start = (def->step > 0) ? def->min_value : def->max_value;
}
ret = seq_check_alter_param(stmt, def, sequence);
dls_spin_unlock(&stmt->session->knl_session, &sequence->entry->lock);
dc_seq_close(&dc_seq);
return ret;
}
status_t sql_parse_alter_sequence(sql_stmt_t *stmt)
{
word_t word;
knl_sequence_def_t *def = NULL;
lex_t *lex = stmt->session->lex;
status_t status;
lex->flags |= LEX_WITH_OWNER;
status = sql_alloc_mem(stmt->context, sizeof(knl_sequence_def_t), (void **)&def);
OG_RETURN_IFERR(status);
sql_init_create_sequence(stmt, def);
stmt->context->entry = def;
stmt->context->type = OGSQL_TYPE_ALTER_SEQUENCE;
status = lex_expected_fetch_variant(stmt->session->lex, &word);
OG_RETURN_IFERR(status);
if (word.ex_count > 0) {
status = sql_copy_prefix_tenant(stmt, (text_t *)&word.text, &def->user, sql_copy_name);
OG_RETURN_IFERR(status);
status =
sql_copy_object_name(stmt->context, word.ex_words[0].type, (text_t *)&word.ex_words[0].text, &def->name);
OG_RETURN_IFERR(status);
} else {
cm_str2text(stmt->session->curr_schema, &def->user);
status = sql_copy_object_name(stmt->context, word.type, (text_t *)&word.text, &def->name);
OG_RETURN_IFERR(status);
}
status = sql_parse_sequence_parameters(stmt, def, &word, OG_FALSE);
OG_RETURN_IFERR(status);
status = sql_check_sequence_conflict_parameters(stmt, def);
OG_RETURN_IFERR(status);
if (sql_parse_check_param(stmt, def) != OG_SUCCESS) {
sql_check_user_priv(stmt, &def->user);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t sql_parse_drop_sequence(sql_stmt_t *stmt)
{
knl_drop_def_t *def = NULL;
bool32 is_cascade = OG_FALSE;
lex_t *lex = stmt->session->lex;
lex->flags = LEX_WITH_OWNER;
stmt->context->type = OGSQL_TYPE_DROP_SEQUENCE;
if (sql_alloc_mem(stmt->context, sizeof(knl_drop_def_t), (void **)&def) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_parse_drop_object(stmt, def) != OG_SUCCESS) {
return OG_ERROR;
}
stmt->context->entry = def;
if (lex_try_fetch(lex, "CASCADE", &is_cascade) != OG_SUCCESS) {
return OG_ERROR;
}
if (is_cascade) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "cascade option no implement.");
return OG_ERROR;
}
return lex_expected_end(lex);
}
static status_t sql_verify_synonym_def(sql_stmt_t *stmt, knl_synonym_def_t *def)
{
knl_dictionary_t dc;
pl_entry_t *pl_entry = NULL;
bool32 is_tab_found = OG_FALSE;
bool32 found = OG_FALSE;
if (knl_open_dc_if_exists(KNL_SESSION(stmt), &def->table_owner, &def->table_name, &dc, &is_tab_found) !=
OG_SUCCESS) {
return OG_ERROR;
}
if (IS_LTT_BY_NAME(def->table_name.str)) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "Prevent creating synonyms of local temporary tables");
return OG_ERROR;
}
if (!is_tab_found) {
if (pl_find_entry(KNL_SESSION(stmt), &def->table_owner, &def->table_name, PL_SYN_LINK_TYPE, &pl_entry,
&found) != OG_SUCCESS) {
return OG_ERROR;
}
if (!found) {
OG_THROW_ERROR(ERR_USER_OBJECT_NOT_EXISTS, "The object", T2S(&def->table_owner), T2S_EX(&def->table_name));
return OG_ERROR;
}
def->is_knl_syn = OG_FALSE;
} else {
if (SYNONYM_EXIST(&dc) || dc.type > DICT_TYPE_GLOBAL_DYNAMIC_VIEW) {
OG_THROW_ERROR(ERR_INVALID_SYNONYM_OBJ_TYPE, T2S(&def->table_owner), T2S_EX(&def->table_name));
knl_close_dc(&dc);
return OG_ERROR;
}
def->ref_uid = dc.uid;
def->ref_oid = dc.oid;
def->ref_org_scn = dc.org_scn;
def->ref_chg_scn = dc.chg_scn;
def->ref_dc_type = dc.type;
def->is_knl_syn = OG_TRUE;
knl_close_dc(&dc);
}
return OG_SUCCESS;
}
static inline status_t sql_convert_object_name_ex(sql_stmt_t *stmt, word_t *word, bool32 is_public, text_t *owner,
text_t *name)
{
status_t status;
text_t public_user = { PUBLIC_USER, (uint32)strlen(PUBLIC_USER) };
sql_copy_func_t sql_copy_func;
sql_copy_func = sql_copy_name;
if (word->ex_count == 1) {
if (is_public) {
if (cm_compare_text_str_ins((text_t *)&word->text, PUBLIC_USER) != 0) {
OG_SRC_THROW_ERROR_EX(word->text.loc, ERR_SQL_SYNTAX_ERROR,
"owner of object should be public, but is %s", T2S((text_t *)&word->text));
return OG_ERROR;
}
OG_RETURN_IFERR(sql_copy_func(stmt->context, &public_user, owner));
} else {
status = sql_copy_prefix_tenant(stmt, (text_t *)&word->text, owner, sql_copy_func);
OG_RETURN_IFERR(status);
}
status = sql_copy_object_name(stmt->context, word->ex_words[0].type, (text_t *)&word->ex_words[0].text, name);
OG_RETURN_IFERR(status);
} else {
if (is_public) {
OG_RETURN_IFERR(sql_copy_text(stmt->context, &public_user, owner));
} else {
cm_str2text(stmt->session->curr_schema, owner);
}
status = sql_copy_object_name(stmt->context, word->type, (text_t *)&word->text, name);
OG_RETURN_IFERR(status);
}
return OG_SUCCESS;
}
status_t sql_parse_create_synonym(sql_stmt_t *stmt, uint32 flags)
{
bool32 is_public = (flags & SYNONYM_IS_PUBLIC) ? OG_TRUE : OG_FALSE;
word_t word;
knl_synonym_def_t *def = NULL;
lex_t *lex = stmt->session->lex;
if (sql_alloc_mem(stmt->context, sizeof(knl_synonym_def_t), (pointer_t *)&def) != OG_SUCCESS) {
return OG_ERROR;
}
def->flags = flags;
stmt->context->type = OGSQL_TYPE_CREATE_SYNONYM;
lex->flags |= LEX_WITH_OWNER;
if (lex_expected_fetch_variant(lex, &word) != OG_SUCCESS) {
return OG_ERROR;
}
if (OG_SUCCESS != sql_convert_object_name_ex(stmt, &word, is_public, &def->owner, &def->name)) {
return OG_ERROR;
}
if (lex_expected_fetch_word(lex, "for") != OG_SUCCESS) {
return OG_ERROR;
}
if (lex_expected_fetch_variant(lex, &word) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_convert_object_name(stmt, &word, &def->table_owner, NULL, &def->table_name) != OG_SUCCESS) {
return OG_ERROR;
}
if (OG_SUCCESS != lex_expected_end(lex)) {
return OG_ERROR;
}
if (sql_verify_synonym_def(stmt, def) != OG_SUCCESS) {
sql_check_user_priv(stmt, &def->table_owner);
return OG_ERROR;
}
stmt->context->entry = def;
return OG_SUCCESS;
}
status_t sql_parse_drop_synonym(sql_stmt_t *stmt, uint32 flags)
{
bool32 result = OG_FALSE;
bool32 is_public = (flags & SYNONYM_IS_PUBLIC) ? OG_TRUE : OG_FALSE;
word_t word;
knl_drop_def_t *def = NULL;
lex_t *lex = stmt->session->lex;
if (sql_alloc_mem(stmt->context, sizeof(knl_drop_def_t), (pointer_t *)&def) != OG_SUCCESS) {
return OG_ERROR;
}
stmt->context->type = OGSQL_TYPE_DROP_SYNONYM;
lex->flags |= LEX_WITH_OWNER;
if (sql_try_parse_if_exists(lex, &def->options) != OG_SUCCESS) {
return OG_ERROR;
}
if (lex_expected_fetch_variant(lex, &word) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_convert_object_name_ex(stmt, &word, is_public, &def->owner, &def->name) != OG_SUCCESS) {
return OG_ERROR;
}
if (lex_try_fetch(lex, "force", &result) != OG_SUCCESS) {
return OG_ERROR;
}
if (result) {
def->options |= DROP_CASCADE_CONS;
}
stmt->context->entry = def;
return lex_expected_end(lex);
}
static status_t og_apply_sequence_option(knl_sequence_def_t *sequence_def, createseq_opt *opt, bool32 allow_restart)
{
switch (opt->type) {
case CREATESEQ_INCREMENT_OPT:
if (sequence_def->is_step_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate INCREMENT specifications");
return OG_ERROR;
}
if (opt->value == 0) {
OG_THROW_ERROR(ERR_SEQ_INVALID, "sequence INCREMENT must be a non-zero integer");
return OG_ERROR;
}
sequence_def->step = opt->value;
sequence_def->is_step_set = 1;
break;
case CREATESEQ_MINVALUE_OPT:
if (sequence_def->is_minval_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate MINVALUE specifications");
return OG_ERROR;
}
sequence_def->min_value = opt->value;
sequence_def->nominval = OG_FALSE;
sequence_def->is_minval_set = 1;
break;
case CREATESEQ_NOMINVALUE_OPT:
if (sequence_def->is_nominval_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate NO_MINVALUE specifications");
return OG_ERROR;
}
sequence_def->nominval = OG_TRUE;
sequence_def->is_nominval_set = 1;
break;
case CREATESEQ_MAXVALUE_OPT:
if (sequence_def->is_maxval_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate MAXVALUE specifications");
return OG_ERROR;
}
sequence_def->max_value = opt->value;
sequence_def->nomaxval = OG_FALSE;
sequence_def->is_maxval_set = 1;
break;
case CREATESEQ_NOMAXVALUE_OPT:
if (sequence_def->is_nomaxval_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate NO_MAXVALUE specifications");
return OG_ERROR;
}
sequence_def->nomaxval = OG_TRUE;
sequence_def->is_nomaxval_set = 1;
break;
case CREATESEQ_START_OPT:
if (sequence_def->is_start_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate START specifications");
return OG_ERROR;
}
sequence_def->start = opt->value;
sequence_def->is_start_set = OG_TRUE;
break;
case CREATESEQ_CACHE_OPT:
if (sequence_def->is_cache_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate CACHE specifications");
return OG_ERROR;
}
sequence_def->cache = opt->value;
sequence_def->is_cache_set = 1;
break;
case CREATESEQ_NOCACHE_OPT:
if (sequence_def->is_nocache_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate NO_CACHE specifications");
return OG_ERROR;
}
sequence_def->nocache = OG_TRUE;
sequence_def->is_nocache_set = 1;
break;
case CREATESEQ_CYCLE_OPT:
if (sequence_def->is_cycle_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate or conflicting CYCLE/NOCYCLE specifications");
return OG_ERROR;
}
sequence_def->is_cycle = OG_TRUE;
sequence_def->is_cycle_set = 1;
break;
case CREATESEQ_NOCYCLE_OPT:
if (sequence_def->is_cycle_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate or conflicting CYCLE/NOCYCLE specifications");
return OG_ERROR;
}
sequence_def->is_cycle = OG_FALSE;
sequence_def->is_cycle_set = 1;
break;
case CREATESEQ_ORDER_OPT:
if (sequence_def->is_order_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate or conflicting ORDER/NOORDER specifications");
return OG_ERROR;
}
sequence_def->is_order = OG_TRUE;
sequence_def->is_order_set = 1;
break;
case CREATESEQ_NOORDER_OPT:
if (sequence_def->is_order_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate or conflicting ORDER/NOORDER specifications");
return OG_ERROR;
}
sequence_def->is_order = OG_FALSE;
sequence_def->is_order_set = 1;
break;
case CREATESEQ_RESTART_OPT:
if (!allow_restart) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "syntax error in sequence statement");
return OG_ERROR;
}
if (sequence_def->is_restart_set == OG_TRUE) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "duplicate RESTART specifications");
return OG_ERROR;
}
sequence_def->is_restart_set = OG_TRUE;
break;
default:
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "syntax error in sequence statement");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t og_apply_sequence_options(knl_sequence_def_t *sequence_def, galist_t *seq_opts, bool32 allow_restart)
{
createseq_opt *opt = NULL;
if (seq_opts == NULL) {
return OG_SUCCESS;
}
for (uint32 i = 0; i < seq_opts->count; i++) {
opt = (createseq_opt *)cm_galist_get(seq_opts, i);
OG_RETURN_IFERR(og_apply_sequence_option(sequence_def, opt, allow_restart));
}
return OG_SUCCESS;
}
status_t og_parse_create_sequence(sql_stmt_t *stmt, knl_sequence_def_t **def, name_with_owner *seq_name,
galist_t *seq_opts)
{
status_t status;
knl_sequence_def_t *sequence_def = NULL;
stmt->context->type = OGSQL_TYPE_CREATE_SEQUENCE;
status = sql_alloc_mem(stmt->context, sizeof(knl_sequence_def_t), (void **)def);
OG_RETURN_IFERR(status);
sequence_def = *def;
sql_init_create_sequence(stmt, sequence_def);
if (seq_name->owner.len == 0) {
cm_str2text(stmt->session->curr_schema, &sequence_def->user);
} else {
sequence_def->user = seq_name->owner;
}
sequence_def->name = seq_name->name;
status = og_apply_sequence_options(sequence_def, seq_opts, OG_FALSE);
OG_RETURN_IFERR(status);
status = sql_check_sequence_parameters_relation(stmt, sequence_def);
OG_RETURN_IFERR(status);
status = sql_format_sequence(stmt, sequence_def);
OG_RETURN_IFERR(status);
return OG_SUCCESS;
}
status_t og_parse_alter_sequence(sql_stmt_t *stmt, knl_sequence_def_t **def, name_with_owner *seq_name,
galist_t *seq_opts)
{
status_t status;
knl_sequence_def_t *sequence_def = NULL;
stmt->context->type = OGSQL_TYPE_ALTER_SEQUENCE;
status = sql_alloc_mem(stmt->context, sizeof(knl_sequence_def_t), (void **)def);
OG_RETURN_IFERR(status);
sequence_def = *def;
sql_init_create_sequence(stmt, sequence_def);
stmt->context->entry = sequence_def;
if (seq_name->owner.len == 0) {
cm_str2text(stmt->session->curr_schema, &sequence_def->user);
} else {
sequence_def->user = seq_name->owner;
}
sequence_def->name = seq_name->name;
status = og_apply_sequence_options(sequence_def, seq_opts, OG_TRUE);
OG_RETURN_IFERR(status);
status = sql_check_sequence_conflict_parameters(stmt, sequence_def);
OG_RETURN_IFERR(status);
if (sql_parse_check_param(stmt, sequence_def) != OG_SUCCESS) {
sql_check_user_priv(stmt, &sequence_def->user);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t og_parse_create_synonym(sql_stmt_t *stmt, knl_synonym_def_t **def, name_with_owner *synonym_name,
name_with_owner *object_name, uint32 flags)
{
status_t status;
knl_synonym_def_t *synonym_def = NULL;
text_t public_user = { PUBLIC_USER, (uint32)strlen(PUBLIC_USER) };
bool32 is_public = (flags & SYNONYM_IS_PUBLIC) ? OG_TRUE : OG_FALSE;
stmt->context->type = OGSQL_TYPE_CREATE_SYNONYM;
status = sql_alloc_mem(stmt->context, sizeof(knl_synonym_def_t), (void **)def);
OG_RETURN_IFERR(status);
synonym_def = *def;
synonym_def->flags = flags;
if (synonym_name->owner.len != 0) {
if (is_public) {
if (cm_compare_text_str_ins(&synonym_name->owner, PUBLIC_USER) != 0) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "owner of object should be public");
return OG_ERROR;
}
if (sql_copy_name(stmt->context, &public_user, &synonym_def->owner) != OG_SUCCESS) {
return OG_ERROR;
}
} else if (sql_copy_prefix_tenant(stmt, &synonym_name->owner, &synonym_def->owner,
sql_copy_name) != OG_SUCCESS) {
return OG_ERROR;
}
synonym_def->name = synonym_name->name;
} else {
if (is_public && sql_copy_text(stmt->context, &public_user, &synonym_def->owner) != OG_SUCCESS) {
return OG_ERROR;
} else if (!is_public) {
cm_str2text(stmt->session->curr_schema, &synonym_def->owner);
}
synonym_def->name = synonym_name->name;
}
if (object_name->owner.len > 0) {
synonym_def->table_owner = object_name->owner;
} else {
cm_str2text(stmt->session->curr_schema, &synonym_def->table_owner);
}
synonym_def->table_name = object_name->name;
if (sql_verify_synonym_def(stmt, synonym_def) != OG_SUCCESS) {
sql_check_user_priv(stmt, &synonym_def->table_owner);
return OG_ERROR;
}
return OG_SUCCESS;
}