Skip to content

MySQL probe

The MySQL probe connects to a MySQL or MariaDB server, runs a SQL statement, and returns the result: a result set, an update count, or a server error. It is VirtuProbe’s first database protocol, which closes the loop on integration testing: after an HTTP call writes a record, a MySQL step can confirm the row actually landed.

Unlike the hand-rolled protocol probes, the MySQL probe is library-backed (MariaDB Connector/J, which speaks both MySQL and MariaDB) with connection pooling, so repeated sends and the steps of a chain reuse connections instead of reconnecting each time.

MySQL probe editor: connection settings, credential picker, and the SQL statement

FieldDescription
HostHostname or IP of the database server
PortServer port (default: 3306)
DatabaseDefault schema to connect to (optional)
TLS modeDisabled, Required (encrypt without verifying the certificate), Verify CA, or Verify identity (verify the certificate chain and hostname)
Allow public-key retrievalLet the driver fetch the server’s RSA public key over a plaintext connection. Required for caching_sha2_password (the MySQL 8 default) without TLS. Off by default, because it exposes the exchange to a MITM.
Allow cleartext password pluginPermit mysql_clear_password (used with PAM/LDAP auth). Off by default.

MySQL logins use the credential store, so the username and password never live on the probe. This keeps secrets out of a shared folder-backed workspace (which stores probes as plain files) and out of exported evidence.

A database login is a username + password, which maps to a Basic credential (username in config, password in secrets). In the probe’s Auth row:

  1. Select an existing credential, or click New credential to create a Basic one (name, username, password).
  2. The effective credential panel shows what will be used and where it came from, either this probe or the project default (the cascade: a probe with no credential falls back to the project’s default credential).
  3. Stored secrets are masked; click the eye to reveal a value on demand (behind a confirmation).
  4. Override for this run lets you type a different username/password for a single send without changing the stored credential, which is how you try alternate credentials against the same target.

Effective-credential panel: source chip, masked secret with reveal, and per-run override

If no credential is selected, the connection is attempted anonymously.

Enter the statement in the SQL editor. Ctrl/Cmd+Enter runs it. {{variable}} placeholders are resolved from the active environment before the statement is sent, and that deliberately includes substitution into the SQL text itself, which enables both data-driven chaining and SQL-injection testing.

When the statement calls a procedure, the Procedure parameters panel binds what it takes and returns. Each row has a direction:

DirectionMeaning
INA value you supply
OUTA value the procedure returns
INOUTBoth: you supply one and the procedure replaces it

Values are bound rather than pasted into the SQL, so a value carrying a quote is a value and not a syntax error. A row you switch off is left out of the call, and order matters, because a procedure’s signature is positional; the arrows on each row move it. An unnamed parameter’s output comes back under its 1-based position among the rows you send, which the greyed-out name shows.

A send returns at most 1000 rows. The field sits under the SQL editor, and 0 means no limit.

A SELECT * against a production table is one keystroke away, and every row that comes back is held in memory and written into the run record, so the limit keeps a mistyped query from taking the app down with it.

When the statement matched more rows than the limit allows, the count beside the grid reads first 1000 rows, limit reached instead of a total. VirtuProbe asks the driver for one row past the limit and throws it away, so a query that returned exactly 1000 rows and a query that was cut off at 1000 are told apart rather than guessed at.

  • Query (SELECT, SHOW, …) → a scrollable result-set table. Column names come from the driver; a SQL NULL renders as an italic NULL.
  • Update / DDL (INSERT, UPDATE, DELETE, CREATE, …) → the number of affected rows, plus any generated auto-increment keys.
  • Server error → a red panel with the message, the vendor error code, and the SQLSTATE. A rejected statement is a valid failed result, not a crash.

A procedure that runs several SELECTs returns each result set in its own tab. Any server warnings (the ones SHOW WARNINGS would list) and any OUT/INOUT values appear below, and an ordinary query shows neither.

The status bar shows the row/affected count, the server version, and the client-side round-trip duration.

MySQL result-set response: status bar and result table

Use these in chain steps to pull values out of a MySQL result for later steps or assertions:

ExtractorReturns
MYSQL_SUCCESS"true" / "false"
MYSQL_ROW_COUNTnumber of rows returned by a query
MYSQL_RESULT_COUNThow many results the statement produced
MYSQL_AFFECTED_ROWSrows affected by an update/DDL (-1 for a query)
MYSQL_COLUMNa single cell, with expression column, row.column or row.colIndex (e.g. email, 0.email, 2.1)
MYSQL_OUT_PARAMone OUT/INOUT value, by label or 1-based position; blank returns the only one when a call has a single output
MYSQL_MESSAGESthe warnings the server raised, newline-joined; blank for all, a 0-based index for one
MYSQL_TRUNCATED"true" when the row cap was reached
MYSQL_ERROR_CODEthe vendor error code (0 on success)
MYSQL_JSONthe whole result set as a JSON array

See Extractors for the full list.

MySQL is a first-class chain step. A common pattern is HTTP → MySQL: call an API that creates a record, then run a SELECT and ASSERT on a MYSQL_COLUMN value to prove the write. {{variable}} values (including extractor output from earlier steps) resolve into the SQL, host, database, and query. Credentials resolve at the moment the query runs, never from the stored probe.

Each send is recorded as a history entry with the statement as sent (resolved variables), the result, and a timestamp. Click an entry to restore it.

A probe keeps its 50 most recent sends. A stored result set keeps its first 1000 rows and any stored text is kept to its first 256 KB, with the original size recorded beside it. History is a quick look back at what a probe returned, so it is bounded more tightly than a chain run, which is the record you keep as evidence.

  • Driver: MariaDB Connector/J (LGPL), which speaks MySQL and MariaDB. The query/extract/chain path has no need to control individual bytes, so a library is the right tool here.
  • Connection pooling: HikariCP, keyed by the connection signature (host/port/database/user/TLS). Reuse avoids reconnecting on every send. Note that pooling hands you a connection, not necessarily the same physical one, so per-session state (temporary tables, @variables, USE) is not guaranteed to persist between chain steps.
  • caching_sha2_password: MySQL 8’s default auth plugin needs either TLS or Allow public-key retrieval on a plaintext socket.