/* Stores multi-insert data related to a single relation in CopyFrom. */ typedefstruct CopyMultiInsertBuffer
{
TupleTableSlot *slots[MAX_BUFFERED_TUPLES]; /* Array to store tuples */
ResultRelInfo *resultRelInfo; /* ResultRelInfo for 'relid' */
BulkInsertState bistate; /* BulkInsertState for this rel if plain
* table; NULL if foreign table */ int nused; /* number of 'slots' containing tuples */
uint64 linenos[MAX_BUFFERED_TUPLES]; /* Line # of tuple in copy
* stream */
} CopyMultiInsertBuffer;
/* *StoresoneormanyCopyMultiInsertBuffersanddetailsaboutthesizeand *numberoftupleswhicharestoredinthem.Thisallowsmultiplebuffersto *existatoncewhenCOPYingintoapartitionedtable.
*/ typedefstruct CopyMultiInsertInfo
{
List *multiInsertBuffers; /* List of tracked CopyMultiInsertBuffers */ int bufferedTuples; /* number of tuples buffered over all buffers */ int bufferedBytes; /* number of bytes from all buffered tuples */
CopyFromState cstate; /* Copy state for this CopyMultiInsertInfo */
EState *estate; /* Executor state used for COPY */
CommandId mycid; /* Command Id used for COPY */ int ti_options; /* table insert options */
} CopyMultiInsertInfo;
/* non-export function prototypes */ staticvoid ClosePipeFromProgram(CopyFromState cstate);
/* *Built-informat-specificroutines.One-rowcallbacksaredefinedin *copyfromparse.c.
*/ staticvoid CopyFromTextLikeInFunc(CopyFromState cstate, Oid atttypid, FmgrInfo *finfo,
Oid *typioparam); staticvoid CopyFromTextLikeStart(CopyFromState cstate, TupleDesc tupDesc); staticvoid CopyFromTextLikeEnd(CopyFromState cstate); staticvoid CopyFromBinaryInFunc(CopyFromState cstate, Oid atttypid,
FmgrInfo *finfo, Oid *typioparam); staticvoid CopyFromBinaryStart(CopyFromState cstate, TupleDesc tupDesc); staticvoid CopyFromBinaryEnd(CopyFromState cstate);
/* Return a COPY FROM routine for the given options */ staticconst CopyFromRoutine *
CopyFromGetRoutine(const CopyFormatOptions *opts)
{ if (opts->csv_mode) return &CopyFromRoutineCSV; elseif (opts->binary) return &CopyFromRoutineBinary;
/* default is text */ return &CopyFromRoutineText;
}
/* Implementation of the start callback for text and CSV formats */ staticvoid
CopyFromTextLikeStart(CopyFromState cstate, TupleDesc tupDesc)
{
AttrNumber attr_count;
/* Implementation of the end callback for text and CSV formats */ staticvoid
CopyFromTextLikeEnd(CopyFromState cstate)
{ /* nothing to do */
}
/* Implementation of the start callback for binary format */ staticvoid
CopyFromBinaryStart(CopyFromState cstate, TupleDesc tupDesc)
{ /* Read and verify binary header */
ReceiveCopyBinaryHeader(cstate);
}
/* *Implementationoftheinfunccallbackforbinaryformat.Assign *thebinaryinputfunctiontothegiven*finfo.
*/ staticvoid
CopyFromBinaryInFunc(CopyFromState cstate, Oid atttypid,
FmgrInfo *finfo, Oid *typioparam)
{
Oid func_oid;
/* Setup back-link so we can easily find this buffer again */
rri->ri_CopyMultiInsertBuffer = buffer; /* Record that we're tracking this buffer */
miinfo->multiInsertBuffers = lappend(miinfo->multiInsertBuffers, buffer);
}
while (sent < nused)
{ int size = (batch_size < nused - sent) ? batch_size : (nused - sent); int inserted = size;
TupleTableSlot **rslots;
/* insert into foreign table: let the FDW do it */
rslots =
resultRelInfo->ri_FdwRoutine->ExecForeignBatchInsert(estate,
resultRelInfo,
&slots[sent],
NULL,
&inserted);
sent += size;
/* No need to do anything if there are no inserted rows */ if (inserted <= 0) continue;
/* Triggers on foreign tables should not have transition tables */
Assert(resultRelInfo->ri_TrigDesc == NULL ||
resultRelInfo->ri_TrigDesc->trig_insert_new_table == false);
/* Run AFTER ROW INSERT triggers */ if (resultRelInfo->ri_TrigDesc != NULL &&
resultRelInfo->ri_TrigDesc->trig_insert_after_row)
{
Oid relid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
for (i = 0; i < inserted; i++)
{
TupleTableSlot *slot = rslots[i];
/* Update the row counter and progress of the COPY command */
*processed += inserted;
pgstat_progress_update_param(PROGRESS_COPY_TUPLES_PROCESSED,
*processed);
}
for (i = 0; i < nused; i++)
ExecClearTuple(slots[i]);
for (i = 0; i < nused; i++)
{ /* *Ifthereareanyindexes,updatethemforalltheinserted *tuples,andrunAFTERROWINSERTtriggers.
*/ if (resultRelInfo->ri_NumIndices > 0)
{
List *recheckIndexes;
/* Update the row counter and progress of the COPY command */
*processed += nused;
pgstat_progress_update_param(PROGRESS_COPY_TUPLES_PROCESSED,
*processed);
/* reset cur_lineno and line_buf_valid to what they were */
cstate->line_buf_valid = line_buf_valid;
cstate->cur_lineno = save_cur_lineno;
}
/* Mark that all slots are free */
buffer->nused = 0;
}
/* Since we only create slots on demand, just drop the non-null ones. */ for (i = 0; i < MAX_BUFFERED_TUPLES && buffer->slots[i] != NULL; i++)
ExecDropSingleTupleTableSlot(buffer->slots[i]);
if (resultRelInfo->ri_FdwRoutine == NULL)
table_finish_bulk_insert(resultRelInfo->ri_RelationDesc,
miinfo->ti_options);
/* *Optimizeifnewrelationstoragewascreatedinthissubxactoroneof *itscommittedchildrenandwewon'tseethoserowslateraspartofan *earlierscanorcommand.Thesubxacttestensuresthatifthissubxact *abortsthenthefrozenrowswon'tbevisibleafterxactcleanup.Note *thatthestrongertestofexactlywhichsubtransactioncreateditis *crucialforcorrectnessofthisoptimization.Thetestforanearlier *scanorcommandtoleratesfalsenegatives.FREEZEcausesothersessions *toseerowstheywouldnotseeunderMVCC,andafalsenegativemerely *spreadsthatanomalytothecurrentsession.
*/ if (cstate->opts.freeze)
{ /* *WecurrentlydisallowCOPYFREEZEonpartitionedtables.The *reasonforthisisthatwe'vesimplynotyetopenedthepartitions *todetermineiftheoptimizationcanbeappliedtothem.Wecould *goandopenthemallhere,butdoingsomaybequiteacostly *overheadforsmallcopies.Inanycase,wemayjustenduprouting *tuplestoasmallnumberofpartitions.Itseemsbetterjustto *raiseanERRORforpartitionedtables.
*/ if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot perform COPY FREEZE on a partitioned table")));
}
/* There's currently no support for COPY FREEZE on foreign tables. */ if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot perform COPY FREEZE on a foreign table")));
/* *TolerateoneregistrationforthebenefitofFirstXactSnapshot. *Scan-bearingqueriesgenerallycreateatleasttworegistrations, *thoughrelyingonthatisfragile,asisignoringActiveSnapshot. *ClearCatalogSnapshottoavoidcountingitsregistration.We'll *stilldetectongoingcatalogscans,eachofwhichseparately *registersthesnapshotituses.
*/
InvalidateCatalogSnapshot(); if (!ThereAreNoPriorRegisteredSnapshots() || !ThereAreNoReadyPortals())
ereport(ERROR,
(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
errmsg("cannot perform COPY FREEZE because of prior transaction activity")));
if (cstate->rel->rd_createSubid != GetCurrentSubTransactionId() &&
cstate->rel->rd_newRelfilelocatorSubid != GetCurrentSubTransactionId())
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
/* Set up callback to identify error line number */
errcallback.callback = CopyFromErrorCallback;
errcallback.arg = cstate;
errcallback.previous = error_context_stack;
error_context_stack = &errcallback;
for (;;)
{
TupleTableSlot *myslot; bool skip_tuple;
/* Report that this tuple was skipped by the ON_ERROR clause */
pgstat_progress_update_param(PROGRESS_COPY_TUPLES_SKIPPED,
cstate->num_errors);
if (cstate->opts.reject_limit > 0 &&
cstate->num_errors > cstate->opts.reject_limit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("skipped more than REJECT_LIMIT (%" PRId64 ") rows due to data type incompatibility",
cstate->opts.reject_limit)));
/* Repeat NextCopyFrom() until no soft error occurs */ continue;
}
if (prevResultRelInfo != resultRelInfo)
{ /* Determine which triggers exist on this partition */
has_before_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_before_row);
/* Set the multi-insert buffer to use for this partition. */ if (leafpart_use_multi_insert)
{ if (resultRelInfo->ri_CopyMultiInsertBuffer == NULL)
CopyMultiInsertInfoSetupBuffer(&multiInsertInfo,
resultRelInfo);
} elseif (insertMethod == CIM_MULTI_CONDITIONAL &&
!CopyMultiInsertInfoIsEmpty(&multiInsertInfo))
{ /* *Flushpendinginsertsifthispartitioncan'tuse *batching,sorowsarevisibletotriggersetc.
*/
CopyMultiInsertInfoFlush(&multiInsertInfo,
resultRelInfo,
&processed);
}
if (bistate != NULL)
ReleaseBulkInsertStatePin(bistate);
prevResultRelInfo = resultRelInfo;
}
/* Store the slot in the multi-insert buffer, when enabled. */ if (insertMethod == CIM_MULTI || leafpart_use_multi_insert)
{ /* *Theslotpreviouslymightpointintotheper-tuple *context.Forbatchingitneedstobelongerlived.
*/
ExecMaterializeSlot(myslot);
/* Add this tuple to the tuple buffer */
CopyMultiInsertInfoStore(&multiInsertInfo,
resultRelInfo, myslot,
cstate->line_buf.len,
cstate->cur_lineno);
/* *Ifenoughinsertshavequeuedup,thenflushall *buffersouttotheirtables.
*/ if (CopyMultiInsertInfoIsFull(&multiInsertInfo))
CopyMultiInsertInfoFlush(&multiInsertInfo,
resultRelInfo,
&processed);
/* *Wedelayupdatingtherowcounterandprogressofthe *COPYcommanduntilafterwritingthetuplesstoredin *thebufferouttothetable,asinsingleinsertmode. *SeeCopyMultiInsertBufferFlush().
*/ continue; /* next tuple please */
} else
{
List *recheckIndexes = NIL;
/* OK, store the tuple */ if (resultRelInfo->ri_FdwRoutine != NULL)
{
myslot = resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate,
resultRelInfo,
myslot,
NULL);
if (myslot == NULL) /* "do nothing" */ continue; /* next tuple please */
/* *AFTERROWTriggersmightreferencethetableoid *column,so(re-)initializetts_tableOidbefore *evaluatingthem.
*/
myslot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
} else
{ /* OK, store the tuple and create index entries for it */
table_tuple_insert(resultRelInfo->ri_RelationDesc,
myslot, mycid, ti_options, bistate);
/* Flush any remaining buffered tuples */ if (insertMethod != CIM_SINGLE)
{ if (!CopyMultiInsertInfoIsEmpty(&multiInsertInfo))
CopyMultiInsertInfoFlush(&multiInsertInfo, NULL, &processed);
}
/* Done, clean up */
error_context_stack = errcallback.previous;
if (cstate->opts.on_error != COPY_ON_ERROR_STOP &&
cstate->num_errors > 0 &&
cstate->opts.log_verbosity >= COPY_LOG_VERBOSITY_DEFAULT)
ereport(NOTICE,
errmsg_plural("%" PRIu64 " row was skipped due to data type incompatibility", "%" PRIu64 " rows were skipped due to data type incompatibility",
cstate->num_errors,
cstate->num_errors));
if (bistate != NULL)
FreeBulkInsertState(bistate);
MemoryContextSwitchTo(oldcontext);
/* Execute AFTER STATEMENT insertion triggers */
ExecASInsertTriggers(estate, target_resultRelInfo, cstate->transition_capture);
/* Handle queued AFTER triggers */
AfterTriggerEndQuery(estate);
/* Allow the FDW to shut down */ if (target_resultRelInfo->ri_FdwRoutine != NULL &&
target_resultRelInfo->ri_FdwRoutine->EndForeignInsert != NULL)
target_resultRelInfo->ri_FdwRoutine->EndForeignInsert(estate,
target_resultRelInfo);
/* Tear down the multi-insert buffer data */ if (insertMethod != CIM_SINGLE)
CopyMultiInsertInfoCleanup(&multiInsertInfo);
/* Close all the partitioned tables, leaf partitions, and their indices */ if (proute)
ExecCleanupTupleRouting(mtstate, proute);
/* Close the result relations, including any trigger target relations */
ExecCloseResultRelations(estate);
ExecCloseRangeTableRelations(estate);
if (!list_member_int(cstate->attnumlist, attnum))
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE), /*- translator: first %s is the name of a COPY option, e.g. FORCE_NOT_NULL */
errmsg("%s column \"%s\" not referenced by COPY", "FORCE_NOT_NULL", NameStr(attr->attname))));
cstate->opts.force_notnull_flags[attnum - 1] = true;
}
}
/* Set up soft error handler for ON_ERROR */ if (cstate->opts.on_error != COPY_ON_ERROR_STOP)
{
cstate->escontext = makeNode(ErrorSaveContext);
cstate->escontext->type = T_ErrorSaveContext;
cstate->escontext->error_occurred = false;
if (!list_member_int(cstate->attnumlist, attnum))
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE), /*- translator: first %s is the name of a COPY option, e.g. FORCE_NOT_NULL */
errmsg("%s column \"%s\" not referenced by COPY", "FORCE_NULL", NameStr(attr->attname))));
cstate->opts.force_null_flags[attnum - 1] = true;
}
}
/* Convert convert_selectively name list to per-column flags */ if (cstate->opts.convert_selectively)
{
List *attnums;
ListCell *cur;
if (!list_member_int(cstate->attnumlist, attnum))
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg_internal("selected column \"%s\" not referenced by COPY",
NameStr(attr->attname))));
cstate->convert_select_flags[attnum - 1] = true;
}
}
/* Use client encoding when ENCODING option is not specified. */ if (cstate->opts.file_encoding < 0)
cstate->file_encoding = pg_get_client_encoding(); else
cstate->file_encoding = cstate->opts.file_encoding;
/* *Lookupencodingconversionfunction.
*/ if (cstate->file_encoding == GetDatabaseEncoding() ||
cstate->file_encoding == PG_SQL_ASCII ||
GetDatabaseEncoding() == PG_SQL_ASCII)
{
cstate->need_transcoding = false;
} else
{
cstate->need_transcoding = true;
cstate->conversion_proc = FindDefaultConversionProc(cstate->file_encoding,
GetDatabaseEncoding()); if (!OidIsValid(cstate->conversion_proc))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("default conversion function for encoding \"%s\" to \"%s\" does not exist",
pg_encoding_to_char(cstate->file_encoding),
pg_encoding_to_char(GetDatabaseEncoding()))));
}
/* Assign range table and rteperminfos, we'll need them in CopyFrom. */ if (pstate)
{
cstate->range_table = pstate->p_rtable;
cstate->rteperminfos = pstate->p_rteperminfos;
}
for (int attnum = 1; attnum <= num_phys_attrs; attnum++)
{
Form_pg_attribute att = TupleDescAttr(tupDesc, attnum - 1);
/* We don't need info for dropped attributes */ if (att->attisdropped) continue;
/* Fetch the input function and typioparam info */
cstate->routine->CopyFromInFunc(cstate, att->atttypid,
&in_functions[attnum - 1],
&typioparams[attnum - 1]);
/* Get default info if available */
defexprs[attnum - 1] = NULL;
/* if NOT copied from input */ /* use default value if one exists */ if (!list_member_int(cstate->attnumlist, attnum))
{
defmap[num_defaults] = attnum - 1;
num_defaults++;
}
/* 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 (data_source_cb)
{
progress_vals[1] = PROGRESS_COPY_TYPE_CALLBACK;
cstate->copy_src = COPY_CALLBACK;
cstate->data_source_cb = data_source_cb;
} elseif (pipe)
{
progress_vals[1] = PROGRESS_COPY_TYPE_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)
{
progress_vals[1] = PROGRESS_COPY_TYPE_PROGRAM;
cstate->copy_file = OpenPipeStream(cstate->filename, PG_BINARY_R); if (cstate->copy_file == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not execute command \"%s\": %m",
cstate->filename)));
} else
{ struct stat st;
progress_vals[1] = PROGRESS_COPY_TYPE_FILE;
cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_R); if (cstate->copy_file == NULL)
{ /* copy errno because ereport subfunctions might change it */ int save_errno = errno;
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open file \"%s\" for reading: %m",
cstate->filename),
(save_errno == ENOENT || save_errno == EACCES) ?
errhint("COPY FROM instructs the PostgreSQL server process to read a file. " "You may want a client-side facility such as psql's \\copy.") : 0));
}
if (fstat(fileno(cstate->copy_file), &st))
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not stat file \"%s\": %m",
cstate->filename)));
if (S_ISDIR(st.st_mode))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is a directory", cstate->filename)));
/* *CleanupstorageandreleaseresourcesforCOPYFROM.
*/ void
EndCopyFrom(CopyFromState cstate)
{ /* Invoke the end callback */
cstate->routine->CopyFromEnd(cstate);
/* No COPY FROM related resources except memory. */ if (cstate->is_program)
{
ClosePipeFromProgram(cstate);
} else
{ if (cstate->filename != NULL && FreeFile(cstate->copy_file))
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not close file \"%s\": %m",
cstate->filename)));
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.42Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.