File scanner_support.c¶
File List > cubrid > src > parser > scanner_support.c
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* scanner_support.c - scanner support functions
*/
#ident "$Id$"
#include "config.h"
#include <math.h>
#include "porting.h"
#include "parser_message.h"
#define JP_MAXNAME 256
#include "parser.h"
#include "chartype.h"
#include "language_support.h"
#include "intl_support.h"
#include "csql_grammar_scan.h"
#include "memory_alloc.h"
#include "misc_string.h"
#define IS_WHITE_SPACE(c) (char_isspace2((c)))
#define IS_HINT_ON_TABLE(h) ((h) & (PT_HINT_INDEX_SS | PT_HINT_INDEX_LS))
int parser_input_host_index = 0;
int parser_statement_OK = 0;
PARSER_CONTEXT *this_parser;
int parser_output_host_index = 0;
extern "C"
{
extern int yycolumn;
extern int csql_yyget_lineno ();
}
extern int yycolumn_end;
#if defined(SA_MODE) && !defined(NDEBUG)
#define ENABLE_WRITE_HINT_LOG
#define HINT_GREP_STR (char*)"[HINT] "
/* matching hint information to output*/
struct st_hint_msg
{
int stmt_no;
bool is_print;
int m_alloc;
int m_used;
char *msg_ptr;
char msg_buf[1024];
public:
st_hint_msg ()
{
stmt_no = -1;
is_print = false;
m_alloc = sizeof (msg_buf);
m_used = 0;
msg_ptr = msg_buf;
msg_buf[0] = 0x00;
}
void reset ()
{
m_used = 0;
if (msg_ptr != msg_buf)
{
free (msg_ptr);
msg_ptr = msg_buf;
m_alloc = sizeof (msg_buf);
}
msg_buf[0] = 0x00;
}
void check_buffer (int size)
{
size++; /* for '\0' */
if ((m_alloc - m_used) <= size)
{
char *ptr = NULL;
int new_alloc_sz = m_alloc;
do
{
new_alloc_sz += 1024 /* 1 KB */ ;
}
while (new_alloc_sz <= (m_used + size));
ptr = (char *) malloc (new_alloc_sz);
assert (ptr != NULL);
memcpy (ptr, msg_ptr, m_used);
if (msg_ptr != msg_buf)
{
free (msg_ptr);
}
msg_ptr = ptr;
m_alloc = new_alloc_sz;
}
}
void add_fmt_string (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
int count = vsnprintf (NULL, 0, fmt, ap);
va_end (ap);
if (count > 0)
{
check_buffer (count);
va_start (ap, fmt);
m_used += vsprintf (msg_ptr + m_used, fmt, ap);
va_end (ap);
}
}
void add_hint_string (char *hint_str)
{
char *ps = hint_str;
char *p;
bool is_first = true;
while (*ps)
{
while (char_isspace (*ps))
{
ps++;
}
for (p = ps; *p; p++)
{
if (*p == '\n')
{
*p = '\0'; // cut
if (is_first)
{
add_fmt_string ((const char *) "%-10s %6s %s\n", HINT_GREP_STR, "Input)", ps);
is_first = false;
}
else
{
add_fmt_string ((const char *) "%-10s %6s %s\n", HINT_GREP_STR, " ", ps);
}
*p = '\n'; // recover
ps = p + 1;
break;
}
}
if (*p == '\0')
{
if (is_first)
{
add_fmt_string ((const char *) "%-10s %6s %s\n", HINT_GREP_STR, "Input)", ps);
}
else
{
add_fmt_string ((const char *) "%-10s %6s %s\n", HINT_GREP_STR, " ", ps);
}
return;
}
}
}
}; // struct st_hint_msg
static void write_hint_2_logfile ();
static void print_hit_hint_string (PT_HINT * hint_table);
static struct st_hint_msg s_hint_msg;
#define ADD_HINT_STRING(...) s_hint_msg.add_fmt_string (__VA_ARGS__)
#else
#define ADD_HINT_STRING(...)
#endif //#if defined(SA_MODE) && !defined(NDEBUG)
#define HINT_LEAD_CHAR_SIZE (129)
static u_char hint_table_lead_offset[HINT_LEAD_CHAR_SIZE] = { 0, };
/*
* pt_makename () -
* return:
* name(in):
*/
char *
pt_makename (const char *name)
{
return pt_append_string (this_parser, NULL, name);
}
/*
* pt_makename_trim_as_identifier () - trim double quotes,
* square brackets, or backtick symbol
* return:
* name(in):
*/
static char *
pt_makename_trim_as_identifier (char *name)
{
char *tmp_name, *pnew, chBk;
size_t len;
len = strlen (name);
if (len >= 2
&& ((name[0] == '[' && name[len - 1] == ']') || (name[0] == '`' && name[len - 1] == '`')
|| (name[0] == '"' && name[len - 1] == '"')))
{
chBk = name[len - 1];
name[len - 1] = '\0';
pnew = pt_makename (name + 1);
name[len - 1] = chBk;
return pnew;
}
else
{
return pt_makename (name);
}
}
/*
* pt_parser_line_col () - set line and column of node allocated to
* current parse position
* return:
* node(in): a PT_NODE ptr
*/
void
pt_parser_line_col (PT_NODE * node)
{
if (node == NULL)
return;
node->line_number = csql_yyget_lineno ();
node->column_number = yycolumn;
}
/*
* pt_nextchar () - called by the scanner
* return: c the next character from input. -1 at end of file
*/
int
pt_nextchar (void)
{
int c = (this_parser->next_char) (this_parser);
return c;
}
static int
hint_token_cmp (const void *a, const void *b)
{
return strcmp (((const PT_HINT *) a)->tokens, ((const PT_HINT *) b)->tokens);
}
/*
* pt_initialize_hint () - initialize hint string
* parser(in): parser context
* hint_table(in): hint table to initialize
*/
void
pt_initialize_hint (PARSER_CONTEXT * parser, PT_HINT hint_table[])
{
#if defined(ENABLE_WRITE_HINT_LOG)
s_hint_msg.stmt_no = -1;
#endif
static bool was_initialized =[](PT_HINT hint_table[]){
int i;
memset (hint_table_lead_offset, 0x00, sizeof (hint_table_lead_offset));
for (i = 0; hint_table[i].tokens; i++)
{
#ifndef NDEBUG
char *p;
for (p = (char *) hint_table[i].tokens; *p; p++)
{
assert (toupper (*p) == *p);
}
#endif
hint_table[i].is_hit = false;
hint_table[i].length = (int) strlen (hint_table[i].tokens);
hint_table_lead_offset[(unsigned char) (hint_table[i].tokens[0])]++;
}
// ordering by asc
qsort (hint_table, i, sizeof (hint_table[0]), &hint_token_cmp);
// Cumulative Distribution Counting
int sum = 0;
int tCnt = hint_table_lead_offset[0];
for (i = 0; i < HINT_LEAD_CHAR_SIZE; i++)
{
tCnt = hint_table_lead_offset[i];
hint_table_lead_offset[i] = sum;
sum += tCnt;
}
// Copy for lower character
for (i = 'A'; i <= 'Z'; i++)
{
hint_table_lead_offset[i + 32 /*('a'-'A') */ ] = hint_table_lead_offset[i];
}
return true;
}
(hint_table);
}
/*
* pt_cleanup_hint () - cleanup hint arg_list
* parser(in): parser context
* hint_table(in): hint table to cleanup
*/
void
pt_cleanup_hint (PARSER_CONTEXT * parser, PT_HINT hint_table[])
{
int i;
for (i = 0; hint_table[i].tokens; i++)
{
if (hint_table[i].arg_list != NULL)
{
parser_free_node (parser, hint_table[i].arg_list);
hint_table[i].arg_list = NULL;
}
}
}
/*
* pt_get_hint () - get hint value from hint table
* text(in): hint text
* hint_table(in): hint info structure list
* node(in): node which will take hint context
*/
void
pt_get_hint (const char *text, PT_HINT hint_table[], PT_NODE * node)
{
int i;
int num_parallel_threads = 0;
#if defined(ENABLE_WRITE_HINT_LOG)
bool first_hit = true;
#endif
/* read hint info */
for (i = 0; hint_table[i].tokens; i++)
{
if (!hint_table[i].is_hit)
{
continue;
}
#if defined(ENABLE_WRITE_HINT_LOG)
if (s_hint_msg.is_print)
{
if (first_hit)
{
ADD_HINT_STRING ((char *) "%-10s Hit) ", HINT_GREP_STR);
first_hit = false;
}
print_hit_hint_string (hint_table + i);
}
#endif
switch (hint_table[i].hint)
{
case PT_HINT_NONE:
break;
case PT_HINT_ORDERED: /* force join left-to-right */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
}
break;
case PT_HINT_LEADING: /* force specific table to join left-to-right */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.leading = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
node->info.delete_.leading_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
node->info.update.leading_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_NO_INDEX_SS: /* disable index skip scan */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_INDEX_SS:
if (node->node_type == PT_SELECT)
{
if (hint_table[i].arg_list != NULL && PT_IS_NULL_NODE (hint_table[i].arg_list))
{
/* For INDEX_SS(), just ignore index skip scan hint */
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint & ~PT_HINT_INDEX_SS);
node->info.query.q.select.index_ss = NULL;
}
else
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.index_ss = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
}
break;
case PT_HINT_USE_NL: /* force nl-join */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.use_nl = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
node->info.delete_.use_nl_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
node->info.update.use_nl_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_USE_IDX: /* force idx-join */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.use_idx = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
node->info.delete_.use_idx_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
node->info.update.use_idx_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_USE_MERGE: /* force m-join */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.use_merge = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
node->info.delete_.use_merge_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
node->info.update.use_merge_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_NO_USE_HASH: /* disable hash-join */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.no_use_hash = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
node->info.delete_.no_use_hash_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
node->info.update.no_use_hash_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_MERGE)
{
node->info.merge.hint = (PT_HINT_ENUM) (node->info.merge.hint | hint_table[i].hint);
node->info.merge.no_use_hash = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_USE_HASH: /* force hash-join */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.use_hash = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
node->info.delete_.use_hash_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
node->info.update.use_hash_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_MERGE)
{
node->info.merge.hint = (PT_HINT_ENUM) (node->info.merge.hint | hint_table[i].hint);
node->info.merge.use_hash = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_RECOMPILE: /* recompile */
node->flag.recompile = 1;
break;
case PT_HINT_LK_TIMEOUT: /* lock timeout */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.waitsecs_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
node->info.update.waitsecs_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
node->info.delete_.waitsecs_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_INSERT)
{
node->info.insert.hint = (PT_HINT_ENUM) (node->info.insert.hint | hint_table[i].hint);
node->info.insert.waitsecs_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
else if (node->node_type == PT_MERGE)
{
node->info.merge.hint = (PT_HINT_ENUM) (node->info.merge.hint | hint_table[i].hint);
node->info.merge.waitsecs_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_NO_LOGGING: /* no logging */
if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
}
else if (node->node_type == PT_INSERT)
{
node->info.insert.hint = (PT_HINT_ENUM) (node->info.insert.hint | hint_table[i].hint);
}
else if (node->node_type == PT_MERGE)
{
node->info.merge.hint = (PT_HINT_ENUM) (node->info.merge.hint | hint_table[i].hint);
}
break;
case PT_HINT_QUERY_CACHE: /* query_cache */
if (PT_IS_QUERY_NODE_TYPE (node->node_type))
{
node->info.query.hint = (PT_HINT_ENUM) (node->info.query.hint | hint_table[i].hint);
node->info.query.qcache_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
if (node->info.query.qcache_hint)
{
if (atoi (node->info.query.qcache_hint->info.name.original))
node->info.query.flag.do_cache = 1;
else
node->info.query.flag.do_not_cache = 1;
}
else
{
node->info.query.flag.do_cache = 1;
}
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
#if 0
case PT_HINT_QUERY_NO_CACHE:
if (PT_IS_QUERY_NODE_TYPE (node->node_type))
{
node->info.query.hint = (PT_HINT_ENUM) (node->info.query.hint | hint_table[i].hint);
node->info.query.qcache_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
/* force not use the query cache */
node->info.query.flag.reexecute = 1;
node->info.query.flag.do_cache = 0;
node->info.query.flag.do_not_cache = 1;
}
break;
#endif
case PT_HINT_REEXECUTE: /* reexecute */
if (PT_IS_QUERY_NODE_TYPE (node->node_type))
{
node->info.query.hint = (PT_HINT_ENUM) (node->info.query.hint | hint_table[i].hint);
node->info.query.flag.reexecute = 1;
}
break;
case PT_HINT_JDBC_CACHE: /* jdbc cache */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.jdbc_life_time = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_USE_IDX_DESC: /* descending index scan */
case PT_HINT_NO_COVERING_IDX: /* do not use covering index scan */
case PT_HINT_NO_IDX_DESC: /* do not use descending index scan */
case PT_HINT_NO_PARALLEL_HASH_JOIN: /* disable parallel hash join */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
}
break;
case PT_HINT_INSERT_MODE:
if (node->node_type == PT_INSERT)
{
node->info.insert.hint = (PT_HINT_ENUM) (node->info.insert.hint | hint_table[i].hint);
node->info.insert.insert_mode = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_NO_MULTI_RANGE_OPT:
case PT_HINT_NO_SORT_LIMIT:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
}
break;
case PT_HINT_USE_UPDATE_IDX:
if (node->node_type == PT_MERGE)
{
node->info.merge.hint = (PT_HINT_ENUM) (node->info.merge.hint | hint_table[i].hint);
node->info.merge.update.index_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_USE_INSERT_IDX:
if (node->node_type == PT_MERGE)
{
node->info.merge.hint = (PT_HINT_ENUM) (node->info.merge.hint | hint_table[i].hint);
node->info.merge.insert.index_hint = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_NO_HASH_AGGREGATE:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_NO_HASH_LIST_SCAN:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_NO_PUSH_PRED:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_NO_MERGE:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_NO_SUBQUERY_CACHE:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_NO_PARALLEL_HEAP_SCAN:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_NO_PARALLEL_SUBQUERY:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_PARALLEL:
if (node->node_type == PT_SELECT)
{
if (hint_table[i].arg_list != NULL)
{
char *p;
num_parallel_threads = (int) strtol (hint_table[i].arg_list->info.name.original, &p, 10);
if (*p == '\0')
{
node->info.query.q.select.hint =
(PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
if (num_parallel_threads < 0)
{
num_parallel_threads = 0;
}
else if (num_parallel_threads > PRM_MAX_PARALLELISM)
{
num_parallel_threads = PRM_MAX_PARALLELISM;
}
node->info.query.q.select.num_parallel_threads = num_parallel_threads;
hint_table[i].arg_list = NULL;
}
}
}
else if (node->node_type == PT_DELETE)
{
if (hint_table[i].arg_list != NULL)
{
char *p;
num_parallel_threads = (int) strtol (hint_table[i].arg_list->info.name.original, &p, 10);
if (*p == '\0')
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
if (num_parallel_threads < 0)
{
num_parallel_threads = 0;
}
else if (num_parallel_threads > PRM_MAX_PARALLELISM)
{
num_parallel_threads = PRM_MAX_PARALLELISM;
}
node->info.delete_.num_parallel_threads = num_parallel_threads;
hint_table[i].arg_list = NULL;
}
}
}
else if (node->node_type == PT_UPDATE)
{
if (hint_table[i].arg_list != NULL)
{
char *p;
num_parallel_threads = (int) strtol (hint_table[i].arg_list->info.name.original, &p, 10);
if (*p == '\0')
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
if (num_parallel_threads < 0)
{
num_parallel_threads = 0;
}
else if (num_parallel_threads > PRM_MAX_PARALLELISM)
{
num_parallel_threads = PRM_MAX_PARALLELISM;
}
node->info.update.num_parallel_threads = num_parallel_threads;
hint_table[i].arg_list = NULL;
}
}
}
break;
case PT_HINT_NLJ_KEEP_HEAP_PAGE_PINNED:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_NO_ELIMINATE_JOIN:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_SKIP_UPDATE_NULL:
if (node->node_type == PT_ALTER)
{
node->info.alter.hint = (PT_HINT_ENUM) (node->info.alter.hint | hint_table[i].hint);
}
break;
case PT_HINT_NO_INDEX_LS: /* disable loose index scan */
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_INDEX_LS: /* enable loose index scan */
if (node->node_type == PT_SELECT)
{
if (hint_table[i].arg_list != NULL && PT_IS_NULL_NODE (hint_table[i].arg_list))
{
/* For INDEX_LS(), just ignore loose index scan hint */
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint & ~PT_HINT_INDEX_LS);
node->info.query.q.select.index_ls = NULL;
}
else
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | PT_HINT_INDEX_LS);
node->info.query.q.select.index_ls = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
}
break;
case PT_HINT_SELECT_RECORD_INFO:
case PT_HINT_SELECT_PAGE_INFO:
case PT_HINT_SAMPLING_SCAN:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_SELECT_KEY_INFO:
case PT_HINT_SELECT_BTREE_NODE_INFO:
if (node->node_type == PT_SELECT)
{
/* SELECT_KEY_INFO hint can work if it has one and only one index name as argument. Same for
* SELECT_BTREE_NODE_INFO. Ignore hint if this condition is not met. */
if (hint_table[i].arg_list == NULL || hint_table[i].arg_list->next != NULL)
{
break;
}
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
node->info.query.q.select.using_index = hint_table[i].arg_list;
hint_table[i].arg_list = NULL;
}
break;
case PT_HINT_USE_SBR: /* statement-based replication */
if (node->node_type == PT_INSERT)
{
node->info.insert.hint = (PT_HINT_ENUM) (node->info.insert.hint | hint_table[i].hint);
}
else if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
}
break;
case PT_HINT_NO_SUPPLEMENTAL_LOG: /* statement-based replication */
if (node->node_type == PT_DELETE)
{
node->info.delete_.hint = (PT_HINT_ENUM) (node->info.delete_.hint | hint_table[i].hint);
}
else if (node->node_type == PT_UPDATE)
{
node->info.update.hint = (PT_HINT_ENUM) (node->info.update.hint | hint_table[i].hint);
}
break;
case PT_HINT_INLINE_CTE:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
case PT_HINT_MATERIALIZE_CTE:
if (node->node_type == PT_SELECT)
{
node->info.query.q.select.hint = (PT_HINT_ENUM) (node->info.query.q.select.hint | hint_table[i].hint);
}
break;
default:
break;
}
if (hint_table[i].arg_list)
{
parser_free_tree (this_parser, hint_table[i].arg_list);
hint_table[i].arg_list = NULL;
}
} /* for (i = ... ) */
#if defined(ENABLE_WRITE_HINT_LOG)
if (s_hint_msg.is_print)
{
ADD_HINT_STRING ((char *) "\n");
write_hint_2_logfile ();
}
#endif
}
//=============================================================================
static void
get_hint_args_func (unsigned char *arg_start, unsigned char *arg_end, unsigned char *arg_dot, PT_HINT * hint_table)
{
unsigned char ch_backup = '\0';
unsigned char *temp;
PT_NODE *arg;
/* trim space around found spec name */
while ((arg_start < arg_end) && IS_WHITE_SPACE (*arg_start))
{
arg_start++;
}
while ((arg_end > arg_start) && IS_WHITE_SPACE (arg_end[-1]))
{
arg_end--;
}
if (arg_start == arg_end)
{
return;
}
arg = parser_new_node (this_parser, PT_NAME);
if (!arg)
{
return;
}
if (!arg_dot || IS_HINT_ON_TABLE (hint_table->hint))
{
ch_backup = *arg_end; // backup
*arg_end = '\0';
arg->info.name.original = pt_makename_trim_as_identifier ((char *) arg_start);
*arg_end = ch_backup; // restore
}
else
{
*arg_dot = '\0';
/* trim space around found spec name */
temp = arg_dot - 1;
while ((temp > arg_start) && IS_WHITE_SPACE (temp[0]))
{
temp--;
}
ch_backup = temp[1]; // backup
temp[1] = '\0';
arg->info.name.resolved = pt_makename_trim_as_identifier ((char *) arg_start);
temp[1] = ch_backup;
*arg_dot++ = '.'; // restore
/* trim space around found spec name */
while ((arg_dot < arg_end) && IS_WHITE_SPACE (*arg_dot))
{
arg_dot++;
}
ch_backup = *arg_end; // backup
*arg_end = '\0';
arg->info.name.original = pt_makename_trim_as_identifier ((char *) arg_dot);
*arg_end = ch_backup; // restore
}
arg->info.name.meta_class = PT_HINT_NAME;
hint_table->arg_list = parser_append_node (arg, hint_table->arg_list);
}
static inline int
hint_case_cmp (const char *input_string, const char *hint_token, int length, int &matched_idx)
{
int cmp;
// hint_token is always uppercase.
while (matched_idx < length)
{
if (input_string[matched_idx] == '\0')
{
return -1;
}
cmp = toupper (input_string[matched_idx]) - hint_token[matched_idx];
if (cmp != 0)
{
return cmp;
}
matched_idx++;
}
return 0;
}
static int
find_hint_token (PT_HINT hint_table[], unsigned char *string)
{
int i, len, matched_idx;
char cBk;
int cmp;
if (!string || string[0] == '\0')
{
return -1;
}
matched_idx = 0;
for (i = hint_table_lead_offset[*string]; i < hint_table_lead_offset[*string + 1]; i++)
{
if (matched_idx > 0)
{
if (memcmp (hint_table[i - 1].tokens, hint_table[i].tokens, matched_idx) != 0)
{
return -1;
}
}
len = hint_table[i].length;
cmp = hint_case_cmp ((char *) string, hint_table[i].tokens, len, matched_idx);
if (cmp == 0)
{
if (string[len] == '\0' || IS_WHITE_SPACE (string[len]) || string[len] == '(')
{
return i;
}
}
else if (cmp < 0)
{
break;
}
}
return -1;
}
static unsigned char *
read_hint_args (unsigned char *instr, PT_HINT hint_table[], int hint_idx, PT_HINT_ENUM * result_hint)
{
unsigned char *sp, delimeter;
unsigned char *in = instr;
unsigned char *dot_ptr = 0x00;
if (*in != '(')
{
/* found specified hint */
hint_table[hint_idx].is_hit = true;
*result_hint |= hint_table[hint_idx].hint;
return instr;
}
/*
* If hint_table[hint_idx].arg_list is reentrant from an existing state,
* which one will be adopted, the old one or the new one?
*/
// As in the existing method, if only the first matched information is judged as valid, the second is ignored.
bool is_illegal_expression = false;
bool is_first_hit = false;
if (hint_table[hint_idx].is_hit == false)
{
is_first_hit = true;
}
in++;
while (IS_WHITE_SPACE (*in))
{
in++;
}
if (*in == ')')
{
if (is_first_hit)
{
if (IS_HINT_ON_TABLE (hint_table[hint_idx].hint))
{
/*
* INDEX_SS() or INDEX_LS() means do not apply
* hint, use special node to mark this.
*/
PT_NODE *arg = parser_new_node (this_parser, PT_VALUE);
if (arg)
{
arg->type_enum = PT_TYPE_NULL;
}
hint_table[hint_idx].arg_list = arg;
hint_table[hint_idx].is_hit = true;
*result_hint |= hint_table[hint_idx].hint;
}
}
return in + 1;
}
sp = in;
while (*in)
{
if (*in == '"' || *in == '[' || *in == '`')
{
delimeter = (*in == '[') ? ']' : *in;
in++;
while (*in)
{
if (*in == '\\' && *(in + 1) == delimeter)
{
in++;
}
else if (*in == delimeter)
{
in++;
break;
}
in++;
}
continue;
}
if (*in == '(')
{
/* illegal hint expression */
is_illegal_expression = true;
}
else if (*in == '.')
{
if (!dot_ptr)
{
dot_ptr = in; // set the position of the first dot
}
}
else if (*in == ',')
{
if (is_first_hit && !is_illegal_expression)
{
get_hint_args_func (sp, in, dot_ptr, &(hint_table[hint_idx]));
}
dot_ptr = 0x00;
sp = in + 1;
}
else if (*in == ')')
{ // OK
if (is_first_hit && !is_illegal_expression)
{
get_hint_args_func (sp, in, dot_ptr, &(hint_table[hint_idx]));
hint_table[hint_idx].is_hit = true;
*result_hint |= hint_table[hint_idx].hint;
}
return in + 1;
}
in++;
}
/* illegal hint expression */
if (is_first_hit)
{
if (hint_table[hint_idx].arg_list != NULL)
{
parser_free_node (this_parser, hint_table[hint_idx].arg_list);
hint_table[hint_idx].arg_list = NULL;
}
#if 1
// This code has been inserted to handle the same as the existing code.
// It responds to the following types of errors: INDEX_SS( (idx)
if (IS_HINT_ON_TABLE (hint_table[hint_idx].hint))
{
/*
* INDEX_SS() or INDEX_LS() means do not apply
* hint, use special node to mark this.
*/
PT_NODE *arg = parser_new_node (this_parser, PT_VALUE);
if (arg)
{
arg->type_enum = PT_TYPE_NULL;
}
hint_table[hint_idx].arg_list = arg;
hint_table[hint_idx].is_hit = true;
*result_hint |= hint_table[hint_idx].hint;
}
#endif
}
return in;
}
/*
* pt_check_hint () - search hint comment from hint table
* text(in): hint comment
* hint_table(in): hint info structure list
* result_hint(in): found result
* prev_is_white_char(in): -
*/
void
pt_check_hint (const char *text, PT_HINT hint_table[], PT_HINT_ENUM * result_hint)
{
unsigned char *hint_p;
int hint_idx;
bool start_flag = true;
unsigned char *h_str = (unsigned char *) text + 1; // skip '+'
#if defined(ENABLE_WRITE_HINT_LOG)
s_hint_msg.reset ();
s_hint_msg.is_print = false;
#endif
if (*h_str == '+')
{
h_str++;
#if defined(ENABLE_WRITE_HINT_LOG)
s_hint_msg.is_print = true;
if (s_hint_msg.stmt_no != this_parser->statement_number)
{
s_hint_msg.stmt_no = this_parser->statement_number;
ADD_HINT_STRING ((char *) "%-10s ========================================\n", HINT_GREP_STR);
}
s_hint_msg.add_hint_string ((char *) h_str);
#endif
}
// reset hit info.
for (int i = 0; hint_table[i].tokens; i++)
{
hint_table[i].is_hit = false;
}
*result_hint = PT_HINT_NONE;
while (IS_WHITE_SPACE (*h_str))
{
h_str++;
}
while (*h_str)
{
if (*h_str >= 0x80)
{
do
{
h_str++;
}
while (*h_str >= 0x80);
start_flag = false;
continue;
}
else if (IS_WHITE_SPACE (*h_str))
{
start_flag = true;
h_str++;
}
else if (start_flag == false)
{
h_str++;
}
else if (hint_table_lead_offset[h_str[0]] >= hint_table_lead_offset[h_str[0] + 1])
{
start_flag = false;
h_str++;
}
else
{
hint_idx = find_hint_token (hint_table, h_str);
if (hint_idx == -1)
{
start_flag = false;
h_str++;
}
else
{
h_str += hint_table[hint_idx].length;
h_str = read_hint_args (h_str, hint_table, hint_idx, result_hint);
}
}
}
#if defined(ENABLE_WRITE_HINT_LOG)
if (s_hint_msg.is_print)
{
if (*result_hint == PT_HINT_NONE)
{
ADD_HINT_STRING ((char *) "%-10s Hit) \n", HINT_GREP_STR);
}
write_hint_2_logfile ();
}
#endif
}
#if defined(ENABLE_WRITE_HINT_LOG)
static void
print_hit_hint_string (PT_HINT * hint_table)
{
PT_NODE *px;
if (hint_table->arg_list == NULL)
{
ADD_HINT_STRING ((const char *) " %s ", (char *) hint_table->tokens);
return;
}
ADD_HINT_STRING ((const char *) " %s(", (char *) hint_table->tokens);
px = hint_table->arg_list;
do
{
if (px->node_type == PT_NAME)
{
if (px->info.name.resolved)
{
ADD_HINT_STRING ((const char *) "[%s].[%s]", (char *) px->info.name.resolved,
(char *) px->info.name.original);
}
else
{
ADD_HINT_STRING ((const char *) "[%s]", (char *) px->info.name.original);
}
}
else if (px->node_type == PT_VALUE)
{
assert (px->type_enum == PT_TYPE_NULL);
ADD_HINT_STRING (" ");
}
else
{
assert (0);
}
px = px->next;
if (px)
{
ADD_HINT_STRING (", ");
}
}
while (px);
ADD_HINT_STRING (")");
}
static void
write_hint_2_logfile ()
{
if (s_hint_msg.msg_ptr && *s_hint_msg.msg_ptr)
{
s_hint_msg.msg_ptr[s_hint_msg.m_used] = '\0';
er_log_debug (ARG_FILE_LINE, "%s \n", s_hint_msg.msg_ptr);
s_hint_msg.reset ();
}
}
#endif // #if defined(ENABLE_WRITE_HINT_LOG)
/*
* pt_check_ipv4 () - Checks the validity of the ip address
* p(in): IP addr
* return:
*/
bool
pt_check_ipv4 (char *p)
{
// ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$
// 127.0.0.1
char *num;
int dot_cnt = 0;
num = p;
if (*num < '0' || *num > '9')
{
return false;
}
for (++p; *p; p++)
{
if (*p >= '0' && *p <= '9')
{
continue;
}
else if ((*p != '.') || (p[1] == '.'))
{
return false;
}
dot_cnt++;
switch ((int) (p - num))
{
case 1:
break;
case 2:
case 3:
if (*num == '0')
{
return false;
}
else if (255 < atoi (num))
{
return false;
}
break;
default:
return false;
}
num = p + 1;
if (*num < '0' || *num > '9')
{
return false;
}
}
if (dot_cnt != 3)
return false;
switch ((int) (p - num))
{
case 1:
break;
case 2:
case 3:
if (*num == '0')
{
return false;
}
else if (255 < atoi (num))
{
return false;
}
break;
default:
return false;
}
return true;
}
/*
* pt_check_hostname () - Checks the validity of the hostname
* p(in): hostname
* return:
*/
bool
pt_check_hostname (char *p)
{
// case RFC 1123)
// ^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$
// case RFC 952) Hostname segment cannot start with a number
// ^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$
// The length of the part separated by '.' is from 1 to 63 characters.
// The total length of the hostname must not exceed 255 characters.
bool isdot = false;
char *s = p;
char *t = p;
if (char_isalnum (*p) == 0)
{
return false;
}
for (p++; *p; p++)
{
if (*p == '.')
{
if (char_isalnum (p[-1]) == 0)
{
return false;
}
else if (63 < (int) (p - t))
{
return false;
}
isdot = true;
}
else if (isdot)
{
if (char_isalnum (*p) == 0)
{
return false;
}
t = p;
isdot = false;
}
else if ((char_isalnum (*p) == 0) && (*p != '-'))
{
return false;
}
}
if (isdot || (p[-1] == '-'))
{
return false;
}
else if (63 < (int) (p - t))
{
return false;
}
if (255 < (int) (p - s))
{
return false;
}
return true;
}