diff options
Diffstat (limited to 'storage/connect/tabmysql.cpp')
-rw-r--r-- | storage/connect/tabmysql.cpp | 296 |
1 files changed, 171 insertions, 125 deletions
diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp index 08938cb9626..80d384d611e 100644 --- a/storage/connect/tabmysql.cpp +++ b/storage/connect/tabmysql.cpp @@ -67,13 +67,15 @@ void PrintResult(PGLOBAL, PSEM, PQRYRES); #endif // _CONSOLE -extern "C" int trace; -extern bool xinfo; - // Used to check whether a MYSQL table is created on itself bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host, const char *db, char *tab, const char *src, int port); +/***********************************************************************/ +/* External function. */ +/***********************************************************************/ +bool ExactInfo(void); + /* -------------- Implementation of the MYSQLDEF class --------------- */ /***********************************************************************/ @@ -430,7 +432,6 @@ TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBASE(tdp) Bind = NULL; Query = NULL; - Qbuf = NULL; Fetched = false; m_Rc = RC_FX; AftRows = 0; @@ -454,7 +455,6 @@ TDBMYSQL::TDBMYSQL(PGLOBAL g, PTDBMY tdbp) : TDBASE(tdbp) Delayed = tdbp->Delayed; Bind = NULL; Query = tdbp->Query; - Qbuf = NULL; Fetched = tdbp->Fetched; m_Rc = tdbp->m_Rc; AftRows = tdbp->AftRows; @@ -495,9 +495,10 @@ PCOL TDBMYSQL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) /***********************************************************************/ bool TDBMYSQL::MakeSelect(PGLOBAL g, bool mx) { - char *tk = "`"; +//char *tk = "`"; + char tk = '`'; int len = 0, rank = 0; - bool b = false; + bool b = false, oom = false; PCOL colp; //PDBUSER dup = PlgGetUser(g); @@ -505,27 +506,24 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g, bool mx) return false; // already done if (Srcdef) { - Query = Srcdef; + Query = new(g)STRING(g, 0, Srcdef); return false; } // endif Srcdef - //Find the address of the suballocated query - Query = (char*)PlugSubAlloc(g, NULL, 0); - strcpy(Query, "SELECT "); + // Allocate the string used to contain Query + Query = new(g) STRING(g, 1023, "SELECT "); if (Columns) { for (colp = Columns; colp; colp = colp->GetNext()) if (!colp->IsSpecial()) { -// if (colp->IsSpecial()) { -// strcpy(g->Message, MSG(NO_SPEC_COL)); -// return true; -// } else { if (b) - strcat(Query, ", "); + oom |= Query->Append(", "); else b = true; - strcat(strcat(strcat(Query, tk), colp->GetName()), tk); + oom |= Query->Append(tk); + oom |= Query->Append(colp->GetName()); + oom |= Query->Append(tk); ((PMYCOL)colp)->Rank = rank++; } // endif colp @@ -534,27 +532,38 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g, bool mx) // Query count(*) from... for which we will count the rows from // Query '*' from... // (the use of a char constant minimize the result storage) - strcat(Query, (Isview) ? "*" : "'*'"); + if (Isview) + oom |= Query->Append('*'); + else + oom |= Query->Append("'*'"); + } // endif ncol - strcat(strcat(strcat(strcat(Query, " FROM "), tk), Tabname), tk); - len = strlen(Query); + oom |= Query->Append(" FROM "); + oom |= Query->Append(tk); + oom |= Query->Append(Tabname); + oom |= Query->Append(tk); + len = Query->GetLength(); if (To_CondFil) { if (!mx) { - strcat(strcat(Query, " WHERE "), To_CondFil->Body); - len = strlen(Query) + 1; + oom |= Query->Append(" WHERE "); + oom |= Query->Append(To_CondFil->Body); + len = Query->GetLength() + 1; } else len += (strlen(To_CondFil->Body) + 256); } else len += (mx ? 256 : 1); + if (oom || Query->Resize(len)) { + strcpy(g->Message, "MakeSelect: Out of memory"); + return true; + } // endif oom + if (trace) - htrc("Query=%s\n", Query); + htrc("Query=%s\n", Query->GetStr()); - // Now we know how much to suballocate - PlugSubAlloc(g, NULL, len); return false; } // end of MakeSelect @@ -563,81 +572,82 @@ bool TDBMYSQL::MakeSelect(PGLOBAL g, bool mx) /***********************************************************************/ bool TDBMYSQL::MakeInsert(PGLOBAL g) { - char *colist, *valist = NULL; char *tk = "`"; - int len = 0, qlen = 0; - bool b = false; + uint len = 0; + bool b = false, oom; PCOL colp; if (Query) return false; // already done - for (colp = Columns; colp; colp = colp->GetNext()) - if (!colp->IsSpecial()) { -// if (colp->IsSpecial()) { -// strcpy(g->Message, MSG(NO_SPEC_COL)); -// return true; -// } else { - len += (strlen(colp->GetName()) + 4); - ((PMYCOL)colp)->Rank = Nparm++; - } // endif colp - - colist = (char*)PlugSubAlloc(g, NULL, len); - *colist = '\0'; - if (Prep) { -#if defined(MYSQL_PREPARED_STATEMENTS) - valist = (char*)PlugSubAlloc(g, NULL, 2 * Nparm); - *valist = '\0'; -#else // !MYSQL_PREPARED_STATEMENTS +#if !defined(MYSQL_PREPARED_STATEMENTS) strcpy(g->Message, "Prepared statements not used (not supported)"); PushWarning(g, this); Prep = false; #endif // !MYSQL_PREPARED_STATEMENTS } // endif Prep - for (colp = Columns; colp; colp = colp->GetNext()) { - if (b) { - strcat(colist, ", "); - if (Prep) strcat(valist, ","); - } else - b = true; - - strcat(strcat(strcat(colist, tk), colp->GetName()), tk); - - // Parameter marker - if (!Prep) { - if (colp->GetResultType() == TYPE_DATE) - qlen += 20; - else - qlen += colp->GetLength(); + for (colp = Columns; colp; colp = colp->GetNext()) + if (colp->IsSpecial()) { + strcpy(g->Message, MSG(NO_SPEC_COL)); + return true; + } else { + len += (strlen(colp->GetName()) + 4); - } else // Prep - strcat(valist, "?"); + // Parameter marker + if (!Prep) { + if (colp->GetResultType() == TYPE_DATE) + len += 20; + else + len += colp->GetLength(); + + } else + len += 2; - } // endfor colp + ((PMYCOL)colp)->Rank = Nparm++; + } // endif colp // Below 40 is enough to contain the fixed part of the query - len = (strlen(Tabname) + strlen(colist) - + ((Prep) ? strlen(valist) : 0) + 40); - Query = (char*)PlugSubAlloc(g, NULL, len); + len += (strlen(Tabname) + 40); + Query = new(g) STRING(g, len); if (Delayed) - strcpy(Query, "INSERT DELAYED INTO "); + oom = Query->Set("INSERT DELAYED INTO "); else - strcpy(Query, "INSERT INTO "); + oom = Query->Set("INSERT INTO "); - strcat(strcat(strcat(Query, tk), Tabname), tk); - strcat(strcat(strcat(Query, " ("), colist), ") VALUES ("); + oom |= Query->Append(tk); + oom |= Query->Append(Tabname); + oom |= Query->Append("` ("); - if (Prep) - strcat(strcat(Query, valist), ")"); - else { - qlen += (strlen(Query) + Nparm); - Qbuf = (char *)PlugSubAlloc(g, NULL, qlen); - } // endelse Prep + for (colp = Columns; colp; colp = colp->GetNext()) { + if (b) + oom |= Query->Append(", "); + else + b = true; + + oom |= Query->Append(tk); + oom |= Query->Append(colp->GetName()); + oom |= Query->Append(tk); + } // endfor colp - return false; + oom |= Query->Append(") VALUES ("); + +#if defined(MYSQL_PREPARED_STATEMENTS) + if (Prep) { + for (int i = 0; i < Nparm; i++) + oom |= Query->Append("?,"); + + Query->RepLast(')'); + Query->Trim(); + } // endif Prep +#endif // MYSQL_PREPARED_STATEMENTS + + if (oom) + strcpy(g->Message, "MakeInsert: Out of memory"); + + return oom; } // end of MakeInsert /***********************************************************************/ @@ -646,7 +656,7 @@ bool TDBMYSQL::MakeInsert(PGLOBAL g) /***********************************************************************/ int TDBMYSQL::MakeCommand(PGLOBAL g) { - Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64); + Query = new(g) STRING(g, strlen(Qrystr) + 64); if (Quoted > 0 || stricmp(Name, Tabname)) { char *p, *qrystr, name[68]; @@ -665,16 +675,23 @@ int TDBMYSQL::MakeCommand(PGLOBAL g) strlwr(strcpy(name, Name)); // Not a keyword if ((p = strstr(qrystr, name))) { - memcpy(Query, Qrystr, p - qrystr); - Query[p - qrystr] = 0; + bool oom = Query->Set(Qrystr, p - qrystr); - if (qtd && *(p-1) == ' ') - strcat(strcat(strcat(Query, "`"), Tabname), "`"); - else - strcat(Query, Tabname); + if (qtd && *(p-1) == ' ') { + oom |= Query->Append('`'); + oom |= Query->Append(Tabname); + oom |= Query->Append('`'); + } else + oom |= Query->Append(Tabname); + + oom |= Query->Append(Qrystr + (p - qrystr) + strlen(name)); + + if (oom) { + strcpy(g->Message, "MakeCommand: Out of memory"); + return RC_FX; + } else + strlwr(strcpy(qrystr, Query->GetStr())); - strcat(Query, Qrystr + (p - qrystr) + strlen(name)); - strlwr(strcpy(qrystr, Query)); } else { sprintf(g->Message, "Cannot use this %s command", (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE"); @@ -682,7 +699,7 @@ int TDBMYSQL::MakeCommand(PGLOBAL g) } // endif p } else - strcpy(Query, Qrystr); + (void)Query->Set(Qrystr); return RC_OK; } // end of MakeCommand @@ -755,7 +772,7 @@ int TDBMYSQL::Cardinality(PGLOBAL g) if (!g) return (Mode == MODE_ANY && !Srcdef) ? 1 : 0; - if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && xinfo) { + if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) { // Info command, we must return the exact table row number char query[96]; MYSQLC myc; @@ -802,7 +819,7 @@ int TDBMYSQL::GetMaxSize(PGLOBAL g) /***********************************************************************/ int TDBMYSQL::RowNumber(PGLOBAL g, bool b) { - return N; + return N + 1; } // end of RowNumber /***********************************************************************/ @@ -871,7 +888,8 @@ bool TDBMYSQL::OpenDB(PGLOBAL g) /*********************************************************************/ if (Mode == MODE_READ || Mode == MODE_READX) { MakeSelect(g, Mode == MODE_READX); - m_Rc = (Mode == MODE_READ) ? Myc.ExecSQL(g, Query) : RC_OK; + m_Rc = (Mode == MODE_READ) + ? Myc.ExecSQL(g, Query->GetStr()) : RC_OK; #if 0 if (!Myc.m_Res || !Myc.m_Fields) { @@ -894,7 +912,8 @@ bool TDBMYSQL::OpenDB(PGLOBAL g) if (!MakeInsert(g)) { #if defined(MYSQL_PREPARED_STATEMENTS) - int n = (Prep) ? Myc.PrepareSQL(g, Query) : Nparm; + int n = (Prep) + ? Myc.PrepareSQL(g, Query->GetCharValue()) : Nparm; if (Nparm != n) { if (n >= 0) // Other errors return negative values @@ -1007,7 +1026,7 @@ int TDBMYSQL::SendCommand(PGLOBAL g) { int w; - if (Myc.ExecSQLcmd(g, Query, &w) == RC_NF) { + if (Myc.ExecSQLcmd(g, Query->GetStr(), &w) == RC_NF) { AftRows = Myc.m_Afrw; sprintf(g->Message, "%s: %d affected rows", Tabname, AftRows); PushWarning(g, this, 0); // 0 means a Note @@ -1037,28 +1056,45 @@ int TDBMYSQL::SendCommand(PGLOBAL g) /***********************************************************************/ bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const void *key, int len) { - int oldlen = strlen(Query); + bool oom; + int oldlen = Query->GetLength(); if (!key || op == OP_NEXT || Mode == MODE_UPDATE || Mode == MODE_DELETE) return false; else if (op == OP_FIRST) { - if (To_CondFil) - strcat(strcat(Query, " WHERE "), To_CondFil->Body); + if (To_CondFil) { + oom = Query->Append(" WHERE "); + + if ((oom |= Query->Append(To_CondFil->Body))) { + strcpy(g->Message, "Readkey: Out of memory"); + return true; + } // endif oom + + } // endif To_Condfil } else { if (Myc.m_Res) Myc.FreeResult(); - To_Def->GetHandler()->MakeKeyWhere(g, Query, op, "`", key, len); + To_Def->GetHandler()->MakeKeyWhere(g, Query->GetStr(), + op, "`", key, len); - if (To_CondFil) - strcat(strcat(strcat(Query, " AND ("), To_CondFil->Body), ")"); + if (To_CondFil) { + oom = Query->Append(" AND ("); + oom |= Query->Append(To_CondFil->Body); + + if ((oom |= Query->Append(')'))) { + strcpy(g->Message, "Readkey: Out of memory"); + return true; + } // endif oom + + } // endif To_Condfil } // endif's op - m_Rc = Myc.ExecSQL(g, Query); - Query[oldlen] = 0; + m_Rc = Myc.ExecSQL(g, Query->GetStr()); + Query->Truncate(oldlen); return (m_Rc == RC_FX) ? true : false; } // end of ReadKey @@ -1102,31 +1138,38 @@ int TDBMYSQL::WriteDB(PGLOBAL g) // Statement was not prepared, we must construct and execute // an insert query for each line to insert int rc; + uint len = Query->GetLength(); char buf[64]; - - strcpy(Qbuf, Query); + bool b, oom = false; // Make the Insert command value list for (PCOL colp = Columns; colp; colp = colp->GetNext()) { if (!colp->GetValue()->IsNull()) { - if (colp->GetResultType() == TYPE_STRING || - colp->GetResultType() == TYPE_DATE) - strcat(Qbuf, "'"); - - strcat(Qbuf, colp->GetValue()->GetCharString(buf)); - - if (colp->GetResultType() == TYPE_STRING || - colp->GetResultType() == TYPE_DATE) - strcat(Qbuf, "'"); - + if ((b = colp->GetResultType() == TYPE_STRING || + colp->GetResultType() == TYPE_DATE)) + oom |= Query->Append('\''); + + oom |= Query->Append(colp->GetValue()->GetCharString(buf)); + + if (b) + oom |= Query->Append('\''); + } else - strcat(Qbuf, "NULL"); - - strcat(Qbuf, (colp->GetNext()) ? "," : ")"); + oom |= Query->Append("NULL"); + + oom |= Query->Append(','); } // endfor colp - Myc.m_Rows = -1; // To execute the query - rc = Myc.ExecSQL(g, Qbuf); + if (unlikely(oom)) { + strcpy(g->Message, "WriteDB: Out of memory"); + rc = RC_FX; + } else { + Query->RepLast(')'); + Myc.m_Rows = -1; // To execute the query + rc = Myc.ExecSQL(g, Query->GetStr()); + Query->Truncate(len); // Restore query + } // endif oom + return (rc == RC_NF) ? RC_OK : rc; // RC_NF is Ok } // end of WriteDB @@ -1531,7 +1574,7 @@ bool TDBMYEXC::OpenDB(PGLOBAL g) if (!(Cmdlist = MakeCMD(g))) { Myc.Close(); return true; - } // endif Query + } // endif Cmdlist return false; } // end of OpenDB @@ -1559,9 +1602,12 @@ int TDBMYEXC::ReadDB(PGLOBAL g) int rc; do { - Query = Cmdlist->Cmd; + if (Query) + Query->Set(Cmdlist->Cmd); + else + Query = new(g) STRING(g, 0, Cmdlist->Cmd); - switch (rc = Myc.ExecSQLcmd(g, Query, &Warnings)) { + switch (rc = Myc.ExecSQLcmd(g, Query->GetStr(), &Warnings)) { case RC_NF: AftRows = Myc.m_Afrw; strcpy(g->Message, "Affected rows"); @@ -1650,11 +1696,11 @@ void MYXCOL::ReadColumn(PGLOBAL g) } else switch (Flag) { - case 0: Value->SetValue_psz(tdbp->Query); break; - case 1: Value->SetValue(tdbp->AftRows); break; - case 2: Value->SetValue_psz(g->Message); break; - case 3: Value->SetValue(tdbp->Warnings); break; - default: Value->SetValue_psz("Invalid Flag"); break; + case 0: Value->SetValue_psz(tdbp->Query->GetStr()); break; + case 1: Value->SetValue(tdbp->AftRows); break; + case 2: Value->SetValue_psz(g->Message); break; + case 3: Value->SetValue(tdbp->Warnings); break; + default: Value->SetValue_psz("Invalid Flag"); break; } // endswitch Flag } // end of ReadColumn |