Skip to content

Commit

Permalink
implement regexp_replace function
Browse files Browse the repository at this point in the history
* add regexp_replace token
* add syntax error code for regexp_replace
* make node for regex_replace
* add regexp_replace into functions map
* add signature of regexp replace function
* constant folding for regexp replace
* set regexp_replace as A medium rank expr
* set REGEXP_REPLACE as wrapped function
* add regexp_replace function name
* rename PT_REGEXP_REPLACE to F_REGEXP_REPLACE
* make regexp_replace able to fetch db values
* return NULL value if any paramter is NULL
* add function signature for regex_replace options
* make regex_replace perform with position and occurence options
* implement position and occurrence, need refactoring
  • Loading branch information
hgryoo committed Jun 25, 2019
1 parent f038576 commit b55afda
Show file tree
Hide file tree
Showing 19 changed files with 516 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/optimizer/query_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -3299,6 +3299,7 @@ get_expr_fcode_rank (FUNC_TYPE fcode)
case F_JSON_UNQUOTE:
case F_JSON_VALID:
case F_INSERT_SUBSTRING:
case F_REGEXP_REPLACE:
return RANK_EXPR_MEDIUM;
default:
/* each function must fill its rank */
Expand Down
7 changes: 7 additions & 0 deletions src/parser/csql_grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ static FUNCTION_MAP functions[] = {
{"crc32", PT_CRC32},
{"schema_def", PT_SCHEMA_DEF},
{"conv_tz", PT_CONV_TZ},
{"regexp_replace", F_REGEXP_REPLACE},
};


Expand Down Expand Up @@ -1342,6 +1343,7 @@ int g_original_buffer_len;
%token REFERENCES
%token REFERENCING
%token REGEXP
%token REGEXP_REPLACE
%token RELATIVE_
%token RENAME
%token REPLACE
Expand Down Expand Up @@ -17099,6 +17101,11 @@ reserved_func
$$ = parser_make_func_with_arg_count (this_parser, F_BENCHMARK, $3, 2, 2);
PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos)
DBG_PRINT}}
| REGEXP_REPLACE '(' expression_list ')'
{{
$$ = parser_make_func_with_arg_count (this_parser, F_REGEXP_REPLACE, $3, 3, 6);
PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos)
DBG_PRINT}}
;

of_cume_dist_percent_rank_function
Expand Down
1 change: 1 addition & 0 deletions src/parser/csql_lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ int yybuffer_pos;
[rR][eE][fF][eE][rR][eE][nN][cC][eE][sS] { begin_token(yytext); return REFERENCES; }
[rR][eE][fF][eE][rR][eE][nN][cC][iI][nN][gG] { begin_token(yytext); return REFERENCING; }
[rR][eE][gG][eE][xX][pP] { begin_token(yytext); return REGEXP; }
[rR][eE][gG][eE][xX][pP][_][rR][eE][pP][lL][aA][cC][eE] { begin_token(yytext); return REGEXP_REPLACE; }
[rR][eE][jJ][eE][cC][tT] { begin_token(yytext);
csql_yylval.cptr = pt_makename(yytext);
return REJECT_; }
Expand Down
11 changes: 11 additions & 0 deletions src/parser/func_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,15 @@ func_all_signatures sig_of_benchmark =
{PT_TYPE_DOUBLE, {PT_GENERIC_TYPE_DISCRETE_NUMBER, PT_GENERIC_TYPE_ANY}, {}},
};

func_all_signatures sig_of_regexp_replace =
{
// all signatures: src, pattern, replacement [,position [,occurrence [, match_type]]] -> STRING
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_TYPE_INTEGER}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_TYPE_INTEGER, PT_GENERIC_TYPE_CHAR}, {}},
};

func_all_signatures *
get_signatures (FUNC_TYPE ft)
{
Expand Down Expand Up @@ -465,6 +474,8 @@ get_signatures (FUNC_TYPE ft)
return &sig_of_json_arrayagg;
case PT_JSON_OBJECTAGG:
return &sig_of_json_objectagg;
case F_REGEXP_REPLACE:
return &sig_of_regexp_replace;
default:
assert (false);
return nullptr;
Expand Down
2 changes: 1 addition & 1 deletion src/parser/parser_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
#define MSGCAT_SYNTAX_MAX_COMMENT_LEN MSGCAT_SYNTAX_NO(127)
#define MSGCAT_SYNTAX_INVALID_JSON_OBJECTAGG MSGCAT_SYNTAX_NO(128)
#define MSGCAT_SYNTAX_INVALID_PARALLEL_ARGUMENT MSGCAT_SYNTAX_NO(129)

#define MSGCAT_SYNTAX_INVALID_REGEXP_REPLACE MSGCAT_SYNTAX_NO(130)

/* Message id in the set MSGCAT_SET_PARSER_SEMANTIC */
#define MSGCAT_SEMANTIC_NO(n) n
Expand Down
3 changes: 2 additions & 1 deletion src/parser/parser_support.c
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,8 @@ pt_is_expr_wrapped_function (PARSER_CONTEXT * parser, const PT_NODE * node)
|| function_type == F_JSON_REPLACE
|| function_type == F_JSON_SEARCH
|| function_type == F_JSON_SET
|| function_type == F_JSON_TYPE || function_type == F_JSON_UNQUOTE || function_type == F_JSON_VALID)
|| function_type == F_JSON_TYPE || function_type == F_JSON_UNQUOTE || function_type == F_JSON_VALID
|| function_type == F_REGEXP_REPLACE)
{
return true;
}
Expand Down
5 changes: 5 additions & 0 deletions src/parser/type_checking.c
Original file line number Diff line number Diff line change
Expand Up @@ -12426,6 +12426,7 @@ pt_eval_function_type (PARSER_CONTEXT * parser, PT_NODE * node)
case F_JSON_TYPE:
case F_JSON_UNQUOTE:
case F_JSON_VALID:
case F_REGEXP_REPLACE:
return pt_eval_function_type_new (parser, node);

// legacy functions are still managed by old checking function; all should be migrated though
Expand Down Expand Up @@ -19834,6 +19835,10 @@ pt_evaluate_function_w_args (PARSER_CONTEXT * parser, FUNC_TYPE fcode, DB_VALUE
error = db_evaluate_json_valid (result, args, num_args);
break;

case F_REGEXP_REPLACE:
error = db_string_regexp_replace(result, args, num_args, NULL, NULL);
break;

default:
/* a supported function doesn't have const folding code */
assert (false);
Expand Down
2 changes: 2 additions & 0 deletions src/parser/xasl_generation.c
Original file line number Diff line number Diff line change
Expand Up @@ -6229,6 +6229,7 @@ pt_make_function (PARSER_CONTEXT * parser, int function_code, const REGU_VARIABL
}

regu_dbval_type_init (regu->value.funcp->value, result_type);
regu->value.funcp->tmp = NULL;
}

return regu;
Expand Down Expand Up @@ -6328,6 +6329,7 @@ pt_function_to_regu (PARSER_CONTEXT * parser, PT_NODE * function)
break;
case F_INSERT_SUBSTRING:
case F_ELT:
case F_REGEXP_REPLACE:
result_type = pt_node_to_db_type (function);
break;
case F_BENCHMARK:
Expand Down
1 change: 1 addition & 0 deletions src/parser/xasl_regu_alloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ regu_init (function_node &fnode)
fnode.value = NULL;
fnode.ftype = (FUNC_TYPE) 0;
fnode.operand = NULL;
fnode.tmp = NULL;

regu_alloc (fnode.value);
}
Expand Down
2 changes: 2 additions & 0 deletions src/query/fetch.c
Original file line number Diff line number Diff line change
Expand Up @@ -3972,6 +3972,7 @@ fetch_peek_dbval (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu_var, val_descr *
case F_JSON_TYPE:
case F_JSON_UNQUOTE:
case F_JSON_VALID:
case F_REGEXP_REPLACE:
{
regu_variable_list_node *operand;

Expand Down Expand Up @@ -4178,6 +4179,7 @@ fetch_peek_dbval (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu_var, val_descr *
case F_JSON_TYPE:
case F_JSON_UNQUOTE:
case F_JSON_VALID:
case F_REGEXP_REPLACE:
break;

default:
Expand Down
16 changes: 16 additions & 0 deletions src/query/query_executor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,22 @@ qexec_clear_regu_var (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, REGU_VARIABLE
case TYPE_FUNC:
pr_clear_value (regu_var->value.funcp->value);
pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, regu_var->value.funcp->operand, is_final);
switch (regu_var->value.funcp->ftype)
{
case F_REGEXP_REPLACE:
{
COMPILED_REGEX *compiled_regex = static_cast < COMPILED_REGEX * >(regu_var->value.funcp->tmp);
if (compiled_regex != NULL)
{
delete compiled_regex;
}
}
break;
default:
//nothing to do
break;
}
regu_var->value.funcp->tmp = NULL;
break;
case TYPE_REGUVAL_LIST:
pg_cnt += qexec_clear_regu_value_list (thread_p, xasl_p, regu_var->value.reguval_list, is_final);
Expand Down
78 changes: 78 additions & 0 deletions src/query/query_opfunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
#include "dbtype.h"

#include <chrono>
#include <memory>
#include <regex>

#define NOT_NULL_VALUE(a, b) ((a) ? (a) : (b))
#define INITIAL_OID_STACK_SIZE 1
Expand Down Expand Up @@ -215,6 +217,9 @@ static int qdata_elt (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_D
static int qdata_benchmark (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple);

static int qdata_regexp_replace_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple);

static int qdata_convert_operands_to_value_and_call (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p,
VAL_DESCR * val_desc_p, OID * obj_oid_p, QFILE_TUPLE tuple,
int (*function_to_call) (DB_VALUE *, DB_VALUE * const *,
Expand Down Expand Up @@ -6880,6 +6885,9 @@ qdata_evaluate_function (THREAD_ENTRY * thread_p, regu_variable_node * function_
return qdata_convert_operands_to_value_and_call (thread_p, funcp, val_desc_p, obj_oid_p, tuple,
db_evaluate_json_valid);

case F_REGEXP_REPLACE:
return qdata_regexp_replace_function (thread_p, funcp, val_desc_p, obj_oid_p, tuple);

default:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_INVALID_XASLNODE, 0);
return ER_FAILED;
Expand Down Expand Up @@ -8459,6 +8467,76 @@ qdata_benchmark (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR
return NO_ERROR;
}

/*
* qdata_regex_replace_function () - Evaluates regexp_replace() function.
* return: NO_ERROR, or ER_FAILED code
* thread_p : thread context
* funcp(in) : function structure pointer
* vd(in) : value descriptor
* obj_oid(in): object identifier
* tpl(in) : tuple
*/
static int
qdata_regexp_replace_function (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple)
{
DB_VALUE *value;
REGU_VARIABLE_LIST operand;
int error_status = NO_ERROR;
int no_args = 0, index = 0;
DB_VALUE **args;

{
assert (function_p != NULL);
assert (function_p->value != NULL);
assert (function_p->operand != NULL);

operand = function_p->operand;

while (operand != NULL)
{
no_args++;
operand = operand->next;
}

args = (DB_VALUE **) db_private_alloc (thread_p, sizeof (DB_VALUE *) * no_args);

operand = function_p->operand;
while (operand != NULL)
{
error_status = fetch_peek_dbval (thread_p, &operand->value, val_desc_p, NULL, obj_oid_p, tuple, &value);
if (error_status != NO_ERROR)
{
goto exit;
}

args[index++] = value;

operand = operand->next;
}

assert (index == no_args);

if (function_p->tmp == NULL)
{
function_p->tmp = new COMPILED_REGEX ();
COMPILED_REGEX *compiled_regex = static_cast < COMPILED_REGEX * >(function_p->tmp);
}

COMPILED_REGEX *compiled_regex = static_cast < COMPILED_REGEX * >(function_p->tmp);
error_status =
db_string_regexp_replace (function_p->value, args, no_args, &compiled_regex->regex, &compiled_regex->pattern);
if (error_status != NO_ERROR)
{
goto exit;
}
}

exit:
db_private_free (thread_p, args);
return error_status;
}

static int
qdata_convert_operands_to_value_and_call (THREAD_ENTRY * thread_p, FUNCTION_TYPE * function_p, VAL_DESCR * val_desc_p,
OID * obj_oid_p, QFILE_TUPLE tuple,
Expand Down
17 changes: 17 additions & 0 deletions src/query/regu_var.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,23 @@ regu_variable_node::clear_xasl_local ()
case TYPE_FUNC:
assert (value.funcp != NULL);
pr_clear_value (value.funcp->value);

switch (value.funcp->ftype)
{
case F_REGEXP_REPLACE:
{
COMPILED_REGEX *compiled_regex = static_cast<COMPILED_REGEX *> (value.funcp->tmp);
if (compiled_regex != NULL)
{
delete compiled_regex;
}
value.funcp->tmp = NULL;
}
break;
default:
//nothing to do
break;
}
break;

case TYPE_DBVAL:
Expand Down
2 changes: 2 additions & 0 deletions src/query/regu_var.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "string_opfunc.h"

#include <functional>
#include <memory>

// forward definitions
struct xasl_node;
Expand Down Expand Up @@ -142,6 +143,7 @@ struct function_node
DB_VALUE *value; /* value of the function */
REGU_VARIABLE_LIST operand; /* operands */
FUNC_TYPE ftype; /* function to call */
mutable void *tmp;
};

/* regular variable flags */
Expand Down
2 changes: 2 additions & 0 deletions src/query/stream_to_xasl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5671,6 +5671,8 @@ stx_build_function_type (THREAD_ENTRY * thread_p, char *ptr, FUNCTION_TYPE * fun
return NULL;
}
}

function->tmp = NULL;

return ptr;
}
Expand Down
Loading

0 comments on commit b55afda

Please sign in to comment.