1/*-------------------------------------------------------------------------
4 * COPY <table> TO file/program/client
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/commands/copyto.c
13 *-------------------------------------------------------------------------
40 * Represents the different dest cases we need to worry about at
51 * This struct contains all the state variables used throughout a COPY TO
54 * Multi-byte encodings: all supported client-side encodings encode multi-byte
55 * characters by having the first byte's high bit set. Subsequent bytes of the
56 * character can have the high bit not set. When scanning data in such an
57 * encoding to look for a match to a single-byte (ie ASCII) character, we must
58 * use the full pg_encoding_mblen() machinery to skip over multibyte
59 * characters, else we might find a false match to a trailing byte. In
60 * supported server encodings, there is no possibility of a false match, and
61 * it's faster to make useless comparisons to trailing bytes than it is to
62 * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
63 * when we have to do it the hard way.
67 /* format-specific routines */
70 /* low-level state data */
72 FILE *
copy_file;
/* used if copy_dest == COPY_FILE */
79 /* parameters from the COPY command */
83 char *
filename;
/* filename, or NULL for STDOUT */
100/* DestReceiver for COPY (query) TO */
108/* NOTE: there's a copy of this in copyfromparse.c */
112/* non-export function prototypes */
120/* built-in format-specific routines */
133/* Low-level communications functions */
145 * COPY TO routines for built-in formats.
147 * CSV and text formats share the same TextLike routines except for the
175/* Return a COPY TO routine for the given options */
181 else if (
opts->binary)
184 /* default is text */
188/* Implementation of the start callback for text and CSV formats */
193 * For non-binary copy, we need to convert null_print to file encoding,
194 * because it will be sent directly with CopySendString.
201 /* if a header has been requested send the line */
205 bool hdr_delim =
false;
229 * Implementation of the outfunc callback for text and CSV formats. Assign
230 * the output function data to the given *finfo.
238 /* Set output function for an attribute */
243/* Implementation of the per-row callback for text format */
250/* Implementation of the per-row callback for CSV format */
258 * Workhorse for CopyToTextOneRow() and CopyToCSVOneRow().
260 * We use pg_attribute_always_inline to reduce function call overhead
261 * and to help compilers to optimize away the 'is_csv' condition.
268 bool need_delim =
false;
302/* Implementation of the end callback for text and CSV formats */
306 /* Nothing to do here */
310 * Implementation of the start callback for binary format. Send a header
323 /* No header extension */
329 * Implementation of the outfunc callback for binary format. Assign
330 * the binary output function to the given *finfo.
338 /* Set output function for an attribute */
343/* Implementation of the per-row callback for binary format */
349 /* Binary per-tuple header */
376/* Implementation of the end callback for binary format */
380 /* Generate trailer for a binary copy */
382 /* Need to flush out the trailer */
387 * Send copy start/stop messages for frontend copies. These have changed
388 * in past protocol redesigns.
401 for (
i = 0;
i < natts;
i++)
410 /* Shouldn't have any unsent data */
412 /* Send Copy Done message */
417 * CopySendData sends output data to the destination (file or frontend)
418 * CopySendString does the same for null-terminated strings
419 * CopySendChar does the same for single characters
420 * CopySendEndOfRow does the appropriate thing at end of each data row
421 * (data is not actually flushed except by CopySendEndOfRow)
423 * NB: no data conversion is applied by these functions
452 if (fwrite(fe_msgbuf->
data, fe_msgbuf->
len, 1,
461 * The pipe will be closed automatically on error at
462 * the end of transaction, but we might get a better
463 * error message from the subprocess' exit code than
469 * If ClosePipeToProgram() didn't throw an error, the
470 * program terminated normally, but closed the pipe
471 * first. Restore errno, and throw an error.
477 errmsg(
"could not write to COPY program: %m")));
482 errmsg(
"could not write to COPY file: %m")));
486 /* Dump the accumulated row as one CopyData message */
494 /* Update the progress */
502 * Wrapper function of CopySendEndOfRow for text and CSV formats. Sends the
503 * line termination and do common appropriate things for the end of row.
511 /* Default line termination depends on platform */
519 /* The FE/BE protocol uses \n as newline for all platforms */
526 /* Now take the actions related to the end of a row */
531 * These functions do apply some data conversion
535 * CopySendInt32 sends an int32 in network byte order
547 * CopySendInt16 sends an int16 in network byte order
559 * Closes the pipe to an external program, checking the pclose() return code.
572 errmsg(
"could not close pipe to external command: %m")));
573 else if (pclose_rc != 0)
576 (
errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
577 errmsg(
"program \"%s\" failed",
584 * Release resources allocated in a cstate for COPY TO/FROM.
598 errmsg(
"could not close file \"%s\": %m",
609 * Setup CopyToState to read tuples from a table or a query for COPY TO.
611 * 'rel': Relation to be copied
612 * 'raw_query': Query whose results are to be copied
613 * 'queryRelId': OID of base relation to convert to a query (for RLS)
614 * 'filename': Name of server-local file to write, NULL for STDOUT
615 * 'is_program': true if 'filename' is program to execute
616 * 'data_dest_cb': Callback that processes the output data
617 * 'attnamelist': List of char *, columns to include. NIL selects all cols.
618 * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
620 * Returns a CopyToState, to be passed to DoCopyTo() and related functions.
634 bool pipe = (
filename == NULL && data_dest_cb == NULL);
638 const int progress_cols[] = {
642 int64 progress_vals[] = {
647 if (rel != NULL && rel->
rd_rel->relkind != RELKIND_RELATION)
649 if (rel->
rd_rel->relkind == RELKIND_VIEW)
651 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
652 errmsg(
"cannot copy from view \"%s\"",
654 errhint(
"Try the COPY (SELECT ...) TO variant.")));
655 else if (rel->
rd_rel->relkind == RELKIND_MATVIEW)
659 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
660 errmsg(
"cannot copy from unpopulated materialized view \"%s\"",
662 errhint(
"Use the REFRESH MATERIALIZED VIEW command."));
664 else if (rel->
rd_rel->relkind == RELKIND_FOREIGN_TABLE)
666 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
667 errmsg(
"cannot copy from foreign table \"%s\"",
669 errhint(
"Try the COPY (SELECT ...) TO variant.")));
670 else if (rel->
rd_rel->relkind == RELKIND_SEQUENCE)
672 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
673 errmsg(
"cannot copy from sequence \"%s\"",
675 else if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
677 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
678 errmsg(
"cannot copy from partitioned table \"%s\"",
680 errhint(
"Try the COPY (SELECT ...) TO variant.")));
683 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
684 errmsg(
"cannot copy from non-table relation \"%s\"",
689 /* Allocate workspace and zero all fields */
693 * We allocate everything used by a cstate in a new memory context. This
694 * avoids memory leaks during repeated use of COPY in a query.
702 /* Extract options from the statement node tree */
705 /* Set format routine */
708 /* Process the source/target relation or query */
727 * Run parse analysis and rewrite. Note this also acquires sufficient
728 * locks on the source table(s).
734 /* check that we got back something we can work with */
735 if (rewritten ==
NIL)
738 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
739 errmsg(
"DO INSTEAD NOTHING rules are not supported for COPY")));
745 /* examine queries to determine which error message to issue */
746 foreach(lc, rewritten)
752 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
753 errmsg(
"conditional DO INSTEAD rules are not supported for COPY")));
756 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
757 errmsg(
"DO ALSO rules are not supported for COPY")));
761 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
762 errmsg(
"multi-statement DO INSTEAD rules are not supported for COPY")));
767 /* The grammar allows SELECT INTO, but we don't support that */
771 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
772 errmsg(
"COPY (SELECT INTO) is not supported")));
774 /* The only other utility command we could see is NOTIFY */
777 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
778 errmsg(
"COPY query must not be a utility command")));
781 * Similarly the grammar doesn't enforce the presence of a RETURNING
782 * clause, but this is required here.
793 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
794 errmsg(
"COPY query must have a RETURNING clause")));
802 * With row-level security and a user using "COPY relation TO", we
803 * have to convert the "COPY relation TO" to a query-based COPY (eg:
804 * "COPY (SELECT * FROM ONLY relation) TO"), to allow the rewriter to
805 * add in any RLS clauses.
807 * When this happens, we are passed in the relid of the originally
808 * found relation (which we have locked). As the planner will look up
809 * the relation again, we double-check here to make sure it found the
810 * same one that we have locked.
815 * Note that with RLS involved there may be multiple relations,
816 * and while the one we need is almost certainly first, we don't
817 * make any guarantees of that in the planner, so check the whole
818 * list and make sure we find the original relation.
822 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
823 errmsg(
"relation referenced by COPY statement has changed")));
827 * Use a snapshot with an updated command ID to ensure this query sees
828 * results of any previously executed queries.
833 /* Create dest receiver for COPY OUT */
837 /* Create a QueryDesc requesting no output */
841 dest, NULL, NULL, 0);
844 * Call ExecutorStart to prepare the plan for execution.
846 * ExecutorStart computes a result tupdesc for us
853 /* Generate or convert list of attributes to process */
856 num_phys_attrs = tupDesc->
natts;
858 /* Convert FORCE_QUOTE name list to per-column flags, check validity */
871 foreach(
cur, attnums)
878 (
errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
879 /*- translator: %s is the name of a COPY option, e.g. FORCE_NOT_NULL */
880 errmsg(
"%s column \"%s\" not referenced by COPY",
881 "FORCE_QUOTE",
NameStr(attr->attname))));
886 /* Use client encoding when ENCODING option is not specified. */
893 * Set up encoding conversion info if the file and server encodings differ
894 * (see also pg_server_to_any).
902 /* See Multibyte encoding comment above */
917 Assert(!is_program);
/* the grammar does not allow this */
933 errmsg(
"could not execute command \"%s\": %m",
938 mode_t oumask;
/* Pre-existing umask value */
944 * Prevent write to relative path ... too easy to shoot oneself in
945 * the foot by overwriting a database file ...
949 (
errcode(ERRCODE_INVALID_NAME),
950 errmsg(
"relative path not allowed for COPY to file")));
964 /* copy errno because ereport subfunctions might change it */
965 int save_errno = errno;
969 errmsg(
"could not open file \"%s\" for writing: %m",
971 (save_errno == ENOENT || save_errno == EACCES) ?
972 errhint(
"COPY TO instructs the PostgreSQL server process to write a file. "
973 "You may want a client-side facility such as psql's \\copy.") : 0));
979 errmsg(
"could not stat file \"%s\": %m",
984 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
989 /* initialize progress */
1002 * Clean up storage and release resources for COPY TO.
1009 /* Close down the query and free resources. */
1016 /* Clean up storage */
1021 * Copy from relation or query TO file.
1023 * Returns the number of rows processed.
1042 num_phys_attrs = tupDesc->
natts;
1045 /* We use fe_msgbuf as a per-row buffer regardless of copy_dest */
1048 /* Get info about the columns we need to process. */
1060 * Create a temporary memory context that we can reset once per row to
1061 * recover palloc'd memory. This avoids any problems with leaks inside
1062 * datatype output routines, and should be faster than retail pfree's
1063 * anyway. (We don't need a whole econtext as CopyFrom does.)
1084 /* Deconstruct the tuple ... */
1087 /* Format and send the data */
1091 * Increment the number of processed tuples, and report the
1103 /* run the plan --- the dest receiver will send tuples */
1119 * Emit one row during DoCopyTo().
1129 /* Make sure the tuple is fully deconstructed */
1138 * Send text representation of one attribute, with conversion and escaping
1140 #define DUMPSOFAR() \
1143 CopySendData(cstate, start, ptr - start); \
1160 * We have to grovel through the string searching for control characters
1161 * and instances of the delimiter character. In most cases, though, these
1162 * are infrequent. To avoid overhead from calling CopySendData once per
1163 * character, we dump out all characters between escaped characters in a
1164 * single call. The loop invariant is that the data from "start" to "ptr"
1165 * can be sent literally, but hasn't yet been.
1167 * We can skip pg_encoding_mblen() overhead when encoding is safe, because
1168 * in valid backend encodings, extra bytes of a multibyte character never
1169 * look like ASCII. This loop is sufficiently performance-critical that
1170 * it's worth making two copies of it to get the IS_HIGHBIT_SET() test out
1171 * of the normal safe-encoding path.
1176 while ((
c = *ptr) !=
'0円')
1178 if ((
unsigned char)
c < (
unsigned char) 0x20)
1181 * \r and \n must be escaped, the others are traditional. We
1182 * prefer to dump these using the C-like notation, rather than
1183 * a backslash and the literal character, because it makes the
1184 * dump file a bit more proof against Microsoftish data
1208 /* If it's the delimiter, must backslash it */
1211 /* All ASCII control chars are length 1 */
1213 continue;
/* fall to end of loop */
1215 /* if we get here, we need to convert the control char */
1219 start = ++ptr;
/* do not include char in next run */
1221 else if (
c ==
'\\' ||
c == delimc)
1225 start = ptr++;
/* we include char in next run */
1236 while ((
c = *ptr) !=
'0円')
1238 if ((
unsigned char)
c < (
unsigned char) 0x20)
1241 * \r and \n must be escaped, the others are traditional. We
1242 * prefer to dump these using the C-like notation, rather than
1243 * a backslash and the literal character, because it makes the
1244 * dump file a bit more proof against Microsoftish data
1268 /* If it's the delimiter, must backslash it */
1271 /* All ASCII control chars are length 1 */
1273 continue;
/* fall to end of loop */
1275 /* if we get here, we need to convert the control char */
1279 start = ++ptr;
/* do not include char in next run */
1281 else if (
c ==
'\\' ||
c == delimc)
1285 start = ptr++;
/* we include char in next run */
1296 * Send text representation of one attribute, with conversion and
1297 * CSV-style escaping
1311 /* force quoting if it matches null_print (before conversion!) */
1321 * Make a preliminary pass to discover if it needs quoting
1326 * Quote '\.' if it appears alone on a line, so that it will not be
1327 * interpreted as an end-of-data marker. (PG 18 and up will not
1328 * interpret '\.' in CSV that way, except in embedded-in-SQL data; but
1329 * we want the data to be loadable by older versions too. Also, this
1330 * avoids breaking clients that are still using PQgetline().)
1332 if (single_attr && strcmp(ptr,
"\\.") == 0)
1336 const char *tptr = ptr;
1338 while ((
c = *tptr) !=
'0円')
1340 if (
c == delimc ||
c == quotec ||
c ==
'\n' ||
c ==
'\r')
1358 * We adopt the same optimization strategy as in CopyAttributeOutText
1361 while ((
c = *ptr) !=
'0円')
1363 if (
c == quotec ||
c == escapec)
1367 start = ptr;
/* we include char in next run */
1380 /* If it doesn't need quoting, we can just dump it as-is */
1386 * copy_dest_startup --- executor startup
1395 * copy_dest_receive --- receive one tuple
1406 /* Increment the number of processed tuples, and report the progress */
1414 * copy_dest_shutdown --- executor end
1423 * copy_dest_destroy --- release DestReceiver object
1432 * CreateCopyDestReceiver -- create a suitable DestReceiver object
1445 self->
cstate = NULL;
/* will be set later */
List * CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
void ProcessCopyOptions(ParseState *pstate, CopyFormatOptions *opts_out, bool is_from, List *options)
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
void pgstat_progress_end_command(void)
#define IS_HIGHBIT_SET(ch)
#define pg_attribute_always_inline
#define MemSet(start, val, len)
static void CopyToBinaryOutFunc(CopyToState cstate, Oid atttypid, FmgrInfo *finfo)
static void CopyToBinaryOneRow(CopyToState cstate, TupleTableSlot *slot)
static void CopySendInt32(CopyToState cstate, int32 val)
static void ClosePipeToProgram(CopyToState cstate)
static const CopyToRoutine CopyToRoutineCSV
static bool copy_dest_receive(TupleTableSlot *slot, DestReceiver *self)
static void CopyAttributeOutCSV(CopyToState cstate, const char *string, bool use_quote)
uint64 DoCopyTo(CopyToState cstate)
static void CopyToTextLikeEnd(CopyToState cstate)
static void CopyAttributeOutText(CopyToState cstate, const char *string)
struct CopyToStateData CopyToStateData
static const CopyToRoutine CopyToRoutineText
static void CopySendInt16(CopyToState cstate, int16 val)
static void CopySendData(CopyToState cstate, const void *databuf, int datasize)
static void CopyToTextOneRow(CopyToState cstate, TupleTableSlot *slot)
static void CopySendChar(CopyToState cstate, char c)
DestReceiver * CreateCopyDestReceiver(void)
static const CopyToRoutine * CopyToGetRoutine(const CopyFormatOptions *opts)
static void CopySendTextLikeEndOfRow(CopyToState cstate)
static void EndCopy(CopyToState cstate)
static void copy_dest_destroy(DestReceiver *self)
static void CopyToTextLikeOutFunc(CopyToState cstate, Oid atttypid, FmgrInfo *finfo)
CopyToState BeginCopyTo(ParseState *pstate, Relation rel, RawStmt *raw_query, Oid queryRelId, const char *filename, bool is_program, copy_data_dest_cb data_dest_cb, List *attnamelist, List *options)
static void copy_dest_shutdown(DestReceiver *self)
static void copy_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
static void CopyToTextLikeStart(CopyToState cstate, TupleDesc tupDesc)
static void SendCopyBegin(CopyToState cstate)
static void SendCopyEnd(CopyToState cstate)
static void CopySendEndOfRow(CopyToState cstate)
static void CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
static void CopyToTextLikeOneRow(CopyToState cstate, TupleTableSlot *slot, bool is_csv)
static void CopySendString(CopyToState cstate, const char *str)
static void CopyToCSVOneRow(CopyToState cstate, TupleTableSlot *slot)
static const char BinarySignature[11]
void EndCopyTo(CopyToState cstate)
static void CopyToBinaryStart(CopyToState cstate, TupleDesc tupDesc)
static const CopyToRoutine CopyToRoutineBinary
static void CopyToBinaryEnd(CopyToState cstate)
DestReceiver * CreateDestReceiver(CommandDest dest)
int errdetail_internal(const char *fmt,...)
int errcode_for_file_access(void)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void ExecutorEnd(QueryDesc *queryDesc)
void ExecutorFinish(QueryDesc *queryDesc)
void ExecutorStart(QueryDesc *queryDesc, int eflags)
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
FILE * OpenPipeStream(const char *command, const char *mode)
int ClosePipeStream(FILE *file)
FILE * AllocateFile(const char *name, const char *mode)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Assert(PointerIsAligned(start, uint64))
void(* copy_data_dest_cb)(void *data, int len)
#define pq_putmessage(msgtype, s, len)
bool list_member_int(const List *list, int datum)
bool list_member_oid(const List *list, Oid datum)
void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
int GetDatabaseEncoding(void)
int pg_get_client_encoding(void)
char * pg_server_to_any(const char *s, int len, int encoding)
void MemoryContextReset(MemoryContext context)
char * pstrdup(const char *in)
void pfree(void *pointer)
void * palloc0(Size size)
MemoryContext CurrentMemoryContext
void MemoryContextDelete(MemoryContext context)
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define CHECK_FOR_INTERRUPTS()
#define IsA(nodeptr, _type_)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
#define CURSOR_OPT_PARALLEL_OK
static AmcheckOptions opts
FormData_pg_attribute * Form_pg_attribute
#define lfirst_node(type, lc)
static int list_length(const List *l)
#define linitial_node(type, l)
#define foreach_int(var, lst)
#define PG_ENCODING_IS_CLIENT_ONLY(_enc)
#define is_absolute_path(filename)
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
CommandDest whereToSendOutput
List * pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char *query_string, const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
void FreeQueryDesc(QueryDesc *qdesc)
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
#define PROGRESS_COPY_COMMAND
#define PROGRESS_COPY_TYPE_FILE
#define PROGRESS_COPY_BYTES_PROCESSED
#define PROGRESS_COPY_COMMAND_TO
#define PROGRESS_COPY_TUPLES_PROCESSED
#define PROGRESS_COPY_TYPE
#define PROGRESS_COPY_TYPE_PROGRAM
#define PROGRESS_COPY_TYPE_CALLBACK
#define PROGRESS_COPY_TYPE_PIPE
#define PqMsg_CopyOutResponse
#define RelationGetRelid(relation)
#define RelationGetDescr(relation)
#define RelationGetRelationName(relation)
#define RelationIsPopulated(relation)
void UpdateActiveSnapshotCommandId(void)
void PopActiveSnapshot(void)
void PushCopiedSnapshot(Snapshot snapshot)
Snapshot GetActiveSnapshot(void)
StringInfo makeStringInfo(void)
void resetStringInfo(StringInfo str)
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
#define appendStringInfoCharMacro(str, ch)
void(* CopyToOutFunc)(CopyToState cstate, Oid atttypid, FmgrInfo *finfo)
void(* CopyToOneRow)(CopyToState cstate, TupleTableSlot *slot)
void(* CopyToEnd)(CopyToState cstate)
void(* CopyToStart)(CopyToState cstate, TupleDesc tupDesc)
MemoryContext copycontext
const CopyToRoutine * routine
copy_data_dest_cb data_dest_cb
bool encoding_embeds_ascii
const char * p_sourcetext
void(* rStartup)(DestReceiver *self, int operation, TupleDesc typeinfo)
void(* rShutdown)(DestReceiver *self)
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
void(* rDestroy)(DestReceiver *self)
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
static void table_endscan(TableScanDesc scan)
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, ScanKeyData *key)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
static void slot_getallattrs(TupleTableSlot *slot)
static Size VARSIZE(const void *PTR)
static char * VARDATA(const void *PTR)
char * wait_result_to_str(int exitstatus)
int pg_encoding_mblen(int encoding, const char *mbstr)