/* Used to compare the content of the data log of the tdssniff program */ #include #include #include #include #include #include #include #include #include using namespace std; struct QUERY{ bool seen; // Has been compared vector fdefs; // Field definitions vector data; // Lines of data int cnt; QUERY(){ seen = false; cnt = -1; } }; struct SQLQUERY{ string sql; QUERY query; SQLQUERY(){} SQLQUERY(const char *_sql){ sql = _sql; } SQLQUERY(const SQLQUERY &q){ sql = q.sql; query = q.query; } }; /* Compare two string, but skip spaces Return 0 if the strings are equal, != 0 if not */ static int compare_nospace(const string &s1, const string &s2) { const char *pt1 = s1.c_str(); const char *pt2 = s2.c_str(); while (1){ pt1 = str_skip(pt1); pt2 = str_skip(pt2); if (*pt1 != *pt2){ break; }else if (*pt1 != '\0'){ pt1++; pt2++; }else{ break; } } return *pt1 == *pt2 ? 0 : 1; } static void datalog_cmp(const string &sql, const char *title, const vector &tb1, const vector &tb2) { if (tb1.size() != tb2.size()){ printf ("%s size: %lu <> %lu %s\n",title,tb1.size(),tb2.size(),sql.c_str()); }else{ bool sql_shown = false; for (unsigned i=0; i &sqls, bool sortrows, bool comparedef, bool boring) { if (boring && ( strcasecmp(newq.sql.c_str(),"SELECT @@IDENTITY")==0 || strcasecmp(newq.sql.c_str(),"set ROWCOUNT 0; select @@spid")==0 || strstr(newq.sql.c_str(),"sc.name, sc.usertype, sc.length, sc.prec, sc.scale, sc.status FROM sysobjects")!=NULL || strstr(newq.sql.c_str(),"SELECT 1 FROM SYSOBJECTS WHERE NAME")!=NULL)){ return; } map::iterator it = sqls.find(newq.sql); if (it == sqls.end()){ sqls[newq.sql] = newq.query; }else if (secondfile){ // We are reviewing a query from the second file, so we compare with the first // Already there, do a compare QUERY &q = it->second; q.seen = true; if (comparedef) datalog_cmp(it->first,"fielddef",q.fdefs,newq.query.fdefs); if (sortrows){ sort (q.data.begin(),q.data.end()); sort (newq.query.data.begin(),newq.query.data.end()); } datalog_cmp(it->first,"data",q.data,newq.query.data); if (newq.query.cnt != q.cnt){ printf ("cnt: %d <> %d %s\n",q.cnt,newq.query.cnt,it->first.c_str()); } } } int main (int argc, char *argv[]) { glocal int ret = -1; glocal bool sortrows = false; glocal int sessionid = -1; glocal bool boring = false; glocal bool comparedef = false; glocal bool notseen = false; glocal.ret = (argc,argv); setproginfo ("","0.0","..."); setarg ('s',"sortrows","Sort data rows (sybase vs mysql sort issue)",glocal.sortrows,false); setarg ('S',"session","Only compare this session ID",glocal.sessionid,false); setarg ('b',"filterboring","Eliminate some useless difference (@@identity for example)",glocal.boring, false); setarg ('d',"comparedef","Compare result set definition",glocal.comparedef,false); int ret = -1; glocal map sqls; for (int i=0; i accums; // Query currently loading, line by line glocal bool second = i > 0; (argv[i],true); const char *pt = strchr(line,':'); if (pt != NULL){ int id = atoi(pt+2); if (glocal.sessionid == -1 || glocal.sessionid==id){ if (strncmp(line,"SQL: ",5)==0){ // We start accumulating information about one query (SQL: is the first statement of the sequence) // So we process the last query with this ID const char *pt = str_skip(str_skipdig(line+5)); map::iterator itsql = glocal.accums.find(id); if (itsql != glocal.accums.end() && itsql->second.sql.size() > 0){ datalog_report (glocal.second,itsql->second,glocal.sqls,glocal.sortrows,glocal.comparedef,glocal.boring); } // Create a new query to accumulate the information for this id. glocal.accums[id] = SQLQUERY(pt); }else if (strncmp(line,"DEF: ",5)==0){ const char *pt = str_skipdig(line+5); glocal.accums[id].query.fdefs.push_back(pt); }else if (strncmp(line,"DATA: ",6)==0){ const char *pt = str_skipdig(line+6); glocal.accums[id].query.data.push_back(pt); }else if (strncmp(line,"CNT: ",5)==0){ const char *pt = str_skipdig(line+5); pt = str_skip(pt); int cnt = atoi(pt); glocal.accums[id].query.cnt = cnt; } } } return 0; // Process the last query accumulated for (map::iterator it=glocal.accums.begin(); it != glocal.accums.end(); it++){ datalog_report (glocal.second,it->second,glocal.sqls,glocal.sortrows,glocal.comparedef,glocal.boring); } if (glocal.notseen){ } } return ret; return glocal.ret; }