db

package
v0.6.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package db manages MySQL connections, statement execution and cancellation.

Index

Constants

View Source
const DialTimeout = 10 * time.Second

DialTimeout bounds how long a connection attempt waits before failing, so an unreachable host does not hang the UI.

View Source
const MaxQueryConns = 4

MaxQueryConns bounds the query pool. A handful is plenty: the user runs one statement at a time, and the spare slots exist so a stalled stream cannot starve the next one.

Variables

This section is empty.

Functions

func DSN

func DSN(ds *config.DataSource, password, addr string) (string, error)

DSN builds a driver connection string for ds.

addr overrides the host:port the driver dials, which is how an SSH tunnel is wired in: the datasource still describes the remote database while the driver connects to the local listener.

The DSN is assembled through mysql.Config rather than string concatenation so that passwords containing "@", "/" or ":" are escaped correctly.

It fails rather than returning a usable-looking string when the TLS settings cannot be honoured: a connection that quietly verified less than was asked of it is the failure this whole path exists to prevent.

func IsInterrupted

func IsInterrupted(err error) bool

IsInterrupted reports whether err is the server saying the statement was killed. Callers use it to present a cancellation as an outcome the user chose rather than as a failure.

func Probe

func Probe(ctx context.Context, ds *config.DataSource, password string) (string, error)

Probe opens a connection to ds and returns the server version.

sql.Open only validates the DSN, so it succeeds even against a host that is down. The version query is what actually proves reachability.

func ReachedServer added in v0.5.0

func ReachedServer(err error) bool

ReachedServer reports whether err is the server refusing, rather than the connection to it failing.

A numbered MySQL error is proof the statement got there: the server read it and answered. Anything else — a socket that has gone, a driver's bad connection — could have failed at any hop between here and the database, and is the only case a caller may attribute to something underneath, such as a bastion that has stopped forwarding.

Types

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn is a live connection to one datasource.

It deliberately holds two separate connections to the same server:

  • pool serves the statements the user runs
  • control is reserved for KILL QUERY and catalog reads

MySQL will not accept another statement on a connection until the current result set has been read to the end, so without this split a long stream would block both cancellation and schema browsing — the two things most needed while a long stream is in flight.

func Open

func Open(ctx context.Context, ds *config.DataSource, password, addr string) (*Conn, error)

Open connects to ds. addr overrides the dialled address, which is how an SSH tunnel is wired in.

func (*Conn) Begin added in v0.3.0

func (c *Conn) Begin(ctx context.Context) error

Begin opens a transaction and pins the connection it runs on.

The pin is the whole point. Statements ordinarily take a connection from the pool and hand it straight back, so a transaction opened on one would be abandoned by the next statement — BEGIN would have nothing to commit and ROLLBACK nothing to undo, while both reported success.

The connection id is read once, here, rather than per statement: it is the same connection every time, and KILL QUERY still has something to aim at.

func (*Conn) Close

func (c *Conn) Close() error

Close releases both connections.

func (*Conn) Commit added in v0.3.0

func (c *Conn) Commit(ctx context.Context) error

Commit ends the transaction, keeping its work.

func (*Conn) DataSource

func (c *Conn) DataSource() *config.DataSource

DataSource returns the datasource this connection serves.

func (*Conn) Exec

func (c *Conn) Exec(ctx context.Context, sql string) (ExecResult, error)

Exec runs a statement that produces no result set.

func (*Conn) InTransaction added in v0.3.0

func (c *Conn) InTransaction() bool

InTransaction reports whether a transaction is open on this connection.

func (*Conn) Owns added in v0.5.0

func (c *Conn) Owns(id uint64) bool

Owns reports whether a server-side connection id belongs to this session.

func (*Conn) Query

func (c *Conn) Query(ctx context.Context, sql string, opt Options) *Stream

Query runs sql and streams the result.

It returns immediately; connecting, sending the statement and reading rows all happen in the background. Failures — including a syntax error — surface through Err once Events is closed.

func (*Conn) Rollback added in v0.3.0

func (c *Conn) Rollback(ctx context.Context) error

Rollback ends the transaction, discarding its work.

func (*Conn) ServerVersion

func (c *Conn) ServerVersion() string

ServerVersion returns the version string reported at connection time.

func (*Conn) WithControl

func (c *Conn) WithControl(ctx context.Context, fn func(*sql.Conn) error) error

WithControl runs fn with exclusive use of the control connection.

This connection is reserved for cancellation and catalog reads, which is what keeps schema browsing responsive while the query pool streams a large result. Access goes through a callback rather than an accessor so that concurrent use — which would corrupt the protocol and kill the connection for good — cannot be expressed.

fn must not retain the connection beyond its return.

type Event

type Event struct {
	Kind EventKind

	// Columns and Types are set on EventColumns.
	Columns []string
	Types   []*sql.ColumnType

	// Rows is set on EventRows.
	Rows [][]any
}

Event is one update from a running statement.

There is deliberately no terminal event: the stream ends when Events is closed, and the reason is read from Err. A final event could be dropped when a cancelled stream closes, leaving the caller unable to tell a cancellation from a clean finish.

type EventKind

type EventKind int

EventKind identifies what a stream event carries.

const (
	// EventColumns arrives once, when the server returns the result header.
	EventColumns EventKind = iota
	// EventRows carries a batch of rows.
	EventRows
)

type ExecResult

type ExecResult struct {
	RowsAffected int64
	LastInsertID int64
}

ExecResult summarises a statement that returns no rows.

type Options

type Options struct {
	// ChunkSize is how many rows are gathered before a batch is published.
	ChunkSize int
	// MaxRows caps how many rows are read. Zero means no cap.
	MaxRows int
	// Schema is the one an unqualified name resolves against. Empty means the
	// schema the connection was opened with.
	Schema string

	// Exec sends the statement as one that returns a count rather than rows,
	// which is the only way the server's affected-row count can be read.
	//
	// It is the caller's decision because only the caller has the parsed
	// statement; asking the driver afterwards is not possible, since a write
	// sent as a query simply yields a result set with no columns and the
	// count is gone.
	Exec bool
}

Options tunes how a result set is streamed.

type Result added in v0.2.0

type Result struct {
	RowsAffected int64
	LastInsertID int64
}

Result is what a statement that returned no rows did instead.

RowsAffected is MySQL's own count, which for an UPDATE is the number of rows *changed* rather than matched: an UPDATE setting a column to the value it already held reports zero, and that is the server's answer rather than a miscount.

type Stream

type Stream struct {
	// Events yields progress until it is closed.
	Events <-chan Event
	// contains filtered or unexported fields
}

Stream is a statement in flight.

Everything after Query returns is delivered on Events, which is closed when the statement ends for any reason. This shape exists because the driver's QueryContext blocks until the server produces a result header: a slow statement would otherwise freeze the caller — and in the TUI, the caller is the event loop that has to stay responsive enough to cancel it.

func (*Stream) Cancel

func (s *Stream) Cancel() error

Cancel stops the statement on the server.

Cancelling the context alone only detaches the client: the server keeps executing until it finishes. KILL QUERY, sent over the separate control connection, is what actually stops the work.

func (*Stream) Close

func (s *Stream) Close() error

Close releases the stream's resources. It is safe to call repeatedly.

func (*Stream) ConnectionID

func (s *Stream) ConnectionID() uint64

ConnectionID returns the server-side connection id, or zero if the statement has not reached the server yet.

func (*Stream) Err

func (s *Stream) Err() error

Err reports why the stream ended, once Events is closed. It is nil when the result set was read to the end.

This mirrors sql.Rows and bufio.Scanner: iterate until the source is exhausted, then ask why it stopped.

func (*Stream) Result added in v0.2.0

func (s *Stream) Result() (Result, bool)

Result reports what a write did, and whether there was one to report.

Like Err, it is read after Events closes rather than delivered as an event, for the reason given on Event: a terminal event can be dropped when a cancelled stream closes, and the caller would not be able to tell the difference.

func (*Stream) Truncated

func (s *Stream) Truncated() bool

Truncated reports whether the stream stopped at Options.MaxRows rather than at the end of the result set.

func (*Stream) WaitConnectionID

func (s *Stream) WaitConnectionID(ctx context.Context) (uint64, error)

WaitConnectionID blocks until the server-side connection id is known.

func (*Stream) Warnings added in v0.2.0

func (s *Stream) Warnings() []Warning

Warnings lists what the server said about the statement, once Events has closed.

They are read on the connection that ran the statement, before it goes back to the pool. SHOW WARNINGS reports on the last statement executed on that connection, so asking any later — or on any other connection — would answer about something else entirely.

type Warning added in v0.2.0

type Warning struct {
	Level   string
	Code    uint16
	Message string
}

Warning is one row of SHOW WARNINGS.

MySQL reports data truncation, implicit conversion and several ALTER side effects only this way, while calling the statement a success — so a column silently cut short on insert is invisible to a client that never asks.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL