diff options
author | Olivier Bertrand <bertrandop@gmail.com> | 2013-05-28 17:22:38 +0200 |
---|---|---|
committer | Olivier Bertrand <bertrandop@gmail.com> | 2013-05-28 17:22:38 +0200 |
commit | 9f7c3fedfacdc62a30e1c9cd4ef2cdf900abffba (patch) | |
tree | 3eeede32a4c944512e298e146eca3555438bb520 /storage | |
parent | cc8174db48942a7a81cb6a74265c8212afe03591 (diff) | |
download | mariadb-git-9f7c3fedfacdc62a30e1c9cd4ef2cdf900abffba.tar.gz |
- 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
Diffstat (limited to 'storage')
-rw-r--r-- | storage/connect/ha_connect.cc | 76 | ||||
-rw-r--r-- | storage/connect/myconn.cpp | 9 | ||||
-rw-r--r-- | storage/connect/myconn.h | 2 | ||||
-rw-r--r-- | storage/connect/plgdbsem.h | 1 | ||||
-rw-r--r-- | storage/connect/plgdbutl.cpp | 1 | ||||
-rw-r--r-- | storage/connect/taboccur.cpp | 234 | ||||
-rw-r--r-- | storage/connect/taboccur.h | 1 | ||||
-rw-r--r-- | storage/connect/tabpivot.cpp | 178 | ||||
-rw-r--r-- | storage/connect/tabpivot.h | 36 | ||||
-rw-r--r-- | 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:<br> ./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 - sql->append(','); + 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,37 +296,13 @@ 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. */ /***********************************************************************/ PCOL TDBOCCUR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) 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];} |