📄 copy.c
字号:
/* * 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++) { values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, &isnull, NULL); if (!isnull) nulls[defmap[i]] = ' '; } /* Next apply any domain constraints */ if (hasConstraints) { ParamExecData *prmdata = &econtext->ecxt_param_exec_vals[0]; for (i = 0; i < num_phys_attrs; i++) { ExprState *exprstate = constraintexprs[i]; if (exprstate == NULL) continue; /* no constraint for this attr */ /* Insert current row's value into the Param value */ prmdata->value = values[i]; prmdata->isnull = (nulls[i] == 'n'); /* * Execute the constraint expression. Allow the expression to * replace the value (consider e.g. a timestamp precision * restriction). */ values[i] = ExecEvalExpr(exprstate, econtext, &isnull, NULL); nulls[i] = isnull ? 'n' : ' '; } } /* And now we can form the input tuple. */ tuple = heap_formtuple(tupDesc, values, nulls); if (cstate->oids && file_has_oids) HeapTupleSetOid(tuple, loaded_oid); /* Triggers and stuff need to be invoked in query context. */ MemoryContextSwitchTo(oldcontext); skip_tuple = false; /* BEFORE ROW INSERT Triggers */ if (resultRelInfo->ri_TrigDesc && resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) { HeapTuple newtuple; newtuple = ExecBRInsertTriggers(estate, resultRelInfo, tuple); if (newtuple == NULL) /* "do nothing" */ skip_tuple = true; else if (newtuple != tuple) /* modified by Trigger(s) */ { heap_freetuple(tuple); tuple = newtuple; } } if (!skip_tuple) { /* Place tuple in tuple slot */ ExecStoreTuple(tuple, slot, InvalidBuffer, false); /* Check the constraints of the tuple */ if (cstate->rel->rd_att->constr) ExecConstraints(resultRelInfo, slot, estate); /* OK, store the tuple and create index entries for it */ simple_heap_insert(cstate->rel, tuple); if (resultRelInfo->ri_NumIndices > 0) ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); /* AFTER ROW INSERT Triggers */ ExecARInsertTriggers(estate, resultRelInfo, tuple); } } /* Done, clean up */ error_context_stack = errcontext.previous; MemoryContextSwitchTo(oldcontext); /* Execute AFTER STATEMENT insertion triggers */ ExecASInsertTriggers(estate, resultRelInfo); /* Handle queued AFTER triggers */ AfterTriggerEndQuery(estate); pfree(values); pfree(nulls); pfree(field_strings); pfree(in_functions); pfree(typioparams); pfree(defmap); pfree(defexprs); pfree(constraintexprs); pfree(force_notnull); ExecDropSingleTupleTableSlot(slot); ExecCloseIndices(resultRelInfo); FreeExecutorState(estate);}/* * Read the next input line and stash it in line_buf, with conversion to * server encoding. * * Result is true if read was terminated by EOF, false if terminated * by newline. The terminating newline or EOF marker is not included * in the final value of line_buf. */static boolCopyReadLine(CopyState cstate){ bool result; /* Reset line_buf to empty */ cstate->line_buf.len = 0; cstate->line_buf.data[0] = '\0'; /* Mark that encoding conversion hasn't occurred yet */ cstate->line_buf_converted = false; /* Parse data and transfer into line_buf */ if (cstate->csv_mode) result = CopyReadLineCSV(cstate); else result = CopyReadLineText(cstate); if (result) { /* * Reached EOF. In protocol version 3, we should ignore anything * after \. up to the protocol end of copy data. (XXX maybe better * not to treat \. as special?) */ if (cstate->copy_dest == COPY_NEW_FE) { do { cstate->raw_buf_index = cstate->raw_buf_len; } while (CopyLoadRawBuf(cstate)); } } else { /* * If we didn't hit EOF, then we must have transferred the EOL marker * to line_buf along with the data. Get rid of it. */ switch (cstate->eol_type) { case EOL_NL: Assert(cstate->line_buf.len >= 1); Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n'); cstate->line_buf.len--; cstate->line_buf.data[cstate->line_buf.len] = '\0'; break; case EOL_CR: Assert(cstate->line_buf.len >= 1); Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r'); cstate->line_buf.len--; cstate->line_buf.data[cstate->line_buf.len] = '\0'; break; case EOL_CRNL: Assert(cstate->line_buf.len >= 2); Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r'); Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n'); cstate->line_buf.len -= 2; cstate->line_buf.data[cstate->line_buf.len] = '\0'; break; case EOL_UNKNOWN: /* shouldn't get here */ Assert(false); break; } } /* Done reading the line. Convert it to server encoding. */ if (cstate->need_transcoding) { char *cvt; cvt = pg_client_to_server(cstate->line_buf.data, cstate->line_buf.len); if (cvt != cstate->line_buf.data) { /* transfer converted data back to line_buf */ cstate->line_buf.len = 0; cstate->line_buf.data[0] = '\0'; appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); pfree(cvt); } } /* Now it's safe to use the buffer in error messages */ cstate->line_buf_converted = true; return result;}/* * CopyReadLineText - inner loop of CopyReadLine for non-CSV mode * * If you need to change this, better look at CopyReadLineCSV too */static boolCopyReadLineText(CopyState cstate){ bool result; char *copy_raw_buf; int raw_buf_ptr; int copy_buf_len; bool need_data; bool hit_eof; char s[2]; s[1] = 0; /* set default status */ result = false; /* * The objective of this loop is to transfer the entire next input line * into line_buf. Hence, we only care for detecting newlines (\r and/or * \n) and the end-of-copy marker (\.). * * For backwards compatibility we allow backslashes to escape newline * characters. Backslashes other than the end marker get put into the * line_buf, since CopyReadAttributesText does its own escape processing. * * These four characters, and only these four, are assumed the same in * frontend and backend encodings. * * For speed, we try to move data to line_buf in chunks rather than one * character at a time. raw_buf_ptr points to the next character to * examine; any characters from raw_buf_index to raw_buf_ptr have been * determined to be part of the line, but not yet transferred to line_buf. * * For a little extra speed within the loop, we copy raw_buf and * raw_buf_len into local variables. */ copy_raw_buf = cstate->raw_buf; raw_buf_ptr = cstate->raw_buf_index; copy_buf_len = cstate->raw_buf_len; need_data = false; /* flag to force reading more data */ hit_eof = false; /* flag indicating no more data available */ for (;;) { int prev_raw_ptr; char c; /* Load more data if needed */ if (raw_buf_ptr >= copy_buf_len || need_data) { /* * Transfer any approved data to line_buf; must do this to be sure * there is some room in raw_buf. */ if (raw_buf_ptr > cstate->raw_buf_index) { appendBinaryStringInfo(&cstate->line_buf, cstate->raw_buf + cstate->raw_buf_index, raw_buf_ptr - cstate->raw_buf_index); cstate->raw_buf_index = raw_buf_ptr; } /* * Try to read some more data. This will certainly reset * raw_buf_index to zero, and raw_buf_ptr must go with it. */ if (!CopyLoadRawBuf(cstate)) hit_eof = true; raw_buf_ptr = 0; copy_buf_len = cstate->raw_buf_len; /* * If we are completely out of data, break out of the loop, * reporting EOF. */ if (copy_buf_len <= 0) { result = true; break; } need_data = false; } /* OK to fetch a character */ prev_raw_ptr = raw_buf_ptr; c = copy_raw_buf[raw_buf_ptr++]; if (c == '\r') { /* Check for \r\n on first line, _and_ handle \r\n. */ if (cstate->eol_type == EOL_UNKNOWN || cstate->eol_type == EOL_CRNL) { /* * If need more data, go back to loop top to load it. * * Note that if we are at EOF, c will wind up as '\0' because * of the guaranteed pad of raw_buf. */ if (raw_buf_ptr >= copy_buf_len && !hit_eof) { raw_buf_ptr = prev_raw_ptr; /* undo fetch */ need_data = true; continue; } c = copy_raw_buf[raw_buf_ptr]; if (c == '\n') { raw_buf_ptr++; /* eat newline */ cstate->eol_type = EOL_CRNL; /* in case not set yet */ } else { /* found \r, but no \n */ if (cstate->eol_type == EOL_CRNL) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("literal carriage return found in data"), errhint("Use \"\\r\" to represent carriage return."))); /* * if we got here, it is the first line and we didn't find * \n, so don't consume the peeked character */ cstate->eol_type = EOL_CR; } } else if (cstate->eol_type == EOL_NL) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("literal carriage return found in data"), errhint("Use \"\\r\" to represent carriage return."))); /* If reach here, we have found the line terminator */ break; } if (c == '\n') { if (cstate->eol_type == EOL_CR || cstate->eol_type == EOL_CRNL) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("literal newline found in data"), errhint("Use \"\\n\" to represent newline."))); cstate->eol_type = EOL_NL; /* in case not set yet */ /* If reach here, we have found the line terminator */ break; } if (c == '\\') { /* * If need more data, go back to loop top to load it. */ if (raw_buf_ptr >= copy_buf_len) { if (hit_eof) { /* backslash just before EOF, treat as data char */ result = true; break; } raw_buf_ptr = prev_raw_ptr; /* undo fetch */ need_data = true; continue; } /* * In non-CSV mode, backslash quotes the following character even * if it's a newline, so we always advance to next character */ c = copy_raw_buf[raw_buf_ptr++]; if (c == '.') { if (cstate->eol_type == EOL_CRNL) { if (raw_buf_ptr >= copy_buf_len && !hit_eof) { raw_buf_ptr = prev_raw_ptr; /* undo fetch */ need_data = true; continue; } /* if hit_eof, c will become '\0' */ c = copy_raw_buf[raw_buf_ptr++]; if (c == '\n') ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("end-of-copy marker does not match previous newline style"))); if (c != '\r') ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("end-of-copy marker corrupt"))); } if (raw_buf_ptr >= copy_buf_len && !hit_eof) { raw_buf_ptr = prev_raw_ptr; /* undo fetch */ need_data = true; continue; } /* if hit_eof, c will become '\0' */ c = copy_raw_buf[raw_buf_ptr++]; if (c != '\r' && c != '\n') ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("end-of-copy marker corrupt"))); if ((cstate->eol_type == EOL_NL && c != '\n') || (cstate->eol_type == EOL_CRNL && c != '\n') || (cstate->eol_type == EOL_CR && c != '\r')) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("end-of-copy marker does not match previous newline style"))); /* * Transfer only the data before the \. into line_buf, then * discard the data and the \. sequence. */ if (prev_raw_ptr > cstate->raw_buf_index) appendBinaryStringInfo(&cstate->line_buf, cstate->raw_buf + cstate->raw_buf_index, prev_raw_ptr - cstate->raw_buf_index); cstate->raw_buf_index = raw_buf_ptr; result = true; /* report EOF */ break; } } /* * Do we need to be careful about trailing bytes of multibyte * characters? (See note above about client_only_encoding) * * We assume here that pg_encoding_mblen only looks at the first byte * of the character! */ if (cstate->client_only_encoding) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -