summaryrefslogtreecommitdiff
path: root/storage/connect/tabmysql.cpp
diff options
context:
space:
mode:
authorOlivier Bertrand <bertrandop@gmail.com>2014-10-21 17:29:51 +0200
committerOlivier Bertrand <bertrandop@gmail.com>2014-10-21 17:29:51 +0200
commit56e27713213e5b0f7be6b3ac01f06ee26584f38a (patch)
tree38df18a52a5bdff0df36a5bc0786745091bfe179 /storage/connect/tabmysql.cpp
parentc65a9fb4c6a0c7aade6fa4c52641cfec3a88b377 (diff)
downloadmariadb-git-56e27713213e5b0f7be6b3ac01f06ee26584f38a.tar.gz
1) Handling string memory allocation with a new STRING class. This is only
the beginning. Defining the STRING class and begining to use it (MYSQL) 2) Change the xtrace, use_tempfile and exact_info connect variables from GLOBAL to SESSION. Remaining GLOBAL variables have been made readonly. 3) Take care of LEX_STRING variables. The .str should not be regarded as allways being 0 terminated. This is handled by the Strz functions that make sure to return 0 terminated strings. Bug fix: - When inserting in MYSQL table with special column(s) a query such as: insert into t2 values(0,4,'new04'),(0,5,'new05'); failed saying: column id (the special column) not found in t2. It is now accepted but must be counted in values (these 0 are ignored) - ROWID was returning row numbers based 0. Now it is from base 1. modified: storage/connect/array.cpp storage/connect/blkfil.cpp storage/connect/colblk.cpp storage/connect/connect.cc storage/connect/filamap.cpp storage/connect/filamdbf.cpp storage/connect/filamfix.cpp storage/connect/filamtxt.cpp storage/connect/filamvct.cpp storage/connect/filamzip.cpp storage/connect/filamzip.h storage/connect/filter.cpp storage/connect/global.h storage/connect/ha_connect.cc storage/connect/ha_connect.h storage/connect/libdoc.cpp storage/connect/mycat.cc storage/connect/myconn.cpp storage/connect/odbconn.cpp storage/connect/plgdbutl.cpp storage/connect/plugutil.c storage/connect/reldef.cpp storage/connect/tabcol.cpp storage/connect/tabdos.cpp storage/connect/tabfix.cpp storage/connect/tabfmt.cpp storage/connect/table.cpp storage/connect/tabmul.cpp storage/connect/tabmysql.cpp storage/connect/tabmysql.h storage/connect/taboccur.cpp storage/connect/tabodbc.cpp storage/connect/tabpivot.cpp storage/connect/tabsys.cpp storage/connect/tabtbl.cpp storage/connect/tabutil.cpp storage/connect/tabvct.cpp storage/connect/tabwmi.cpp storage/connect/tabwmi.h storage/connect/tabxcl.cpp storage/connect/tabxml.cpp storage/connect/user_connect.cc storage/connect/valblk.cpp storage/connect/value.cpp storage/connect/value.h storage/connect/xindex.cpp storage/connect/xobject.cpp storage/connect/xobject.h storage/connect/xtable.h
Diffstat (limited to 'storage/connect/tabmysql.cpp')
-rw-r--r--storage/connect/tabmysql.cpp296
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