|
|
@@ -0,0 +1,209 @@
|
|
|
+// Package capabilities describes the SQL surface an engine build supports.
|
|
|
+//
|
|
|
+// The document is machine-readable and versioned separately from the engine
|
|
|
+// build. Clients should compare SchemaVersion when parsing it and use
|
|
|
+// EngineVersion to pin behavior to a specific PizzaSQL release. Keep this file
|
|
|
+// in sync with the tests it advertises: every claim here must be covered by an
|
|
|
+// engine test in the same repository.
|
|
|
+package capabilities
|
|
|
+
|
|
|
+import (
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/danfragoso/pizzasql-next/pkg/version"
|
|
|
+)
|
|
|
+
|
|
|
+// SchemaVersion changes only when the document's shape or semantics change in a
|
|
|
+// way clients must handle. Additive fields do not require a bump.
|
|
|
+const SchemaVersion = 1
|
|
|
+
|
|
|
+// Feature reports whether a capability is supported and, when it is not,
|
|
|
+// whether the engine rejects the syntax or accepts it with different semantics.
|
|
|
+type Feature struct {
|
|
|
+ Supported bool `json:"supported"`
|
|
|
+ Status string `json:"status"`
|
|
|
+ SQLState string `json:"sqlstate,omitempty"`
|
|
|
+ Notes string `json:"notes,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+// Document is the machine-readable capability description served by
|
|
|
+// GET /capabilities.
|
|
|
+type Document struct {
|
|
|
+ SchemaVersion int `json:"schema_version"`
|
|
|
+ Engine string `json:"engine"`
|
|
|
+ EngineVersion string `json:"engine_version"`
|
|
|
+ Commit string `json:"commit"`
|
|
|
+ GeneratedAt string `json:"generated_at,omitempty"`
|
|
|
+
|
|
|
+ Protocol Protocol `json:"protocol"`
|
|
|
+ Constraints Constraints `json:"constraints"`
|
|
|
+ DDL DDL `json:"ddl"`
|
|
|
+ Transactions Transactions `json:"transactions"`
|
|
|
+ Types Types `json:"types"`
|
|
|
+ Parameters Parameters `json:"parameters"`
|
|
|
+ JSON JSON `json:"json"`
|
|
|
+ ErrorCodes map[string]string `json:"error_codes"`
|
|
|
+ Documentation Documentation `json:"documentation"`
|
|
|
+}
|
|
|
+
|
|
|
+type Protocol struct {
|
|
|
+ PostgresCompat string `json:"postgres_compat"`
|
|
|
+ SQLiteCompat string `json:"sqlite_compat"`
|
|
|
+ SimpleQuery bool `json:"simple_query"`
|
|
|
+ ExtendedQuery bool `json:"extended_query"`
|
|
|
+ TLS string `json:"tls"`
|
|
|
+}
|
|
|
+
|
|
|
+type Constraints struct {
|
|
|
+ NotNull Feature `json:"not_null"`
|
|
|
+ Unique Feature `json:"unique"`
|
|
|
+ PrimaryKey Feature `json:"primary_key"`
|
|
|
+ CompositePK Feature `json:"composite_primary_key"`
|
|
|
+ ForeignKey Feature `json:"foreign_key"`
|
|
|
+ Check Feature `json:"check"`
|
|
|
+ DefaultValues Feature `json:"default_values"`
|
|
|
+}
|
|
|
+
|
|
|
+type DDL struct {
|
|
|
+ AddColumn Feature `json:"add_column"`
|
|
|
+ AddColumnBackfill Feature `json:"add_column_backfill"`
|
|
|
+ DropColumn Feature `json:"drop_column"`
|
|
|
+ RenameColumn Feature `json:"rename_column"`
|
|
|
+ RenameColumnIndexes Feature `json:"rename_column_updates_indexes"`
|
|
|
+ CreateTableIfNotExists bool `json:"create_table_if_not_exists"`
|
|
|
+ AddColumnIfNotExists bool `json:"add_column_if_not_exists"`
|
|
|
+}
|
|
|
+
|
|
|
+type Transactions struct {
|
|
|
+ Model string `json:"model"`
|
|
|
+ Isolation string `json:"isolation"`
|
|
|
+ SerializationCode string `json:"serialization_sqlstate"`
|
|
|
+ RowLocks Feature `json:"row_locks"`
|
|
|
+ Savepoints Feature `json:"savepoints"`
|
|
|
+ RetryRecommended bool `json:"retry_recommended"`
|
|
|
+}
|
|
|
+
|
|
|
+type Types struct {
|
|
|
+ Integer bool `json:"integer"`
|
|
|
+ Bigint bool `json:"bigint"`
|
|
|
+ Real bool `json:"real"`
|
|
|
+ Text bool `json:"text"`
|
|
|
+ Blob bool `json:"blob"`
|
|
|
+ Boolean bool `json:"boolean"`
|
|
|
+ DateTime bool `json:"datetime"`
|
|
|
+ JSONText bool `json:"json_as_text"`
|
|
|
+ JSONB Feature `json:"jsonb"`
|
|
|
+ Arrays Feature `json:"arrays"`
|
|
|
+ RowID Feature `json:"rowid"`
|
|
|
+}
|
|
|
+
|
|
|
+type Parameters struct {
|
|
|
+ Positional bool `json:"positional"`
|
|
|
+ MaxOID string `json:"max_oid"`
|
|
|
+ Arrays Feature `json:"arrays"`
|
|
|
+ BinaryNumeric bool `json:"binary_numeric"`
|
|
|
+}
|
|
|
+
|
|
|
+type JSON struct {
|
|
|
+ Storage string `json:"storage"`
|
|
|
+ Functions string `json:"functions"`
|
|
|
+ ArrowOperators Feature `json:"arrow_operators"`
|
|
|
+ InvalidInput string `json:"invalid_input"`
|
|
|
+}
|
|
|
+
|
|
|
+type Documentation struct {
|
|
|
+ Compatibility string `json:"compatibility"`
|
|
|
+ Isolation string `json:"isolation"`
|
|
|
+}
|
|
|
+
|
|
|
+// Current returns the capability document for this build.
|
|
|
+func Current() *Document {
|
|
|
+ return &Document{
|
|
|
+ SchemaVersion: SchemaVersion,
|
|
|
+ Engine: "pizzasql",
|
|
|
+ EngineVersion: version.String(),
|
|
|
+ Commit: version.Commit,
|
|
|
+ GeneratedAt: time.Now().UTC().Format(time.RFC3339),
|
|
|
+
|
|
|
+ Protocol: Protocol{
|
|
|
+ PostgresCompat: "14.0",
|
|
|
+ SQLiteCompat: "3.35.0",
|
|
|
+ SimpleQuery: true,
|
|
|
+ ExtendedQuery: true,
|
|
|
+ TLS: "terminated by the managed pgproxy, not the engine listener",
|
|
|
+ },
|
|
|
+
|
|
|
+ Constraints: Constraints{
|
|
|
+ NotNull: Feature{Supported: true, Status: "enforced"},
|
|
|
+ Unique: Feature{Supported: true, Status: "enforced", SQLState: "23505", Notes: "unique indexes, INLINE UNIQUE, and ON CONFLICT are enforced atomically"},
|
|
|
+ PrimaryKey: Feature{Supported: true, Status: "enforced", Notes: "single-column only"},
|
|
|
+ CompositePK: Feature{Supported: false, Status: "rejected", SQLState: "0A000", Notes: "declare a single-column primary key"},
|
|
|
+ ForeignKey: Feature{Supported: false, Status: "rejected", SQLState: "0A000", Notes: "inline and table-level FOREIGN KEY are rejected; enforce referential integrity in the application, cascades are not implemented"},
|
|
|
+ Check: Feature{Supported: false, Status: "rejected", SQLState: "0A000", Notes: "inline and table-level CHECK are rejected; enforce the rule in the application"},
|
|
|
+ DefaultValues: Feature{Supported: true, Status: "constant_only", SQLState: "0A000", Notes: "non-constant defaults (CURRENT_TIMESTAMP, function calls) are rejected instead of being frozen at DDL time"},
|
|
|
+ },
|
|
|
+
|
|
|
+ DDL: DDL{
|
|
|
+ AddColumn: Feature{Supported: true, Status: "metadata_only"},
|
|
|
+ AddColumnBackfill: Feature{Supported: false, Status: "no_backfill", Notes: "existing rows read NULL; a DEFAULT applies to later INSERTs only"},
|
|
|
+ DropColumn: Feature{Supported: true, Status: "rewrites_rows"},
|
|
|
+ RenameColumn: Feature{Supported: true, Status: "rewrites_rows"},
|
|
|
+ RenameColumnIndexes: Feature{Supported: false, Status: "stale_index_metadata", Notes: "drop and recreate indexes that reference a renamed column"},
|
|
|
+ CreateTableIfNotExists: true,
|
|
|
+ AddColumnIfNotExists: true,
|
|
|
+ },
|
|
|
+
|
|
|
+ Transactions: Transactions{
|
|
|
+ Model: "optimistic compare-batch commit; no MVCC or snapshots",
|
|
|
+ Isolation: "serializable-equivalent for single-row compare-batch commits; write skew is possible across independent rows",
|
|
|
+ SerializationCode: "40001",
|
|
|
+ RowLocks: Feature{Supported: false, Status: "rejected", SQLState: "0A000", Notes: "SELECT ... FOR UPDATE/SHARE and NOWAIT/SKIP LOCKED are rejected"},
|
|
|
+ Savepoints: Feature{Supported: true, Status: "enforced"},
|
|
|
+ RetryRecommended: true,
|
|
|
+ },
|
|
|
+
|
|
|
+ Types: Types{
|
|
|
+ Integer: true,
|
|
|
+ Bigint: true,
|
|
|
+ Real: true,
|
|
|
+ Text: true,
|
|
|
+ Blob: true,
|
|
|
+ Boolean: true,
|
|
|
+ DateTime: true,
|
|
|
+ JSONText: true,
|
|
|
+ JSONB: Feature{Supported: false, Status: "type_name_alias", Notes: "JSONB is accepted as a column type name with no native semantics; values are stored as text and reported as TEXT over the wire"},
|
|
|
+ Arrays: Feature{Supported: false, Status: "rejected", SQLState: "0A000"},
|
|
|
+ RowID: Feature{Supported: true, Status: "auto_assigned", Notes: "rowid/oid/_rowid_ are BIGINT over the wire; monotonic when the engine assigns the rowid, stable across UPDATE, not monotonic for client-assigned descending INTEGER PRIMARY KEY values"},
|
|
|
+ },
|
|
|
+
|
|
|
+ Parameters: Parameters{
|
|
|
+ Positional: true,
|
|
|
+ MaxOID: "int8/text/bool/bytea/float; arrays are rejected",
|
|
|
+ Arrays: Feature{Supported: false, Status: "rejected", SQLState: "0A000", Notes: "id = ANY($1) is rejected; expand to IN (...) with individual parameters"},
|
|
|
+ BinaryNumeric: true,
|
|
|
+ },
|
|
|
+
|
|
|
+ JSON: JSON{
|
|
|
+ Storage: "TEXT (JSON and JSONB type names are accepted without native semantics; insert JSON as text)",
|
|
|
+ Functions: "json, json_extract, json_set, json_insert, json_replace, json_remove, json_valid, json_type, json_array, json_object, json_quote, json_group_array",
|
|
|
+ ArrowOperators: Feature{Supported: false, Status: "rejected", SQLState: "42601", Notes: "-> and ->> are not implemented; use json_extract"},
|
|
|
+ InvalidInput: "json_extract/json_set throw 'malformed JSON'; json_valid returns 0",
|
|
|
+ },
|
|
|
+
|
|
|
+ ErrorCodes: map[string]string{
|
|
|
+ "23505": "unique_violation",
|
|
|
+ "40001": "serialization_failure",
|
|
|
+ "0A000": "feature_not_supported",
|
|
|
+ "42601": "syntax_error",
|
|
|
+ "25P02": "in_failed_sql_transaction",
|
|
|
+ "08P01": "protocol_violation (managed proxy: TLS required)",
|
|
|
+ "53300": "too_many_connections (managed proxy: organization quota)",
|
|
|
+ "XX000": "internal_error",
|
|
|
+ },
|
|
|
+
|
|
|
+ Documentation: Documentation{
|
|
|
+ Compatibility: "https://docs.database.pizza/sql-reference/compatibility/",
|
|
|
+ Isolation: "https://docs.database.pizza/engine/concurrency/",
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|