PostgreSQL Source Code  git master
file_fdw.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * file_fdw.c
4  * foreign-data wrapper for server-side flat files (or programs).
5  *
6  * Copyright (c) 2010-2024, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * contrib/file_fdw/file_fdw.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 
15 #include <sys/stat.h>
16 #include <unistd.h>
17 
18 #include "access/htup_details.h"
19 #include "access/reloptions.h"
20 #include "access/sysattr.h"
21 #include "access/table.h"
22 #include "catalog/pg_authid.h"
24 #include "commands/copy.h"
26 #include "commands/defrem.h"
27 #include "commands/explain.h"
28 #include "commands/vacuum.h"
29 #include "foreign/fdwapi.h"
30 #include "foreign/foreign.h"
31 #include "miscadmin.h"
32 #include "nodes/makefuncs.h"
33 #include "optimizer/optimizer.h"
34 #include "optimizer/pathnode.h"
35 #include "optimizer/planmain.h"
36 #include "optimizer/restrictinfo.h"
37 #include "utils/acl.h"
38 #include "utils/memutils.h"
39 #include "utils/rel.h"
40 #include "utils/sampling.h"
41 #include "utils/varlena.h"
42 
44 
45 /*
46  * Describes the valid options for objects that use this wrapper.
47  */
49 {
50  const char *optname;
51  Oid optcontext; /* Oid of catalog in which option may appear */
52 };
53 
54 /*
55  * Valid options for file_fdw.
56  * These options are based on the options for the COPY FROM command.
57  * But note that force_not_null and force_null are handled as boolean options
58  * attached to a column, not as table options.
59  *
60  * Note: If you are adding new option for user mapping, you need to modify
61  * fileGetOptions(), which currently doesn't bother to look at user mappings.
62  */
63 static const struct FileFdwOption valid_options[] = {
64  /* Data source options */
65  {"filename", ForeignTableRelationId},
66  {"program", ForeignTableRelationId},
67 
68  /* Format options */
69  /* oids option is not supported */
70  {"format", ForeignTableRelationId},
71  {"header", ForeignTableRelationId},
72  {"delimiter", ForeignTableRelationId},
73  {"quote", ForeignTableRelationId},
74  {"escape", ForeignTableRelationId},
75  {"null", ForeignTableRelationId},
76  {"default", ForeignTableRelationId},
77  {"encoding", ForeignTableRelationId},
78  {"on_error", ForeignTableRelationId},
79  {"log_verbosity", ForeignTableRelationId},
80  {"force_not_null", AttributeRelationId},
81  {"force_null", AttributeRelationId},
82 
83  /*
84  * force_quote is not supported by file_fdw because it's for COPY TO.
85  */
86 
87  /* Sentinel */
88  {NULL, InvalidOid}
89 };
90 
91 /*
92  * FDW-specific information for RelOptInfo.fdw_private.
93  */
94 typedef struct FileFdwPlanState
95 {
96  char *filename; /* file or program to read from */
97  bool is_program; /* true if filename represents an OS command */
98  List *options; /* merged COPY options, excluding filename and
99  * is_program */
100  BlockNumber pages; /* estimate of file's physical size */
101  double ntuples; /* estimate of number of data rows */
103 
104 /*
105  * FDW-specific information for ForeignScanState.fdw_state.
106  */
107 typedef struct FileFdwExecutionState
108 {
109  char *filename; /* file or program to read from */
110  bool is_program; /* true if filename represents an OS command */
111  List *options; /* merged COPY options, excluding filename and
112  * is_program */
113  CopyFromState cstate; /* COPY execution state */
115 
116 /*
117  * SQL functions
118  */
121 
122 /*
123  * FDW callback routines
124  */
126  RelOptInfo *baserel,
127  Oid foreigntableid);
129  RelOptInfo *baserel,
130  Oid foreigntableid);
132  RelOptInfo *baserel,
133  Oid foreigntableid,
134  ForeignPath *best_path,
135  List *tlist,
136  List *scan_clauses,
137  Plan *outer_plan);
139 static void fileBeginForeignScan(ForeignScanState *node, int eflags);
141 static void fileReScanForeignScan(ForeignScanState *node);
142 static void fileEndForeignScan(ForeignScanState *node);
143 static bool fileAnalyzeForeignTable(Relation relation,
144  AcquireSampleRowsFunc *func,
145  BlockNumber *totalpages);
147  RangeTblEntry *rte);
148 
149 /*
150  * Helper functions
151  */
152 static bool is_valid_option(const char *option, Oid context);
153 static void fileGetOptions(Oid foreigntableid,
154  char **filename,
155  bool *is_program,
156  List **other_options);
158 static bool check_selective_binary_conversion(RelOptInfo *baserel,
159  Oid foreigntableid,
160  List **columns);
161 static void estimate_size(PlannerInfo *root, RelOptInfo *baserel,
162  FileFdwPlanState *fdw_private);
163 static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
164  FileFdwPlanState *fdw_private,
165  Cost *startup_cost, Cost *total_cost);
166 static int file_acquire_sample_rows(Relation onerel, int elevel,
167  HeapTuple *rows, int targrows,
168  double *totalrows, double *totaldeadrows);
169 
170 
171 /*
172  * Foreign-data wrapper handler function: return a struct with pointers
173  * to my callback routines.
174  */
175 Datum
177 {
178  FdwRoutine *fdwroutine = makeNode(FdwRoutine);
179 
181  fdwroutine->GetForeignPaths = fileGetForeignPaths;
182  fdwroutine->GetForeignPlan = fileGetForeignPlan;
187  fdwroutine->EndForeignScan = fileEndForeignScan;
190 
191  PG_RETURN_POINTER(fdwroutine);
192 }
193 
194 /*
195  * Validate the generic options given to a FOREIGN DATA WRAPPER, SERVER,
196  * USER MAPPING or FOREIGN TABLE that uses file_fdw.
197  *
198  * Raise an ERROR if the option or its value is considered invalid.
199  */
200 Datum
202 {
203  List *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
204  Oid catalog = PG_GETARG_OID(1);
205  char *filename = NULL;
206  DefElem *force_not_null = NULL;
207  DefElem *force_null = NULL;
208  List *other_options = NIL;
209  ListCell *cell;
210 
211  /*
212  * Check that only options supported by file_fdw, and allowed for the
213  * current object type, are given.
214  */
215  foreach(cell, options_list)
216  {
217  DefElem *def = (DefElem *) lfirst(cell);
218 
219  if (!is_valid_option(def->defname, catalog))
220  {
221  const struct FileFdwOption *opt;
222  const char *closest_match;
224  bool has_valid_options = false;
225 
226  /*
227  * Unknown option specified, complain about it. Provide a hint
228  * with a valid option that looks similar, if there is one.
229  */
231  for (opt = valid_options; opt->optname; opt++)
232  {
233  if (catalog == opt->optcontext)
234  {
235  has_valid_options = true;
237  }
238  }
239 
240  closest_match = getClosestMatch(&match_state);
241  ereport(ERROR,
242  (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
243  errmsg("invalid option \"%s\"", def->defname),
244  has_valid_options ? closest_match ?
245  errhint("Perhaps you meant the option \"%s\".",
246  closest_match) : 0 :
247  errhint("There are no valid options in this context.")));
248  }
249 
250  /*
251  * Separate out filename, program, and column-specific options, since
252  * ProcessCopyOptions won't accept them.
253  */
254  if (strcmp(def->defname, "filename") == 0 ||
255  strcmp(def->defname, "program") == 0)
256  {
257  if (filename)
258  ereport(ERROR,
259  (errcode(ERRCODE_SYNTAX_ERROR),
260  errmsg("conflicting or redundant options")));
261 
262  /*
263  * Check permissions for changing which file or program is used by
264  * the file_fdw.
265  *
266  * Only members of the role 'pg_read_server_files' are allowed to
267  * set the 'filename' option of a file_fdw foreign table, while
268  * only members of the role 'pg_execute_server_program' are
269  * allowed to set the 'program' option. This is because we don't
270  * want regular users to be able to control which file gets read
271  * or which program gets executed.
272  *
273  * Putting this sort of permissions check in a validator is a bit
274  * of a crock, but there doesn't seem to be any other place that
275  * can enforce the check more cleanly.
276  *
277  * Note that the valid_options[] array disallows setting filename
278  * and program at any options level other than foreign table ---
279  * otherwise there'd still be a security hole.
280  */
281  if (strcmp(def->defname, "filename") == 0 &&
282  !has_privs_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
283  ereport(ERROR,
284  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
285  errmsg("permission denied to set the \"%s\" option of a file_fdw foreign table",
286  "filename"),
287  errdetail("Only roles with privileges of the \"%s\" role may set this option.",
288  "pg_read_server_files")));
289 
290  if (strcmp(def->defname, "program") == 0 &&
291  !has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM))
292  ereport(ERROR,
293  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
294  errmsg("permission denied to set the \"%s\" option of a file_fdw foreign table",
295  "program"),
296  errdetail("Only roles with privileges of the \"%s\" role may set this option.",
297  "pg_execute_server_program")));
298 
299  filename = defGetString(def);
300  }
301 
302  /*
303  * force_not_null is a boolean option; after validation we can discard
304  * it - it will be retrieved later in get_file_fdw_attribute_options()
305  */
306  else if (strcmp(def->defname, "force_not_null") == 0)
307  {
308  if (force_not_null)
309  ereport(ERROR,
310  (errcode(ERRCODE_SYNTAX_ERROR),
311  errmsg("conflicting or redundant options"),
312  errhint("Option \"force_not_null\" supplied more than once for a column.")));
313  force_not_null = def;
314  /* Don't care what the value is, as long as it's a legal boolean */
315  (void) defGetBoolean(def);
316  }
317  /* See comments for force_not_null above */
318  else if (strcmp(def->defname, "force_null") == 0)
319  {
320  if (force_null)
321  ereport(ERROR,
322  (errcode(ERRCODE_SYNTAX_ERROR),
323  errmsg("conflicting or redundant options"),
324  errhint("Option \"force_null\" supplied more than once for a column.")));
325  force_null = def;
326  (void) defGetBoolean(def);
327  }
328  else
329  other_options = lappend(other_options, def);
330  }
331 
332  /*
333  * Now apply the core COPY code's validation logic for more checks.
334  */
335  ProcessCopyOptions(NULL, NULL, true, other_options);
336 
337  /*
338  * Either filename or program option is required for file_fdw foreign
339  * tables.
340  */
341  if (catalog == ForeignTableRelationId && filename == NULL)
342  ereport(ERROR,
343  (errcode(ERRCODE_FDW_DYNAMIC_PARAMETER_VALUE_NEEDED),
344  errmsg("either filename or program is required for file_fdw foreign tables")));
345 
346  PG_RETURN_VOID();
347 }
348 
349 /*
350  * Check if the provided option is one of the valid options.
351  * context is the Oid of the catalog holding the object the option is for.
352  */
353 static bool
355 {
356  const struct FileFdwOption *opt;
357 
358  for (opt = valid_options; opt->optname; opt++)
359  {
360  if (context == opt->optcontext && strcmp(opt->optname, option) == 0)
361  return true;
362  }
363  return false;
364 }
365 
366 /*
367  * Fetch the options for a file_fdw foreign table.
368  *
369  * We have to separate out filename/program from the other options because
370  * those must not appear in the options list passed to the core COPY code.
371  */
372 static void
373 fileGetOptions(Oid foreigntableid,
374  char **filename, bool *is_program, List **other_options)
375 {
376  ForeignTable *table;
377  ForeignServer *server;
378  ForeignDataWrapper *wrapper;
379  List *options;
380  ListCell *lc;
381 
382  /*
383  * Extract options from FDW objects. We ignore user mappings because
384  * file_fdw doesn't have any options that can be specified there.
385  *
386  * (XXX Actually, given the current contents of valid_options[], there's
387  * no point in examining anything except the foreign table's own options.
388  * Simplify?)
389  */
390  table = GetForeignTable(foreigntableid);
391  server = GetForeignServer(table->serverid);
392  wrapper = GetForeignDataWrapper(server->fdwid);
393 
394  options = NIL;
395  options = list_concat(options, wrapper->options);
396  options = list_concat(options, server->options);
397  options = list_concat(options, table->options);
399 
400  /*
401  * Separate out the filename or program option (we assume there is only
402  * one).
403  */
404  *filename = NULL;
405  *is_program = false;
406  foreach(lc, options)
407  {
408  DefElem *def = (DefElem *) lfirst(lc);
409 
410  if (strcmp(def->defname, "filename") == 0)
411  {
412  *filename = defGetString(def);
414  break;
415  }
416  else if (strcmp(def->defname, "program") == 0)
417  {
418  *filename = defGetString(def);
419  *is_program = true;
421  break;
422  }
423  }
424 
425  /*
426  * The validator should have checked that filename or program was included
427  * in the options, but check again, just in case.
428  */
429  if (*filename == NULL)
430  elog(ERROR, "either filename or program is required for file_fdw foreign tables");
431 
432  *other_options = options;
433 }
434 
435 /*
436  * Retrieve per-column generic options from pg_attribute and construct a list
437  * of DefElems representing them.
438  *
439  * At the moment we only have "force_not_null", and "force_null",
440  * which should each be combined into a single DefElem listing all such
441  * columns, since that's what COPY expects.
442  */
443 static List *
445 {
446  Relation rel;
447  TupleDesc tupleDesc;
448  AttrNumber natts;
450  List *fnncolumns = NIL;
451  List *fncolumns = NIL;
452 
453  List *options = NIL;
454 
455  rel = table_open(relid, AccessShareLock);
456  tupleDesc = RelationGetDescr(rel);
457  natts = tupleDesc->natts;
458 
459  /* Retrieve FDW options for all user-defined attributes. */
460  for (attnum = 1; attnum <= natts; attnum++)
461  {
462  Form_pg_attribute attr = TupleDescAttr(tupleDesc, attnum - 1);
463  List *column_options;
464  ListCell *lc;
465 
466  /* Skip dropped attributes. */
467  if (attr->attisdropped)
468  continue;
469 
470  column_options = GetForeignColumnOptions(relid, attnum);
471  foreach(lc, column_options)
472  {
473  DefElem *def = (DefElem *) lfirst(lc);
474 
475  if (strcmp(def->defname, "force_not_null") == 0)
476  {
477  if (defGetBoolean(def))
478  {
479  char *attname = pstrdup(NameStr(attr->attname));
480 
481  fnncolumns = lappend(fnncolumns, makeString(attname));
482  }
483  }
484  else if (strcmp(def->defname, "force_null") == 0)
485  {
486  if (defGetBoolean(def))
487  {
488  char *attname = pstrdup(NameStr(attr->attname));
489 
490  fncolumns = lappend(fncolumns, makeString(attname));
491  }
492  }
493  /* maybe in future handle other column options here */
494  }
495  }
496 
498 
499  /*
500  * Return DefElem only when some column(s) have force_not_null /
501  * force_null options set
502  */
503  if (fnncolumns != NIL)
504  options = lappend(options, makeDefElem("force_not_null", (Node *) fnncolumns, -1));
505 
506  if (fncolumns != NIL)
507  options = lappend(options, makeDefElem("force_null", (Node *) fncolumns, -1));
508 
509  return options;
510 }
511 
512 /*
513  * fileGetForeignRelSize
514  * Obtain relation size estimates for a foreign table
515  */
516 static void
518  RelOptInfo *baserel,
519  Oid foreigntableid)
520 {
521  FileFdwPlanState *fdw_private;
522 
523  /*
524  * Fetch options. We only need filename (or program) at this point, but
525  * we might as well get everything and not need to re-fetch it later in
526  * planning.
527  */
528  fdw_private = (FileFdwPlanState *) palloc(sizeof(FileFdwPlanState));
529  fileGetOptions(foreigntableid,
530  &fdw_private->filename,
531  &fdw_private->is_program,
532  &fdw_private->options);
533  baserel->fdw_private = (void *) fdw_private;
534 
535  /* Estimate relation size */
536  estimate_size(root, baserel, fdw_private);
537 }
538 
539 /*
540  * fileGetForeignPaths
541  * Create possible access paths for a scan on the foreign table
542  *
543  * Currently we don't support any push-down feature, so there is only one
544  * possible access path, which simply returns all records in the order in
545  * the data file.
546  */
547 static void
549  RelOptInfo *baserel,
550  Oid foreigntableid)
551 {
552  FileFdwPlanState *fdw_private = (FileFdwPlanState *) baserel->fdw_private;
553  Cost startup_cost;
554  Cost total_cost;
555  List *columns;
556  List *coptions = NIL;
557 
558  /* Decide whether to selectively perform binary conversion */
560  foreigntableid,
561  &columns))
562  coptions = list_make1(makeDefElem("convert_selectively",
563  (Node *) columns, -1));
564 
565  /* Estimate costs */
566  estimate_costs(root, baserel, fdw_private,
567  &startup_cost, &total_cost);
568 
569  /*
570  * Create a ForeignPath node and add it as only possible path. We use the
571  * fdw_private list of the path to carry the convert_selectively option;
572  * it will be propagated into the fdw_private list of the Plan node.
573  *
574  * We don't support pushing join clauses into the quals of this path, but
575  * it could still have required parameterization due to LATERAL refs in
576  * its tlist.
577  */
578  add_path(baserel, (Path *)
579  create_foreignscan_path(root, baserel,
580  NULL, /* default pathtarget */
581  baserel->rows,
582  0,
583  startup_cost,
584  total_cost,
585  NIL, /* no pathkeys */
586  baserel->lateral_relids,
587  NULL, /* no extra plan */
588  NIL, /* no fdw_restrictinfo list */
589  coptions));
590 
591  /*
592  * If data file was sorted, and we knew it somehow, we could insert
593  * appropriate pathkeys into the ForeignPath node to tell the planner
594  * that.
595  */
596 }
597 
598 /*
599  * fileGetForeignPlan
600  * Create a ForeignScan plan node for scanning the foreign table
601  */
602 static ForeignScan *
604  RelOptInfo *baserel,
605  Oid foreigntableid,
606  ForeignPath *best_path,
607  List *tlist,
608  List *scan_clauses,
609  Plan *outer_plan)
610 {
611  Index scan_relid = baserel->relid;
612 
613  /*
614  * We have no native ability to evaluate restriction clauses, so we just
615  * put all the scan_clauses into the plan node's qual list for the
616  * executor to check. So all we have to do here is strip RestrictInfo
617  * nodes from the clauses and ignore pseudoconstants (which will be
618  * handled elsewhere).
619  */
620  scan_clauses = extract_actual_clauses(scan_clauses, false);
621 
622  /* Create the ForeignScan node */
623  return make_foreignscan(tlist,
624  scan_clauses,
625  scan_relid,
626  NIL, /* no expressions to evaluate */
627  best_path->fdw_private,
628  NIL, /* no custom tlist */
629  NIL, /* no remote quals */
630  outer_plan);
631 }
632 
633 /*
634  * fileExplainForeignScan
635  * Produce extra output for EXPLAIN
636  */
637 static void
639 {
640  char *filename;
641  bool is_program;
642  List *options;
643 
644  /* Fetch options --- we only need filename and is_program at this point */
646  &filename, &is_program, &options);
647 
648  if (is_program)
649  ExplainPropertyText("Foreign Program", filename, es);
650  else
651  ExplainPropertyText("Foreign File", filename, es);
652 
653  /* Suppress file size if we're not showing cost details */
654  if (es->costs)
655  {
656  struct stat stat_buf;
657 
658  if (!is_program &&
659  stat(filename, &stat_buf) == 0)
660  ExplainPropertyInteger("Foreign File Size", "b",
661  (int64) stat_buf.st_size, es);
662  }
663 }
664 
665 /*
666  * fileBeginForeignScan
667  * Initiate access to the file by creating CopyState
668  */
669 static void
671 {
672  ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
673  char *filename;
674  bool is_program;
675  List *options;
676  CopyFromState cstate;
677  FileFdwExecutionState *festate;
678 
679  /*
680  * Do nothing in EXPLAIN (no ANALYZE) case. node->fdw_state stays NULL.
681  */
682  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
683  return;
684 
685  /* Fetch options of foreign table */
687  &filename, &is_program, &options);
688 
689  /* Add any options from the plan (currently only convert_selectively) */
690  options = list_concat(options, plan->fdw_private);
691 
692  /*
693  * Create CopyState from FDW options. We always acquire all columns, so
694  * as to match the expected ScanTupleSlot signature.
695  */
696  cstate = BeginCopyFrom(NULL,
697  node->ss.ss_currentRelation,
698  NULL,
699  filename,
700  is_program,
701  NULL,
702  NIL,
703  options);
704 
705  /*
706  * Save state in node->fdw_state. We must save enough information to call
707  * BeginCopyFrom() again.
708  */
709  festate = (FileFdwExecutionState *) palloc(sizeof(FileFdwExecutionState));
710  festate->filename = filename;
711  festate->is_program = is_program;
712  festate->options = options;
713  festate->cstate = cstate;
714 
715  node->fdw_state = (void *) festate;
716 }
717 
718 /*
719  * fileIterateForeignScan
720  * Read next record from the data file and store it into the
721  * ScanTupleSlot as a virtual tuple
722  */
723 static TupleTableSlot *
725 {
727  EState *estate = CreateExecutorState();
728  ExprContext *econtext;
729  MemoryContext oldcontext = CurrentMemoryContext;
730  TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
731  CopyFromState cstate = festate->cstate;
732  ErrorContextCallback errcallback;
733 
734  /* Set up callback to identify error line number. */
735  errcallback.callback = CopyFromErrorCallback;
736  errcallback.arg = (void *) cstate;
737  errcallback.previous = error_context_stack;
738  error_context_stack = &errcallback;
739 
740  /*
741  * We pass ExprContext because there might be a use of the DEFAULT option
742  * in COPY FROM, so we may need to evaluate default expressions.
743  */
744  econtext = GetPerTupleExprContext(estate);
745 
746 retry:
747 
748  /*
749  * DEFAULT expressions need to be evaluated in a per-tuple context, so
750  * switch in case we are doing that.
751  */
753 
754  /*
755  * The protocol for loading a virtual tuple into a slot is first
756  * ExecClearTuple, then fill the values/isnull arrays, then
757  * ExecStoreVirtualTuple. If we don't find another row in the file, we
758  * just skip the last step, leaving the slot empty as required.
759  *
760  */
761  ExecClearTuple(slot);
762 
763  if (NextCopyFrom(cstate, econtext, slot->tts_values, slot->tts_isnull))
764  {
765  if (cstate->opts.on_error == COPY_ON_ERROR_IGNORE &&
766  cstate->escontext->error_occurred)
767  {
768  /*
769  * Soft error occurred, skip this tuple and just make
770  * ErrorSaveContext ready for the next NextCopyFrom. Since we
771  * don't set details_wanted and error_data is not to be filled,
772  * just resetting error_occurred is enough.
773  */
774  cstate->escontext->error_occurred = false;
775 
776  /* Switch back to original memory context */
777  MemoryContextSwitchTo(oldcontext);
778 
779  /*
780  * Make sure we are interruptible while repeatedly calling
781  * NextCopyFrom() until no soft error occurs.
782  */
784 
785  /*
786  * Reset the per-tuple exprcontext, to clean-up after expression
787  * evaluations etc.
788  */
789  ResetPerTupleExprContext(estate);
790 
791  /* Repeat NextCopyFrom() until no soft error occurs */
792  goto retry;
793  }
794 
795  ExecStoreVirtualTuple(slot);
796  }
797 
798  /* Switch back to original memory context */
799  MemoryContextSwitchTo(oldcontext);
800 
801  /* Remove error callback. */
802  error_context_stack = errcallback.previous;
803 
804  return slot;
805 }
806 
807 /*
808  * fileReScanForeignScan
809  * Rescan table, possibly with new parameters
810  */
811 static void
813 {
815 
816  EndCopyFrom(festate->cstate);
817 
818  festate->cstate = BeginCopyFrom(NULL,
819  node->ss.ss_currentRelation,
820  NULL,
821  festate->filename,
822  festate->is_program,
823  NULL,
824  NIL,
825  festate->options);
826 }
827 
828 /*
829  * fileEndForeignScan
830  * Finish scanning foreign table and dispose objects used for this scan
831  */
832 static void
834 {
836 
837  /* if festate is NULL, we are in EXPLAIN; nothing to do */
838  if (!festate)
839  return;
840 
841  if (festate->cstate->opts.on_error == COPY_ON_ERROR_IGNORE &&
842  festate->cstate->num_errors > 0 &&
844  ereport(NOTICE,
845  errmsg_plural("%llu row was skipped due to data type incompatibility",
846  "%llu rows were skipped due to data type incompatibility",
847  (unsigned long long) festate->cstate->num_errors,
848  (unsigned long long) festate->cstate->num_errors));
849 
850  EndCopyFrom(festate->cstate);
851 }
852 
853 /*
854  * fileAnalyzeForeignTable
855  * Test whether analyzing this foreign table is supported
856  */
857 static bool
859  AcquireSampleRowsFunc *func,
860  BlockNumber *totalpages)
861 {
862  char *filename;
863  bool is_program;
864  List *options;
865  struct stat stat_buf;
866 
867  /* Fetch options of foreign table */
868  fileGetOptions(RelationGetRelid(relation), &filename, &is_program, &options);
869 
870  /*
871  * If this is a program instead of a file, just return false to skip
872  * analyzing the table. We could run the program and collect stats on
873  * whatever it currently returns, but it seems likely that in such cases
874  * the output would be too volatile for the stats to be useful. Maybe
875  * there should be an option to enable doing this?
876  */
877  if (is_program)
878  return false;
879 
880  /*
881  * Get size of the file. (XXX if we fail here, would it be better to just
882  * return false to skip analyzing the table?)
883  */
884  if (stat(filename, &stat_buf) < 0)
885  ereport(ERROR,
887  errmsg("could not stat file \"%s\": %m",
888  filename)));
889 
890  /*
891  * Convert size to pages. Must return at least 1 so that we can tell
892  * later on that pg_class.relpages is not default.
893  */
894  *totalpages = (stat_buf.st_size + (BLCKSZ - 1)) / BLCKSZ;
895  if (*totalpages < 1)
896  *totalpages = 1;
897 
898  *func = file_acquire_sample_rows;
899 
900  return true;
901 }
902 
903 /*
904  * fileIsForeignScanParallelSafe
905  * Reading a file, or external program, in a parallel worker should work
906  * just the same as reading it in the leader, so mark scans safe.
907  */
908 static bool
910  RangeTblEntry *rte)
911 {
912  return true;
913 }
914 
915 /*
916  * check_selective_binary_conversion
917  *
918  * Check to see if it's useful to convert only a subset of the file's columns
919  * to binary. If so, construct a list of the column names to be converted,
920  * return that at *columns, and return true. (Note that it's possible to
921  * determine that no columns need be converted, for instance with a COUNT(*)
922  * query. So we can't use returning a NIL list to indicate failure.)
923  */
924 static bool
926  Oid foreigntableid,
927  List **columns)
928 {
929  ForeignTable *table;
930  ListCell *lc;
931  Relation rel;
932  TupleDesc tupleDesc;
933  int attidx;
934  Bitmapset *attrs_used = NULL;
935  bool has_wholerow = false;
936  int numattrs;
937  int i;
938 
939  *columns = NIL; /* default result */
940 
941  /*
942  * Check format of the file. If binary format, this is irrelevant.
943  */
944  table = GetForeignTable(foreigntableid);
945  foreach(lc, table->options)
946  {
947  DefElem *def = (DefElem *) lfirst(lc);
948 
949  if (strcmp(def->defname, "format") == 0)
950  {
951  char *format = defGetString(def);
952 
953  if (strcmp(format, "binary") == 0)
954  return false;
955  break;
956  }
957  }
958 
959  /* Collect all the attributes needed for joins or final output. */
960  pull_varattnos((Node *) baserel->reltarget->exprs, baserel->relid,
961  &attrs_used);
962 
963  /* Add all the attributes used by restriction clauses. */
964  foreach(lc, baserel->baserestrictinfo)
965  {
966  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
967 
968  pull_varattnos((Node *) rinfo->clause, baserel->relid,
969  &attrs_used);
970  }
971 
972  /* Convert attribute numbers to column names. */
973  rel = table_open(foreigntableid, AccessShareLock);
974  tupleDesc = RelationGetDescr(rel);
975 
976  attidx = -1;
977  while ((attidx = bms_next_member(attrs_used, attidx)) >= 0)
978  {
979  /* attidx is zero-based, attnum is the normal attribute number */
981 
982  if (attnum == 0)
983  {
984  has_wholerow = true;
985  break;
986  }
987 
988  /* Ignore system attributes. */
989  if (attnum < 0)
990  continue;
991 
992  /* Get user attributes. */
993  if (attnum > 0)
994  {
995  Form_pg_attribute attr = TupleDescAttr(tupleDesc, attnum - 1);
996  char *attname = NameStr(attr->attname);
997 
998  /* Skip dropped attributes (probably shouldn't see any here). */
999  if (attr->attisdropped)
1000  continue;
1001 
1002  /*
1003  * Skip generated columns (COPY won't accept them in the column
1004  * list)
1005  */
1006  if (attr->attgenerated)
1007  continue;
1008  *columns = lappend(*columns, makeString(pstrdup(attname)));
1009  }
1010  }
1011 
1012  /* Count non-dropped user attributes while we have the tupdesc. */
1013  numattrs = 0;
1014  for (i = 0; i < tupleDesc->natts; i++)
1015  {
1016  Form_pg_attribute attr = TupleDescAttr(tupleDesc, i);
1017 
1018  if (attr->attisdropped)
1019  continue;
1020  numattrs++;
1021  }
1022 
1024 
1025  /* If there's a whole-row reference, fail: we need all the columns. */
1026  if (has_wholerow)
1027  {
1028  *columns = NIL;
1029  return false;
1030  }
1031 
1032  /* If all the user attributes are needed, fail. */
1033  if (numattrs == list_length(*columns))
1034  {
1035  *columns = NIL;
1036  return false;
1037  }
1038 
1039  return true;
1040 }
1041 
1042 /*
1043  * Estimate size of a foreign table.
1044  *
1045  * The main result is returned in baserel->rows. We also set
1046  * fdw_private->pages and fdw_private->ntuples for later use in the cost
1047  * calculation.
1048  */
1049 static void
1051  FileFdwPlanState *fdw_private)
1052 {
1053  struct stat stat_buf;
1054  BlockNumber pages;
1055  double ntuples;
1056  double nrows;
1057 
1058  /*
1059  * Get size of the file. It might not be there at plan time, though, in
1060  * which case we have to use a default estimate. We also have to fall
1061  * back to the default if using a program as the input.
1062  */
1063  if (fdw_private->is_program || stat(fdw_private->filename, &stat_buf) < 0)
1064  stat_buf.st_size = 10 * BLCKSZ;
1065 
1066  /*
1067  * Convert size to pages for use in I/O cost estimate later.
1068  */
1069  pages = (stat_buf.st_size + (BLCKSZ - 1)) / BLCKSZ;
1070  if (pages < 1)
1071  pages = 1;
1072  fdw_private->pages = pages;
1073 
1074  /*
1075  * Estimate the number of tuples in the file.
1076  */
1077  if (baserel->tuples >= 0 && baserel->pages > 0)
1078  {
1079  /*
1080  * We have # of pages and # of tuples from pg_class (that is, from a
1081  * previous ANALYZE), so compute a tuples-per-page estimate and scale
1082  * that by the current file size.
1083  */
1084  double density;
1085 
1086  density = baserel->tuples / (double) baserel->pages;
1087  ntuples = clamp_row_est(density * (double) pages);
1088  }
1089  else
1090  {
1091  /*
1092  * Otherwise we have to fake it. We back into this estimate using the
1093  * planner's idea of the relation width; which is bogus if not all
1094  * columns are being read, not to mention that the text representation
1095  * of a row probably isn't the same size as its internal
1096  * representation. Possibly we could do something better, but the
1097  * real answer to anyone who complains is "ANALYZE" ...
1098  */
1099  int tuple_width;
1100 
1101  tuple_width = MAXALIGN(baserel->reltarget->width) +
1103  ntuples = clamp_row_est((double) stat_buf.st_size /
1104  (double) tuple_width);
1105  }
1106  fdw_private->ntuples = ntuples;
1107 
1108  /*
1109  * Now estimate the number of rows returned by the scan after applying the
1110  * baserestrictinfo quals.
1111  */
1112  nrows = ntuples *
1114  baserel->baserestrictinfo,
1115  0,
1116  JOIN_INNER,
1117  NULL);
1118 
1119  nrows = clamp_row_est(nrows);
1120 
1121  /* Save the output-rows estimate for the planner */
1122  baserel->rows = nrows;
1123 }
1124 
1125 /*
1126  * Estimate costs of scanning a foreign table.
1127  *
1128  * Results are returned in *startup_cost and *total_cost.
1129  */
1130 static void
1132  FileFdwPlanState *fdw_private,
1133  Cost *startup_cost, Cost *total_cost)
1134 {
1135  BlockNumber pages = fdw_private->pages;
1136  double ntuples = fdw_private->ntuples;
1137  Cost run_cost = 0;
1138  Cost cpu_per_tuple;
1139 
1140  /*
1141  * We estimate costs almost the same way as cost_seqscan(), thus assuming
1142  * that I/O costs are equivalent to a regular table file of the same size.
1143  * However, we take per-tuple CPU costs as 10x of a seqscan, to account
1144  * for the cost of parsing records.
1145  *
1146  * In the case of a program source, this calculation is even more divorced
1147  * from reality, but we have no good alternative; and it's not clear that
1148  * the numbers we produce here matter much anyway, since there's only one
1149  * access path for the rel.
1150  */
1151  run_cost += seq_page_cost * pages;
1152 
1153  *startup_cost = baserel->baserestrictcost.startup;
1154  cpu_per_tuple = cpu_tuple_cost * 10 + baserel->baserestrictcost.per_tuple;
1155  run_cost += cpu_per_tuple * ntuples;
1156  *total_cost = *startup_cost + run_cost;
1157 }
1158 
1159 /*
1160  * file_acquire_sample_rows -- acquire a random sample of rows from the table
1161  *
1162  * Selected rows are returned in the caller-allocated array rows[],
1163  * which must have at least targrows entries.
1164  * The actual number of rows selected is returned as the function result.
1165  * We also count the total number of rows in the file and return it into
1166  * *totalrows. Rows skipped due to on_error = 'ignore' are not included
1167  * in this count. Note that *totaldeadrows is always set to 0.
1168  *
1169  * Note that the returned list of rows is not always in order by physical
1170  * position in the file. Therefore, correlation estimates derived later
1171  * may be meaningless, but it's OK because we don't use the estimates
1172  * currently (the planner only pays attention to correlation for indexscans).
1173  */
1174 static int
1176  HeapTuple *rows, int targrows,
1177  double *totalrows, double *totaldeadrows)
1178 {
1179  int numrows = 0;
1180  double rowstoskip = -1; /* -1 means not set yet */
1181  ReservoirStateData rstate;
1182  TupleDesc tupDesc;
1183  Datum *values;
1184  bool *nulls;
1185  bool found;
1186  char *filename;
1187  bool is_program;
1188  List *options;
1189  CopyFromState cstate;
1190  ErrorContextCallback errcallback;
1191  MemoryContext oldcontext = CurrentMemoryContext;
1192  MemoryContext tupcontext;
1193 
1194  Assert(onerel);
1195  Assert(targrows > 0);
1196 
1197  tupDesc = RelationGetDescr(onerel);
1198  values = (Datum *) palloc(tupDesc->natts * sizeof(Datum));
1199  nulls = (bool *) palloc(tupDesc->natts * sizeof(bool));
1200 
1201  /* Fetch options of foreign table */
1202  fileGetOptions(RelationGetRelid(onerel), &filename, &is_program, &options);
1203 
1204  /*
1205  * Create CopyState from FDW options.
1206  */
1207  cstate = BeginCopyFrom(NULL, onerel, NULL, filename, is_program, NULL, NIL,
1208  options);
1209 
1210  /*
1211  * Use per-tuple memory context to prevent leak of memory used to read
1212  * rows from the file with Copy routines.
1213  */
1215  "file_fdw temporary context",
1217 
1218  /* Prepare for sampling rows */
1219  reservoir_init_selection_state(&rstate, targrows);
1220 
1221  /* Set up callback to identify error line number. */
1222  errcallback.callback = CopyFromErrorCallback;
1223  errcallback.arg = (void *) cstate;
1224  errcallback.previous = error_context_stack;
1225  error_context_stack = &errcallback;
1226 
1227  *totalrows = 0;
1228  *totaldeadrows = 0;
1229  for (;;)
1230  {
1231  /* Check for user-requested abort or sleep */
1233 
1234  /* Fetch next row */
1235  MemoryContextReset(tupcontext);
1236  MemoryContextSwitchTo(tupcontext);
1237 
1238  found = NextCopyFrom(cstate, NULL, values, nulls);
1239 
1240  MemoryContextSwitchTo(oldcontext);
1241 
1242  if (!found)
1243  break;
1244 
1245  if (cstate->opts.on_error == COPY_ON_ERROR_IGNORE &&
1246  cstate->escontext->error_occurred)
1247  {
1248  /*
1249  * Soft error occurred, skip this tuple and just make
1250  * ErrorSaveContext ready for the next NextCopyFrom. Since we
1251  * don't set details_wanted and error_data is not to be filled,
1252  * just resetting error_occurred is enough.
1253  */
1254  cstate->escontext->error_occurred = false;
1255 
1256  /* Repeat NextCopyFrom() until no soft error occurs */
1257  continue;
1258  }
1259 
1260  /*
1261  * The first targrows sample rows are simply copied into the
1262  * reservoir. Then we start replacing tuples in the sample until we
1263  * reach the end of the relation. This algorithm is from Jeff Vitter's
1264  * paper (see more info in commands/analyze.c).
1265  */
1266  if (numrows < targrows)
1267  {
1268  rows[numrows++] = heap_form_tuple(tupDesc, values, nulls);
1269  }
1270  else
1271  {
1272  /*
1273  * t in Vitter's paper is the number of records already processed.
1274  * If we need to compute a new S value, we must use the
1275  * not-yet-incremented value of totalrows as t.
1276  */
1277  if (rowstoskip < 0)
1278  rowstoskip = reservoir_get_next_S(&rstate, *totalrows, targrows);
1279 
1280  if (rowstoskip <= 0)
1281  {
1282  /*
1283  * Found a suitable tuple, so save it, replacing one old tuple
1284  * at random
1285  */
1286  int k = (int) (targrows * sampler_random_fract(&rstate.randstate));
1287 
1288  Assert(k >= 0 && k < targrows);
1289  heap_freetuple(rows[k]);
1290  rows[k] = heap_form_tuple(tupDesc, values, nulls);
1291  }
1292 
1293  rowstoskip -= 1;
1294  }
1295 
1296  *totalrows += 1;
1297  }
1298 
1299  /* Remove error callback. */
1300  error_context_stack = errcallback.previous;
1301 
1302  /* Clean up. */
1303  MemoryContextDelete(tupcontext);
1304 
1305  if (cstate->opts.on_error == COPY_ON_ERROR_IGNORE &&
1306  cstate->num_errors > 0 &&
1308  ereport(NOTICE,
1309  errmsg_plural("%llu row was skipped due to data type incompatibility",
1310  "%llu rows were skipped due to data type incompatibility",
1311  (unsigned long long) cstate->num_errors,
1312  (unsigned long long) cstate->num_errors));
1313 
1314  EndCopyFrom(cstate);
1315 
1316  pfree(values);
1317  pfree(nulls);
1318 
1319  /*
1320  * Emit some interesting relation info
1321  */
1322  ereport(elevel,
1323  (errmsg("\"%s\": file contains %.0f rows; "
1324  "%d rows in sample",
1325  RelationGetRelationName(onerel),
1326  *totalrows, numrows)));
1327 
1328  return numrows;
1329 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5268
int16 AttrNumber
Definition: attnum.h:21
void ProcessCopyOptions(ParseState *pstate, CopyFormatOptions *opts_out, bool is_from, List *options)
Definition: copy.c:482
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
uint32 BlockNumber
Definition: block.h:31
static Datum values[MAXATTR]
Definition: bootstrap.c:150
#define NameStr(name)
Definition: c.h:737
#define MAXALIGN(LEN)
Definition: c.h:802
#define Assert(condition)
Definition: c.h:849
unsigned int Index
Definition: c.h:605
Selectivity clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo)
Definition: clausesel.c:100
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)
double cpu_tuple_cost
Definition: costsize.c:132
double seq_page_cost
Definition: costsize.c:130
double clamp_row_est(double nrows)
Definition: costsize.c:213
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:5896
bool defGetBoolean(DefElem *def)
Definition: define.c:107
char * defGetString(DefElem *def)
Definition: define.c:48
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1180
int errcode_for_file_access(void)
Definition: elog.c:876
int errdetail(const char *fmt,...)
Definition: elog.c:1203
ErrorContextCallback * error_context_stack
Definition: elog.c:94
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1639
EState * CreateExecutorState(void)
Definition: execUtils.c:88
#define ResetPerTupleExprContext(estate)
Definition: executor.h:570
#define GetPerTupleExprContext(estate)
Definition: executor.h:561
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:566
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:65
void ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
Definition: explain.c:5111
void ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value, ExplainState *es)
Definition: explain.c:5120
int(* AcquireSampleRowsFunc)(Relation relation, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
Definition: fdwapi.h:151
static ForeignScan * fileGetForeignPlan(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan)
Definition: file_fdw.c:603
static void fileEndForeignScan(ForeignScanState *node)
Definition: file_fdw.c:833
Datum file_fdw_handler(PG_FUNCTION_ARGS)
Definition: file_fdw.c:176
static bool check_selective_binary_conversion(RelOptInfo *baserel, Oid foreigntableid, List **columns)
Definition: file_fdw.c:925
static void fileGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
Definition: file_fdw.c:517
static void fileExplainForeignScan(ForeignScanState *node, ExplainState *es)
Definition: file_fdw.c:638
static List * get_file_fdw_attribute_options(Oid relid)
Definition: file_fdw.c:444
PG_MODULE_MAGIC
Definition: file_fdw.c:43
Datum file_fdw_validator(PG_FUNCTION_ARGS)
Definition: file_fdw.c:201
static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel, FileFdwPlanState *fdw_private, Cost *startup_cost, Cost *total_cost)
Definition: file_fdw.c:1131
static int file_acquire_sample_rows(Relation onerel, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
Definition: file_fdw.c:1175
PG_FUNCTION_INFO_V1(file_fdw_handler)
static const struct FileFdwOption valid_options[]
Definition: file_fdw.c:63
static bool fileAnalyzeForeignTable(Relation relation, AcquireSampleRowsFunc *func, BlockNumber *totalpages)
Definition: file_fdw.c:858
static void fileReScanForeignScan(ForeignScanState *node)
Definition: file_fdw.c:812
struct FileFdwExecutionState FileFdwExecutionState
static bool is_valid_option(const char *option, Oid context)
Definition: file_fdw.c:354
static bool fileIsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
Definition: file_fdw.c:909
static void fileGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid)
Definition: file_fdw.c:548
static void fileGetOptions(Oid foreigntableid, char **filename, bool *is_program, List **other_options)
Definition: file_fdw.c:373
static void estimate_size(PlannerInfo *root, RelOptInfo *baserel, FileFdwPlanState *fdw_private)
Definition: file_fdw.c:1050
static void fileBeginForeignScan(ForeignScanState *node, int eflags)
Definition: file_fdw.c:670
static TupleTableSlot * fileIterateForeignScan(ForeignScanState *node)
Definition: file_fdw.c:724
struct FileFdwPlanState FileFdwPlanState
#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
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:37
ForeignTable * GetForeignTable(Oid relid)
Definition: foreign.c:254
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition: foreign.c:292
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:111
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define SizeofHeapTupleHeader
Definition: htup_details.h:185
@ COPY_ON_ERROR_IGNORE
Definition: copy.h:40
@ COPY_LOG_VERBOSITY_DEFAULT
Definition: copy.h:49
struct parser_state match_state[5]
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
#define AccessShareLock
Definition: lockdefs.h:36
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:564
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
void * palloc(Size size)
Definition: mcxt.c:1317
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Oid GetUserId(void)
Definition: miscinit.c:514
double Cost
Definition: nodes.h:251
#define makeNode(_type_)
Definition: nodes.h:155
@ JOIN_INNER
Definition: nodes.h:293
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:461
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
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
static char format
static char * filename
Definition: pg_dumpall.c:119
#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 foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
#define list_make1(x1)
Definition: pg_list.h:212
static char ** options
#define plan(x)
Definition: pg_regress.c:162
uintptr_t Datum
Definition: postgres.h:64
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
tree context
Definition: radixtree.h:1835
MemoryContextSwitchTo(old_ctx)
tree ctl root
Definition: radixtree.h:1886
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetRelationName(relation)
Definition: rel.h:539
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1331
List * extract_actual_clauses(List *restrictinfo_list, bool pseudoconstant)
Definition: restrictinfo.c:494
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
char * defname
Definition: parsenodes.h:817
struct ErrorContextCallback * previous
Definition: elog.h:296
void(* callback)(void *arg)
Definition: elog.h:297
bool error_occurred
Definition: miscnodes.h:47
bool costs
Definition: explain.h:50
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
CopyFromState cstate
Definition: file_fdw.c:113
Oid optcontext
Definition: file_fdw.c:51
const char * optname
Definition: file_fdw.c:50
char * filename
Definition: file_fdw.c:96
double ntuples
Definition: file_fdw.c:101
BlockNumber pages
Definition: file_fdw.c:100
List * options
Definition: file_fdw.c:98
List * options
Definition: foreign.h:31
List * fdw_private
Definition: pathnodes.h:1882
ScanState ss
Definition: execnodes.h:2076
List * options
Definition: foreign.h:42
List * options
Definition: foreign.h:57
Oid serverid
Definition: foreign.h:56
Definition: pg_list.h:54
Definition: nodes.h:129
List * exprs
Definition: pathnodes.h:1542
Plan * plan
Definition: execnodes.h:1128
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47
List * baserestrictinfo
Definition: pathnodes.h:985
struct PathTarget * reltarget
Definition: pathnodes.h:893
Index relid
Definition: pathnodes.h:918
Cardinality tuples
Definition: pathnodes.h:949
BlockNumber pages
Definition: pathnodes.h:948
Relids lateral_relids
Definition: pathnodes.h:913
QualCost baserestrictcost
Definition: pathnodes.h:987
Cardinality rows
Definition: pathnodes.h:877
pg_prng_state randstate
Definition: sampling.h:49
Expr * clause
Definition: pathnodes.h:2574
Relation ss_currentRelation
Definition: execnodes.h:1576
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1578
PlanState ps
Definition: execnodes.h:1575
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
__int64 st_size
Definition: win32_port.h:273
#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
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
void vacuum_delay_point(void)
Definition: vacuum.c:2362
String * makeString(char *str)
Definition: value.c:63
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296
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
#define stat
Definition: win32_port.h:284