#include "../shared/MiscSQL.h" #include "FieldLists.h" void DatabaseFieldInfo::appendSql(std::string &destination, Record::Ref const &source) const { ValueBox value = source->lookUpValue(_id); // It's tempting to check for the empty value here. In this case we'd // silently use the default. If the value was not empty, but was not the // right type, we'd still use the default but we'd report a warning to the // log. bool valid = false; switch (_type) { case String: { std::string sValue; value.getString(valid, sValue); if (valid) { destination += '"'; destination += mysqlEscapeString(sValue); destination += '"'; } break; } case Int: case ID: { int64_t iValue; value.getInt(valid, iValue); if (valid) { destination += ntoa(iValue); } break; } case DateTime: { int64_t iValue; value.getInt(valid, iValue); if (valid) { destination += '"'; destination += timeTToMysql(iValue); destination += '"'; } break; } case Date: { int64_t iValue; value.getInt(valid, iValue); if (valid) { destination += '"'; destination += dateToMysql(iValue, true); destination += '"'; } break; } case Float: { double dValue; value.getDouble(valid, dValue); if (valid) // It's tempting to check if this was stored as a float or a double. // If this was stored as a float, we might want to display fewer // digits. It won't make a huge difference since the database only // stores floats, but it would be nice to make this string shorter. destination += ntoa(dValue); break; } case BooleanYN: { bool bValue; value.getBoolean(valid, bValue); if (valid) { destination += '"'; destination += bValue?'Y':'N'; destination += '"'; } break; } } if (!valid) // The original code would try to convert some unknowns to nulls. I think // that goes back to the old days. Back then, MySQL didn't // support the "default" keyword. Some of these fields cannot be null, so // returning null here would not work well. destination += "DEFAULT"; } volatile bool DatabaseFieldInfo::_initialized = false; pthread_once_t DatabaseFieldInfo::_once = PTHREAD_ONCE_INIT; std::vector< DatabaseFieldInfo > DatabaseFieldInfo::_alertFields; std::vector< DatabaseFieldInfo > DatabaseFieldInfo::_topListFields; std::vector< DatabaseFieldInfo > DatabaseFieldInfo::_dailyFields; void DatabaseFieldInfo::init() { if (!_initialized) { pthread_once(&_once, initOnce); _initialized = true; } } std::vector< DatabaseFieldInfo > const &DatabaseFieldInfo::getAlertFields() { init(); return _alertFields; } std::vector< DatabaseFieldInfo > const &DatabaseFieldInfo::getTopListFields() { init(); return _topListFields; } std::vector< DatabaseFieldInfo > const &DatabaseFieldInfo::getDailyFields() { init(); return _dailyFields; } void DatabaseFieldInfo::initOnce() { _alertFields = { DatabaseFieldInfo("id", MainFields::id, DatabaseFieldInfo::ID), DatabaseFieldInfo("alert_type", MainFields::alert_type, DatabaseFieldInfo::String), DatabaseFieldInfo("symbol", MainFields::symbol, DatabaseFieldInfo::String), DatabaseFieldInfo("description", MainFields::description, DatabaseFieldInfo::String), DatabaseFieldInfo("timestamp", MainFields::timestamp, DatabaseFieldInfo::DateTime), DatabaseFieldInfo("price", MainFields::price, DatabaseFieldInfo::Float), DatabaseFieldInfo("last", MainFields::last, DatabaseFieldInfo::Float), DatabaseFieldInfo("spread", MainFields::spread, DatabaseFieldInfo::Float), DatabaseFieldInfo("fake", MainFields::fake, DatabaseFieldInfo::BooleanYN), DatabaseFieldInfo("bid_size", MainFields::bid_size, DatabaseFieldInfo::Int), DatabaseFieldInfo("ask_size", MainFields::ask_size, DatabaseFieldInfo::Int), DatabaseFieldInfo("relvol", MainFields::relvol, DatabaseFieldInfo::Float), DatabaseFieldInfo("quality", MainFields::quality, DatabaseFieldInfo::Float), DatabaseFieldInfo("most_recent_close", MainFields::most_recent_close, DatabaseFieldInfo::Float), DatabaseFieldInfo("expected_open", MainFields::expected_open, DatabaseFieldInfo::Float), DatabaseFieldInfo("num", MainFields::num, DatabaseFieldInfo::Int), DatabaseFieldInfo("tvol", MainFields::tvol, DatabaseFieldInfo::Int), DatabaseFieldInfo("rsi_5", MainFields::rsi_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("rsi_15", MainFields::rsi_15, DatabaseFieldInfo::Float), DatabaseFieldInfo("up_5", MainFields::up_5, DatabaseFieldInfo::Int), DatabaseFieldInfo("up_10", MainFields::up_10, DatabaseFieldInfo::Int), DatabaseFieldInfo("up_15", MainFields::up_15, DatabaseFieldInfo::Int), DatabaseFieldInfo("up_30", MainFields::up_30, DatabaseFieldInfo::Int), DatabaseFieldInfo("sale_condition", MainFields::sale_condition, DatabaseFieldInfo::Int), DatabaseFieldInfo("distance_from_nbbo", MainFields::distance_from_nbbo, DatabaseFieldInfo::Float), DatabaseFieldInfo("t_high", MainFields::t_high, DatabaseFieldInfo::Float), DatabaseFieldInfo("t_low", MainFields::t_low, DatabaseFieldInfo::Float), DatabaseFieldInfo("p_up_1", MainFields::p_up_1, DatabaseFieldInfo::Float), DatabaseFieldInfo("p_up_5", MainFields::p_up_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("p_up_10", MainFields::p_up_10, DatabaseFieldInfo::Float), DatabaseFieldInfo("p_up_15", MainFields::p_up_15, DatabaseFieldInfo::Float), DatabaseFieldInfo("p_up_30", MainFields::p_up_30, DatabaseFieldInfo::Float), DatabaseFieldInfo("p_up_60", MainFields::p_up_60, DatabaseFieldInfo::Float), DatabaseFieldInfo("p_up_120", MainFields::p_up_120, DatabaseFieldInfo::Float), DatabaseFieldInfo("v_up_1", MainFields::v_up_1, DatabaseFieldInfo::Int), DatabaseFieldInfo("v_up_2", MainFields::v_up_2, DatabaseFieldInfo::Int), DatabaseFieldInfo("v_up_5", MainFields::v_up_5, DatabaseFieldInfo::Int), DatabaseFieldInfo("v_up_10", MainFields::v_up_10, DatabaseFieldInfo::Int), DatabaseFieldInfo("v_up_15", MainFields::v_up_15, DatabaseFieldInfo::Int), DatabaseFieldInfo("v_up_30", MainFields::v_up_30, DatabaseFieldInfo::Int), DatabaseFieldInfo("sma_2_8", MainFields::sma_2_8, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_2_20", MainFields::sma_2_20, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_2_200", MainFields::sma_2_200, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_5_8", MainFields::sma_5_8, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_5_20", MainFields::sma_5_20, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_5_200", MainFields::sma_5_200, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_15_8", MainFields::sma_15_8, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_15_20", MainFields::sma_15_20, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_15_200", MainFields::sma_15_200, DatabaseFieldInfo::Float), DatabaseFieldInfo("range_30", MainFields::range_30, DatabaseFieldInfo::Float), DatabaseFieldInfo("range_60", MainFields::range_60, DatabaseFieldInfo::Float), DatabaseFieldInfo("range_120", MainFields::range_120, DatabaseFieldInfo::Float), DatabaseFieldInfo("qqqq_5", MainFields::qqqq_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("qqqq_10", MainFields::qqqq_10, DatabaseFieldInfo::Float), DatabaseFieldInfo("qqqq_15", MainFields::qqqq_15, DatabaseFieldInfo::Float), DatabaseFieldInfo("qqqq_30", MainFields::qqqq_30, DatabaseFieldInfo::Float), DatabaseFieldInfo("qqqq_d", MainFields::qqqq_d, DatabaseFieldInfo::Float), DatabaseFieldInfo("spy_5", MainFields::spy_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("spy_10", MainFields::spy_10, DatabaseFieldInfo::Float), DatabaseFieldInfo("spy_15", MainFields::spy_15, DatabaseFieldInfo::Float), DatabaseFieldInfo("spy_30", MainFields::spy_30, DatabaseFieldInfo::Float), DatabaseFieldInfo("spy_d", MainFields::spy_d, DatabaseFieldInfo::Float), DatabaseFieldInfo("dia_5", MainFields::dia_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("dia_10", MainFields::dia_10, DatabaseFieldInfo::Float), DatabaseFieldInfo("dia_15", MainFields::dia_15, DatabaseFieldInfo::Float), DatabaseFieldInfo("dia_30", MainFields::dia_30, DatabaseFieldInfo::Float), DatabaseFieldInfo("dia_d", MainFields::dia_d, DatabaseFieldInfo::Float), DatabaseFieldInfo("up_60", MainFields::up_60, DatabaseFieldInfo::Int), DatabaseFieldInfo("sma_60_8", MainFields::sma_60_8, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_60_20", MainFields::sma_60_20, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_60_200", MainFields::sma_60_200, DatabaseFieldInfo::Float), DatabaseFieldInfo("range_15", MainFields::range_15, DatabaseFieldInfo::Float), DatabaseFieldInfo("std_5_20", MainFields::std_5_20, DatabaseFieldInfo::Float), DatabaseFieldInfo("std_15_20", MainFields::std_15_20, DatabaseFieldInfo::Float), DatabaseFieldInfo("std_60_20", MainFields::std_60_20, DatabaseFieldInfo::Float), DatabaseFieldInfo("alt_description", MainFields::alt_description, DatabaseFieldInfo::String), DatabaseFieldInfo("vwap", MainFields::vwap, DatabaseFieldInfo::Float), DatabaseFieldInfo("rsi_1", MainFields::rsi_1, DatabaseFieldInfo::Float), DatabaseFieldInfo("rsi_2", MainFields::rsi_2, DatabaseFieldInfo::Float), DatabaseFieldInfo("prange_5", MainFields::prange_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("prange_15", MainFields::prange_15, DatabaseFieldInfo::Float), DatabaseFieldInfo("prange_30", MainFields::prange_30, DatabaseFieldInfo::Float), DatabaseFieldInfo("prange_60", MainFields::prange_60, DatabaseFieldInfo::Float), DatabaseFieldInfo("put_v", MainFields::put_v, DatabaseFieldInfo::Int), DatabaseFieldInfo("call_v", MainFields::call_v, DatabaseFieldInfo::Int), DatabaseFieldInfo("p_up_2", MainFields::p_up_2, DatabaseFieldInfo::Float), DatabaseFieldInfo("range_2", MainFields::range_2, DatabaseFieldInfo::Float), DatabaseFieldInfo("range_5", MainFields::range_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("social_rv", MainFields::social_rv, DatabaseFieldInfo::Float), DatabaseFieldInfo("up_1", MainFields::up_1, DatabaseFieldInfo::Int), DatabaseFieldInfo("up_2", MainFields::up_2, DatabaseFieldInfo::Int), DatabaseFieldInfo("bid", MainFields::bid, DatabaseFieldInfo::Float), DatabaseFieldInfo("ask", MainFields::ask, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_2_5", MainFields::sma_2_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_5_5", MainFields::sma_5_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_15_5", MainFields::sma_15_5, DatabaseFieldInfo::Float), DatabaseFieldInfo("pm_volume", MainFields::pm_volume, DatabaseFieldInfo::Int), DatabaseFieldInfo("rsi_60", MainFields::rsi_60, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_15_130", MainFields::sma_15_130, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_pre", MainFields::high_pre, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_pre", MainFields::low_pre, DatabaseFieldInfo::Float), DatabaseFieldInfo("limit_up", MainFields::limit_up, DatabaseFieldInfo::Float), DatabaseFieldInfo("limit_down", MainFields::limit_down, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_2_10", MainFields::sma_2_10, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_5_10", MainFields::sma_5_10, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_15_10", MainFields::sma_15_10, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_60_10", MainFields::sma_60_10, DatabaseFieldInfo::Float), }; _topListFields.reserve(_alertFields.size() - 6); for (std::vector< DatabaseFieldInfo >::const_iterator it = _alertFields.begin(); it != _alertFields.end(); it++) switch (it->id()) { case MainFields::alert_type: case MainFields::description: case MainFields::quality: case MainFields::fake: case MainFields::num: case MainFields::alt_description: break; default: _topListFields.push_back(*it); } _dailyFields = { DatabaseFieldInfo("d_symbol", DailyFields::d_symbol, DatabaseFieldInfo::String), DatabaseFieldInfo("date", DailyFields::date, DatabaseFieldInfo::Date), DatabaseFieldInfo("advol", DailyFields::advol, DatabaseFieldInfo::Int), DatabaseFieldInfo("advol_5d", DailyFields::advol_5d, DatabaseFieldInfo::Int), DatabaseFieldInfo("list_exch", DailyFields::list_exch, DatabaseFieldInfo::String), DatabaseFieldInfo("up_days", DailyFields::up_days, DatabaseFieldInfo::Int), DatabaseFieldInfo("volatility", DailyFields::volatility, DatabaseFieldInfo::Float), DatabaseFieldInfo("range_contraction", DailyFields::range_contraction, DatabaseFieldInfo::Int), DatabaseFieldInfo("sma_200", DailyFields::sma_200, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_50", DailyFields::sma_50, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_20", DailyFields::sma_20, DatabaseFieldInfo::Float), DatabaseFieldInfo("rsi_d", DailyFields::rsi_d, DatabaseFieldInfo::Float), DatabaseFieldInfo("bright_volatility", DailyFields::bright_volatility, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_p", DailyFields::high_p, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_p", DailyFields::low_p, DatabaseFieldInfo::Float), DatabaseFieldInfo("close_p", DailyFields::close_p, DatabaseFieldInfo::Float), DatabaseFieldInfo("open_p", DailyFields::open_p, DatabaseFieldInfo::Float), DatabaseFieldInfo("volume_p", DailyFields::volume_p, DatabaseFieldInfo::Int), DatabaseFieldInfo("high_52w", DailyFields::high_52w, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_52w", DailyFields::low_52w, DatabaseFieldInfo::Float), DatabaseFieldInfo("std_20", DailyFields::std_20, DatabaseFieldInfo::Float), DatabaseFieldInfo("bunny_130", DailyFields::bunny_130, DatabaseFieldInfo::Float), DatabaseFieldInfo("consolidation_days", DailyFields::consolidation_days, DatabaseFieldInfo::Int), DatabaseFieldInfo("consolidation_high", DailyFields::consolidation_high, DatabaseFieldInfo::Float), DatabaseFieldInfo("consolidation_low", DailyFields::consolidation_low, DatabaseFieldInfo::Float), DatabaseFieldInfo("average_true_range", DailyFields::average_true_range, DatabaseFieldInfo::Float), DatabaseFieldInfo("last_price", DailyFields::last_price, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_life", DailyFields::high_life, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_life", DailyFields::low_life, DatabaseFieldInfo::Float), DatabaseFieldInfo("prev_put_volume", DailyFields::prev_put_volume, DatabaseFieldInfo::Int), DatabaseFieldInfo("prev_call_volume", DailyFields::prev_call_volume, DatabaseFieldInfo::Int), DatabaseFieldInfo("avg_put_call_volume", DailyFields::avg_put_call_volume, DatabaseFieldInfo::Float), DatabaseFieldInfo("debt", DailyFields::debt, DatabaseFieldInfo::Float), DatabaseFieldInfo("assets", DailyFields::assets, DatabaseFieldInfo::Float), DatabaseFieldInfo("eps", DailyFields::eps, DatabaseFieldInfo::Float), DatabaseFieldInfo("pe_ratio", DailyFields::pe_ratio, DatabaseFieldInfo::Float), DatabaseFieldInfo("revenue", DailyFields::revenue, DatabaseFieldInfo::Float), DatabaseFieldInfo("income", DailyFields::income, DatabaseFieldInfo::Float), DatabaseFieldInfo("earnings", DailyFields::earnings, DatabaseFieldInfo::Float), DatabaseFieldInfo("market_cap", DailyFields::market_cap, DatabaseFieldInfo::Float), DatabaseFieldInfo("beta", DailyFields::beta, DatabaseFieldInfo::Float), DatabaseFieldInfo("shares_out", DailyFields::shares_out, DatabaseFieldInfo::Int), DatabaseFieldInfo("yield", DailyFields::yield, DatabaseFieldInfo::Float), DatabaseFieldInfo("dividend", DailyFields::dividend, DatabaseFieldInfo::Float), DatabaseFieldInfo("trailing_dividend_rate", DailyFields::trailing_dividend_rate, DatabaseFieldInfo::Float), DatabaseFieldInfo("forward_dividend_rate", DailyFields::forward_dividend_rate, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_5d", DailyFields::high_5d, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_5d", DailyFields::low_5d, DatabaseFieldInfo::Float), DatabaseFieldInfo("close_5d", DailyFields::close_5d, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_10d", DailyFields::high_10d, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_10d", DailyFields::low_10d, DatabaseFieldInfo::Float), DatabaseFieldInfo("close_10d", DailyFields::close_10d, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_20d", DailyFields::high_20d, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_20d", DailyFields::low_20d, DatabaseFieldInfo::Float), DatabaseFieldInfo("close_20d", DailyFields::close_20d, DatabaseFieldInfo::Float), DatabaseFieldInfo("adx_14d", DailyFields::adx_14d, DatabaseFieldInfo::Float), DatabaseFieldInfo("pdi_14d", DailyFields::pdi_14d, DatabaseFieldInfo::Float), DatabaseFieldInfo("mdi_14d", DailyFields::mdi_14d, DatabaseFieldInfo::Float), DatabaseFieldInfo("shares_per_print", DailyFields::shares_per_print, DatabaseFieldInfo::Float), DatabaseFieldInfo("short_interest", DailyFields::short_interest, DatabaseFieldInfo::Int), DatabaseFieldInfo("earning_day", DailyFields::earning_day, DatabaseFieldInfo::Float), DatabaseFieldInfo("sector", DailyFields::sector, DatabaseFieldInfo::String), DatabaseFieldInfo("close_1y", DailyFields::close_1y, DatabaseFieldInfo::Float), DatabaseFieldInfo("advol_3m", DailyFields::advol_3m, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_8", DailyFields::sma_8, DatabaseFieldInfo::Float), DatabaseFieldInfo("social_average", DailyFields::social_average, DatabaseFieldInfo::Float), DatabaseFieldInfo("close_last_year", DailyFields::close_last_year, DatabaseFieldInfo::Float), DatabaseFieldInfo("revenue_growth", DailyFields::revenue_growth, DatabaseFieldInfo::Float), DatabaseFieldInfo("earnings_growth", DailyFields::earnings_growth, DatabaseFieldInfo::Float), DatabaseFieldInfo("held_by_insiders", DailyFields::held_by_insiders, DatabaseFieldInfo::Float), DatabaseFieldInfo("held_by_institutions", DailyFields::held_by_institutions, DatabaseFieldInfo::Float), DatabaseFieldInfo("short_ratio", DailyFields::short_ratio, DatabaseFieldInfo::Float), DatabaseFieldInfo("short_float", DailyFields::short_float, DatabaseFieldInfo::Float), DatabaseFieldInfo("cash", DailyFields::cash, DatabaseFieldInfo::Float), DatabaseFieldInfo("enterprise_value", DailyFields::enterprise_value, DatabaseFieldInfo::Float), DatabaseFieldInfo("peg", DailyFields::peg, DatabaseFieldInfo::Float), DatabaseFieldInfo("estimated_quarterly_eps_growth", DailyFields::estimated_quarterly_eps_growth, DatabaseFieldInfo::Float), DatabaseFieldInfo("estimated_annual_eps_growth", DailyFields::estimated_annual_eps_growth, DatabaseFieldInfo::Float), DatabaseFieldInfo("short_growth", DailyFields::short_growth, DatabaseFieldInfo::Float), DatabaseFieldInfo("cusip", DailyFields::cusip, DatabaseFieldInfo::String), DatabaseFieldInfo("flt", DailyFields::flt, DatabaseFieldInfo::Float), DatabaseFieldInfo("social_q", DailyFields::social_q, DatabaseFieldInfo::Float), DatabaseFieldInfo("social_m", DailyFields::social_m, DatabaseFieldInfo::Float), DatabaseFieldInfo("social_w", DailyFields::social_w, DatabaseFieldInfo::Float), DatabaseFieldInfo("social_d", DailyFields::social_d, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_104w", DailyFields::high_104w, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_104w", DailyFields::low_104w, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_13w", DailyFields::high_13w, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_13w", DailyFields::low_13w, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_26w", DailyFields::high_26w, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_26w", DailyFields::low_26w, DatabaseFieldInfo::Float), DatabaseFieldInfo("high_39w", DailyFields::high_39w, DatabaseFieldInfo::Float), DatabaseFieldInfo("low_39w", DailyFields::low_39w, DatabaseFieldInfo::Float), DatabaseFieldInfo("avwap_2_pv", DailyFields::avwap_2_pv, DatabaseFieldInfo::Float), DatabaseFieldInfo("avwap_2_tv", DailyFields::avwap_2_tv, DatabaseFieldInfo::Float), DatabaseFieldInfo("avwap_3_pv", DailyFields::avwap_3_pv, DatabaseFieldInfo::Float), DatabaseFieldInfo("avwap_3_tv", DailyFields::avwap_3_tv, DatabaseFieldInfo::Float), DatabaseFieldInfo("avwap_4_pv", DailyFields::avwap_4_pv, DatabaseFieldInfo::Float), DatabaseFieldInfo("avwap_4_tv", DailyFields::avwap_4_tv, DatabaseFieldInfo::Float), DatabaseFieldInfo("avwap_5_pv", DailyFields::avwap_5_pv, DatabaseFieldInfo::Float), DatabaseFieldInfo("avwap_5_tv", DailyFields::avwap_5_tv, DatabaseFieldInfo::Float), DatabaseFieldInfo("sma_10", DailyFields::sma_10, DatabaseFieldInfo::Float), DatabaseFieldInfo("days_to_cover", DailyFields::days_to_cover, DatabaseFieldInfo::Float), DatabaseFieldInfo("interest_income", DailyFields::interest_income, DatabaseFieldInfo::Float), }; } std::string DatabaseFieldInfo::makeSqlFieldList (std::vector< DatabaseFieldInfo > const &fields) { assert(!fields.empty()); std::string result; bool first = true; for (std::vector< DatabaseFieldInfo >::const_iterator it = fields.begin(); it != fields.end(); it++) { if (first) first = false; else result += ','; // It's tempting to add backquotes. result += it->databaseName(); } return result; } Record::Ref DatabaseFieldInfo::makeRecord(MysqlResultRef source, std::vector< DatabaseFieldInfo > const &fields) { if ((!source->rowIsValid()) || fields.empty()) return Record::EMPTY; RecordBuilder rb; int i = 0; for (std::vector< DatabaseFieldInfo >::const_iterator it = fields.begin(); it != fields.end(); it++, i++) { if (source->fieldIsEmpty(i)) continue; const std::string asString = source->getStringField(i); switch (it->type()) { case DatabaseFieldInfo::String: rb.append(it->id(), asString); break; case DatabaseFieldInfo::Int: { try { int64_t value; nfroma(value, asString); rb.append(it->id(), value); } // Tempting to print a warning if we can't parse the number. Since // we already checking for a NULL, that shouldn't happen. Probably // means we have bad info about the data type of the field. catch (InvalidConversionException ex) { } break; } case DatabaseFieldInfo::ID: { try { int64_t value; nfroma(value, asString); rb.reserveInt(it->id(), value); } catch (InvalidConversionException ex) { rb.reserveInt(it->id()); } break; } case DatabaseFieldInfo::DateTime: case DatabaseFieldInfo::Date: { time_t value = mysqlToTimeT(asString); if (value > 0) rb.append(it->id(), value); break; } case DatabaseFieldInfo::Float: { try { double value; nfroma(value, asString); rb.append(it->id(), (float)value); } // Tempting to print a warning if we can't parse the number. Since // we already checking for a NULL, that shouldn't happen. Probably // means we have bad info about the data type of the field. catch (InvalidConversionException ex) { } break; } case DatabaseFieldInfo::BooleanYN: if (asString == "Y") rb.append(it->id(), true); else if (asString == "N") rb.append(it->id(), false); // else print warning? break; } } if (auto result = Record::create(rb.exportAsString())) return result; else return Record::EMPTY; } std::string DatabaseFieldInfo::makeSql(Record::Ref const &record, std::vector< DatabaseFieldInfo > const &fields) { std::string result; for (std::vector< DatabaseFieldInfo >::const_iterator it = fields.begin(); it != fields.end(); it++) { if (result.empty()) result += '('; else result += ','; it->appendSql(result, record); } result += ')'; return result; } std::string DatabaseFieldInfo::debugDump(Record const *record, std::vector< DatabaseFieldInfo > const &fields) { TclList result; for (std::vector< DatabaseFieldInfo >::const_iterator it = fields.begin(); it != fields.end(); it++) { const ValueBox value = record->lookUpValue(it->id()); if (value.getType() == InternalType::EMPTY) // Make the output shorter and hopefully easier to read by skipping NULL // values. continue; TclList item; item<databaseName()<type()) { case DateTime: case Date: { bool valid; int64_t iValue; value.getInt(valid, iValue); if ((!valid)||(iValue <= 0)) item<<'?'; else item< "8.57999992370605", but dtoa(8.58f) -> "8.58". // Using 8 digits instead of 7 would normally work, but occasionally // I'd see something ugly. I'm not sure if i'm loosing anything // by using only 7. item< #include "../shared/DatabaseWithRetry.h" #include "../shared/GlobalConfigFile.h" static const std::string SQL1 = "SELECT " + DatabaseFieldInfo::makeSqlFieldList(DatabaseFieldInfo::getAlertFields()) + " FROM alerts WHERE id >= "; static const std::string SQL2 = " ORDER BY id LIMIT "; static int64_t nextId = 0; static void updateNextId(Record::Ref const &record) { bool valid; int64_t id; record->lookUpValue((FieldId)MainFields::id)->getInt(valid, id); assert(valid); nextId = id + 1; } int main(int args, char *argv[]) { setlocale(LC_ALL, ""); addConfigItems("database_RO=wally-balls"); if (!addConfigItemsFromCommandLine(argv + 1)) { return 1; } configItemsComplete(); DatabaseWithRetry database(true, "read only database"); while (std::cin) { std::cout<<"How many? "; int count; std::cin>>count; if (!std::cin) break; int found = 0; const std::string sql = SQL1 + ntoa(nextId) + SQL2 + ntoa(count); for (MysqlResultRef result = database.tryQueryUntilSuccess(sql); result->rowIsValid(); result->nextRow()) { found++; Record::Ref record = DatabaseFieldInfo::makeRecord(result, DatabaseFieldInfo::getAlertFields()); std::cout<