* 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_parser.c
*
*
* IDENTIFICATION
* src/ogsql/parser/ogsql_parser.c
*
* -------------------------------------------------------------------------
*/
#include "ogsql_parser.h"
#include "dml_parser.h"
#include "ddl_parser.h"
#include "dcl_parser.h"
#include "srv_instance.h"
#include "pl_compiler.h"
#include "pl_executor.h"
#include "ogsql_audit.h"
#include "dml_executor.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SQL_REFORM_CALL_HEAD_SIZE 6
#define SQL_COMMENT_MARK_LEN 2
#define SQL_LABEL_MARK_LEN 2
typedef struct st_sql_bison_diag_keyword {
const char *name;
key_wid_t id;
} sql_bison_diag_keyword_t;
static const sql_bison_diag_keyword_t g_sql_bison_diag_keywords[] = {
{ "alter", KEY_WORD_ALTER },
{ "analyze", KEY_WORD_ANALYZE },
{ "backup", KEY_WORD_BACKUP },
{ "begin", KEY_WORD_BEGIN },
{ "build", KEY_WORD_BUILD },
{ "call", KEY_WORD_CALL },
{ "comment", KEY_WORD_COMMENT },
{ "commit", KEY_WORD_COMMIT },
{ "create", KEY_WORD_CREATE },
{ "declare", KEY_WORD_DECLARE },
{ "delete", KEY_WORD_DELETE },
{ "drop", KEY_WORD_DROP },
{ "end", KEY_WORD_END },
{ "exec", KEY_WORD_EXEC },
{ "execute", KEY_WORD_EXECUTE },
{ "explain", KEY_WORD_EXPLAIN },
{ "flashback", KEY_WORD_FLASHBACK },
{ "grant", KEY_WORD_GRANT },
{ "insert", KEY_WORD_INSERT },
{ "lock", KEY_WORD_LOCK },
{ "merge", KEY_WORD_MERGE },
{ "ograc", KEY_WORD_OGRAC },
{ "prepare", KEY_WORD_PREPARE },
{ "purge", KEY_WORD_PURGE },
{ "recover", KEY_WORD_RECOVER },
{ "release", KEY_WORD_RELEASE },
{ "repair_copyctrl", KEY_WORD_REPAIR_COPYCTRL },
{ "repair_page", KEY_WORD_REPAIR_PAGE },
{ "replace", KEY_WORD_REPLACE },
{ "restore", KEY_WORD_RESTORE },
{ "revoke", KEY_WORD_REVOKE },
{ "rollback", KEY_WORD_ROLLBACK },
{ "savepoint", KEY_WORD_SAVEPOINT },
{ "select", KEY_WORD_SELECT },
{ "session", KEY_WORD_SESSION },
{ "set", KEY_WORD_SET },
{ "shutdown", KEY_WORD_SHUTDOWN },
{ "start", KEY_WORD_START },
#ifdef DB_DEBUG_VERSION
{ "syncpoint", KEY_WORD_SYNCPOINT },
#endif
{ "system", KEY_WORD_SYSTEM },
{ "transaction", KEY_WORD_TRANSACTION },
{ "truncate", KEY_WORD_TRUNCATE },
{ "update", KEY_WORD_UPDATE },
{ "validate", KEY_WORD_VALIDATE },
{ "with", KEY_WORD_WITH },
};
static void sql_skip_blank_chars(text_t *text, uint32 *pos)
{
while (*pos < text->len && cm_is_space((int)text->str[*pos])) {
(*pos)++;
}
}
static bool32 sql_is_name_char(char ch)
{
return (bool32)(CM_IS_NAMING_LETER(ch) || CM_IS_DIGIT(ch) || ch == '$' || ch == '#' || ch == '_');
}
static status_t sql_read_call_name_part(text_t *text, uint32 *pos, text_t *part)
{
uint32 start;
part->str = NULL;
part->len = 0;
sql_skip_blank_chars(text, pos);
if (*pos >= text->len) {
return OG_SUCCESS;
}
if (text->str[*pos] == '"') {
(*pos)++;
start = *pos;
while (*pos < text->len && text->str[*pos] != '"') {
(*pos)++;
}
if (*pos >= text->len) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "invalid quoted procedure name");
return OG_ERROR;
}
part->str = text->str + start;
part->len = *pos - start;
(*pos)++;
return OG_SUCCESS;
}
start = *pos;
while (*pos < text->len) {
char ch = text->str[*pos];
if (!sql_is_name_char(ch)) {
break;
}
(*pos)++;
}
if (*pos > start) {
part->str = text->str + start;
part->len = *pos - start;
}
return OG_SUCCESS;
}
sql_text_t *sql_current_parse_text(sql_stmt_t *stmt)
{
if (g_instance->sql.use_bison_parser && stmt->parser_text_valid) {
return &stmt->parser_text;
}
return &stmt->session->lex->text;
}
static void sql_bison_skip_comment(text_t *sql, uint32 *pos)
{
if (*pos + 1 >= sql->len) {
return;
}
if (sql->str[*pos] == '-' && sql->str[*pos + 1] == '-') {
*pos += SQL_COMMENT_MARK_LEN;
while (*pos < sql->len && sql->str[*pos] != '\n') {
(*pos)++;
}
return;
}
if (sql->str[*pos] == '/' && sql->str[*pos + 1] == '*') {
*pos += SQL_COMMENT_MARK_LEN;
while (*pos + 1 < sql->len) {
if (sql->str[*pos] == '*' && sql->str[*pos + 1] == '/') {
*pos += SQL_COMMENT_MARK_LEN;
return;
}
(*pos)++;
}
}
}
static void sql_bison_skip_blank_and_comments(text_t *sql, uint32 *pos)
{
while (*pos < sql->len) {
while (*pos < sql->len && cm_is_space((int)sql->str[*pos])) {
(*pos)++;
}
if (*pos + 1 >= sql->len ||
!((sql->str[*pos] == '-' && sql->str[*pos + 1] == '-') ||
(sql->str[*pos] == '/' && sql->str[*pos + 1] == '*'))) {
return;
}
sql_bison_skip_comment(sql, pos);
}
}
static key_wid_t sql_bison_keyword_id(text_t *word)
{
for (uint32 i = 0; i < ELEMENT_COUNT(g_sql_bison_diag_keywords); i++) {
if (cm_text_str_equal_ins(word, g_sql_bison_diag_keywords[i].name)) {
return g_sql_bison_diag_keywords[i].id;
}
}
return KEY_WORD_0_UNKNOWN;
}
static void sql_bison_read_word(sql_text_t *sql_text, uint32 *pos, word_t *word)
{
text_t sql = sql_text->value;
uint32 start;
key_wid_t key_wid;
*word = (word_t){ 0 };
sql_bison_skip_blank_and_comments(&sql, pos);
word->loc = sql_text->loc;
word->text.loc = sql_text->loc;
if (*pos >= sql.len) {
word->type = WORD_TYPE_EOF;
return;
}
start = *pos;
if (sql.str[*pos] == '(') {
word->type = WORD_TYPE_BRACKET;
word->id = KEY_WORD_SELECT;
word->text.str = sql.str + start;
word->text.len = sql.len - start;
return;
}
if (*pos + 1 < sql.len && sql.str[*pos] == '<' && sql.str[*pos + 1] == '<') {
word->type = WORD_TYPE_KEYWORD;
word->id = KEY_WORD_DECLARE;
word->text.str = sql.str + start;
word->text.len = SQL_LABEL_MARK_LEN;
*pos += SQL_LABEL_MARK_LEN;
return;
}
while (*pos < sql.len && sql_is_name_char(sql.str[*pos])) {
(*pos)++;
}
word->text.str = sql.str + start;
word->text.len = *pos - start;
key_wid = sql_bison_keyword_id(&word->text.value);
word->id = key_wid;
word->type = (key_wid == KEY_WORD_0_UNKNOWN) ? WORD_TYPE_VARIANT : WORD_TYPE_KEYWORD;
}
static lang_type_t sql_diag_begin_type_bison(sql_text_t *sql, uint32 pos)
{
word_t word;
sql_bison_read_word(sql, &pos, &word);
if (word.type == WORD_TYPE_EOF || word.id == KEY_WORD_TRANSACTION) {
return LANG_DCL;
}
return LANG_PL;
}
static lang_type_t sql_diag_alter_type_bison(sql_text_t *sql, uint32 pos)
{
word_t word;
sql_bison_read_word(sql, &pos, &word);
if (word.id == KEY_WORD_SYSTEM || word.id == KEY_WORD_SESSION) {
return LANG_DCL;
}
return LANG_DDL;
}
static lang_type_t sql_diag_direct_lang_type_bison(key_wid_t word_id)
{
switch (word_id) {
case KEY_WORD_SELECT:
case KEY_WORD_INSERT:
case KEY_WORD_UPDATE:
case KEY_WORD_DELETE:
case KEY_WORD_MERGE:
case KEY_WORD_WITH:
case KEY_WORD_REPLACE:
return LANG_DML;
case KEY_WORD_EXPLAIN:
return LANG_EXPLAIN;
case KEY_WORD_DECLARE:
case KEY_WORD_CALL:
case KEY_WORD_EXEC:
case KEY_WORD_EXECUTE:
return LANG_PL;
default:
return LANG_INVALID;
}
}
static bool32 sql_diag_is_ddl_bison(key_wid_t word_id)
{
switch (word_id) {
case KEY_WORD_CREATE:
case KEY_WORD_DROP:
case KEY_WORD_TRUNCATE:
case KEY_WORD_FLASHBACK:
case KEY_WORD_PURGE:
case KEY_WORD_COMMENT:
case KEY_WORD_GRANT:
case KEY_WORD_REVOKE:
case KEY_WORD_ANALYZE:
return OG_TRUE;
default:
return OG_FALSE;
}
}
static bool32 sql_diag_is_dcl_bison(key_wid_t word_id)
{
switch (word_id) {
case KEY_WORD_START:
case KEY_WORD_END:
case KEY_WORD_PREPARE:
case KEY_WORD_COMMIT:
case KEY_WORD_SAVEPOINT:
case KEY_WORD_RELEASE:
case KEY_WORD_SET:
case KEY_WORD_ROLLBACK:
case KEY_WORD_BACKUP:
case KEY_WORD_RESTORE:
case KEY_WORD_RECOVER:
case KEY_WORD_OGRAC:
case KEY_WORD_SHUTDOWN:
case KEY_WORD_BUILD:
case KEY_WORD_VALIDATE:
case KEY_WORD_REPAIR_PAGE:
case KEY_WORD_REPAIR_COPYCTRL:
#ifdef DB_DEBUG_VERSION
case KEY_WORD_SYNCPOINT:
#endif
case KEY_WORD_LOCK:
return OG_TRUE;
default:
return OG_FALSE;
}
}
static lang_type_t sql_diag_lang_type_bison(sql_text_t *sql, word_t *leader_word)
{
uint32 pos = 0;
lang_type_t lang_type;
sql_bison_read_word(sql, &pos, leader_word);
if (leader_word->type == WORD_TYPE_EOF) {
return LANG_INVALID;
}
lang_type = sql_diag_direct_lang_type_bison(leader_word->id);
if (lang_type != LANG_INVALID) {
return lang_type;
}
if (leader_word->id == KEY_WORD_BEGIN) {
return sql_diag_begin_type_bison(sql, pos);
}
if (leader_word->id == KEY_WORD_ALTER) {
return sql_diag_alter_type_bison(sql, pos);
}
if (sql_diag_is_ddl_bison(leader_word->id)) {
return LANG_DDL;
}
return sql_diag_is_dcl_bison(leader_word->id) ? LANG_DCL : LANG_INVALID;
}
static status_t sql_aud_proc_check_text(sql_stmt_t *stmt, word_t *leader)
{
text_t clean_aud_log_name = {
.str = "AUD$CLEAN_AUD_LOG",
.len = 17
};
text_t modify_setting_name = {
.str = "AUD$MODIFY_SETTING",
.len = 18
};
text_t sys_user_name = {
.str = SYS_USER_NAME,
.len = SYS_USER_NAME_LEN
};
text_t *curr_user = &stmt->session->curr_user;
text_t sql = sql_current_parse_text(stmt)->value;
text_t first;
text_t second;
text_t owner;
text_t name;
char owner_buf[OG_NAME_BUFFER_SIZE];
uint32 pos = (uint32)((leader->text.value.str + leader->text.value.len) - sql.str);
OG_RETURN_IFERR(sql_read_call_name_part(&sql, &pos, &first));
if (first.len == 0 || cm_text_str_equal_ins(&first, "immediate")) {
return OG_SUCCESS;
}
sql_skip_blank_chars(&sql, &pos);
if (pos < sql.len && sql.str[pos] == '.') {
pos++;
OG_RETURN_IFERR(sql_read_call_name_part(&sql, &pos, &second));
if (second.len == 0) {
return OG_SUCCESS;
}
OG_RETURN_IFERR(cm_text2str(&first, owner_buf, OG_NAME_BUFFER_SIZE));
OG_RETURN_IFERR(sql_user_prefix_tenant(stmt->session, owner_buf));
cm_str2text_safe(owner_buf, (uint32)strlen(owner_buf), &owner);
name = second;
} else {
owner.str = stmt->session->curr_schema;
owner.len = (uint32)strlen(stmt->session->curr_schema);
name = first;
}
if ((cm_compare_text_ins(&name, &modify_setting_name) == 0) ||
(cm_compare_text_ins(&name, &clean_aud_log_name) == 0)) {
if (cm_compare_text_ins(&owner, &sys_user_name) == 0) {
if (cm_compare_text_ins(curr_user, &sys_user_name) != 0) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "The common user can't call this procedure, only for sys.");
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t sql_reform_call(sql_stmt_t *stmt)
{
sql_text_t origin_sql;
uint32 buf_len = stmt->session->lex->curr_text->len + (uint32)strlen("begin\n") + (uint32)strlen(";\nend;\n/");
char *buffer = NULL;
OG_RETURN_IFERR(sql_push(stmt, buf_len, (void **)&buffer));
text_t sql = {
.str = buffer,
.len = 0
};
source_location_t loc = {
.line = 0,
.column = 1
};
status_t status;
origin_sql = stmt->session->lex->text;
cm_concat_string(&sql, buf_len, "begin\n");
cm_concat_text(&sql, buf_len, &stmt->session->lex->curr_text->value);
cm_concat_string(&sql, buf_len, ";\nend;\n/");
stmt->is_reform_call = OG_TRUE;
stmt->text_shift =
(int32)(stmt->session->lex->curr_text->str - stmt->session->lex->text.str) - SQL_REFORM_CALL_HEAD_SIZE;
status = sql_parse(stmt, &sql, &loc);
stmt->session->sql_audit.sql = origin_sql.value;
return status;
}
static status_t sql_aud_proc_check(sql_stmt_t *stmt, word_t *leader)
{
text_t clean_aud_log_name = {
.str = "AUD$CLEAN_AUD_LOG",
.len = 17
};
text_t modify_setting_name = {
.str = "AUD$MODIFY_SETTING",
.len = 18
};
text_t sys_user_name = {
.str = SYS_USER_NAME,
.len = SYS_USER_NAME_LEN
};
text_t *curr_user = &stmt->session->curr_user;
text_t owner;
text_t name;
char buffer[OG_NAME_BUFFER_SIZE];
lex_t *lex = stmt->session->lex;
word_t word;
LEX_SAVE(lex);
uint32 prev_flags = lex->flags;
lex->flags = LEX_WITH_OWNER;
OG_RETURN_IFERR(lex_expected_fetch_variant(lex, &word));
if (word.ex_count == 1) {
OG_RETURN_IFERR(cm_text2str(&word.text.value, buffer, OG_MAX_NAME_LEN));
OG_RETURN_IFERR(sql_user_prefix_tenant(stmt->session, buffer));
cm_str2text_safe(buffer, (uint32)strlen(buffer), &owner);
name = word.ex_words[0].text.value;
} else if (word.ex_count == 0) {
owner.str = stmt->session->curr_schema;
owner.len = (uint32)strlen(stmt->session->curr_schema);
name = word.text.value;
} else {
LEX_RESTORE(lex);
lex->flags = prev_flags;
return OG_SUCCESS;
}
if ((cm_compare_text_ins(&name, &modify_setting_name) == 0) ||
(cm_compare_text_ins(&name, &clean_aud_log_name) == 0)) {
if (cm_compare_text_ins(&owner, &sys_user_name) == 0) {
if (cm_compare_text_ins(curr_user, &sys_user_name) != 0) {
LEX_RESTORE(lex);
lex->flags = prev_flags;
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR, "The common user can't call this procedure, only for sys.");
return OG_ERROR;
}
}
}
LEX_RESTORE(lex);
lex->flags = prev_flags;
return OG_SUCCESS;
}
static status_t sql_parse_anonymous(sql_stmt_t *stmt, word_t *leader)
{
if (!GET_PL_MGR->initialized) {
OG_THROW_ERROR(ERR_DATABASE_NOT_AVAILABLE);
return OG_ERROR;
}
{
OG_RETURN_IFERR(sql_parse_anonymous_directly(stmt, leader, &stmt->session->lex->text));
}
return OG_SUCCESS;
}
static status_t sql_parse_pl_bison_text(sql_stmt_t *stmt, sql_text_t *sql_text)
{
status_t status;
text_t origin_sql = sql_text->value;
if (!GET_PL_MGR->initialized) {
OG_THROW_ERROR(ERR_DATABASE_NOT_AVAILABLE);
return OG_ERROR;
}
OG_RETURN_IFERR(sql_alloc_context(stmt));
OG_RETURN_IFERR(sql_create_list(stmt, &stmt->context->params));
OG_RETURN_IFERR(sql_create_list(stmt, &stmt->context->ref_objects));
status = raw_parser(stmt, sql_text, &stmt->context->entry);
if (status != OG_SUCCESS) {
return status;
}
if (!SQL_OPT_PWD_DDL_TYPE(stmt->context->type)) {
OG_RETURN_IFERR(ogx_write_text(&stmt->context->ctrl, &origin_sql));
stmt->context->ctrl.hash_value = cm_hash_text(&origin_sql, INFINITE_HASH_RANGE);
}
return OG_SUCCESS;
}
static status_t sql_parse_pl_bison(sql_stmt_t *stmt)
{
return sql_parse_pl_bison_text(stmt, sql_current_parse_text(stmt));
}
static status_t sql_reform_pl_text_bison(sql_stmt_t *stmt, text_t *body, source_location_t loc, int32 text_shift)
{
sql_text_t reform_sql = { 0 };
uint32 buf_len = body->len + (uint32)strlen("begin\n") + (uint32)strlen(";\nend;\n/");
char *buffer = NULL;
status_t status;
OG_RETURN_IFERR(sql_push(stmt, buf_len, (void **)&buffer));
reform_sql.str = buffer;
reform_sql.len = 0;
reform_sql.loc = loc;
reform_sql.implicit = OG_FALSE;
cm_concat_string((text_t *)&reform_sql, buf_len, "begin\n");
cm_concat_text((text_t *)&reform_sql, buf_len, body);
cm_concat_string((text_t *)&reform_sql, buf_len, ";\nend;\n/");
stmt->is_reform_call = OG_TRUE;
stmt->text_shift = text_shift;
status = sql_parse_pl_bison_text(stmt, &reform_sql);
stmt->session->sql_audit.sql = sql_current_parse_text(stmt)->value;
return status;
}
static status_t sql_reform_call_bison(sql_stmt_t *stmt, word_t *leader)
{
sql_text_t *origin_sql = sql_current_parse_text(stmt);
uint32 body_offset = (uint32)((leader->text.value.str + leader->text.value.len) - origin_sql->str);
text_t body = {
.str = origin_sql->str + body_offset,
.len = origin_sql->len - body_offset
};
source_location_t loc = {
.line = 0,
.column = 1
};
return sql_reform_pl_text_bison(stmt, &body, loc, (int32)body_offset - SQL_REFORM_CALL_HEAD_SIZE);
}
static status_t sql_reform_execute_immediate_bison(sql_stmt_t *stmt)
{
sql_text_t *origin_sql = sql_current_parse_text(stmt);
source_location_t loc = {
.line = 0,
.column = 1
};
return sql_reform_pl_text_bison(stmt, &origin_sql->value, loc, -SQL_REFORM_CALL_HEAD_SIZE);
}
static bool32 sql_is_execute_immediate(sql_stmt_t *stmt, word_t *leader)
{
sql_text_t *sql_text = sql_current_parse_text(stmt);
text_t sql = sql_text->value;
uint32 pos = (uint32)((leader->text.value.str + leader->text.value.len) - sql.str);
uint32 immediate_len = (uint32)strlen("immediate");
if (leader->id != KEY_WORD_EXECUTE) {
return OG_FALSE;
}
sql_skip_blank_chars(&sql, &pos);
return (bool32)(pos + immediate_len <= sql.len &&
cm_strcmpni(sql.str + pos, "immediate", immediate_len) == 0 &&
(pos + immediate_len == sql.len || !sql_is_name_char(sql.str[pos + immediate_len])));
}
static bool32 sql_need_reform_pl_call(sql_stmt_t *stmt, word_t *leader)
{
return leader->id == KEY_WORD_CALL || leader->id == KEY_WORD_EXEC ||
(leader->id == KEY_WORD_EXECUTE && !sql_is_execute_immediate(stmt, leader));
}
static status_t sql_parse_pl(sql_stmt_t *stmt, word_t *leader)
{
status_t status;
SQL_SET_IGNORE_PWD(stmt->session);
SQL_SET_COPY_LOG(stmt->session, OG_TRUE);
if (leader->id == KEY_WORD_CALL || leader->id == KEY_WORD_EXEC || leader->id == KEY_WORD_EXECUTE) {
if (g_instance->sql.use_bison_parser) {
OG_RETURN_IFERR(sql_aud_proc_check_text(stmt, leader));
} else {
OG_RETURN_IFERR(sql_aud_proc_check(stmt, leader));
}
}
knl_set_session_scn(&stmt->session->knl_session, OG_INVALID_ID64);
stmt->session->sql_audit.audit_type = SQL_AUDIT_PL;
OGSQL_SAVE_STACK(stmt);
if (g_instance->sql.use_bison_parser) {
if (sql_is_execute_immediate(stmt, leader)) {
status = sql_reform_execute_immediate_bison(stmt);
} else {
status = sql_need_reform_pl_call(stmt, leader) ?
sql_reform_call_bison(stmt, leader) : sql_parse_pl_bison(stmt);
}
} else if (sql_need_reform_pl_call(stmt, leader)) {
status = sql_reform_call(stmt);
} else {
status = sql_parse_anonymous(stmt, leader);
}
OGSQL_RESTORE_STACK(stmt);
return status;
}
static lang_type_t sql_diag_begin_type(sql_stmt_t *stmt)
{
word_t word;
if (lex_push(stmt->session->lex, stmt->session->lex->curr_text) != OG_SUCCESS) {
return LANG_INVALID;
}
if (lex_fetch(stmt->session->lex, &word) != OG_SUCCESS) {
lex_pop(stmt->session->lex);
return LANG_INVALID;
}
lex_pop(stmt->session->lex);
if (word.type == WORD_TYPE_EOF || word.id == KEY_WORD_TRANSACTION) {
return LANG_DCL;
}
return LANG_PL;
}
static lang_type_t sql_diag_alter_type(sql_stmt_t *stmt)
{
uint32 matched_id;
if (lex_push(stmt->session->lex, stmt->session->lex->curr_text) != OG_SUCCESS) {
return LANG_DDL;
}
if (lex_try_fetch_1of2(stmt->session->lex, "SYSTEM", "SESSION", &matched_id) != OG_SUCCESS) {
lex_pop(stmt->session->lex);
return LANG_DDL;
} else {
if (matched_id != OG_INVALID_ID32) {
lex_pop(stmt->session->lex);
return LANG_DCL;
}
}
lex_pop(stmt->session->lex);
return LANG_DDL;
}
lang_type_t sql_diag_lang_type(sql_stmt_t *stmt, sql_text_t *sql, word_t *leader_word)
{
if (g_instance->sql.use_bison_parser) {
return sql_diag_lang_type_bison(sql, leader_word);
}
lex_init_for_native_type(stmt->session->lex, sql, &stmt->session->curr_user, stmt->session->call_version,
USE_NATIVE_DATATYPE);
OG_RETVALUE_IFTRUE((lex_fetch(stmt->session->lex, leader_word) != OG_SUCCESS), LANG_INVALID);
if (leader_word->type == WORD_TYPE_BRACKET) {
leader_word->id = KEY_WORD_SELECT;
}
if (IS_PL_LABEL(leader_word)) {
leader_word->id = KEY_WORD_DECLARE;
}
switch (leader_word->id) {
case KEY_WORD_SELECT:
case KEY_WORD_INSERT:
case KEY_WORD_UPDATE:
case KEY_WORD_DELETE:
case KEY_WORD_MERGE:
case KEY_WORD_WITH:
case KEY_WORD_REPLACE:
return LANG_DML;
case KEY_WORD_EXPLAIN:
return LANG_EXPLAIN;
case KEY_WORD_DECLARE:
case KEY_WORD_CALL:
case KEY_WORD_EXEC:
case KEY_WORD_EXECUTE:
return LANG_PL;
case KEY_WORD_BEGIN:
return sql_diag_begin_type(stmt);
case KEY_WORD_START:
case KEY_WORD_END:
return LANG_DCL;
case KEY_WORD_CREATE:
case KEY_WORD_DROP:
case KEY_WORD_TRUNCATE:
case KEY_WORD_FLASHBACK:
case KEY_WORD_PURGE:
case KEY_WORD_COMMENT:
case KEY_WORD_GRANT:
case KEY_WORD_REVOKE:
case KEY_WORD_ANALYZE:
return LANG_DDL;
case KEY_WORD_ALTER:
return sql_diag_alter_type(stmt);
case KEY_WORD_PREPARE:
case KEY_WORD_COMMIT:
case KEY_WORD_SAVEPOINT:
case KEY_WORD_RELEASE:
case KEY_WORD_SET:
case KEY_WORD_ROLLBACK:
case KEY_WORD_BACKUP:
case KEY_WORD_RESTORE:
case KEY_WORD_RECOVER:
case KEY_WORD_OGRAC:
case KEY_WORD_SHUTDOWN:
case KEY_WORD_BUILD:
case KEY_WORD_VALIDATE:
case KEY_WORD_REPAIR_PAGE:
case KEY_WORD_REPAIR_COPYCTRL:
#ifdef DB_DEBUG_VERSION
case KEY_WORD_SYNCPOINT:
#endif
case KEY_WORD_LOCK:
return LANG_DCL;
default:
return LANG_INVALID;
}
}
sql_parser_t g_sql_parser[] = { { LANG_DML, sql_parse_dml },
{ LANG_DCL, sql_parse_dcl },
{ LANG_DDL, sql_parse_ddl },
{ LANG_PL, sql_parse_pl },
{ LANG_EXPLAIN, ogsql_parse_explain_sql } };
static status_t sql_parse_by_lang_type(sql_stmt_t *stmt, sql_text_t *sql_text, word_t *leader_word)
{
status_t status;
if (stmt->lang_type < LANG_MAX && stmt->lang_type != LANG_INVALID) {
status = g_sql_parser[stmt->lang_type - LANG_DML].sql_parse(stmt, leader_word);
} else {
OG_SRC_THROW_ERROR(sql_text->loc, ERR_SQL_SYNTAX_ERROR, "key word expected");
status = OG_ERROR;
}
text_t sql_log_text = stmt->session->sql_audit.sql;
if (LOG_DEBUG_ERR_ON || LOG_DEBUG_INF_ON) {
sql_ignore_passwd_log(stmt->session, &sql_log_text);
}
sql_free_vmemory(stmt);
if (status != OG_SUCCESS) {
sql_unlock_lnk_tabs(stmt);
sql_release_context(stmt);
OBJ_STACK_RESET(&stmt->ssa_stack);
OBJ_STACK_RESET(&stmt->node_stack);
OG_LOG_DEBUG_ERR("Parse SQL failed, SQL = %s", T2S(&sql_log_text));
} else {
OG_LOG_DEBUG_INF("Parse SQL successfully, SQL = %s", T2S(&sql_log_text));
}
return status;
}
static status_t sql_parse_core(sql_stmt_t *stmt, text_t *sql, source_location_t *loc)
{
sql_text_t sql_text;
word_t leader_word;
status_t status;
timeval_t timeval_end;
timeval_t timeval_begin;
sql_text_t parser_text_bak = stmt->parser_text;
bool32 parser_text_valid_bak = stmt->parser_text_valid;
stmt->pl_failed = OG_FALSE;
stmt->session->sql_audit.sql = *sql;
sql_text.value = *sql;
sql_text.loc = *loc;
SQL_SET_COPY_LOG(stmt->session, OG_FALSE);
if (stmt->pl_exec != NULL || stmt->pl_compiler != NULL) {
SQL_SET_COPY_LOG(stmt->session, OG_TRUE);
}
(void)cm_gettimeofday(&timeval_begin);
OGSQL_SAVE_STACK(stmt);
stmt->lang_type = sql_diag_lang_type(stmt, &sql_text, &leader_word);
if (g_instance->sql.use_bison_parser) {
stmt->parser_text = sql_text;
stmt->parser_text_valid = OG_TRUE;
}
status = sql_parse_by_lang_type(stmt, &sql_text, &leader_word);
stmt->parser_text = parser_text_bak;
stmt->parser_text_valid = parser_text_valid_bak;
OGSQL_RESTORE_STACK(stmt);
(void)cm_gettimeofday(&timeval_end);
stmt->session->stat.parses++;
stmt->session->stat.parses_time_elapse += TIMEVAL_DIFF_US(&timeval_begin, &timeval_end);
g_instance->library_cache_info[stmt->lang_type].lang_type = stmt->lang_type;
return status;
}
static inline bool32 sql_bootstrap_use_native_parser(sql_stmt_t *stmt)
{
* initdb/initplsql bootstrap runs before all SYS PL entries and built-in
* package grants are fully visible through dictionary lookups. Keep that
* bootstrap script path on the native parser; after bootstrap the
* USE_BISON_PARSER parameter controls normal SQL parsing.
*/
return g_instance->sql.use_bison_parser && KNL_SESSION(stmt)->bootstrap;
}
status_t sql_parse(sql_stmt_t *stmt, text_t *sql, source_location_t *loc)
{
word_t leader_word;
status_t status;
sql_text_t sql_text = { 0 };
bool32 use_bison_bak = g_instance->sql.use_bison_parser;
bool32 use_native = sql_bootstrap_use_native_parser(stmt);
if (use_native) {
g_instance->sql.use_bison_parser = OG_FALSE;
}
OGSQL_SAVE_STACK(stmt);
sql_text.value = *sql;
sql_text.loc = *loc;
stmt->lang_type = sql_diag_lang_type(stmt, &sql_text, &leader_word);
status = sql_parse_core(stmt, sql, loc);
OGSQL_RESTORE_STACK(stmt);
if (use_native) {
g_instance->sql.use_bison_parser = use_bison_bak;
}
return status;
}
#ifdef __cplusplus
}
#endif