File method_query_util.cpp¶
File List > cubrid > src > method > method_query_util.cpp
Go to the documentation of this file
/*
*
* 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.
*
*/
#include "method_query_util.hpp"
#include <algorithm>
#include <cstring>
#include <unordered_set>
#include "dbtype.h"
#if !defined(SERVER_MODE)
#include "dbi.h"
#include "object_domain.h"
#include "object_primitive.h"
#endif
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
namespace cubmethod
{
#define STK_SIZE 100
void
str_trim (std::string &str)
{
str.erase (0, str.find_first_not_of ("\t\n\r "));
str.erase (str.find_last_not_of ("\t\n\r ") + 1);
}
char *
get_backslash_escape_string (void)
{
if (prm_get_bool_value (PRM_ID_NO_BACKSLASH_ESCAPES))
{
return (char *) "\\";
}
else
{
return (char *) "\\\\";
}
}
#define B_ERROR -1
#define B_TRUE 1
#define B_FALSE 0
int
is_korean (unsigned char ch)
{
return (ch >= 0xb0 && ch <= 0xc8) || (ch >= 0xa1 && ch <= 0xfe);
}
int
str_eval_like (const unsigned char *tar, const unsigned char *expr, unsigned char escape)
{
const int IN_CHECK = 0;
const int IN_PERCENT = 1;
const int IN_PERCENT_UNDERSCORE = 2;
int status = IN_CHECK;
const unsigned char *tarstack[STK_SIZE], *exprstack[STK_SIZE];
int stackp = -1;
int inescape = 0;
if (escape == 0)
{
escape = 2;
}
while (1)
{
if (status == IN_CHECK)
{
if (*expr == escape)
{
expr++;
if (*expr == '%' || *expr == '_')
{
inescape = 1;
continue;
}
else if (*tar
&& ((!is_korean (*tar) && *tar == *expr)
|| (is_korean (*tar) && *tar == *expr && * (tar + 1) == * (expr + 1))))
{
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
if (is_korean (*expr))
{
expr += 2;
}
else
{
expr++;
}
continue;
}
}
if (inescape)
{
if (*tar == *expr)
{
tar++;
expr++;
}
else
{
if (stackp >= 0 && stackp < STK_SIZE)
{
tar = tarstack[stackp];
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
expr = exprstack[stackp--];
}
else
{
return B_FALSE;
}
}
inescape = 0;
continue;
}
/* goto check */
if (*expr == 0)
{
while (*tar == ' ')
{
tar++;
}
if (*tar == 0)
{
return B_TRUE;
}
else
{
if (stackp >= 0 && stackp < STK_SIZE)
{
tar = tarstack[stackp];
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
expr = exprstack[stackp--];
}
else
{
return B_FALSE;
}
}
}
else if (*expr == '%')
{
status = IN_PERCENT;
while (* (expr + 1) == '%')
{
expr++;
}
}
else if ((*expr == '_') || (!is_korean (*tar) && *tar == *expr)
|| (is_korean (*tar) && *tar == *expr && * (tar + 1) == * (expr + 1)))
{
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
if (is_korean (*expr))
{
expr += 2;
}
else
{
expr++;
}
}
else if (stackp >= 0 && stackp < STK_SIZE)
{
tar = tarstack[stackp];
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
expr = exprstack[stackp--];
}
else if (stackp >= STK_SIZE)
{
return B_ERROR;
}
else
{
return B_FALSE;
}
}
else if (status == IN_PERCENT)
{
if (* (expr + 1) == '_')
{
if (stackp >= STK_SIZE - 1)
{
return B_ERROR;
}
tarstack[++stackp] = tar;
exprstack[stackp] = expr;
expr++;
inescape = 0;
status = IN_PERCENT_UNDERSCORE;
continue;
}
if (* (expr + 1) == escape)
{
expr++;
inescape = 1;
if (* (expr + 1) != '%' && * (expr + 1) != '_')
{
return B_ERROR;
}
}
while (*tar && *tar != * (expr + 1))
{
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
}
if (*tar == * (expr + 1))
{
if (stackp >= STK_SIZE - 1)
{
return B_ERROR;
}
tarstack[++stackp] = tar;
exprstack[stackp] = expr;
if (is_korean (*expr))
{
expr += 2;
}
else
{
expr++;
}
inescape = 0;
status = IN_CHECK;
}
}
if (status == IN_PERCENT_UNDERSCORE)
{
if (*expr == escape)
{
expr++;
inescape = 1;
if (*expr != '%' && *expr != '_')
{
return B_ERROR;
}
continue;
}
if (inescape)
{
if (*tar == *expr)
{
tar++;
expr++;
}
else
{
if (stackp >= 0 && stackp < STK_SIZE)
{
tar = tarstack[stackp];
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
expr = exprstack[stackp--];
}
else
{
return B_FALSE;
}
}
inescape = 0;
continue;
}
/* goto check */
if (*expr == 0)
{
while (*tar == ' ')
{
tar++;
}
if (*tar == 0)
{
return B_TRUE;
}
else
{
if (stackp >= 0 && stackp < STK_SIZE)
{
tar = tarstack[stackp];
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
expr = exprstack[stackp--];
}
else
{
return B_FALSE;
}
}
}
else if (*expr == '%')
{
status = IN_PERCENT;
while (* (expr + 1) == '%')
{
expr++;
}
}
else if ((*expr == '_') || (!is_korean (*tar) && *tar == *expr)
|| (is_korean (*tar) && *tar == *expr && * (tar + 1) == * (expr + 1)))
{
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
if (is_korean (*expr))
{
expr += 2;
}
else
{
expr++;
}
}
else if (stackp >= 0 && stackp < STK_SIZE)
{
tar = tarstack[stackp];
if (is_korean (*tar))
{
tar += 2;
}
else
{
tar++;
}
expr = exprstack[stackp--];
}
else if (stackp >= STK_SIZE)
{
return B_ERROR;
}
else
{
return B_FALSE;
}
}
if (*tar == 0)
{
if (*expr)
{
while (*expr == '%')
{
expr++;
}
}
if (*expr == 0)
{
return B_TRUE;
}
else
{
return B_FALSE;
}
}
}
}
int
str_like (std::string src, std::string pattern, char esc_char)
{
int result;
std::transform (src.begin(), src.end(), src.begin(), ::tolower);
std::transform (pattern.begin(), pattern.end(), pattern.begin(), ::tolower);
result =
str_eval_like ((const unsigned char *) src.c_str(), (const unsigned char *) pattern.c_str (), (unsigned char) esc_char);
return result;
}
std::string convert_db_value_to_string (DB_VALUE *value, DB_VALUE *value_string)
{
const char *val_str = NULL;
int err;
err = db_value_coerce (value, value_string, db_type_to_db_domain (DB_TYPE_VARCHAR));
if (err >= 0)
{
val_str = db_get_char (value_string);
}
return std::string (val_str);
}
#if !defined(SERVER_MODE)
int
get_stmt_type (std::string sql)
{
char *stmt = sql.data ();
if (strncasecmp (stmt, "insert", 6) == 0)
{
return CUBRID_STMT_INSERT;
}
else if (strncasecmp (stmt, "update", 6) == 0)
{
return CUBRID_STMT_UPDATE;
}
else if (strncasecmp (stmt, "delete", 6) == 0)
{
return CUBRID_STMT_DELETE;
}
else if (strncasecmp (stmt, "call", 4) == 0)
{
return CUBRID_STMT_CALL;
}
else if (strncasecmp (stmt, "evaluate", 8) == 0)
{
return CUBRID_STMT_EVALUATE;
}
else
{
return CUBRID_MAX_STMT_TYPE;
}
}
int
calculate_num_markers (const std::string &sql)
{
if (sql.empty())
{
return -1;
}
std::unordered_set<int> numbered_markers;
int num_markers = 0;
int sql_len = sql.size ();
for (int i = 0; i < sql_len; i++)
{
if (sql[i] == '?')
{
if (i + 1 < sql_len && sql[++i] == ':')
{
// read ?:<number> form
int begin_idx = i + 1;
int idx = begin_idx;
while (idx < sql_len && sql[idx] >= '0' && sql[idx] <= '9')
{
idx++;
}
if (idx > begin_idx)
{
std::string number (&sql[begin_idx], idx - begin_idx);
numbered_markers.insert (stoi (number));
}
i = idx;
}
else
{
num_markers++;
}
}
else if (sql[i] == '-' && sql[i + 1] == '-')
{
i = consume_tokens (sql, i + 2, SQL_STYLE_COMMENT);
}
else if (sql[i] == '/' && sql[i + 1] == '*')
{
i = consume_tokens (sql, i + 2, C_STYLE_COMMENT);
}
else if (sql[i] == '/' && sql[i + 1] == '/')
{
i = consume_tokens (sql, i + 2, CPP_STYLE_COMMENT);
}
else if (sql[i] == '\'')
{
i = consume_tokens (sql, i + 1, SINGLE_QUOTED_STRING);
}
else if (/* cas_default_ansi_quotes == false && */ sql[i] == '\"')
{
i = consume_tokens (sql, i + 1, DOUBLE_QUOTED_STRING);
}
}
num_markers += numbered_markers.size ();
return num_markers;
}
int
consume_tokens (std::string sql, int index, STATEMENT_STATUS stmt_status)
{
int sql_len = sql.size ();
if (stmt_status == SQL_STYLE_COMMENT || stmt_status == CPP_STYLE_COMMENT)
{
for (; index < sql_len; index++)
{
if (sql[index] == '\n')
{
break;
}
}
}
else if (stmt_status == C_STYLE_COMMENT)
{
for (; index < sql_len; index++)
{
if (sql[index] == '*' && sql[index + 1] == '/')
{
index++;
break;
}
}
}
else if (stmt_status == SINGLE_QUOTED_STRING)
{
for (; index < sql_len; index++)
{
if (sql[index] == '\'' && sql[index + 1] == '\'')
{
index++;
}
else if (/* cas_default_no_backslash_escapes == false && */ sql[index] == '\\')
{
index++;
}
else if (sql[index] == '\'')
{
break;
}
}
}
else if (stmt_status == DOUBLE_QUOTED_STRING)
{
for (; index < sql_len; index++)
{
if (sql[index] == '\"' && sql[index + 1] == '\"')
{
index++;
}
else if (/* cas_default_no_backslash_escapes == false && */ sql[index] == '\\')
{
index++;
}
else if (sql[index] == '\"')
{
break;
}
}
}
return index;
}
std::string
get_column_default_as_string (DB_ATTRIBUTE *attr)
{
int error = NO_ERROR;
std::string result_default_value_string;
char *default_value_string = NULL;
/* Get default value string */
DB_VALUE *def = db_attribute_default (attr);
if (def == NULL)
{
return "";
}
const char *default_value_expr_type_string = NULL, *default_expr_format = NULL;
const char *default_value_expr_op_string = NULL;
default_value_expr_type_string = db_default_expression_string (attr->default_value.default_expr.default_expr_type);
if (default_value_expr_type_string != NULL)
{
/* default expression case */
int len;
if (attr->default_value.default_expr.default_expr_op != NULL_DEFAULT_EXPRESSION_OPERATOR)
{
/* We now accept only T_TO_CHAR for attr->default_value.default_expr.default_expr_op */
default_value_expr_op_string = "TO_CHAR"; /* FIXME - remove this hard code */
}
default_expr_format = attr->default_value.default_expr.default_expr_format;
if (default_value_expr_op_string != NULL)
{
result_default_value_string.assign (default_value_expr_op_string);
result_default_value_string.append ("(");
result_default_value_string.append (default_value_expr_type_string);
if (default_expr_format)
{
result_default_value_string.append (", \'");
result_default_value_string.append (default_expr_format);
result_default_value_string.append ("\'");
}
result_default_value_string.append (")");
}
else
{
result_default_value_string.assign (default_value_expr_type_string);
}
return result_default_value_string;
}
if (db_value_is_null (def))
{
return "NULL";
}
/* default value case */
switch (db_value_type (def))
{
case DB_TYPE_UNKNOWN:
break;
case DB_TYPE_SET:
case DB_TYPE_MULTISET:
case DB_TYPE_SEQUENCE: /* DB_TYPE_LIST */
serialize_collection_as_string (def, result_default_value_string);
break;
case DB_TYPE_CHAR:
case DB_TYPE_VARCHAR:
{
int def_size = db_get_string_size (def);
const char *def_str_p = db_get_string (def);
if (def_str_p)
{
result_default_value_string.push_back ('\'');
result_default_value_string.append (def_str_p);
result_default_value_string.push_back ('\'');
result_default_value_string.push_back ('\0');
}
}
break;
default:
{
DB_VALUE tmp_val;
error = db_value_coerce (def, &tmp_val, db_type_to_db_domain (DB_TYPE_VARCHAR));
if (error == NO_ERROR)
{
int def_size = db_get_string_size (&tmp_val);
const char *def_str_p = db_get_string (&tmp_val);
result_default_value_string.assign (def_str_p);
}
db_value_clear (&tmp_val);
}
break;
}
return result_default_value_string;
}
void
serialize_collection_as_string (DB_VALUE *col, std::string &out)
{
out.clear ();
if (!TP_IS_SET_TYPE (db_value_type (col)))
{
return;
}
DB_COLLECTION *db_set = db_get_collection (col);
int size = db_set_size (db_set);
/* first compute the size of the result */
const char *single_value = NULL;
DB_VALUE value, value_string;
out.push_back ('{');
for (int i = 0; i < size; i++)
{
if (db_set_get (db_set, i, &value) != NO_ERROR)
{
out.clear ();
return;
}
std::string single_value = convert_db_value_to_string (&value, &value_string);
out.append (single_value);
if (i != size - 1)
{
out.append (", ");
}
db_value_clear (&value_string);
db_value_clear (&value);
}
out.push_back ('}');
}
char
get_set_domain (DB_DOMAIN *set_domain, int &precision, short &scale, char &charset)
{
int set_domain_count = 0;
int set_type = DB_TYPE_NULL;
precision = 0;
scale = 0;
charset = lang_charset ();
DB_DOMAIN *ele_domain = db_domain_set (set_domain);
for (; ele_domain; ele_domain = db_domain_next (ele_domain))
{
set_domain_count++;
set_type = TP_DOMAIN_TYPE (ele_domain);
precision = db_domain_precision (ele_domain);
scale = (short) db_domain_scale (ele_domain);
charset = db_domain_codeset (ele_domain);
}
return (set_domain_count != 1) ? DB_TYPE_NULL : set_type;
}
#endif
}