From 9f7c3fedfacdc62a30e1c9cd4ef2cdf900abffba Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 28 May 2013 17:22:38 +0200 Subject: [PATCH] - Extending connect_assisted_discovery column automatic definition to OCCUR and PIVOT table types. modified: storage/connect/ha_connect.cc storage/connect/myconn.cpp storage/connect/myconn.h storage/connect/plgdbsem.h storage/connect/plgdbutl.cpp storage/connect/taboccur.cpp storage/connect/taboccur.h storage/connect/tabpivot.cpp storage/connect/tabpivot.h - Fix wrong definition of GetVlen for TYPE template modified: storage/connect/valblk.h --- storage/connect/ha_connect.cc | 76 ++++++++--- storage/connect/myconn.cpp | 9 +- storage/connect/myconn.h | 2 + storage/connect/plgdbsem.h | 1 + storage/connect/plgdbutl.cpp | 1 + storage/connect/taboccur.cpp | 234 ++++++++++++++++++++++++++++++---- storage/connect/taboccur.h | 1 - storage/connect/tabpivot.cpp | 178 +++++++++++++++++++++++++- storage/connect/tabpivot.h | 36 +++++- storage/connect/valblk.h | 3 +- 10 files changed, 494 insertions(+), 47 deletions(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index ba96f99e28a..db789dda5bd 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -27,11 +27,12 @@ ha_connect will let you create/open/delete tables, the created table can be done specifying an already existing file, the drop table command will just suppress the table definition but not the eventual data file. - Indexes are not yet supported but data can be inserted, updated or deleted. + Indexes are not supported for all table types but data can be inserted, + updated or deleted. You can enable the CONNECT storage engine in your build by doing the following during your build process:
./configure - --with-connect-storage-engine (not implemented yet) + --with-connect-storage-engine You can install the CONNECT handler as all other storage handlers. @@ -166,6 +167,16 @@ extern "C" { int trace= 0; // The general trace value } // extern "C" +bool OcrColumns(PGLOBAL g, PQRYRES qrp, const char *col, + const char *ocr, const char *rank); +bool OcrSrcCols(PGLOBAL g, PQRYRES qrp, const char *col, + const char *ocr, const char *rank); +PQRYRES PivotColumns(PGLOBAL g, const char *tab, const char *src, + const char *picol, const char *fncol, + const char *host, const char *db, + const char *user, const char *pwd, + int port); + /****************************************************************************/ /* Initialize the ha_connect static members. */ /****************************************************************************/ @@ -3333,7 +3344,7 @@ static char *encode(PGLOBAL g, char *cnm) */ static bool add_field(String *sql, const char *field_name, const char *type, - int len, int dec, uint tm, const char *rem) + int len, int dec, uint tm, const char *rem, int flag) { bool error= false; @@ -3341,15 +3352,18 @@ static bool add_field(String *sql, const char *field_name, const char *type, error|= sql->append(field_name); error|= sql->append("` "); error|= sql->append(type); + if (len) { error|= sql->append('('); error|= sql->append_ulonglong(len); + if (dec || !strcmp(type, "DOUBLE")) { error|= sql->append(','); error|= sql->append_ulonglong(dec); - } + } // endif dec + error|= sql->append(')'); - } + } // endif len if (tm) error|= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info); @@ -3358,10 +3372,14 @@ static bool add_field(String *sql, const char *field_name, const char *type, error|= sql->append(" COMMENT '"); error|= sql->append_for_single_quote(rem, strlen(rem)); error|= sql->append("'"); - } + } // endif rem + + if (flag) { + error|= sql->append(" FLAG="); + error|= sql->append_ulonglong(flag); + } // endif flag sql->append(','); - return error; } // end of add_field @@ -3381,6 +3399,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, char spc= ',', qch= 0; const char *fncn= "?"; const char *user, *fn, *db, *host, *pwd, *prt, *sep, *tbl, *src; + const char *col, *ocl, *rnk, *pic, *fcl; char *tab, *dsn; #if defined(WIN32) char *nsp= NULL, *cls= NULL; @@ -3402,7 +3421,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info); - user= host= pwd= prt= tbl= src= dsn= NULL; + user= host= pwd= prt= tbl= src= col= ocl= pic= fcl= rnk= dsn= NULL; // Get the useful create options ttp= GetTypeID(topt->type); @@ -3417,12 +3436,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, qch= topt->qchar ? *topt->qchar : topt->quoted >= 0 ? '"' : 0; hdr= (int)topt->header; tbl= topt->tablist; + col= topt->colist; if (topt->oplist) { host= GetListOption(g,"host", topt->oplist, "localhost"); user= GetListOption(g,"user", topt->oplist, "root"); // Default value db can come from the DBNAME=xxx option. db= GetListOption(g,"database", topt->oplist, db); + col= GetListOption(g,"colist", topt->oplist, col); + ocl= GetListOption(g,"occurcol", topt->oplist, NULL); + pic= GetListOption(g,"pivotcol", topt->oplist, NULL); + fcl= GetListOption(g,"fnccol", topt->oplist, NULL); + rnk= GetListOption(g,"rankcol", topt->oplist, NULL); pwd= GetListOption(g,"password", topt->oplist); prt= GetListOption(g,"port", topt->oplist); port= (prt) ? atoi(prt) : 0; @@ -3537,9 +3562,12 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, ok= true; break; #endif // WIN32 + case TAB_PIVOT: + supfnc = FNC_NO; case TAB_PRX: case TAB_TBL: case TAB_XCL: + case TAB_OCCUR: ok= true; break; default: @@ -3563,7 +3591,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, if (ok) { char *cnm, *rem; - int i, len, dec, typ; + int i, len, dec, typ, flg; const char *type; PDBUSER dup= PlgGetUser(g); PCATLG cat= (dup) ? dup->Catalog : NULL; @@ -3573,9 +3601,16 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, else return HA_ERR_INTERNAL_ERROR; // Should never happen - if (src) + if (src && ttp != TAB_PIVOT) { qrp= SrcColumns(g, host, db, user, pwd, src, port); - else switch (ttp) { + + if (ttp == TAB_OCCUR) + if (OcrSrcCols(g, qrp, col, ocl, rnk)) { + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + return HA_ERR_INTERNAL_ERROR; + } // endif OcrSrcCols + + } else switch (ttp) { case TAB_DBF: qrp= DBFColumns(g, fn, fnc == FNC_COL); break; @@ -3618,12 +3653,22 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, case TAB_PRX: case TAB_TBL: case TAB_XCL: + case TAB_OCCUR: bif= fnc == FNC_COL; qrp= TabColumns(g, thd, db, tab, bif); if (!qrp && bif && fnc != FNC_COL) // tab is a view qrp= MyColumns(g, host, db, user, pwd, tab, NULL, port, false); + if (ttp == TAB_OCCUR && fnc != FNC_COL) + if (OcrColumns(g, qrp, col, ocl, rnk)) { + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + return HA_ERR_INTERNAL_ERROR; + } // endif OcrColumns + + break; + case TAB_PIVOT: + qrp= PivotColumns(g, tab, src, pic, fcl, host, db, user, pwd, port); break; default: strcpy(g->Message, "System error during assisted discovery"); @@ -3635,16 +3680,17 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, return HA_ERR_INTERNAL_ERROR; } // endif qrp - if (fnc != FNC_NO || src) { - // Catalog table + if (fnc != FNC_NO || src || ttp == TAB_PIVOT) { + // Catalog like table for (crp=qrp->Colresp; !b && crp; crp= crp->Next) { cnm= encode(g, crp->Name); type= PLGtoMYSQLtype(crp->Type, dbf); len= crp->Length; dec= crp->Prec; + flg= crp->Flag; // Now add the field - if (add_field(&sql, cnm, type, len, dec, NOT_NULL_FLAG, 0)) + if (add_field(&sql, cnm, type, len, dec, NOT_NULL_FLAG, 0, flg)) b= HA_ERR_OUT_OF_MEM; } // endfor crp @@ -3714,7 +3760,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, len= 0; // Now add the field - if (add_field(&sql, cnm, type, len, dec, tm, rem)) + if (add_field(&sql, cnm, type, len, dec, tm, rem, 0)) b= HA_ERR_OUT_OF_MEM; } // endfor i diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index 220be7ca0be..9ebf77ff35a 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -64,6 +64,12 @@ static char *server_groups[] = { extern "C" int trace; extern MYSQL_PLUGIN_IMPORT uint mysqld_port; +// Returns the current used port +uint GetDefaultPort(void) +{ + return mysqld_port; +} // end of GetDefaultPort + /************************************************************************/ /* MyColumns: constructs the result blocks containing all columns */ /* of a MySQL table or view. */ @@ -673,6 +679,7 @@ PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb) *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); crp = *pcrp; pcrp = &crp->Next; + memset(crp, 0, sizeof(COLRES)); crp->Ncol = ++qrp->Nbcol; crp->Name = (char*)PlugSubAlloc(g, NULL, fld->name_length + 1); @@ -686,7 +693,7 @@ PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb) // For direct MySQL connection, display the MySQL date string crp->Type = TYPE_STRING; - crp->Prec = fld->decimals; + crp->Prec = (crp->Type == TYPE_FLOAT) ? fld->decimals : 0; crp->Length = fld->max_length; crp->Clen = GetTypeSize(crp->Type, crp->Length); diff --git a/storage/connect/myconn.h b/storage/connect/myconn.h index 8148630b812..f8c8c3dcbae 100644 --- a/storage/connect/myconn.h +++ b/storage/connect/myconn.h @@ -44,6 +44,8 @@ PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db, const char *user, const char *pwd, const char *srcdef, int port); +uint GetDefaultPort(void); + /* -------------------------- MYCONN class --------------------------- */ /***********************************************************************/ diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index dfa46a650a6..919f3452a4d 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -518,6 +518,7 @@ typedef struct _colres { int Clen; /* Data individual internal size */ int Length; /* Data individual print length */ int Prec; /* Precision */ + int Flag; /* Flag option value */ XFLD Fld; /* Type of field info */ } COLRES; diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp index 598075ac52a..73b468c9209 100644 --- a/storage/connect/plgdbutl.cpp +++ b/storage/connect/plgdbutl.cpp @@ -298,6 +298,7 @@ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); crp = *pcrp; pcrp = &crp->Next; + memset(crp, 0, sizeof(COLRES)); crp->Colp = NULL; crp->Ncol = ++qrp->Nbcol; crp->Type = buftyp[i]; diff --git a/storage/connect/taboccur.cpp b/storage/connect/taboccur.cpp index 6c33aefbb68..065da269caa 100644 --- a/storage/connect/taboccur.cpp +++ b/storage/connect/taboccur.cpp @@ -1,5 +1,5 @@ /************ TabOccur CPP Declares Source Code File (.CPP) ************/ -/* Name: TABOCCUR.CPP Version 1.0 */ +/* Name: TABOCCUR.CPP Version 1.1 */ /* */ /* (C) Copyright to the author Olivier BERTRAND 2013 */ /* */ @@ -53,6 +53,210 @@ extern "C" int trace; +/***********************************************************************/ +/* Prepare and count columns in the column list. */ +/***********************************************************************/ +int PrepareColist(char *colist) + { + char *p, *pn; + int n = 0; + + // Count the number of columns and change separator into null char + for (pn = colist; ; pn += (strlen(pn) + 1)) + // Separator can be ; if colist was specified in the option_list + if ((p = strchr(pn, ',')) || (p = strchr(pn, ';'))) { + *p++ = '\0'; + n++; + } else { + if (*pn) + n++; + + break; + } // endif p + + return n; + } // end of PrepareColist + +/************************************************************************/ +/* OcrColumns: constructs the result blocks containing all the columns */ +/* of the object table that will be retrieved by GetData commands. */ +/************************************************************************/ +bool OcrColumns(PGLOBAL g, PQRYRES qrp, const char *col, + const char *ocr, const char *rank) + { + char *pn, *colist; + int i, k, m, n = 0, c = 0, j = qrp->Nblin; + bool rk, b = false; + PCOLRES crp; + + if (!col || !*col) { + strcpy(g->Message, "Missing colist"); + return true; + } // endif col + + // Prepare the column list + colist = (char*)PlugSubAlloc(g, NULL, strlen(col) + 1); + strcpy(colist, col); + m = PrepareColist(colist); + + if ((rk = (rank && *rank))) { + if (m == 1) { + strcpy(g->Message, "Cannot handle one column colist and rank"); + return true; + } // endif m + + for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1)) + n = max(n, (signed)strlen(pn)); + + } // endif k + + // Default occur column name is the 1st colist column name + if (!ocr || !*ocr) + ocr = colist; + + /**********************************************************************/ + /* Replace the columns of the colist by the rank and occur columns. */ + /**********************************************************************/ + for (i = 0; i < qrp->Nblin; i++) { + for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1)) + if (!stricmp(pn, qrp->Colresp->Kdata->GetCharValue(i))) + break; + + if (k < m) { + // This column belongs to colist + if (rk) { + // Place the rank column here + for (crp = qrp->Colresp; crp; crp = crp->Next) + switch (crp->Fld) { + case FLD_NAME: crp->Kdata->SetValue((char*)rank, i); break; + case FLD_TYPE: crp->Kdata->SetValue(TYPE_STRING, i); break; + case FLD_PREC: crp->Kdata->SetValue(n, i); break; + case FLD_SCALE: crp->Kdata->SetValue(0, i); break; + case FLD_NULL: crp->Kdata->SetValue(0, i); break; + case FLD_REM: crp->Kdata->Reset(i); break; + default: ; // Ignored by CONNECT + } // endswich Fld + + rk = false; + } else if (!b) { + // First remaining listed column, will be the occur column + for (crp = qrp->Colresp; crp; crp = crp->Next) + switch (crp->Fld) { + case FLD_NAME: crp->Kdata->SetValue((char*)ocr, i); break; + case FLD_REM: crp->Kdata->Reset(i); break; + default: ; // Nothing to do + } // endswich Fld + + b = true; + } else if (j == qrp->Nblin) + j = i; // Column to remove + + c++; + } else if (j < i) { + // Move this column in empty spot + for (crp = qrp->Colresp; crp; crp = crp->Next) + crp->Kdata->Move(i, j); + + j++; + } // endif k + + } // endfor i + + // Check whether all columns of the list where found + if (c < m) { + strcpy(g->Message, "Some colist columns are not in the source table"); + return true; + } // endif crp + + /**********************************************************************/ + /* Set the number of columns of the table. */ + /**********************************************************************/ + qrp->Nblin = j; + return false; + } // end of OcrColumns + +/************************************************************************/ +/* OcrSrcCols: constructs the result blocks containing all the columns */ +/* of the object table that will be retrieved by GetData commands. */ +/************************************************************************/ +bool OcrSrcCols(PGLOBAL g, PQRYRES qrp, const char *col, + const char *ocr, const char *rank) + { + char *pn, *colist; + int i, k, m, n = 0, c = 0; + bool rk, b = false; + PCOLRES crp, rcrp, *pcrp; + + if (!col || !*col) { + strcpy(g->Message, "Missing colist"); + return true; + } // endif col + + // Prepare the column list + colist = (char*)PlugSubAlloc(g, NULL, strlen(col) + 1); + strcpy(colist, col); + m = PrepareColist(colist); + + if ((rk = (rank && *rank))) + for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1)) + n = max(n, (signed)strlen(pn)); + + // Default occur column name is the 1st colist column name + if (!ocr || !*ocr) + ocr = colist; + + /**********************************************************************/ + /* Replace the columns of the colist by the rank and occur columns. */ + /**********************************************************************/ + for (i = 0, pcrp = &qrp->Colresp; crp = *pcrp; ) { + for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1)) + if (!stricmp(pn, crp->Name)) + break; + + if (k < m) { + // This column belongs to colist + c++; + + if (!b) { + if (rk) { + // Add the rank column here + rcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); + memset(rcrp, 0, sizeof(COLRES)); + rcrp->Next = crp; + rcrp->Name = (char*)rank; + rcrp->Type = TYPE_STRING; + rcrp->Length = n; + rcrp->Ncol = ++i; + *pcrp = rcrp; + } // endif rk + + // First remaining listed column, will be the occur column + crp->Name = (char*)ocr; + b = true; + } else { + *pcrp = crp->Next; // Remove this column + continue; + } // endif b + + } // endif k + + crp->Ncol = ++i; + pcrp = &crp->Next; + } // endfor pcrp + + // Check whether all columns of the list where found + if (c < m) { + strcpy(g->Message, "Some colist columns are not in the source table"); + return true; + } // endif crp + + /**********************************************************************/ + /* Set the number of columns of the table. */ + /**********************************************************************/ + qrp->Nblin = i; + return false; + } // end of OcrSrcCols + /* -------------- Implementation of the OCCUR classes ---------------- */ /***********************************************************************/ @@ -60,9 +264,9 @@ extern "C" int trace; /***********************************************************************/ bool OCCURDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) { - Xcol = Cat->GetStringCatInfo(g, "OccurCol", ""); Rcol = Cat->GetStringCatInfo(g, "RankCol", ""); Colist = Cat->GetStringCatInfo(g, "Colist", ""); + Xcol = Cat->GetStringCatInfo(g, "OccurCol", Colist); return PRXDEF::DefineAM(g, am, poff); } // end of DefineAM @@ -92,36 +296,12 @@ TDBOCCUR::TDBOCCUR(POCCURDEF tdp) : TDBPRX(tdp) Rcolumn = tdp->Rcol; // Rank column name Xcolp = NULL; // To the OCCURCOL column Col = NULL; // To source column blocks array - Mult = PrepareColist(); // Multiplication factor + Mult = PrepareColist(Colist); // Multiplication factor N = 0; // The current table index M = 0; // The occurence rank RowFlag = 0; // 0: Ok, 1: Same, 2: Skip } // end of TDBOCCUR constructor -/***********************************************************************/ -/* Prepare and count columns in the column list. */ -/***********************************************************************/ -int TDBOCCUR::PrepareColist(void) - { - char *p, *pn; - int n = 0; - - // Count the number of columns and change separator into null char - for (pn = Colist; ; pn += (strlen(pn) + 1)) - // Separator can be ; if colist was specified in the option_list - if ((p = strchr(pn, ',')) || (p = strchr(pn, ';'))) { - *p++ = '\0'; - n++; - } else { - if (*pn) - n++; - - break; - } // endif p - - return n; - } // end of PrepareColist - /***********************************************************************/ /* Allocate OCCUR/SRC column description block. */ /***********************************************************************/ diff --git a/storage/connect/taboccur.h b/storage/connect/taboccur.h index b7d51e05b7d..10f94329703 100644 --- a/storage/connect/taboccur.h +++ b/storage/connect/taboccur.h @@ -58,7 +58,6 @@ class TDBOCCUR : public TDBPRX { // Methods virtual void ResetDB(void) {N = 0; Tdbp->ResetDB();} virtual int RowNumber(PGLOBAL g, bool b = FALSE); - int PrepareColist(void); bool MakeColumnList(PGLOBAL g); bool ViewColumnList(PGLOBAL g); diff --git a/storage/connect/tabpivot.cpp b/storage/connect/tabpivot.cpp index 916a3c2584e..dbe702c7462 100644 --- a/storage/connect/tabpivot.cpp +++ b/storage/connect/tabpivot.cpp @@ -1,7 +1,7 @@ /************ TabPivot C++ Program Source Code File (.CPP) *************/ /* PROGRAM NAME: TABPIVOT */ /* ------------- */ -/* Version 1.5 */ +/* Version 1.6 */ /* */ /* COPYRIGHT: */ /* ---------- */ @@ -53,6 +53,182 @@ extern "C" int trace; +/***********************************************************************/ +/* Make the Pivot table column list. */ +/***********************************************************************/ +PQRYRES PivotColumns(PGLOBAL g, const char *tab, const char *src, + const char *picol, const char *fncol, + const char *host, const char *db, + const char *user, const char *pwd, + int port) + { + PIVAID pvd(tab, src, picol, fncol, host, db, user, pwd, port); + + return pvd.MakePivotColumns(g); + } // end of PivotColumns + +/* --------------- Implementation of the PIVAID classe --------------- */ + +/***********************************************************************/ +/* PIVAID constructor. */ +/***********************************************************************/ +PIVAID::PIVAID(const char *tab, const char *src, const char *picol, + const char *fncol, const char *host, const char *db, + const char *user, const char *pwd, int port) + : CSORT(false) + { + Host = (char*)host; + User = (char*)user; + Pwd = (char*)pwd; + Qryp = NULL; + Database = (char*)db; + Tabname = (char*)tab; + Tabsrc = (char*)src; + Picol = (char*)picol; + Fncol = (char*)fncol; + Rblkp = NULL; + Port = (port) ? port : GetDefaultPort(); + } // end of PIVAID constructor + +/***********************************************************************/ +/* Make the Pivot table column list. */ +/***********************************************************************/ +PQRYRES PIVAID::MakePivotColumns(PGLOBAL g) + { + char *query, *colname, buf[32]; + int ndif, nblin, w = 0; + PVAL valp; + PCOLRES *pcrp, crp, fncrp = NULL; + + if (!Tabsrc && Tabname) { + // Locate the query + query = (char*)PlugSubAlloc(g, NULL, strlen(Tabname) + 16); + sprintf(query, "SELECT * FROM %s", Tabname); + } else if (!Tabsrc) { + strcpy(g->Message, MSG(SRC_TABLE_UNDEF)); + return NULL; + } else + query = Tabsrc; + + // Open a MySQL connection for this table + if (Myc.Open(g, Host, Database, User, Pwd, Port)) + return NULL; + + // Send the source command to MySQL + if (Myc.ExecSQL(g, query, &w) == RC_FX) { + Myc.Close(); + return NULL; + } // endif Exec + + // We must have a storage query to get pivot column values + Qryp = Myc.GetResult(g); + Myc.Close(); + + if (!Fncol) { + for (crp = Qryp->Colresp; crp; crp = crp->Next) + if (!Picol || stricmp(Picol, crp->Name)) + Fncol = crp->Name; + + if (!Fncol) { + strcpy(g->Message, MSG(NO_DEF_FNCCOL)); + return NULL; + } // endif Fncol + + } // endif Fncol + + if (!Picol) { + // Find default Picol as the last one not equal to Fncol + for (crp = Qryp->Colresp; crp; crp = crp->Next) + if (stricmp(Fncol, crp->Name)) + Picol = crp->Name; + + if (!Picol) { + strcpy(g->Message, MSG(NO_DEF_PIVOTCOL)); + return NULL; + } // endif Picol + + } // endif picol + + // Prepare the column list + for (pcrp = &Qryp->Colresp; crp = *pcrp; ) + if (!stricmp(Picol, crp->Name)) { + Rblkp = crp->Kdata; + *pcrp = crp->Next; + } else if (!stricmp(Fncol, crp->Name)) { + fncrp = crp; + *pcrp = crp->Next; + } else + pcrp = &crp->Next; + + if (!Rblkp) { + strcpy(g->Message, MSG(NO_DEF_PIVOTCOL)); + return NULL; + } else if (!fncrp) { + strcpy(g->Message, MSG(NO_DEF_FNCCOL)); + return NULL; + } // endif + + // Before calling sort, initialize all + nblin = Qryp->Nblin; + + Index.Size = nblin * sizeof(int); + Index.Sub = TRUE; // Should be small enough + + if (!PlgDBalloc(g, NULL, Index)) + return NULL; + + Offset.Size = (nblin + 1) * sizeof(int); + Offset.Sub = TRUE; // Should be small enough + + if (!PlgDBalloc(g, NULL, Offset)) + return NULL; + + ndif = Qsort(g, nblin); + + if (ndif < 0) // error + return NULL; + + // Allocate the Value used to retieve column names + if (!(valp = AllocateValue(g, Rblkp->GetType(), + Rblkp->GetVlen(), + Rblkp->GetPrec()))) + return NULL; + + // Now make the functional columns + for (int i = 0; i < ndif; i++) { + if (i) { + crp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES)); + memcpy(crp, fncrp, sizeof(COLRES)); + } else + crp = fncrp; + + // Get the value that will be the generated column name + valp->SetValue_pvblk(Rblkp, Pex[Pof[i]]); + colname = valp->GetCharString(buf); + crp->Name = (char*)PlugSubAlloc(g, NULL, strlen(colname) + 1); + strcpy(crp->Name, colname); + crp->Flag = 1; + + // Add this column + *pcrp = crp; + crp->Next = NULL; + pcrp = &crp->Next; + } // endfor i + + // We added ndif columns and removed 2 (picol and fncol) + Qryp->Nbcol += (ndif - 2); + return Qryp; + } // end of MakePivotColumns + +/***********************************************************************/ +/* PIVAID: Compare routine for sorting pivot column values. */ +/***********************************************************************/ +int PIVAID::Qcompare(int *i1, int *i2) + { + // TODO: the actual comparison between pivot column result values. + return Rblkp->CompVal(*i1, *i2); + } // end of Qcompare + /* --------------- Implementation of the PIVOT classes --------------- */ /***********************************************************************/ diff --git a/storage/connect/tabpivot.h b/storage/connect/tabpivot.h index 1617801298b..4a766700162 100644 --- a/storage/connect/tabpivot.h +++ b/storage/connect/tabpivot.h @@ -1,5 +1,5 @@ /************** TabPivot H Declares Source Code File (.H) **************/ -/* Name: TABPIVOT.H Version 1.4 */ +/* Name: TABPIVOT.H Version 1.5 */ /* */ /* (C) Copyright to the author Olivier BERTRAND 2005-2013 */ /* */ @@ -10,6 +10,40 @@ typedef class TDBPIVOT *PTDBPIVOT; typedef class FNCCOL *PFNCCOL; typedef class SRCCOL *PSRCCOL; +/***********************************************************************/ +/* This class is used to generate PIVOT table column definitions. */ +/***********************************************************************/ +class PIVAID : public CSORT { + friend class FNCCOL; + friend class SRCCOL; + public: + // Constructor + PIVAID(const char *tab, const char *src, const char *picol, + const char *fncol, const char *host, const char *db, + const char *user, const char *pwd, int port); + + // Methods + PQRYRES MakePivotColumns(PGLOBAL g); + + // The sorting function + virtual int Qcompare(int *, int *); + + protected: + // Members + MYSQLC Myc; // MySQL connection class + char *Host; // Host machine to use + char *User; // User logon info + char *Pwd; // Password logon info + char *Database; // Database to be used by server + PQRYRES Qryp; // Points to Query result block + char *Tabname; // Name of source table + char *Tabsrc; // SQL of source table + char *Picol; // Pivot column name + char *Fncol; // Function column name + PVBLK Rblkp; // The value block of the pivot column + int Port; // MySQL port number + }; // end of class PIVAID + /* -------------------------- PIVOT classes -------------------------- */ /***********************************************************************/ diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h index a7b1b5046d7..d9286b72f9f 100644 --- a/storage/connect/valblk.h +++ b/storage/connect/valblk.h @@ -36,6 +36,7 @@ class VALBLK : public BLOCK { void *GetValPointer(void) {return Blkp;} void SetValPointer(void *mp) {Blkp = mp;} int GetType(void) {return Type;} + int GetPrec(void) {return Prec;} void SetCheck(bool b) {Check = b;} void MoveNull(int i, int j) {if (To_Nulls) To_Nulls[j] = To_Nulls[j];} @@ -110,7 +111,7 @@ class TYPBLK : public VALBLK { // Implementation virtual void Init(PGLOBAL g, bool check); - virtual int GetVlen(void) {return sizeof(int);} + virtual int GetVlen(void) {return sizeof(TYPE);} //virtual PSZ GetCharValue(int n); virtual short GetShortValue(int n) {return (short)Typp[n];} virtual int GetIntValue(int n) {return (int)Typp[n];}