#ifndef MYSQLXX_MANIP_H #define MYSQLXX_MANIP_H #include #include #include #include #include namespace mysqlxx { /** @brief Манипулятор ostream, который escape-ит строки для записи в tab delimited файл. * Использование: tab_separated_ostr << mysqlxx::escape << x; */ enum escape_enum { escape }; /** @brief Манипулятор ostream, который quote-ит строки для записи в MySQL запрос. * Внимание! Не использует функции MySQL API, а использует свой метод quote-инга, * который может быть некорректным при использовании некоторых кодировок * (multi-byte attack), а также может оказаться некорректным при изменении libmysqlclient. * Это сделано для увеличения производительности и это имеет значение. * * Использование: query << mysqlxx::quote << x; */ enum quote_enum { quote }; struct EscapeManipResult { std::ostream & ostr; EscapeManipResult(std::ostream & ostr_) : ostr(ostr_) {} std::ostream & operator<< (bool value) { return ostr << value; } std::ostream & operator<< (char value) { return ostr << value; } std::ostream & operator<< (unsigned char value) { return ostr << value; } std::ostream & operator<< (signed char value) { return ostr << value; } std::ostream & operator<< (short value) { return ostr << value; } std::ostream & operator<< (unsigned short value) { return ostr << value; } std::ostream & operator<< (int value) { return ostr << value; } std::ostream & operator<< (unsigned int value) { return ostr << value; } std::ostream & operator<< (long value) { return ostr << value; } std::ostream & operator<< (unsigned long value) { return ostr << value; } std::ostream & operator<< (float value) { return ostr << value; } std::ostream & operator<< (double value) { return ostr << value; } std::ostream & operator<< (long long value) { return ostr << value; } std::ostream & operator<< (unsigned long long value) { return ostr << value; } std::ostream & operator<< (Date value) { return ostr << value; } std::ostream & operator<< (DateTime value) { return ostr << value; } std::ostream & operator<< (const std::string & value) { writeEscapedData(value.data(), value.length()); return ostr; } std::ostream & operator<< (const char * value) { while (const char * it = std::strpbrk(value, "\t\n\\")) { ostr.write(value, it - value); switch (*it) { case '\t': ostr.write("\\t", 2); break; case '\n': ostr.write("\\n", 2); break; case '\\': ostr.write("\\\\", 2); break; default: ; } value = it + 1; } return ostr << value; } std::ostream & operator<< (const String & string) { writeEscapedData(string.data(), string.size()); return ostr; } std::ostream & operator<< (const Row & row) { for (size_t i = 0; i < row.size(); ++i) { if (i != 0) ostr << '\t'; if (row[i].isNull()) { ostr << "\\N"; continue; } (*this) << row[i]; } return ostr; } template std::ostream & operator<< (const Null & value) { if(value.is_null) { ostr << "\\N"; } else { *this << value.data; } return ostr ; } private: void writeEscapedData(const char * data, size_t length) { size_t i = 0; while (true) { size_t remaining_length = std::strlen(data); (*this) << data; if (i + remaining_length == length) break; ostr.write("\\0", 2); i += remaining_length + 1; data += remaining_length + 1; } } }; inline EscapeManipResult operator<< (std::ostream & ostr, escape_enum manip) { return EscapeManipResult(ostr); } struct QuoteManipResult { public: std::ostream & ostr; QuoteManipResult(std::ostream & ostr_) : ostr(ostr_) {} std::ostream & operator<< (bool value) { return ostr << value; } std::ostream & operator<< (char value) { return ostr << value; } std::ostream & operator<< (unsigned char value) { return ostr << value; } std::ostream & operator<< (signed char value) { return ostr << value; } std::ostream & operator<< (short value) { return ostr << value; } std::ostream & operator<< (unsigned short value) { return ostr << value; } std::ostream & operator<< (int value) { return ostr << value; } std::ostream & operator<< (unsigned int value) { return ostr << value; } std::ostream & operator<< (long value) { return ostr << value; } std::ostream & operator<< (unsigned long value) { return ostr << value; } std::ostream & operator<< (float value) { return ostr << value; } std::ostream & operator<< (double value) { return ostr << value; } std::ostream & operator<< (long long value) { return ostr << value; } std::ostream & operator<< (unsigned long long value) { return ostr << value; } std::ostream & operator<< (Date value) { return ostr << '\'' << value << '\''; } std::ostream & operator<< (DateTime value) { return ostr << '\'' << value << '\''; } std::ostream & operator<< (const std::string & value) { ostr.put('\''); writeEscapedData(value.data(), value.length()); ostr.put('\''); return ostr; } std::ostream & operator<< (const char * value) { ostr.put('\''); writeEscapedCString(value); ostr.put('\''); return ostr; } template std::ostream & operator<< (const Null & value) { if(value.is_null) { ostr << "\\N"; } else { *this << value.data; } return ostr ; } private: void writeEscapedCString(const char * value) { while (const char * it = std::strpbrk(value, "'\\\"")) { ostr.write(value, it - value); switch (*it) { case '"': ostr.write("\\\"", 2); break; case '\'': ostr.write("\\'", 2); break; case '\\': ostr.write("\\\\", 2); break; default: ; } value = it + 1; } ostr << value; } void writeEscapedData(const char * data, size_t length) { size_t i = 0; while (true) { size_t remaining_length = std::strlen(data); writeEscapedCString(data); if (i + remaining_length == length) break; ostr.write("\\0", 2); i += remaining_length + 1; data += remaining_length + 1; } } }; inline QuoteManipResult operator<< (std::ostream & ostr, quote_enum manip) { return QuoteManipResult(ostr); } /** Манипулятор istream, позволяет считывать значения из tab delimited файла. */ enum unescape_enum { unescape }; /** Манипулятор istream, который позволяет читать значения в кавычках или без. */ enum unquote_enum { unquote }; inline void parseEscapeSequence(std::istream & istr, std::string & value) { char c = istr.get(); if (!istr.good()) throw Poco::Exception("Cannot parse string: unexpected end of input."); switch(c) { case 'b': value.push_back('\b'); break; case 'f': value.push_back('\f'); break; case 'n': value.push_back('\n'); break; case 'r': value.push_back('\r'); break; case 't': value.push_back('\t'); break; default: value.push_back(c); break; } } struct UnEscapeManipResult { std::istream & istr; UnEscapeManipResult(std::istream & istr_) : istr(istr_) {} std::istream & operator>> (bool & value) { return istr >> value; } std::istream & operator>> (char & value) { return istr >> value; } std::istream & operator>> (unsigned char & value) { return istr >> value; } std::istream & operator>> (signed char & value) { return istr >> value; } std::istream & operator>> (short & value) { return istr >> value; } std::istream & operator>> (unsigned short & value) { return istr >> value; } std::istream & operator>> (int & value) { return istr >> value; } std::istream & operator>> (unsigned int & value) { return istr >> value; } std::istream & operator>> (long & value) { return istr >> value; } std::istream & operator>> (unsigned long & value) { return istr >> value; } std::istream & operator>> (float & value) { return istr >> value; } std::istream & operator>> (double & value) { return istr >> value; } std::istream & operator>> (long long & value) { return istr >> value; } std::istream & operator>> (unsigned long long & value) { return istr >> value; } std::istream & operator>> (std::string & value) { value.clear(); char c; while (1) { istr.get(c); if (!istr.good()) break; switch (c) { case '\\': parseEscapeSequence(istr, value); break; case '\t': istr.unget(); return istr; break; case '\n': istr.unget(); return istr; break; default: value.push_back(c); break; } } return istr; } /// Чтение NULL-able типа. template std::istream & operator>> (Null & value) { char c; istr.get(c); if (c == '\\' && istr.peek() == 'N') { value.is_null = true; istr.ignore(); } else { istr.unget(); value.is_null = false; *this >> value.data; } return istr; } std::istream & operator>> (Date & value) { std::string s; (*this) >> s; value = Date(s); return istr; } std::istream & operator>> (DateTime & value) { std::string s; (*this) >> s; value = DateTime(s); return istr; } }; inline UnEscapeManipResult operator>> (std::istream & istr, unescape_enum manip) { return UnEscapeManipResult(istr); } struct UnQuoteManipResult { public: std::istream & istr; UnQuoteManipResult(std::istream & istr_) : istr(istr_) {} std::istream & operator>> (bool & value) { return istr >> value; } std::istream & operator>> (char & value) { return istr >> value; } std::istream & operator>> (unsigned char & value) { return istr >> value; } std::istream & operator>> (signed char & value) { return istr >> value; } std::istream & operator>> (short & value) { return istr >> value; } std::istream & operator>> (unsigned short & value) { return istr >> value; } std::istream & operator>> (int & value) { return istr >> value; } std::istream & operator>> (unsigned int & value) { return istr >> value; } std::istream & operator>> (long & value) { return istr >> value; } std::istream & operator>> (unsigned long & value) { return istr >> value; } std::istream & operator>> (float & value) { return istr >> value; } std::istream & operator>> (double & value) { return istr >> value; } std::istream & operator>> (long long & value) { return istr >> value; } std::istream & operator>> (unsigned long long & value) { return istr >> value; } std::istream & operator>> (std::string & value) { value.clear(); readQuote(); char c; while (1) { istr.get(c); if (!istr.good()) break; switch (c) { case '\\': parseEscapeSequence(istr, value); break; case '\'': return istr; break; default: value.push_back(c); break; } } throw Poco::Exception("Cannot parse string: unexpected end of input."); } private: void readQuote() { char c = istr.get(); if (!istr.good()) throw Poco::Exception("Cannot parse string: unexpected end of input."); if (c != '\'') throw Poco::Exception("Cannot parse string: missing opening single quote."); } }; inline UnQuoteManipResult operator>> (std::istream & istr, unquote_enum manip) { return UnQuoteManipResult(istr); } } #endif