Skip to content

Commit c872d27

Browse files
authored
Use REAL not FLOAT as SQLite column type (#680)
* Use REAL not FLOAT as SQLite column type, refs #645 * Fix for REAL columns by CSV --detect-types Refs #645 (comment) * Removed note about strict and REAL
1 parent fb93452 commit c872d27

File tree

9 files changed

+61
-37
lines changed

9 files changed

+61
-37
lines changed

docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Unreleased
1010
----------
1111

1212
- The ``table.insert_all()`` and ``table.upsert_all()`` methods can now accept an iterator of lists or tuples as an alternative to dictionaries. The first item should be a list/tuple of column names. See :ref:`python_api_insert_lists` for details. (:issue:`672`)
13+
- **Breaking change:** The default floating point column type has been changed from ``FLOAT`` to ``REAL``, which is the correct SQLite type for floating point values. This affects auto-detected columns when inserting data. (:issue:`645`)
1314

1415
.. _v4_0a0:
1516

docs/cli-reference.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,8 +457,8 @@ See :ref:`cli_transform_table`.
457457
--rename column2 column_renamed
458458

459459
Options:
460-
--type <TEXT CHOICE>... Change column type to INTEGER, TEXT, FLOAT or
461-
BLOB
460+
--type <TEXT CHOICE>... Change column type to INTEGER, TEXT, FLOAT,
461+
REAL or BLOB
462462
--drop TEXT Drop this column
463463
--rename <TEXT TEXT>... Rename this column to X
464464
-o, --column-order TEXT Reorder columns
@@ -1142,7 +1142,7 @@ See :ref:`cli_add_column`.
11421142
::
11431143

11441144
Usage: sqlite-utils add-column [OPTIONS] PATH TABLE COL_NAME
1145-
[[integer|int|float|text|str|blob|bytes]]
1145+
[[integer|int|float|real|text|str|blob|bytes]]
11461146

11471147
Add a column to the specified table
11481148

docs/cli.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,7 +1247,7 @@ To stop inserting after a specified number of records - useful for getting a fas
12471247
12481248
A progress bar is displayed when inserting data from a file. You can hide the progress bar using the ``--silent`` option.
12491249

1250-
By default every column inserted from a CSV or TSV file will be of type ``TEXT``. To automatically detect column types - resulting in a mix of ``TEXT``, ``INTEGER`` and ``FLOAT`` columns, use the ``--detect-types`` option (or its shortcut ``-d``).
1250+
By default every column inserted from a CSV or TSV file will be of type ``TEXT``. To automatically detect column types - resulting in a mix of ``TEXT``, ``INTEGER`` and ``REAL`` columns, use the ``--detect-types`` option (or its shortcut ``-d``).
12511251

12521252
For example, given a ``creatures.csv`` file containing this:
12531253

@@ -1274,7 +1274,7 @@ Will produce this schema:
12741274
CREATE TABLE "creatures" (
12751275
"name" TEXT,
12761276
"age" INTEGER,
1277-
"weight" FLOAT
1277+
"weight" REAL
12781278
);
12791279
12801280
You can set the ``SQLITE_UTILS_DETECT_TYPES`` environment variable if you want ``--detect-types`` to be the default behavior:
@@ -1589,7 +1589,7 @@ This will result in the following schema:
15891589
CREATE TABLE "images" (
15901590
"path" TEXT PRIMARY KEY,
15911591
"md5" TEXT,
1592-
"mtime" FLOAT
1592+
"mtime" REAL
15931593
);
15941594
15951595
Note that there's no ``content`` column here at all - if you specify custom columns using ``-c`` you need to include ``-c content`` to create that column.
@@ -1888,8 +1888,8 @@ The type of the returned values will be taken into account when creating the new
18881888
18891889
CREATE TABLE "places" (
18901890
"location" TEXT,
1891-
"latitude" FLOAT,
1892-
"longitude" FLOAT
1891+
"latitude" REAL,
1892+
"longitude" REAL
18931893
);
18941894
18951895
The code function can also return ``None``, in which case its output will be ignored. You can drop the original column at the end of the operation by adding ``--drop``.

docs/python-api.rst

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ This will create a table with the following schema:
548548
"id" INTEGER PRIMARY KEY,
549549
"name" TEXT,
550550
"age" INTEGER,
551-
"weight" FLOAT
551+
"weight" REAL
552552
)
553553
554554
.. _python_api_explicit_create:
@@ -1271,11 +1271,11 @@ You can specify the ``col_type`` argument either using a SQLite type as a string
12711271

12721272
The ``col_type`` is optional - if you omit it the type of ``TEXT`` will be used.
12731273

1274-
SQLite types you can specify are ``"TEXT"``, ``"INTEGER"``, ``"FLOAT"`` or ``"BLOB"``.
1274+
SQLite types you can specify are ``"TEXT"``, ``"INTEGER"``, ``"FLOAT"``, ``"REAL"`` or ``"BLOB"``.
12751275

12761276
If you pass a Python type, it will be mapped to SQLite types as shown here::
12771277

1278-
float: "FLOAT"
1278+
float: "REAL"
12791279
int: "INTEGER"
12801280
bool: "INTEGER"
12811281
str: "TEXT"
@@ -1294,12 +1294,9 @@ If you pass a Python type, it will be mapped to SQLite types as shown here::
12941294
np.uint16: "INTEGER"
12951295
np.uint32: "INTEGER"
12961296
np.uint64: "INTEGER"
1297-
np.float16: "FLOAT"
1298-
np.float32: "FLOAT"
1299-
np.float64: "FLOAT"
1300-
1301-
.. note::
1302-
In sqlite-utils 3.x ``FLOAT`` is used for floating point columns when the correct column type is actually ``REAL``. If you specify ``strict=True`` tables created in strict mode will use the correct column type of ``REAL`` instead. We plan to change this behavior in ``sqlite-utils`` 4.x to always use ``REAL``, but this will represent a minor breaking change and so is being held for the next major release, see issue :issue:`645`.
1297+
np.float16: "REAL"
1298+
np.float32: "REAL"
1299+
np.float64: "REAL"
13031300

13041301
You can also add a column that is a foreign key reference to another table using the ``fk`` parameter:
13051302

sqlite_utils/cli.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
4646

47-
VALID_COLUMN_TYPES = ("INTEGER", "TEXT", "FLOAT", "BLOB")
47+
VALID_COLUMN_TYPES = ("INTEGER", "TEXT", "FLOAT", "REAL", "BLOB")
4848

4949
UNICODE_ERROR = """
5050
{}
@@ -419,7 +419,7 @@ def dump(path, load_extension):
419419
@click.argument(
420420
"col_type",
421421
type=click.Choice(
422-
["integer", "int", "float", "text", "str", "blob", "bytes"],
422+
["integer", "int", "float", "real", "text", "str", "blob", "bytes"],
423423
case_sensitive=False,
424424
),
425425
required=False,
@@ -2425,10 +2425,12 @@ def schema(
24252425
"--type",
24262426
type=(
24272427
str,
2428-
click.Choice(["INTEGER", "TEXT", "FLOAT", "BLOB"], case_sensitive=False),
2428+
click.Choice(
2429+
["INTEGER", "TEXT", "FLOAT", "REAL", "BLOB"], case_sensitive=False
2430+
),
24292431
),
24302432
multiple=True,
2431-
help="Change column type to INTEGER, TEXT, FLOAT or BLOB",
2433+
help="Change column type to INTEGER, TEXT, FLOAT, REAL or BLOB",
24322434
)
24332435
@click.option("--drop", type=str, multiple=True, help="Drop this column")
24342436
@click.option(

sqlite_utils/db.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ class Default:
189189
DEFAULT = Default()
190190

191191
COLUMN_TYPE_MAPPING = {
192-
float: "FLOAT",
192+
float: "REAL",
193193
int: "INTEGER",
194194
bool: "INTEGER",
195195
str: "TEXT",
@@ -203,19 +203,21 @@ class Default:
203203
datetime.date: "TEXT",
204204
datetime.time: "TEXT",
205205
datetime.timedelta: "TEXT",
206-
decimal.Decimal: "FLOAT",
206+
decimal.Decimal: "REAL",
207207
None.__class__: "TEXT",
208208
uuid.UUID: "TEXT",
209209
# SQLite explicit types
210210
"TEXT": "TEXT",
211211
"INTEGER": "INTEGER",
212212
"FLOAT": "FLOAT",
213+
"REAL": "REAL",
213214
"BLOB": "BLOB",
214215
"text": "TEXT",
215216
"str": "TEXT",
216217
"integer": "INTEGER",
217218
"int": "INTEGER",
218-
"float": "FLOAT",
219+
"float": "REAL",
220+
"real": "REAL",
219221
"blob": "BLOB",
220222
"bytes": "BLOB",
221223
}
@@ -232,9 +234,9 @@ class Default:
232234
np.uint16: "INTEGER",
233235
np.uint32: "INTEGER",
234236
np.uint64: "INTEGER",
235-
np.float16: "FLOAT",
236-
np.float32: "FLOAT",
237-
np.float64: "FLOAT",
237+
np.float16: "REAL",
238+
np.float32: "REAL",
239+
np.float64: "REAL",
238240
}
239241
)
240242
except AttributeError:

tests/test_cli.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ def test_create_index_desc(db_path):
284284
"int",
285285
'CREATE TABLE "dogs" (\n "name" TEXT\n, "integer" INTEGER)',
286286
),
287-
("float", "FLOAT", 'CREATE TABLE "dogs" (\n "name" TEXT\n, "float" FLOAT)'),
287+
("float", "FLOAT", 'CREATE TABLE "dogs" (\n "name" TEXT\n, "float" REAL)'),
288288
("blob", "blob", 'CREATE TABLE "dogs" (\n "name" TEXT\n, "blob" BLOB)'),
289289
("blob", "BLOB", 'CREATE TABLE "dogs" (\n "name" TEXT\n, "blob" BLOB)'),
290290
("blob", "bytes", 'CREATE TABLE "dogs" (\n "name" TEXT\n, "blob" BLOB)'),
@@ -2240,6 +2240,28 @@ def test_upsert_detect_types(tmpdir, option):
22402240
]
22412241

22422242

2243+
def test_csv_detect_types_creates_real_columns(tmpdir):
2244+
"""Test that CSV import with --detect-types creates REAL columns for floats"""
2245+
db_path = str(tmpdir / "test.db")
2246+
data = "name,age,weight\nCleo,6,45.5\nDori,1,3.5"
2247+
result = CliRunner().invoke(
2248+
cli.cli,
2249+
["insert", db_path, "creatures", "-", "--csv", "--detect-types"],
2250+
catch_exceptions=False,
2251+
input=data,
2252+
)
2253+
assert result.exit_code == 0
2254+
db = Database(db_path)
2255+
# Check that the schema uses REAL for the weight column
2256+
assert db["creatures"].schema == (
2257+
'CREATE TABLE "creatures" (\n'
2258+
' "name" TEXT,\n'
2259+
' "age" INTEGER,\n'
2260+
' "weight" REAL\n'
2261+
")"
2262+
)
2263+
2264+
22432265
def test_integer_overflow_error(tmpdir):
22442266
db_path = str(tmpdir / "test.db")
22452267
result = CliRunner().invoke(

tests/test_cli_convert.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ def test_convert_multi_complex_column_types(fresh_db_and_path):
408408
assert db["rows"].schema == (
409409
'CREATE TABLE "rows" (\n'
410410
' "id" INTEGER PRIMARY KEY\n'
411-
', "is_str" TEXT, "is_float" FLOAT, "is_int" INTEGER, "is_bytes" BLOB)'
411+
', "is_str" TEXT, "is_float" REAL, "is_int" INTEGER, "is_bytes" BLOB)'
412412
)
413413

414414

tests/test_create.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def test_create_table(fresh_db):
4343
assert ["test_table"] == fresh_db.table_names()
4444
assert [
4545
{"name": "text_col", "type": "TEXT"},
46-
{"name": "float_col", "type": "FLOAT"},
46+
{"name": "float_col", "type": "REAL"},
4747
{"name": "int_col", "type": "INTEGER"},
4848
{"name": "bool_col", "type": "INTEGER"},
4949
{"name": "bytes_col", "type": "BLOB"},
@@ -52,7 +52,7 @@ def test_create_table(fresh_db):
5252
assert (
5353
'CREATE TABLE "test_table" (\n'
5454
' "text_col" TEXT,\n'
55-
' "float_col" FLOAT,\n'
55+
' "float_col" REAL,\n'
5656
' "int_col" INTEGER,\n'
5757
' "bool_col" INTEGER,\n'
5858
' "bytes_col" BLOB,\n'
@@ -143,7 +143,7 @@ def test_create_table_with_not_null(fresh_db):
143143
[{"name": "create", "type": "TEXT"}, {"name": "table", "type": "TEXT"}],
144144
),
145145
({"day": datetime.time(11, 0)}, [{"name": "day", "type": "TEXT"}]),
146-
({"decimal": decimal.Decimal("1.2")}, [{"name": "decimal", "type": "FLOAT"}]),
146+
({"decimal": decimal.Decimal("1.2")}, [{"name": "decimal", "type": "REAL"}]),
147147
(
148148
{"memoryview": memoryview(b"hello")},
149149
[{"name": "memoryview", "type": "BLOB"}],
@@ -193,7 +193,7 @@ def test_create_table_with_custom_columns(method_name, use_old_upsert):
193193
{"name": "id", "type": "INTEGER"},
194194
{"name": "name", "type": "TEXT"},
195195
{"name": "age", "type": "INTEGER"},
196-
{"name": "weight", "type": "FLOAT"},
196+
{"name": "weight", "type": "REAL"},
197197
]
198198
assert expected_columns == [
199199
{"name": col.name, "type": col.type} for col in table.columns
@@ -357,7 +357,7 @@ def test_create_error_if_invalid_self_referential_foreign_keys(fresh_db):
357357
"weight",
358358
float,
359359
None,
360-
'CREATE TABLE "dogs" (\n "name" TEXT\n, "weight" FLOAT)',
360+
'CREATE TABLE "dogs" (\n "name" TEXT\n, "weight" REAL)',
361361
),
362362
("text", "TEXT", None, 'CREATE TABLE "dogs" (\n "name" TEXT\n, "text" TEXT)'),
363363
(
@@ -561,7 +561,7 @@ def test_index_foreign_keys_if_index_name_is_already_used(fresh_db):
561561
),
562562
(
563563
{"hats": 5, "rating": 3.5},
564-
[{"name": "hats", "type": "INTEGER"}, {"name": "rating", "type": "FLOAT"}],
564+
[{"name": "hats", "type": "INTEGER"}, {"name": "rating", "type": "REAL"}],
565565
),
566566
],
567567
)
@@ -1197,7 +1197,7 @@ def test_create(fresh_db):
11971197
assert fresh_db["t"].schema == (
11981198
'CREATE TABLE "t" (\n'
11991199
' "id" INTEGER PRIMARY KEY,\n'
1200-
' "float" FLOAT NOT NULL,\n'
1200+
' "float" REAL NOT NULL,\n'
12011201
' "text" TEXT,\n'
12021202
' "integer" INTEGER NOT NULL DEFAULT 0,\n'
12031203
' "bytes" BLOB\n'
@@ -1360,7 +1360,7 @@ def test_insert_upsert_strict(fresh_db, method_name, strict):
13601360
def test_create_table_strict(fresh_db, strict):
13611361
table = fresh_db.create_table("t", {"id": int, "f": float}, strict=strict)
13621362
assert table.strict == strict or not fresh_db.supports_strict
1363-
expected_schema = 'CREATE TABLE "t" (\n' ' "id" INTEGER,\n' ' "f" FLOAT\n' ")"
1363+
expected_schema = 'CREATE TABLE "t" (\n' ' "id" INTEGER,\n' ' "f" REAL\n' ")"
13641364
if strict and not fresh_db.supports_strict:
13651365
return
13661366
if strict:

0 commit comments

Comments
 (0)