diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 2454386af8..3b8e137ab5 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 @@ -880,6 +882,8 @@ plpgsql_compile_inline(char *proc_source) function->extra_warnings = 0; function->extra_errors = 0; + function->nstatements = 0; + plpgsql_ns_init(); plpgsql_ns_push(func_name, PLPGSQL_LABEL_BLOCK); plpgsql_DumpExecTree = false; @@ -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..03f7cdce8c 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; @@ -905,6 +906,7 @@ stmt_perform : K_PERFORM expr_until_semi new = palloc0(sizeof(PLpgSQL_stmt_perform)); new->cmd_type = PLPGSQL_STMT_PERFORM; new->lineno = plpgsql_location_to_lineno(@1); + new->stmtid = ++plpgsql_curr_compile->nstatements; new->expr = $2; $$ = (PLpgSQL_stmt *)new; @@ -918,6 +920,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 +935,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 +951,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 +967,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 +1155,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 +1260,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 +1278,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 +1299,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 +1314,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 +1344,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 +1390,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 +1505,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 +1540,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 +1641,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 +1688,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 +1780,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 +1925,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 +2003,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 +2060,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 +2185,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 +2206,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 +2219,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 +2232,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 +2245,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 +3027,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 +3053,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 +3206,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 +3294,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; @@ -3327,6 +3358,7 @@ make_return_query_stmt(int location) new = palloc0(sizeof(PLpgSQL_stmt_return_query)); new->cmd_type = PLPGSQL_STMT_RETURN_QUERY; new->lineno = plpgsql_location_to_lineno(location); + new->stmtid = ++plpgsql_curr_compile->nstatements; /* check for RETURN QUERY EXECUTE */ if ((tok = yylex()) != K_EXECUTE) @@ -3997,6 +4029,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 a7118b8386..0a5fbfa9d6 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -447,6 +447,13 @@ typedef struct PLpgSQL_stmt { PLpgSQL_stmt_type cmd_type; int lineno; + + /* + * Unique statement ID in this function (starting at 1; 0 is invalid/not + * set). This can be used by a profiler as the index for an array of + * per-statement metrics. + */ + unsigned int stmtid; } PLpgSQL_stmt; /* @@ -486,6 +493,7 @@ typedef struct PLpgSQL_stmt_block { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; char *label; List *body; /* List of statements */ int n_initvars; /* Length of initvarnos[] */ @@ -500,6 +508,7 @@ typedef struct PLpgSQL_stmt_assign { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; int varno; PLpgSQL_expr *expr; } PLpgSQL_stmt_assign; @@ -511,6 +520,7 @@ typedef struct PLpgSQL_stmt_perform { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; PLpgSQL_expr *expr; } PLpgSQL_stmt_perform; @@ -521,6 +531,7 @@ typedef struct PLpgSQL_stmt_call { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; PLpgSQL_expr *expr; bool is_call; PLpgSQL_variable *target; @@ -533,6 +544,7 @@ typedef struct PLpgSQL_stmt_commit { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; } PLpgSQL_stmt_commit; /* @@ -542,6 +554,7 @@ typedef struct PLpgSQL_stmt_rollback { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; } PLpgSQL_stmt_rollback; /* @@ -551,6 +564,7 @@ typedef struct PLpgSQL_stmt_set { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; PLpgSQL_expr *expr; } PLpgSQL_stmt_set; @@ -570,6 +584,7 @@ typedef struct PLpgSQL_stmt_getdiag { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; bool is_stacked; /* STACKED or CURRENT diagnostics area? */ List *diag_items; /* List of PLpgSQL_diag_item */ } PLpgSQL_stmt_getdiag; @@ -581,6 +596,7 @@ typedef struct PLpgSQL_stmt_if { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned 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 +620,7 @@ typedef struct PLpgSQL_stmt_case { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned 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 */ @@ -628,6 +645,7 @@ typedef struct PLpgSQL_stmt_loop { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; char *label; List *body; /* List of statements */ } PLpgSQL_stmt_loop; @@ -639,6 +657,7 @@ typedef struct PLpgSQL_stmt_while { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; char *label; PLpgSQL_expr *cond; List *body; /* List of statements */ @@ -651,6 +670,7 @@ typedef struct PLpgSQL_stmt_fori { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; char *label; PLpgSQL_var *var; PLpgSQL_expr *lower; @@ -669,6 +689,7 @@ typedef struct PLpgSQL_stmt_forq { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; char *label; PLpgSQL_variable *var; /* Loop variable (record or row) */ List *body; /* List of statements */ @@ -681,6 +702,7 @@ typedef struct PLpgSQL_stmt_fors { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; char *label; PLpgSQL_variable *var; /* Loop variable (record or row) */ List *body; /* List of statements */ @@ -695,6 +717,7 @@ typedef struct PLpgSQL_stmt_forc { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; char *label; PLpgSQL_variable *var; /* Loop variable (record or row) */ List *body; /* List of statements */ @@ -710,6 +733,7 @@ typedef struct PLpgSQL_stmt_dynfors { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; char *label; PLpgSQL_variable *var; /* Loop variable (record or row) */ List *body; /* List of statements */ @@ -725,6 +749,7 @@ typedef struct PLpgSQL_stmt_foreach_a { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; char *label; int varno; /* loop target variable */ int slice; /* slice dimension, or 0 */ @@ -739,6 +764,7 @@ typedef struct PLpgSQL_stmt_open { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; int curvar; int cursor_options; PLpgSQL_expr *argquery; @@ -754,6 +780,7 @@ typedef struct PLpgSQL_stmt_fetch { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; PLpgSQL_variable *target; /* target (record or row) */ int curvar; /* cursor variable to fetch from */ FetchDirection direction; /* fetch direction */ @@ -770,6 +797,7 @@ typedef struct PLpgSQL_stmt_close { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; int curvar; } PLpgSQL_stmt_close; @@ -780,6 +808,7 @@ typedef struct PLpgSQL_stmt_exit { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned 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 +821,7 @@ typedef struct PLpgSQL_stmt_return { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; PLpgSQL_expr *expr; int retvarno; } PLpgSQL_stmt_return; @@ -803,6 +833,7 @@ typedef struct PLpgSQL_stmt_return_next { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; PLpgSQL_expr *expr; int retvarno; } PLpgSQL_stmt_return_next; @@ -814,6 +845,7 @@ typedef struct PLpgSQL_stmt_return_query { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned 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 +858,7 @@ typedef struct PLpgSQL_stmt_raise { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; int elog_level; char *condname; /* condition name, SQLSTATE, or NULL */ char *message; /* old-style message format literal, or NULL */ @@ -849,6 +882,7 @@ typedef struct PLpgSQL_stmt_assert { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; PLpgSQL_expr *cond; PLpgSQL_expr *message; } PLpgSQL_stmt_assert; @@ -860,6 +894,7 @@ typedef struct PLpgSQL_stmt_execsql { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned 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 +910,7 @@ typedef struct PLpgSQL_stmt_dynexecute { PLpgSQL_stmt_type cmd_type; int lineno; + unsigned int stmtid; PLpgSQL_expr *query; /* string expression */ bool into; /* INTO supplied? */ bool strict; /* INTO STRICT flag */ @@ -963,6 +999,9 @@ typedef struct PLpgSQL_function int extra_warnings; int extra_errors; + /* count of statements inside function */ + unsigned int nstatements; + /* the datums representing the function's local variables */ int ndatums; PLpgSQL_datum **datums;