mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
1203 lines
39 KiB
C++
1203 lines
39 KiB
C++
|
/************ TabPivot C++ Program Source Code File (.CPP) *************/
|
||
|
/* PROGRAM NAME: TABPIVOT */
|
||
|
/* ------------- */
|
||
|
/* Version 1.3 */
|
||
|
/* */
|
||
|
/* COPYRIGHT: */
|
||
|
/* ---------- */
|
||
|
/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
|
||
|
/* */
|
||
|
/* WHAT THIS PROGRAM DOES: */
|
||
|
/* ----------------------- */
|
||
|
/* This program are the PIVOT classes DB execution routines. */
|
||
|
/***********************************************************************/
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Include relevant sections of the operating system header file. */
|
||
|
/***********************************************************************/
|
||
|
#include "my_global.h"
|
||
|
#if defined(WIN32)
|
||
|
#if defined(__BORLANDC__)
|
||
|
#define __MFC_COMPAT__ // To define min/max as macro
|
||
|
#endif
|
||
|
//#include <windows.h>
|
||
|
#elif defined(UNIX)
|
||
|
#include <errno.h>
|
||
|
#include <unistd.h>
|
||
|
#include "osutil.h"
|
||
|
#else
|
||
|
#include <io.h>
|
||
|
#endif
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Include application header files: */
|
||
|
/* global.h is header containing all global declarations. */
|
||
|
/* plgdbsem.h is header containing the DB application declarations. */
|
||
|
/***********************************************************************/
|
||
|
#define FRM_VER 6
|
||
|
#include "table.h" // MySQL table definitions
|
||
|
#include "sql_const.h"
|
||
|
#include "field.h"
|
||
|
#include "global.h"
|
||
|
#include "plgdbsem.h"
|
||
|
#include "xtable.h"
|
||
|
#include "xindex.h"
|
||
|
#include "colblk.h"
|
||
|
#include "tabmysql.h"
|
||
|
#include "csort.h"
|
||
|
#include "tabpivot.h"
|
||
|
#include "valblk.h"
|
||
|
#include "ha_connect.h"
|
||
|
#include "mycat.h" // For GetHandler
|
||
|
|
||
|
extern "C" int trace;
|
||
|
|
||
|
/* --------------- Implementation of the PIVOT classes --------------- */
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* DefineAM: define specific AM block values from PIVOT table. */
|
||
|
/***********************************************************************/
|
||
|
bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
|
||
|
{
|
||
|
char *p1, *p2;
|
||
|
PHC hc = ((MYCAT*)Cat)->GetHandler();
|
||
|
|
||
|
Host = Cat->GetStringCatInfo(g, Name, "Host", "localhost");
|
||
|
User = Cat->GetStringCatInfo(g, Name, "User", "root");
|
||
|
Pwd = Cat->GetStringCatInfo(g, Name, "Password", NULL);
|
||
|
DB = Cat->GetStringCatInfo(g, Name, "Database", (PSZ)hc->GetDBName(NULL));
|
||
|
Tabsrc = Cat->GetStringCatInfo(g, Name, "SrcDef", NULL);
|
||
|
Tabname = Cat->GetStringCatInfo(g, Name, "Name", NULL);
|
||
|
Picol = Cat->GetStringCatInfo(g, Name, "PivotCol", NULL);
|
||
|
Fncol = Cat->GetStringCatInfo(g, Name, "FncCol", NULL);
|
||
|
|
||
|
// If fncol is like avg(colname), separate Fncol and Function
|
||
|
if (Fncol && (p1 = strchr(Fncol, '(')) && (p2 = strchr(p1, ')')) &&
|
||
|
(*Fncol != '"') && (!*(p2+1))) {
|
||
|
*p1++ = '\0'; *p2 = '\0';
|
||
|
Function = Fncol;
|
||
|
Fncol = p1;
|
||
|
} else
|
||
|
Function = Cat->GetStringCatInfo(g, Name, "Function", "SUM");
|
||
|
|
||
|
GBdone = Cat->GetIntCatInfo(Name, "Groupby", 0) ? TRUE : FALSE;
|
||
|
Port = Cat->GetIntCatInfo(Name, "Port", 3306);
|
||
|
Desc = (*Tabname) ? Tabname : Tabsrc;
|
||
|
return FALSE;
|
||
|
} // end of DefineAM
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* GetTable: makes a new TDB of the proper type. */
|
||
|
/***********************************************************************/
|
||
|
PTDB PIVOTDEF::GetTable(PGLOBAL g, MODE m)
|
||
|
{
|
||
|
return new(g) TDBPIVOT(this);
|
||
|
} // end of GetTable
|
||
|
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Implementation of the TDBPIVOT class. */
|
||
|
/***********************************************************************/
|
||
|
TDBPIVOT::TDBPIVOT(PPIVOTDEF tdp) : TDBASE(tdp), CSORT(FALSE)
|
||
|
{
|
||
|
Tqrp = NULL;
|
||
|
Host = tdp->Host;
|
||
|
Database = tdp->DB;
|
||
|
User = tdp->User;
|
||
|
Pwd = tdp->Pwd;
|
||
|
Port = tdp->Port;
|
||
|
Qryp = NULL;
|
||
|
Tabname = tdp->Tabname; // Name of source table
|
||
|
Tabsrc = tdp->Tabsrc; // SQL description of source table
|
||
|
Picol = tdp->Picol; // Pivot column name
|
||
|
Fncol = tdp->Fncol; // Function column name
|
||
|
Function = tdp->Function; // Aggregate function name
|
||
|
Xcolp = NULL; // To the FNCCOL column
|
||
|
//Xresp = NULL; // To the pivot result column
|
||
|
//Rblkp = NULL; // The value block of the pivot column
|
||
|
Fcolp = NULL; // To the function column
|
||
|
GBdone = tdp->GBdone;
|
||
|
Mult = -1; // Estimated table size
|
||
|
N = 0; // The current table index
|
||
|
M = 0; // The occurence rank
|
||
|
FileStatus = 0; // Logical End-of-File
|
||
|
RowFlag = 0; // 0: Ok, 1: Same, 2: Skip
|
||
|
} // end of TDBPIVOT constructor
|
||
|
|
||
|
#if 0
|
||
|
TDBPIVOT::TDBPIVOT(PTDBPIVOT tdbp) : TDBASE(tdbp), CSORT(FALSE)
|
||
|
{
|
||
|
Tdbp = tdbp->Tdbp;
|
||
|
Sqlp = tdbp->Sqlp;
|
||
|
Qryp = tdbp->Qryp;
|
||
|
Tabname = tdbp->Tabname;
|
||
|
Tabsrc = tdbp->Tabsrc;
|
||
|
Picol = tdbp->Picol;
|
||
|
Fncol = tdbp->Fncol;
|
||
|
Function = tdbp->Function;
|
||
|
Xcolp = tdbp->Xcolp;
|
||
|
Xresp = tdbp->Xresp;
|
||
|
Rblkp = tdbp->Rblkp;
|
||
|
Fcolp = tdbp->Fcolp;
|
||
|
Mult = tdbp->Mult;
|
||
|
N = tdbp->N;
|
||
|
M = tdbp->M;
|
||
|
FileStatus = tdbp->FileStatus;
|
||
|
RowFlag = tdbp->RowFlag;
|
||
|
} // end of TDBPIVOT copy constructor
|
||
|
|
||
|
// Is this really useful ???
|
||
|
PTDB TDBPIVOT::CopyOne(PTABS t)
|
||
|
{
|
||
|
PTDB tp = new(t->G) TDBPIVOT(this);
|
||
|
|
||
|
tp->SetColumns(Columns);
|
||
|
return tp;
|
||
|
} // end of CopyOne
|
||
|
#endif // 0
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Prepare the source table Query. */
|
||
|
/***********************************************************************/
|
||
|
PQRYRES TDBPIVOT::GetSourceTable(PGLOBAL g)
|
||
|
{
|
||
|
if (Qryp)
|
||
|
return Qryp; // Already done
|
||
|
|
||
|
if (!Tabsrc && Tabname) {
|
||
|
char *def, *colist;
|
||
|
size_t len = 0;
|
||
|
PCOL colp;
|
||
|
PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
|
||
|
|
||
|
// Evaluate the length of the column list
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
len += (strlen(colp->GetName()) + 2);
|
||
|
|
||
|
*(colist = (char*)PlugSubAlloc(g, NULL, len)) = 0;
|
||
|
|
||
|
// Locate the suballocated string (size is not known yet)
|
||
|
def = (char*)PlugSubAlloc(g, NULL, 0);
|
||
|
strcpy(def, "SELECT ");
|
||
|
|
||
|
if (!Fncol) {
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
if (!Picol || stricmp(Picol, colp->GetName()))
|
||
|
Fncol = colp->GetName();
|
||
|
|
||
|
if (!Fncol) {
|
||
|
strcpy(g->Message, MSG(NO_DEF_FNCCOL));
|
||
|
return NULL;
|
||
|
} // endif Fncol
|
||
|
|
||
|
} else if (!(ColDB(g, Fncol, 0))) {
|
||
|
// Function column not found in table
|
||
|
sprintf(g->Message, MSG(COL_ISNOT_TABLE), Fncol, Tabname);
|
||
|
return NULL;
|
||
|
} // endif Fcolp
|
||
|
|
||
|
if (!Picol) {
|
||
|
// Find default Picol as the last one not equal to Fncol
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
if (!Fncol || stricmp(Fncol, colp->GetName()))
|
||
|
Picol = colp->GetName();
|
||
|
|
||
|
if (!Picol) {
|
||
|
strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
|
||
|
return NULL;
|
||
|
} // endif Picol
|
||
|
|
||
|
} else if (!(ColDB(g, Picol, 0))) {
|
||
|
// Pivot column not found in table
|
||
|
sprintf(g->Message, MSG(COL_ISNOT_TABLE), Picol, Tabname);
|
||
|
return NULL;
|
||
|
} // endif Xcolp
|
||
|
|
||
|
// Make the other column list
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
if (stricmp(Picol, colp->GetName()) &&
|
||
|
stricmp(Fncol, colp->GetName()))
|
||
|
strcat(strcat(colist, colp->GetName()), ", ");
|
||
|
|
||
|
// Add the Pivot column at the end of the list
|
||
|
strcat(strcat(def, strcat(colist, Picol)), ", ");
|
||
|
|
||
|
// Continue making the definition
|
||
|
if (!GBdone) {
|
||
|
// Make it suitable for Pivot by doing the group by
|
||
|
strcat(strcat(def, Function), "(");
|
||
|
strcat(strcat(strcat(def, Fncol), ") "), Fncol);
|
||
|
strcat(strcat(def, " FROM "), Tabname);
|
||
|
strcat(strcat(def, " GROUP BY "), colist);
|
||
|
} else // Gbdone
|
||
|
strcat(strcat(strcat(def, Fncol), " FROM "), Tabname);
|
||
|
|
||
|
// Now we know how much was suballocated
|
||
|
Tabsrc = (char*)PlugSubAlloc(g, NULL, strlen(def));
|
||
|
} else {
|
||
|
strcpy(g->Message, MSG(SRC_TABLE_UNDEF));
|
||
|
return NULL;
|
||
|
} // endif Tabsrc
|
||
|
|
||
|
int w;
|
||
|
|
||
|
// 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, Tabsrc, &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();
|
||
|
Tqrp = new(g) TDBQRS(Qryp);
|
||
|
Tqrp->OpenDB(g);
|
||
|
|
||
|
if (MakePivotColumns(g) < 0)
|
||
|
return NULL;
|
||
|
|
||
|
return Qryp;
|
||
|
} // end of GetSourceTable
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Allocate PIVOT columns description block. */
|
||
|
/***********************************************************************/
|
||
|
int TDBPIVOT::MakePivotColumns(PGLOBAL g)
|
||
|
{
|
||
|
if (Mult < 0) {
|
||
|
int ndif, n = 0, nblin = Qryp->Nblin;
|
||
|
PVAL valp;
|
||
|
PCOL cp;
|
||
|
PSRCCOL colp;
|
||
|
PFNCCOL cfnp;
|
||
|
|
||
|
// Allocate all the source columns
|
||
|
Tqrp->ColDB(g, NULL, 0);
|
||
|
Columns = NULL; // Discard dummy columns blocks
|
||
|
|
||
|
for (cp = Tqrp->GetColumns(); cp; cp = cp->GetNext()) {
|
||
|
if (cp->InitValue(g))
|
||
|
return -1;
|
||
|
|
||
|
if (!stricmp(cp->GetName(), Picol)) {
|
||
|
Xcolp = (PQRSCOL)cp;
|
||
|
Xresp = Xcolp->GetCrp();
|
||
|
Rblkp = Xresp->Kdata;
|
||
|
} else if (!stricmp(cp->GetName(), Fncol)) {
|
||
|
Fcolp = (PQRSCOL)cp;
|
||
|
} else
|
||
|
if ((colp = new(g) SRCCOL(cp, this, ++n))->Init(g, this))
|
||
|
return -1;
|
||
|
|
||
|
} // endfor cp
|
||
|
|
||
|
if (!Xcolp) {
|
||
|
sprintf(g->Message, MSG(COL_ISNOT_TABLE),
|
||
|
Picol, Tabname ? Tabname : "TabSrc");
|
||
|
return -1;
|
||
|
} else if (!Fcolp) {
|
||
|
sprintf(g->Message, MSG(COL_ISNOT_TABLE),
|
||
|
Fncol, Tabname ? Tabname : "TabSrc");
|
||
|
return -1;
|
||
|
} // endif Fcolp
|
||
|
|
||
|
// Before calling sort, initialize all
|
||
|
Index.Size = nblin * sizeof(int);
|
||
|
Index.Sub = TRUE; // Should be small enough
|
||
|
|
||
|
if (!PlgDBalloc(g, NULL, Index))
|
||
|
return -1;
|
||
|
|
||
|
Offset.Size = (nblin + 1) * sizeof(int);
|
||
|
Offset.Sub = TRUE; // Should be small enough
|
||
|
|
||
|
if (!PlgDBalloc(g, NULL, Offset))
|
||
|
return -2;
|
||
|
|
||
|
ndif = Qsort(g, nblin);
|
||
|
|
||
|
if (ndif < 0) { // error
|
||
|
return -3;
|
||
|
} else
|
||
|
Ncol = ndif;
|
||
|
|
||
|
// Now make the functional columns
|
||
|
for (int i = 0; i < Ncol; i++) {
|
||
|
// Allocate the Value used to retieve column names
|
||
|
if (!(valp = AllocateValue(g, Xcolp->GetResultType(),
|
||
|
Xcolp->GetLengthEx(), Xcolp->GetPrecision(),
|
||
|
Xcolp->GetDomain(), Xcolp->GetTo_Tdb()->GetCat())))
|
||
|
return -4;
|
||
|
|
||
|
// Get the value that will be the generated column name
|
||
|
valp->SetValue_pvblk(Rblkp, Pex[Pof[i]]);
|
||
|
|
||
|
// Copy the functional column with new Name and new Value
|
||
|
cfnp = (PFNCCOL)new(g) FNCCOL(Fcolp, this);
|
||
|
|
||
|
// Initialize the generated column
|
||
|
if (cfnp->InitColumn(g, valp))
|
||
|
return -5;
|
||
|
|
||
|
} // endfor i
|
||
|
|
||
|
// Fields must be updated for ha_connect
|
||
|
// if (UpdateTableFields(g, n + Ncol))
|
||
|
// return -6;
|
||
|
|
||
|
// This should be refined later
|
||
|
Mult = nblin;
|
||
|
} // endif Mult
|
||
|
|
||
|
return Mult;
|
||
|
} // end of MakePivotColumns
|
||
|
|
||
|
#if 0
|
||
|
/***********************************************************************/
|
||
|
/* Update fields in the MySQL table structure */
|
||
|
/* Note: this does not work. Indeed the new rows are correctly made */
|
||
|
/* but the final result still specify the unmodified table and the */
|
||
|
/* returned table only contains the original column values. */
|
||
|
/* In addition, a new query on the table, when it is into the cache, */
|
||
|
/* specifies all the new columns and fails because they do not belong */
|
||
|
/* to the original table. */
|
||
|
/***********************************************************************/
|
||
|
bool TDBPIVOT::UpdateTableFields(PGLOBAL g, int n)
|
||
|
{
|
||
|
uchar *trec, *srec, *tptr, *sptr;
|
||
|
int i = 0, k = 0;
|
||
|
uint len;
|
||
|
uint32 nmp, lwm;
|
||
|
size_t buffsize;
|
||
|
PCOL colp;
|
||
|
PHC hc = ((MYCAT*)((PIVOTDEF*)To_Def)->Cat)->GetHandler();
|
||
|
TABLE *table = hc->GetTable();
|
||
|
st_mem_root *tmr = &table->mem_root;
|
||
|
st_mem_root *smr = &table->s->mem_root;
|
||
|
Field* *field;
|
||
|
Field *fp, *tfncp, *sfncp;
|
||
|
Field* *ntf;
|
||
|
Field* *nsf;
|
||
|
//my_bitmap_map *org_bitmap;
|
||
|
const MY_BITMAP *map;
|
||
|
|
||
|
// When sorting read_set selects all columns, so we use def_read_set
|
||
|
map= (const MY_BITMAP *)&table->def_read_set;
|
||
|
|
||
|
// Find the function field
|
||
|
for (field= table->field; *field; field++) {
|
||
|
fp= *field;
|
||
|
|
||
|
if (bitmap_is_set(map, fp->field_index))
|
||
|
if (!stricmp(fp->field_name, Fncol)) {
|
||
|
tfncp = fp;
|
||
|
break;
|
||
|
} // endif Name
|
||
|
|
||
|
} // endfor field
|
||
|
|
||
|
for (field= table->s->field; *field; field++) {
|
||
|
fp= *field;
|
||
|
|
||
|
if (bitmap_is_set(map, fp->field_index))
|
||
|
if (!stricmp(fp->field_name, Fncol)) {
|
||
|
sfncp = fp;
|
||
|
break;
|
||
|
} // endif Name
|
||
|
|
||
|
} // endfor field
|
||
|
|
||
|
// Calculate the new buffer size
|
||
|
len = tfncp->max_data_length();
|
||
|
buffsize = table->s->rec_buff_length + len * Ncol;
|
||
|
|
||
|
// Allocate the new record space
|
||
|
if (!(tptr = trec = (uchar*)alloc_root(tmr, 2 * buffsize)))
|
||
|
return TRUE;
|
||
|
|
||
|
if (!(sptr = srec = (uchar*)alloc_root(smr, 2 * buffsize)))
|
||
|
return TRUE;
|
||
|
|
||
|
|
||
|
// Allocate the array of all new table field pointers
|
||
|
if (!(ntf = (Field**)alloc_root(tmr, (uint)((n+1) * sizeof(Field*)))))
|
||
|
return TRUE;
|
||
|
|
||
|
// Allocate the array of all new table share field pointers
|
||
|
if (!(nsf = (Field**)alloc_root(smr, (uint)((n+1) * sizeof(Field*)))))
|
||
|
return TRUE;
|
||
|
|
||
|
// First fields are the the ones of the source columns
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
if (colp->GetAmType() == TYPE_AM_SRC) {
|
||
|
for (field= table->field; *field; field++) {
|
||
|
fp= *field;
|
||
|
|
||
|
if (bitmap_is_set(map, fp->field_index))
|
||
|
if (!stricmp(colp->GetName(), fp->field_name)) {
|
||
|
ntf[i] = fp;
|
||
|
fp->field_index = i++;
|
||
|
fp->ptr = tptr;
|
||
|
tptr += fp->max_data_length();
|
||
|
break;
|
||
|
} // endif Name
|
||
|
|
||
|
} // endfor field
|
||
|
|
||
|
for (field= table->s->field; *field; field++) {
|
||
|
fp= *field;
|
||
|
|
||
|
if (bitmap_is_set(map, fp->field_index))
|
||
|
if (!stricmp(colp->GetName(), fp->field_name)) {
|
||
|
nsf[k] = fp;
|
||
|
fp->field_index = k++;
|
||
|
fp->ptr = srec;
|
||
|
srec += fp->max_data_length();
|
||
|
break;
|
||
|
} // endif Name
|
||
|
|
||
|
} // endfor field
|
||
|
|
||
|
} // endif AmType
|
||
|
|
||
|
// Now add the pivot generated columns
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
if (colp->GetAmType() == TYPE_AM_FNC) {
|
||
|
if ((fp = (Field*)memdup_root(tmr, (char*)tfncp, tfncp->size_of()))) {
|
||
|
ntf[i] = fp;
|
||
|
fp->ptr = tptr;
|
||
|
fp->field_name = colp->GetName();
|
||
|
fp->field_index = i++;
|
||
|
fp->vcol_info = NULL;
|
||
|
fp->stored_in_db = TRUE;
|
||
|
tptr += len;
|
||
|
} else
|
||
|
return TRUE;
|
||
|
|
||
|
if ((fp = (Field*)memdup_root(smr, (char*)sfncp, sfncp->size_of()))) {
|
||
|
nsf[i] = fp;
|
||
|
fp->ptr = sptr;
|
||
|
fp->field_name = colp->GetName();
|
||
|
fp->field_index = k++;
|
||
|
fp->vcol_info = NULL;
|
||
|
fp->stored_in_db = TRUE;
|
||
|
sptr += len;
|
||
|
} else
|
||
|
return TRUE;
|
||
|
|
||
|
} // endif AM_FNC
|
||
|
|
||
|
// Mark end of the list
|
||
|
ntf[i] = NULL;
|
||
|
nsf[k] = NULL;
|
||
|
|
||
|
// Update the table fields
|
||
|
nmp = (uint32)((1<<i) - 1);
|
||
|
lwm = (uint32)((-1)<<i);
|
||
|
table->field = ntf;
|
||
|
table->used_fields = i;
|
||
|
table->record[0] = trec;
|
||
|
table->record[1] = trec + buffsize;
|
||
|
*table->def_read_set.bitmap = nmp;
|
||
|
*table->def_read_set.last_word_ptr = nmp;
|
||
|
table->def_read_set.last_word_mask = lwm;
|
||
|
table->def_read_set.n_bits = i;
|
||
|
*table->read_set->bitmap = nmp;
|
||
|
*table->read_set->last_word_ptr = nmp;
|
||
|
table->read_set->last_word_mask = lwm;
|
||
|
table->read_set->n_bits = i;
|
||
|
table->write_set->n_bits = i;
|
||
|
*table->vcol_set->bitmap = 0;
|
||
|
table->vcol_set->n_bits = i;
|
||
|
|
||
|
// and the share fields
|
||
|
table->s->field = nsf;
|
||
|
table->s->reclength = sptr - srec;
|
||
|
table->s->stored_rec_length = sptr - srec;
|
||
|
table->s->fields = k;
|
||
|
table->s->stored_fields = k;
|
||
|
table->s->rec_buff_length = buffsize;
|
||
|
//table->s->varchar_fields = ???;
|
||
|
//table->s->db_record_offset = ???;
|
||
|
//table->s->null_field_first = ???;
|
||
|
return FALSE;
|
||
|
} // end of UpdateTableFields
|
||
|
#endif // 0
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Allocate source column description block. */
|
||
|
/***********************************************************************/
|
||
|
PCOL TDBPIVOT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
||
|
{
|
||
|
PCOL colp = NULL;
|
||
|
|
||
|
//if (stricmp(cdp->GetName(), Picol) && stricmp(cdp->GetName(), Fncol)) {
|
||
|
colp = new(g) COLBLK(cdp, this, n);
|
||
|
|
||
|
// if (((PSRCCOL)colp)->Init(g, this))
|
||
|
// return NULL;
|
||
|
|
||
|
//} else {
|
||
|
// sprintf(g->Message, MSG(NO_MORE_COL), cdp->GetName());
|
||
|
// return NULL;
|
||
|
//} // endif Name
|
||
|
|
||
|
if (cprec) {
|
||
|
colp->SetNext(cprec->GetNext());
|
||
|
cprec->SetNext(colp);
|
||
|
} else {
|
||
|
colp->SetNext(Columns);
|
||
|
Columns = colp;
|
||
|
} // endif cprec
|
||
|
|
||
|
return colp;
|
||
|
} // end of MakeCol
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* PIVOT GetMaxSize: returns the maximum number of rows in the table. */
|
||
|
/***********************************************************************/
|
||
|
int TDBPIVOT::GetMaxSize(PGLOBAL g)
|
||
|
{
|
||
|
#if 0
|
||
|
if (MaxSize < 0)
|
||
|
MaxSize = MakePivotColumns(g);
|
||
|
|
||
|
return MaxSize;
|
||
|
#endif // 0
|
||
|
return 0;
|
||
|
} // end of GetMaxSize
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* In this sample, ROWID will be the (virtual) row number, */
|
||
|
/* while ROWNUM will be the occurence rank in the multiple column. */
|
||
|
/***********************************************************************/
|
||
|
int TDBPIVOT::RowNumber(PGLOBAL g, bool b)
|
||
|
{
|
||
|
return (b) ? M : N;
|
||
|
} // end of RowNumber
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* PIVOT Access Method opening routine. */
|
||
|
/***********************************************************************/
|
||
|
bool TDBPIVOT::OpenDB(PGLOBAL g)
|
||
|
{
|
||
|
//PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
|
||
|
|
||
|
if (Use == USE_OPEN) {
|
||
|
/*******************************************************************/
|
||
|
/* Table already open, just replace it at its beginning. */
|
||
|
/*******************************************************************/
|
||
|
N = M = 0;
|
||
|
RowFlag = 0;
|
||
|
FileStatus = 0;
|
||
|
return FALSE;
|
||
|
} // endif use
|
||
|
|
||
|
/*********************************************************************/
|
||
|
/* Do it here if not done yet (should not be the case). */
|
||
|
/*********************************************************************/
|
||
|
//if (MakePivotColumns(g) < 0)
|
||
|
if (!(Qryp = GetSourceTable(g)))
|
||
|
return TRUE;
|
||
|
|
||
|
if (Mode != MODE_READ) {
|
||
|
/*******************************************************************/
|
||
|
/* Currently PIVOT tables cannot be modified. */
|
||
|
/*******************************************************************/
|
||
|
sprintf(g->Message, MSG(TABLE_READ_ONLY), "PIVOT");
|
||
|
return TRUE;
|
||
|
} // endif Mode
|
||
|
|
||
|
if (To_Key_Col || To_Kindex) {
|
||
|
/*******************************************************************/
|
||
|
/* Direct access of PIVOT tables is not implemented yet. */
|
||
|
/*******************************************************************/
|
||
|
strcpy(g->Message, MSG(NO_PIV_DIR_ACC));
|
||
|
return TRUE;
|
||
|
} // endif To_Key_Col
|
||
|
|
||
|
return FALSE;
|
||
|
} // end of OpenDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Data Base read routine for PIVOT access method. */
|
||
|
/***********************************************************************/
|
||
|
int TDBPIVOT::ReadDB(PGLOBAL g)
|
||
|
{
|
||
|
int rc = RC_OK;
|
||
|
bool newrow = FALSE;
|
||
|
PCOL colp;
|
||
|
PVAL vp1, vp2;
|
||
|
|
||
|
if (FileStatus == 2)
|
||
|
return RC_EF;
|
||
|
|
||
|
if (FileStatus)
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
if (colp->GetAmType() == TYPE_AM_SRC)
|
||
|
((PSRCCOL)colp)->SetColumn();
|
||
|
|
||
|
// New row, reset all function column values
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
if (colp->GetAmType() == TYPE_AM_FNC)
|
||
|
colp->GetValue()->Reset();
|
||
|
|
||
|
/*********************************************************************/
|
||
|
/* Now start the multi reading process. */
|
||
|
/*********************************************************************/
|
||
|
do {
|
||
|
if (RowFlag != 1) {
|
||
|
if ((rc = Tqrp->ReadDB(g)) != RC_OK) {
|
||
|
if (FileStatus && rc == RC_EF) {
|
||
|
// A prepared row remains to be sent
|
||
|
FileStatus = 2;
|
||
|
rc = RC_OK;
|
||
|
} // endif FileStatus
|
||
|
|
||
|
break;
|
||
|
} // endif rc
|
||
|
|
||
|
for (colp = Tqrp->GetColumns(); colp; colp = colp->GetNext())
|
||
|
colp->ReadColumn(g);
|
||
|
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
if (colp->GetAmType() == TYPE_AM_SRC)
|
||
|
if (FileStatus) {
|
||
|
if (((PSRCCOL)colp)->CompareColumn())
|
||
|
newrow = (RowFlag) ? TRUE : FALSE;
|
||
|
|
||
|
} else
|
||
|
((PSRCCOL)colp)->SetColumn();
|
||
|
|
||
|
FileStatus = 1;
|
||
|
} // endif RowFlag
|
||
|
|
||
|
if (newrow) {
|
||
|
RowFlag = 1;
|
||
|
break;
|
||
|
} else
|
||
|
RowFlag = 2;
|
||
|
|
||
|
vp1 = Xcolp->GetValue();
|
||
|
|
||
|
// Look for the column having this header
|
||
|
for (colp = Columns; colp; colp = colp->GetNext())
|
||
|
if (colp->GetAmType() == TYPE_AM_FNC) {
|
||
|
vp2 = ((PFNCCOL)colp)->Hval;
|
||
|
|
||
|
if (!vp1->CompareValue(vp2))
|
||
|
break;
|
||
|
|
||
|
} // endif AmType
|
||
|
|
||
|
if (!colp) {
|
||
|
strcpy(g->Message, MSG(NO_MATCH_COL));
|
||
|
return RC_FX;
|
||
|
} // endif colp
|
||
|
|
||
|
// Set the value of the matching column from the fonction value
|
||
|
colp->GetValue()->SetValue_pval(Fcolp->GetValue());
|
||
|
} while (RowFlag == 2);
|
||
|
|
||
|
N++;
|
||
|
return rc;
|
||
|
} // end of ReadDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* WriteDB: Data Base write routine for PIVOT access methods. */
|
||
|
/***********************************************************************/
|
||
|
int TDBPIVOT::WriteDB(PGLOBAL g)
|
||
|
{
|
||
|
sprintf(g->Message, MSG(TABLE_READ_ONLY), "PIVOT");
|
||
|
return RC_FX;
|
||
|
} // end of WriteDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Data Base delete line routine for PIVOT access methods. */
|
||
|
/***********************************************************************/
|
||
|
int TDBPIVOT::DeleteDB(PGLOBAL g, int irc)
|
||
|
{
|
||
|
sprintf(g->Message, MSG(NO_TABLE_DEL), "PIVOT");
|
||
|
return RC_FX;
|
||
|
} // end of DeleteDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Data Base close routine for PIVOT access method. */
|
||
|
/***********************************************************************/
|
||
|
void TDBPIVOT::CloseDB(PGLOBAL g)
|
||
|
{
|
||
|
//Tdbp->CloseDB(g);
|
||
|
} // end of CloseDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* TDBPIVOT: Compare routine for sorting pivot column values. */
|
||
|
/***********************************************************************/
|
||
|
int TDBPIVOT::Qcompare(int *i1, int *i2)
|
||
|
{
|
||
|
// TODO: the actual comparison between pivot column result values.
|
||
|
return Rblkp->CompVal(*i1, *i2);
|
||
|
} // end of Qcompare
|
||
|
|
||
|
// ------------------------ FNCCOL functions ----------------------------
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* FNCCOL public constructor. */
|
||
|
/***********************************************************************/
|
||
|
FNCCOL::FNCCOL(PCOL col1, PTDBPIVOT tdbp)
|
||
|
: COLBLK(col1, tdbp)
|
||
|
{
|
||
|
Value = NULL; // We'll get a new one later
|
||
|
Hval = NULL; // The unconverted header value
|
||
|
} // end of FNCCOL constructor
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* FNCCOL initialization function. */
|
||
|
/***********************************************************************/
|
||
|
bool FNCCOL::InitColumn(PGLOBAL g, PVAL valp)
|
||
|
{
|
||
|
char *p, buf[128];
|
||
|
int len;
|
||
|
|
||
|
// Must have its own value block
|
||
|
if (InitValue(g))
|
||
|
return TRUE;
|
||
|
|
||
|
// Convert header value to a null terminated character string
|
||
|
Hval = valp;
|
||
|
p = Hval->GetCharString(buf);
|
||
|
len = strlen(p) + 1;
|
||
|
|
||
|
if (len > (signed)sizeof(buf)) {
|
||
|
strcpy(g->Message, MSG(COLNAM_TOO_LONG));
|
||
|
return TRUE;
|
||
|
} // endif buf
|
||
|
|
||
|
// Set the name of the functional pivot column
|
||
|
Name = (PSZ)PlugSubAlloc(g, NULL, len);
|
||
|
strcpy(Name, p);
|
||
|
AddStatus(BUF_READ); // All is done here
|
||
|
return FALSE;
|
||
|
} // end of InitColumn
|
||
|
|
||
|
// ------------------------ SRCCOL functions ----------------------------
|
||
|
|
||
|
#if 0
|
||
|
/***********************************************************************/
|
||
|
/* SRCCOL public constructor. */
|
||
|
/***********************************************************************/
|
||
|
SRCCOL::SRCCOL(PCOLDEF cdp, PTDBPIVOT tdbp, int n)
|
||
|
: COLBLK(cdp, tdbp, n)
|
||
|
{
|
||
|
// Set additional SRC access method information for column.
|
||
|
Colp = NULL;
|
||
|
Cnval = NULL;
|
||
|
} // end of SRCCOL constructor
|
||
|
#endif // 0
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* SRCCOL public constructor. */
|
||
|
/***********************************************************************/
|
||
|
SRCCOL::SRCCOL(PCOL cp, PTDBPIVOT tdbp, int n)
|
||
|
: COLBLK(cp, tdbp)
|
||
|
{
|
||
|
Index = n;
|
||
|
|
||
|
// Set additional SRC access method information for column.
|
||
|
Colp = (PQRSCOL)cp;
|
||
|
|
||
|
// Don't share Value with the source column so we can compare
|
||
|
Cnval = Value = NULL;
|
||
|
} // end of SRCCOL constructor
|
||
|
|
||
|
#if 0
|
||
|
/***********************************************************************/
|
||
|
/* SRCCOL constructor used for copying columns. */
|
||
|
/* tdbp is the pointer to the new table descriptor. */
|
||
|
/***********************************************************************/
|
||
|
SRCCOL::SRCCOL(SRCCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
|
||
|
{
|
||
|
Colp = col1->Colp;
|
||
|
} // end of SRCCOL copy constructor
|
||
|
#endif // 0
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Initialize the column as pointing to the source column. */
|
||
|
/***********************************************************************/
|
||
|
bool SRCCOL::Init(PGLOBAL g, PTDBPIVOT tdbp)
|
||
|
{
|
||
|
// Currently we ignore the type of the create table column
|
||
|
bool conv = FALSE;
|
||
|
|
||
|
#if 0
|
||
|
if (!Colp) {
|
||
|
// Column was defined in the Create Table statement
|
||
|
if (!(Colp = tdbp->ColDB(g, Name, 0)))
|
||
|
return TRUE;
|
||
|
|
||
|
// We can have a conversion problem converting from numeric to
|
||
|
// character because GetCharValue does not exist for numeric types.
|
||
|
conv = (IsTypeChar(Buf_Type) && IsTypeNum(Colp->GetResultType()));
|
||
|
} else
|
||
|
#endif // 0
|
||
|
conv = FALSE;
|
||
|
|
||
|
if (InitValue(g))
|
||
|
return TRUE;
|
||
|
|
||
|
//if (conv)
|
||
|
// Cnval = AllocateValue(g, Colp->GetValue());
|
||
|
//else
|
||
|
Cnval = Value;
|
||
|
|
||
|
AddStatus(BUF_READ); // All is done here
|
||
|
return FALSE;
|
||
|
} // end of SRCCOL constructor
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* SetColumn: have the column value set from the source column. */
|
||
|
/***********************************************************************/
|
||
|
void SRCCOL::SetColumn(void)
|
||
|
{
|
||
|
#if defined(_DEBUG)
|
||
|
Cnval->SetValue_pval(Colp->GetValue(), TRUE);
|
||
|
#else
|
||
|
Cnval->SetValue_pval(Colp->GetValue());
|
||
|
#endif // _DEBUG
|
||
|
|
||
|
if (Value != Cnval)
|
||
|
// Convert value
|
||
|
Value->SetValue_pval(Cnval);
|
||
|
|
||
|
} // end of SetColumn
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* SetColumn: Compare column value with source column value. */
|
||
|
/***********************************************************************/
|
||
|
bool SRCCOL::CompareColumn(void)
|
||
|
{
|
||
|
// Compare the unconverted values
|
||
|
return Cnval->CompareValue(Colp->GetValue());
|
||
|
} // end of CompareColumn
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------------- */
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Implementation of the TDBQRS class. */
|
||
|
/***********************************************************************/
|
||
|
TDBQRS::TDBQRS(PTDBQRS tdbp) : TDBASE(tdbp)
|
||
|
{
|
||
|
Qrp = tdbp->Qrp;
|
||
|
CurPos = tdbp->CurPos;
|
||
|
} // end of TDBQRS copy constructor
|
||
|
|
||
|
// Method
|
||
|
PTDB TDBQRS::CopyOne(PTABS t)
|
||
|
{
|
||
|
PTDB tp;
|
||
|
PQRSCOL cp1, cp2;
|
||
|
PGLOBAL g = t->G; // Is this really useful ???
|
||
|
|
||
|
tp = new(g) TDBQRS(this);
|
||
|
|
||
|
for (cp1 = (PQRSCOL)Columns; cp1; cp1 = (PQRSCOL)cp1->GetNext()) {
|
||
|
cp2 = new(g) QRSCOL(cp1, tp); // Make a copy
|
||
|
NewPointer(t, cp1, cp2);
|
||
|
} // endfor cp1
|
||
|
|
||
|
return tp;
|
||
|
} // end of CopyOne
|
||
|
|
||
|
#if 0 // The TDBASE functions return NULL when To_Def is NULL
|
||
|
/***********************************************************************/
|
||
|
/* Return the pointer on the DB catalog this table belongs to. */
|
||
|
/***********************************************************************/
|
||
|
PCATLG TDBQRS::GetCat(void)
|
||
|
{
|
||
|
// To_Def is null for QRYRES tables
|
||
|
return NULL;
|
||
|
} // end of GetCat
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Return the datapath of the DB this table belongs to. */
|
||
|
/***********************************************************************/
|
||
|
PSZ TDBQRS::GetPath(void)
|
||
|
{
|
||
|
// To_Def is null for QRYRES tables
|
||
|
return NULL;
|
||
|
} // end of GetPath
|
||
|
#endif // 0
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Initialize QRS column description block construction. */
|
||
|
/* name is used to call columns by name. */
|
||
|
/* num is used by LNA to construct columns by index number. */
|
||
|
/* Note: name=Null and num=0 for constructing all columns (select *) */
|
||
|
/***********************************************************************/
|
||
|
PCOL TDBQRS::ColDB(PGLOBAL g, PSZ name, int num)
|
||
|
{
|
||
|
int i;
|
||
|
PCOLRES crp;
|
||
|
PCOL cp, colp = NULL, cprec = NULL;
|
||
|
|
||
|
if (trace)
|
||
|
htrc("QRS ColDB: colname=%s tabname=%s num=%d\n",
|
||
|
SVP(name), Name, num);
|
||
|
|
||
|
for (crp = Qrp->Colresp, i = 1; crp; crp = crp->Next, i++)
|
||
|
if ((!name && !num) ||
|
||
|
(name && !stricmp(crp->Name, name)) || num == i) {
|
||
|
// Check for existence of desired column
|
||
|
// Also find where to insert the new block
|
||
|
for (cp = Columns; cp; cp = cp->GetNext())
|
||
|
if (cp->GetIndex() < i)
|
||
|
cprec = cp;
|
||
|
else if (cp->GetIndex() == i)
|
||
|
break;
|
||
|
|
||
|
if (trace) {
|
||
|
if (cp)
|
||
|
htrc("cp(%d).Name=%s cp=%p\n", i, cp->GetName(), cp);
|
||
|
else
|
||
|
htrc("cp(%d) cp=%p\n", i, cp);
|
||
|
} // endif trace
|
||
|
|
||
|
// Now take care of Column Description Block
|
||
|
if (cp)
|
||
|
colp = cp;
|
||
|
else
|
||
|
colp = new(g) QRSCOL(g, crp, this, cprec, i);
|
||
|
|
||
|
if (name || num)
|
||
|
break;
|
||
|
else
|
||
|
cprec = colp;
|
||
|
|
||
|
} // endif Name
|
||
|
|
||
|
return (colp);
|
||
|
} // end of ColDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* QRS GetMaxSize: returns maximum table size in number of lines. */
|
||
|
/***********************************************************************/
|
||
|
int TDBQRS::GetMaxSize(PGLOBAL g)
|
||
|
{
|
||
|
MaxSize = Qrp->Maxsize;
|
||
|
return MaxSize;
|
||
|
} // end of GetMaxSize
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* RowNumber: returns the current row ordinal number. */
|
||
|
/***********************************************************************/
|
||
|
int TDBQRS::RowNumber(PGLOBAL g, BOOL b)
|
||
|
{
|
||
|
return (CurPos + 1);
|
||
|
} // end of RowNumber
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* QRS Access Method opening routine. */
|
||
|
/* New method now that this routine is called recursively (last table */
|
||
|
/* first in reverse order): index blocks are immediately linked to */
|
||
|
/* join block of next table if it exists or else are discarted. */
|
||
|
/***********************************************************************/
|
||
|
bool TDBQRS::OpenDB(PGLOBAL g)
|
||
|
{
|
||
|
if (trace)
|
||
|
htrc("QRS OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
|
||
|
this, Tdb_No, Use, To_Key_Col, Mode);
|
||
|
|
||
|
if (Mode != MODE_READ) {
|
||
|
sprintf(g->Message, MSG(BAD_QUERY_OPEN), Mode);
|
||
|
return TRUE;
|
||
|
} // endif Mode
|
||
|
|
||
|
CurPos = -1;
|
||
|
|
||
|
if (Use == USE_OPEN) {
|
||
|
/*******************************************************************/
|
||
|
/* Table already open, just replace it at its beginning. */
|
||
|
/*******************************************************************/
|
||
|
if (To_Kindex)
|
||
|
/*****************************************************************/
|
||
|
/* Table is to be accessed through a sorted index table. */
|
||
|
/*****************************************************************/
|
||
|
To_Kindex->Reset();
|
||
|
|
||
|
return FALSE;
|
||
|
} // endif use
|
||
|
|
||
|
/*********************************************************************/
|
||
|
/* Open (retrieve data from) the query if not already open. */
|
||
|
/*********************************************************************/
|
||
|
Use = USE_OPEN; // Do it now in case we are recursively called
|
||
|
|
||
|
return FALSE;
|
||
|
} // end of OpenDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* GetRecpos: returns current position of next sequential read. */
|
||
|
/***********************************************************************/
|
||
|
int TDBQRS::GetRecpos(void)
|
||
|
{
|
||
|
return (CurPos);
|
||
|
} // end of GetRecpos
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* ReadDB: Data Base read routine for QRS access method. */
|
||
|
/***********************************************************************/
|
||
|
int TDBQRS::ReadDB(PGLOBAL g)
|
||
|
{
|
||
|
int rc = RC_OK;
|
||
|
|
||
|
if (trace)
|
||
|
htrc("QRS ReadDB: R%d CurPos=%d key=%p link=%p Kindex=%p\n",
|
||
|
GetTdb_No(), CurPos, To_Key_Col, To_Link, To_Kindex);
|
||
|
|
||
|
if (To_Kindex) {
|
||
|
/*******************************************************************/
|
||
|
/* Reading is by an index table. */
|
||
|
/*******************************************************************/
|
||
|
int recpos = To_Kindex->Fetch(g);
|
||
|
|
||
|
switch (recpos) {
|
||
|
case -1: // End of file reached
|
||
|
rc = RC_EF;
|
||
|
break;
|
||
|
case -2: // No match for join
|
||
|
rc = RC_NF;
|
||
|
break;
|
||
|
case -3: // Same record as last non null one
|
||
|
rc = RC_OK;
|
||
|
break;
|
||
|
default:
|
||
|
/***************************************************************/
|
||
|
/* Set the file position according to record to read. */
|
||
|
/***************************************************************/
|
||
|
CurPos = recpos;
|
||
|
} // endswitch recpos
|
||
|
|
||
|
if (trace)
|
||
|
htrc("Position is now %d\n", CurPos);
|
||
|
|
||
|
} else
|
||
|
/*******************************************************************/
|
||
|
/* !To_Kindex ---> sequential reading */
|
||
|
/*******************************************************************/
|
||
|
rc = (++CurPos < Qrp->Nblin) ? RC_OK : RC_EF;
|
||
|
|
||
|
return rc;
|
||
|
} // end of ReadDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Dummy WriteDB: just send back an error return. */
|
||
|
/***********************************************************************/
|
||
|
int TDBQRS::WriteDB(PGLOBAL g)
|
||
|
{
|
||
|
strcpy(g->Message, MSG(QRY_READ_ONLY));
|
||
|
return RC_FX;
|
||
|
} // end of WriteDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Dummy DeleteDB routine, just returns an error code. */
|
||
|
/***********************************************************************/
|
||
|
int TDBQRS::DeleteDB(PGLOBAL g, int irc)
|
||
|
{
|
||
|
strcpy(g->Message, MSG(NO_QRY_DELETE));
|
||
|
return RC_FX;
|
||
|
} // end of DeleteDB
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Data Base close routine for QRS access method. */
|
||
|
/***********************************************************************/
|
||
|
void TDBQRS::CloseDB(PGLOBAL g)
|
||
|
{
|
||
|
if (To_Kindex) {
|
||
|
To_Kindex->Close();
|
||
|
To_Kindex = NULL;
|
||
|
} // endif
|
||
|
|
||
|
if (trace)
|
||
|
htrc("Qryres CloseDB");
|
||
|
|
||
|
//Qryp->Sqlp->CloseDB();
|
||
|
} // end of CloseDB
|
||
|
|
||
|
// ------------------------ QRSCOL functions ----------------------------
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* QRSCOL public constructor. */
|
||
|
/***********************************************************************/
|
||
|
QRSCOL::QRSCOL(PGLOBAL g, PCOLRES crp, PTDB tdbp, PCOL cprec, int i)
|
||
|
: COLBLK(NULL, tdbp, i)
|
||
|
{
|
||
|
if (cprec) {
|
||
|
Next = cprec->GetNext();
|
||
|
cprec->SetNext(this);
|
||
|
} else {
|
||
|
Next = tdbp->GetColumns();
|
||
|
tdbp->SetColumns(this);
|
||
|
} // endif cprec
|
||
|
|
||
|
// Set additional QRS access method information for column.
|
||
|
Crp = crp;
|
||
|
Name = Crp->Name;
|
||
|
Long = Crp->Clen;
|
||
|
Buf_Type = crp->Type;
|
||
|
strcpy(Format.Type, GetFormatType(Buf_Type));
|
||
|
Format.Length = (SHORT)Long;
|
||
|
Format.Prec = (SHORT)Crp->Prec;
|
||
|
|
||
|
if (trace) {
|
||
|
htrc("Making new QRSCOL C%d %s at %p\n", Index, Name, this);
|
||
|
htrc(" BufType=%d Long=%d length=%d clen=%d\n",
|
||
|
Buf_Type, Long, Format.Length, Crp->Clen);
|
||
|
} // endif trace
|
||
|
|
||
|
} // end of QRSCOL constructor
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* QRSCOL constructor used for copying columns. */
|
||
|
/* tdbp is the pointer to the new table descriptor. */
|
||
|
/***********************************************************************/
|
||
|
QRSCOL::QRSCOL(QRSCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
|
||
|
{
|
||
|
Crp = col1->Crp;
|
||
|
} // end of QRSCOL copy constructor
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* ReadColumn: what this routine does is to extract the RESCOL block */
|
||
|
/* current value and convert it to the column buffer type. */
|
||
|
/***********************************************************************/
|
||
|
void QRSCOL::ReadColumn(PGLOBAL g)
|
||
|
{
|
||
|
PTDBQRS tdbp = (PTDBQRS)To_Tdb;
|
||
|
|
||
|
if (trace)
|
||
|
htrc("QRS RC: col %s R%d type=%d CurPos=%d Len=%d\n",
|
||
|
Name, tdbp->GetTdb_No(), Buf_Type, tdbp->CurPos, Crp->Clen);
|
||
|
|
||
|
if (Crp->Kdata)
|
||
|
Value->SetValue_pvblk(Crp->Kdata, tdbp->CurPos);
|
||
|
else
|
||
|
Value->Reset();
|
||
|
|
||
|
} // end of ReadColumn
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* Make file output of a Dos column descriptor block. */
|
||
|
/***********************************************************************/
|
||
|
void QRSCOL::Print(PGLOBAL g, FILE *f, UINT n)
|
||
|
{
|
||
|
COLBLK::Print(g, f, n);
|
||
|
|
||
|
fprintf(f, " Crp=%p\n", Crp);
|
||
|
} // end of Print
|
||
|
|
||
|
/* --------------------- End of TabPivot/TabQrs ---------------------- */
|