stephencelis / SQLite.swift

A type-safe, Swift-language layer over SQLite3.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Creating a column affinity based on a string does not produce the correct affinity

stefansaasen opened this issue · comments

E.g. take the example table definition from the TestHelper:

CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
age INTEGER,
salary REAL,
admin BOOLEAN NOT NULL DEFAULT 0 CHECK (admin IN (0, 1)),
manager_id INTEGER,
created_at DATETIME,
FOREIGN KEY(manager_id) REFERENCES users(id)
)

According to 3.1. Determination Of Column Affinity the affinity of a column is based on the declared type. With the "parsing" following a set of five rules (see linked page).

So for the above table definition, the column affinity should be:

  • id -> rule 1: INTEGER
  • email -> rule 2: TEXT
  • age -> rule 1: INTEGER
  • salary -> rule 4: REAL
  • admin -> rule 5: NUMERIC
  • manager_id -> rule 1: INTEGER
  • created_at -> rule 5: NUMERIC

but the affinity is incorrect for the following columns: admin and created_at (TEXT instead of NUMERIC).

See

ColumnDefinition(name: "id",
primaryKey: .init(autoIncrement: false, onConflict: nil),
type: .INTEGER,
nullable: true,
defaultValue: .NULL,
references: nil),
ColumnDefinition(name: "email",
primaryKey: nil,
type: .TEXT,
nullable: false,
defaultValue: .NULL,
references: nil),
ColumnDefinition(name: "age",
primaryKey: nil,
type: .INTEGER,
nullable: true,
defaultValue: .NULL,
references: nil),
ColumnDefinition(name: "salary",
primaryKey: nil,
type: .REAL,
nullable: true,
defaultValue: .NULL,
references: nil),
ColumnDefinition(name: "admin",
primaryKey: nil,
type: .TEXT,
nullable: false,
defaultValue: .numericLiteral("0"),
references: nil),
ColumnDefinition(name: "manager_id",
primaryKey: nil, type: .INTEGER,
nullable: true,
defaultValue: .NULL,
references: .init(table: "users", column: "manager_id", primaryKey: "id", onUpdate: nil, onDelete: nil)),
ColumnDefinition(name: "created_at",
primaryKey: nil,
type: .TEXT,
nullable: true,
defaultValue: .NULL,
references: nil)

A possible solution is to create the Affinity and implement the 5 rules, e.g. like here: stefansaasen@fabbe8c

There is one important thing to consider here, the default affinity for declared types that are not covered is now NUMERIC instead of TEXT. E.g. with the gotcha mentioned here: https://www.sqlite.org/datatype3.html#determination_of_column_affinity

And the declared type of "STRING" has an affinity of NUMERIC, not TEXT

Should probably considered to be a breaking change.

P.S.: Happy to create a PR if the approach in the commit linked above is acceptable.

Build Information

  • Include the SQLite.swift version: 0.14.1
  • Mention Xcode and OS X versions affected: Xcode 14.3 and macOS Ventura 13.4
  • How do do you integrate SQLite.swift in your project: Swift Package manager

Possible fix: #1218