NValue NValue::opDivideDecimals(const NValue lhs, const NValue rhs) const { if ((lhs.getValueType() != VALUE_TYPE_DECIMAL) || (rhs.getValueType() != VALUE_TYPE_DECIMAL)) { throw SQLException(SQLException::dynamic_sql_error, "No decimal NValue in decimal subtract"); } if (lhs.isNull() || rhs.isNull()) { TTInt retval; retval.SetMin(); return getDecimalValue( retval ); } TTLInt calc; calc.FromInt(lhs.getDecimal()); calc *= NValue::kMaxScaleFactor; if (calc.Div(rhs.getDecimal())) { char message[4096]; snprintf( message, 4096, "Attempted to divide %s by %s causing overflow/underflow (or divide by zero)", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } TTInt retval; if (retval.FromInt(calc) || retval > s_maxDecimalValue || retval < s_minDecimalValue) { char message[4096]; snprintf( message, 4096, "Attempted to divide %s by %s causing overflow. Unscaled result was %s", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str(), calc.ToString(10).c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } return getDecimalValue(retval); }
static void throwInvalidDistanceDWithin(const std::string& msg) { std::ostringstream oss; oss << "Invalid input to DWITHIN function: '" << msg << "'."; throw SQLException(SQLException::data_exception_invalid_parameter, oss.str().c_str()); }
static void throwInvalidPolygonLongitude(const std::string& input) { std::ostringstream oss; oss << "Invalid input to POLYGONFROMTEXT: '" << input << "'"; oss << ". Longitude must be in the range [-180,180]."; throw SQLException(SQLException::data_exception_invalid_parameter, oss.str().c_str()); }
static void throwInvalidWktPoly(const std::string& reason) { std::ostringstream oss; oss << "Invalid input to POLYGONFROMTEXT: " << reason << ". "; oss << "Expected input of the form 'POLYGON((<lng> <lat>, ...), ...)'"; throw SQLException(SQLException::data_exception_invalid_parameter, oss.str().c_str()); }
static void throwInvalidWktPoint(const std::string& input) { std::ostringstream oss; oss << "Invalid input to POINTFROMTEXT: "; oss << "'" << input << "', "; oss << "expected input of the form 'POINT(<lng> <lat>)'"; throw SQLException(SQLException::data_exception_invalid_parameter, oss.str().c_str()); }
inline static void throwTimestampFormatError(const std::string &str) { char message[4096]; // No space separator for between the date and time snprintf(message, 4096, "Attempted to cast \'%s\' to type %s failed. Supported format: \'YYYY-MM-DD HH:MM:SS.UUUUUU\'" "or \'YYYY-MM-DD\'", str.c_str(), valueToString(VALUE_TYPE_TIMESTAMP).c_str()); throw SQLException(SQLException::dynamic_sql_error, message); }
//----------------- int Statement::executeUpdate(const std::string& sql) { int rc = sqlite3_exec(mhdbc->hdbc, (const char*)sql.c_str(), 0, 0, NULL); if( rc !=SQLITE_OK) { throw SQLException( (const char*)sqlite3_errmsg( mhdbc->hdbc ) ); } return sqlite3_changes(mhdbc->hdbc); }
void SQLCode::buildSQLStatement(SQLVarParms& varParms, SQLStatement& rSqlStatement) { FUNCTION_ENTRY("SQLCode::_ConstructSQLStatement()"); std::string strSQLKey; SQLStatement SQLFormats; int nDbType = 0; size_t uiTotalSQLSize = 0; try { size_t uVarCount = varParms.size(); if (uVarCount < defMINPARAMSIZE) TA_THROW(BadParamCount("the PrepareStatement parameter count error")); _GetDbTypeAndSQLKey(varParms, strSQLKey); _GetSQLFormat(strSQLKey, SQLFormats); //_GetSQLID(strSQLKey, rSqlStatement); _BuildNormalSQL(varParms, SQLFormats, rSqlStatement); _PrintSQL(strSQLKey, rSqlStatement); } catch (BadParamCount* e) { SQLCodeException SQLException(e->what()); throw SQLException; } catch (BadIndex* e) { SQLCodeException SQLException(e->what()); throw SQLException; } catch(DbTypeNotSupported* e) { SQLCodeException SQLException(e->what()); throw SQLException; } catch (...) { SQLCodeException SQLException("Unknown SQLCode exception"); throw SQLException; } FUNCTION_EXIT; }
String Query::toSQL() const { if (m_expectedFileds.size() == 0) throw SQLException("No fields to query"); bool selectAll = (m_expectedFileds[0].trim() == "*"); String where = m_where->toSQL(); String having = m_having->toSQL(); StringBuilder sql(128 + where.length() + having.length()); //String::format("select %s from %s where %s", ...); // select * sql.append("select "); if (m_distinct) sql.append("distinct "); sql.append(String(",").join(m_expectedFileds)); // from table sql.append(" from "); sql.append(table()); // where if (!m_where.equals(CW_NONE)) { sql.append(" where "); sql.append(where); } // group-by if (m_groupBy.size() > 0) { sql.append(" group by "); sql.append(String(",").join(m_groupBy)); } // having if (!m_having.equals(CW_NONE)) { sql.append(" having "); sql.append(having); } // order by for (size_t i=0; i<m_orderBy.size(); i++) { sql.append(" order by "); sql.append(m_orderBy[i].key); sql.append(m_orderBy[i].value ? " desc " : ""); } // limit if (m_limit > 0) { // TODO: add more generic way('limit' is just in mysql/pg) sql.append(" limit "); sql.append((int)m_limit); } // offset if (m_offset > 0) { sql.append(" offset "); sql.append((int)m_offset); } return sql.toString(); }
//----------------------- boost::shared_ptr<ResultSet> Statement::executeQuery( const std::string& sql ) { int rc = sqlite3_prepare_v2(mhdbc->hdbc, (const char*)sql.c_str(), strlen((const char*)sql.c_str()) * sizeof(char), &mhstmt->hstmt,NULL); if( rc !=SQLITE_OK) { throw SQLException( (const char*)sqlite3_errmsg( mhdbc->hdbc ) ); } mrset.reset( new ResultSet(mhdbc,mhstmt)); return mrset; }
/* * This code is needed in the limit executor as well as anywhere limit * is inlined. Centralize it here. */ void LimitPlanNode::getLimitAndOffsetByReference(const NValueArray ¶ms, int &limit, int &offset) { limit = getLimit(); offset = getOffset(); // Limit and offset parameters strictly integers. Can't limit <?=varchar>. // Converting the loop counter to NValue's doesn't make it cleaner - // and probably makes it slower. Would have to initialize an nvalue for // each loop iteration. if (getLimitParamIdx() != -1) { limit = ValuePeeker::peekInteger(params[getLimitParamIdx()]); if (limit < 0) { throw SQLException(SQLException::data_exception_invalid_parameter, "Negative parameter to LIMIT"); } } if (getOffsetParamIdx() != -1) { offset = ValuePeeker::peekInteger(params[getOffsetParamIdx()]); if (offset < 0) { throw SQLException(SQLException::data_exception_invalid_parameter, "Negative parameter to LIMIT OFFSET"); } } // If the limit expression is not null, we need to evaluate it and assign // the result to limit, offset must be 0 if (limitExpression != NULL) { // The expression should be an operator expression with either constant // value expression or parameter value expression as children limitExpression->substitute(params); limit = ValuePeeker::peekAsInteger(limitExpression->eval(NULL, NULL)); assert(offset == 0); } }
/* {{{ MySQL_PreparedResultSetMetaData::getColumnDisplaySize -I- */ unsigned int MySQL_PreparedResultSetMetaData::getColumnDisplaySize(unsigned int columnIndex) { CPP_ENTER("MySQL_PreparedResultSetMetaData::getColumnDisplaySize"); CPP_INFO_FMT("this=%p", this); checkColumnIndex(columnIndex); const MYSQL_FIELD * const field = getFieldMeta(columnIndex); const sql::mysql::util::OUR_CHARSET * const cs = sql::mysql::util::find_charset(field->charsetnr); if (!cs) { std::ostringstream msg("Server sent uknown charsetnr ("); msg << field->charsetnr << ") . Please report"; throw SQLException(msg.str()); } int ret = field->length / cs->char_maxlen; CPP_INFO_FMT("column=%u display_size=%d", columnIndex, ret); return ret; }
Connection * Database::getConnection() throw (SQLException) { if (dbConnection == NULL) { driver = get_driver_instance(); if (driver != NULL) { dbConnection = driver ->connect(hostname, username, password); dbConnection ->setSchema(schema); } else { throw SQLException("Unable to find a driver"); } } return dbConnection; }
/* {{{ MySQL_PreparedResultSetMetaData::isCaseSensitive -I- */ bool MySQL_PreparedResultSetMetaData::isCaseSensitive(unsigned int columnIndex) { CPP_ENTER("MySQL_PreparedResultSetMetaData::isCaseSensitive"); CPP_INFO_FMT("this=%p", this); checkColumnIndex(columnIndex); const MYSQL_FIELD * const field = getFieldMeta(columnIndex); if (field->flags & NUM_FLAG || field->type == MYSQL_TYPE_NEWDECIMAL || field->type == MYSQL_TYPE_DECIMAL) { return false; } const sql::mysql::util::OUR_CHARSET * const cs = sql::mysql::util::find_charset(field->charsetnr); if (!cs) { std::ostringstream msg("Server sent uknown charsetnr ("); msg << field->charsetnr << ") . Please report"; throw SQLException(msg.str()); } return NULL == strstr(cs->collation, "_ci"); }
std::shared_ptr<Connection> Database::getConnection(std::string user,std::string password) { LOG_DEBUG(std::string(__FILE__) + " " + std::to_string(__LINE__)); std::lock_guard<std::mutex> lock(g_i_mutex); SQLHENV henv; SQLHDBC hdbc; SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); SQLRETURN ret; SQLCHAR outstr[1024]; SQLSMALLINT outstrlen; std::string dsnname; dsnname += "DSN=" + dsnentry_ + ";UID=" + user + ";PWD=" + password; LOG_DEBUG(std::string("ODBCSYSINI :") + std::string(getenv("ODBCSYSINI"))); LOG_DEBUG(std::string("ODBCINI:") + std::string(getenv("ODBCINI"))); LOG_DEBUG(std::string("TNS_ADMIN:") + std::string(getenv("TNS_ADMIN"))); LOG_DEBUG(dsnname); ret = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)dsnname.c_str(), SQL_NTS,outstr, sizeof(outstr), &outstrlen,SQL_DRIVER_COMPLETE); LOG_DEBUG(std::string(__FILE__) + " " + std::to_string(__LINE__)); if (SQL_SUCCEEDED(ret)) { if (ret == SQL_SUCCESS_WITH_INFO) { LOG_DEBUG("SQLDriverConnect"); ODBCError err; LOG_DEBUG(err("SQLDriverConnect", hdbc, SQL_HANDLE_DBC)); } std::shared_ptr<Connection> cnx(new Connection(user,password,henv,hdbc)); cnx->setProvider(provider_); cnx->setSchema(schema_); LOG_DEBUG(std::string("Provider set for connection : ") + DBPROVIDERS[provider_]); return move(cnx); } else { ODBCError err; std::string message = err("SQLDriverConnect", hdbc, SQL_HANDLE_DBC) + "\nDSN : " + dsnentry_ + "\nDatabase user : " + user; throw SQLException(message); } }
// returns the actual ODBC cursor type this datasource would // use for a given ResultSet type inline int getODBCCursorTypeFor(int rsType, const DriverInfo* di) { int r; switch(rsType) { case ResultSet::TYPE_FORWARD_ONLY: r=SQL_CURSOR_FORWARD_ONLY; break; case ResultSet::TYPE_SCROLL_INSENSITIVE: r=SQL_CURSOR_STATIC; break; case ResultSet::TYPE_SCROLL_SENSITIVE: if(di->getCursorMask()&SQL_SO_DYNAMIC) { r=SQL_CURSOR_DYNAMIC; } else { r=SQL_CURSOR_KEYSET_DRIVEN; } break; default: throw SQLException(ODBCXX_STRING_CONST("[libodbc++]: Invalid ResultSet type ")+intToString(rsType), ODBCXX_STRING_CONST("S1009")); } return r; }
/* {{{ MySQL_Connection::init() -I- */ void MySQL_Connection::init(ConnectOptionsMap & properties) { CPP_ENTER_WL(intern->logger, "MySQL_Connection::init"); intern->is_valid = true; MySQL_Uri uri; sql::SQLString userName; sql::SQLString password; sql::SQLString defaultCharset("utf8"); sql::SQLString characterSetResults("utf8"); sql::SQLString sslKey, sslCert, sslCA, sslCAPath, sslCipher, postInit; bool ssl_used = false; int flags = CLIENT_MULTI_RESULTS; const int * p_i; const bool * p_b; const sql::SQLString * p_s; bool opt_reconnect = false; bool opt_reconnect_value = false; bool client_doesnt_support_exp_pwd = false; /* Values set in properties individually should have priority over those we restore from Uri */ sql::ConnectOptionsMap::const_iterator it = properties.find("hostName"); if (it != properties.end()) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { /* Parsing uri prior to processing all parameters, so indivudually specified parameters precede over those in the uri */ parseUri(*p_s, uri); } else { throw sql::InvalidArgumentException("No string value passed for hostName"); } } #define PROCESS_CONN_OPTION(option_type, options_map) process_connection_option< option_type >(it, options_map, sizeof(options_map)/sizeof(String2IntMap), proxy) for (it = properties.begin(); it != properties.end(); ++it) { if (!it->first.compare("userName")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { userName = *p_s; } else { throw sql::InvalidArgumentException("No string value passed for userName"); } } else if (!it->first.compare("password")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { password = *p_s; } else { throw sql::InvalidArgumentException("No string value passed for password"); } } else if (!it->first.compare("port")) { if ((p_i = boost::get< int >(&it->second))) { uri.setPort(static_cast<unsigned int>(*p_i)); } else { throw sql::InvalidArgumentException("No long long value passed for port"); } } else if (!it->first.compare("socket")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { uri.setSocket(*p_s); } else { throw sql::InvalidArgumentException("No string value passed for socket"); } } else if (!it->first.compare("pipe")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { uri.setPipe(*p_s); } else { throw sql::InvalidArgumentException("No string value passed for pipe"); } } else if (!it->first.compare("schema")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { uri.setSchema(*p_s); } else { throw sql::InvalidArgumentException("No string value passed for schema"); } } else if (!it->first.compare("characterSetResults")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { characterSetResults = *p_s; } else { throw sql::InvalidArgumentException("No string value passed for characterSetResults"); } } else if (!it->first.compare("sslKey")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { sslKey = *p_s; } else { throw sql::InvalidArgumentException("No string value passed for sslKey"); } ssl_used = true; } else if (!it->first.compare("sslCert")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { sslCert = *p_s; } else { throw sql::InvalidArgumentException("No string value passed for sslCert"); } ssl_used = true; } else if (!it->first.compare("sslCA")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { sslCA = *p_s; } else { throw sql::InvalidArgumentException("No string value passed for sslCA"); } ssl_used = true; } else if (!it->first.compare("sslCAPath")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { sslCAPath = *p_s; } else { throw sql::InvalidArgumentException("No string value passed for sslCAPath"); } ssl_used = true; } else if (!it->first.compare("sslCipher")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { sslCipher = *p_s; } else { throw sql::InvalidArgumentException("No string value passed for sslCipher"); } ssl_used = true; } else if (!it->first.compare("defaultStatementResultType")) { if (!(p_i = boost::get< int >(&it->second))) { throw sql::InvalidArgumentException("No long long value passed for defaultStatementResultType"); } do { if (static_cast< int >(sql::ResultSet::TYPE_FORWARD_ONLY) == *p_i) break; if (static_cast< int >(sql::ResultSet::TYPE_SCROLL_INSENSITIVE) == *p_i) break; if (static_cast< int >(sql::ResultSet::TYPE_SCROLL_SENSITIVE) == *p_i) { std::ostringstream msg; msg << "Invalid value " << *p_i << " for option defaultStatementResultType. TYPE_SCROLL_SENSITIVE is not supported"; throw sql::InvalidArgumentException(msg.str()); } std::ostringstream msg; msg << "Invalid value (" << *p_i << " for option defaultStatementResultType"; throw sql::InvalidArgumentException(msg.str()); } while (0); intern->defaultStatementResultType = static_cast< sql::ResultSet::enum_type >(*p_i); /* The connector is not ready for unbuffered as we need to refetch */ } else if (!it->first.compare("defaultPreparedStatementResultType")) { #if WE_SUPPORT_USE_RESULT_WITH_PS if (!(p_i = boost::get< int >(&it->second))) { throw sql::InvalidArgumentException("No long long value passed for defaultPreparedStatementResultType"); } do { if (static_cast< int >(sql::ResultSet::TYPE_FORWARD_ONLY) == *p_i) break; if (static_cast< int >(sql::ResultSet::TYPE_SCROLL_INSENSITIVE) == *p_i) break; if (static_cast< int >(sql::ResultSet::TYPE_SCROLL_SENSITIVE) == *p_i) { std::ostringstream msg; msg << "Invalid value " << *p_i << " for option defaultPreparedStatementResultType. TYPE_SCROLL_SENSITIVE is not supported"; throw sql::InvalidArgumentException(msg.str()); } std::ostringstream msg; msg << "Invalid value (" << *p_i << " for option defaultPreparedStatementResultType"; throw sql::InvalidArgumentException(msg.str()); } while (0); intern->defaultPreparedStatementResultType = static_cast< sql::ResultSet::enum_type >(*p_i); #else throw SQLException("defaultPreparedStatementResultType parameter still not implemented"); #endif } else if (!it->first.compare("metadataUseInfoSchema")) { if ((p_b = boost::get<bool>(&it->second))) { intern->metadata_use_info_schema = *p_b; } else { throw sql::InvalidArgumentException("No bool value passed for metadataUseInfoSchema"); } } else if (!it->first.compare("OPT_RECONNECT")) { if (!(p_b = boost::get<bool>(&it->second))) { throw sql::InvalidArgumentException("No bool value passed for OPT_RECONNECT"); } opt_reconnect = true; opt_reconnect_value = *p_b; } else if (!it->first.compare("OPT_CHARSET_NAME")) { if (!(p_s = boost::get< sql::SQLString >(&it->second))) { throw sql::InvalidArgumentException("No SQLString value passed for OPT_CHARSET_NAME"); } defaultCharset = *p_s; } else if (!it->first.compare("OPT_NAMED_PIPE")) { /* Not sure it is really needed */ uri.setProtocol(NativeAPI::PROTOCOL_PIPE); } else if (!it->first.compare("OPT_CAN_HANDLE_EXPIRED_PASSWORDS")) { /* We need to know client version at runtime */ long client_ver= proxy->get_client_version(); if (proxy->get_client_version() < 50610) { // TODO: I think we should throw a warning here /* We only need this flag set if application has said it supports expired password mode */ client_doesnt_support_exp_pwd= true; } else { if (!(p_b = boost::get< bool >(&it->second))) { throw sql::InvalidArgumentException("No bool value passed for " "OPT_CAN_HANDLE_EXPIRED_PASSWORDS"); } /* We do not care here about server version */ proxy->options(MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, (const char*)p_b); } } else if (!it->first.compare("postInit")) { if ((p_s = boost::get< sql::SQLString >(&it->second))) { postInit= *p_s; } else { throw sql::InvalidArgumentException("No string value passed for postInit"); } /* If you need to add new integer connection option that should result in calling mysql_optiong - add its mapping to the intOptions array */ } else if (PROCESS_CONN_OPTION(int, intOptions)) { // Nothing to do here /* For boolean coonection option - add mapping to booleanOptions array */ } else if (PROCESS_CONN_OPTION(bool, booleanOptions)) { // Nothing to do here /* For string coonection option - add mapping to stringOptions array */ } else if (PROCESS_CONN_OPTION(sql::SQLString, stringOptions)) { // Nothing to do here } else if (read_connection_flag(it, flags)) { // Nothing to do here } else { // TODO: Shouldn't we really create a warning here? as soon as we are able to // create a warning } } /* End of cycle on connection options map */ #undef PROCESS_CONNSTR_OPTION /* libmysql shouldn't think it is too smart */ if (tcpProtocol(uri) && !uri.Host().compare(util::LOCALHOST)) { uri.setHost("127.0.0.1"); } // Throwing in case of wrong protocol #ifdef _WIN32 if (uri.Protocol() == NativeAPI::PROTOCOL_SOCKET) { throw sql::InvalidArgumentException("Invalid for this platform protocol requested(MYSQL_PROTOCOL_SOCKET)"); } #else if (uri.Protocol() == NativeAPI::PROTOCOL_PIPE) { throw sql::InvalidArgumentException("Invalid for this platform protocol requested(MYSQL_PROTOCOL_PIPE)"); } #endif proxy->use_protocol(uri.Protocol()); { const char tmp_bool = 1; proxy->options(MYSQL_SECURE_AUTH, &tmp_bool); } proxy->options(MYSQL_SET_CHARSET_NAME, defaultCharset.c_str()); if (ssl_used) { /* According to the docs, always returns 0 */ proxy->ssl_set(sslKey.c_str(), sslCert.c_str(), sslCA.c_str(), sslCAPath.c_str(), sslCipher.c_str()); } CPP_INFO_FMT("hostName=%s", uri.Host().c_str()); CPP_INFO_FMT("user=%s", userName.c_str()); CPP_INFO_FMT("port=%d", uri.Port()); CPP_INFO_FMT("schema=%s", uri.Schema().c_str()); CPP_INFO_FMT("socket/pipe=%s", uri.SocketOrPipe().c_str()); if (!proxy->connect(uri.Host(), userName, password, uri.Schema() /* schema */, uri.Port(), uri.SocketOrPipe() /*socket or named pipe */, flags)) { CPP_ERR_FMT("Couldn't connect : %d", proxy->errNo()); CPP_ERR_FMT("Couldn't connect : (%s)", proxy->sqlstate().c_str()); CPP_ERR_FMT("Couldn't connect : %s", proxy->error().c_str()); CPP_ERR_FMT("Couldn't connect : %d:(%s) %s", proxy->errNo(), proxy->sqlstate().c_str(), proxy->error().c_str()); /* If error is "Password has expired" and application supports it while mysql client lib does not */ std::string error_message; int native_error= proxy->errNo(); if (native_error == ER_MUST_CHANGE_PASSWORD_LOGIN && client_doesnt_support_exp_pwd) { native_error= deCL_CANT_HANDLE_EXP_PWD; error_message= "Your password has expired, but your instance of" " Connector/C++ is not linked against mysql client library that" " allows to reset it. To resolve this you either need to change" " the password with mysql client that is capable to do that," " or rebuild your instance of Connector/C++ against mysql client" " library that supports resetting of an expired password."; } else { error_message= proxy->error(); } sql::SQLException e(error_message, proxy->sqlstate(), native_error); proxy.reset(); throw e; } if (opt_reconnect) { proxy->options(MYSQL_OPT_RECONNECT, (const char *) &opt_reconnect_value); } setAutoCommit(true); setTransactionIsolation(sql::TRANSACTION_REPEATABLE_READ); // Different Values means we have to set different result set encoding if (characterSetResults.compare(defaultCharset)) { setSessionVariable("character_set_results", characterSetResults.length() ? characterSetResults:"NULL"); } intern->meta.reset(new MySQL_ConnectionMetaData(service.get(), proxy, intern->logger)); if (postInit.length() > 0) { service->executeUpdate(postInit); } }
void SQLAdvancedDeleteCommand::commit() { SQLDatabase sql = getSQLConnection(); QList<QMap<QString, QString> > colInfo = SQLListColumns(sql, tableName); QString nameCode(""); QString valueCode(""); unsigned int nc = 0; for (QList<QMap<QString, QString> >::iterator it = colInfo.begin() ; it != colInfo.end() ; it++) { QMap<QString, QString> col = *it; if (nc != 0) nameCode += ","; nameCode += col["name"]; nc++; } QString query = QString("SELECT %1 FROM %2 WHERE %3") .arg(nameCode) .arg(tableName) .arg(whereClause); SQLResult res = sql.sendQuery(query); if (!res.isValid()) { throw SQLException("Error storing SQL result", __FILE__, __LINE__); } unsigned int numRemoved = 0; bool first = true; while (res.nextRecord()) { if (!first) valueCode +=","; valueCode += "("; for (unsigned int i = 0 ; i < nc ; i++) { if (i != 0) { valueCode += ","; } valueCode += QString("'%1'").arg(sql.escapeString(res.getString(i))); } valueCode += ")"; first = false; numRemoved++; } if (numRemoved != 0) { revertQuery = QString("INSERT INTO %1 (%2) VALUES %3") .arg(tableName) .arg(nameCode) .arg(valueCode); query = QString("DELETE FROM %1 WHERE %2") .arg(tableName) .arg(whereClause); sql.sendQuery(query); } else { revertQuery = QString(); } }
/* * Avoid scaling both sides if possible. E.g, don't turn dec * 2 into * (dec * 2*kMaxScale*E-12). Then the result of simple multiplication * is a*b*E-24 and have to further multiply to get back to the assumed * E-12, which can overflow unnecessarily at the middle step. */ NValue NValue::opMultiplyDecimals(const NValue &lhs, const NValue &rhs) const { if ((lhs.getValueType() != VALUE_TYPE_DECIMAL) && (rhs.getValueType() != VALUE_TYPE_DECIMAL)) { throw SQLException(SQLException::dynamic_sql_error, "Non-decimal NValue in decimal multiply"); } if (lhs.isNull() || rhs.isNull()) { TTInt retval; retval.SetMin(); return getDecimalValue( retval ); } if ((lhs.getValueType() == VALUE_TYPE_DECIMAL) && (rhs.getValueType() == VALUE_TYPE_DECIMAL)) { TTLInt calc; calc.FromInt(lhs.getDecimal()); calc *= rhs.getDecimal(); calc /= NValue::kMaxScaleFactor; TTInt retval; if (retval.FromInt(calc) || retval > s_maxDecimalValue || retval < s_minDecimalValue) { char message[4096]; snprintf(message, 4096, "Attempted to multiply %s by %s causing overflow/underflow. Unscaled result was %s", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str(), calc.ToString(10).c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } return getDecimalValue(retval); } else if (lhs.getValueType() != VALUE_TYPE_DECIMAL) { TTLInt calc; calc.FromInt(rhs.getDecimal()); calc *= lhs.castAsDecimalAndGetValue(); calc /= NValue::kMaxScaleFactor; TTInt retval; if (retval.FromInt(calc) || retval > s_maxDecimalValue || retval < s_minDecimalValue) { char message[4096]; snprintf(message, 4096, "Attempted to multiply %s by %s causing overflow/underflow. Unscaled result was %s", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str(), calc.ToString(10).c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } return getDecimalValue(retval); } else { TTLInt calc; calc.FromInt(lhs.getDecimal()); calc *= rhs.castAsDecimalAndGetValue(); calc /= NValue::kMaxScaleFactor; TTInt retval; if (retval.FromInt(calc) || retval > s_maxDecimalValue || retval < s_minDecimalValue) { char message[4096]; snprintf(message, 4096, "Attempted to multiply %s by %s causing overflow/underflow. Unscaled result was %s", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str(), calc.ToString(10).c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } return getDecimalValue(retval); } }
/** * Set a decimal value from a serialized representation * This function does not handle scientific notation string, Java planner should convert that to plan string first. */ void NValue::createDecimalFromString(const std::string &txt) { if (txt.length() == 0) { throw SQLException(SQLException::volt_decimal_serialization_error, "Empty string provided"); } bool setSign = false; if (txt[0] == '-') { setSign = true; } /** * Check for invalid characters */ for (int ii = (setSign ? 1 : 0); ii < static_cast<int>(txt.size()); ii++) { if ((txt[ii] < '0' || txt[ii] > '9') && txt[ii] != '.') { char message[4096]; snprintf(message, 4096, "Invalid characters in decimal string: %s", txt.c_str()); throw SQLException(SQLException::volt_decimal_serialization_error, message); } } std::size_t separatorPos = txt.find( '.', 0); if (separatorPos == std::string::npos) { const std::string wholeString = txt.substr( setSign ? 1 : 0, txt.size()); const std::size_t wholeStringSize = wholeString.size(); if (wholeStringSize > 26) { throw SQLException(SQLException::volt_decimal_serialization_error, "Maximum precision exceeded. Maximum of 26 digits to the left of the decimal point"); } TTInt whole(wholeString); if (setSign) { whole.SetSign(); } whole *= kMaxScaleFactor; getDecimal() = whole; return; } if (txt.find( '.', separatorPos + 1) != std::string::npos) { throw SQLException(SQLException::volt_decimal_serialization_error, "Too many decimal points"); } // This is set to 1 if we carry in the scale. int carryScale = 0; // This is set to 1 if we carry from the scale to the whole. int carryWhole = 0; // Start with the fractional part. We need to // see if we need to carry from it first. std::string fractionalString = txt.substr( separatorPos + 1, txt.size() - (separatorPos + 1)); // remove trailing zeros while (fractionalString.size() > 0 && fractionalString[fractionalString.size() - 1] == '0') fractionalString.erase(fractionalString.size() - 1, 1); // // If the scale is too large, then we will round // the number to the nearest 10**-12, and to the // furthest from zero if the number is equidistant // from the next highest and lowest. This is the // definition of the Java rounding mode HALF_UP. // // At some point we will read a rounding mode from the // Java side at Engine configuration time, or something // like that, and have a whole flurry of rounding modes // here. However, for now we have just the one. // if (fractionalString.size() > kMaxDecScale) { carryScale = ('5' <= fractionalString[kMaxDecScale]) ? 1 : 0; fractionalString = fractionalString.substr(0, kMaxDecScale); } else { while(fractionalString.size() < NValue::kMaxDecScale) { fractionalString.push_back('0'); } } TTInt fractional(fractionalString); // If we decided to carry above, then do it here. // The fractional string is set up so that it represents // 1.0e-12 * units. fractional += carryScale; if (TTInt((uint64_t)kMaxScaleFactor) <= fractional) { // We know fractional was < kMaxScaleFactor before // we rounded, since fractional is 12 digits and // kMaxScaleFactor is 13. So, if carrying makes // the fractional number too big, it must be eactly // too big. That is to say, the rounded fractional // number number has become zero, and we need to // carry to the whole number. fractional = 0; carryWhole = 1; } // Process the whole number string. const std::string wholeString = txt.substr( setSign ? 1 : 0, separatorPos - (setSign ? 1 : 0)); // We will check for oversize numbers below, so don't waste time // doing it now. TTInt whole(wholeString); whole += carryWhole; if (oversizeWholeDecimal(whole)) { throw SQLException(SQLException::volt_decimal_serialization_error, "Maximum precision exceeded. Maximum of 26 digits to the left of the decimal point"); } whole *= kMaxScaleFactor; whole += fractional; if (setSign) { whole.SetSign(); } getDecimal() = whole; }
/** * Set a decimal value from a serialized representation * This function does not handle scientific notation string, Java planner should convert that to plan string first. */ void NValue::createDecimalFromString(const std::string &txt) { if (txt.length() == 0) { throw SQLException(SQLException::volt_decimal_serialization_error, "Empty string provided"); } bool setSign = false; if (txt[0] == '-') { setSign = true; } /** * Check for invalid characters */ for (int ii = (setSign ? 1 : 0); ii < static_cast<int>(txt.size()); ii++) { if ((txt[ii] < '0' || txt[ii] > '9') && txt[ii] != '.') { char message[4096]; snprintf(message, 4096, "Invalid characters in decimal string: %s", txt.c_str()); throw SQLException(SQLException::volt_decimal_serialization_error, message); } } std::size_t separatorPos = txt.find( '.', 0); if (separatorPos == std::string::npos) { const std::string wholeString = txt.substr( setSign ? 1 : 0, txt.size()); const std::size_t wholeStringSize = wholeString.size(); if (wholeStringSize > 26) { throw SQLException(SQLException::volt_decimal_serialization_error, "Maximum precision exceeded. Maximum of 26 digits to the left of the decimal point"); } TTInt whole(wholeString); if (setSign) { whole.SetSign(); } whole *= kMaxScaleFactor; getDecimal() = whole; return; } if (txt.find( '.', separatorPos + 1) != std::string::npos) { throw SQLException(SQLException::volt_decimal_serialization_error, "Too many decimal points"); } const std::string wholeString = txt.substr( setSign ? 1 : 0, separatorPos - (setSign ? 1 : 0)); const std::size_t wholeStringSize = wholeString.size(); if (wholeStringSize > 26) { throw SQLException(SQLException::volt_decimal_serialization_error, "Maximum precision exceeded. Maximum of 26 digits to the left of the decimal point"); } TTInt whole(wholeString); std::string fractionalString = txt.substr( separatorPos + 1, txt.size() - (separatorPos + 1)); // remove trailing zeros while (fractionalString.size() > 0 && fractionalString[fractionalString.size() - 1] == '0') fractionalString.erase(fractionalString.size() - 1, 1); // check if too many decimal places if (fractionalString.size() > 12) { throw SQLException(SQLException::volt_decimal_serialization_error, "Maximum scale exceeded. Maximum of 12 digits to the right of the decimal point"); } while(fractionalString.size() < NValue::kMaxDecScale) { fractionalString.push_back('0'); } TTInt fractional(fractionalString); whole *= kMaxScaleFactor; whole += fractional; if (setSign) { whole.SetSign(); } getDecimal() = whole; }