| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- package pgserver
- import (
- "testing"
- )
- // A dangling foreign key reports SQLSTATE 23503 on both the simple and the
- // extended protocol, and inside a transaction block it leaves the transaction
- // failed like the other integrity errors.
- func TestForeignKeySQLStateAcrossProtocolPaths(t *testing.T) {
- for _, extended := range []bool{false, true} {
- for _, transaction := range []bool{false, true} {
- c, client := newDataConnection(t)
- runQuery(t, c, client, simpleQueryMessage("CREATE TABLE parent (id INTEGER PRIMARY KEY)"))
- runQuery(t, c, client, simpleQueryMessage("CREATE TABLE child (id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES parent(id))"))
- if transaction {
- runQuery(t, c, client, simpleQueryMessage("BEGIN"))
- }
- sql := "INSERT INTO child (id, parent_id) VALUES (1, 99)"
- var messages []*Message
- if extended {
- messages = runExtendedExecution(t, c, client, sql)
- } else {
- messages = runQuery(t, c, client, simpleQueryMessage(sql))
- }
- if transaction {
- // A staged write is validated at COMMIT, not by the INSERT.
- if code := errorCode(messages[0]); code != "" {
- t.Fatalf("extended=%v staged INSERT SQLSTATE = %q, want none", extended, code)
- }
- messages = runQuery(t, c, client, simpleQueryMessage("COMMIT"))
- }
- if code := errorCode(messages[0]); code != ErrCodeForeignKeyViolation {
- t.Fatalf("extended=%v transaction=%v SQLSTATE = %q, want %q", extended, transaction, code, ErrCodeForeignKeyViolation)
- }
- if transaction {
- if c.txStatus != TxStatusIdle {
- t.Fatalf("tx status = %v, want idle after a failed COMMIT", c.txStatus)
- }
- runQuery(t, c, client, simpleQueryMessage("ROLLBACK"))
- }
- count := runQuery(t, c, client, simpleQueryMessage("SELECT COUNT(*) FROM child"))
- if values := dataRowValues(t, count[1]); len(values) != 1 || values[0] != "0" {
- t.Fatalf("rejected insert left rows behind: %v", values)
- }
- }
- }
- }
- // Deleting a referenced parent reports 23503 over the wire and leaves the
- // parent row in place.
- func TestForeignKeyParentDeleteSQLState(t *testing.T) {
- c, client := newDataConnection(t)
- runQuery(t, c, client, simpleQueryMessage("CREATE TABLE parent (id INTEGER PRIMARY KEY)"))
- runQuery(t, c, client, simpleQueryMessage("CREATE TABLE child (id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES parent(id))"))
- runQuery(t, c, client, simpleQueryMessage("INSERT INTO parent (id) VALUES (1)"))
- runQuery(t, c, client, simpleQueryMessage("INSERT INTO child (id, parent_id) VALUES (10, 1)"))
- messages := runQuery(t, c, client, simpleQueryMessage("DELETE FROM parent WHERE id = 1"))
- if code := errorCode(messages[0]); code != ErrCodeForeignKeyViolation {
- t.Fatalf("DELETE SQLSTATE = %q, want %q", code, ErrCodeForeignKeyViolation)
- }
- count := runQuery(t, c, client, simpleQueryMessage("SELECT COUNT(*) FROM parent"))
- if values := dataRowValues(t, count[1]); len(values) != 1 || values[0] != "1" {
- t.Fatalf("rejected delete removed the parent: %v", values)
- }
- }
- // Foreign keys are always enforced, so disabling them is rejected as an
- // unsupported feature (0A000) rather than a generic execution error.
- func TestForeignKeyPragmaOffReturnsFeatureNotSupported(t *testing.T) {
- c, client := newDataConnection(t)
- messages := runQuery(t, c, client, simpleQueryMessage("PRAGMA foreign_keys = OFF"))
- if code := errorCode(messages[0]); code != ErrCodeFeatureNotSupported {
- t.Fatalf("PRAGMA foreign_keys = OFF SQLSTATE = %q, want %q", code, ErrCodeFeatureNotSupported)
- }
- }
|