Optmize query denormalization

Instead of copying original query text byte by byte, copy data between
query placeholders in chunks, example:

`INSERT INTO foo(a, b, c) VALUES('test', 100, 'test again)'`

Would result in normalized query:

`INSERT INTO foo(a, b, c) VALUES($1, $2, $3)`

The original patch would copy the parts between placeholders byte by
byte, e.g. `INSERT INTO foo(a, b, c) VALUES(`, instead we can copy this
whole block at once, 1 function call and maybe 1 buffer re-allocation
per call.

Also make use of `appendBinaryStringInfo` to avoid calculating string
length as we have this info already.
pull/481/head
Diego Fronza 2024-08-01 15:53:05 -03:00
parent 70aaa0875e
commit 6acc63e5a6
1 changed files with 37 additions and 18 deletions

View File

@ -20,6 +20,7 @@
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "utils/guc.h" #include "utils/guc.h"
#include <regex.h> #include <regex.h>
#include <stddef.h>
#include "pgstat.h" #include "pgstat.h"
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "commands/explain.h" #include "commands/explain.h"
@ -4085,40 +4086,58 @@ get_denormalized_query(const ParamListInfo paramlist, const char *query_text)
int i; int i;
char **param_text; char **param_text;
const char *cursor_ori; const char *cursor_ori;
const char *cursor_curr;
StringInfoData result_buf; StringInfoData result_buf;
ptrdiff_t len;
param_text = get_params_text_list(paramlist); param_text = get_params_text_list(paramlist);
param_num = paramlist->numParams; param_num = paramlist->numParams;
current_param = 0; current_param = 0;
cursor_ori = query_text; cursor_ori = query_text;
cursor_curr = cursor_ori;
initStringInfo(&result_buf); initStringInfo(&result_buf);
while(*cursor_ori != '\0') do
{ {
if(*cursor_ori != '$') // advance cursor until detecting a placeholder '$' start.
while (*cursor_ori && *cursor_ori != '$')
++cursor_ori;
// calculate length of query text before placeholder.
len = cursor_ori - cursor_curr;
// check if end of string is reached
if (!*cursor_ori)
{ {
/* copy the origin query string to result*/ // there may have remaining query data to append
appendStringInfoChar(&result_buf,*cursor_ori); if (len > 0)
cursor_ori++; appendBinaryStringInfo(&result_buf, cursor_curr, len);
break;
} }
else
{ // append query text before the '$' sign found.
if (len > 0)
appendBinaryStringInfo(&result_buf, cursor_curr, len);
// skip '$'
++cursor_ori;
/* skip the placeholder */ /* skip the placeholder */
while(*cursor_ori && *cursor_ori >= '0' && *cursor_ori <= '9')
cursor_ori++; cursor_ori++;
while(*cursor_ori >= '0' && *cursor_ori <= '9')
{ // advance current cursor
cursor_ori++; cursor_curr = cursor_ori;
}
/* replace the placeholder with actual value */ /* replace the placeholder with actual value */
appendStringInfo(&result_buf,"%s",param_text[current_param++]); appendStringInfoString(&result_buf, param_text[current_param++]);
} } while (*cursor_ori != '\0');
}
/* free the query text array*/ /* free the query text array*/
for(i = 0; i < param_num; i++) for(i = 0; i < param_num; i++)
{
pfree(param_text[i]); pfree(param_text[i]);
}
pfree(param_text); pfree(param_text);
return result_buf; return result_buf;