#ifndef ____mysql_h__ #define ____mysql_h__ #include "Tag.h" #include "ZString.h" #include "MString.h" #include #include #include #include namespace jet { class __mysql : public Tag { public: __mysql(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local); ~__mysql(); void query(coreutils::MString query); void nextRow(); bool hasRow(); coreutils::ZString getColumnValue(coreutils::ZString column); private: // Explicitly initialized - result/row/fieldLength were otherwise // left as garbage stack values until query() first ran. A // ... block that connects successfully but never // runs a query inside it (e.g. just a connectivity check) // would previously reach ~__mysql()'s mysql_free_result(result) // with an uninitialized pointer - real undefined behavior, found // while root-causing a live crash in a related part of this same // class's constructor. MYSQL *mysql = NULL; MYSQL_RES *result = NULL; MYSQL_ROW row = NULL; unsigned long *fieldLength = NULL; unsigned int qFields = 0; coreutils::MString sessionId; // Column-name -> row[] index, built once per query() call (see its // own comment) instead of getColumnValue() re-deriving it via a // fresh mysql_fetch_field_direct() linear scan on every single // named lookup - a template reading N columns off one row used to // pay that scan N times over, even though the schema is fixed for // the lifetime of one result set. std::unordered_map fieldIndex; coreutils::MString nbrOfRows = "0"; coreutils::MString nbrOfColumns = "0"; }; } #endif