Skip to content

Commit 9cffd29

Browse files
authored
Release v2.1.1 (#47)
Support Insert/Update with generated column Support check invalid options Bug fixings: - Fix issue #44 on GitHub - Fix memory leak
2 parents 56fb787 + f14eed3 commit 9cffd29

File tree

201 files changed

+2703
-1086
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

201 files changed

+2703
-1086
lines changed

META.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
"name": "sqlite_fdw",
33
"abstract": "Foreign Data Wrapper for SQLite databases",
44
"description": "PostgreSQL extension which implements a Foreign Data Wrapper (FDW) for SQLite databases.",
5-
"version": "2.1.0",
5+
"version": "2.1.1",
66
"maintainer": "pgspider",
77
"license": "postgresql",
88
"provides": {
99
"sqlite_fdw": {
1010
"abstract": "Foreign Data Wrapper for SQLite databases",
1111
"file": "sqlite_fdw.c",
1212
"docfile": "README.md",
13-
"version": "2.1.0"
13+
"version": "2.1.1"
1414
}
1515
},
1616
"prereqs": {

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,11 @@ SELECT * FROM t1;
7979
- Support list cached connections to foreign servers by using function sqlite_fdw_get_connections()
8080
- Support discard cached connections to foreign servers by using function sqlite_fdw_disconnect(), sqlite_fdw_disconnect_all().
8181
- Support Bulk Insert by using batch_size option
82+
- Support Insert/Update with generated column
8283

8384
## Limitations
8485
- `COPY` command for foreign tables is not supported
86+
- IMPORT of generated column is not supported
8587
- Insert into a partitioned table which has foreign partitions is not supported
8688
- 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.
8789
## Contributing

connection.c

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ typedef struct ConnCacheEntry
4848
bool truncatable; /* check table can truncate or not */
4949
bool invalidated; /* true if reconnect is pending */
5050
Oid serverid; /* foreign server OID used to get server name */
51+
List *stmtList; /* list stmt associated with conn */
5152
uint32 server_hashvalue; /* hash value of foreign server OID */
5253
uint32 mapping_hashvalue; /* hash value of user mapping OID */
5354
} ConnCacheEntry;
@@ -76,6 +77,8 @@ static void sqlitefdw_inval_callback(Datum arg, int cacheid, uint32 hashvalue);
7677
#if PG_VERSION_NUM >= 140000
7778
static bool sqlite_disconnect_cached_connections(Oid serverid);
7879
#endif
80+
static void sqlite_finalize_list_stmt(List **list);
81+
static List *sqlite_append_stmt_to_list(List *list, sqlite3_stmt * stmt);
7982

8083
/*
8184
* sqlite_get_connection:
@@ -187,6 +190,7 @@ sqlite_make_new_connection(ConnCacheEntry *entry, ForeignServer *server)
187190
entry->serverid = server->serverid;
188191
entry->xact_depth = 0;
189192
entry->invalidated = false;
193+
entry->stmtList = NULL;
190194
entry->keep_connections = true;
191195
entry->server_hashvalue =
192196
GetSysCacheHashValue1(FOREIGNSERVEROID,
@@ -240,16 +244,11 @@ sqlite_cleanup_connection(void)
240244
hash_seq_init(&scan, ConnectionHash);
241245
while ((entry = (ConnCacheEntry *) hash_seq_search(&scan)))
242246
{
243-
sqlite3_stmt *cur = NULL;
244-
245247
if (entry->conn == NULL)
246248
continue;
247249

248-
while ((cur = sqlite3_next_stmt(entry->conn, cur)) != NULL)
249-
{
250-
elog(DEBUG1, "finalize %s", sqlite3_sql(cur));
251-
sqlite3_finalize(cur);
252-
}
250+
sqlite_finalize_list_stmt(&entry->stmtList);
251+
253252
elog(DEBUG1, "disconnecting sqlite_fdw connection %p", entry->conn);
254253
rc = sqlite3_close(entry->conn);
255254
entry->conn = NULL;
@@ -359,10 +358,6 @@ sqlitefdw_report_error(int elevel, sqlite3_stmt * stmt, sqlite3 * conn,
359358
if (sql)
360359
sql = pstrdup(sqlite3_sql(stmt));
361360
}
362-
363-
if (stmt)
364-
sqlite3_finalize(stmt);
365-
366361
ereport(ERROR,
367362
(errcode(sqlstate),
368363
errmsg("failed to execute remote SQL: rc=%d %s \n sql=%s",
@@ -412,6 +407,8 @@ sqlitefdw_xact_callback(XactEvent event, void *arg)
412407
/* Commit all remote transactions during pre-commit */
413408
if (!sqlite3_get_autocommit(entry->conn))
414409
sqlite_do_sql_command(entry->conn, "COMMIT", ERROR);
410+
/* Finalize all prepared statements */
411+
sqlite_finalize_list_stmt(&entry->stmtList);
415412
break;
416413
case XACT_EVENT_PRE_PREPARE:
417414

@@ -437,15 +434,10 @@ sqlitefdw_xact_callback(XactEvent event, void *arg)
437434
case XACT_EVENT_PARALLEL_ABORT:
438435
case XACT_EVENT_ABORT:
439436
{
440-
sqlite3_stmt *cur = NULL;
441-
442437
elog(DEBUG3, "abort transaction");
443438

444439
/* Finalize all prepared statements */
445-
while ((cur = sqlite3_next_stmt(entry->conn, NULL)) != NULL)
446-
{
447-
sqlite3_finalize(cur);
448-
}
440+
sqlite_finalize_list_stmt(&entry->stmtList);
449441

450442
/*
451443
* rollback if in transaction because SQLite may
@@ -880,6 +872,7 @@ sqlite_disconnect_cached_connections(Oid serverid)
880872
else
881873
{
882874
elog(DEBUG3, "discarding sqlite_fdw connection %p", entry->conn);
875+
sqlite_finalize_list_stmt(&entry->stmtList);
883876
sqlite3_close(entry->conn);
884877
entry->conn = NULL;
885878
result = true;
@@ -889,3 +882,61 @@ sqlite_disconnect_cached_connections(Oid serverid)
889882
return result;
890883
}
891884
#endif
885+
886+
/*
887+
* cache sqlite3 statement to finalize at the end of transaction
888+
*/
889+
void
890+
sqlite_cache_stmt(ForeignServer *server, sqlite3_stmt * *stmt)
891+
{
892+
bool found;
893+
ConnCacheEntry *entry;
894+
ConnCacheKey key = server->serverid;
895+
896+
/*
897+
* Find cached entry for requested connection.
898+
*/
899+
entry = hash_search(ConnectionHash, &key, HASH_ENTER, &found);
900+
901+
/* We must always have found the entry */
902+
Assert(found);
903+
904+
entry->stmtList = sqlite_append_stmt_to_list(entry->stmtList, *stmt);
905+
}
906+
907+
/*
908+
* finalize all sqlite statement
909+
*/
910+
static void
911+
sqlite_finalize_list_stmt(List **list)
912+
{
913+
ListCell *lc;
914+
915+
foreach(lc, *list)
916+
{
917+
sqlite3_stmt *stmt = (sqlite3_stmt *) lfirst(lc);
918+
919+
elog(DEBUG1, "sqlite_fdw: finalize %s", sqlite3_sql(stmt));
920+
sqlite3_finalize(stmt);
921+
}
922+
923+
list_free(*list);
924+
*list = NULL;
925+
}
926+
927+
/*
928+
* append sqlite3 stmt to the head of linked list
929+
*/
930+
static List *
931+
sqlite_append_stmt_to_list(List *list, sqlite3_stmt * stmt)
932+
{
933+
/*
934+
* CurrentMemoryContext is released before cleanup transaction (when the
935+
* list is called), so, use TopMemoryContext instead.
936+
*/
937+
MemoryContext oldcontext = MemoryContextSwitchTo(TopMemoryContext);
938+
939+
list = lappend(list, stmt);
940+
MemoryContextSwitchTo(oldcontext);
941+
return list;
942+
}

deparse.c

Lines changed: 90 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,27 +1545,66 @@ sqlite_deparse_insert(StringInfo buf, PlannerInfo *root,
15451545
List *targetAttrs, bool doNothing,
15461546
int *values_end_len)
15471547
{
1548+
#if PG_VERSION_NUM >= 140000
1549+
TupleDesc tupdesc = RelationGetDescr(rel);
1550+
bool all_columns_generated = true;
1551+
#endif
15481552
AttrNumber pindex;
15491553
bool first;
15501554
ListCell *lc;
15511555

15521556
appendStringInfo(buf, "INSERT %sINTO ", doNothing ? "OR IGNORE " : "");
15531557
sqlite_deparse_relation(buf, rel);
15541558

1559+
#if PG_VERSION_NUM >= 140000
1560+
1561+
/*
1562+
* Check all columns in table that they are all generated column or not.
1563+
* If true, we will skip all columns and just add 'DEFAULT VALUES'. If
1564+
* not, we still push down other columns which are not generated column.
1565+
*/
15551566
if (targetAttrs)
1567+
{
1568+
foreach(lc, targetAttrs)
1569+
{
1570+
int attnum = linitial_int(targetAttrs);
1571+
Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
1572+
1573+
if (!attr->attgenerated)
1574+
{
1575+
all_columns_generated = false;
1576+
break;
1577+
}
1578+
}
1579+
}
1580+
#endif
1581+
1582+
#if (PG_VERSION_NUM >= 140000)
1583+
if (targetAttrs && !all_columns_generated)
1584+
#else
1585+
if (targetAttrs)
1586+
#endif
15561587
{
15571588
appendStringInfoChar(buf, '(');
15581589

15591590
first = true;
15601591
foreach(lc, targetAttrs)
15611592
{
15621593
int attnum = lfirst_int(lc);
1594+
#if PG_VERSION_NUM >= 140000
1595+
Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
15631596

1564-
if (!first)
1565-
appendStringInfoString(buf, ", ");
1566-
first = false;
1597+
if (!attr->attgenerated)
1598+
{
1599+
#endif
1600+
if (!first)
1601+
appendStringInfoString(buf, ", ");
1602+
first = false;
15671603

1568-
sqlite_deparse_column_ref(buf, rtindex, attnum, root, false);
1604+
sqlite_deparse_column_ref(buf, rtindex, attnum, root, false);
1605+
#if PG_VERSION_NUM >= 140000
1606+
}
1607+
#endif
15691608
}
15701609

15711610
appendStringInfoString(buf, ") VALUES (");
@@ -1574,12 +1613,21 @@ sqlite_deparse_insert(StringInfo buf, PlannerInfo *root,
15741613
first = true;
15751614
foreach(lc, targetAttrs)
15761615
{
1577-
if (!first)
1578-
appendStringInfoString(buf, ", ");
1579-
first = false;
1616+
#if PG_VERSION_NUM >= 140000
1617+
int attnum = lfirst_int(lc);
1618+
Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
15801619

1581-
appendStringInfo(buf, "?");
1582-
pindex++;
1620+
if (!attr->attgenerated)
1621+
{
1622+
#endif
1623+
if (!first)
1624+
appendStringInfoString(buf, ", ");
1625+
first = false;
1626+
appendStringInfo(buf, "?");
1627+
pindex++;
1628+
#if PG_VERSION_NUM >= 140000
1629+
}
1630+
#endif
15831631
}
15841632

15851633
appendStringInfoChar(buf, ')');
@@ -1597,13 +1645,14 @@ sqlite_deparse_insert(StringInfo buf, PlannerInfo *root,
15971645
* right number of parameters.
15981646
*/
15991647
void
1600-
sqlite_rebuild_insert(StringInfo buf, char *orig_query,
1601-
int values_end_len, int num_cols,
1648+
sqlite_rebuild_insert(StringInfo buf, Relation rel, char *orig_query,
1649+
List *target_attrs, int values_end_len, int num_params,
16021650
int num_rows)
16031651
{
1604-
int i,
1605-
j;
1652+
TupleDesc tupdesc = RelationGetDescr(rel);
1653+
int i;
16061654
bool first;
1655+
ListCell *lc;
16071656

16081657
/* Make sure the values_end_len is sensible */
16091658
Assert((values_end_len > 0) && (values_end_len <= strlen(orig_query)));
@@ -1620,13 +1669,19 @@ sqlite_rebuild_insert(StringInfo buf, char *orig_query,
16201669
appendStringInfoString(buf, ", (");
16211670

16221671
first = true;
1623-
for (j = 0; j < num_cols; j++)
1672+
foreach(lc, target_attrs)
16241673
{
1625-
if (!first)
1626-
appendStringInfoString(buf, ", ");
1627-
first = false;
1674+
int attnum = lfirst_int(lc);
1675+
Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
1676+
1677+
if (!attr->attgenerated)
1678+
{
1679+
if (!first)
1680+
appendStringInfoString(buf, ", ");
1681+
first = false;
16281682

1629-
appendStringInfo(buf, "?");
1683+
appendStringInfo(buf, "?");
1684+
}
16301685
}
16311686

16321687
appendStringInfoChar(buf, ')');
@@ -2028,6 +2083,9 @@ sqlite_deparse_update(StringInfo buf, PlannerInfo *root,
20282083
Index rtindex, Relation rel,
20292084
List *targetAttrs, List *attnums)
20302085
{
2086+
#if PG_VERSION_NUM >= 140000
2087+
TupleDesc tupdesc = RelationGetDescr(rel);
2088+
#endif
20312089
AttrNumber pindex;
20322090
bool first;
20332091
ListCell *lc;
@@ -2042,14 +2100,21 @@ sqlite_deparse_update(StringInfo buf, PlannerInfo *root,
20422100
foreach(lc, targetAttrs)
20432101
{
20442102
int attnum = lfirst_int(lc);
2103+
#if PG_VERSION_NUM >= 140000
2104+
Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
20452105

2046-
if (!first)
2047-
appendStringInfoString(buf, ", ");
2048-
first = false;
2049-
2050-
sqlite_deparse_column_ref(buf, rtindex, attnum, root, false);
2051-
appendStringInfo(buf, " = ?");
2052-
pindex++;
2106+
if (!attr->attgenerated)
2107+
{
2108+
#endif
2109+
if (!first)
2110+
appendStringInfoString(buf, ", ");
2111+
first = false;
2112+
sqlite_deparse_column_ref(buf, rtindex, attnum, root, false);
2113+
appendStringInfo(buf, " = ?");
2114+
pindex++;
2115+
#if PG_VERSION_NUM >= 140000
2116+
}
2117+
#endif
20532118
}
20542119
i = 0;
20552120
foreach(lc, attnums)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)