@ -27,10 +27,10 @@
* to blame query costs on the proper queryId .
* to blame query costs on the proper queryId .
*
*
* To facilitate presenting entries to users , we create " representative " query
* To facilitate presenting entries to users , we create " representative " query
* strings in which constants are replaced with ' ? ' characters , to make it
* strings in which constants are replaced with parameter symbols ( $ n ) , to
* clearer what a normalized entry can represent . To save on shared memory ,
* make it clearer what a normalized entry can represent . To save on shared
* and to avoid having to truncate oversized query strings , we store thes e
* memory , and to avoid having to truncate oversized query strings , we store
* strings in a temporary external query - texts file . Offsets into this
* these strings in a temporary external query - texts file . Offsets into this
* file are kept in shared memory .
* file are kept in shared memory .
*
*
* Note about locking issues : to create or delete an entry in the shared
* Note about locking issues : to create or delete an entry in the shared
@ -219,6 +219,9 @@ typedef struct pgssJumbleState
/* Current number of valid entries in clocations array */
/* Current number of valid entries in clocations array */
int clocations_count ;
int clocations_count ;
/* highest Param id we've seen, in order to start normalization correctly */
int highest_extern_param_id ;
} pgssJumbleState ;
} pgssJumbleState ;
/*---- Local variables ----*/
/*---- Local variables ----*/
@ -803,6 +806,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query)
jstate . clocations = ( pgssLocationLen * )
jstate . clocations = ( pgssLocationLen * )
palloc ( jstate . clocations_buf_size * sizeof ( pgssLocationLen ) ) ;
palloc ( jstate . clocations_buf_size * sizeof ( pgssLocationLen ) ) ;
jstate . clocations_count = 0 ;
jstate . clocations_count = 0 ;
jstate . highest_extern_param_id = 0 ;
/* Compute query ID and mark the Query node with it */
/* Compute query ID and mark the Query node with it */
JumbleQuery ( & jstate , query ) ;
JumbleQuery ( & jstate , query ) ;
@ -2482,6 +2486,10 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
APP_JUMB ( p - > paramkind ) ;
APP_JUMB ( p - > paramkind ) ;
APP_JUMB ( p - > paramid ) ;
APP_JUMB ( p - > paramid ) ;
APP_JUMB ( p - > paramtype ) ;
APP_JUMB ( p - > paramtype ) ;
/* Also, track the highest external Param id */
if ( p - > paramkind = = PARAM_EXTERN & &
p - > paramid > jstate - > highest_extern_param_id )
jstate - > highest_extern_param_id = p - > paramid ;
}
}
break ;
break ;
case T_Aggref :
case T_Aggref :
@ -2874,7 +2882,7 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
break ;
break ;
case T_TableFunc :
case T_TableFunc :
{
{
TableFunc * tablefunc = ( TableFunc * ) node ;
TableFunc * tablefunc = ( TableFunc * ) node ;
JumbleExpr ( jstate , tablefunc - > docexpr ) ;
JumbleExpr ( jstate , tablefunc - > docexpr ) ;
JumbleExpr ( jstate , tablefunc - > rowexpr ) ;
JumbleExpr ( jstate , tablefunc - > rowexpr ) ;
@ -2938,7 +2946,8 @@ RecordConstLocation(pgssJumbleState *jstate, int location)
* of interest , so it ' s worth doing . )
* of interest , so it ' s worth doing . )
*
*
* * query_len_p contains the input string length , and is updated with
* * query_len_p contains the input string length , and is updated with
* the result string length ( which cannot be longer ) on exit .
* the result string length on exit . The resulting string might be longer
* or shorter depending on what happens with replacement of constants .
*
*
* Returns a palloc ' d string .
* Returns a palloc ' d string .
*/
*/
@ -2949,6 +2958,7 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query,
char * norm_query ;
char * norm_query ;
int query_len = * query_len_p ;
int query_len = * query_len_p ;
int i ,
int i ,
norm_query_buflen , /* Space allowed for norm_query */
len_to_wrt , /* Length (in bytes) to write */
len_to_wrt , /* Length (in bytes) to write */
quer_loc = 0 , /* Source query byte location */
quer_loc = 0 , /* Source query byte location */
n_quer_loc = 0 , /* Normalized query byte location */
n_quer_loc = 0 , /* Normalized query byte location */
@ -2961,8 +2971,17 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query,
*/
*/
fill_in_constant_lengths ( jstate , query , query_loc ) ;
fill_in_constant_lengths ( jstate , query , query_loc ) ;
/*
* Allow for $ n symbols to be longer than the constants they replace .
* Constants must take at least one byte in text form , while a $ n symbol
* certainly isn ' t more than 11 bytes , even if n reaches INT_MAX . We
* could refine that limit based on the max value of n for the current
* query , but it hardly seems worth any extra effort to do so .
*/
norm_query_buflen = query_len + jstate - > clocations_count * 10 ;
/* Allocate result buffer */
/* Allocate result buffer */
norm_query = palloc ( query_len + 1 ) ;
norm_query = palloc ( norm_ query_buf len + 1 ) ;
for ( i = 0 ; i < jstate - > clocations_count ; i + + )
for ( i = 0 ; i < jstate - > clocations_count ; i + + )
{
{
@ -2986,8 +3005,9 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query,
memcpy ( norm_query + n_quer_loc , query + quer_loc , len_to_wrt ) ;
memcpy ( norm_query + n_quer_loc , query + quer_loc , len_to_wrt ) ;
n_quer_loc + = len_to_wrt ;
n_quer_loc + = len_to_wrt ;
/* And insert a '?' in place of the constant token */
/* And insert a param symbol in place of the constant token */
norm_query [ n_quer_loc + + ] = ' ? ' ;
n_quer_loc + = sprintf ( norm_query + n_quer_loc , " $%d " ,
i + 1 + jstate - > highest_extern_param_id ) ;
quer_loc = off + tok_len ;
quer_loc = off + tok_len ;
last_off = off ;
last_off = off ;
@ -3004,7 +3024,7 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query,
memcpy ( norm_query + n_quer_loc , query + quer_loc , len_to_wrt ) ;
memcpy ( norm_query + n_quer_loc , query + quer_loc , len_to_wrt ) ;
n_quer_loc + = len_to_wrt ;
n_quer_loc + = len_to_wrt ;
Assert ( n_quer_loc < = query_len ) ;
Assert ( n_quer_loc < = norm_ query_buf len) ;
norm_query [ n_quer_loc ] = ' \0 ' ;
norm_query [ n_quer_loc ] = ' \0 ' ;
* query_len_p = n_quer_loc ;
* query_len_p = n_quer_loc ;