pá 4. 1. 2019 v 13:58 odesílatel Peter Eisentraut < peter.eisentr...@2ndquadrant.com> napsal:
> On 13/11/2018 14:35, Pavel Stehule wrote: > > I am try to enhance plpgsql_check about profiler functionality and I > > have to solve how to identify every plpgsql statement across different > > sessions. There is lineno, but surely it should not be unique. I propose > > introduce stmtid to every statement structure. This number will be > > unique inside function. > > That seems reasonable enough, although I wouldn't use 0 as a valid stmtid. > done > A documenting comment near PLpgSQL_stmt might be nice. > done Regards Pavel > -- > Peter Eisentraut http://www.2ndQuadrant.com/ > PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services >
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 0e9ea10596..9e98134c05 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -368,6 +368,8 @@ do_compile(FunctionCallInfo fcinfo, function->fn_prokind = procStruct->prokind; + function->nstatements = 0; + /* * Initialize the compiler, particularly the namespace stack. The * outermost namespace contains function parameters and other special @@ -911,6 +913,8 @@ plpgsql_compile_inline(char *proc_source) true); function->found_varno = var->dno; + function->nstatements = 0; + /* * Now parse the function's text */ @@ -1020,6 +1024,7 @@ add_dummy_return(PLpgSQL_function *function) new = palloc0(sizeof(PLpgSQL_stmt_block)); new->cmd_type = PLPGSQL_STMT_BLOCK; + new->stmtid = ++function->nstatements; new->body = list_make1(function->action); function->action = new; @@ -1031,6 +1036,7 @@ add_dummy_return(PLpgSQL_function *function) new = palloc0(sizeof(PLpgSQL_stmt_return)); new->cmd_type = PLPGSQL_STMT_RETURN; + new->stmtid = ++function->nstatements; new->expr = NULL; new->retvarno = function->out_param_varno; diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 59063976b3..55c041c175 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -414,6 +414,7 @@ pl_block : decl_sect K_BEGIN proc_sect exception_sect K_END opt_label new->cmd_type = PLPGSQL_STMT_BLOCK; new->lineno = plpgsql_location_to_lineno(@2); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1.label; new->n_initvars = $1.n_initvars; new->initvarnos = $1.initvarnos; @@ -918,6 +919,7 @@ stmt_call : K_CALL new = palloc0(sizeof(PLpgSQL_stmt_call)); new->cmd_type = PLPGSQL_STMT_CALL; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->expr = read_sql_stmt("CALL "); new->is_call = true; @@ -932,6 +934,7 @@ stmt_call : K_CALL new = palloc0(sizeof(PLpgSQL_stmt_call)); new->cmd_type = PLPGSQL_STMT_CALL; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->expr = read_sql_stmt("DO "); new->is_call = false; @@ -947,6 +950,7 @@ stmt_assign : assign_var assign_operator expr_until_semi new = palloc0(sizeof(PLpgSQL_stmt_assign)); new->cmd_type = PLPGSQL_STMT_ASSIGN; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->varno = $1->dno; new->expr = $3; @@ -962,6 +966,7 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';' new = palloc0(sizeof(PLpgSQL_stmt_getdiag)); new->cmd_type = PLPGSQL_STMT_GETDIAG; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->is_stacked = $2; new->diag_items = $4; @@ -1149,6 +1154,7 @@ stmt_if : K_IF expr_until_then proc_sect stmt_elsifs stmt_else K_END K_IF ';' new = palloc0(sizeof(PLpgSQL_stmt_if)); new->cmd_type = PLPGSQL_STMT_IF; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->cond = $2; new->then_body = $3; new->elsif_list = $4; @@ -1253,6 +1259,7 @@ stmt_loop : opt_loop_label K_LOOP loop_body new = palloc0(sizeof(PLpgSQL_stmt_loop)); new->cmd_type = PLPGSQL_STMT_LOOP; new->lineno = plpgsql_location_to_lineno(@2); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->body = $3.stmts; @@ -1270,6 +1277,7 @@ stmt_while : opt_loop_label K_WHILE expr_until_loop loop_body new = palloc0(sizeof(PLpgSQL_stmt_while)); new->cmd_type = PLPGSQL_STMT_WHILE; new->lineno = plpgsql_location_to_lineno(@2); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->cond = $3; new->body = $4.stmts; @@ -1290,6 +1298,7 @@ stmt_for : opt_loop_label K_FOR for_control loop_body new = (PLpgSQL_stmt_fori *) $3; new->lineno = plpgsql_location_to_lineno(@2); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->body = $4.stmts; $$ = (PLpgSQL_stmt *) new; @@ -1304,6 +1313,7 @@ stmt_for : opt_loop_label K_FOR for_control loop_body /* forq is the common supertype of all three */ new = (PLpgSQL_stmt_forq *) $3; new->lineno = plpgsql_location_to_lineno(@2); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->body = $4.stmts; $$ = (PLpgSQL_stmt *) new; @@ -1333,6 +1343,7 @@ for_control : for_variable K_IN new = palloc0(sizeof(PLpgSQL_stmt_dynfors)); new->cmd_type = PLPGSQL_STMT_DYNFORS; + new->stmtid = ++plpgsql_curr_compile->nstatements; if ($1.row) { new->var = (PLpgSQL_variable *) $1.row; @@ -1378,6 +1389,7 @@ for_control : for_variable K_IN new = (PLpgSQL_stmt_forc *) palloc0(sizeof(PLpgSQL_stmt_forc)); new->cmd_type = PLPGSQL_STMT_FORC; + new->stmtid = ++plpgsql_curr_compile->nstatements; new->curvar = cursor->dno; /* Should have had a single variable name */ @@ -1492,6 +1504,7 @@ for_control : for_variable K_IN new = palloc0(sizeof(PLpgSQL_stmt_fori)); new->cmd_type = PLPGSQL_STMT_FORI; + new->stmtid = ++plpgsql_curr_compile->nstatements; new->var = fvar; new->reverse = reverse; new->lower = expr1; @@ -1526,6 +1539,7 @@ for_control : for_variable K_IN new = palloc0(sizeof(PLpgSQL_stmt_fors)); new->cmd_type = PLPGSQL_STMT_FORS; + new->stmtid = ++plpgsql_curr_compile->nstatements; if ($1.row) { new->var = (PLpgSQL_variable *) $1.row; @@ -1626,6 +1640,7 @@ stmt_foreach_a : opt_loop_label K_FOREACH for_variable foreach_slice K_IN K_ARRA new = palloc0(sizeof(PLpgSQL_stmt_foreach_a)); new->cmd_type = PLPGSQL_STMT_FOREACH_A; new->lineno = plpgsql_location_to_lineno(@2); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->label = $1; new->slice = $4; new->expr = $7; @@ -1672,6 +1687,7 @@ stmt_exit : exit_type opt_label opt_exitcond new = palloc0(sizeof(PLpgSQL_stmt_exit)); new->cmd_type = PLPGSQL_STMT_EXIT; + new->stmtid = ++plpgsql_curr_compile->nstatements; new->is_exit = $1; new->lineno = plpgsql_location_to_lineno(@1); new->label = $2; @@ -1763,6 +1779,7 @@ stmt_raise : K_RAISE new->cmd_type = PLPGSQL_STMT_RAISE; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->elog_level = ERROR; /* default */ new->condname = NULL; new->message = NULL; @@ -1907,6 +1924,7 @@ stmt_assert : K_ASSERT new->cmd_type = PLPGSQL_STMT_ASSERT; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->cond = read_sql_expression2(',', ';', ", or ;", @@ -1984,6 +2002,7 @@ stmt_dynexecute : K_EXECUTE new = palloc(sizeof(PLpgSQL_stmt_dynexecute)); new->cmd_type = PLPGSQL_STMT_DYNEXECUTE; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->query = expr; new->into = false; new->strict = false; @@ -2040,6 +2059,7 @@ stmt_open : K_OPEN cursor_variable new = palloc0(sizeof(PLpgSQL_stmt_open)); new->cmd_type = PLPGSQL_STMT_OPEN; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->curvar = $2->dno; new->cursor_options = CURSOR_OPT_FAST_PLAN; @@ -2164,6 +2184,7 @@ stmt_close : K_CLOSE cursor_variable ';' new = palloc(sizeof(PLpgSQL_stmt_close)); new->cmd_type = PLPGSQL_STMT_CLOSE; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->curvar = $2->dno; $$ = (PLpgSQL_stmt *)new; @@ -2184,6 +2205,7 @@ stmt_commit : K_COMMIT ';' new = palloc(sizeof(PLpgSQL_stmt_commit)); new->cmd_type = PLPGSQL_STMT_COMMIT; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; $$ = (PLpgSQL_stmt *)new; } @@ -2196,6 +2218,7 @@ stmt_rollback : K_ROLLBACK ';' new = palloc(sizeof(PLpgSQL_stmt_rollback)); new->cmd_type = PLPGSQL_STMT_ROLLBACK; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; $$ = (PLpgSQL_stmt *)new; } @@ -2208,6 +2231,8 @@ stmt_set : K_SET new = palloc0(sizeof(PLpgSQL_stmt_set)); new->cmd_type = PLPGSQL_STMT_SET; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; + new->expr = read_sql_stmt("SET "); $$ = (PLpgSQL_stmt *)new; @@ -2219,6 +2244,7 @@ stmt_set : K_SET new = palloc0(sizeof(PLpgSQL_stmt_set)); new->cmd_type = PLPGSQL_STMT_SET; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->expr = read_sql_stmt("RESET "); $$ = (PLpgSQL_stmt *)new; @@ -3000,6 +3026,7 @@ make_execsql_stmt(int firsttoken, int location) execsql = palloc(sizeof(PLpgSQL_stmt_execsql)); execsql->cmd_type = PLPGSQL_STMT_EXECSQL; execsql->lineno = plpgsql_location_to_lineno(location); + execsql->stmtid = ++plpgsql_curr_compile->nstatements; execsql->sqlstmt = expr; execsql->into = have_into; execsql->strict = have_strict; @@ -3025,6 +3052,7 @@ read_fetch_direction(void) */ fetch = (PLpgSQL_stmt_fetch *) palloc0(sizeof(PLpgSQL_stmt_fetch)); fetch->cmd_type = PLPGSQL_STMT_FETCH; + fetch->stmtid = ++plpgsql_curr_compile->nstatements; /* set direction defaults: */ fetch->direction = FETCH_FORWARD; fetch->how_many = 1; @@ -3177,6 +3205,7 @@ make_return_stmt(int location) new = palloc0(sizeof(PLpgSQL_stmt_return)); new->cmd_type = PLPGSQL_STMT_RETURN; new->lineno = plpgsql_location_to_lineno(location); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->expr = NULL; new->retvarno = -1; @@ -3264,6 +3293,7 @@ make_return_next_stmt(int location) new = palloc0(sizeof(PLpgSQL_stmt_return_next)); new->cmd_type = PLPGSQL_STMT_RETURN_NEXT; new->lineno = plpgsql_location_to_lineno(location); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->expr = NULL; new->retvarno = -1; @@ -3326,6 +3356,7 @@ make_return_query_stmt(int location) new = palloc0(sizeof(PLpgSQL_stmt_return_query)); new->cmd_type = PLPGSQL_STMT_RETURN_QUERY; + new->stmtid = ++plpgsql_curr_compile->nstatements; new->lineno = plpgsql_location_to_lineno(location); /* check for RETURN QUERY EXECUTE */ @@ -3997,6 +4028,7 @@ make_case(int location, PLpgSQL_expr *t_expr, new = palloc(sizeof(PLpgSQL_stmt_case)); new->cmd_type = PLPGSQL_STMT_CASE; new->lineno = plpgsql_location_to_lineno(location); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->t_expr = t_expr; new->t_varno = 0; new->case_when_list = case_when_list; diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 2dca49334a..f60b33b344 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -447,6 +447,12 @@ typedef struct PLpgSQL_stmt { PLpgSQL_stmt_type cmd_type; int lineno; + + /* + * A profilers needs to hold metrics per statement. Integer + * statement identifier can be used as index to array of metrics. + */ + int stmtid; } PLpgSQL_stmt; /* @@ -486,6 +492,7 @@ typedef struct PLpgSQL_stmt_block { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; char *label; List *body; /* List of statements */ int n_initvars; /* Length of initvarnos[] */ @@ -500,6 +507,7 @@ typedef struct PLpgSQL_stmt_assign { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; int varno; PLpgSQL_expr *expr; } PLpgSQL_stmt_assign; @@ -511,6 +519,7 @@ typedef struct PLpgSQL_stmt_perform { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *expr; } PLpgSQL_stmt_perform; @@ -521,6 +530,7 @@ typedef struct PLpgSQL_stmt_call { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *expr; bool is_call; PLpgSQL_variable *target; @@ -533,6 +543,7 @@ typedef struct PLpgSQL_stmt_commit { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; } PLpgSQL_stmt_commit; /* @@ -542,6 +553,7 @@ typedef struct PLpgSQL_stmt_rollback { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; } PLpgSQL_stmt_rollback; /* @@ -551,6 +563,7 @@ typedef struct PLpgSQL_stmt_set { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *expr; } PLpgSQL_stmt_set; @@ -570,6 +583,7 @@ typedef struct PLpgSQL_stmt_getdiag { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; bool is_stacked; /* STACKED or CURRENT diagnostics area? */ List *diag_items; /* List of PLpgSQL_diag_item */ } PLpgSQL_stmt_getdiag; @@ -581,6 +595,7 @@ typedef struct PLpgSQL_stmt_if { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *cond; /* boolean expression for THEN */ List *then_body; /* List of statements */ List *elsif_list; /* List of PLpgSQL_if_elsif structs */ @@ -604,6 +619,7 @@ typedef struct PLpgSQL_stmt_case { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *t_expr; /* test expression, or NULL if none */ int t_varno; /* var to store test expression value into */ List *case_when_list; /* List of PLpgSQL_case_when structs */ @@ -627,6 +643,7 @@ typedef struct PLpgSQL_case_when typedef struct PLpgSQL_stmt_loop { PLpgSQL_stmt_type cmd_type; + int stmtid; int lineno; char *label; List *body; /* List of statements */ @@ -639,6 +656,7 @@ typedef struct PLpgSQL_stmt_while { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; char *label; PLpgSQL_expr *cond; List *body; /* List of statements */ @@ -651,6 +669,7 @@ typedef struct PLpgSQL_stmt_fori { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; char *label; PLpgSQL_var *var; PLpgSQL_expr *lower; @@ -669,6 +688,7 @@ typedef struct PLpgSQL_stmt_forq { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; char *label; PLpgSQL_variable *var; /* Loop variable (record or row) */ List *body; /* List of statements */ @@ -681,6 +701,7 @@ typedef struct PLpgSQL_stmt_fors { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; char *label; PLpgSQL_variable *var; /* Loop variable (record or row) */ List *body; /* List of statements */ @@ -695,6 +716,7 @@ typedef struct PLpgSQL_stmt_forc { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; char *label; PLpgSQL_variable *var; /* Loop variable (record or row) */ List *body; /* List of statements */ @@ -710,6 +732,7 @@ typedef struct PLpgSQL_stmt_dynfors { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; char *label; PLpgSQL_variable *var; /* Loop variable (record or row) */ List *body; /* List of statements */ @@ -725,6 +748,7 @@ typedef struct PLpgSQL_stmt_foreach_a { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; char *label; int varno; /* loop target variable */ int slice; /* slice dimension, or 0 */ @@ -739,6 +763,7 @@ typedef struct PLpgSQL_stmt_open { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; int curvar; int cursor_options; PLpgSQL_expr *argquery; @@ -754,6 +779,7 @@ typedef struct PLpgSQL_stmt_fetch { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_variable *target; /* target (record or row) */ int curvar; /* cursor variable to fetch from */ FetchDirection direction; /* fetch direction */ @@ -770,6 +796,7 @@ typedef struct PLpgSQL_stmt_close { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; int curvar; } PLpgSQL_stmt_close; @@ -780,6 +807,7 @@ typedef struct PLpgSQL_stmt_exit { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; bool is_exit; /* Is this an exit or a continue? */ char *label; /* NULL if it's an unlabelled EXIT/CONTINUE */ PLpgSQL_expr *cond; @@ -792,6 +820,7 @@ typedef struct PLpgSQL_stmt_return { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *expr; int retvarno; } PLpgSQL_stmt_return; @@ -803,6 +832,7 @@ typedef struct PLpgSQL_stmt_return_next { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *expr; int retvarno; } PLpgSQL_stmt_return_next; @@ -814,6 +844,7 @@ typedef struct PLpgSQL_stmt_return_query { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *query; /* if static query */ PLpgSQL_expr *dynquery; /* if dynamic query (RETURN QUERY EXECUTE) */ List *params; /* USING arguments for dynamic query */ @@ -826,6 +857,7 @@ typedef struct PLpgSQL_stmt_raise { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; int elog_level; char *condname; /* condition name, SQLSTATE, or NULL */ char *message; /* old-style message format literal, or NULL */ @@ -849,6 +881,7 @@ typedef struct PLpgSQL_stmt_assert { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *cond; PLpgSQL_expr *message; } PLpgSQL_stmt_assert; @@ -860,6 +893,7 @@ typedef struct PLpgSQL_stmt_execsql { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *sqlstmt; bool mod_stmt; /* is the stmt INSERT/UPDATE/DELETE? Note: * mod_stmt is set when we plan the query */ @@ -875,6 +909,7 @@ typedef struct PLpgSQL_stmt_dynexecute { PLpgSQL_stmt_type cmd_type; int lineno; + int stmtid; PLpgSQL_expr *query; /* string expression */ bool into; /* INTO supplied? */ bool strict; /* INTO STRICT flag */ @@ -971,6 +1006,9 @@ typedef struct PLpgSQL_function /* function body parsetree */ PLpgSQL_stmt_block *action; + /* number of statements inside functions */ + int nstatements; + /* these fields change when the function is used */ struct PLpgSQL_execstate *cur_estate; unsigned long use_count;