copy.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,233 行 · 第 1/4 页
C
2,233 行
if (!skip_tuple) { /* Place tuple in tuple slot */ ExecStoreTuple(tuple, slot, InvalidBuffer, false); /* * Check the constraints of the tuple */ if (rel->rd_att->constr) ExecConstraints(resultRelInfo, slot, estate); /* * OK, store the tuple and create index entries for it */ simple_heap_insert(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); pfree(values); pfree(nulls); if (!binary) { pfree(in_functions); pfree(elements); } ExecDropTupleTable(tupleTable, true); 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. */static boolCopyReadLine(void){ bool result; bool change_encoding = (client_encoding != server_encoding); int c; int mblen; int j; unsigned char s[2]; char *cvt; s[1] = 0; /* reset line_buf to empty */ line_buf.len = 0; line_buf.data[0] = '\0'; line_buf.cursor = 0; /* mark that encoding conversion hasn't occurred yet */ line_buf_converted = false; /* set default status */ result = false; /* * In this loop 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 * CopyReadAttribute does its own escape processing. These four * characters, and only these four, are assumed the same in frontend * and backend encodings. We do not assume that second and later bytes * of a frontend multibyte character couldn't look like ASCII characters. */ for (;;) { c = CopyGetChar(); if (c == EOF) { result = true; break; } if (c == '\r') { if (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."))); /* Check for \r\n on first line, _and_ handle \r\n. */ if (eol_type == EOL_UNKNOWN || eol_type == EOL_CRNL) { int c2 = CopyPeekChar(); if (c2 == '\n') { CopyDonePeek(c2, true); /* eat newline */ eol_type = EOL_CRNL; } else { /* found \r, but no \n */ if (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 * get \n, so put it back */ CopyDonePeek(c2, false); eol_type = EOL_CR; } } break; } if (c == '\n') { if (eol_type == EOL_CR || eol_type == EOL_CRNL) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("literal newline found in data"), errhint("Use \"\\n\" to represent newline."))); eol_type = EOL_NL; break; } if (c == '\\') { c = CopyGetChar(); if (c == EOF) { result = true; break; } if (c == '.') { if (eol_type == EOL_CRNL) { c = CopyGetChar(); 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"))); } c = CopyGetChar(); if (c != '\r' && c != '\n') ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("end-of-copy marker corrupt"))); if ((eol_type == EOL_NL && c != '\n') || (eol_type == EOL_CRNL && c != '\n') || (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"))); /* * 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 (copy_dest == COPY_NEW_FE) { while (c != EOF) c = CopyGetChar(); } result = true; /* report EOF */ break; } /* not EOF mark, so emit \ and following char literally */ appendStringInfoCharMacro(&line_buf, '\\'); } appendStringInfoCharMacro(&line_buf, c); /* * When client encoding != server, must be careful to read the * extra bytes of a multibyte character exactly, since the encoding * might not ensure they don't look like ASCII. When the encodings * are the same, we need not do this, since no server encoding we * use has ASCII-like following bytes. */ if (change_encoding) { s[0] = c; mblen = pg_encoding_mblen(client_encoding, s); for (j = 1; j < mblen; j++) { c = CopyGetChar(); if (c == EOF) { result = true; break; } appendStringInfoCharMacro(&line_buf, c); } if (result) break; /* out of outer loop */ } } /* end of outer loop */ /* * Done reading the line. Convert it to server encoding. * * Note: set line_buf_converted to true *before* attempting conversion; * this prevents infinite recursion during error reporting should * pg_client_to_server() issue an error, due to copy_in_error_callback * again attempting the same conversion. We'll end up issuing the message * without conversion, which is bad but better than nothing ... */ line_buf_converted = true; if (change_encoding) { cvt = (char *) pg_client_to_server((unsigned char *) line_buf.data, line_buf.len); if (cvt != line_buf.data) { /* transfer converted data back to line_buf */ line_buf.len = 0; line_buf.data[0] = '\0'; appendBinaryStringInfo(&line_buf, cvt, strlen(cvt)); } } return result;}/*---------- * Read the value of a single attribute, performing de-escaping as needed. * * delim is the column delimiter string (must be just one byte for now). * null_print is the null marker string. Note that this is compared to * the pre-de-escaped input string. * * *result is set to indicate what terminated the read: * NORMAL_ATTR: column delimiter * END_OF_LINE: end of line * In either case, the string read up to the terminator is returned. * * *isnull is set true or false depending on whether the input matched * the null marker. Note that the caller cannot check this since the * returned string will be the post-de-escaping equivalent, which may * look the same as some valid data string. *---------- */static char *CopyReadAttribute(const char *delim, const char *null_print, CopyReadResult *result, bool *isnull){ char c; char delimc = delim[0]; int start_cursor = line_buf.cursor; int end_cursor; int input_len; /* reset attribute_buf to empty */ attribute_buf.len = 0; attribute_buf.data[0] = '\0'; /* set default status */ *result = END_OF_LINE; for (;;) { end_cursor = line_buf.cursor; if (line_buf.cursor >= line_buf.len) break; c = line_buf.data[line_buf.cursor++]; if (c == delimc) { *result = NORMAL_ATTR; break; } if (c == '\\') { if (line_buf.cursor >= line_buf.len) break; c = line_buf.data[line_buf.cursor++]; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int val; val = OCTVALUE(c); if (line_buf.cursor < line_buf.len) { c = line_buf.data[line_buf.cursor]; if (ISOCTAL(c)) { line_buf.cursor++; val = (val << 3) + OCTVALUE(c); if (line_buf.cursor < line_buf.len) { c = line_buf.data[line_buf.cursor]; if (ISOCTAL(c)) { line_buf.cursor++; val = (val << 3) + OCTVALUE(c); } } } } c = val & 0377; } break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; /* * in all other cases, take the char after '\' literally */ } } appendStringInfoCharMacro(&attribute_buf, c); } /* check whether raw input matched null marker */ input_len = end_cursor - start_cursor; if (input_len == strlen(null_print) && strncmp(&line_buf.data[start_cursor], null_print, input_len) == 0) *isnull = true; else *isnull = false; return attribute_buf.data;}/* * Read a binary attribute */static DatumCopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem, bool *isnull){ int32 fld_size; Datum result; fld_size = CopyGetInt32(); if (CopyGetEof()) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("unexpected EOF in COPY data"))); if (fld_size == -1) { *isnull = true; return (Datum) 0; } if (fld_size < 0) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("invalid field size"))); /* reset attribute_buf to empty, and load raw data in it */ attribute_buf.len = 0; attribute_buf.data[0] = '\0'; attribute_buf.cursor = 0; enlargeStringInfo(&attribute_buf, fld_size); CopyGetData(attribute_buf.data, fld_size); if (CopyGetEof()) ereport(ERROR, (errcode(ERRCODE_BAD_COPY_FILE_FORMAT), errmsg("unexpected EOF in COPY data"))); attribute_buf.len = fld_size; attribute_buf.data[fld_size] = '\0'; /* Call the column type's binary input converter */ result = FunctionCall2(flinfo, PointerGetDatum(&attribute_buf), ObjectIdGetDatum(typelem)); /* Trouble if it didn't eat the whole buffer */ if (attribute_buf.cursor != attribute_buf.len) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("incorrect binary data format"))); *isnull = false; return result;}/* * Send text representation of one attribute, with conversion and escaping */static voidCopyAttributeOut(char *server_string, char *delim){ char *string; char c; char delimc = delim[0]; bool same_encoding; int mblen; int i; same_encoding = (server_encoding == client_encoding); if (!same_encoding) string = (char *) pg_server_to_client((unsigned char *) server_string, strlen(server_string)); else string = server_string; for (; (c = *string) != '\0'; string += mblen) { mblen = 1; switch (c) { case '\b': CopySendString("\\b"); break; case '\f': CopySendString("\\f"); break; case '\n': CopySendString("\\n"); break; case '\r': CopySendString("\\r"); break; case '\t': CopySendString("\\t"); break; case '\v': CopySendString("\\v"); break; case '\\': CopySendString("\\\\"); break; default: if (c == delimc) CopySendChar('\\'); CopySendChar(c); /* * We can skip pg_encoding_mblen() overhead when encoding * is same, because in valid backend encodings, extra * bytes of a multibyte character never look like ASCII. */ if (!same_encoding) { /* send additional bytes of the char, if any */ mblen = pg_encoding_mblen(client_encoding, string); for (i = 1; i < mblen; i++) CopySendChar(string[i]); } break; } }}/* * CopyGetAttnums - build an integer list of attnums to be copied * * The input attnamelist is either the user-specified column list, * or NIL if there was none (in which case we want all the non-dropped * columns). */static List *CopyGetAttnums(Relation rel, List *attnamelist){ List *attnums = NIL; if (attnamelist == NIL) { /* Generate default column list */ TupleDesc tupDesc = RelationGetDescr(rel); Form_pg_attribute *attr = tupDesc->attrs; int attr_count = tupDesc->natts; int i; for (i = 0; i < attr_count; i++) { if (attr[i]->attisdropped) continue; attnums = lappendi(attnums, i + 1); } } else { /* Validate the user-supplied list and extract attnums */ List *l; foreach(l, attnamelist) { char *name = strVal(lfirst(l)); int attnum; /* Lookup column name, ereport on failure */ /* Note we disallow system columns here */ attnum = attnameAttNum(rel, name, false); /* Check for duplicates */ if (intMember(attnum, attnums)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column \"%s\" specified more than once", name))); attnums = lappendi(attnums, attnum); } } return attnums;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?