sqlsanitize

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package sqlsanitize turns one application SQL statement into the two forms the application-SQL ingest path keeps: a literal-free text that is safe to store, and a canonical form whose hash is the statement's deduplication key.

The rules it applies are:

N1  every literal becomes `?`, and a PostgreSQL `$n` is rewritten to the same `?`
    so that one statement has one stored form however the application wrote it.
    An application may already have replaced its literals, which is why the
    rewrite has to be idempotent
N2  comments are removed; all other spacing is preserved byte for byte
N3  identifiers and keywords are copied verbatim, quotes and case included
N4  an IN list of placeholders is one placeholder
N5  a VALUES list of repeated placeholder groups is one group

N1-N3 shape both forms; N4 and N5 shape the fingerprint alone, so the stored text keeps what the application wrote. Nothing else folds: an operator and a placeholder count are part of a statement's identity. See fold.go. Any later change to these rules must bump Version, so that a deployment can tell which rows were fingerprinted under which rules.

Classification reads the token's source text rather than omni's token-type constants, which are unexported in every dialect package. See token.go.

Index

Constants

View Source
const (
	// Version identifies the rules applied by this package, and is stored beside every
	// fingerprint. It is 1 because this is the first rule set to run anywhere: the
	// foldings in fold.go were added while the feature was still unreleased, so they are
	// part of version 1 rather than a second version with rows to migrate.
	//
	// Its whole purpose is the next change. Rewriting a rule splits one statement into
	// rows fingerprinted under the old one, and a deployment that already holds rows
	// needs to know that happened; Version is how it finds out.
	Version = 1

	// Placeholder is the wire and stored form of every literal. Applications send
	// it, and it is the only form that is ever persisted.
	Placeholder = "?"
)

Variables

View Source
var ErrUnlexable = errors.New("statement could not be lexed")

ErrUnlexable reports a statement that could not be tokenized: empty input, text that is not UTF-8 at all, or a dialect whose lexer stopped on a malformed token. Such a statement is never stored.

Functions

func Analyzable

func Analyzable(engine storepb.Engine, text string) string

Analyzable returns the text an analyzer can parse. Every placeholder becomes a string literal, because the MySQL family's grammar has no production that accepts a placeholder at all. The rewrite walks tokens, so a `?` inside a quoted identifier is never touched.

Types

type Statement

type Statement struct {
	// Text is what gets stored: every literal replaced by Placeholder, comments
	// removed, and all other spacing left as the application wrote it. Spacing is
	// preserved because the analyzer names an unaliased expression column after its
	// source text, and that name is stored in column_lineage.
	Text string

	// Canonical is Text with its tokens re-joined by single spaces. It exists only to
	// be hashed: whitespace must not split one statement into two.
	Canonical string

	// Fingerprint is the statement's deduplication key, the sha256 of Canonical.
	Fingerprint string
}

Statement is one statement in the two forms the ingest path keeps.

func Sanitize

func Sanitize(engine storepb.Engine, sql string) (Statement, error)

Sanitize rewrites one statement. The caller splits a multi-statement script first: this package is defined for exactly one statement, like the analyzers it feeds.

Jump to

Keyboard shortcuts

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