📄 pg_backup_db.c
字号:
appendBinaryPQExpBuffer(AH->pgCopyBuf, qry, (eos - qry)); return eos; } /* * fprintf(stderr, "Found cr at %d, prev char was %c, next was %c\n", * loc, qry[loc-1], qry[loc+1]); */ /* Count the number of preceding slashes */ sPos = loc; while (sPos > 0 && qry[sPos - 1] == '\\') sPos--; sPos = loc - sPos; /* * If an odd number of preceding slashes, then \n was escaped so set * the next search pos, and loop (if any left). */ if ((sPos & 1) == 1) { /* fprintf(stderr, "cr was escaped\n"); */ pos = loc + 1; if (pos >= (eos - qry)) { appendBinaryPQExpBuffer(AH->pgCopyBuf, qry, (eos - qry)); return eos; } } else break; } /* We found an unquoted newline */ qry[loc] = '\0'; appendPQExpBuffer(AH->pgCopyBuf, "%s\n", qry); isEnd = (strcmp(AH->pgCopyBuf->data, "\\.\n") == 0); /* * Note that we drop the data on the floor if libpq has failed to * enter COPY mode; this allows us to behave reasonably when trying * to continue after an error in a COPY command. */ if (AH->pgCopyIn && PQputline(AH->connection, AH->pgCopyBuf->data) != 0) die_horribly(AH, modulename, "error returned by PQputline: %s", PQerrorMessage(AH->connection)); resetPQExpBuffer(AH->pgCopyBuf); /* * fprintf(stderr, "Buffer is '%s'\n", AH->pgCopyBuf->data); */ if (isEnd) { if (AH->pgCopyIn && PQendcopy(AH->connection) != 0) die_horribly(AH, modulename, "error returned by PQendcopy: %s", PQerrorMessage(AH->connection)); AH->pgCopyIn = false; } return qry + loc + 1;}/* * Used by ExecuteSqlCommandBuf to send one buffered line of SQL * (not data for the copy command). */static char *_sendSQLLine(ArchiveHandle *AH, char *qry, char *eos){ /* * The following is a mini state machine to assess the end of an SQL * statement. It really only needs to parse good SQL, or at least that's * the theory... End-of-statement is assumed to be an unquoted, * un-commented semi-colon that's not within any parentheses. * * Note: the input can be split into bufferloads at arbitrary boundaries. * Therefore all state must be kept in AH->sqlparse, not in local * variables of this routine. We assume that AH->sqlparse was filled with * zeroes when created. */ for (; qry < eos; qry++) { switch (AH->sqlparse.state) { case SQL_SCAN: /* Default state == 0, set in _allocAH */ if (*qry == ';' && AH->sqlparse.braceDepth == 0) { /* * We've found the end of a statement. Send it and reset * the buffer. */ appendPQExpBufferChar(AH->sqlBuf, ';'); /* inessential */ ExecuteSqlCommand(AH, AH->sqlBuf, "could not execute query"); resetPQExpBuffer(AH->sqlBuf); AH->sqlparse.lastChar = '\0'; /* * Remove any following newlines - so that embedded COPY * commands don't get a starting newline. */ qry++; while (qry < eos && *qry == '\n') qry++; /* We've finished one line, so exit */ return qry; } else if (*qry == '\'') { if (AH->sqlparse.lastChar == 'E') AH->sqlparse.state = SQL_IN_E_QUOTE; else AH->sqlparse.state = SQL_IN_SINGLE_QUOTE; AH->sqlparse.backSlash = false; } else if (*qry == '"') { AH->sqlparse.state = SQL_IN_DOUBLE_QUOTE; } /* * Look for dollar-quotes. We make the assumption that * $-quotes will not have an ident character just before them * in pg_dump output. XXX is this good enough? */ else if (*qry == '$' && !_isIdentChar(AH->sqlparse.lastChar)) { AH->sqlparse.state = SQL_IN_DOLLAR_TAG; /* initialize separate buffer with possible tag */ if (AH->sqlparse.tagBuf == NULL) AH->sqlparse.tagBuf = createPQExpBuffer(); else resetPQExpBuffer(AH->sqlparse.tagBuf); appendPQExpBufferChar(AH->sqlparse.tagBuf, *qry); } else if (*qry == '-' && AH->sqlparse.lastChar == '-') AH->sqlparse.state = SQL_IN_SQL_COMMENT; else if (*qry == '*' && AH->sqlparse.lastChar == '/') AH->sqlparse.state = SQL_IN_EXT_COMMENT; else if (*qry == '(') AH->sqlparse.braceDepth++; else if (*qry == ')') AH->sqlparse.braceDepth--; break; case SQL_IN_SQL_COMMENT: if (*qry == '\n') AH->sqlparse.state = SQL_SCAN; break; case SQL_IN_EXT_COMMENT: /* * This isn't fully correct, because we don't account for * nested slash-stars, but pg_dump never emits such. */ if (AH->sqlparse.lastChar == '*' && *qry == '/') AH->sqlparse.state = SQL_SCAN; break; case SQL_IN_SINGLE_QUOTE: /* We needn't handle '' specially */ if (*qry == '\'' && !AH->sqlparse.backSlash) AH->sqlparse.state = SQL_SCAN; else if (*qry == '\\') AH->sqlparse.backSlash = !AH->sqlparse.backSlash; else AH->sqlparse.backSlash = false; break; case SQL_IN_E_QUOTE: /* * Eventually we will need to handle '' specially, because * after E'...''... we should still be in E_QUOTE state. * * XXX problem: how do we tell whether the dump was made by a * version that thinks backslashes aren't special in non-E * literals?? */ if (*qry == '\'' && !AH->sqlparse.backSlash) AH->sqlparse.state = SQL_SCAN; else if (*qry == '\\') AH->sqlparse.backSlash = !AH->sqlparse.backSlash; else AH->sqlparse.backSlash = false; break; case SQL_IN_DOUBLE_QUOTE: /* We needn't handle "" specially */ if (*qry == '"') AH->sqlparse.state = SQL_SCAN; break; case SQL_IN_DOLLAR_TAG: if (*qry == '$') { /* Do not add the closing $ to tagBuf */ AH->sqlparse.state = SQL_IN_DOLLAR_QUOTE; AH->sqlparse.minTagEndPos = AH->sqlBuf->len + AH->sqlparse.tagBuf->len + 1; } else if (_isDQChar(*qry, (AH->sqlparse.tagBuf->len == 1))) { /* Valid, so add to tag */ appendPQExpBufferChar(AH->sqlparse.tagBuf, *qry); } else { /* * Ooops, we're not really in a dollar-tag. Valid tag * chars do not include the various chars we look for in * this state machine, so it's safe to just jump from this * state back to SCAN. We have to back up the qry pointer * so that the current character gets rescanned in SCAN * state; and then "continue" so that the bottom-of-loop * actions aren't done yet. */ AH->sqlparse.state = SQL_SCAN; qry--; continue; } break; case SQL_IN_DOLLAR_QUOTE: /* * If we are at a $, see whether what precedes it matches * tagBuf. (Remember that the trailing $ of the tag was not * added to tagBuf.) However, don't compare until we have * enough data to be a possible match --- this is needed to * avoid false match on '$a$a$...' */ if (*qry == '$' && AH->sqlBuf->len >= AH->sqlparse.minTagEndPos && strcmp(AH->sqlparse.tagBuf->data, AH->sqlBuf->data + AH->sqlBuf->len - AH->sqlparse.tagBuf->len) == 0) AH->sqlparse.state = SQL_SCAN; break; } appendPQExpBufferChar(AH->sqlBuf, *qry); AH->sqlparse.lastChar = *qry; } /* * If we get here, we've processed entire bufferload with no complete SQL * stmt */ return eos;}/* Convenience function to send one or more queries. Monitors result to handle COPY statements */intExecuteSqlCommandBuf(ArchiveHandle *AH, void *qryv, size_t bufLen){ char *qry = (char *) qryv; char *eos = qry + bufLen; /* * fprintf(stderr, "\n\n*****\n Buffer:\n\n%s\n*******************\n\n", * qry); */ /* Could switch between command and COPY IN mode at each line */ while (qry < eos) { /* * If libpq is in CopyIn mode *or* if the archive structure shows we * are sending COPY data, treat the data as COPY data. The pgCopyIn * check is only needed for backwards compatibility with ancient * archive files that might just issue a COPY command without marking * it properly. Note that in an archive entry that has a copyStmt, * all data up to the end of the entry will go to _sendCopyLine, and * therefore will be dropped if libpq has failed to enter COPY mode. * Also, if a "\." data terminator is found, anything remaining in the * archive entry will be dropped. */ if (AH->pgCopyIn || AH->writingCopyData) qry = _sendCopyLine(AH, qry, eos); else qry = _sendSQLLine(AH, qry, eos); } return 1;}voidStartTransaction(ArchiveHandle *AH){ PQExpBuffer qry = createPQExpBuffer(); appendPQExpBuffer(qry, "BEGIN"); ExecuteSqlCommand(AH, qry, "could not start database transaction"); destroyPQExpBuffer(qry);}voidCommitTransaction(ArchiveHandle *AH){ PQExpBuffer qry = createPQExpBuffer(); appendPQExpBuffer(qry, "COMMIT"); ExecuteSqlCommand(AH, qry, "could not commit database transaction"); destroyPQExpBuffer(qry);}static bool_isIdentChar(unsigned char c){ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '$') || (c >= (unsigned char) '\200') /* no need to check <= \377 */ ) return true; else return false;}static bool_isDQChar(unsigned char c, bool atStart){ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (!atStart && c >= '0' && c <= '9') || (c >= (unsigned char) '\200') /* no need to check <= \377 */ ) return true; else return false;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -