Skip to content

Commit

Permalink
RELEASE v2.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Nguyen Ngoc Son authored and Nguyen Ngoc Son committed Sep 26, 2022
1 parent 9cffd29 commit fc708d7
Show file tree
Hide file tree
Showing 208 changed files with 22,707 additions and 11,680 deletions.
4 changes: 2 additions & 2 deletions License
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
SQLite Foreign Data Wrapper for PostgreSQL

Copyright (c) 2017 - 2021, TOSHIBA Corporation
Copyright (c) 2018, TOSHIBA CORPORATION
Copyright (c) 2011 - 2016, EnterpriseDB Corporation

Permission to use, copy, modify, and distribute this software and its
Expand All @@ -17,4 +17,4 @@ TOSHIBA CORPORATION SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
TOSHIBA CORPORATION HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
4 changes: 2 additions & 2 deletions META.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"name": "sqlite_fdw",
"abstract": "Foreign Data Wrapper for SQLite databases",
"description": "PostgreSQL extension which implements a Foreign Data Wrapper (FDW) for SQLite databases.",
"version": "2.1.1",
"version": "2.2.0",
"maintainer": "pgspider",
"license": "postgresql",
"provides": {
"sqlite_fdw": {
"abstract": "Foreign Data Wrapper for SQLite databases",
"file": "sqlite_fdw.c",
"docfile": "README.md",
"version": "2.1.1"
"version": "2.2.0"
}
},
"prereqs": {
Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# SQLite Foreign Data Wrapper for PostgreSQL
#
# Portions Copyright (c) 2021, TOSHIBA CORPORATION
# Portions Copyright (c) 2018, TOSHIBA CORPORATION
#
# IDENTIFICATION
# Makefile
Expand Down Expand Up @@ -36,8 +36,8 @@ include $(PGXS)
ifndef MAJORVERSION
MAJORVERSION := $(basename $(VERSION))
endif
ifeq (,$(findstring $(MAJORVERSION), 10 11 12 13 14))
$(error PostgreSQL 10, 11, 12, 13 or 14 is required to compile this extension)
ifeq (,$(findstring $(MAJORVERSION), 11 12 13 14 15))
$(error PostgreSQL 11, 12, 13, 14 or 15 is required to compile this extension)
endif

else
Expand All @@ -54,4 +54,4 @@ REGRESS_PREFIX_SUB = $(VERSION)
endif

REGRESS := $(addprefix $(REGRESS_PREFIX_SUB)/,$(REGRESS))
$(shell mkdir -p results/$(REGRESS_PREFIX_SUB)/extra)
$(shell mkdir -p results/$(REGRESS_PREFIX_SUB)/extra)
42 changes: 36 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SQLite Foreign Data Wrapper for PostgreSQL
This PostgreSQL extension is a Foreign Data Wrapper for [SQLite][1].

The current version can work with PostgreSQL 10, 11, 12, 13 and 14.
The current version can work with PostgreSQL 11, 12, 13, 14 and 15.

## Installation
### 1. Install SQLite library
Expand All @@ -28,6 +28,18 @@ make install
</pre>

## Usage

### FDW options

| **No** | Option name | Context | Required | Description |
|--------|-------------|---------|----------|-------------|
| 1 | database | SERVER | Required | SQLite database path. |
| 2 | table | FOREIGN TABLE | Required | SQLite table name. |
| 3 | key | ATTRIBUTE | Optional | Primary key or unique key of SQLite table. |
| 4 | column_type | ATTRIBUTE | Optional | Option to convert INT SQLite column (epoch Unix Time) to be treated/visualized as TIMESTAMP in PostgreSQL. |
| 5 | column_name | ATTRIBUTE | Optional | This option gives the column name to use for the column on the remote server. |
| 6 | truncatable | SERVER,<br>FOREIGN TABLE | Optional | This option controls whether sqlite_fdw allows foreign tables to be truncated using the TRUNCATE command. |

### Load extension
<pre>
CREATE EXTENSION sqlite_fdw;
Expand Down Expand Up @@ -67,11 +79,12 @@ SELECT * FROM t1;
</pre>

## Features
- Support update to foreign table
- Support INSERT/UPDATE/DELETE (both Direct modification and Foreign modification).
- WHERE clauses are pushdowned
- Aggregate function are pushdowned
- Order By is pushdowned
- Joins (left/right/inner) are pushdowned
- Joins (left/right/inner/cross) are pushdowned
- CASE expressions are pushdowned.
- Limit and Offset are pushdowned (*when all tables queried are fdw)
- Transactions
- Support TRUNCATE by deparsing into DELETE statement without WHERE clause
Expand All @@ -80,17 +93,34 @@ SELECT * FROM t1;
- Support discard cached connections to foreign servers by using function sqlite_fdw_disconnect(), sqlite_fdw_disconnect_all().
- Support Bulk Insert by using batch_size option
- Support Insert/Update with generated column

- Support GROUP BY, HAVING push-down.
- Support ON CONFLICT DO NOTHING.
## Limitations
- `COPY` command for foreign tables is not supported
- IMPORT of generated column is not supported
- Insert into a partitioned table which has foreign partitions is not supported
- Insert into a partitioned table which has foreign partitions is not supported. Error "Not support partition insert" will display.
- TRUNCATE in sqlite_fdw always delete data of both parent and child tables (no matter user inputs `TRUNCATE table CASCADE` or `TRUNCATE table RESTRICT`) if there are foreign-keys references with "ON DELETE CASCADE" clause.
- RETURNING is not supported.

## Notes
- SQLite evaluates division by zero as NULL. It is different from PostgreSQL, which will display "Division by zero" error.
- 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 as float8), the column of foreign table should be float8, too. If the column of foreign table is float4, it may cause wrong result when select.
- For 'key' option, user needs to specify the primary key column of SQLite table corresponding with the 'key' option. If not, wrong result may occur when update or delete.
- When Sum of data in table is out of range, SQLite FDW will display "Infinity" value. It is different from PostgreSQL FDW, which will display "ERROR: value out of range: overflow" error.
- For push-down case, the number after floating point may be different from the result of PostgreSQL.
- For numeric type, SQLite FDW use sqlite3_column_double to get value, while SQLite shell uses sqlite3_column_text to get value. Those 2 APIs may return different numeric value. Therefore, for numeric type, the value returned from SQLite FDW may different from the value returned from SQLite shell.
- SQLite FDW can return implementation-dependent order for column if the column is not specified in ORDER BY clause.
- WITH TIES option is not pushed down.
- upper, lower functions are not pushed down because they does not work with UNICODE character in SQLite.
- 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 type character varying will simply store the shorter string.
- SQLite FDW only supports ARRAY const, for example, ANY (ARRAY[1, 2, 3]) or ANY ('{1, 2 ,3}'). SQlite FDW does not support ARRAY expression, for example, ANY (ARRAY[c1, 1, c1+0]). For ANY(ARRAY) clause, SQLite FDW deparses it using IN operator.
- For sum function of SQLite, output of sum(bigint) is integer value. 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 of bigint, 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.
## Contributing
Opening issues and pull requests on GitHub are welcome.

## License
Copyright (c) 2017 - 2021, TOSHIBA Corporation
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.
Expand Down
110 changes: 79 additions & 31 deletions connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*
* SQLite Foreign Data Wrapper for PostgreSQL
*
* Portions Copyright (c) 2021, TOSHIBA CORPORATION
* Portions Copyright (c) 2018, TOSHIBA CORPORATION
*
* IDENTIFICATION
* connection.c
Expand Down Expand Up @@ -59,7 +59,7 @@ typedef struct ConnCacheEntry
static HTAB *ConnectionHash = NULL;

/* tracks whether any work is needed in callback functions */
static bool xact_got_connection = false;
static volatile bool xact_got_connection = false;

PG_FUNCTION_INFO_V1(sqlite_fdw_get_connections);
PG_FUNCTION_INFO_V1(sqlite_fdw_disconnect);
Expand All @@ -69,11 +69,13 @@ static void sqlite_make_new_connection(ConnCacheEntry *entry, ForeignServer *ser
void sqlite_do_sql_command(sqlite3 * conn, const char *sql, int level);
static void sqlite_begin_remote_xact(ConnCacheEntry *entry);
static void sqlitefdw_xact_callback(XactEvent event, void *arg);
static void sqlitefdw_reset_xact_state(ConnCacheEntry *entry, bool toplevel);
static void sqlitefdw_subxact_callback(SubXactEvent event,
SubTransactionId mySubid,
SubTransactionId parentSubid,
void *arg);
static void sqlitefdw_inval_callback(Datum arg, int cacheid, uint32 hashvalue);
static void sqlitefdw_abort_cleanup(ConnCacheEntry *entry, bool toplevel);
#if PG_VERSION_NUM >= 140000
static bool sqlite_disconnect_cached_connections(Oid serverid);
#endif
Expand Down Expand Up @@ -434,23 +436,30 @@ sqlitefdw_xact_callback(XactEvent event, void *arg)
case XACT_EVENT_PARALLEL_ABORT:
case XACT_EVENT_ABORT:
{
elog(DEBUG3, "abort transaction");

/* Finalize all prepared statements */
sqlite_finalize_list_stmt(&entry->stmtList);

/*
* rollback if in transaction because SQLite may
* already rollback
*/
if (!sqlite3_get_autocommit(entry->conn))
sqlite_do_sql_command(entry->conn, "ROLLBACK", WARNING);

sqlitefdw_abort_cleanup(entry, true);
break;
}
}
}

/* Reset state to show we're out of a transaction */
sqlitefdw_reset_xact_state(entry, true);
}

/*
* Regardless of the event type, we can now mark ourselves as out of the
* transaction. (Note: if we are here during PRE_COMMIT or PRE_PREPARE,
* this saves a useless scan of the hashtable during COMMIT or PREPARE.)
*/
xact_got_connection = false;
}

/*
* sqlitefdw_reset_xact_state --- Reset state to show we're out of a (sub)transaction
*/
static void
sqlitefdw_reset_xact_state(ConnCacheEntry *entry, bool toplevel) {
if (toplevel) {
/* Reset state to show we're out of a transaction */
entry->xact_depth = 0;

Expand All @@ -467,16 +476,11 @@ sqlitefdw_xact_callback(XactEvent event, void *arg)
sqlite3_close(entry->conn);
entry->conn = NULL;
}
} else {
/* Reset state to show we're out of a subtransaction */
entry->xact_depth--;
}

/*
* Regardless of the event type, we can now mark ourselves as out of the
* transaction. (Note: if we are here during PRE_COMMIT or PRE_PREPARE,
* this saves a useless scan of the hashtable during COMMIT or PREPARE.)
*/
xact_got_connection = false;
}

/*
* sqlitefdw_subxact_callback --- cleanup at subtransaction end.
*/
Expand Down Expand Up @@ -538,15 +542,11 @@ sqlitefdw_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
else
{
/* Rollback all remote subtransactions during abort */
snprintf(sql, sizeof(sql),
"ROLLBACK TO SAVEPOINT s%d; RELEASE SAVEPOINT s%d",
curlevel, curlevel);
if (!sqlite3_get_autocommit(entry->conn))
sqlite_do_sql_command(entry->conn, sql, ERROR);
sqlitefdw_abort_cleanup(entry, false);
}

/* OK, we're outta that level of subtransaction */
entry->xact_depth--;
sqlitefdw_reset_xact_state(entry, false);
}
}

Expand Down Expand Up @@ -628,13 +628,18 @@ sqlite_fdw_get_connections(PG_FUNCTION_ARGS)
#else
#define SQLITE_FDW_GET_CONNECTIONS_COLS 2
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
HASH_SEQ_STATUS scan;
ConnCacheEntry *entry;
#if PG_VERSION_NUM < 150000
TupleDesc tupdesc;
Tuplestorestate *tupstore;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
HASH_SEQ_STATUS scan;
ConnCacheEntry *entry;
#endif

#if PG_VERSION_NUM >= 150000
SetSingleFuncCall(fcinfo, 0);
#else
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
Expand All @@ -659,12 +664,15 @@ sqlite_fdw_get_connections(PG_FUNCTION_ARGS)
rsinfo->setDesc = tupdesc;

MemoryContextSwitchTo(oldcontext);
#endif

/* If cache doesn't exist, we return no records */
if (!ConnectionHash)
{
#if PG_VERSION_NUM < 150000
/* clean up and return the tuplestore */
tuplestore_donestoring(tupstore);
#endif

PG_RETURN_VOID();
}
Expand Down Expand Up @@ -728,12 +736,17 @@ sqlite_fdw_get_connections(PG_FUNCTION_ARGS)
values[0] = CStringGetTextDatum(server->servername);

values[1] = BoolGetDatum(!entry->invalidated);

#if PG_VERSION_NUM >= 150000
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
#else
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
#endif
}

#if PG_VERSION_NUM < 150000
/* clean up and return the tuplestore */
tuplestore_donestoring(tupstore);
#endif

PG_RETURN_VOID();
#endif
Expand Down Expand Up @@ -792,6 +805,41 @@ sqlite_fdw_disconnect_all(PG_FUNCTION_ARGS)
#endif
}

/*
* Abort remote transaction or subtransaction.
*
* "toplevel" should be set to true if toplevel (main) transaction is
* rollbacked, false otherwise.
*/
static void
sqlitefdw_abort_cleanup(ConnCacheEntry *entry, bool toplevel)
{
if (toplevel)
{
elog(DEBUG3, "abort transaction");

/* Finalize all prepared statements */
sqlite_finalize_list_stmt(&entry->stmtList);

/*
* rollback if in transaction because SQLite may
* already rollback
*/
if (!sqlite3_get_autocommit(entry->conn))
sqlite_do_sql_command(entry->conn, "ROLLBACK", WARNING);
}
else
{
char sql[100];
int curlevel = GetCurrentTransactionNestLevel();
snprintf(sql, sizeof(sql),
"ROLLBACK TO SAVEPOINT s%d; RELEASE SAVEPOINT s%d",
curlevel, curlevel);
if (!sqlite3_get_autocommit(entry->conn))
sqlite_do_sql_command(entry->conn, sql, ERROR);
}
}

#if PG_VERSION_NUM >= 140000
/*
* Workhorse to disconnect cached connections.
Expand Down
Loading

0 comments on commit fc708d7

Please sign in to comment.