Header And Logo

PostgreSQL
| The world's most advanced open source database.

Typedefs | Functions

copy.h File Reference

#include "nodes/execnodes.h"
#include "nodes/parsenodes.h"
#include "tcop/dest.h"
Include dependency graph for copy.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef struct CopyStateDataCopyState

Functions

Oid DoCopy (const CopyStmt *stmt, const char *queryString, uint64 *processed)
void ProcessCopyOptions (CopyState cstate, bool is_from, List *options)
CopyState BeginCopyFrom (Relation rel, const char *filename, bool is_program, List *attnamelist, List *options)
void EndCopyFrom (CopyState cstate)
bool NextCopyFrom (CopyState cstate, ExprContext *econtext, Datum *values, bool *nulls, Oid *tupleOid)
bool NextCopyFromRawFields (CopyState cstate, char ***fields, int *nfields)
void CopyFromErrorCallback (void *arg)
DestReceiverCreateCopyDestReceiver (void)

Typedef Documentation

typedef struct CopyStateData* CopyState

Definition at line 22 of file copy.h.


Function Documentation

CopyState BeginCopyFrom ( Relation  rel,
const char *  filename,
bool  is_program,
List attnamelist,
List options 
)

Definition at line 2403 of file copy.c.

References AllocateFile(), Assert, CopyStateData::attnumlist, CopyStateData::attribute_buf, tupleDesc::attrs, BeginCopy(), CopyStateData::binary, BinarySignature, build_column_default(), contain_volatile_functions(), CopyStateData::copy_file, CopyStateData::copycontext, CopyGetData(), CopyGetInt32(), CopyStateData::cur_attname, CopyStateData::cur_attval, CopyStateData::cur_lineno, CopyStateData::cur_relname, CopyStateData::defexprs, CopyStateData::defmap, DestRemote, CopyStateData::eol_type, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, ExecInitExpr(), expression_planner(), CopyStateData::fe_eof, CopyStateData::file_has_oids, CopyStateData::filename, fmgr_info(), getTypeBinaryInputInfo(), getTypeInputInfo(), CopyStateData::in_functions, initStringInfo(), CopyStateData::is_program, CopyStateData::line_buf, CopyStateData::line_buf_converted, list_length(), list_member_int(), CopyStateData::max_fields, memcmp(), MemoryContextSwitchTo(), tupleDesc::natts, NULL, CopyStateData::num_defaults, CopyStateData::oid_in_function, CopyStateData::oid_typioparam, OIDOID, CopyStateData::oids, OpenPipeStream(), palloc(), PG_BINARY_R, pstrdup(), CopyStateData::raw_buf, CopyStateData::raw_buf_index, CopyStateData::raw_buf_len, RAW_BUF_SIZE, CopyStateData::raw_fields, ReceiveCopyBegin(), CopyStateData::rel, RelationGetDescr, RelationGetRelationName, CopyStateData::typioparams, CopyStateData::volatile_defexprs, and whereToSendOutput.

Referenced by DoCopy(), file_acquire_sample_rows(), fileBeginForeignScan(), and fileReScanForeignScan().

{
    CopyState   cstate;
    bool        pipe = (filename == NULL);
    TupleDesc   tupDesc;
    Form_pg_attribute *attr;
    AttrNumber  num_phys_attrs,
                num_defaults;
    FmgrInfo   *in_functions;
    Oid        *typioparams;
    int         attnum;
    Oid         in_func_oid;
    int        *defmap;
    ExprState **defexprs;
    MemoryContext oldcontext;
    bool        volatile_defexprs;

    cstate = BeginCopy(true, rel, NULL, NULL, attnamelist, options);
    oldcontext = MemoryContextSwitchTo(cstate->copycontext);

    /* Initialize state variables */
    cstate->fe_eof = false;
    cstate->eol_type = EOL_UNKNOWN;
    cstate->cur_relname = RelationGetRelationName(cstate->rel);
    cstate->cur_lineno = 0;
    cstate->cur_attname = NULL;
    cstate->cur_attval = NULL;

    /* Set up variables to avoid per-attribute overhead. */
    initStringInfo(&cstate->attribute_buf);
    initStringInfo(&cstate->line_buf);
    cstate->line_buf_converted = false;
    cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
    cstate->raw_buf_index = cstate->raw_buf_len = 0;

    tupDesc = RelationGetDescr(cstate->rel);
    attr = tupDesc->attrs;
    num_phys_attrs = tupDesc->natts;
    num_defaults = 0;
    volatile_defexprs = false;

    /*
     * Pick up the required catalog information for each attribute in the
     * relation, including the input function, the element type (to pass to
     * the input function), and info about defaults and constraints. (Which
     * input function we use depends on text/binary format choice.)
     */
    in_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
    typioparams = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
    defmap = (int *) palloc(num_phys_attrs * sizeof(int));
    defexprs = (ExprState **) palloc(num_phys_attrs * sizeof(ExprState *));

    for (attnum = 1; attnum <= num_phys_attrs; attnum++)
    {
        /* We don't need info for dropped attributes */
        if (attr[attnum - 1]->attisdropped)
            continue;

        /* Fetch the input function and typioparam info */
        if (cstate->binary)
            getTypeBinaryInputInfo(attr[attnum - 1]->atttypid,
                                   &in_func_oid, &typioparams[attnum - 1]);
        else
            getTypeInputInfo(attr[attnum - 1]->atttypid,
                             &in_func_oid, &typioparams[attnum - 1]);
        fmgr_info(in_func_oid, &in_functions[attnum - 1]);

        /* Get default info if needed */
        if (!list_member_int(cstate->attnumlist, attnum))
        {
            /* attribute is NOT to be copied from input */
            /* use default value if one exists */
            Node       *defexpr = build_column_default(cstate->rel, attnum);

            if (defexpr != NULL)
            {
                /* Initialize expressions in copycontext. */
                defexprs[num_defaults] = ExecInitExpr(
                                 expression_planner((Expr *) defexpr), NULL);
                defmap[num_defaults] = attnum - 1;
                num_defaults++;

                if (!volatile_defexprs)
                    volatile_defexprs = contain_volatile_functions(defexpr);
            }
        }
    }

    /* We keep those variables in cstate. */
    cstate->in_functions = in_functions;
    cstate->typioparams = typioparams;
    cstate->defmap = defmap;
    cstate->defexprs = defexprs;
    cstate->volatile_defexprs = volatile_defexprs;
    cstate->num_defaults = num_defaults;
    cstate->is_program = is_program;

    if (pipe)
    {
        Assert(!is_program);    /* the grammar does not allow this */
        if (whereToSendOutput == DestRemote)
            ReceiveCopyBegin(cstate);
        else
            cstate->copy_file = stdin;
    }
    else
    {
        cstate->filename = pstrdup(filename);

        if (cstate->is_program)
        {
            cstate->copy_file = OpenPipeStream(cstate->filename, PG_BINARY_R);
            if (cstate->copy_file == NULL)
                ereport(ERROR,
                        (errmsg("could not execute command \"%s\": %m",
                                cstate->filename)));
        }
        else
        {
            struct stat st;

            cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_R);
            if (cstate->copy_file == NULL)
                ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not open file \"%s\" for reading: %m",
                                cstate->filename)));

            fstat(fileno(cstate->copy_file), &st);
            if (S_ISDIR(st.st_mode))
                ereport(ERROR,
                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                         errmsg("\"%s\" is a directory", cstate->filename)));
        }
    }

    if (!cstate->binary)
    {
        /* must rely on user to tell us... */
        cstate->file_has_oids = cstate->oids;
    }
    else
    {
        /* Read and verify binary header */
        char        readSig[11];
        int32       tmp;

        /* Signature */
        if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
            memcmp(readSig, BinarySignature, 11) != 0)
            ereport(ERROR,
                    (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                     errmsg("COPY file signature not recognized")));
        /* Flags field */
        if (!CopyGetInt32(cstate, &tmp))
            ereport(ERROR,
                    (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                     errmsg("invalid COPY file header (missing flags)")));
        cstate->file_has_oids = (tmp & (1 << 16)) != 0;
        tmp &= ~(1 << 16);
        if ((tmp >> 16) != 0)
            ereport(ERROR,
                    (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                 errmsg("unrecognized critical flags in COPY file header")));
        /* Header extension length */
        if (!CopyGetInt32(cstate, &tmp) ||
            tmp < 0)
            ereport(ERROR,
                    (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                     errmsg("invalid COPY file header (missing length)")));
        /* Skip extension header, if present */
        while (tmp-- > 0)
        {
            if (CopyGetData(cstate, readSig, 1, 1) != 1)
                ereport(ERROR,
                        (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                         errmsg("invalid COPY file header (wrong length)")));
        }
    }

    if (cstate->file_has_oids && cstate->binary)
    {
        getTypeBinaryInputInfo(OIDOID,
                               &in_func_oid, &cstate->oid_typioparam);
        fmgr_info(in_func_oid, &cstate->oid_in_function);
    }

    /* create workspace for CopyReadAttributes results */
    if (!cstate->binary)
    {
        AttrNumber  attr_count = list_length(cstate->attnumlist);
        int         nfields = cstate->file_has_oids ? (attr_count + 1) : attr_count;

        cstate->max_fields = nfields;
        cstate->raw_fields = (char **) palloc(nfields * sizeof(char *));
    }

    MemoryContextSwitchTo(oldcontext);

    return cstate;
}

void CopyFromErrorCallback ( void *  arg  ) 

Definition at line 1889 of file copy.c.

References CopyStateData::binary, CopyStateData::cur_attname, CopyStateData::cur_attval, CopyStateData::cur_lineno, CopyStateData::cur_relname, StringInfoData::data, errcontext, limit_printout_length(), CopyStateData::line_buf, CopyStateData::line_buf_converted, CopyStateData::need_transcoding, and pfree().

Referenced by fileIterateForeignScan().

{
    CopyState   cstate = (CopyState) arg;

    if (cstate->binary)
    {
        /* can't usefully display the data */
        if (cstate->cur_attname)
            errcontext("COPY %s, line %d, column %s",
                       cstate->cur_relname, cstate->cur_lineno,
                       cstate->cur_attname);
        else
            errcontext("COPY %s, line %d",
                       cstate->cur_relname, cstate->cur_lineno);
    }
    else
    {
        if (cstate->cur_attname && cstate->cur_attval)
        {
            /* error is relevant to a particular column */
            char       *attval;

            attval = limit_printout_length(cstate->cur_attval);
            errcontext("COPY %s, line %d, column %s: \"%s\"",
                       cstate->cur_relname, cstate->cur_lineno,
                       cstate->cur_attname, attval);
            pfree(attval);
        }
        else if (cstate->cur_attname)
        {
            /* error is relevant to a particular column, value is NULL */
            errcontext("COPY %s, line %d, column %s: null input",
                       cstate->cur_relname, cstate->cur_lineno,
                       cstate->cur_attname);
        }
        else
        {
            /* error is relevant to a particular line */
            if (cstate->line_buf_converted || !cstate->need_transcoding)
            {
                char       *lineval;

                lineval = limit_printout_length(cstate->line_buf.data);
                errcontext("COPY %s, line %d: \"%s\"",
                           cstate->cur_relname, cstate->cur_lineno, lineval);
                pfree(lineval);
            }
            else
            {
                /*
                 * Here, the line buffer is still in a foreign encoding, and
                 * indeed it's quite likely that the error is precisely a
                 * failure to do encoding conversion (ie, bad data).  We dare
                 * not try to convert it, and at present there's no way to
                 * regurgitate it without conversion.  So we have to punt and
                 * just report the line number.
                 */
                errcontext("COPY %s, line %d",
                           cstate->cur_relname, cstate->cur_lineno);
            }
        }
    }
}

DestReceiver* CreateCopyDestReceiver ( void   ) 

Definition at line 4204 of file copy.c.

References palloc().

Referenced by CreateDestReceiver().

{
    DR_copy    *self = (DR_copy *) palloc(sizeof(DR_copy));

    self->pub.receiveSlot = copy_dest_receive;
    self->pub.rStartup = copy_dest_startup;
    self->pub.rShutdown = copy_dest_shutdown;
    self->pub.rDestroy = copy_dest_destroy;
    self->pub.mydest = DestCopyOut;

    self->cstate = NULL;        /* will be set later */
    self->processed = 0;

    return (DestReceiver *) self;
}

Oid DoCopy ( const CopyStmt stmt,
const char *  queryString,
uint64 *  processed 
)

Definition at line 776 of file copy.c.

References AccessShareLock, ACL_INSERT, Assert, CopyStmt::attlist, BeginCopyFrom(), BeginCopyTo(), bms_add_member(), CopyFrom(), CopyGetAttnums(), cur, DoCopyTo(), EndCopyFrom(), EndCopyTo(), ereport, errcode(), errhint(), errmsg(), ERROR, ExecCheckRTPerms(), CopyStmt::filename, heap_close, heap_openrv(), CopyStmt::is_from, CopyStmt::is_program, lfirst_int, list_make1, makeNode, RangeTblEntry::modifiedCols, NoLock, NULL, CopyStmt::options, PreventCommandIfReadOnly(), CopyStmt::query, RelationData::rd_islocaltemp, RelationData::rd_rel, CopyStmt::relation, RelationGetDescr, RelationGetRelid, RangeTblEntry::relid, RangeTblEntry::relkind, RangeTblEntry::requiredPerms, RowExclusiveLock, RangeTblEntry::rtekind, RangeTblEntry::selectedCols, superuser(), and XactReadOnly.

Referenced by standard_ProcessUtility().

{
    CopyState   cstate;
    bool        is_from = stmt->is_from;
    bool        pipe = (stmt->filename == NULL);
    Relation    rel;
    Oid         relid;

    /* Disallow COPY to/from file or program except to superusers. */
    if (!pipe && !superuser())
    {
        if (stmt->is_program)
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
             errmsg("must be superuser to COPY to or from an external program"),
                     errhint("Anyone can COPY to stdout or from stdin. "
                             "psql's \\copy command also works for anyone.")));
        else
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must be superuser to COPY to or from a file"),
                     errhint("Anyone can COPY to stdout or from stdin. "
                             "psql's \\copy command also works for anyone.")));
    }

    if (stmt->relation)
    {
        TupleDesc   tupDesc;
        AclMode     required_access = (is_from ? ACL_INSERT : ACL_SELECT);
        RangeTblEntry *rte;
        List       *attnums;
        ListCell   *cur;

        Assert(!stmt->query);

        /* Open and lock the relation, using the appropriate lock type. */
        rel = heap_openrv(stmt->relation,
                          (is_from ? RowExclusiveLock : AccessShareLock));

        relid = RelationGetRelid(rel);

        rte = makeNode(RangeTblEntry);
        rte->rtekind = RTE_RELATION;
        rte->relid = RelationGetRelid(rel);
        rte->relkind = rel->rd_rel->relkind;
        rte->requiredPerms = required_access;

        tupDesc = RelationGetDescr(rel);
        attnums = CopyGetAttnums(tupDesc, rel, stmt->attlist);
        foreach(cur, attnums)
        {
            int         attno = lfirst_int(cur) -
            FirstLowInvalidHeapAttributeNumber;

            if (is_from)
                rte->modifiedCols = bms_add_member(rte->modifiedCols, attno);
            else
                rte->selectedCols = bms_add_member(rte->selectedCols, attno);
        }
        ExecCheckRTPerms(list_make1(rte), true);
    }
    else
    {
        Assert(stmt->query);

        relid = InvalidOid;
        rel = NULL;
    }

    if (is_from)
    {
        Assert(rel);

        /* check read-only transaction */
        if (XactReadOnly && !rel->rd_islocaltemp)
            PreventCommandIfReadOnly("COPY FROM");

        cstate = BeginCopyFrom(rel, stmt->filename, stmt->is_program,
                               stmt->attlist, stmt->options);
        *processed = CopyFrom(cstate);  /* copy from file to database */
        EndCopyFrom(cstate);
    }
    else
    {
        cstate = BeginCopyTo(rel, stmt->query, queryString,
                             stmt->filename, stmt->is_program,
                             stmt->attlist, stmt->options);
        *processed = DoCopyTo(cstate);  /* copy from database to file */
        EndCopyTo(cstate);
    }

    /*
     * Close the relation. If reading, we can release the AccessShareLock we
     * got; if writing, we should hold the lock until end of transaction to
     * ensure that updates will be committed before lock is released.
     */
    if (rel != NULL)
        heap_close(rel, (is_from ? NoLock : AccessShareLock));

    return relid;
}

void EndCopyFrom ( CopyState  cstate  ) 

Definition at line 2897 of file copy.c.

References EndCopy().

Referenced by DoCopy(), file_acquire_sample_rows(), fileEndForeignScan(), and fileReScanForeignScan().

{
    /* No COPY FROM related resources except memory. */

    EndCopy(cstate);
}

bool NextCopyFrom ( CopyState  cstate,
ExprContext econtext,
Datum values,
bool nulls,
Oid tupleOid 
)

Definition at line 2673 of file copy.c.

References Assert, CopyStateData::attnumlist, tupleDesc::attrs, CopyStateData::binary, CopyStateData::convert_select_flags, CopyStateData::copy_dest, COPY_OLD_FE, CopyGetData(), CopyGetInt16(), CopyReadBinaryAttribute(), CStringGetDatum, CopyStateData::csv_mode, cur, CopyStateData::cur_attname, CopyStateData::cur_attval, CopyStateData::cur_lineno, CurrentMemoryContext, DatumGetObjectId, CopyStateData::defexprs, CopyStateData::defmap, DirectFunctionCall1, ExprContext::ecxt_per_tuple_memory, ereport, errcode(), errmsg(), ERROR, ExecEvalExpr, CopyStateData::file_has_oids, CopyStateData::force_notnull_flags, i, CopyStateData::in_functions, InputFunctionCall(), InvalidOid, lfirst_int, list_length(), MemSet, NameStr, tupleDesc::natts, NextCopyFromRawFields(), NULL, CopyStateData::null_print, CopyStateData::num_defaults, CopyStateData::oid_in_function, CopyStateData::oid_typioparam, oidin(), CopyStateData::oids, CopyStateData::rel, RelationGetDescr, and CopyStateData::typioparams.

Referenced by CopyFrom(), file_acquire_sample_rows(), and fileIterateForeignScan().

{
    TupleDesc   tupDesc;
    Form_pg_attribute *attr;
    AttrNumber  num_phys_attrs,
                attr_count,
                num_defaults = cstate->num_defaults;
    FmgrInfo   *in_functions = cstate->in_functions;
    Oid        *typioparams = cstate->typioparams;
    int         i;
    int         nfields;
    bool        isnull;
    bool        file_has_oids = cstate->file_has_oids;
    int        *defmap = cstate->defmap;
    ExprState **defexprs = cstate->defexprs;

    tupDesc = RelationGetDescr(cstate->rel);
    attr = tupDesc->attrs;
    num_phys_attrs = tupDesc->natts;
    attr_count = list_length(cstate->attnumlist);
    nfields = file_has_oids ? (attr_count + 1) : attr_count;

    /* Initialize all values for row to NULL */
    MemSet(values, 0, num_phys_attrs * sizeof(Datum));
    MemSet(nulls, true, num_phys_attrs * sizeof(bool));

    if (!cstate->binary)
    {
        char      **field_strings;
        ListCell   *cur;
        int         fldct;
        int         fieldno;
        char       *string;

        /* read raw fields in the next line */
        if (!NextCopyFromRawFields(cstate, &field_strings, &fldct))
            return false;

        /* check for overflowing fields */
        if (nfields > 0 && fldct > nfields)
            ereport(ERROR,
                    (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                     errmsg("extra data after last expected column")));

        fieldno = 0;

        /* Read the OID field if present */
        if (file_has_oids)
        {
            if (fieldno >= fldct)
                ereport(ERROR,
                        (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                         errmsg("missing data for OID column")));
            string = field_strings[fieldno++];

            if (string == NULL)
                ereport(ERROR,
                        (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                         errmsg("null OID in COPY data")));
            else if (cstate->oids && tupleOid != NULL)
            {
                cstate->cur_attname = "oid";
                cstate->cur_attval = string;
                *tupleOid = DatumGetObjectId(DirectFunctionCall1(oidin,
                                                   CStringGetDatum(string)));
                if (*tupleOid == InvalidOid)
                    ereport(ERROR,
                            (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                             errmsg("invalid OID in COPY data")));
                cstate->cur_attname = NULL;
                cstate->cur_attval = NULL;
            }
        }

        /* Loop to read the user attributes on the line. */
        foreach(cur, cstate->attnumlist)
        {
            int         attnum = lfirst_int(cur);
            int         m = attnum - 1;

            if (fieldno >= fldct)
                ereport(ERROR,
                        (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                         errmsg("missing data for column \"%s\"",
                                NameStr(attr[m]->attname))));
            string = field_strings[fieldno++];

            if (cstate->convert_select_flags &&
                !cstate->convert_select_flags[m])
            {
                /* ignore input field, leaving column as NULL */
                continue;
            }

            if (cstate->csv_mode && string == NULL &&
                cstate->force_notnull_flags[m])
            {
                /* Go ahead and read the NULL string */
                string = cstate->null_print;
            }

            cstate->cur_attname = NameStr(attr[m]->attname);
            cstate->cur_attval = string;
            values[m] = InputFunctionCall(&in_functions[m],
                                          string,
                                          typioparams[m],
                                          attr[m]->atttypmod);
            if (string != NULL)
                nulls[m] = false;
            cstate->cur_attname = NULL;
            cstate->cur_attval = NULL;
        }

        Assert(fieldno == nfields);
    }
    else
    {
        /* binary */
        int16       fld_count;
        ListCell   *cur;

        cstate->cur_lineno++;

        if (!CopyGetInt16(cstate, &fld_count))
        {
            /* EOF detected (end of file, or protocol-level EOF) */
            return false;
        }

        if (fld_count == -1)
        {
            /*
             * Received EOF marker.  In a V3-protocol copy, wait for the
             * protocol-level EOF, and complain if it doesn't come
             * immediately.  This ensures that we correctly handle CopyFail,
             * if client chooses to send that now.
             *
             * Note that we MUST NOT try to read more data in an old-protocol
             * copy, since there is no protocol-level EOF marker then.  We
             * could go either way for copy from file, but choose to throw
             * error if there's data after the EOF marker, for consistency
             * with the new-protocol case.
             */
            char        dummy;

            if (cstate->copy_dest != COPY_OLD_FE &&
                CopyGetData(cstate, &dummy, 1, 1) > 0)
                ereport(ERROR,
                        (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                         errmsg("received copy data after EOF marker")));
            return false;
        }

        if (fld_count != attr_count)
            ereport(ERROR,
                    (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                     errmsg("row field count is %d, expected %d",
                            (int) fld_count, attr_count)));

        if (file_has_oids)
        {
            Oid         loaded_oid;

            cstate->cur_attname = "oid";
            loaded_oid =
                DatumGetObjectId(CopyReadBinaryAttribute(cstate,
                                                         0,
                                                    &cstate->oid_in_function,
                                                      cstate->oid_typioparam,
                                                         -1,
                                                         &isnull));
            if (isnull || loaded_oid == InvalidOid)
                ereport(ERROR,
                        (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
                         errmsg("invalid OID in COPY data")));
            cstate->cur_attname = NULL;
            if (cstate->oids && tupleOid != NULL)
                *tupleOid = loaded_oid;
        }

        i = 0;
        foreach(cur, cstate->attnumlist)
        {
            int         attnum = lfirst_int(cur);
            int         m = attnum - 1;

            cstate->cur_attname = NameStr(attr[m]->attname);
            i++;
            values[m] = CopyReadBinaryAttribute(cstate,
                                                i,
                                                &in_functions[m],
                                                typioparams[m],
                                                attr[m]->atttypmod,
                                                &nulls[m]);
            cstate->cur_attname = NULL;
        }
    }

    /*
     * Now compute and insert any defaults available for the columns not
     * provided by the input data.  Anything not processed here or above will
     * remain NULL.
     */
    for (i = 0; i < num_defaults; i++)
    {
        /*
         * The caller must supply econtext and have switched into the
         * per-tuple memory context in it.
         */
        Assert(econtext != NULL);
        Assert(CurrentMemoryContext == econtext->ecxt_per_tuple_memory);

        values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext,
                                         &nulls[defmap[i]], NULL);
    }

    return true;
}

bool NextCopyFromRawFields ( CopyState  cstate,
char ***  fields,
int *  nfields 
)

Definition at line 2621 of file copy.c.

References Assert, CopyStateData::binary, CopyReadAttributesCSV(), CopyReadAttributesText(), CopyReadLine(), CopyStateData::csv_mode, CopyStateData::cur_lineno, CopyStateData::header_line, StringInfoData::len, CopyStateData::line_buf, and CopyStateData::raw_fields.

Referenced by NextCopyFrom().

{
    int         fldct;
    bool        done;

    /* only available for text or csv input */
    Assert(!cstate->binary);

    /* on input just throw the header line away */
    if (cstate->cur_lineno == 0 && cstate->header_line)
    {
        cstate->cur_lineno++;
        if (CopyReadLine(cstate))
            return false;       /* done */
    }

    cstate->cur_lineno++;

    /* Actually read the line into memory here */
    done = CopyReadLine(cstate);

    /*
     * EOF at start of line means we're done.  If we see EOF after some
     * characters, we act as though it was newline followed by EOF, ie,
     * process the line and then exit loop on next iteration.
     */
    if (done && cstate->line_buf.len == 0)
        return false;

    /* Parse the line into de-escaped field values */
    if (cstate->csv_mode)
        fldct = CopyReadAttributesCSV(cstate);
    else
        fldct = CopyReadAttributesText(cstate);

    *fields = cstate->raw_fields;
    *nfields = fldct;
    return true;
}

void ProcessCopyOptions ( CopyState  cstate,
bool  is_from,
List options 
)

Definition at line 896 of file copy.c.

References DefElem::arg, CopyStateData::binary, CopyStateData::convert_select, CopyStateData::convert_selectively, CopyStateData::csv_mode, defGetBoolean(), defGetString(), DefElem::defname, CopyStateData::delim, ereport, errcode(), errmsg(), ERROR, CopyStateData::escape, CopyStateData::file_encoding, CopyStateData::force_notnull, CopyStateData::force_quote, CopyStateData::force_quote_all, CopyStateData::freeze, CopyStateData::header_line, IsA, lfirst, NIL, NULL, CopyStateData::null_print, CopyStateData::null_print_len, CopyStateData::oids, palloc0(), pg_char_to_encoding(), and CopyStateData::quote.

Referenced by BeginCopy(), and file_fdw_validator().

{
    bool        format_specified = false;
    ListCell   *option;

    /* Support external use for option sanity checking */
    if (cstate == NULL)
        cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));

    cstate->file_encoding = -1;

    /* Extract options from the statement node tree */
    foreach(option, options)
    {
        DefElem    *defel = (DefElem *) lfirst(option);

        if (strcmp(defel->defname, "format") == 0)
        {
            char       *fmt = defGetString(defel);

            if (format_specified)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            format_specified = true;
            if (strcmp(fmt, "text") == 0)
                 /* default format */ ;
            else if (strcmp(fmt, "csv") == 0)
                cstate->csv_mode = true;
            else if (strcmp(fmt, "binary") == 0)
                cstate->binary = true;
            else
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("COPY format \"%s\" not recognized", fmt)));
        }
        else if (strcmp(defel->defname, "oids") == 0)
        {
            if (cstate->oids)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            cstate->oids = defGetBoolean(defel);
        }
        else if (strcmp(defel->defname, "freeze") == 0)
        {
            if (cstate->freeze)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            cstate->freeze = defGetBoolean(defel);
        }
        else if (strcmp(defel->defname, "delimiter") == 0)
        {
            if (cstate->delim)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            cstate->delim = defGetString(defel);
        }
        else if (strcmp(defel->defname, "null") == 0)
        {
            if (cstate->null_print)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            cstate->null_print = defGetString(defel);
        }
        else if (strcmp(defel->defname, "header") == 0)
        {
            if (cstate->header_line)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            cstate->header_line = defGetBoolean(defel);
        }
        else if (strcmp(defel->defname, "quote") == 0)
        {
            if (cstate->quote)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            cstate->quote = defGetString(defel);
        }
        else if (strcmp(defel->defname, "escape") == 0)
        {
            if (cstate->escape)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            cstate->escape = defGetString(defel);
        }
        else if (strcmp(defel->defname, "force_quote") == 0)
        {
            if (cstate->force_quote || cstate->force_quote_all)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            if (defel->arg && IsA(defel->arg, A_Star))
                cstate->force_quote_all = true;
            else if (defel->arg && IsA(defel->arg, List))
                cstate->force_quote = (List *) defel->arg;
            else
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("argument to option \"%s\" must be a list of column names",
                                defel->defname)));
        }
        else if (strcmp(defel->defname, "force_not_null") == 0)
        {
            if (cstate->force_notnull)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            if (defel->arg && IsA(defel->arg, List))
                cstate->force_notnull = (List *) defel->arg;
            else
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("argument to option \"%s\" must be a list of column names",
                                defel->defname)));
        }
        else if (strcmp(defel->defname, "convert_selectively") == 0)
        {
            /*
             * Undocumented, not-accessible-from-SQL option: convert only
             * the named columns to binary form, storing the rest as NULLs.
             * It's allowed for the column list to be NIL.
             */
            if (cstate->convert_selectively)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            cstate->convert_selectively = true;
            if (defel->arg == NULL || IsA(defel->arg, List))
                cstate->convert_select = (List *) defel->arg;
            else
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("argument to option \"%s\" must be a list of column names",
                                defel->defname)));
        }
        else if (strcmp(defel->defname, "encoding") == 0)
        {
            if (cstate->file_encoding >= 0)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            cstate->file_encoding = pg_char_to_encoding(defGetString(defel));
            if (cstate->file_encoding < 0)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("argument to option \"%s\" must be a valid encoding name",
                                defel->defname)));
        }
        else
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("option \"%s\" not recognized",
                            defel->defname)));
    }

    /*
     * Check for incompatible options (must do these two before inserting
     * defaults)
     */
    if (cstate->binary && cstate->delim)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("cannot specify DELIMITER in BINARY mode")));

    if (cstate->binary && cstate->null_print)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("cannot specify NULL in BINARY mode")));

    /* Set defaults for omitted options */
    if (!cstate->delim)
        cstate->delim = cstate->csv_mode ? "," : "\t";

    if (!cstate->null_print)
        cstate->null_print = cstate->csv_mode ? "" : "\\N";
    cstate->null_print_len = strlen(cstate->null_print);

    if (cstate->csv_mode)
    {
        if (!cstate->quote)
            cstate->quote = "\"";
        if (!cstate->escape)
            cstate->escape = cstate->quote;
    }

    /* Only single-byte delimiter strings are supported. */
    if (strlen(cstate->delim) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
              errmsg("COPY delimiter must be a single one-byte character")));

    /* Disallow end-of-line characters */
    if (strchr(cstate->delim, '\r') != NULL ||
        strchr(cstate->delim, '\n') != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
             errmsg("COPY delimiter cannot be newline or carriage return")));

    if (strchr(cstate->null_print, '\r') != NULL ||
        strchr(cstate->null_print, '\n') != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("COPY null representation cannot use newline or carriage return")));

    /*
     * Disallow unsafe delimiter characters in non-CSV mode.  We can't allow
     * backslash because it would be ambiguous.  We can't allow the other
     * cases because data characters matching the delimiter must be
     * backslashed, and certain backslash combinations are interpreted
     * non-literally by COPY IN.  Disallowing all lower case ASCII letters is
     * more than strictly necessary, but seems best for consistency and
     * future-proofing.  Likewise we disallow all digits though only octal
     * digits are actually dangerous.
     */
    if (!cstate->csv_mode &&
        strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789",
               cstate->delim[0]) != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("COPY delimiter cannot be \"%s\"", cstate->delim)));

    /* Check header */
    if (!cstate->csv_mode && cstate->header_line)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("COPY HEADER available only in CSV mode")));

    /* Check quote */
    if (!cstate->csv_mode && cstate->quote != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("COPY quote available only in CSV mode")));

    if (cstate->csv_mode && strlen(cstate->quote) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("COPY quote must be a single one-byte character")));

    if (cstate->csv_mode && cstate->delim[0] == cstate->quote[0])
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("COPY delimiter and quote must be different")));

    /* Check escape */
    if (!cstate->csv_mode && cstate->escape != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("COPY escape available only in CSV mode")));

    if (cstate->csv_mode && strlen(cstate->escape) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("COPY escape must be a single one-byte character")));

    /* Check force_quote */
    if (!cstate->csv_mode && (cstate->force_quote || cstate->force_quote_all))
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("COPY force quote available only in CSV mode")));
    if ((cstate->force_quote || cstate->force_quote_all) && is_from)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("COPY force quote only available using COPY TO")));

    /* Check force_notnull */
    if (!cstate->csv_mode && cstate->force_notnull != NIL)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("COPY force not null available only in CSV mode")));
    if (cstate->force_notnull != NIL && !is_from)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
              errmsg("COPY force not null only available using COPY FROM")));

    /* Don't allow the delimiter to appear in the null string. */
    if (strchr(cstate->null_print, cstate->delim[0]) != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
        errmsg("COPY delimiter must not appear in the NULL specification")));

    /* Don't allow the CSV quote char to appear in the null string. */
    if (cstate->csv_mode &&
        strchr(cstate->null_print, cstate->quote[0]) != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("CSV quote character must not appear in the NULL specification")));
}