mirror of https://github.com/citusdata/citus.git
Merge pull request #4 from citusdata/fdw-relfilenode
create relfilenode for FDWmerge-cstore-pykello
commit
b8b5d3aeee
241
cstore_fdw.c
241
cstore_fdw.c
|
@ -21,9 +21,13 @@
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/reloptions.h"
|
#include "access/reloptions.h"
|
||||||
#include "access/tuptoaster.h"
|
#include "access/tuptoaster.h"
|
||||||
|
#include "access/xact.h"
|
||||||
|
#include "catalog/catalog.h"
|
||||||
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "catalog/pg_foreign_table.h"
|
#include "catalog/pg_foreign_table.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
|
#include "catalog/storage.h"
|
||||||
#include "commands/copy.h"
|
#include "commands/copy.h"
|
||||||
#include "commands/dbcommands.h"
|
#include "commands/dbcommands.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
|
@ -50,18 +54,20 @@
|
||||||
#include "parser/parser.h"
|
#include "parser/parser.h"
|
||||||
#include "parser/parse_coerce.h"
|
#include "parser/parse_coerce.h"
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
|
#include "storage/smgr.h"
|
||||||
#include "tcop/utility.h"
|
#include "tcop/utility.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
#if PG_VERSION_NUM < 120000
|
||||||
|
#include "utils/rel.h"
|
||||||
|
#endif
|
||||||
#if PG_VERSION_NUM >= 120000
|
#if PG_VERSION_NUM >= 120000
|
||||||
#include "utils/snapmgr.h"
|
#include "utils/snapmgr.h"
|
||||||
#else
|
#else
|
||||||
#include "utils/tqual.h"
|
#include "utils/tqual.h"
|
||||||
#endif
|
#endif
|
||||||
#if PG_VERSION_NUM < 120000
|
#include "utils/syscache.h"
|
||||||
#include "utils/rel.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "cstore.h"
|
#include "cstore.h"
|
||||||
#include "cstore_fdw.h"
|
#include "cstore_fdw.h"
|
||||||
|
@ -121,9 +127,10 @@ static uint64 CopyIntoCStoreTable(const CopyStmt *copyStatement,
|
||||||
const char *queryString);
|
const char *queryString);
|
||||||
static uint64 CopyOutCStoreTable(CopyStmt *copyStatement, const char *queryString);
|
static uint64 CopyOutCStoreTable(CopyStmt *copyStatement, const char *queryString);
|
||||||
static void CStoreProcessAlterTableCommand(AlterTableStmt *alterStatement);
|
static void CStoreProcessAlterTableCommand(AlterTableStmt *alterStatement);
|
||||||
static List * DroppedCStoreFilenameList(DropStmt *dropStatement);
|
static List * DroppedCStoreRelidList(DropStmt *dropStatement);
|
||||||
static List * FindCStoreTables(List *tableList);
|
static List * FindCStoreTables(List *tableList);
|
||||||
static List * OpenRelationsForTruncate(List *cstoreTableList);
|
static List * OpenRelationsForTruncate(List *cstoreTableList);
|
||||||
|
static void InitializeRelFileNode(Relation relation);
|
||||||
static void TruncateCStoreTables(List *cstoreRelationList);
|
static void TruncateCStoreTables(List *cstoreRelationList);
|
||||||
static bool CStoreTable(Oid relationId);
|
static bool CStoreTable(Oid relationId);
|
||||||
static bool CStoreServer(ForeignServer *server);
|
static bool CStoreServer(ForeignServer *server);
|
||||||
|
@ -183,6 +190,9 @@ static void CStoreEndForeignInsert(EState *executorState, ResultRelInfo *relatio
|
||||||
static bool CStoreIsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel,
|
static bool CStoreIsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel,
|
||||||
RangeTblEntry *rte);
|
RangeTblEntry *rte);
|
||||||
#endif
|
#endif
|
||||||
|
static void cstore_fdw_initrel(Relation rel);
|
||||||
|
static Relation cstore_fdw_open(Oid relationId, LOCKMODE lockmode);
|
||||||
|
static Relation cstore_fdw_openrv(RangeVar *relation, LOCKMODE lockmode);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(cstore_ddl_event_end_trigger);
|
PG_FUNCTION_INFO_V1(cstore_ddl_event_end_trigger);
|
||||||
PG_FUNCTION_INFO_V1(cstore_table_size);
|
PG_FUNCTION_INFO_V1(cstore_table_size);
|
||||||
|
@ -261,7 +271,7 @@ cstore_ddl_event_end_trigger(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid relationId = RangeVarGetRelid(createStatement->base.relation,
|
Oid relationId = RangeVarGetRelid(createStatement->base.relation,
|
||||||
AccessShareLock, false);
|
AccessShareLock, false);
|
||||||
Relation relation = heap_open(relationId, AccessExclusiveLock);
|
Relation relation = cstore_fdw_open(relationId, AccessExclusiveLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure database directory exists before creating a table.
|
* Make sure database directory exists before creating a table.
|
||||||
|
@ -359,17 +369,43 @@ CStoreProcessUtility(Node * parseTree, const char * queryString,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ListCell *fileListCell = NULL;
|
List *dropRelids = DroppedCStoreRelidList((DropStmt *) parseTree);
|
||||||
List *droppedTables = DroppedCStoreFilenameList((DropStmt *) parseTree);
|
List *dropFiles = NIL;
|
||||||
|
ListCell *lc = NULL;
|
||||||
|
|
||||||
|
/* drop smgr storage */
|
||||||
|
foreach(lc, dropRelids)
|
||||||
|
{
|
||||||
|
Oid relid = lfirst_oid(lc);
|
||||||
|
Relation relation = cstore_fdw_open(relid, AccessExclusiveLock);
|
||||||
|
CStoreOptions *cstoreOptions = CStoreGetOptions(relid);
|
||||||
|
char *defaultfilename = CStoreDefaultFilePath(relid);
|
||||||
|
|
||||||
|
RelationOpenSmgr(relation);
|
||||||
|
RelationDropStorage(relation);
|
||||||
|
heap_close(relation, AccessExclusiveLock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip files that are placed in default location, they are handled
|
||||||
|
* by sql drop trigger. Both paths are generated by code, use
|
||||||
|
* of strcmp is safe here.
|
||||||
|
*/
|
||||||
|
if (strcmp(defaultfilename, cstoreOptions->filename) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dropFiles = lappend(dropFiles, cstoreOptions->filename);
|
||||||
|
}
|
||||||
|
|
||||||
CALL_PREVIOUS_UTILITY(parseTree, queryString, context, paramListInfo,
|
CALL_PREVIOUS_UTILITY(parseTree, queryString, context, paramListInfo,
|
||||||
destReceiver, completionTag);
|
destReceiver, completionTag);
|
||||||
|
|
||||||
foreach(fileListCell, droppedTables)
|
/* drop files */
|
||||||
|
foreach(lc, dropFiles)
|
||||||
{
|
{
|
||||||
char *fileName = lfirst(fileListCell);
|
char *filename = lfirst(lc);
|
||||||
|
DeleteCStoreTableFiles(filename);
|
||||||
DeleteCStoreTableFiles(fileName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -562,7 +598,7 @@ CopyIntoCStoreTable(const CopyStmt *copyStatement, const char *queryString)
|
||||||
* Open and lock the relation. We acquire ShareUpdateExclusiveLock to allow
|
* Open and lock the relation. We acquire ShareUpdateExclusiveLock to allow
|
||||||
* concurrent reads, but block concurrent writes.
|
* concurrent reads, but block concurrent writes.
|
||||||
*/
|
*/
|
||||||
relation = heap_openrv(copyStatement->relation, ShareUpdateExclusiveLock);
|
relation = cstore_fdw_openrv(copyStatement->relation, ShareUpdateExclusiveLock);
|
||||||
relationId = RelationGetRelid(relation);
|
relationId = RelationGetRelid(relation);
|
||||||
|
|
||||||
/* allocate column values and nulls arrays */
|
/* allocate column values and nulls arrays */
|
||||||
|
@ -773,13 +809,13 @@ CStoreProcessAlterTableCommand(AlterTableStmt *alterStatement)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DropppedCStoreFilenameList extracts and returns the list of cstore file names
|
* DropppedCStoreRelidList extracts and returns the list of cstore relids
|
||||||
* from DROP table statement
|
* from DROP table statement
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
DroppedCStoreFilenameList(DropStmt *dropStatement)
|
DroppedCStoreRelidList(DropStmt *dropStatement)
|
||||||
{
|
{
|
||||||
List *droppedCStoreFileList = NIL;
|
List *droppedCStoreRelidList = NIL;
|
||||||
|
|
||||||
if (dropStatement->removeType == OBJECT_FOREIGN_TABLE)
|
if (dropStatement->removeType == OBJECT_FOREIGN_TABLE)
|
||||||
{
|
{
|
||||||
|
@ -792,26 +828,13 @@ DroppedCStoreFilenameList(DropStmt *dropStatement)
|
||||||
Oid relationId = RangeVarGetRelid(rangeVar, AccessShareLock, true);
|
Oid relationId = RangeVarGetRelid(rangeVar, AccessShareLock, true);
|
||||||
if (CStoreTable(relationId))
|
if (CStoreTable(relationId))
|
||||||
{
|
{
|
||||||
CStoreOptions *cstoreOptions = CStoreGetOptions(relationId);
|
droppedCStoreRelidList = lappend_oid(droppedCStoreRelidList,
|
||||||
char *defaultfilename = CStoreDefaultFilePath(relationId);
|
relationId);
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip files that are placed in default location, they are handled
|
|
||||||
* by sql drop trigger. Both paths are generated by code, use
|
|
||||||
* of strcmp is safe here.
|
|
||||||
*/
|
|
||||||
if (strcmp(defaultfilename, cstoreOptions->filename) == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
droppedCStoreFileList = lappend(droppedCStoreFileList,
|
|
||||||
cstoreOptions->filename);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return droppedCStoreFileList;
|
return droppedCStoreRelidList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -850,7 +873,7 @@ OpenRelationsForTruncate(List *cstoreTableList)
|
||||||
foreach(relationCell, cstoreTableList)
|
foreach(relationCell, cstoreTableList)
|
||||||
{
|
{
|
||||||
RangeVar *rangeVar = (RangeVar *) lfirst(relationCell);
|
RangeVar *rangeVar = (RangeVar *) lfirst(relationCell);
|
||||||
Relation relation = heap_openrv(rangeVar, AccessExclusiveLock);
|
Relation relation = cstore_fdw_openrv(rangeVar, AccessExclusiveLock);
|
||||||
Oid relationId = relation->rd_id;
|
Oid relationId = relation->rd_id;
|
||||||
AclResult aclresult = pg_class_aclcheck(relationId, GetUserId(),
|
AclResult aclresult = pg_class_aclcheck(relationId, GetUserId(),
|
||||||
ACL_TRUNCATE);
|
ACL_TRUNCATE);
|
||||||
|
@ -889,11 +912,85 @@ TruncateCStoreTables(List *cstoreRelationList)
|
||||||
Assert(CStoreTable(relationId));
|
Assert(CStoreTable(relationId));
|
||||||
|
|
||||||
cstoreOptions = CStoreGetOptions(relationId);
|
cstoreOptions = CStoreGetOptions(relationId);
|
||||||
|
if (OidIsValid(relation->rd_rel->relfilenode))
|
||||||
|
{
|
||||||
|
RelationOpenSmgr(relation);
|
||||||
|
RelationDropStorage(relation);
|
||||||
|
}
|
||||||
DeleteCStoreTableFiles(cstoreOptions->filename);
|
DeleteCStoreTableFiles(cstoreOptions->filename);
|
||||||
InitializeCStoreTableFile(relationId, relation, CStoreGetOptions(relationId));
|
InitializeCStoreTableFile(relationId, relation, CStoreGetOptions(relationId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Version 11 and earlier already create a relfilenode for foreign
|
||||||
|
* tables. Version 12 and later do not, so we need to create one manually.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
InitializeRelFileNode(Relation relation)
|
||||||
|
{
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
Relation pg_class;
|
||||||
|
HeapTuple tuple;
|
||||||
|
Form_pg_class classform;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a writable copy of the pg_class tuple for the given relation.
|
||||||
|
*/
|
||||||
|
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
|
||||||
|
|
||||||
|
tuple = SearchSysCacheCopy1(RELOID,
|
||||||
|
ObjectIdGetDatum(RelationGetRelid(relation)));
|
||||||
|
if (!HeapTupleIsValid(tuple))
|
||||||
|
elog(ERROR, "could not find tuple for relation %u",
|
||||||
|
RelationGetRelid(relation));
|
||||||
|
classform = (Form_pg_class) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
if (!OidIsValid(classform->relfilenode))
|
||||||
|
{
|
||||||
|
Relation tmprel;
|
||||||
|
Oid tablespace;
|
||||||
|
Oid filenode = relation->rd_id;
|
||||||
|
char persistence = relation->rd_rel->relpersistence;
|
||||||
|
RelFileNode newrnode;
|
||||||
|
SMgrRelation srel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Upgrade to AccessExclusiveLock, and hold until the end of the
|
||||||
|
* transaction. This shouldn't happen during a read, but it's hard to
|
||||||
|
* prove that because it happens lazily.
|
||||||
|
*/
|
||||||
|
tmprel = heap_open(relation->rd_id, AccessExclusiveLock);
|
||||||
|
heap_close(tmprel, NoLock);
|
||||||
|
|
||||||
|
if (OidIsValid(relation->rd_rel->reltablespace))
|
||||||
|
tablespace = relation->rd_rel->reltablespace;
|
||||||
|
else
|
||||||
|
tablespace = MyDatabaseTableSpace;
|
||||||
|
|
||||||
|
newrnode.spcNode = tablespace;
|
||||||
|
newrnode.dbNode = MyDatabaseId;
|
||||||
|
newrnode.relNode = filenode;
|
||||||
|
|
||||||
|
srel = RelationCreateStorage(newrnode, persistence);
|
||||||
|
smgrclose(srel);
|
||||||
|
|
||||||
|
classform->relfilenode = filenode;
|
||||||
|
classform->relpages = 0; /* it's empty until further notice */
|
||||||
|
classform->reltuples = 0;
|
||||||
|
classform->relallvisible = 0;
|
||||||
|
classform->relfrozenxid = InvalidTransactionId;
|
||||||
|
classform->relminmxid = InvalidTransactionId;
|
||||||
|
|
||||||
|
CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
|
||||||
|
CommandCounterIncrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_freetuple(tuple);
|
||||||
|
heap_close(pg_class, RowExclusiveLock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CStoreTable checks if the given table name belongs to a foreign columnar store
|
* CStoreTable checks if the given table name belongs to a foreign columnar store
|
||||||
|
@ -1179,6 +1276,15 @@ cstore_clean_table_resources(PG_FUNCTION_ARGS)
|
||||||
struct stat fileStat;
|
struct stat fileStat;
|
||||||
int statResult = -1;
|
int statResult = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Event triggers do not offer the relfilenode of the
|
||||||
|
* dropped table, and by the time the sql_drop event trigger
|
||||||
|
* is called, the object is already gone so we can't look it
|
||||||
|
* up. Therefore, we can't drop the Smgr storage here, which
|
||||||
|
* means that cascaded drops of cstore foreign tables will
|
||||||
|
* leak storage.
|
||||||
|
*/
|
||||||
|
|
||||||
appendStringInfo(filePath, "%s/%s/%d/%d", DataDir, CSTORE_FDW_NAME,
|
appendStringInfo(filePath, "%s/%s/%d/%d", DataDir, CSTORE_FDW_NAME,
|
||||||
(int) MyDatabaseId, (int) relationId);
|
(int) MyDatabaseId, (int) relationId);
|
||||||
|
|
||||||
|
@ -1402,7 +1508,7 @@ static char *
|
||||||
CStoreDefaultFilePath(Oid foreignTableId)
|
CStoreDefaultFilePath(Oid foreignTableId)
|
||||||
{
|
{
|
||||||
StringInfo cstoreFilePath = NULL;
|
StringInfo cstoreFilePath = NULL;
|
||||||
Relation relation = relation_open(foreignTableId, AccessShareLock);
|
Relation relation = cstore_fdw_open(foreignTableId, AccessShareLock);
|
||||||
RelFileNode relationFileNode = relation->rd_node;
|
RelFileNode relationFileNode = relation->rd_node;
|
||||||
Oid databaseOid = relationFileNode.dbNode;
|
Oid databaseOid = relationFileNode.dbNode;
|
||||||
Oid relationFileOid = relationFileNode.relNode;
|
Oid relationFileOid = relationFileNode.relNode;
|
||||||
|
@ -1453,7 +1559,7 @@ CStoreGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreignTableId
|
||||||
{
|
{
|
||||||
Path *foreignScanPath = NULL;
|
Path *foreignScanPath = NULL;
|
||||||
CStoreOptions *cstoreOptions = CStoreGetOptions(foreignTableId);
|
CStoreOptions *cstoreOptions = CStoreGetOptions(foreignTableId);
|
||||||
Relation relation = heap_open(foreignTableId, AccessShareLock);
|
Relation relation = cstore_fdw_open(foreignTableId, AccessShareLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We skip reading columns that are not in query. Here we assume that all
|
* We skip reading columns that are not in query. Here we assume that all
|
||||||
|
@ -1659,7 +1765,7 @@ ColumnList(RelOptInfo *baserel, Oid foreignTableId)
|
||||||
List *restrictInfoList = baserel->baserestrictinfo;
|
List *restrictInfoList = baserel->baserestrictinfo;
|
||||||
ListCell *restrictInfoCell = NULL;
|
ListCell *restrictInfoCell = NULL;
|
||||||
const AttrNumber wholeRow = 0;
|
const AttrNumber wholeRow = 0;
|
||||||
Relation relation = heap_open(foreignTableId, AccessShareLock);
|
Relation relation = cstore_fdw_open(foreignTableId, AccessShareLock);
|
||||||
TupleDesc tupleDescriptor = RelationGetDescr(relation);
|
TupleDesc tupleDescriptor = RelationGetDescr(relation);
|
||||||
|
|
||||||
/* first add the columns used in joins and projections */
|
/* first add the columns used in joins and projections */
|
||||||
|
@ -1750,10 +1856,13 @@ ColumnList(RelOptInfo *baserel, Oid foreignTableId)
|
||||||
static void
|
static void
|
||||||
CStoreExplainForeignScan(ForeignScanState *scanState, ExplainState *explainState)
|
CStoreExplainForeignScan(ForeignScanState *scanState, ExplainState *explainState)
|
||||||
{
|
{
|
||||||
Oid foreignTableId = RelationGetRelid(scanState->ss.ss_currentRelation);
|
Relation relation = scanState->ss.ss_currentRelation;
|
||||||
CStoreOptions *cstoreOptions = CStoreGetOptions(foreignTableId);
|
CStoreOptions *cstoreOptions;
|
||||||
|
Oid foreignTableId;
|
||||||
|
|
||||||
ExplainPropertyText("CStore File", cstoreOptions->filename, explainState);
|
cstore_fdw_initrel(relation);
|
||||||
|
foreignTableId = RelationGetRelid(relation);
|
||||||
|
cstoreOptions = CStoreGetOptions(foreignTableId);
|
||||||
|
|
||||||
/* supress file size if we're not showing cost details */
|
/* supress file size if we're not showing cost details */
|
||||||
if (explainState->costs)
|
if (explainState->costs)
|
||||||
|
@ -1784,6 +1893,8 @@ CStoreBeginForeignScan(ForeignScanState *scanState, int executorFlags)
|
||||||
List *foreignPrivateList = NIL;
|
List *foreignPrivateList = NIL;
|
||||||
List *whereClauseList = NIL;
|
List *whereClauseList = NIL;
|
||||||
|
|
||||||
|
cstore_fdw_initrel(currentRelation);
|
||||||
|
|
||||||
/* if Explain with no Analyze, do nothing */
|
/* if Explain with no Analyze, do nothing */
|
||||||
if (executorFlags & EXEC_FLAG_EXPLAIN_ONLY)
|
if (executorFlags & EXEC_FLAG_EXPLAIN_ONLY)
|
||||||
{
|
{
|
||||||
|
@ -1869,9 +1980,12 @@ CStoreAnalyzeForeignTable(Relation relation,
|
||||||
BlockNumber *totalPageCount)
|
BlockNumber *totalPageCount)
|
||||||
{
|
{
|
||||||
Oid foreignTableId = RelationGetRelid(relation);
|
Oid foreignTableId = RelationGetRelid(relation);
|
||||||
CStoreOptions *cstoreOptions = CStoreGetOptions(foreignTableId);
|
CStoreOptions *cstoreOptions;
|
||||||
struct stat statBuffer;
|
struct stat statBuffer;
|
||||||
|
|
||||||
|
cstore_fdw_initrel(relation);
|
||||||
|
cstoreOptions = CStoreGetOptions(foreignTableId);
|
||||||
|
|
||||||
int statResult = stat(cstoreOptions->filename, &statBuffer);
|
int statResult = stat(cstoreOptions->filename, &statBuffer);
|
||||||
if (statResult < 0)
|
if (statResult < 0)
|
||||||
{
|
{
|
||||||
|
@ -1924,6 +2038,7 @@ CStoreAcquireSampleRows(Relation relation, int logLevel,
|
||||||
TupleDesc tupleDescriptor = RelationGetDescr(relation);
|
TupleDesc tupleDescriptor = RelationGetDescr(relation);
|
||||||
uint32 columnCount = tupleDescriptor->natts;
|
uint32 columnCount = tupleDescriptor->natts;
|
||||||
|
|
||||||
|
cstore_fdw_initrel(relation);
|
||||||
|
|
||||||
/* create list of columns of the relation */
|
/* create list of columns of the relation */
|
||||||
uint32 columnIndex = 0;
|
uint32 columnIndex = 0;
|
||||||
|
@ -2147,7 +2262,7 @@ CStoreBeginForeignInsert(ModifyTableState *modifyTableState, ResultRelInfo *rela
|
||||||
Relation relation = NULL;
|
Relation relation = NULL;
|
||||||
|
|
||||||
foreignTableOid = RelationGetRelid(relationInfo->ri_RelationDesc);
|
foreignTableOid = RelationGetRelid(relationInfo->ri_RelationDesc);
|
||||||
relation = heap_open(foreignTableOid, ShareUpdateExclusiveLock);
|
relation = cstore_fdw_open(foreignTableOid, ShareUpdateExclusiveLock);
|
||||||
cstoreOptions = CStoreGetOptions(foreignTableOid);
|
cstoreOptions = CStoreGetOptions(foreignTableOid);
|
||||||
tupleDescriptor = RelationGetDescr(relationInfo->ri_RelationDesc);
|
tupleDescriptor = RelationGetDescr(relationInfo->ri_RelationDesc);
|
||||||
|
|
||||||
|
@ -2246,3 +2361,49 @@ CStoreIsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel,
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Versions 12 and later do not initialize rd_node even if the relation has a
|
||||||
|
* valid relfilenode, so we need to initialize it each time a cstore FDW
|
||||||
|
* relation is opened.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
cstore_fdw_initrel(Relation rel)
|
||||||
|
{
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
if (rel->rd_rel->relfilenode == InvalidOid)
|
||||||
|
InitializeRelFileNode(rel);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copied code from RelationInitPhysicalAddr(), which doesn't
|
||||||
|
* work on foreign tables.
|
||||||
|
*/
|
||||||
|
if (OidIsValid(rel->rd_rel->reltablespace))
|
||||||
|
rel->rd_node.spcNode = rel->rd_rel->reltablespace;
|
||||||
|
else
|
||||||
|
rel->rd_node.spcNode = MyDatabaseTableSpace;
|
||||||
|
|
||||||
|
rel->rd_node.dbNode = MyDatabaseId;
|
||||||
|
rel->rd_node.relNode = rel->rd_rel->relfilenode;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static Relation
|
||||||
|
cstore_fdw_open(Oid relationId, LOCKMODE lockmode)
|
||||||
|
{
|
||||||
|
Relation rel = heap_open(relationId, lockmode);
|
||||||
|
|
||||||
|
cstore_fdw_initrel(rel);
|
||||||
|
|
||||||
|
return rel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Relation
|
||||||
|
cstore_fdw_openrv(RangeVar *relation, LOCKMODE lockmode)
|
||||||
|
{
|
||||||
|
Relation rel = heap_openrv(relation, lockmode);
|
||||||
|
|
||||||
|
cstore_fdw_initrel(rel);
|
||||||
|
|
||||||
|
return rel;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue