PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
file_fdw.c File Reference
#include "postgres.h"
#include <sys/stat.h>
#include <unistd.h>
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_foreign_table.h"
#include "commands/copy.h"
#include "commands/copyfrom_internal.h"
#include "commands/defrem.h"
#include "commands/explain.h"
#include "commands/vacuum.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/planmain.h"
#include "optimizer/restrictinfo.h"
#include "utils/acl.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/sampling.h"
#include "utils/varlena.h"
Include dependency graph for file_fdw.c:

Go to the source code of this file.

Data Structures

struct  FileFdwOption
 
struct  FileFdwPlanState
 
struct  FileFdwExecutionState
 

Typedefs

typedef struct FileFdwPlanState FileFdwPlanState
 
typedef struct FileFdwExecutionState FileFdwExecutionState
 

Functions

 PG_FUNCTION_INFO_V1 (file_fdw_handler)
 
 PG_FUNCTION_INFO_V1 (file_fdw_validator)
 
static void fileGetForeignRelSize (PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
 
static void fileGetForeignPaths (PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
 
static ForeignScanfileGetForeignPlan (PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan)
 
static void fileExplainForeignScan (ForeignScanState *node, ExplainState *es)
 
static void fileBeginForeignScan (ForeignScanState *node, int eflags)
 
static TupleTableSlotfileIterateForeignScan (ForeignScanState *node)
 
static void fileReScanForeignScan (ForeignScanState *node)
 
static void fileEndForeignScan (ForeignScanState *node)
 
static bool fileAnalyzeForeignTable (Relation relation, AcquireSampleRowsFunc *func, BlockNumber *totalpages)
 
static bool fileIsForeignScanParallelSafe (PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 
static bool is_valid_option (const char *option, Oid context)
 
static void fileGetOptions (Oid foreigntableid, char **filename, bool *is_program, List **other_options)
 
static Listget_file_fdw_attribute_options (Oid relid)
 
static bool check_selective_binary_conversion (RelOptInfo *baserel, Oid foreigntableid, List **columns)
 
static void estimate_size (PlannerInfo *root, RelOptInfo *baserel, FileFdwPlanState *fdw_private)
 
static void estimate_costs (PlannerInfo *root, RelOptInfo *baserel, FileFdwPlanState *fdw_private, Cost *startup_cost, Cost *total_cost)
 
static int file_acquire_sample_rows (Relation onerel, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
 
Datum file_fdw_handler (PG_FUNCTION_ARGS)
 
Datum file_fdw_validator (PG_FUNCTION_ARGS)
 

Variables

 PG_MODULE_MAGIC
 
static const struct FileFdwOption valid_options []
 

Typedef Documentation

◆ FileFdwExecutionState

◆ FileFdwPlanState

Function Documentation

◆ check_selective_binary_conversion()

static bool check_selective_binary_conversion ( RelOptInfo baserel,
Oid  foreigntableid,
List **  columns 
)
static

Definition at line 933 of file file_fdw.c.

936{
937 ForeignTable *table;
938 ListCell *lc;
939 Relation rel;
940 TupleDesc tupleDesc;
941 int attidx;
942 Bitmapset *attrs_used = NULL;
943 bool has_wholerow = false;
944 int numattrs;
945 int i;
946
947 *columns = NIL; /* default result */
948
949 /*
950 * Check format of the file. If binary format, this is irrelevant.
951 */
952 table = GetForeignTable(foreigntableid);
953 foreach(lc, table->options)
954 {
955 DefElem *def = (DefElem *) lfirst(lc);
956
957 if (strcmp(def->defname, "format") == 0)
958 {
959 char *format = defGetString(def);
960
961 if (strcmp(format, "binary") == 0)
962 return false;
963 break;
964 }
965 }
966
967 /* Collect all the attributes needed for joins or final output. */
968 pull_varattnos((Node *) baserel->reltarget->exprs, baserel->relid,
969 &attrs_used);
970
971 /* Add all the attributes used by restriction clauses. */
972 foreach(lc, baserel->baserestrictinfo)
973 {
974 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
975
976 pull_varattnos((Node *) rinfo->clause, baserel->relid,
977 &attrs_used);
978 }
979
980 /* Convert attribute numbers to column names. */
981 rel = table_open(foreigntableid, AccessShareLock);
982 tupleDesc = RelationGetDescr(rel);
983
984 attidx = -1;
985 while ((attidx = bms_next_member(attrs_used, attidx)) >= 0)
986 {
987 /* attidx is zero-based, attnum is the normal attribute number */
989
990 if (attnum == 0)
991 {
992 has_wholerow = true;
993 break;
994 }
995
996 /* Ignore system attributes. */
997 if (attnum < 0)
998 continue;
999
1000 /* Get user attributes. */
1001 if (attnum > 0)
1002 {
1003 Form_pg_attribute attr = TupleDescAttr(tupleDesc, attnum - 1);
1004 char *attname = NameStr(attr->attname);
1005
1006 /* Skip dropped attributes (probably shouldn't see any here). */
1007 if (attr->attisdropped)
1008 continue;
1009
1010 /*
1011 * Skip generated columns (COPY won't accept them in the column
1012 * list)
1013 */
1014 if (attr->attgenerated)
1015 continue;
1016 *columns = lappend(*columns, makeString(pstrdup(attname)));
1017 }
1018 }
1019
1020 /* Count non-dropped user attributes while we have the tupdesc. */
1021 numattrs = 0;
1022 for (i = 0; i < tupleDesc->natts; i++)
1023 {
1024 Form_pg_attribute attr = TupleDescAttr(tupleDesc, i);
1025
1026 if (attr->attisdropped)
1027 continue;
1028 numattrs++;
1029 }
1030
1032
1033 /* If there's a whole-row reference, fail: we need all the columns. */
1034 if (has_wholerow)
1035 {
1036 *columns = NIL;
1037 return false;
1038 }
1039
1040 /* If all the user attributes are needed, fail. */
1041 if (numattrs == list_length(*columns))
1042 {
1043 *columns = NIL;
1044 return false;
1045 }
1046
1047 return true;
1048}
int16 AttrNumber
Definition: attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
#define NameStr(name)
Definition: c.h:700
char * defGetString(DefElem *def)
Definition: define.c:35
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:254
int i
Definition: isn.c:72
List * lappend(List *list, void *datum)
Definition: list.c:339
#define AccessShareLock
Definition: lockdefs.h:36
char * pstrdup(const char *in)
Definition: mcxt.c:1696
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
static char format
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define RelationGetDescr(relation)
Definition: rel.h:531
char * defname
Definition: parsenodes.h:817
List * options
Definition: foreign.h:57
Definition: nodes.h:129
List * exprs
Definition: pathnodes.h:1544
List * baserestrictinfo
Definition: pathnodes.h:985
struct PathTarget * reltarget
Definition: pathnodes.h:893
Index relid
Definition: pathnodes.h:918
Expr * clause
Definition: pathnodes.h:2575
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:152
String * makeString(char *str)
Definition: value.c:63
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:295

References AccessShareLock, attname, attnum, RelOptInfo::baserestrictinfo, bms_next_member(), RestrictInfo::clause, defGetString(), DefElem::defname, PathTarget::exprs, FirstLowInvalidHeapAttributeNumber, format, GetForeignTable(), i, lappend(), lfirst, list_length(), makeString(), NameStr, TupleDescData::natts, NIL, ForeignTable::options, pstrdup(), pull_varattnos(), RelationGetDescr, RelOptInfo::relid, RelOptInfo::reltarget, table_close(), table_open(), and TupleDescAttr().

Referenced by fileGetForeignPaths().

◆ estimate_costs()

static void estimate_costs ( PlannerInfo root,
RelOptInfo baserel,
FileFdwPlanState fdw_private,
Cost startup_cost,
Cost total_cost 
)
static

Definition at line 1139 of file file_fdw.c.

1142{
1143 BlockNumber pages = fdw_private->pages;
1144 double ntuples = fdw_private->ntuples;
1145 Cost run_cost = 0;
1146 Cost cpu_per_tuple;
1147
1148 /*
1149 * We estimate costs almost the same way as cost_seqscan(), thus assuming
1150 * that I/O costs are equivalent to a regular table file of the same size.
1151 * However, we take per-tuple CPU costs as 10x of a seqscan, to account
1152 * for the cost of parsing records.
1153 *
1154 * In the case of a program source, this calculation is even more divorced
1155 * from reality, but we have no good alternative; and it's not clear that
1156 * the numbers we produce here matter much anyway, since there's only one
1157 * access path for the rel.
1158 */
1159 run_cost += seq_page_cost * pages;
1160
1161 *startup_cost = baserel->baserestrictcost.startup;
1162 cpu_per_tuple = cpu_tuple_cost * 10 + baserel->baserestrictcost.per_tuple;
1163 run_cost += cpu_per_tuple * ntuples;
1164 *total_cost = *startup_cost + run_cost;
1165}
uint32 BlockNumber
Definition: block.h:31
double cpu_tuple_cost
Definition: costsize.c:132
double seq_page_cost
Definition: costsize.c:130
double Cost
Definition: nodes.h:251
double ntuples
Definition: file_fdw.c:102
BlockNumber pages
Definition: file_fdw.c:101
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47
QualCost baserestrictcost
Definition: pathnodes.h:987

References RelOptInfo::baserestrictcost, cpu_tuple_cost, FileFdwPlanState::ntuples, FileFdwPlanState::pages, QualCost::per_tuple, seq_page_cost, and QualCost::startup.

Referenced by fileGetForeignPaths().

◆ estimate_size()

static void estimate_size ( PlannerInfo root,
RelOptInfo baserel,
FileFdwPlanState fdw_private 
)
static

Definition at line 1058 of file file_fdw.c.

1060{
1061 struct stat stat_buf;
1062 BlockNumber pages;
1063 double ntuples;
1064 double nrows;
1065
1066 /*
1067 * Get size of the file. It might not be there at plan time, though, in
1068 * which case we have to use a default estimate. We also have to fall
1069 * back to the default if using a program as the input.
1070 */
1071 if (fdw_private->is_program || stat(fdw_private->filename, &stat_buf) < 0)
1072 stat_buf.st_size = 10 * BLCKSZ;
1073
1074 /*
1075 * Convert size to pages for use in I/O cost estimate later.
1076 */
1077 pages = (stat_buf.st_size + (BLCKSZ - 1)) / BLCKSZ;
1078 if (pages < 1)
1079 pages = 1;
1080 fdw_private->pages = pages;
1081
1082 /*
1083 * Estimate the number of tuples in the file.
1084 */
1085 if (baserel->tuples >= 0 && baserel->pages > 0)
1086 {
1087 /*
1088 * We have # of pages and # of tuples from pg_class (that is, from a
1089 * previous ANALYZE), so compute a tuples-per-page estimate and scale
1090 * that by the current file size.
1091 */
1092 double density;
1093
1094 density = baserel->tuples / (double) baserel->pages;
1095 ntuples = clamp_row_est(density * (double) pages);
1096 }
1097 else
1098 {
1099 /*
1100 * Otherwise we have to fake it. We back into this estimate using the
1101 * planner's idea of the relation width; which is bogus if not all
1102 * columns are being read, not to mention that the text representation
1103 * of a row probably isn't the same size as its internal
1104 * representation. Possibly we could do something better, but the
1105 * real answer to anyone who complains is "ANALYZE" ...
1106 */
1107 int tuple_width;
1108
1109 tuple_width = MAXALIGN(baserel->reltarget->width) +
1111 ntuples = clamp_row_est((double) stat_buf.st_size /
1112 (double) tuple_width);
1113 }
1114 fdw_private->ntuples = ntuples;
1115
1116 /*
1117 * Now estimate the number of rows returned by the scan after applying the
1118 * baserestrictinfo quals.
1119 */
1120 nrows = ntuples *
1122 baserel->baserestrictinfo,
1123 0,
1124 JOIN_INNER,
1125 NULL);
1126
1127 nrows = clamp_row_est(nrows);
1128
1129 /* Save the output-rows estimate for the planner */
1130 baserel->rows = nrows;
1131}
#define MAXALIGN(LEN)
Definition: c.h:765
Selectivity clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo)
Definition: clausesel.c:100
double clamp_row_est(double nrows)
Definition: costsize.c:213
#define SizeofHeapTupleHeader
Definition: htup_details.h:185
@ JOIN_INNER
Definition: nodes.h:293
tree ctl root
Definition: radixtree.h:1857
char * filename
Definition: file_fdw.c:97
Cardinality tuples
Definition: pathnodes.h:949
BlockNumber pages
Definition: pathnodes.h:948
Cardinality rows
Definition: pathnodes.h:877
__int64 st_size
Definition: win32_port.h:273

References RelOptInfo::baserestrictinfo, clamp_row_est(), clauselist_selectivity(), FileFdwPlanState::filename, FileFdwPlanState::is_program, JOIN_INNER, MAXALIGN, FileFdwPlanState::ntuples, FileFdwPlanState::pages, RelOptInfo::pages, RelOptInfo::reltarget, root, RelOptInfo::rows, SizeofHeapTupleHeader, stat::st_size, RelOptInfo::tuples, and PathTarget::width.

Referenced by fileGetForeignRelSize().

◆ file_acquire_sample_rows()

static int file_acquire_sample_rows ( Relation  onerel,
int  elevel,
HeapTuple rows,
int  targrows,
double *  totalrows,
double *  totaldeadrows 
)
static

Definition at line 1183 of file file_fdw.c.

1186{
1187 int numrows = 0;
1188 double rowstoskip = -1; /* -1 means not set yet */
1189 ReservoirStateData rstate;
1190 TupleDesc tupDesc;
1191 Datum *values;
1192 bool *nulls;
1193 bool found;
1194 char *filename;
1195 bool is_program;
1196 List *options;
1197 CopyFromState cstate;
1198 ErrorContextCallback errcallback;
1200 MemoryContext tupcontext;
1201
1202 Assert(onerel);
1203 Assert(targrows > 0);
1204
1205 tupDesc = RelationGetDescr(onerel);
1206 values = (Datum *) palloc(tupDesc->natts * sizeof(Datum));
1207 nulls = (bool *) palloc(tupDesc->natts * sizeof(bool));
1208
1209 /* Fetch options of foreign table */
1210 fileGetOptions(RelationGetRelid(onerel), &filename, &is_program, &options);
1211
1212 /*
1213 * Create CopyState from FDW options.
1214 */
1215 cstate = BeginCopyFrom(NULL, onerel, NULL, filename, is_program, NULL, NIL,
1216 options);
1217
1218 /*
1219 * Use per-tuple memory context to prevent leak of memory used to read
1220 * rows from the file with Copy routines.
1221 */
1223 "file_fdw temporary context",
1225
1226 /* Prepare for sampling rows */
1227 reservoir_init_selection_state(&rstate, targrows);
1228
1229 /* Set up callback to identify error line number. */
1230 errcallback.callback = CopyFromErrorCallback;
1231 errcallback.arg = cstate;
1232 errcallback.previous = error_context_stack;
1233 error_context_stack = &errcallback;
1234
1235 *totalrows = 0;
1236 *totaldeadrows = 0;
1237 for (;;)
1238 {
1239 /* Check for user-requested abort or sleep */
1241
1242 /* Fetch next row */
1243 MemoryContextReset(tupcontext);
1244 MemoryContextSwitchTo(tupcontext);
1245
1246 found = NextCopyFrom(cstate, NULL, values, nulls);
1247
1248 MemoryContextSwitchTo(oldcontext);
1249
1250 if (!found)
1251 break;
1252
1253 if (cstate->opts.on_error == COPY_ON_ERROR_IGNORE &&
1254 cstate->escontext->error_occurred)
1255 {
1256 /*
1257 * Soft error occurred, skip this tuple and just make
1258 * ErrorSaveContext ready for the next NextCopyFrom. Since we
1259 * don't set details_wanted and error_data is not to be filled,
1260 * just resetting error_occurred is enough.
1261 */
1262 cstate->escontext->error_occurred = false;
1263
1264 /* Repeat NextCopyFrom() until no soft error occurs */
1265 continue;
1266 }
1267
1268 /*
1269 * The first targrows sample rows are simply copied into the
1270 * reservoir. Then we start replacing tuples in the sample until we
1271 * reach the end of the relation. This algorithm is from Jeff Vitter's
1272 * paper (see more info in commands/analyze.c).
1273 */
1274 if (numrows < targrows)
1275 {
1276 rows[numrows++] = heap_form_tuple(tupDesc, values, nulls);
1277 }
1278 else
1279 {
1280 /*
1281 * t in Vitter's paper is the number of records already processed.
1282 * If we need to compute a new S value, we must use the
1283 * not-yet-incremented value of totalrows as t.
1284 */
1285 if (rowstoskip < 0)
1286 rowstoskip = reservoir_get_next_S(&rstate, *totalrows, targrows);
1287
1288 if (rowstoskip <= 0)
1289 {
1290 /*
1291 * Found a suitable tuple, so save it, replacing one old tuple
1292 * at random
1293 */
1294 int k = (int) (targrows * sampler_random_fract(&rstate.randstate));
1295
1296 Assert(k >= 0 && k < targrows);
1297 heap_freetuple(rows[k]);
1298 rows[k] = heap_form_tuple(tupDesc, values, nulls);
1299 }
1300
1301 rowstoskip -= 1;
1302 }
1303
1304 *totalrows += 1;
1305 }
1306
1307 /* Remove error callback. */
1308 error_context_stack = errcallback.previous;
1309
1310 /* Clean up. */
1311 MemoryContextDelete(tupcontext);
1312
1313 if (cstate->opts.on_error == COPY_ON_ERROR_IGNORE &&
1314 cstate->num_errors > 0 &&
1317 errmsg_plural("%llu row was skipped due to data type incompatibility",
1318 "%llu rows were skipped due to data type incompatibility",
1319 (unsigned long long) cstate->num_errors,
1320 (unsigned long long) cstate->num_errors));
1321
1322 EndCopyFrom(cstate);
1323
1324 pfree(values);
1325 pfree(nulls);
1326
1327 /*
1328 * Emit some interesting relation info
1329 */
1330 ereport(elevel,
1331 (errmsg("\"%s\": file contains %.0f rows; "
1332 "%d rows in sample",
1334 *totalrows, numrows)));
1335
1336 return numrows;
1337}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define Assert(condition)
Definition: c.h:812
CopyFromState BeginCopyFrom(ParseState *pstate, Relation rel, Node *whereClause, const char *filename, bool is_program, copy_data_source_cb data_source_cb, List *attnamelist, List *options)
Definition: copyfrom.c:1383
void EndCopyFrom(CopyFromState cstate)
Definition: copyfrom.c:1802
void CopyFromErrorCallback(void *arg)
Definition: copyfrom.c:115
bool NextCopyFrom(CopyFromState cstate, ExprContext *econtext, Datum *values, bool *nulls)
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1180
ErrorContextCallback * error_context_stack
Definition: elog.c:94
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
static void fileGetOptions(Oid foreigntableid, char **filename, bool *is_program, List **other_options)
Definition: file_fdw.c:374
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
@ COPY_ON_ERROR_IGNORE
Definition: copy.h:40
@ COPY_LOG_VERBOSITY_DEFAULT
Definition: copy.h:49
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static char * filename
Definition: pg_dumpall.c:119
static char ** options
uintptr_t Datum
Definition: postgres.h:64
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetRelationName(relation)
Definition: rel.h:539
void reservoir_init_selection_state(ReservoirState rs, int n)
Definition: sampling.c:133
double sampler_random_fract(pg_prng_state *randstate)
Definition: sampling.c:241
double reservoir_get_next_S(ReservoirState rs, double t, int n)
Definition: sampling.c:147
CopyLogVerbosityChoice log_verbosity
Definition: copy.h:87
CopyOnErrorChoice on_error
Definition: copy.h:86
CopyFormatOptions opts
ErrorSaveContext * escontext
struct ErrorContextCallback * previous
Definition: elog.h:296
void(* callback)(void *arg)
Definition: elog.h:297
bool error_occurred
Definition: miscnodes.h:47
Definition: pg_list.h:54
pg_prng_state randstate
Definition: sampling.h:49
void vacuum_delay_point(void)
Definition: vacuum.c:2362

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, ErrorContextCallback::arg, Assert, BeginCopyFrom(), ErrorContextCallback::callback, COPY_LOG_VERBOSITY_DEFAULT, COPY_ON_ERROR_IGNORE, CopyFromErrorCallback(), CurrentMemoryContext, EndCopyFrom(), ereport, errmsg(), errmsg_plural(), error_context_stack, ErrorSaveContext::error_occurred, CopyFromStateData::escontext, fileGetOptions(), filename, heap_form_tuple(), heap_freetuple(), CopyFormatOptions::log_verbosity, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), TupleDescData::natts, NextCopyFrom(), NIL, NOTICE, CopyFromStateData::num_errors, CopyFormatOptions::on_error, options, CopyFromStateData::opts, palloc(), pfree(), ErrorContextCallback::previous, ReservoirStateData::randstate, RelationGetDescr, RelationGetRelationName, RelationGetRelid, reservoir_get_next_S(), reservoir_init_selection_state(), sampler_random_fract(), vacuum_delay_point(), and values.

Referenced by fileAnalyzeForeignTable().

◆ file_fdw_handler()

Datum file_fdw_handler ( PG_FUNCTION_ARGS  )

Definition at line 177 of file file_fdw.c.

178{
179 FdwRoutine *fdwroutine = makeNode(FdwRoutine);
180
191
192 PG_RETURN_POINTER(fdwroutine);
193}
static ForeignScan * fileGetForeignPlan(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan)
Definition: file_fdw.c:604
static void fileEndForeignScan(ForeignScanState *node)
Definition: file_fdw.c:841
static void fileGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
Definition: file_fdw.c:518
static void fileExplainForeignScan(ForeignScanState *node, ExplainState *es)
Definition: file_fdw.c:639
static bool fileAnalyzeForeignTable(Relation relation, AcquireSampleRowsFunc *func, BlockNumber *totalpages)
Definition: file_fdw.c:866
static void fileReScanForeignScan(ForeignScanState *node)
Definition: file_fdw.c:820
static bool fileIsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
Definition: file_fdw.c:917
static void fileGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
Definition: file_fdw.c:549
static void fileBeginForeignScan(ForeignScanState *node, int eflags)
Definition: file_fdw.c:671
static TupleTableSlot * fileIterateForeignScan(ForeignScanState *node)
Definition: file_fdw.c:725
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define makeNode(_type_)
Definition: nodes.h:155
ReScanForeignScan_function ReScanForeignScan
Definition: fdwapi.h:214
BeginForeignScan_function BeginForeignScan
Definition: fdwapi.h:212
IsForeignScanParallelSafe_function IsForeignScanParallelSafe
Definition: fdwapi.h:266
GetForeignPaths_function GetForeignPaths
Definition: fdwapi.h:210
GetForeignRelSize_function GetForeignRelSize
Definition: fdwapi.h:209
ExplainForeignScan_function ExplainForeignScan
Definition: fdwapi.h:252
EndForeignScan_function EndForeignScan
Definition: fdwapi.h:215
AnalyzeForeignTable_function AnalyzeForeignTable
Definition: fdwapi.h:257
IterateForeignScan_function IterateForeignScan
Definition: fdwapi.h:213
GetForeignPlan_function GetForeignPlan
Definition: fdwapi.h:211

References FdwRoutine::AnalyzeForeignTable, FdwRoutine::BeginForeignScan, FdwRoutine::EndForeignScan, FdwRoutine::ExplainForeignScan, fileAnalyzeForeignTable(), fileBeginForeignScan(), fileEndForeignScan(), fileExplainForeignScan(), fileGetForeignPaths(), fileGetForeignPlan(), fileGetForeignRelSize(), fileIsForeignScanParallelSafe(), fileIterateForeignScan(), fileReScanForeignScan(), FdwRoutine::GetForeignPaths, FdwRoutine::GetForeignPlan, FdwRoutine::GetForeignRelSize, FdwRoutine::IsForeignScanParallelSafe, FdwRoutine::IterateForeignScan, makeNode, PG_RETURN_POINTER, and FdwRoutine::ReScanForeignScan.

◆ file_fdw_validator()

Datum file_fdw_validator ( PG_FUNCTION_ARGS  )

Definition at line 202 of file file_fdw.c.

203{
204 List *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
205 Oid catalog = PG_GETARG_OID(1);
206 char *filename = NULL;
207 DefElem *force_not_null = NULL;
208 DefElem *force_null = NULL;
209 List *other_options = NIL;
210 ListCell *cell;
211
212 /*
213 * Check that only options supported by file_fdw, and allowed for the
214 * current object type, are given.
215 */
216 foreach(cell, options_list)
217 {
218 DefElem *def = (DefElem *) lfirst(cell);
219
220 if (!is_valid_option(def->defname, catalog))
221 {
222 const struct FileFdwOption *opt;
223 const char *closest_match;
225 bool has_valid_options = false;
226
227 /*
228 * Unknown option specified, complain about it. Provide a hint
229 * with a valid option that looks similar, if there is one.
230 */
232 for (opt = valid_options; opt->optname; opt++)
233 {
234 if (catalog == opt->optcontext)
235 {
236 has_valid_options = true;
238 }
239 }
240
241 closest_match = getClosestMatch(&match_state);
243 (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
244 errmsg("invalid option \"%s\"", def->defname),
245 has_valid_options ? closest_match ?
246 errhint("Perhaps you meant the option \"%s\".",
247 closest_match) : 0 :
248 errhint("There are no valid options in this context.")));
249 }
250
251 /*
252 * Separate out filename, program, and column-specific options, since
253 * ProcessCopyOptions won't accept them.
254 */
255 if (strcmp(def->defname, "filename") == 0 ||
256 strcmp(def->defname, "program") == 0)
257 {
258 if (filename)
260 (errcode(ERRCODE_SYNTAX_ERROR),
261 errmsg("conflicting or redundant options")));
262
263 /*
264 * Check permissions for changing which file or program is used by
265 * the file_fdw.
266 *
267 * Only members of the role 'pg_read_server_files' are allowed to
268 * set the 'filename' option of a file_fdw foreign table, while
269 * only members of the role 'pg_execute_server_program' are
270 * allowed to set the 'program' option. This is because we don't
271 * want regular users to be able to control which file gets read
272 * or which program gets executed.
273 *
274 * Putting this sort of permissions check in a validator is a bit
275 * of a crock, but there doesn't seem to be any other place that
276 * can enforce the check more cleanly.
277 *
278 * Note that the valid_options[] array disallows setting filename
279 * and program at any options level other than foreign table ---
280 * otherwise there'd still be a security hole.
281 */
282 if (strcmp(def->defname, "filename") == 0 &&
283 !has_privs_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
285 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
286 errmsg("permission denied to set the \"%s\" option of a file_fdw foreign table",
287 "filename"),
288 errdetail("Only roles with privileges of the \"%s\" role may set this option.",
289 "pg_read_server_files")));
290
291 if (strcmp(def->defname, "program") == 0 &&
292 !has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM))
294 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
295 errmsg("permission denied to set the \"%s\" option of a file_fdw foreign table",
296 "program"),
297 errdetail("Only roles with privileges of the \"%s\" role may set this option.",
298 "pg_execute_server_program")));
299
300 filename = defGetString(def);
301 }
302
303 /*
304 * force_not_null is a boolean option; after validation we can discard
305 * it - it will be retrieved later in get_file_fdw_attribute_options()
306 */
307 else if (strcmp(def->defname, "force_not_null") == 0)
308 {
309 if (force_not_null)
311 (errcode(ERRCODE_SYNTAX_ERROR),
312 errmsg("conflicting or redundant options"),
313 errhint("Option \"force_not_null\" supplied more than once for a column.")));
314 force_not_null = def;
315 /* Don't care what the value is, as long as it's a legal boolean */
316 (void) defGetBoolean(def);
317 }
318 /* See comments for force_not_null above */
319 else if (strcmp(def->defname, "force_null") == 0)
320 {
321 if (force_null)
323 (errcode(ERRCODE_SYNTAX_ERROR),
324 errmsg("conflicting or redundant options"),
325 errhint("Option \"force_null\" supplied more than once for a column.")));
326 force_null = def;
327 (void) defGetBoolean(def);
328 }
329 else
330 other_options = lappend(other_options, def);
331 }
332
333 /*
334 * Now apply the core COPY code's validation logic for more checks.
335 */
336 ProcessCopyOptions(NULL, NULL, true, other_options);
337
338 /*
339 * Either filename or program option is required for file_fdw foreign
340 * tables.
341 */
342 if (catalog == ForeignTableRelationId && filename == NULL)
344 (errcode(ERRCODE_FDW_DYNAMIC_PARAMETER_VALUE_NEEDED),
345 errmsg("either filename or program is required for file_fdw foreign tables")));
346
348}
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5268
void ProcessCopyOptions(ParseState *pstate, CopyFormatOptions *opts_out, bool is_from, List *options)
Definition: copy.c:496
bool defGetBoolean(DefElem *def)
Definition: define.c:94
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
#define ERROR
Definition: elog.h:39
static const struct FileFdwOption valid_options[]
Definition: file_fdw.c:63
static bool is_valid_option(const char *option, Oid context)
Definition: file_fdw.c:355
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
struct parser_state match_state[5]
Oid GetUserId(void)
Definition: miscinit.c:517
unsigned int Oid
Definition: postgres_ext.h:31
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1331
Oid optcontext
Definition: file_fdw.c:51
const char * optname
Definition: file_fdw.c:50
const char * getClosestMatch(ClosestMatchState *state)
Definition: varlena.c:6256
void initClosestMatch(ClosestMatchState *state, const char *source, int max_d)
Definition: varlena.c:6201
void updateClosestMatch(ClosestMatchState *state, const char *candidate)
Definition: varlena.c:6221

References defGetBoolean(), defGetString(), DefElem::defname, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, filename, getClosestMatch(), GetUserId(), has_privs_of_role(), initClosestMatch(), is_valid_option(), lappend(), lfirst, match_state, NIL, FileFdwOption::optcontext, FileFdwOption::optname, PG_GETARG_DATUM, PG_GETARG_OID, PG_RETURN_VOID, ProcessCopyOptions(), untransformRelOptions(), updateClosestMatch(), and valid_options.

◆ fileAnalyzeForeignTable()

static bool fileAnalyzeForeignTable ( Relation  relation,
AcquireSampleRowsFunc func,
BlockNumber totalpages 
)
static

Definition at line 866 of file file_fdw.c.

869{
870 char *filename;
871 bool is_program;
872 List *options;
873 struct stat stat_buf;
874
875 /* Fetch options of foreign table */
876 fileGetOptions(RelationGetRelid(relation), &filename, &is_program, &options);
877
878 /*
879 * If this is a program instead of a file, just return false to skip
880 * analyzing the table. We could run the program and collect stats on
881 * whatever it currently returns, but it seems likely that in such cases
882 * the output would be too volatile for the stats to be useful. Maybe
883 * there should be an option to enable doing this?
884 */
885 if (is_program)
886 return false;
887
888 /*
889 * Get size of the file. (XXX if we fail here, would it be better to just
890 * return false to skip analyzing the table?)
891 */
892 if (stat(filename, &stat_buf) < 0)
895 errmsg("could not stat file \"%s\": %m",
896 filename)));
897
898 /*
899 * Convert size to pages. Must return at least 1 so that we can tell
900 * later on that pg_class.relpages is not default.
901 */
902 *totalpages = (stat_buf.st_size + (BLCKSZ - 1)) / BLCKSZ;
903 if (*totalpages < 1)
904 *totalpages = 1;
905
907
908 return true;
909}
int errcode_for_file_access(void)
Definition: elog.c:876
static int file_acquire_sample_rows(Relation onerel, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
Definition: file_fdw.c:1183
#define stat
Definition: win32_port.h:284

References ereport, errcode_for_file_access(), errmsg(), ERROR, file_acquire_sample_rows(), fileGetOptions(), filename, options, RelationGetRelid, stat::st_size, and stat.

Referenced by file_fdw_handler().

◆ fileBeginForeignScan()

static void fileBeginForeignScan ( ForeignScanState node,
int  eflags 
)
static

Definition at line 671 of file file_fdw.c.

672{
673 ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
674 char *filename;
675 bool is_program;
676 List *options;
677 CopyFromState cstate;
678 FileFdwExecutionState *festate;
679
680 /*
681 * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL.
682 */
683 if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
684 return;
685
686 /* Fetch options of foreign table */
688 &filename, &is_program, &options);
689
690 /* Add any options from the plan (currently only convert_selectively) */
691 options = list_concat(options, plan->fdw_private);
692
693 /*
694 * Create CopyState from FDW options. We always acquire all columns, so
695 * as to match the expected ScanTupleSlot signature.
696 */
697 cstate = BeginCopyFrom(NULL,
699 NULL,
700 filename,
701 is_program,
702 NULL,
703 NIL,
704 options);
705
706 /*
707 * Save state in node->fdw_state. We must save enough information to call
708 * BeginCopyFrom() again.
709 */
711 festate->filename = filename;
712 festate->is_program = is_program;
713 festate->options = options;
714 festate->cstate = cstate;
715
716 node->fdw_state = festate;
717}
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:65
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
#define plan(x)
Definition: pg_regress.c:161
ScanState ss
Definition: execnodes.h:2072
Plan * plan
Definition: execnodes.h:1126
Relation ss_currentRelation
Definition: execnodes.h:1574
PlanState ps
Definition: execnodes.h:1573

References BeginCopyFrom(), EXEC_FLAG_EXPLAIN_ONLY, ForeignScanState::fdw_state, fileGetOptions(), filename, if(), list_concat(), NIL, options, palloc(), PlanState::plan, plan, ScanState::ps, RelationGetRelid, ForeignScanState::ss, and ScanState::ss_currentRelation.

Referenced by file_fdw_handler().

◆ fileEndForeignScan()

static void fileEndForeignScan ( ForeignScanState node)
static

Definition at line 841 of file file_fdw.c.

842{
844
845 /* if festate is NULL, we are in EXPLAIN; nothing to do */
846 if (!festate)
847 return;
848
849 if (festate->cstate->opts.on_error == COPY_ON_ERROR_IGNORE &&
850 festate->cstate->num_errors > 0 &&
853 errmsg_plural("%llu row was skipped due to data type incompatibility",
854 "%llu rows were skipped due to data type incompatibility",
855 (unsigned long long) festate->cstate->num_errors,
856 (unsigned long long) festate->cstate->num_errors));
857
858 EndCopyFrom(festate->cstate);
859}
CopyFromState cstate
Definition: file_fdw.c:114

References COPY_LOG_VERBOSITY_DEFAULT, COPY_ON_ERROR_IGNORE, FileFdwExecutionState::cstate, EndCopyFrom(), ereport, errmsg_plural(), ForeignScanState::fdw_state, if(), CopyFormatOptions::log_verbosity, NOTICE, CopyFromStateData::num_errors, CopyFormatOptions::on_error, and CopyFromStateData::opts.

Referenced by file_fdw_handler().

◆ fileExplainForeignScan()

static void fileExplainForeignScan ( ForeignScanState node,
ExplainState es 
)
static

Definition at line 639 of file file_fdw.c.

640{
641 char *filename;
642 bool is_program;
643 List *options;
644
645 /* Fetch options --- we only need filename and is_program at this point */
647 &filename, &is_program, &options);
648
649 if (is_program)
650 ExplainPropertyText("Foreign Program", filename, es);
651 else
652 ExplainPropertyText("Foreign File", filename, es);
653
654 /* Suppress file size if we're not showing cost details */
655 if (es->costs)
656 {
657 struct stat stat_buf;
658
659 if (!is_program &&
660 stat(filename, &stat_buf) == 0)
661 ExplainPropertyInteger("Foreign File Size", "b",
662 (int64) stat_buf.st_size, es);
663 }
664}
int64_t int64
Definition: c.h:482
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:5129
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:5138
bool costs
Definition: explain.h:50

References ExplainState::costs, ExplainPropertyInteger(), ExplainPropertyText(), fileGetOptions(), filename, options, RelationGetRelid, ForeignScanState::ss, ScanState::ss_currentRelation, stat::st_size, and stat.

Referenced by file_fdw_handler().

◆ fileGetForeignPaths()

static void fileGetForeignPaths ( PlannerInfo root,
RelOptInfo baserel,
Oid  foreigntableid 
)
static

Definition at line 549 of file file_fdw.c.

552{
553 FileFdwPlanState *fdw_private = (FileFdwPlanState *) baserel->fdw_private;
554 Cost startup_cost;
555 Cost total_cost;
556 List *columns;
557 List *coptions = NIL;
558
559 /* Decide whether to selectively perform binary conversion */
561 foreigntableid,
562 &columns))
563 coptions = list_make1(makeDefElem("convert_selectively",
564 (Node *) columns, -1));
565
566 /* Estimate costs */
567 estimate_costs(root, baserel, fdw_private,
568 &startup_cost, &total_cost);
569
570 /*
571 * Create a ForeignPath node and add it as only possible path. We use the
572 * fdw_private list of the path to carry the convert_selectively option;
573 * it will be propagated into the fdw_private list of the Plan node.
574 *
575 * We don't support pushing join clauses into the quals of this path, but
576 * it could still have required parameterization due to LATERAL refs in
577 * its tlist.
578 */
579 add_path(baserel, (Path *)
581 NULL, /* default pathtarget */
582 baserel->rows,
583 0,
584 startup_cost,
585 total_cost,
586 NIL, /* no pathkeys */
587 baserel->lateral_relids,
588 NULL, /* no extra plan */
589 NIL, /* no fdw_restrictinfo list */
590 coptions));
591
592 /*
593 * If data file was sorted, and we knew it somehow, we could insert
594 * appropriate pathkeys into the ForeignPath node to tell the planner
595 * that.
596 */
597}
static bool check_selective_binary_conversion(RelOptInfo *baserel, Oid foreigntableid, List **columns)
Definition: file_fdw.c:933
static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel, FileFdwPlanState *fdw_private, Cost *startup_cost, Cost *total_cost)
Definition: file_fdw.c:1139
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:587
ForeignPath * create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, double rows, int disabled_nodes, Cost startup_cost, Cost total_cost, List *pathkeys, Relids required_outer, Path *fdw_outerpath, List *fdw_restrictinfo, List *fdw_private)
Definition: pathnode.c:2307
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:461
#define list_make1(x1)
Definition: pg_list.h:212
Relids lateral_relids
Definition: pathnodes.h:913

References add_path(), check_selective_binary_conversion(), create_foreignscan_path(), estimate_costs(), if(), RelOptInfo::lateral_relids, list_make1, makeDefElem(), NIL, root, and RelOptInfo::rows.

Referenced by file_fdw_handler().

◆ fileGetForeignPlan()

static ForeignScan * fileGetForeignPlan ( PlannerInfo root,
RelOptInfo baserel,
Oid  foreigntableid,
ForeignPath best_path,
List tlist,
List scan_clauses,
Plan outer_plan 
)
static

Definition at line 604 of file file_fdw.c.

611{
612 Index scan_relid = baserel->relid;
613
614 /*
615 * We have no native ability to evaluate restriction clauses, so we just
616 * put all the scan_clauses into the plan node's qual list for the
617 * executor to check. So all we have to do here is strip RestrictInfo
618 * nodes from the clauses and ignore pseudoconstants (which will be
619 * handled elsewhere).
620 */
621 scan_clauses = extract_actual_clauses(scan_clauses, false);
622
623 /* Create the ForeignScan node */
624 return make_foreignscan(tlist,
625 scan_clauses,
626 scan_relid,
627 NIL, /* no expressions to evaluate */
628 best_path->fdw_private,
629 NIL, /* no custom tlist */
630 NIL, /* no remote quals */
631 outer_plan);
632}
unsigned int Index
Definition: c.h:568
ForeignScan * make_foreignscan(List *qptlist, List *qpqual, Index scanrelid, List *fdw_exprs, List *fdw_private, List *fdw_scan_tlist, List *fdw_recheck_quals, Plan *outer_plan)
Definition: createplan.c:5898
List * extract_actual_clauses(List *restrictinfo_list, bool pseudoconstant)
Definition: restrictinfo.c:485
List * fdw_private
Definition: pathnodes.h:1884

References extract_actual_clauses(), ForeignPath::fdw_private, make_foreignscan(), NIL, and RelOptInfo::relid.

Referenced by file_fdw_handler().

◆ fileGetForeignRelSize()

static void fileGetForeignRelSize ( PlannerInfo root,
RelOptInfo baserel,
Oid  foreigntableid 
)
static

Definition at line 518 of file file_fdw.c.

521{
522 FileFdwPlanState *fdw_private;
523
524 /*
525 * Fetch options. We only need filename (or program) at this point, but
526 * we might as well get everything and not need to re-fetch it later in
527 * planning.
528 */
529 fdw_private = (FileFdwPlanState *) palloc(sizeof(FileFdwPlanState));
530 fileGetOptions(foreigntableid,
531 &fdw_private->filename,
532 &fdw_private->is_program,
533 &fdw_private->options);
534 baserel->fdw_private = fdw_private;
535
536 /* Estimate relation size */
537 estimate_size(root, baserel, fdw_private);
538}
static void estimate_size(PlannerInfo *root, RelOptInfo *baserel, FileFdwPlanState *fdw_private)
Definition: file_fdw.c:1058
List * options
Definition: file_fdw.c:99

References estimate_size(), fileGetOptions(), FileFdwPlanState::filename, FileFdwPlanState::is_program, FileFdwPlanState::options, palloc(), and root.

Referenced by file_fdw_handler().

◆ fileGetOptions()

static void fileGetOptions ( Oid  foreigntableid,
char **  filename,
bool *  is_program,
List **  other_options 
)
static

Definition at line 374 of file file_fdw.c.

376{
377 ForeignTable *table;
378 ForeignServer *server;
379 ForeignDataWrapper *wrapper;
380 List *options;
381 ListCell *lc;
382
383 /*
384 * Extract options from FDW objects. We ignore user mappings because
385 * file_fdw doesn't have any options that can be specified there.
386 *
387 * (XXX Actually, given the current contents of valid_options[], there's
388 * no point in examining anything except the foreign table's own options.
389 * Simplify?)
390 */
391 table = GetForeignTable(foreigntableid);
392 server = GetForeignServer(table->serverid);
393 wrapper = GetForeignDataWrapper(server->fdwid);
394
395 options = NIL;
396 options = list_concat(options, wrapper->options);
400
401 /*
402 * Separate out the filename or program option (we assume there is only
403 * one).
404 */
405 *filename = NULL;
406 *is_program = false;
407 foreach(lc, options)
408 {
409 DefElem *def = (DefElem *) lfirst(lc);
410
411 if (strcmp(def->defname, "filename") == 0)
412 {
413 *filename = defGetString(def);
415 break;
416 }
417 else if (strcmp(def->defname, "program") == 0)
418 {
419 *filename = defGetString(def);
420 *is_program = true;
422 break;
423 }
424 }
425
426 /*
427 * The validator should have checked that filename or program was included
428 * in the options, but check again, just in case.
429 */
430 if (*filename == NULL)
431 elog(ERROR, "either filename or program is required for file_fdw foreign tables");
432
433 *other_options = options;
434}
#define elog(elevel,...)
Definition: elog.h:225
static List * get_file_fdw_attribute_options(Oid relid)
Definition: file_fdw.c:445
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:37
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:111
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
List * options
Definition: foreign.h:31
List * options
Definition: foreign.h:42
Oid serverid
Definition: foreign.h:56

References defGetString(), DefElem::defname, elog, ERROR, ForeignServer::fdwid, filename, foreach_delete_current, get_file_fdw_attribute_options(), GetForeignDataWrapper(), GetForeignServer(), GetForeignTable(), lfirst, list_concat(), NIL, options, ForeignDataWrapper::options, ForeignServer::options, ForeignTable::options, and ForeignTable::serverid.

Referenced by file_acquire_sample_rows(), fileAnalyzeForeignTable(), fileBeginForeignScan(), fileExplainForeignScan(), and fileGetForeignRelSize().

◆ fileIsForeignScanParallelSafe()

static bool fileIsForeignScanParallelSafe ( PlannerInfo root,
RelOptInfo rel,
RangeTblEntry rte 
)
static

Definition at line 917 of file file_fdw.c.

919{
920 return true;
921}

Referenced by file_fdw_handler().

◆ fileIterateForeignScan()

static TupleTableSlot * fileIterateForeignScan ( ForeignScanState node)
static

Definition at line 725 of file file_fdw.c.

726{
728 EState *estate = CreateExecutorState();
729 ExprContext *econtext;
731 TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
732 CopyFromState cstate = festate->cstate;
733 ErrorContextCallback errcallback;
734
735 /* Set up callback to identify error line number. */
736 errcallback.callback = CopyFromErrorCallback;
737 errcallback.arg = cstate;
738 errcallback.previous = error_context_stack;
739 error_context_stack = &errcallback;
740
741 /*
742 * We pass ExprContext because there might be a use of the DEFAULT option
743 * in COPY FROM, so we may need to evaluate default expressions.
744 */
745 econtext = GetPerTupleExprContext(estate);
746
747retry:
748
749 /*
750 * DEFAULT expressions need to be evaluated in a per-tuple context, so
751 * switch in case we are doing that.
752 */
754
755 /*
756 * The protocol for loading a virtual tuple into a slot is first
757 * ExecClearTuple, then fill the values/isnull arrays, then
758 * ExecStoreVirtualTuple. If we don't find another row in the file, we
759 * just skip the last step, leaving the slot empty as required.
760 *
761 */
762 ExecClearTuple(slot);
763
764 if (NextCopyFrom(cstate, econtext, slot->tts_values, slot->tts_isnull))
765 {
766 if (cstate->opts.on_error == COPY_ON_ERROR_IGNORE &&
767 cstate->escontext->error_occurred)
768 {
769 /*
770 * Soft error occurred, skip this tuple and just make
771 * ErrorSaveContext ready for the next NextCopyFrom. Since we
772 * don't set details_wanted and error_data is not to be filled,
773 * just resetting error_occurred is enough.
774 */
775 cstate->escontext->error_occurred = false;
776
777 /* Switch back to original memory context */
778 MemoryContextSwitchTo(oldcontext);
779
780 /*
781 * Make sure we are interruptible while repeatedly calling
782 * NextCopyFrom() until no soft error occurs.
783 */
785
786 /*
787 * Reset the per-tuple exprcontext, to clean-up after expression
788 * evaluations etc.
789 */
791
792 if (cstate->opts.reject_limit > 0 &&
793 cstate->num_errors > cstate->opts.reject_limit)
795 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
796 errmsg("skipped more than REJECT_LIMIT (%lld) rows due to data type incompatibility",
797 (long long) cstate->opts.reject_limit)));
798
799 /* Repeat NextCopyFrom() until no soft error occurs */
800 goto retry;
801 }
802
804 }
805
806 /* Switch back to original memory context */
807 MemoryContextSwitchTo(oldcontext);
808
809 /* Remove error callback. */
810 error_context_stack = errcallback.previous;
811
812 return slot;
813}
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1739
EState * CreateExecutorState(void)
Definition: execUtils.c:88
#define ResetPerTupleExprContext(estate)
Definition: executor.h:572
#define GetPerTupleExprContext(estate)
Definition: executor.h:563
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:568
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
int64 reject_limit
Definition: copy.h:88
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1576
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454

References ErrorContextCallback::arg, ErrorContextCallback::callback, CHECK_FOR_INTERRUPTS, COPY_ON_ERROR_IGNORE, CopyFromErrorCallback(), CreateExecutorState(), FileFdwExecutionState::cstate, CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, error_context_stack, ErrorSaveContext::error_occurred, CopyFromStateData::escontext, ExecClearTuple(), ExecStoreVirtualTuple(), ForeignScanState::fdw_state, GetPerTupleExprContext, GetPerTupleMemoryContext, MemoryContextSwitchTo(), NextCopyFrom(), CopyFromStateData::num_errors, CopyFormatOptions::on_error, CopyFromStateData::opts, ErrorContextCallback::previous, CopyFormatOptions::reject_limit, ResetPerTupleExprContext, ForeignScanState::ss, ScanState::ss_ScanTupleSlot, TupleTableSlot::tts_isnull, and TupleTableSlot::tts_values.

Referenced by file_fdw_handler().

◆ fileReScanForeignScan()

static void fileReScanForeignScan ( ForeignScanState node)
static

◆ get_file_fdw_attribute_options()

static List * get_file_fdw_attribute_options ( Oid  relid)
static

Definition at line 445 of file file_fdw.c.

446{
447 Relation rel;
448 TupleDesc tupleDesc;
449 AttrNumber natts;
451 List *fnncolumns = NIL;
452 List *fncolumns = NIL;
453
454 List *options = NIL;
455
456 rel = table_open(relid, AccessShareLock);
457 tupleDesc = RelationGetDescr(rel);
458 natts = tupleDesc->natts;
459
460 /* Retrieve FDW options for all user-defined attributes. */
461 for (attnum = 1; attnum <= natts; attnum++)
462 {
463 Form_pg_attribute attr = TupleDescAttr(tupleDesc, attnum - 1);
464 List *column_options;
465 ListCell *lc;
466
467 /* Skip dropped attributes. */
468 if (attr->attisdropped)
469 continue;
470
471 column_options = GetForeignColumnOptions(relid, attnum);
472 foreach(lc, column_options)
473 {
474 DefElem *def = (DefElem *) lfirst(lc);
475
476 if (strcmp(def->defname, "force_not_null") == 0)
477 {
478 if (defGetBoolean(def))
479 {
480 char *attname = pstrdup(NameStr(attr->attname));
481
482 fnncolumns = lappend(fnncolumns, makeString(attname));
483 }
484 }
485 else if (strcmp(def->defname, "force_null") == 0)
486 {
487 if (defGetBoolean(def))
488 {
489 char *attname = pstrdup(NameStr(attr->attname));
490
491 fncolumns = lappend(fncolumns, makeString(attname));
492 }
493 }
494 /* maybe in future handle other column options here */
495 }
496 }
497
499
500 /*
501 * Return DefElem only when some column(s) have force_not_null /
502 * force_null options set
503 */
504 if (fnncolumns != NIL)
505 options = lappend(options, makeDefElem("force_not_null", (Node *) fnncolumns, -1));
506
507 if (fncolumns != NIL)
508 options = lappend(options, makeDefElem("force_null", (Node *) fncolumns, -1));
509
510 return options;
511}
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition: foreign.c:292

References AccessShareLock, attname, attnum, defGetBoolean(), DefElem::defname, GetForeignColumnOptions(), lappend(), lfirst, makeDefElem(), makeString(), NameStr, TupleDescData::natts, NIL, options, pstrdup(), RelationGetDescr, table_close(), table_open(), and TupleDescAttr().

Referenced by fileGetOptions().

◆ is_valid_option()

static bool is_valid_option ( const char *  option,
Oid  context 
)
static

Definition at line 355 of file file_fdw.c.

356{
357 const struct FileFdwOption *opt;
358
359 for (opt = valid_options; opt->optname; opt++)
360 {
361 if (context == opt->optcontext && strcmp(opt->optname, option) == 0)
362 return true;
363 }
364 return false;
365}

References FileFdwOption::optcontext, FileFdwOption::optname, and valid_options.

Referenced by file_fdw_validator().

◆ PG_FUNCTION_INFO_V1() [1/2]

PG_FUNCTION_INFO_V1 ( file_fdw_handler  )

◆ PG_FUNCTION_INFO_V1() [2/2]

PG_FUNCTION_INFO_V1 ( file_fdw_validator  )

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 43 of file file_fdw.c.

◆ valid_options

const struct FileFdwOption valid_options[]
static
Initial value:
= {
{"filename", ForeignTableRelationId},
{"program", ForeignTableRelationId},
{"format", ForeignTableRelationId},
{"header", ForeignTableRelationId},
{"delimiter", ForeignTableRelationId},
{"quote", ForeignTableRelationId},
{"escape", ForeignTableRelationId},
{"null", ForeignTableRelationId},
{"default", ForeignTableRelationId},
{"encoding", ForeignTableRelationId},
{"on_error", ForeignTableRelationId},
{"log_verbosity", ForeignTableRelationId},
{"reject_limit", ForeignTableRelationId},
{"force_not_null", AttributeRelationId},
{"force_null", AttributeRelationId},
{NULL, InvalidOid}
}
#define InvalidOid
Definition: postgres_ext.h:36

Definition at line 63 of file file_fdw.c.

Referenced by file_fdw_validator(), and is_valid_option().