// Used to check whether a MYSQL table is created on itself bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, PCSZ host, PCSZ db,
PCSZ tab, PCSZ src, int port);
/***********************************************************************/ /* Get connection info from the declared server. */ /***********************************************************************/ bool MYSQLDEF::GetServerInfo(PGLOBAL g, constchar *server_name)
{
THD *thd= current_thd;
MEM_ROOT *mem= thd->mem_root;
FOREIGN_SERVER *server, server_buffer;
DBUG_ENTER("GetServerInfo");
DBUG_PRINT("info", ("server_name %s", server_name));
if (!server_name || !strlen(server_name)) {
DBUG_PRINT("info", ("server_name not defined!"));
snprintf(g->Message, sizeof(g->Message), "server_name not defined!");
DBUG_RETURN(true);
} // endif server_name
// get_server_by_name() clones the server if exists and allocates // copies of strings in the supplied mem_root if (!(server= get_server_by_name(mem, server_name, &server_buffer))) {
DBUG_PRINT("info", ("get_server_by_name returned > 0 error condition!")); /* need to come up with error handling */
snprintf(g->Message, sizeof(g->Message), "get_server_by_name returned > 0 error condition!");
DBUG_RETURN(true);
} // endif server
DBUG_PRINT("info", ("get_server_by_name returned server at %p",
server));
// TODO: We need to examine which of these can really be NULL
Hostname = PlugDup(g, server->host);
Tabschema = PlugDup(g, server->db);
Username = PlugDup(g, server->username);
Password = PlugDup(g, server->password);
Portnumber = (server->port) ? server->port : GetDefaultPort();
DBUG_RETURN(false);
} // end of GetServerInfo
/***********************************************************************/ /* Parse connection string */ /* */ /* SYNOPSIS */ /* ParseURL() */ /* url The connection string to parse */ /* */ /* DESCRIPTION */ /* Populates the table with information about the connection */ /* to the foreign database that will serve as the data source. */ /* This string must be specified (currently) in the "CONNECTION" */ /* field, listed in the CREATE TABLE statement. */ /* */ /* This string MUST be in the format of any of these: */ /* */ /* CONNECTION="scheme://user:pwd@host:port/database/table" */ /* CONNECTION="scheme://user@host/database/table" */ /* CONNECTION="scheme://user@host:port/database/table" */ /* CONNECTION="scheme://user:pwd@host/database/table" */ /* */ /* _OR_ */ /* */ /* CONNECTION="connection name" (NIY) */ /* */ /* An Example: */ /* */ /* CREATE TABLE t1 (id int(32)) */ /* ENGINE="CONNECT" TABLE_TYPE="MYSQL" */ /* CONNECTION="mysql://joe:pwd@192.168.1.111:9308/dbname/tabname"; */ /* */ /* CREATE TABLE t2 ( */ /* id int(4) NOT NULL auto_increment, */ /* name varchar(32) NOT NULL, */ /* PRIMARY KEY(id) */ /* ) ENGINE="CONNECT" TABLE_TYPE="MYSQL" */ /* CONNECTION="my_conn"; (NIY) */ /* */ /* 'password' and 'port' are both optional. */ /* */ /* RETURN VALUE */ /* false success */ /* true error */ /* */ /***********************************************************************/ bool MYSQLDEF::ParseURL(PGLOBAL g, char *url, bool b)
{ char *tabn, *pwd, *schema;
if ((!strstr(url, "://") && (!strchr(url, '@')))) { // No :// or @ in connection string. Must be a straight // connection name of either "server" or "server/table" // ok, so we do a little parsing, but not completely! if ((tabn= strchr(url, '/'))) { // If there is a single '/' in the connection string, // this means the user is specifying a table name
*tabn++= '\0';
// there better not be any more '/'s ! if (strchr(tabn, '/')) returntrue;
if (trace(1))
htrc("server: %s TableName: %s", url, Tabname);
Server = url; return GetServerInfo(g, url);
} else { // URL, parse it char *sport, *scheme = url;
if (!(Username = strstr(url, "://"))) {
snprintf(g->Message, sizeof(g->Message), "Connection is not an URL"); returntrue;
} // endif User
scheme[Username - scheme] = 0;
if (stricmp(scheme, "mysql")) {
snprintf(g->Message, sizeof(g->Message), "scheme must be mysql"); returntrue;
} // endif scheme
Username += 3;
if (!(Hostname = (char*)strchr(Username, '@'))) {
snprintf(g->Message, sizeof(g->Message), "No host specified in URL"); returntrue;
} else {
*Hostname++ = 0; // End Username
Server = Hostname;
} // endif Hostname
if ((pwd = (char*)strchr(Username, ':'))) {
*pwd++ = 0; // End username
// Make sure there isn't an extra / if (strchr(pwd, '/')) {
snprintf(g->Message, sizeof(g->Message), "Syntax error in URL"); returntrue;
} // endif
// Found that if the string is: // user:@hostname:port/db/table // Then password is a null string, so set to NULL if (pwd[0] == 0)
Password = NULL; else
Password = pwd;
} // endif password
// Make sure there isn't an extra / or @ */ if ((strchr(Username, '/')) || (strchr(Hostname, '@'))) {
snprintf(g->Message, sizeof(g->Message), "Syntax error in URL"); returntrue;
} // endif
if ((schema = strchr(Hostname, '/'))) {
*schema++ = 0;
if ((tabn = strchr(schema, '/'))) {
*tabn++ = 0;
// Make sure there's not an extra / if ((strchr(tabn, '/'))) {
snprintf(g->Message, sizeof(g->Message), "Syntax error in URL"); returntrue;
} // endif /
Tabname = tabn;
} // endif TableName
Tabschema = schema;
} // endif database
if ((sport = strchr(Hostname, ':')))
*sport++ = 0;
// For unspecified values, get the values of old style options // but only if called from MYSQLDEF, else set them to NULL
Portnumber = (sport && sport[0]) ? atoi(sport)
: (b) ? GetIntCatInfo("Port", GetDefaultPort()) : 0;
/***********************************************************************/ /* Allocate MYSQL column description block. */ /***********************************************************************/
PCOL TDBMYSQL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{ returnnew(g) MYSQLCOL(cdp, this, cprec, n);
} // end of MakeCol
/***********************************************************************/ /* MakeSelect: make the Select statement use with MySQL connection. */ /* Note: when implementing EOM filtering, column only used in local */ /* filter should be removed from column list. */ /***********************************************************************/ bool TDBMYSQL::MakeSelect(PGLOBAL g, bool mx)
{ //char *tk = "`"; char tk = '`'; int len = 0, rank = 0; bool b = false;
PCOL colp; //PDBUSER dup = PlgGetUser(g);
if (Query) returnfalse; // already done
if (Srcdef) return MakeSrcdef(g);
// 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 (b)
Query->Append(", "); else
b = true;
} else { // ncol == 0 can occur for views or queries such as // Query count(*) from... for which we will count the rows from // Query '*' from... // (the use of a char constant minimize the result storage) if (Isview)
Query->Append('*'); else
Query->Append("'*'");
} // endif ncol
Query->Append(" FROM ");
Query->Append(tk);
Query->Append(TableName);
Query->Append(tk);
len = Query->GetLength();
if (To_CondFil) { if (!mx) {
Query->Append(" WHERE ");
Query->Append(To_CondFil->Body);
len = Query->GetLength() + 1;
} else
len += (strlen(To_CondFil->Body) + 256);
} else
len += (mx ? 256 : 1);
if (Query->IsTruncated() || Query->Resize(len)) {
snprintf(g->Message, sizeof(g->Message), "MakeSelect: Out of memory"); returntrue;
} // endif Query
if (trace(33))
htrc("Query=%s\n", Query->GetStr());
returnfalse;
} // end of MakeSelect
/***********************************************************************/ /* MakeInsert: make the Insert statement used with MySQL connection. */ /***********************************************************************/ bool TDBMYSQL::MakeInsert(PGLOBAL g)
{ constchar *tk = "`";
uint len = 0; bool oom, b = false;
PCOL colp;
if (Query) returnfalse; // already done
if (Prep) { #if !defined(MYSQL_PREPARED_STATEMENTS)
snprintf(g->Message, sizeof(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 (colp->IsSpecial()) {
snprintf(g->Message, sizeof(g->Message), MSG(NO_SPEC_COL)); returntrue;
} else {
len += (strlen(colp->GetName()) + 4);
// Parameter marker if (!Prep) { if (colp->GetResultType() == TYPE_DATE)
len += 20; else
len += colp->GetLength();
} else
len += 2;
((PMYCOL)colp)->Rank = Nparm++;
} // endif colp
// Below 40 is enough to contain the fixed part of the query
len += (strlen(TableName) + 40);
Query = new(g) STRING(g, len);
Query->Set("INSERT "); if (Delayed)
Query->Append("DELAYED "); if (Ignored)
Query->Append("IGNORE ");
if ((oom = Query->IsTruncated()))
snprintf(g->Message, sizeof(g->Message), "MakeInsert: Out of memory");
return oom;
} // end of MakeInsert
/***********************************************************************/ /* MakeCommand: make the Update or Delete statement to send to the */ /* MySQL server. Limited to remote values and filtering. */ /***********************************************************************/ bool TDBMYSQL::MakeCommand(PGLOBAL g)
{
Query = new(g) STRING(g, strlen(Qrystr) + 64);
// Make a lower case copy of the originale query
qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 5);
strlwr(strcpy(qrystr, Qrystr));
// Check whether the table name is equal to a keyword // If so, it must be quoted in the original query
strlwr(strcat(strcat(strcpy(name, "`"), Name), "`"));
if (!strstr("`update`delete`low_priority`ignore`quick`from`", name))
strlwr(strcpy(name, Name)); // Not a keyword
if ((p = strstr(qrystr, name))) {
Query->Set(Qrystr, (uint)(p - qrystr));
if (Query->IsTruncated()) {
snprintf(g->Message, sizeof(g->Message), "MakeCommand: Out of memory"); returntrue;
} else
strlwr(strcpy(qrystr, Query->GetStr()));
} else {
snprintf(g->Message, sizeof(g->Message), "Cannot use this %s command",
(Mode == MODE_UPDATE) ? "UPDATE" : "DELETE"); returntrue;
} // endif p
} else
(void)Query->Set(Qrystr);
returnfalse;
} // end of MakeCommand
#if0 /***********************************************************************/ /* MakeUpdate: make the Update statement use with MySQL connection. */ /* Limited to remote values and filtering. */ /***********************************************************************/ int TDBMYSQL::MakeUpdate(PGLOBAL g)
{ char *qc, cmd[8], tab[96], end[1024];
assert(!stricmp(cmd, "update"));
strcat(strcat(strcat(strcpy(Query, "UPDATE "), qc), TableName), qc);
strcat(Query, end); return RC_OK;
} // end of MakeUpdate
/***********************************************************************/ /* MakeDelete: make the Delete statement used with MySQL connection. */ /* Limited to remote filtering. */ /***********************************************************************/ int TDBMYSQL::MakeDelete(PGLOBAL g)
{ char *qc, cmd[8], from[8], tab[96], end[512];
/***********************************************************************/ /* MYSQL Cardinality: returns the number of rows in the table. */ /***********************************************************************/ int TDBMYSQL::Cardinality(PGLOBAL g)
{ if (!g) return (Mode == MODE_ANY && !Srcdef) ? 1 : 0;
if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) { // Info command, we must return the exact table row number char query[96];
MYSQLC myc;
if (myc.Open(g, Host, Schema, User, Pwd, Port, csname)) return -1;
Cardinal = myc.GetTableSize(g, query);
myc.Close();
} else
Cardinal = 10; // To make MySQL happy
return Cardinal;
} // end of Cardinality
#if0 /***********************************************************************/ /* MYSQL GetMaxSize: returns the maximum number of rows in the table. */ /***********************************************************************/ int TDBMYSQL::GetMaxSize(PGLOBAL g)
{ if (MaxSize < 0) { if (Mode == MODE_DELETE) // Return 0 in mode DELETE in case of delete all.
MaxSize = 0; elseif (!Cardinality(NULL))
MaxSize = 10; // To make MySQL happy elseif ((MaxSize = Cardinality(g)) < 0)
MaxSize = 12; // So we can see an error occurred
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize #endif// 0
/***********************************************************************/ /* This a fake routine as ROWID does not exist in MySQL. */ /***********************************************************************/ int TDBMYSQL::RowNumber(PGLOBAL, bool)
{ return N + 1;
} // end of RowNumber
/***********************************************************************/ /* Return 0 in mode UPDATE to tell that the update is done. */ /***********************************************************************/ int TDBMYSQL::GetProgMax(PGLOBAL g)
{ return (Mode == MODE_UPDATE) ? 0 : GetMaxSize(g);
} // end of GetProgMax
/***********************************************************************/ /* MySQL Bind Parameter function. */ /***********************************************************************/ int TDBMYSQL::BindColumns(PGLOBAL g __attribute__((unused)))
{ #ifdefined(MYSQL_PREPARED_STATEMENTS) if (Prep) {
Bind = (MYSQL_BIND*)PlugSubAlloc(g, NULL, Nparm * sizeof(MYSQL_BIND));
for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next)
colp->InitBind(g);
/***********************************************************************/ /* MySQL Access Method opening routine. */ /***********************************************************************/ bool TDBMYSQL::OpenDB(PGLOBAL g)
{ if (Use == USE_OPEN) { /*******************************************************************/ /* Table already open, just replace it at its beginning. */ /*******************************************************************/ if (Myc.Rewind(g, (Mode == MODE_READX) ? Query->GetStr() : NULL) != RC_OK) returntrue;
N = -1; returnfalse;
} // endif use
/*********************************************************************/ /* Open a MySQL connection for this table. */ /* Note: this may not be the proper way to do. Perhaps it is better */ /* to test whether a connection is already open for this server */ /* and if so to allocate just a new result set. But this only for */ /* servers allowing concurency in getting results ??? */ /*********************************************************************/ if (!Myc.Connected()) { if (Myc.Open(g, Host, Schema, User, Pwd, Port, csname)) returntrue;
} // endif Connected
/*********************************************************************/ /* Take care of DATE columns. */ /*********************************************************************/ for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next) if (colp->Buf_Type == TYPE_DATE) // Format must match DATETIME MySQL type
((DTVAL*)colp->GetValue())->SetFormat(g, "YYYY-MM-DD hh:mm:ss", 19);
/*********************************************************************/ /* Allocate whatever is used for getting results. */ /*********************************************************************/ if (Mode == MODE_READ || Mode == MODE_READX) {
MakeSelect(g, Mode == MODE_READX); if (Mode == MODE_READ && !Query)
{
Myc.Close(); returntrue;
}
m_Rc = (Mode == MODE_READ)
? Myc.ExecSQL(g, Query->GetStr()) : RC_OK;
/***********************************************************************/ /* Set the rank of columns in the result set. */ /***********************************************************************/ bool TDBMYSQL::SetColumnRanks(PGLOBAL g)
{ for (PCOL colp = Columns; colp; colp = colp->GetNext()) if (((PMYCOL)colp)->FindRank(g)) returntrue;
returnfalse;
} // end of SetColumnRanks
/***********************************************************************/ /* Called by Parent table to make the columns of a View. */ /***********************************************************************/
PCOL TDBMYSQL::MakeFieldColumn(PGLOBAL g, char *name)
{ int n;
MYSQL_FIELD *fld;
PCOL cp, colp = NULL;
for (n = 0; n < Myc.m_Fields; n++) {
fld = &Myc.m_Res->fields[n];
if (!stricmp(name, fld->name)) {
colp = new(g) MYSQLCOL(fld, this, n);
if (colp->InitValue(g)) return NULL;
if (!Columns)
Columns = colp; elsefor (cp = Columns; cp; cp = cp->GetNext()) if (!cp->GetNext()) {
cp->SetNext(colp); break;
} // endif Next
break;
} // endif name
} // endfor n
if (!colp)
snprintf(g->Message, sizeof(g->Message), "Column %s is not in view", name);
return colp;
} // end of MakeFieldColumn
/***********************************************************************/ /* Called by Pivot tables to find default column names in a View */ /* as the name of last field not equal to the passed name. */ /***********************************************************************/ char *TDBMYSQL::FindFieldColumn(char *name)
{ int n;
MYSQL_FIELD *fld; char *cp = NULL;
for (n = Myc.m_Fields - 1; n >= 0; n--) {
fld = &Myc.m_Res->fields[n];
if (!name || stricmp(name, fld->name)) {
cp = fld->name; break;
} // endif name
} // endfor n
return cp;
} // end of FindFieldColumn
/***********************************************************************/ /* Send an UPDATE or DELETE command to the remote server. */ /***********************************************************************/ int TDBMYSQL::SendCommand(PGLOBAL g)
{ int w;
if (Myc.ExecSQLcmd(g, Query->GetStr(), &w) == RC_NF) {
AftRows = Myc.m_Afrw;
snprintf(g->Message, sizeof(g->Message), "%s: %d affected rows", TableName, AftRows);
PushWarning(g, this, 0); // 0 means a Note
if (trace(1))
htrc("%s\n", g->Message);
if (w && Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK) { // We got warnings from the remote server while (Myc.Fetch(g, -1) == RC_OK) {
snprintf(g->Message, sizeof(g->Message), "%s: (%s) %s", TableName,
Myc.GetCharField(1), Myc.GetCharField(2));
PushWarning(g, this);
} // endwhile Fetch
Myc.FreeResult();
} // endif w
return RC_EF; // Nothing else to do
} else return RC_FX; // Error
} // end of SendCommand
/***********************************************************************/ /* Data Base indexed read routine for MYSQL access method. */ /***********************************************************************/ bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
{ int oldlen = Query->GetLength();
PHC hc = To_Def->GetHandler();
if (!(kr || hc->end_range) || op == OP_NEXT ||
Mode == MODE_UPDATE || Mode == MODE_DELETE) { if (!kr && Mode == MODE_READX) { // This is a false indexed read
m_Rc = Myc.ExecSQL(g, Query->GetStr());
Mode = MODE_READ; return (m_Rc == RC_FX) ? true : false;
} // endif key
returnfalse;
} else { if (Myc.m_Res)
Myc.FreeResult();
if (hc->MakeKeyWhere(g, Query, op, '`', kr)) returntrue;
if (To_CondFil) { if (To_CondFil->Idx != hc->active_index) {
To_CondFil->Idx = hc->active_index;
To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
*To_CondFil->Body= 0;
if (To_CondFil) if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
snprintf(g->Message, sizeof(g->Message), "Readkey: Out of memory"); returntrue;
} // endif Append
} // endif To_Condfil
Mode = MODE_READ;
} // endif's op
if (trace(33))
htrc("MYSQL ReadKey: Query=%s\n", Query->GetStr());
m_Rc = Myc.ExecSQL(g, Query->GetStr());
Query->Truncate(oldlen); return (m_Rc == RC_FX) ? true : false;
} // end of ReadKey
/***********************************************************************/ /* Data Base read routine for MYSQL access method. */ /***********************************************************************/ int TDBMYSQL::ReadDB(PGLOBAL g)
{ int rc;
if (trace(2))
htrc("MySQL ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode);
if (Mode == MODE_UPDATE || Mode == MODE_DELETE) return SendCommand(g);
/*********************************************************************/ /* Now start the reading process. */ /* Here is the place to fetch the line. */ /*********************************************************************/
N++;
Fetched = ((rc = Myc.Fetch(g, -1)) == RC_OK);
if (trace(2))
htrc(" Read: rc=%d\n", rc);
return rc;
} // end of ReadDB
/***********************************************************************/ /* WriteDB: Data Base write routine for MYSQL access methods. */ /***********************************************************************/ int TDBMYSQL::WriteDB(PGLOBAL g)
{ #ifdefined(MYSQL_PREPARED_STATEMENTS) if (Prep) return Myc.ExecStmt(g); #endif// MYSQL_PREPARED_STATEMENTS
// 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];
// 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)
Query->Append_quoted(colp->GetValue()->GetCharString(buf)); else
Query->Append(colp->GetValue()->GetCharString(buf));
} else
Query->Append("NULL");
Query->Append(',');
} // endfor colp
if (unlikely(Query->IsTruncated())) {
snprintf(g->Message, sizeof(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 Query
return (rc == RC_NF) ? RC_OK : rc; // RC_NF is Ok
} // end of WriteDB
/***********************************************************************/ /* Data Base delete all routine for MYSQL access methods. */ /***********************************************************************/ int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
{ if (irc == RC_FX) // Send the DELETE (all) command to the remote table return (SendCommand(g) == RC_FX) ? RC_FX : RC_OK; else return RC_OK; // Ignore
} // end of DeleteDB
/***********************************************************************/ /* Data Base close routine for MySQL access method. */ /***********************************************************************/ void TDBMYSQL::CloseDB(PGLOBAL g)
{ if (Myc.Connected()) {
Myc.Close();
} // endif Myc
if (trace(1))
htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc);
/***********************************************************************/ /* MYSQLCOL public constructor. */ /***********************************************************************/
MYSQLCOL::MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
: COLBLK(cdp, tdbp, i)
{ if (cprec) {
Next = cprec->GetNext();
cprec->SetNext(this);
} else {
Next = tdbp->GetColumns();
tdbp->SetColumns(this);
} // endif cprec
// Set additional MySQL access method information for column.
Precision = Long = cdp->GetLong();
Bind = NULL;
To_Val = NULL;
Slen = 0;
Rank = -1; // Not known yet
if (trace(1))
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
} // end of MYSQLCOL constructor
/***********************************************************************/ /* MYSQLCOL public constructor. */ /***********************************************************************/
MYSQLCOL::MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am)
: COLBLK(NULL, tdbp, i)
{ //const char *chset = get_charset_name(fld->charsetnr); //char v = (!strcmp(chset, "binary")) ? 'B' : 0; char v = 0;
// Set additional MySQL access method information for column.
Bind = NULL;
To_Val = NULL;
Slen = 0;
Rank = i;
if (trace(1))
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
} // end of MYSQLCOL constructor
/***********************************************************************/ /* MYSQLCOL constructor used for copying columns. */ /* tdbp is the pointer to the new table descriptor. */ /***********************************************************************/
MYSQLCOL::MYSQLCOL(MYSQLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
{ Long = col1->Long;
Bind = NULL;
To_Val = NULL;
Slen = col1->Slen;
Rank = col1->Rank;
} // end of MYSQLCOL copy constructor
/***********************************************************************/ /* FindRank: Find the rank of this column in the result set. */ /***********************************************************************/ bool MYSQLCOL::FindRank(PGLOBAL g)
{ int n;
MYSQLC myc = ((PTDBMY)To_Tdb)->Myc;
for (n = 0; n < myc.m_Fields; n++) if (!stricmp(Name, myc.m_Res->fields[n].name)) {
Rank = n; returnfalse;
} // endif Name
snprintf(g->Message, sizeof(g->Message), "Column %s not in result set", Name); returntrue;
} // end of FindRank
/***********************************************************************/ /* SetBuffer: prepare a column block for write operation. */ /***********************************************************************/ bool MYSQLCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
{ if (!(To_Val = value)) {
snprintf(g->Message, sizeof(g->Message), MSG(VALUE_ERROR), Name); returntrue;
} elseif (Buf_Type == value->GetType()) { // Values are of the (good) column type if (Buf_Type == TYPE_DATE) { // If any of the date values is formatted // output format must be set for the receiving table if (GetDomain() || ((DTVAL *)value)->IsFormatted()) goto newval; // This will make a new value;
} elseif (Buf_Type == TYPE_DOUBLE) // Float values must be written with the correct (column) precision // Note: maybe this should be forced by ShowValue instead of this ?
value->SetPrec(GetScale());
Value = value; // Directly access the external value
} else { // Values are not of the (good) column type if (check) {
snprintf(g->Message, sizeof(g->Message), MSG(TYPE_VALUE_ERR), Name,
GetTypeName(Buf_Type), GetTypeName(value->GetType())); returntrue;
} // endif check
newval: if (InitValue(g)) // Allocate the matching value block returntrue;
} // endif's Value, Buf_Type
// Because Colblk's have been made from a copy of the original TDB in // case of Update, we must reset them to point to the original one. if (To_Tdb->GetOrig())
To_Tdb = (PTDB)To_Tdb->GetOrig();
// Set the Column
Status = (ok) ? BUF_EMPTY : BUF_NO; returnfalse;
} // end of SetBuffer
/***********************************************************************/ /* InitBind: Initialize the bind structure according to type. */ /***********************************************************************/ void MYSQLCOL::InitBind(PGLOBAL g)
{
PTDBMY tdbp = (PTDBMY)To_Tdb;
/*********************************************************************/ /* If physical fetching of the line was deferred, do it now. */ /*********************************************************************/ if (!tdbp->Fetched)
{ if ((rc = tdbp->Myc.Fetch(g, tdbp->N)) != RC_OK) { if (rc == RC_EF)
snprintf(g->Message, sizeof(g->Message), MSG(INV_DEF_READ), rc);
throw11;
} else
tdbp->Fetched = true;
} if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank))) { if (trace(2))
htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf);
// TODO: have a true way to differenciate temporal values if (Buf_Type == TYPE_DATE && strlen(buf) == 8) // This is a TIME value
p = strcat(strcpy(tim, "1970-01-01 "), buf); else
p = buf;
if (Value->SetValue_char(p, strlen(p))) {
snprintf(g->Message, sizeof(g->Message), "Out of range value for column %s at row %d",
Name, tdbp->RowNumber(g));
PushWarning(g, tdbp);
} // endif SetValue_char
} else { if (Nullable)
Value->SetNull(true);
Value->Reset(); // Null value
} // endif buf
} // end of ReadColumn
/***********************************************************************/ /* WriteColumn: make sure the bind buffer is updated. */ /***********************************************************************/ void MYSQLCOL::WriteColumn(PGLOBAL)
{ /*********************************************************************/ /* Do convert the column value if necessary. */ /*********************************************************************/ if (Value != To_Val)
Value->SetValue_pval(To_Val, false); // Convert the inserted value
/***********************************************************************/ /* MakeCMD: make the SQL statement to send to MYSQL connection. */ /***********************************************************************/
PCMD TDBMYEXC::MakeCMD(PGLOBAL g)
{
PCMD xcmd = NULL;
if (To_CondFil) { if (Cmdcol) { if (!stricmp(Cmdcol, To_CondFil->Body) &&
(To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) {
xcmd = To_CondFil->Cmds;
} else
snprintf(g->Message, sizeof(g->Message), "Invalid command specification filter");
} else
snprintf(g->Message, sizeof(g->Message), "No command column in select list");
/***********************************************************************/ /* EXC GetMaxSize: returns the maximum number of rows in the table. */ /***********************************************************************/ int TDBMYEXC::GetMaxSize(PGLOBAL)
{ if (MaxSize < 0) {
MaxSize = 10; // a guess
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/ /* MySQL Exec Access Method opening routine. */ /***********************************************************************/ bool TDBMYEXC::OpenDB(PGLOBAL g)
{ if (Use == USE_OPEN) {
snprintf(g->Message, sizeof(g->Message), "Multiple execution is not allowed"); returntrue;
} // endif use
/*********************************************************************/ /* Open a MySQL connection for this table. */ /* Note: this may not be the proper way to do. Perhaps it is better */ /* to test whether a connection is already open for this server */ /* and if so to allocate just a new result set. But this only for */ /* servers allowing concurency in getting results ??? */ /*********************************************************************/ if (!Myc.Connected()) if (Myc.Open(g, Host, Schema, User, Pwd, Port)) returntrue;
Use = USE_OPEN; // Do it now in case we are recursively called
if (Mode != MODE_READ && Mode != MODE_READX) {
snprintf(g->Message, sizeof(g->Message), "No INSERT/DELETE/UPDATE of MYSQL EXEC tables"); returntrue;
} // endif Mode
/*********************************************************************/ /* Get the command to execute. */ /*********************************************************************/ if (!(Cmdlist = MakeCMD(g))) { // Next lines commented out because of CHECK TABLE //Myc.Close(); //return true;
} // endif Cmdlist
returnfalse;
} // end of OpenDB
/***********************************************************************/ /* Data Base read routine for MYSQL access method. */ /***********************************************************************/ int TDBMYEXC::ReadDB(PGLOBAL g)
{ if (Havew) { // Process result set from SHOW WARNINGS if (Myc.Fetch(g, -1) != RC_OK) {
Myc.FreeResult();
Havew = Isw = false;
} else {
N++;
Isw = true; return RC_OK;
} // endif Fetch
} // endif m_Res
if (Cmdlist) { // Process query to send int rc;
do { if (Query)
Query->Set(Cmdlist->Cmd); else
Query = new(g) STRING(g, 0, Cmdlist->Cmd);
switch (rc = Myc.ExecSQLcmd(g, Query->GetStr(), &Warnings)) { case RC_NF:
AftRows = Myc.m_Afrw;
snprintf(g->Message, sizeof(g->Message), "Affected rows"); break; case RC_OK:
AftRows = Myc.m_Fields;
snprintf(g->Message, sizeof(g->Message), "Result set columns"); break; case RC_FX:
AftRows = Myc.m_Afrw;
Nerr++; break; case RC_INFO:
Shw = true;
} // endswitch rc
/***********************************************************************/ /* WriteDB: Data Base write routine for Exec MYSQL access methods. */ /***********************************************************************/ int TDBMYEXC::WriteDB(PGLOBAL g)
{
snprintf(g->Message, sizeof(g->Message), "EXEC MYSQL tables are read only"); return RC_FX;
} // end of WriteDB
/***********************************************************************/ /* MYXCOL public constructor. */ /***********************************************************************/
MYXCOL::MYXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
: MYSQLCOL(cdp, tdbp, cprec, i, am)
{ // Set additional EXEC MYSQL access method information for column.
Flag = cdp->GetOffset();
} // end of MYSQLCOL constructor
/***********************************************************************/ /* MYSQLCOL public constructor. */ /***********************************************************************/
MYXCOL::MYXCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am)
: MYSQLCOL(fld, tdbp, i, am)
{ if (trace(1))
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
} // end of MYSQLCOL constructor
/***********************************************************************/ /* MYXCOL constructor used for copying columns. */ /* tdbp is the pointer to the new table descriptor. */ /***********************************************************************/
MYXCOL::MYXCOL(MYXCOL *col1, PTDB tdbp) : MYSQLCOL(col1, tdbp)
{
Flag = col1->Flag;
} // end of MYXCOL copy constructor
/***********************************************************************/ /* WriteColumn: should never be called. */ /***********************************************************************/ void MYXCOL::WriteColumn(PGLOBAL)
{
assert(false);
} // end of WriteColumn
/* ---------------------------TDBMCL class --------------------------- */
/***********************************************************************/ /* TDBMCL class constructor. */ /***********************************************************************/
TDBMCL::TDBMCL(PMYDEF tdp) : TDBCAT(tdp)
{
Host = tdp->Hostname;
Db = tdp->Tabschema;
Tab = tdp->Tabname;
User = tdp->Username;
Pwd = tdp->Password;
Port = tdp->Portnumber;
} // end of TDBMCL constructor
/***********************************************************************/ /* GetResult: Get the list the MYSQL table columns. */ /***********************************************************************/
PQRYRES TDBMCL::GetResult(PGLOBAL g)
{ return MyColumns(g, NULL, Host, Db, User, Pwd, Tab, NULL, Port, false);
} // end of GetResult
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.