Extensions
- sqlite_fdw 2.4.0
- Foreign Data Wrapper for SQLite databases
README
Contents
- SQLite Foreign Data Wrapper for PostgreSQL
- Contents
- Features
- Supported platforms
- Installation
- Usage
- CREATE SERVER options
- CREATE USER MAPPING options
- CREATE FOREIGN TABLE options
- IMPORT FOREIGN SCHEMA options
- TRUNCATE support
- Functions
- sqlite_fdw_version
- Identifier case handling
- Generated columns
- Character set handling
- Examples
- Limitations
- Tests
- Contributing
- Useful links
- License
SQLite Foreign Data Wrapper for PostgreSQL
This is a foreign data wrapper (FDW) to connect PostgreSQL to SQLite database file. This FDW works with PostgreSQL 12, 13, 14, 15, 16 and confirmed with SQLite 3.42.0.
+
Contents
- Features
- Supported platforms
- Installation
- Usage
- Functions
- Identifier case handling
- Generated columns
- Character set handling
- Examples
- Limitations
- Tests
- Contributing
- Useful links
Features
Common features
- Transactions
- Support
INSERT/UPDATE/DELETE(both Direct modification and Foreign modification). - Support
TRUNCATEby deparsing intoDELETEstatement withoutWHEREclause - Allow control over whether foreign servers keep connections open after transaction completion. This is controlled by
keep_connectionsand defaults to on - Support list cached connections to foreign servers by using function
sqlite_fdw_get_connections() - Support discard cached connections to foreign servers by using function
sqlite_fdw_disconnect(),sqlite_fdw_disconnect_all(). - Support Bulk
INSERTby usingbatch_sizeoption - Support
INSERT/UPDATEwith generated column - Support
ON CONFLICT DO NOTHING.
Pushdowning
WHEREclauses are pushdowned- Aggregate function are pushdowned
ORDER BYis pushdowned- Joins (left/right/inner/cross) are pushdowned
CASEexpressions are pushdowned.LIMITandOFFSETare pushdowned (*when all tables queried are fdw)- Support
GROUP BY,HAVINGpush-down. upper,lowerand other character case functions are not pushed down because they does not work with UNICODE character in SQLite.WITH TIESoption is not pushed down.
Notes about pushdowning
- For push-down case, the number after floating point may be different from the result of PostgreSQL.
Notes about features
- SQLite evaluates division by zero as
NULL. It is different from PostgreSQL, which will displayDivision by zeroerror. - The data type of column of foreign table should match with data type of column in SQLite to avoid wrong result. For example, if the column of SQLite is
float(which will be stored asfloat8), the column of foreign table should befloat8, too. If the column of foreign table isfloat4, it may cause wrong result whenSELECT. - For
keyoption, user needs to specify the primary key column of SQLite table corresponding with thekeyoption. If not, wrong result may occur whenUPDATEorDELETE. - When
Sumof data in table is out of range,sqlite_fdwwill displayInfinityvalue. It is different from PostgreSQL FDW, which will displayERROR: value out of range: overflowerror. - For
numericdata type,sqlite_fdwusesqlite3_column_doubleto get value, while SQLite shell usessqlite3_column_textto get value. Those 2 APIs may return different numeric value. Therefore, fornumericdata type, the value returned fromsqlite_fdwmay different from the value returned from SQLite shell. sqlite_fdwcan return implementation-dependent order for column if the column is not specified inORDER BYclause.- When the column type is
varchar array, if the string is shorter than the declared length, values of type character will be space-padded; values of typecharacter varyingwill simply store the shorter string.
Also see Limitations
Supported platforms
sqlite_fdw was developed on Linux and should run on any
reasonably POSIX-compliant system.
Installation
Package installation
For some Linux distributives internal packages with sqlite_fdw are avalilable.
- sqlite_fdw_14 rpm for CentOS 9, RHEL 9, Rocky Linux 9, AlmaLinux 9. Also there is other versions.
- sqlite_fdw git package for Arch Linux.
Source installation
Prerequisites:
* libsqlite3-dev, especially sqlite.h
* postgresql-server-dev, especially postgres.h
* gcc
* make
1. Install SQLite & Postgres Development Libraries
For Debian or Ubuntu:
apt-get install libsqlite3-dev
apt-get install postgresql-server-dev-XX, where XX matches your postgres version, i.e. apt-get install postgresql-server-dev-15
You can also download SQLite source code and build SQLite with FTS5 for full-text search.
2. Build and install sqlite_fdw
Add a directory of pg_config to PATH and build and install sqlite_fdw.
sh
make USE_PGXS=1
make install USE_PGXS=1
If you want to build sqlite_fdw in a source tree of PostgreSQL, use
sh
make
make install
Usage
CREATE SERVER options
sqlite_fdw accepts the following options via the CREATE SERVER command:
database as string, required
SQLite database path.
updatable as boolean, optional, default true
This option allow or disallow write operations on SQLite database file.
truncatable as boolean, optional, default true
Allows foreign tables to be truncated using the
TRUNCATEcommand.keep_connections as boolean, optional, default true
Allows to keep connections to SQLite while there is no SQL operations between PostgreSQL and SQLite.
batch_size as integer, optional, default 1
Specifies the number of rows which should be inserted in a single
INSERToperation. This setting can be overridden for individual tables.
CREATE USER MAPPING options
There is no user or password conceptions in SQLite, hence sqlite_fdw no need any CREATE USER MAPPING command.
In OS sqlite_fdw works as executed code with permissions of user of PostgreSQL server. Usually it is postgres OS user. For interacting with SQLite database without access errors ensure this user have follow permissions:
- read permission on all directories by path to the SQLite database file;
- read permission on SQLite database file;
- write permissions both on SQLite database file and directory it contains if you need a modification. During INSERT, UPDATE or DELETE in SQLite database, SQLite engine functions makes temporary files with transaction data in the directory near SQLite database file. Hence without write permissions you'll have a message failed to execute remote SQL: rc=8 attempt to write a readonly database.
CREATE FOREIGN TABLE options
sqlite_fdw accepts the following table-level options via the
CREATE FOREIGN TABLE command:
table as string, optional, no default
SQLite table name. Use if not equal to name of foreign table in PostgreSQL. Also see about identifier case handling.
truncatable as boolean, optional, default from the same
CREATE SERVERoptionSee
CREATE SERVERoptions section for details.batch_size as integer, optional, default from the same
CREATE SERVERoptionSee
CREATE SERVERoptions section for details.updatable as boolean, optional, default true
This option can allow or disallow write operations on a SQLite table independed of the same server option.
sqlite_fdw accepts the following column-level options via the
CREATE FOREIGN TABLE command:
column_name as string, optional, no default
This option gives the column name to use for the column on the remote server. Also see about identifier case handling.
column_type as string, optional, no default
Option to convert INT SQLite column (epoch Unix Time) to be treated/visualized as TIMESTAMP in PostgreSQL.
key as boolean, optional, default false
Indicates a column as a part of primary key or unique key of SQLite table.
IMPORT FOREIGN SCHEMA options
sqlite_fdw supports IMPORT FOREIGN SCHEMA
(PostgreSQL 9.5+) and accepts no custom options for this command.
TRUNCATE support
sqlite_fdw implements the foreign data wrapper TRUNCATE API, available
from PostgreSQL 14.
As SQlite does not provide a TRUNCATE command, it is simulated with a
simple unqualified DELETE operation.
Actually, TRUNCATE ... CASCADE can be simulated if we create child table of SQLite with foreign keys and ON DELETE CASCADE, and then executing TRUNCATE (which will be deparsed to DELETE).
Following restrictions apply:
- TRUNCATE ... RESTART IDENTITY is not supported
- SQLite tables with foreign key references can cause errors during truncating
Functions
As well as the standard sqlite_fdw_handler() and sqlite_fdw_validator()
functions, sqlite_fdw provides the following user-callable utility functions:
SETOF record sqlite_fdw_get_connections(server_name text, valid bool)
bool sqlite_fdw_disconnect(text)
Closes connection from PostgreSQL to SQLite in the current session.
bool sqlite_fdw_disconnect_all()
sqlite_fdw_version(); Returns standard "version integer" as
major version * 10000 + minor version * 100 + bugfix. ```sqlite_fdw_version
20400```
Identifier case handling
PostgreSQL folds identifiers to lower case by default, SQlite is case insensetive by default. It's important to be aware of potential issues with table and column names.
This SQL isn't correct for SQLite: Error: duplicate column name: a, but is correct for PostgreSQL
sql
CREATE TABLE T (
"A" INTEGER,
"a" NUMERIC
);
For SQLite there is no difference between
sql
SELECT * FROM t; -- №1
SELECT * FROM T; -- №2
SELECT * FROM "t"; -- №3
SELECT * FROM "T"; -- №4
For PostgreSQL the query with comment №4 is independend query to table T, not to table t as other queries.
If there is
sql
CREATE TABLE T (
A INTEGER,
b REAL
);
in SQLite, both a and A , b and B columns will have the same real datasource in SQlite in follow foreign table:
sql
CREATE FOREIGN TABLE "SQLite test" (
"A" int4 NULL,
"B" float8 NULL,
"a" int8 NULL,
"b" numeric NULL
)
SERVER sqlite_server
OPTIONS (table 'T');
Generated columns
SQLite provides support for generated columns.
Behaviour of sqlite_fdw with this columns isn't yet described.
Note that while sqlite_fdw will INSERT or UPDATE the generated column value
in SQLite, there is nothing to stop the value being modified within SQLite,
and hence no guarantee that in subsequent SELECT operations the column will
still contain the expected generated value. This limitation also applies to
postgres_fdw.
For more details on generated columns see:
Character set handling
There is no character set metadata
stored in SQLite, only PRAGMA encoding; with UTF-only values (UTF-8, UTF-16, UTF-16le, UTF-16be). SQLite text output function guarantees UTF-8 encoding.
When sqlite_fdw connects to a SQLite, all strings are interpreted acording the PostgreSQL database's server encoding.
It's not a problem if your PostgreSQL database encoding belongs to Unicode family. Otherewise interpretation transformation problems can occur. Some unproper for PostgreSQL database encoding characters will be replaced to default 'no such character' character or there will error like character with byte sequence 0x** in encoding "UTF8" has no equivalent in encoding "**".
Character case functions such as upper, lower and other are not pushed down because they does not work with UNICODE character in SQLite.
Sqlite_fdw tested with PostgreSQL database encodings EUC_JP, EUC_KR, ISO_8859_5, ISO_8859_6, ISO_8859_7, ISO_8859_8, LATIN1, LATIN2, LATIN3, LATIN4, LATIN5, LATIN6, LATIN7, LATIN8, LATIN9, LATIN9, LATIN10, WIN1250, WIN1251, WIN1252, WIN1253, WIN1254, WIN1255, WIN1256, WIN1257 and it's synomyms. Some other encodings also can be supported, but not tested.
Examples
Install the extension:
Once for a database you need, as PostgreSQL superuser.
sql
CREATE EXTENSION sqlite_fdw;
Create a foreign server with appropriate configuration:
Once for a foreign datasource you need, as PostgreSQL superuser. Please specify SQLite database path using database option.
sql
CREATE SERVER sqlite_server
FOREIGN DATA WRAPPER sqlite_fdw
OPTIONS (
database '/path/to/database'
);
Grant usage on foreign server to normal user in PostgreSQL:
Once for a normal user (non-superuser) in PostgreSQL, as PostgreSQL superuser. It is a good idea to use a superuser only where really necessary, so let's allow a normal user to use the foreign server (this is not required for the example to work, but it's secirity recomedation).
sql
GRANT USAGE ON FOREIGN SERVER sqlite_server TO pguser;
Where pguser is a sample user for works with foreign server (and foreign tables).
User mapping
There is no user or password conceptions in SQLite, hence sqlite_fdw no need any CREATE USER MAPPING command. About access problems see in CREATE USER MAPPING options.
Create foreign table
All CREATE FOREIGN TABLE SQL commands can be executed as a normal PostgreSQL user if there were correct GRANT USAGE ON FOREIGN SERVER. No need PostgreSQL supersuer for secirity reasons but also works with PostgreSQL supersuer.
Please specify table option if SQLite table name is different from foreign table name.
sql
CREATE FOREIGN TABLE t1 (
a integer,
b text
)
SERVER sqlite_server
OPTIONS (
table 't1_sqlite'
);
If you want to update tables, please add OPTIONS (key 'true') to a primary key or unique key like the following:
sql
CREATE FOREIGN TABLE t1(
a integer OPTIONS (key 'true'),
b text
)
SERVER sqlite_server
OPTIONS (
table 't1_sqlite'
);
If you need to convert INT SQLite column (epoch Unix Time) to be treated/visualized as TIMESTAMP in PostgreSQL, please add OPTIONS (column_type 'INT') when defining FOREIGN table at PostgreSQL like the following:
sql
CREATE FOREIGN TABLE t1(
a integer,
b text,
c timestamp without time zone OPTIONS (column_type 'INT')
)
SERVER sqlite_server
OPTIONS (
table 't1_sqlite'
);
As above, but with aliased column names:
sql
CREATE FOREIGN TABLE t1(
a integer,
b text OPTIONS (column_name 'test_id'),
c timestamp without time zone OPTIONS (column_type 'INT', column_name 'unixtime')
)
SERVER sqlite_server
OPTIONS (
table 't1_sqlite'
);
Import a SQLite database as schema to PostgreSQL:
sql
IMPORT FOREIGN SCHEMA someschema
FROM SERVER sqlite_server
INTO public;
Note: someschema has no particular meaning and can be set to an arbitrary value.
Access foreign table
For the table from previous examples
sql
SELECT * FROM t1;
Limitations
SQL commands
COPYcommand for foreign tables is not supportedIMPORTof generated column is not supportedINSERTinto a partitioned table which has foreign partitions is not supported. ErrorNot support partition insertwill display.TRUNCATEinsqlite_fdwalways delete data of both parent and child tables (no matter user inputsTRUNCATE table CASCADEorTRUNCATE table RESTRICT) if there are foreign-keys references withON DELETE CASCADEclause.RETURNINGis not supported.
Arrays
sqlite_fdwonly supportsARRAYconst, for example,ANY (ARRAY[1, 2, 3])orANY ('{1, 2 ,3}').sqlite_fdwdoes not supportARRAYexpression, for example,ANY (ARRAY[c1, 1, c1+0]).- For
ANY(ARRAY)clause,sqlite_fdwdeparses it usingINoperator.
Numbers (range and precision)
- For
sumfunction of SQLite, output ofsum(bigint)isintegervalue. If input values are big, the overflow error may occurs on SQLite because it overflow within the range of signed 64bit. For PostgreSQL, it can calculate as over the precision ofbigint, so overflow does not occur. - SQLite promises to preserve the 15 most significant digits of a floating point value. The big value which exceed 15 most significant digits may become different value after inserted.
- SQLite does not support
numerictype as PostgreSQL. Therefore, it does not allow to store numbers with too high precision and scale. Error out of range occurs. - SQLite does not support special values for IEEE 754-2008 numbers such as
NaN,+Infinityand-Infinityin SQL expressions with numeric context. Also SQLite can not store this values withrealaffinity. In opposite to SQLite, PostgreSQL can store special values in columns belongs torealdatatype family such asfloatordouble precisionand use arithmetic comparation for this values. In oppose to PostgreSQL, SQLite storesNaN,+Infinityand-Infinityas a text values. Also conditions with special literals (such asn < '+Infinity'orm > '-Infinity') isn't numeric conditions in SQLite and gives unexpected result after pushdowning in oppose to internal PostgreSQL calculations. DuringINSERT INTO ... SELECTor inWHEREconditionssqlite_fdwuses given by PostgreSQL standard case sensetive literals only in follow forms:NaN,-Infinity,Infinity, not original strings fromWHEREcondition. This can caused selecting issues.
Boolean values
sqlite_fdwboolean values support exists only forboolcolumns in foreign table. SQLite documentation recommends to store boolean as value withintegeraffinity.NULLisn't converted, 1 converted totrue, all otherNOT NULLvalues converted tofalse. DuringSELECT ... WHERE condition_columncondition converted only tocondition_column.sqlite_fdwdon't provides limited support of boolean values ifboolcolumn in foreign table mapped to SQLitetextaffinity.
Tests
Test directory have structure as following:
sql
+---sql
| +---12.15
| | filename1.sql
| | filename2.sql
| |
| +---13.11
| | filename1.sql
| | filename2.sql
| |
.................
| \---15.3
| filename1.sql
| filename2.sql
|
\---expected
| +---12.15
| | filename1.out
| | filename2.out
| |
| +---13.11
| | filename1.out
| | filename2.out
| |
.................
| \---15.3
filename1.out
filename2.out
The test cases for each version are based on the test of corresponding version of PostgreSQL.
You can execute test by test.sh directly.
The version of PostgreSQL is detected automatically by $(VERSION) variable in Makefile.
The corresponding sql and expected directory will be used to compare the result. For example, for Postgres 15.0, you can execute "test.sh" directly, and the sql/15.0 and expected/15.0 will be used to compare automatically.
Contributing
Opening issues and pull requests on GitHub are welcome. For pull request, please make sure these items below for testing: - Create test cases (if needed) for the latest version of PostgreSQL supported by sqlite_fdw. - Execute test cases and update expectations for the latest version of PostgreSQL - Test creation and execution for other PostgreSQL versions are welcome but not required.
Useful links
Source
- https://github.com/pgspider/sqlite_fdw
- https://pgxn.org/dist/sqlite_fdw/
General FDW Documentation
- https://www.postgresql.org/docs/current/ddl-foreign-data.html
- https://www.postgresql.org/docs/current/sql-createforeigndatawrapper.html
- https://www.postgresql.org/docs/current/sql-createforeigntable.html
- https://www.postgresql.org/docs/current/sql-importforeignschema.html
- https://www.postgresql.org/docs/current/fdwhandler.html
- https://www.postgresql.org/docs/current/postgres-fdw.html
Other FDWs
- https://wiki.postgresql.org/wiki/Fdw
- https://pgxn.org/tag/fdw/
License
Copyright (c) 2018, TOSHIBA CORPORATION Copyright (c) 2011 - 2016, EnterpriseDB Corporation
Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies.
See the License file for full details.