1/*-------------------------------------------------------------------------
4 * Implements the COPY utility command
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/copy.c
13 *-------------------------------------------------------------------------
43 * DoCopy executes the SQL COPY statement
45 * Either unload or reload contents of table <relation>, depending on <from>.
46 * (<from> = true means we are inserting into the table.) In the "TO" case
47 * we also support copying the output of an arbitrary SELECT, INSERT, UPDATE
50 * If <pipe> is false, transfer is between the table and the file named
51 * <filename>. Otherwise, transfer is between the table and our regular
52 * input/output stream. The latter could be either stdin/stdout or a
53 * socket, depending on whether we're running under Postmaster control.
55 * Do not allow a Postgres user without the 'pg_read_server_files' or
56 * 'pg_write_server_files' role to read from or write to a file.
58 * Do not allow the copy if user doesn't have proper permission to access
59 * the table or the specifically requested columns.
63 int stmt_location,
int stmt_len,
66 bool is_from =
stmt->is_from;
67 bool pipe = (
stmt->filename == NULL);
71 Node *whereClause = NULL;
74 * Disallow COPY to/from file or program except to users with the
83 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
84 errmsg(
"permission denied to COPY to or from an external program"),
85 errdetail(
"Only roles with privileges of the \"%s\" role may COPY to or from an external program.",
86 "pg_execute_server_program"),
87 errhint(
"Anyone can COPY to stdout or from stdin. "
88 "psql's \\copy command also works for anyone.")));
94 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
95 errmsg(
"permission denied to COPY from a file"),
96 errdetail(
"Only roles with privileges of the \"%s\" role may COPY from a file.",
97 "pg_read_server_files"),
98 errhint(
"Anyone can COPY to stdout or from stdin. "
99 "psql's \\copy command also works for anyone.")));
103 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
104 errmsg(
"permission denied to COPY to a file"),
105 errdetail(
"Only roles with privileges of the \"%s\" role may COPY to a file.",
106 "pg_write_server_files"),
107 errhint(
"Anyone can COPY to stdout or from stdin. "
108 "psql's \\copy command also works for anyone.")));
123 /* Open and lock the relation, using the appropriate lock type. */
134 if (
stmt->whereClause)
136 /* add nsitem to query namespace */
139 /* Transform the raw expression tree */
142 /* Make sure it yields a boolean result. */
145 /* we have to fix its collations too */
156 foreach(
cur, attnums)
169 * Permission check for row security policies.
171 * check_enable_rls will ereport(ERROR) if the user has requested
172 * something invalid and will otherwise indicate if we should enable
173 * RLS (returns RLS_ENABLED) or not for this COPY statement.
175 * If the relation has a row security policy and we are to apply it
176 * then perform a "query" copy and allow the normal query processing
177 * to handle the policies.
179 * If RLS is not enabled for this, then just fall through to the
180 * normal non-filtering relation handling.
192 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
193 errmsg(
"COPY FROM not supported with row-level security"),
194 errhint(
"Use INSERT statements instead.")));
199 * If no columns are specified in the attribute list of the COPY
200 * command, then the target list is 'all' columns. Therefore, '*'
201 * should be used as the target list for the resulting SELECT
204 * In the case that columns are specified in the attribute list,
205 * create a ColumnRef and ResTarget for each column and add them
206 * to the target list for the resulting SELECT statement.
226 foreach(lc,
stmt->attlist)
229 * Build the ColumnRef for each column. The ColumnRef
230 * 'fields' property is a String node that corresponds to
231 * the column name respectively.
237 /* Build the ResTarget and add the ColumnRef to it. */
244 /* Add each column to the SELECT statement's target list */
245 targetList =
lappend(targetList, target);
250 * Build RangeVar for from clause, fully qualified based on the
251 * relation which we have opened and locked. Use "ONLY" so that
252 * COPY retrieves rows from only the target table not any
253 * inheritance children, the same as when RLS doesn't apply.
258 from->
inh =
false;
/* apply ONLY */
262 select->targetList = targetList;
271 * Close the relation for now, but keep the lock on it to prevent
272 * changes between now and when we start the query-based COPY.
274 * We'll reopen it later as part of the query-based COPY.
299 /* check read-only transaction and parallel mode */
305 NULL,
stmt->attlist,
stmt->options);
306 *processed =
CopyFrom(cstate);
/* copy from file to database */
315 NULL,
stmt->attlist,
stmt->options);
316 *processed =
DoCopyTo(cstate);
/* copy from database to file */
325 * Extract the CopyFormatOptions.header_line value from a DefElem.
327 * Parses the HEADER option for COPY, which can be a boolean, a non-negative
328 * integer (number of lines to skip), or the special value "match".
334 * If no parameter value given, assume "true" is meant.
336 if (def->
arg == NULL)
340 * Allow 0, 1, "true", "false", "on", "off", a non-negative integer, or
351 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
352 errmsg(
"a negative integer value cannot be "
353 "specified for %s", def->
defname)));
355 if (!is_from && ival > 1)
357 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
358 errmsg(
"cannot use multi-line header in COPY TO")));
368 * The set of strings accepted here should match up with the
369 * grammar's opt_boolean_or_string production.
383 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
384 errmsg(
"cannot use \"%s\" with HEADER in COPY TO",
392 (
errcode(ERRCODE_SYNTAX_ERROR),
393 errmsg(
"%s requires a Boolean value, a non-negative integer, "
394 "or the string \"match\"",
400 * Extract a CopyOnErrorChoice value from a DefElem.
409 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
410 /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
411 second %s is a COPY with direction, e.g. COPY TO */
412 errmsg(
"COPY %s cannot be used with %s",
"ON_ERROR",
"COPY TO"),
416 * Allow "stop", or "ignore" values.
424 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
425 /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR */
426 errmsg(
"COPY %s \"%s\" not recognized",
"ON_ERROR", sval),
432 * Extract REJECT_LIMIT value from a DefElem.
434 * REJECT_LIMIT can be specified in two ways: as an int64 for the COPY command
435 * option or as a single-quoted string for the foreign table option using
436 * file_fdw. Therefore this function needs to handle both formats.
443 if (def->
arg == NULL)
445 (
errcode(ERRCODE_SYNTAX_ERROR),
446 errmsg(
"%s requires a numeric value",
453 if (reject_limit <= 0)
455 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
456 errmsg(
"REJECT_LIMIT (%" PRId64
") must be greater than zero",
463 * Extract a CopyLogVerbosityChoice value from a DefElem.
471 * Allow "silent", "default", or "verbose" values.
482 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
483 /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR */
484 errmsg(
"COPY %s \"%s\" not recognized",
"LOG_VERBOSITY", sval),
490 * Process the statement option list for COPY.
492 * Scan the options list (a list of DefElem) and transpose the information
493 * into *opts_out, applying appropriate error checking.
495 * If 'opts_out' is not NULL, it is assumed to be filled with zeroes initially.
497 * This is exported so that external users of the COPY API can sanity-check
498 * a list of options. In that usage, 'opts_out' can be passed as NULL and
499 * the collected data is just leaked until CurrentMemoryContext is reset.
501 * Note that additional checking, such as whether column names listed in FORCE
502 * QUOTE actually exist, has to be applied later. This just checks for
503 * self-consistency of the options list.
511 bool format_specified =
false;
512 bool freeze_specified =
false;
513 bool header_specified =
false;
514 bool on_error_specified =
false;
515 bool log_verbosity_specified =
false;
516 bool reject_limit_specified =
false;
519 /* Support external use for option sanity checking */
520 if (opts_out == NULL)
525 /* Extract options from the statement node tree */
530 if (strcmp(defel->
defname,
"format") == 0)
534 if (format_specified)
536 format_specified =
true;
537 if (strcmp(fmt,
"text") == 0)
538 /* default format */ ;
539 else if (strcmp(fmt,
"csv") == 0)
541 else if (strcmp(fmt,
"binary") == 0)
545 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
546 errmsg(
"COPY format \"%s\" not recognized", fmt),
549 else if (strcmp(defel->
defname,
"freeze") == 0)
551 if (freeze_specified)
553 freeze_specified =
true;
556 else if (strcmp(defel->
defname,
"delimiter") == 0)
562 else if (strcmp(defel->
defname,
"null") == 0)
568 else if (strcmp(defel->
defname,
"default") == 0)
574 else if (strcmp(defel->
defname,
"header") == 0)
576 if (header_specified)
578 header_specified =
true;
581 else if (strcmp(defel->
defname,
"quote") == 0)
587 else if (strcmp(defel->
defname,
"escape") == 0)
593 else if (strcmp(defel->
defname,
"force_quote") == 0)
603 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
604 errmsg(
"argument to option \"%s\" must be a list of column names",
608 else if (strcmp(defel->
defname,
"force_not_null") == 0)
618 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
619 errmsg(
"argument to option \"%s\" must be a list of column names",
623 else if (strcmp(defel->
defname,
"force_null") == 0)
633 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
634 errmsg(
"argument to option \"%s\" must be a list of column names",
638 else if (strcmp(defel->
defname,
"convert_selectively") == 0)
641 * Undocumented, not-accessible-from-SQL option: convert only the
642 * named columns to binary form, storing the rest as NULLs. It's
643 * allowed for the column list to be NIL.
652 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
653 errmsg(
"argument to option \"%s\" must be a list of column names",
657 else if (strcmp(defel->
defname,
"encoding") == 0)
664 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
665 errmsg(
"argument to option \"%s\" must be a valid encoding name",
669 else if (strcmp(defel->
defname,
"on_error") == 0)
671 if (on_error_specified)
673 on_error_specified =
true;
676 else if (strcmp(defel->
defname,
"log_verbosity") == 0)
678 if (log_verbosity_specified)
680 log_verbosity_specified =
true;
683 else if (strcmp(defel->
defname,
"reject_limit") == 0)
685 if (reject_limit_specified)
687 reject_limit_specified =
true;
692 (
errcode(ERRCODE_SYNTAX_ERROR),
693 errmsg(
"option \"%s\" not recognized",
699 * Check for incompatible options (must do these three before inserting
704 (
errcode(ERRCODE_SYNTAX_ERROR),
705 /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
706 errmsg(
"cannot specify %s in BINARY mode",
"DELIMITER")));
710 (
errcode(ERRCODE_SYNTAX_ERROR),
711 errmsg(
"cannot specify %s in BINARY mode",
"NULL")));
715 (
errcode(ERRCODE_SYNTAX_ERROR),
716 errmsg(
"cannot specify %s in BINARY mode",
"DEFAULT")));
718 /* Set defaults for omitted options */
719 if (!opts_out->
delim)
728 if (!opts_out->
quote)
729 opts_out->
quote =
"\"";
734 /* Only single-byte delimiter strings are supported. */
735 if (strlen(opts_out->
delim) != 1)
737 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
738 errmsg(
"COPY delimiter must be a single one-byte character")));
740 /* Disallow end-of-line characters */
741 if (strchr(opts_out->
delim,
'\r') != NULL ||
742 strchr(opts_out->
delim,
'\n') != NULL)
744 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
745 errmsg(
"COPY delimiter cannot be newline or carriage return")));
747 if (strchr(opts_out->
null_print,
'\r') != NULL ||
750 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
751 errmsg(
"COPY null representation cannot use newline or carriage return")));
760 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
761 errmsg(
"COPY default representation cannot use newline or carriage return")));
765 * Disallow unsafe delimiter characters in non-CSV mode. We can't allow
766 * backslash because it would be ambiguous. We can't allow the other
767 * cases because data characters matching the delimiter must be
768 * backslashed, and certain backslash combinations are interpreted
769 * non-literally by COPY IN. Disallowing all lower case ASCII letters is
770 * more than strictly necessary, but seems best for consistency and
771 * future-proofing. Likewise we disallow all digits though only octal
772 * digits are actually dangerous.
775 strchr(
"\\.abcdefghijklmnopqrstuvwxyz0123456789",
776 opts_out->
delim[0]) != NULL)
778 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
779 errmsg(
"COPY delimiter cannot be \"%s\"", opts_out->
delim)));
784 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
785 /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
786 errmsg(
"cannot specify %s in BINARY mode",
"HEADER")));
791 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
792 /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
793 errmsg(
"COPY %s requires CSV mode",
"QUOTE")));
797 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
798 errmsg(
"COPY quote must be a single one-byte character")));
802 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
803 errmsg(
"COPY delimiter and quote must be different")));
808 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
809 /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
810 errmsg(
"COPY %s requires CSV mode",
"ESCAPE")));
814 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
815 errmsg(
"COPY escape must be a single one-byte character")));
817 /* Check force_quote */
820 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
821 /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
822 errmsg(
"COPY %s requires CSV mode",
"FORCE_QUOTE")));
825 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
826 /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
827 second %s is a COPY with direction, e.g. COPY TO */
828 errmsg(
"COPY %s cannot be used with %s",
"FORCE_QUOTE",
831 /* Check force_notnull */
835 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
836 /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
837 errmsg(
"COPY %s requires CSV mode",
"FORCE_NOT_NULL")));
841 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
842 /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
843 second %s is a COPY with direction, e.g. COPY TO */
844 errmsg(
"COPY %s cannot be used with %s",
"FORCE_NOT_NULL",
847 /* Check force_null */
851 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
852 /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
853 errmsg(
"COPY %s requires CSV mode",
"FORCE_NULL")));
858 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
859 /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
860 second %s is a COPY with direction, e.g. COPY TO */
861 errmsg(
"COPY %s cannot be used with %s",
"FORCE_NULL",
864 /* Don't allow the delimiter to appear in the null string. */
867 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
868 /*- translator: %s is the name of a COPY option, e.g. NULL */
869 errmsg(
"COPY delimiter character must not appear in the %s specification",
872 /* Don't allow the CSV quote char to appear in the null string. */
876 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
877 /*- translator: %s is the name of a COPY option, e.g. NULL */
878 errmsg(
"CSV quote character must not appear in the %s specification",
882 if (opts_out->
freeze && !is_from)
884 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
885 /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
886 second %s is a COPY with direction, e.g. COPY TO */
887 errmsg(
"COPY %s cannot be used with %s",
"FREEZE",
894 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
895 /*- translator: first %s is the name of a COPY option, e.g. ON_ERROR,
896 second %s is a COPY with direction, e.g. COPY TO */
897 errmsg(
"COPY %s cannot be used with %s",
"DEFAULT",
900 /* Don't allow the delimiter to appear in the default string. */
903 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
904 /*- translator: %s is the name of a COPY option, e.g. NULL */
905 errmsg(
"COPY delimiter character must not appear in the %s specification",
908 /* Don't allow the CSV quote char to appear in the default string. */
912 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
913 /*- translator: %s is the name of a COPY option, e.g. NULL */
914 errmsg(
"CSV quote character must not appear in the %s specification",
917 /* Don't allow the NULL and DEFAULT string to be the same */
922 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
923 errmsg(
"NULL specification and DEFAULT specification cannot be the same")));
928 (
errcode(ERRCODE_SYNTAX_ERROR),
929 errmsg(
"only ON_ERROR STOP is allowed in BINARY mode")));
933 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
934 /*- translator: first and second %s are the names of COPY option, e.g.
935 * ON_ERROR, third is the value of the COPY option, e.g. IGNORE */
936 errmsg(
"COPY %s requires %s to be set to %s",
937 "REJECT_LIMIT",
"ON_ERROR",
"IGNORE")));
941 * CopyGetAttnums - build an integer list of attnums to be copied
943 * The input attnamelist is either the user-specified column list,
944 * or NIL if there was none (in which case we want all the non-dropped
947 * We don't include generated columns in the generated full list and we don't
948 * allow them to be specified explicitly. They don't make sense for COPY
949 * FROM, but we could possibly allow them for COPY TO. But this way it's at
950 * least ensured that whatever we copy out can be copied back in.
952 * rel can be NULL ... it's only used for error reports.
959 if (attnamelist ==
NIL)
961 /* Generate default column list */
962 int attr_count = tupDesc->
natts;
965 for (
i = 0;
i < attr_count;
i++)
976 /* Validate the user-supplied list and extract attnums */
979 foreach(l, attnamelist)
985 /* Lookup column name */
987 for (
i = 0;
i < tupDesc->
natts;
i++)
991 if (att->attisdropped)
995 if (att->attgenerated)
997 (
errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
998 errmsg(
"column \"%s\" is a generated column",
1000 errdetail(
"Generated columns cannot be used in COPY.")));
1009 (
errcode(ERRCODE_UNDEFINED_COLUMN),
1010 errmsg(
"column \"%s\" of relation \"%s\" does not exist",
1014 (
errcode(ERRCODE_UNDEFINED_COLUMN),
1015 errmsg(
"column \"%s\" does not exist",
1018 /* Check for duplicates */
1021 (
errcode(ERRCODE_DUPLICATE_COLUMN),
1022 errmsg(
"column \"%s\" specified more than once",
bool has_privs_of_role(Oid member, Oid role)
#define InvalidAttrNumber
void DoCopy(ParseState *pstate, const CopyStmt *stmt, int stmt_location, int stmt_len, uint64 *processed)
static int defGetCopyHeaderOption(DefElem *def, bool is_from)
static int64 defGetCopyRejectLimitOption(DefElem *def)
List * CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
static CopyOnErrorChoice defGetCopyOnErrorChoice(DefElem *def, ParseState *pstate, bool is_from)
void ProcessCopyOptions(ParseState *pstate, CopyFormatOptions *opts_out, bool is_from, List *options)
static CopyLogVerbosityChoice defGetCopyLogVerbosityChoice(DefElem *def, ParseState *pstate)
Bitmapset * bms_add_member(Bitmapset *a, int x)
Node * eval_const_expressions(PlannerInfo *root, Node *node)
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)
uint64 CopyFrom(CopyFromState cstate)
void EndCopyFrom(CopyFromState cstate)
uint64 DoCopyTo(CopyToState cstate)
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)
void EndCopyTo(CopyToState cstate)
char * defGetString(DefElem *def)
bool defGetBoolean(DefElem *def)
int64 defGetInt64(DefElem *def)
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
int errdetail(const char *fmt,...)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
bool ExecCheckPermissions(List *rangeTable, List *rteperminfos, bool ereport_on_violation)
Assert(PointerIsAligned(start, uint64))
@ COPY_LOG_VERBOSITY_SILENT
@ COPY_LOG_VERBOSITY_VERBOSE
@ COPY_LOG_VERBOSITY_DEFAULT
#define COPY_HEADER_MATCH
#define COPY_HEADER_FALSE
List * lappend(List *list, void *datum)
List * lappend_int(List *list, int datum)
bool list_member_int(const List *list, int datum)
char * get_namespace_name(Oid nspid)
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
List * make_ands_implicit(Expr *clause)
char * pstrdup(const char *in)
void * palloc0(Size size)
int namestrcmp(Name name, const char *str)
#define IsA(nodeptr, _type_)
#define castNode(_type_, nodeptr)
int64 pg_strtoint64(const char *s)
Node * coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
int parser_errposition(ParseState *pstate, int location)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
FormData_pg_attribute * Form_pg_attribute
#define lfirst_node(type, lc)
#define pg_char_to_encoding
int pg_strcasecmp(const char *s1, const char *s2)
Expr * canonicalize_qual(Expr *qual, bool is_check)
#define RelationGetRelid(relation)
#define RelationGetDescr(relation)
#define RelationGetRelationName(relation)
#define RelationGetNamespace(relation)
int check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
RTEPermissionInfo * p_perminfo
#define FirstLowInvalidHeapAttributeNumber
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
void PreventCommandIfReadOnly(const char *cmdname)
#define select(n, r, w, e, timeout)