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-2025, 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"
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 */
63static 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 {"reject_limit", ForeignTableRelationId},
81 {"force_not_null", AttributeRelationId},
82 {"force_null", AttributeRelationId},
83
84 /*
85 * force_quote is not supported by file_fdw because it's for COPY TO.
86 */
87
88 /* Sentinel */
89 {NULL, InvalidOid}
90};
91
92/*
93 * FDW-specific information for RelOptInfo.fdw_private.
94 */
95typedef struct FileFdwPlanState
96{
97 char *filename; /* file or program to read from */
98 bool is_program; /* true if filename represents an OS command */
99 List *options; /* merged COPY options, excluding filename and
100 * is_program */
101 BlockNumber pages; /* estimate of file's physical size */
102 double ntuples; /* estimate of number of data rows */
104
105/*
106 * FDW-specific information for ForeignScanState.fdw_state.
107 */
109{
110 char *filename; /* file or program to read from */
111 bool is_program; /* true if filename represents an OS command */
112 List *options; /* merged COPY options, excluding filename and
113 * is_program */
114 CopyFromState cstate; /* COPY execution state */
116
117/*
118 * SQL functions
119 */
122
123/*
124 * FDW callback routines
125 */
127 RelOptInfo *baserel,
128 Oid foreigntableid);
130 RelOptInfo *baserel,
131 Oid foreigntableid);
133 RelOptInfo *baserel,
134 Oid foreigntableid,
135 ForeignPath *best_path,
136 List *tlist,
137 List *scan_clauses,
138 Plan *outer_plan);
140static void fileBeginForeignScan(ForeignScanState *node, int eflags);
142static void fileReScanForeignScan(ForeignScanState *node);
143static void fileEndForeignScan(ForeignScanState *node);
144static bool fileAnalyzeForeignTable(Relation relation,
146 BlockNumber *totalpages);
148 RangeTblEntry *rte);
149
150/*
151 * Helper functions
152 */
153static bool is_valid_option(const char *option, Oid context);
154static void fileGetOptions(Oid foreigntableid,
155 char **filename,
156 bool *is_program,
157 List **other_options);
160 Oid foreigntableid,
161 List **columns);
162static void estimate_size(PlannerInfo *root, RelOptInfo *baserel,
163 FileFdwPlanState *fdw_private);
164static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
165 FileFdwPlanState *fdw_private,
166 Cost *startup_cost, Cost *total_cost);
167static int file_acquire_sample_rows(Relation onerel, int elevel,
168 HeapTuple *rows, int targrows,
169 double *totalrows, double *totaldeadrows);
170
171
172/*
173 * Foreign-data wrapper handler function: return a struct with pointers
174 * to my callback routines.
175 */
176Datum
178{
179 FdwRoutine *fdwroutine = makeNode(FdwRoutine);
180
191
192 PG_RETURN_POINTER(fdwroutine);
193}
194
195/*
196 * Validate the generic options given to a FOREIGN DATA WRAPPER, SERVER,
197 * USER MAPPING or FOREIGN TABLE that uses file_fdw.
198 *
199 * Raise an ERROR if the option or its value is considered invalid.
200 */
201Datum
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}
349
350/*
351 * Check if the provided option is one of the valid options.
352 * context is the Oid of the catalog holding the object the option is for.
353 */
354static bool
355is_valid_option(const char *option, Oid context)
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}
366
367/*
368 * Fetch the options for a file_fdw foreign table.
369 *
370 * We have to separate out filename/program from the other options because
371 * those must not appear in the options list passed to the core COPY code.
372 */
373static void
374fileGetOptions(Oid foreigntableid,
375 char **filename, bool *is_program, List **other_options)
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}
435
436/*
437 * Retrieve per-column generic options from pg_attribute and construct a list
438 * of DefElems representing them.
439 *
440 * At the moment we only have "force_not_null", and "force_null",
441 * which should each be combined into a single DefElem listing all such
442 * columns, since that's what COPY expects.
443 */
444static List *
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}
512
513/*
514 * fileGetForeignRelSize
515 * Obtain relation size estimates for a foreign table
516 */
517static void
519 RelOptInfo *baserel,
520 Oid foreigntableid)
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}
539
540/*
541 * fileGetForeignPaths
542 * Create possible access paths for a scan on the foreign table
543 *
544 * Currently we don't support any push-down feature, so there is only one
545 * possible access path, which simply returns all records in the order in
546 * the data file.
547 */
548static void
550 RelOptInfo *baserel,
551 Oid foreigntableid)
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}
598
599/*
600 * fileGetForeignPlan
601 * Create a ForeignScan plan node for scanning the foreign table
602 */
603static ForeignScan *
605 RelOptInfo *baserel,
606 Oid foreigntableid,
607 ForeignPath *best_path,
608 List *tlist,
609 List *scan_clauses,
610 Plan *outer_plan)
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}
633
634/*
635 * fileExplainForeignScan
636 * Produce extra output for EXPLAIN
637 */
638static void
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}
665
666/*
667 * fileBeginForeignScan
668 * Initiate access to the file by creating CopyState
669 */
670static void
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}
718
719/*
720 * fileIterateForeignScan
721 * Read next record from the data file and store it into the
722 * ScanTupleSlot as a virtual tuple
723 */
724static TupleTableSlot *
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}
814
815/*
816 * fileReScanForeignScan
817 * Rescan table, possibly with new parameters
818 */
819static void
821{
823
824 EndCopyFrom(festate->cstate);
825
826 festate->cstate = BeginCopyFrom(NULL,
828 NULL,
829 festate->filename,
830 festate->is_program,
831 NULL,
832 NIL,
833 festate->options);
834}
835
836/*
837 * fileEndForeignScan
838 * Finish scanning foreign table and dispose objects used for this scan
839 */
840static void
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}
860
861/*
862 * fileAnalyzeForeignTable
863 * Test whether analyzing this foreign table is supported
864 */
865static bool
868 BlockNumber *totalpages)
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}
910
911/*
912 * fileIsForeignScanParallelSafe
913 * Reading a file, or external program, in a parallel worker should work
914 * just the same as reading it in the leader, so mark scans safe.
915 */
916static bool
918 RangeTblEntry *rte)
919{
920 return true;
921}
922
923/*
924 * check_selective_binary_conversion
925 *
926 * Check to see if it's useful to convert only a subset of the file's columns
927 * to binary. If so, construct a list of the column names to be converted,
928 * return that at *columns, and return true. (Note that it's possible to
929 * determine that no columns need be converted, for instance with a COUNT(*)
930 * query. So we can't use returning a NIL list to indicate failure.)
931 */
932static bool
934 Oid foreigntableid,
935 List **columns)
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}
1049
1050/*
1051 * Estimate size of a foreign table.
1052 *
1053 * The main result is returned in baserel->rows. We also set
1054 * fdw_private->pages and fdw_private->ntuples for later use in the cost
1055 * calculation.
1056 */
1057static void
1059 FileFdwPlanState *fdw_private)
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}
1132
1133/*
1134 * Estimate costs of scanning a foreign table.
1135 *
1136 * Results are returned in *startup_cost and *total_cost.
1137 */
1138static void
1140 FileFdwPlanState *fdw_private,
1141 Cost *startup_cost, Cost *total_cost)
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}
1166
1167/*
1168 * file_acquire_sample_rows -- acquire a random sample of rows from the table
1169 *
1170 * Selected rows are returned in the caller-allocated array rows[],
1171 * which must have at least targrows entries.
1172 * The actual number of rows selected is returned as the function result.
1173 * We also count the total number of rows in the file and return it into
1174 * *totalrows. Rows skipped due to on_error = 'ignore' are not included
1175 * in this count. Note that *totaldeadrows is always set to 0.
1176 *
1177 * Note that the returned list of rows is not always in order by physical
1178 * position in the file. Therefore, correlation estimates derived later
1179 * may be meaningless, but it's OK because we don't use the estimates
1180 * currently (the planner only pays attention to correlation for indexscans).
1181 */
1182static int
1184 HeapTuple *rows, int targrows,
1185 double *totalrows, double *totaldeadrows)
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 */
1240 vacuum_delay_point(true);
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}
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:496
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:151
#define NameStr(name)
Definition: c.h:703
#define MAXALIGN(LEN)
Definition: c.h:768
#define Assert(condition)
Definition: c.h:815
int64_t int64
Definition: c.h:485
unsigned int Index
Definition: c.h:571
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:1390
void EndCopyFrom(CopyFromState cstate)
Definition: copyfrom.c:1809
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:5899
char * defGetString(DefElem *def)
Definition: define.c:35
bool defGetBoolean(DefElem *def)
Definition: define.c:94
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: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 EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:65
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
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:604
static void fileEndForeignScan(ForeignScanState *node)
Definition: file_fdw.c:841
Datum file_fdw_handler(PG_FUNCTION_ARGS)
Definition: file_fdw.c:177
static bool check_selective_binary_conversion(RelOptInfo *baserel, Oid foreigntableid, List **columns)
Definition: file_fdw.c:933
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 List * get_file_fdw_attribute_options(Oid relid)
Definition: file_fdw.c:445
PG_MODULE_MAGIC
Definition: file_fdw.c:43
Datum file_fdw_validator(PG_FUNCTION_ARGS)
Definition: file_fdw.c:202
static void estimate_costs(PlannerInfo *root, RelOptInfo *baserel, FileFdwPlanState *fdw_private, Cost *startup_cost, Cost *total_cost)
Definition: file_fdw.c:1139
static int file_acquire_sample_rows(Relation onerel, int elevel, HeapTuple *rows, int targrows, double *totalrows, double *totaldeadrows)
Definition: file_fdw.c:1183
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:866
static void fileReScanForeignScan(ForeignScanState *node)
Definition: file_fdw.c:820
struct FileFdwExecutionState FileFdwExecutionState
static bool is_valid_option(const char *option, Oid context)
Definition: file_fdw.c:355
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 fileGetOptions(Oid foreigntableid, char **filename, bool *is_program, List **other_options)
Definition: file_fdw.c:374
static void estimate_size(PlannerInfo *root, RelOptInfo *baserel, FileFdwPlanState *fdw_private)
Definition: file_fdw.c:1058
static void fileBeginForeignScan(ForeignScanState *node, int eflags)
Definition: file_fdw.c:671
static TupleTableSlot * fileIterateForeignScan(ForeignScanState *node)
Definition: file_fdw.c:725
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
ForeignServer * GetForeignServer(Oid serverid)
Definition: foreign.c:111
List * GetForeignColumnOptions(Oid relid, AttrNumber attnum)
Definition: foreign.c:292
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
#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:72
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
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:590
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
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
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Oid GetUserId(void)
Definition: miscinit.c:517
double Cost
Definition: nodes.h:251
#define makeNode(_type_)
Definition: nodes.h:155
@ JOIN_INNER
Definition: nodes.h:293
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
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
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
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:161
uintptr_t Datum
Definition: postgres.h:69
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
tree ctl root
Definition: radixtree.h:1857
#define RelationGetRelid(relation)
Definition: rel.h:512
#define RelationGetDescr(relation)
Definition: rel.h:538
#define RelationGetRelationName(relation)
Definition: rel.h:546
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1350
List * extract_actual_clauses(List *restrictinfo_list, bool pseudoconstant)
Definition: restrictinfo.c:485
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
int64 reject_limit
Definition: copy.h:88
CopyFormatOptions opts
ErrorSaveContext * escontext
char * defname
Definition: parsenodes.h:826
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:114
Oid optcontext
Definition: file_fdw.c:51
const char * optname
Definition: file_fdw.c:50
char * filename
Definition: file_fdw.c:97
double ntuples
Definition: file_fdw.c:102
BlockNumber pages
Definition: file_fdw.c:101
List * options
Definition: file_fdw.c:99
List * options
Definition: foreign.h:31
List * fdw_private
Definition: pathnodes.h:1903
ScanState ss
Definition: execnodes.h:2102
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:1563
Plan * plan
Definition: execnodes.h:1150
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47
List * baserestrictinfo
Definition: pathnodes.h:1004
struct PathTarget * reltarget
Definition: pathnodes.h:912
Index relid
Definition: pathnodes.h:937
Cardinality tuples
Definition: pathnodes.h:968
BlockNumber pages
Definition: pathnodes.h:967
Relids lateral_relids
Definition: pathnodes.h:932
QualCost baserestrictcost
Definition: pathnodes.h:1006
Cardinality rows
Definition: pathnodes.h:896
pg_prng_state randstate
Definition: sampling.h:49
Expr * clause
Definition: pathnodes.h:2594
Relation ss_currentRelation
Definition: execnodes.h:1604
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1606
PlanState ps
Definition: execnodes.h:1603
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
__int64 st_size
Definition: win32_port.h:263
#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:154
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
void vacuum_delay_point(bool is_analyze)
Definition: vacuum.c:2387
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:274