The Debugger runs a PSQL block or a script one statement at a time. A run pauses at a breakpoint, at an exception or when asked. While it is paused, the values of the variables can be read and changed, and the run goes on step by step or to the next pause. The Debugger is a window of its own, so it can sit on a second screen next to the query tab. It is available from release 28.0. ![[20261009-qtm-debugger-paused.png]] ## Starting a Run The menu "Query" holds the entries of the Debugger: - "Debug Statement at Cursor" runs the statement at the cursor under the Debugger, as "Execute" runs it. - "Debug All" (Alt+F5) runs all statements of the query tab, as "Execute All" does. It needs the same licence for scripts. - "Pause at Start" makes a run pause before its first statement. It is on by default. - "Open Debugger" brings the window forward without starting a run. The button "Debug" next to "Execute All" starts "Debug All" too. While a run is paused, the band of the query tab says where, and its button "Show Debugger" brings the window forward. Its button "Copy State" puts the state of the paused run on the clipboard, as described below. "Cancel" in the band stops a paused run as it stops a running one. ## The Window The tool bar holds the commands of the run: - "Continue" (F5) runs until the next pause. - "Pause" (F8) pauses a running run at the next statement. - "Step Over" (F10) runs the current statement, including the procedures it calls. - "Step Into" (F11) goes into a procedure or function which the statement calls. - "Step Out" (Shift+F11) runs to the end of the current procedure. - "Leave Loop" runs the rest of the current loop and pauses after it. - "Run to Cursor" (Ctrl+F10) runs to the line of the cursor in the source. - "Stop" (Shift+F5) ends the run. On MacOS the keys of the debuggers of the browsers apply: Command+\ for "Continue", Command+' for "Step Over", Command+; for "Step Into", Shift+Command+; for "Step Out" and Shift+Command+. for "Stop". The window has a list of sources on the left, the source in the middle, a side bar on the right and the "Debug Console" below. The source shows one unit per tab: the statements of the run, and every procedure or function the run steps into, also when it was created earlier in the session. The bar above the source names the unit and where it comes from. "Open in Editor" selects the same line in the query tab, since the lines are numbered as in the editor. The yellow band says why the run paused, in a sentence, and the yellow arrow marks the statement which runs next. While a step runs a statement for more than half a second, the band turns green and says which line runs and for how long. Its button "Freeze in Progress" holds the rows of the statement, as "Freeze All" of the [[Invantive Query Tool Multi-Platform/Progress|Progress]] pane does, so the statement can be studied there. "Release in Progress", "Pause" and "Stop" let the rows go. A run under the Debugger is followed by the Progress pane even when its button "Progress" is off, and a "Step Into" of an SQL statement brings the pane to the front. The box at the right of the tool bar lists the runs of the session. An earlier run can be picked to read its console and its last state; it cannot be resumed. ## Copy State "Copy State" in the tool bar puts the state of the paused run on the clipboard as JSON: where it paused and why, and the call stack with the variables of every frame. Values which look like personal data, such as names, e-mail addresses and bank accounts, are replaced by their type and length, and secrets are always left out. The JSON can be pasted into an AI assistant or sent along with a question. "Save State As..." writes the same JSON to a file. ## Coverage With "Coverage" on in the tool bar, the run counts how often each line runs. A bar left of every line with a statement is green when the line ran and grey when it never did, so code which a test did not reach stands out. Counting makes the run slower, and it starts when the button is pressed. ## Breakpoints A click in the margin left of the line numbers sets a breakpoint on a line, and F9 does the same for the line of the cursor. The context menu of the margin offers more: - "Add Conditional..." pauses only when a condition is true, such as `l_change_pct > 25`. - "Add Log Point..." writes a message to the console and does not pause. - "Hit Count..." pauses only at a given hit. - "Disable" keeps the breakpoint without using it, and "Remove" deletes it. The section "Breakpoints" of the side bar takes a breakpoint as text: `30`, `30 if l_n > 3`, or `unit` followed by the name of a procedure. A breakpoint typed for a line which already has one replaces it. Breakpoints and the exception settings are kept for the next run. ## Values The section "Scope" lists the variables of the selected frame of the "Call Stack", with the row of a loop in a group of its own. A value which changed since the previous pause is red, and its tool tip gives the value it had. At the end of the lines which ran in the current pass, the values they produced are shown in a light box. Resting on a name in the source shows its value in a tip; Ctrl+I does the same for the name at the cursor. The tip of the row of a loop lists its columns. "Pin" keeps the tip open while the run goes on, and it follows the value from step to step. A tip shows only what "Scope" holds, so resting on a name never runs a function. The context menu of a value in "Scope" offers: - "Edit Value (F2)" opens a field over the value. Enter sets it, converted to the type of the variable, and Escape leaves it. A value which cannot be converted is refused, with the reason under the field. - "Show in Viewer" opens the value in the Value Viewer, as a double click does. - "Go to Declaration" selects the declaration of the variable in the source. - "Set to Null", "Copy Value", "Copy Name" and "Copy as Assignment" do what they say; the last one copies a line such as `l_n := 41;`. - "Add Watch" adds the variable to the section "Watch", which also takes an expression. - "Pause When Value Changes" pauses the run at the statement after the one which gave the variable another value. Below the section "Watch", a loop table keeps chosen variables for every pass of a loop. It is entered as the line of the loop, a colon and the variables, such as `9: r_pjt.pjt_code, l_change_pct`, followed by "Add Loop Table". From the next pass on, the grid shows a row per pass with the worker and the values, so the passes can be compared side by side. ## The Value Viewer The Value Viewer shows a long value in the way its content asks for, and a chip names what it was recognised as: - JSON as a tree with the path of the selection, or as formatted text. - XML as an outline with the XPath of the selection, or as text. A known document is named, such as a UBL invoice with Peppol BIS or NLCIUS, an ISO 20022 bank statement or payment file, an XBRL instance or an XML Audit File. - Text with "Decode" from Base64, URL encoding, quoted-printable and hexadecimal, and a JWT ([RFC 7519](https://www.rfc-editor.org/rfc/rfc7519)) as its header and payload. The signature of a JWT is not checked. - Binary values in hexadecimal, with a band which names what the first bytes tell. "Decompress" unpacks gzip and zlib and recognises the result again. - An image as an image, a ZIP as its list of entries with "Open Entry", a certificate as its fields, an EDIFACT interchange as one segment per line and an MT940 statement as one field per line. - An e-mail as its headers with the list of its parts; "Open Part" shows an attachment, which is recognised again. The tree of JSON and the outline of XML have a search field for names and values; "Find Next" goes to the next match and shows its path. Text has the search of the editor with Ctrl+F. A private key and a store of keys are named and never shown. "Save As..." writes the value as it is, also when it is larger than the part shown. ![[20261009-qtm-debugger-value-viewer.png]] ## Exceptions The box "Exceptions" sets when an exception pauses the run: "None", "Uncaught" or "All". "Uncaught" pauses when no handler will catch the exception, before the frames unwind, so the variables of the failing frame can still be read. "Exception Settings..." refines this per message code or pattern, such as `xxivechk*`, with the choices "Pause when raised", "Pause when uncaught" and "Never pause". ## Parallel Work When a run starts parallel work, the tab "Parallel Work" appears next to the sources. It has a lane for every worker, with its state, the line it runs and a time line of the passes of its loop. A pass which raised an exception is red. Selecting a lane while the run is paused selects the worker, as the section "Threads" does. When one worker pauses, the others pause at their next statement. "Parallel One by One" runs the workers one after the other, so the work of one worker can be followed first. ![[20261009-qtm-debugger-parallel.png]] Below the lanes, "Between Workers" lists what the workers share: every lock of `dbms_lock` with the worker which holds it and how many wait for it, every value of `dbms_atomic` with who changed it last, and the lines of DBMS output a worker holds back until its branch or pass ends. The workers are listed under "Parallel Work" in the list of sources too. ## Connection Monitor The calls which a debugged run makes carry the PSQL statement which made them in the column "PSQL Location" of the [[Invantive Query Tool Multi-Platform/Connection Monitor|Connection Monitor]], such as `dbg_check_revenue:15 · iteration 3`. "Only from the Debugger" leaves only those calls. "Show in Debugger" in the menu of a call selects that statement in the Debugger window. ## Resource Use The tab "Resource Use" shows where the time and memory of the run go, for each unit and each statement in it: the passes, the time, the CPU of PSQL and of SQL, the memory and the I/O. A bar behind the time shows its share of the run, and the two statements with the most CPU of SQL are marked. "Self" shows the CPU of a statement without the statements inside it, and "Copy as Table" copies the table. The time the run was paused is left out. The section "Resource Use" of the side bar lists the heaviest statements so far. ## Debug Console The "Debug Console" lists what happened in the run, in order and with times in UTC: the pauses, the lines of DBMS output, the messages of log points and the values changed by hand. Its field evaluates an expression in the selected frame.