diff options
Diffstat (limited to 'storage/connect/connect.cc')
-rw-r--r-- | storage/connect/connect.cc | 1720 |
1 files changed, 860 insertions, 860 deletions
diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index 8395ab65f41..436969c5932 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -1,860 +1,860 @@ -/* Copyright (C) Olivier Bertrand 2004 - 2012
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/***********************************************************************/
-/* Author Olivier BERTRAND bertrandop@gmail.com 2004-2012 */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the CONNECT general purpose semantic routines. */
-/***********************************************************************/
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-/***********************************************************************/
-/* Include application header files */
-/* */
-/* global.h is header containing all global declarations. */
-/* plgdbsem.h is header containing the DB applic. declarations. */
-/***********************************************************************/
-#define MYSQL_SERVER 1
-#define DONT_DEFINE_VOID
-#include "handler.h"
-#undef OFFSET
-
-typedef class ha_connect *PHC;
-
-#include "global.h"
-#include "plgdbsem.h"
-#include "xobject.h"
-#include "connect.h"
-#include "tabcol.h"
-#include "catalog.h"
-#include "ha_connect.h"
-#include "mycat.h"
-
-#define my_strupr(p) my_caseup_str(default_charset_info, (p));
-#define my_strlwr(p) my_casedn_str(default_charset_info, (p));
-#define my_stricmp(a, b) my_strcasecmp(default_charset_info, (a), (b))
-
-/***********************************************************************/
-/* DB static variables. */
-/***********************************************************************/
-extern int xtrace;
-
-/***********************************************************************/
-/* Routines called internally by semantic routines. */
-/***********************************************************************/
-void CntEndDB(PGLOBAL);
-RCODE EvalColumns(PGLOBAL g, PTDB tdbp);
-
-/***********************************************************************/
-/* MySQL routines called externally by semantic routines. */
-/***********************************************************************/
-int rename_file_ext(const char *from, const char *to,const char *ext);
-
-/***********************************************************************/
-/* CntExit: CONNECT termination routine. */
-/***********************************************************************/
-PGLOBAL CntExit(PGLOBAL g)
- {
- if (g) {
- PDBUSER dup= PlgGetUser(g);
-
- CntEndDB(g);
- PlugExit(g);
-
- if (dup->Catalog) {
- delete dup->Catalog;
- dup->Catalog= NULL;
- } // endif
-
- free(dup);
- g= NULL;
- } // endif g
-
- return g;
- } // end of CntExit
-
-/***********************************************************************/
-/* CntEndDB: DB termination semantic routine. */
-/***********************************************************************/
-void CntEndDB(PGLOBAL g)
- {
- PDBUSER dbuserp= PlgGetUser(g);
-
- if (dbuserp) {
- if (dbuserp->Catalog) {
- delete dbuserp->Catalog;
- dbuserp->Catalog= NULL;
- } // endif Catalog
-
- *dbuserp->Name= '\0';
-// *dbuserp->Work= '\0';
- } // endif dbuserp
-
- } // end of CntEndDB
-
-/***********************************************************************/
-/* CntCheckDB: Initialize a DB application session. */
-/* Note: because MySQL does not call a storage handler when a user */
-/* executes a use db command, a check must be done before an SQL */
-/* command is executed to check whether we are still working on the */
-/* current database, and if not to load the newly used database. */
-/***********************************************************************/
-bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname)
- {
- bool rc= false;
- PDBUSER dbuserp= PlgGetUser(g);
-
- if (xtrace) {
- printf("CntCheckDB: dbuserp=%p\n", dbuserp);
- } // endif xtrace
-
- if (!dbuserp || !handler)
- return true;
-
- if (xtrace)
- printf("cat=%p oldhandler=%p newhandler=%p\n", dbuserp->Catalog,
- (dbuserp->Catalog) ? ((MYCAT*)dbuserp->Catalog)->GetHandler() : NULL,
- handler);
-
- if (dbuserp->Catalog) {
-// ((MYCAT *)dbuserp->Catalog)->SetHandler(handler); done later
- ((MYCAT *)dbuserp->Catalog)->SetDataPath(g, pathname);
- return false; // Nothing else to do
- } // endif Catalog
-
- // Copy new database name in dbuser block
- strncpy(dbuserp->Name, "???", sizeof(dbuserp->Name) - 1);
-
- dbuserp->Vtdbno= 0; // Init of TDB numbers
-
- /*********************************************************************/
- /* Now allocate and initialize the Database Catalog. */
- /*********************************************************************/
- dbuserp->Step= MSG(READY);
-
- if (!(dbuserp->Catalog= new MYCAT(handler)))
- return true;
-
- ((MYCAT *)dbuserp->Catalog)->SetDataPath(g, pathname);
- dbuserp->UseTemp= TMP_YES; // Must use temporary file
-
- /*********************************************************************/
- /* All is correct. */
- /*********************************************************************/
- sprintf(g->Message, MSG(DATABASE_LOADED), "???");
-
- if (xtrace)
- printf("msg=%s\n", g->Message);
-
- return rc;
- } // end of CntCheckDB
-
-/***********************************************************************/
-/* CntInfo: Get table info. */
-/* Returns valid: true if this is a table info. */
-/***********************************************************************/
-bool CntInfo(PGLOBAL g, PTDB tp, PXF info)
- {
- bool b;
- PTDBDOS tdbp= (PTDBDOS)tp;
-
- if (tdbp) {
- b= tdbp->GetFtype() != RECFM_NAF;
- info->data_file_length= (b) ? (ulonglong)tdbp->GetFileLength(g) : 0;
- info->records= (unsigned)tdbp->GetMaxSize(g);
-// info->mean_rec_length= tdbp->GetLrecl();
- info->mean_rec_length= 0;
- info->data_file_name= (b) ? tdbp->GetFile(g) : NULL;
- return true;
- } else {
- info->data_file_length= 0;
- info->records= 0;
- info->mean_rec_length= 0;
- info->data_file_name= NULL;
- return false;
- } // endif tdbp
-
- } // end of CntInfo
-
-/***********************************************************************/
-/* GetTDB: Get the table description block of a CONNECT table. */
-/***********************************************************************/
-PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h)
- {
- int rc;
- PTDB tdbp;
- PTABLE tabp;
- PDBUSER dup= PlgGetUser(g);
- PCATLG cat= (dup) ? dup->Catalog : NULL; // Safe over longjmp
-
- if (xtrace)
- printf("CntGetTDB: name=%s mode=%d cat=%p\n", name, mode, cat);
-
- if (!cat)
- return NULL;
-
- // Save stack and allocation environment and prepare error return
- if (g->jump_level == MAX_JUMP) {
- strcpy(g->Message, MSG(TOO_MANY_JUMPS));
- return NULL;
- } // endif jump_level
-
- if ((rc= setjmp(g->jumper[++g->jump_level])) != 0) {
- tdbp= NULL;
- goto err;
- } // endif rc
-
- // Get table object from the catalog
- tabp= new(g) XTAB(name);
-
- if (xtrace)
- printf("CntGetTDB: tabp=%p\n", tabp);
-
- // Perhaps this should be made thread safe
- ((MYCAT*)cat)->SetHandler(h);
-
- if (!(tdbp= cat->GetTable(g, tabp, mode)))
- printf("CntGetTDB: %s\n", g->Message);
-
- err:
- if (xtrace)
- printf("Returning tdbp=%p mode=%d\n", tdbp, mode);
-
- g->jump_level--;
- return tdbp;
- } // end of CntGetTDB
-
-/***********************************************************************/
-/* OPENTAB: Open a Table. */
-/***********************************************************************/
-bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2,
- bool del, PHC h)
- {
- char *p;
- int i, n;
- PCOL colp;
- PCOLUMN cp;
- PDBUSER dup= PlgGetUser(g);
-
- if (xtrace)
- printf("CntOpenTable: tdbp=%p mode=%d\n", tdbp, mode);
-
- if (!tdbp) {
- strcpy(g->Message, "Null tdbp");
- printf("CntOpenTable: %s\n", g->Message);
- return true;
- } // endif tdbp
-
- if (!c1)
- // Allocate all column blocks for that table
- tdbp->ColDB(g, NULL, 0);
- else for (p= c1; *p; p+= n) {
- // Allocate only used column blocks
- if (xtrace)
- printf("Allocating column %s\n", p);
-
- if (*p == '*') {
- // This is a special column
- cp= new(g) COLUMN(p + 1);
- cp->SetTo_Table(tdbp->GetTable());
- colp= ((PTDBASE)tdbp)->InsertSpcBlk(g, cp);
- } else
- colp= tdbp->ColDB(g, p, 0);
-
- if (!colp) {
- sprintf(g->Message, "Column %s not found in %s", p, tdbp->GetName());
- return true;
- } // endif colp
-
- n= strlen(p) + 1;
- } // endfor p
-
- for (i= 0, colp= tdbp->GetColumns(); colp; i++, colp= colp->GetNext()) {
- if (colp->InitValue(g))
- return true;
-
- if (mode == MODE_INSERT)
- if (colp->SetBuffer(g, colp->GetValue(), true, true))
- return true;
-
- colp->AddColUse(U_P); // For PLG tables
- } // endfor colp
-
- // Now do open the physical table
- tdbp->SetMode(mode);
-
- if (del && ((PTDBASE)tdbp)->GetFtype() != RECFM_NAF) {
- // To avoid erasing the table when doing a partial delete
- // make a fake Next
- PDOSDEF ddp= new(g) DOSDEF;
- PTDB tp= new(g) TDBDOS(ddp, NULL);
- tdbp->SetNext(tp);
- dup->Check &= ~CHK_DELETE;
- } // endif del
-
-
- if (xtrace)
- printf("About to open the table: tdbp=%p\n", tdbp);
-
- if (mode != MODE_ANY) {
- if (tdbp->OpenDB(g)) {
- printf("%s\n", g->Message);
- return true;
- } else
- tdbp->SetNext(NULL);
-
- } // endif mode
-
- /*********************************************************************/
- /* In Update mode, the updated column blocks must be distinct from */
- /* the read column blocks. So make a copy of the TDB and allocate */
- /* its column blocks in mode write (required by XML tables). */
- /*********************************************************************/
- if (mode == MODE_UPDATE) {
- PTDBASE utp;
-
- if (!(utp= (PTDBASE)tdbp->Duplicate(g))) {
- sprintf(g->Message, MSG(INV_UPDT_TABLE), tdbp->GetName());
- return true;
- } // endif tp
-
- if (!c2)
- // Allocate all column blocks for that table
- utp->ColDB(g, NULL, 0);
- else for (p= c2; *p; p+= n) {
- // Allocate only used column blocks
- utp->ColDB(g, p, 0);
- n= strlen(p) + 1;
- } // endfor p
-
- for (i= 0, colp= utp->GetColumns(); colp; i++, colp= colp->GetNext()) {
- if (colp->InitValue(g))
- return true;
-
- if (colp->SetBuffer(g, colp->GetValue(), true, true))
- return true;
-
- } // endfor colp
-
- // Attach the updated columns list to the main table
- ((PTDBASE)tdbp)->SetSetCols(utp->GetColumns());
- } else if (tdbp && mode == MODE_INSERT)
- ((PTDBASE)tdbp)->SetSetCols(tdbp->GetColumns());
-
- if (xtrace)
- printf("Opening table %s in mode %d tdbp=%p\n",
- tdbp->GetName(), mode, tdbp);
-
- return false;
- } // end of CntOpenTable
-
-/***********************************************************************/
-/* Rewind a table by reopening it. */
-/***********************************************************************/
-bool CntRewindTable(PGLOBAL g, PTDB tdbp)
-{
- if (!tdbp)
- return true;
-
- tdbp->OpenDB(g);
- return false;
-} // end of CntRewindTable
-
-/***********************************************************************/
-/* Evaluate all columns after a record is read. */
-/***********************************************************************/
-RCODE EvalColumns(PGLOBAL g, PTDB tdbp)
- {
- RCODE rc= RC_OK;
- PCOL colp;
-
- // Save stack and allocation environment and prepare error return
- if (g->jump_level == MAX_JUMP) {
- if (xtrace) {
- strcpy(g->Message, MSG(TOO_MANY_JUMPS));
- printf("EvalColumns: %s\n", g->Message);
- } // endif
-
- return RC_FX;
- } // endif jump_level
-
- if (setjmp(g->jumper[++g->jump_level]) != 0) {
- if (xtrace)
- printf("Error reading columns: %s\n", g->Message);
-
- rc= RC_FX;
- goto err;
- } // endif rc
-
- for (colp= tdbp->GetColumns(); rc == RC_OK && colp;
- colp= colp->GetNext()) {
- colp->Reset();
-
- // Virtual columns are computed by MariaDB
- if (!colp->GetColUse(U_VIRTUAL))
- if (colp->Eval(g))
- rc= RC_FX;
-
- } // endfor colp
-
- err:
- g->jump_level--;
- return rc;
- } // end of EvalColumns
-
-/***********************************************************************/
-/* ReadNext: Read next record sequentially. */
-/***********************************************************************/
-RCODE CntReadNext(PGLOBAL g, PTDB tdbp)
- {
- RCODE rc;
-
- if (!tdbp)
- return RC_FX;
- else if (((PTDBASE)tdbp)->GetKindex()) {
- // Reading sequencially an indexed table. This happens after the
- // handler function records_in_range was called and MySQL decides
- // to quit using the index (!!!) Drop the index.
- for (PCOL colp= tdbp->GetColumns(); colp; colp= colp->GetNext())
- colp->SetKcol(NULL);
-
- ((PTDBASE)tdbp)->SetKindex(NULL);
- } // endif index
-
- while ((rc= (RCODE)tdbp->ReadDB(g)) == RC_NF) ;
-
- return (rc != RC_OK) ? rc : EvalColumns(g, tdbp);
- } // end of CntReadNext
-
-/***********************************************************************/
-/* WriteRow: Insert a new row into a table. */
-/***********************************************************************/
-RCODE CntWriteRow(PGLOBAL g, PTDB tdbp)
- {
- RCODE rc;
- PCOL colp;
- PTDBASE tp= (PTDBASE)tdbp;
-
- if (!tdbp)
- return RC_FX;
-
- // Save stack and allocation environment and prepare error return
- if (g->jump_level == MAX_JUMP) {
- strcpy(g->Message, MSG(TOO_MANY_JUMPS));
- return RC_FX;
- } // endif jump_level
-
- if (setjmp(g->jumper[++g->jump_level]) != 0) {
- printf("%s\n", g->Message);
- rc= RC_FX;
- goto err;
- } // endif rc
-
- // Store column values in table write buffer(s)
- for (colp= tp->GetSetCols(); colp; colp= colp->GetNext())
- if (!colp->GetColUse(U_VIRTUAL))
- colp->WriteColumn(g);
-
-// if (tdbp->GetMode() == MODE_INSERT)
-// tbxp->SetModified(true);
-
- // Return result code from write operation
- rc= (RCODE)tdbp->WriteDB(g);
-
- err:
- g->jump_level--;
- return rc;
- } // end of CntWriteRow
-
-/***********************************************************************/
-/* UpdateRow: Update a row into a table. */
-/***********************************************************************/
-RCODE CntUpdateRow(PGLOBAL g, PTDB tdbp)
- {
- if (!tdbp || tdbp->GetMode() != MODE_UPDATE)
- return RC_FX;
-
- // Return result code from write operation
- return CntWriteRow(g, tdbp);
- } // end of CntUpdateRow
-
-/***********************************************************************/
-/* DeleteRow: Delete a row from a table. */
-/***********************************************************************/
-RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all)
- {
- RCODE rc;
-
- if (!tdbp || tdbp->GetMode() != MODE_DELETE)
- return RC_FX;
-// else
-// ((PTDBDOX)tdbp)->SetModified(true);
-
- if (((PTDBASE)tdbp)->GetDef()->Indexable() && all)
- ((PTDBDOS)tdbp)->Cardinal= 0;
-
- // Return result code from delete operation
- // Note: if all, this call will be done when closing the table
- rc= (RCODE)tdbp->DeleteDB(g, (all) ? RC_FX : RC_OK);
- return rc;
- } // end of CntDeleteRow
-
-/***********************************************************************/
-/* CLOSETAB: Close a table. */
-/***********************************************************************/
-int CntCloseTable(PGLOBAL g, PTDB tdbp)
- {
- int rc= RC_OK;
- TDBDOX *tbxp= NULL;
-
- if (!tdbp)
- return rc; // Already done
-
- if (xtrace)
- printf("CntCloseTable: tdbp=%p mode=%d\n", tdbp, tdbp->GetMode());
-
- /*********************************************************************/
- /* This will close the table file(s) and also finalize write */
- /* operations such as Insert, Update, or Delete. */
- /*********************************************************************/
- if (tdbp->GetMode() == MODE_DELETE)
- rc= tdbp->DeleteDB(g, RC_EF); // Specific A.M. delete routine
-
- // Prepare error return
- if (g->jump_level == MAX_JUMP) {
- strcpy(g->Message, MSG(TOO_MANY_JUMPS));
- rc= RC_FX;
- goto err;
- } // endif
-
- if ((rc = setjmp(g->jumper[++g->jump_level])) != 0) {
- g->jump_level--;
- goto err;
- } // endif
-
- tdbp->CloseDB(g);
-
- g->jump_level--;
-
- if (xtrace > 1)
- printf("Table %s closed\n", tdbp->GetName());
-
-//if (!((PTDBDOX)tdbp)->GetModified())
-// return 0;
-
- if (tdbp->GetMode() == MODE_READ || tdbp->GetMode() == MODE_ANY)
- return 0;
-
- if (xtrace > 1)
- printf("About to reset opt\n");
-
- // Make all the eventual indexes
- tbxp= (TDBDOX*)tdbp;
- tbxp->SetKindex(NULL);
- tbxp->To_Key_Col= NULL;
- rc= tbxp->ResetTableOpt(g, ((PTDBASE)tdbp)->GetDef()->Indexable());
-
- err:
- if (xtrace > 1)
- printf("Done rc=%d\n", rc);
-
- return (rc == RC_OK || rc == RC_INFO) ? 0 : rc;
- } // end of CntCloseTable
-
-/***********************************************************************/
-/* Load and initialize the use of an index. */
-/* This is the condition(s) for doing indexing. */
-/* Note: FIX table are not reset here to Nrec= 1. */
-/***********************************************************************/
-int CntIndexInit(PGLOBAL g, PTDB ptdb, int id)
- {
- int k;
- PCOL colp;
- PVAL valp;
- PKXBASE xp;
- PXLOAD pxp;
- PIXDEF xdp;
- XKPDEF *kdp;
- PTDBDOX tdbp;
- PCOLDEF cdp;
- DOXDEF *dfp;
-
- if (!ptdb)
- return -1;
- else if (!((PTDBASE)ptdb)->GetDef()->Indexable()) {
- sprintf(g->Message, "Table %s is not indexable", ptdb->GetName());
- return 0;
- } else
- tdbp= (PTDBDOX)ptdb;
-
- dfp= (DOXDEF*)tdbp->To_Def;
-
-//if (!(k= colp->GetKey()))
-// if (colp->GetOpt() >= 2) {
-// strcpy(g->Message, "Not a valid indexed column");
-// return -1;
-// } else
- // This is a pseudo indexed sorted block optimized column
-// return 0;
-
- if (tdbp->To_Kindex)
- if (((XXBASE*)tdbp->To_Kindex)->GetID() == id) {
- tdbp->To_Kindex->Reset(); // Same index
- return (tdbp->To_Kindex->IsMul()) ? 2 : 1;
- } else {
- tdbp->To_Kindex->Close();
- tdbp->To_Kindex= NULL;
- } // endif colp
-
- for (xdp= dfp->To_Indx; xdp; xdp= xdp->GetNext())
- if (xdp->GetID() == id)
- break;
-
- if (!xdp) {
- sprintf(g->Message, "Wrong index ID %d", id);
- return 0;
- } // endif xdp
-
- // Allocate the key columns definition block
- tdbp->Knum= xdp->GetNparts();
- tdbp->To_Key_Col= (PCOL*)PlugSubAlloc(g, NULL, tdbp->Knum * sizeof(PCOL));
-
- // Get the key column description list
- for (k= 0, kdp= (XKPDEF*)xdp->GetToKeyParts(); kdp; kdp= (XKPDEF*)kdp->Next)
- if (!(colp= tdbp->ColDB(g, kdp->Name, 0)) || colp->InitValue(g)) {
- sprintf(g->Message, "Wrong column %s", kdp->Name);
- return 0;
- } else
- tdbp->To_Key_Col[k++]= colp;
-
-#if defined(_DEBUG)
- if (k != tdbp->Knum) {
- sprintf(g->Message, "Key part number mismatch for %s",
- xdp->GetName());
- return 0;
- } // endif k
-#endif // _DEBUG
-
- // Allocate the pseudo constants that will contain the key values
- tdbp->To_Link= (PXOB*)PlugSubAlloc(g, NULL, tdbp->Knum * sizeof(PXOB));
-
- for (k= 0, kdp= (XKPDEF*)xdp->GetToKeyParts();
- kdp; k++, kdp= (XKPDEF*)kdp->Next) {
- cdp= tdbp->Key(k)->GetCdp();
- valp= AllocateValue(g, cdp->GetType(), cdp->GetLength());
- tdbp->To_Link[k]= new(g) CONSTANT(valp);
-
-//if (kdp->Klen && tdbp->To_Link[k]->GetResultType() == TYPE_STRING)
-// ((XCOLBLK*)tdbp->To_Link[k])->SetLength(kdp->Klen);
-
-//((PCOL)tdbp->To_Link[k])->InitValue(g);
- } // endfor k
-
- // Make the index on xdp
- if (!xdp->IsAuto()) {
- if (dfp->Huge)
- pxp= new(g) XHUGE;
- else
- pxp= new(g) XFILE;
-
- if (tdbp->Knum == 1) // Single index
- xp= new(g) XINDXS(tdbp, xdp, pxp, tdbp->To_Key_Col, tdbp->To_Link);
- else // Multi-Column index
- xp= new(g) XINDEX(tdbp, xdp, pxp, tdbp->To_Key_Col, tdbp->To_Link);
-
- } else // Column contains same values as ROWID
- xp= new(g) XXROW(tdbp);
-
- if (xp->Init(g))
- return 0;
-
- tdbp->To_Kindex= xp;
- return (xp->IsMul()) ? 2 : 1;
- } // end of CntIndexInit
-
-/***********************************************************************/
-/* IndexRead: fetch a record having the index value. */
-/***********************************************************************/
-RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op,
- const void *key, int len)
- {
- char *kp= (char*)key;
- int n;
- short lg;
- RCODE rc;
- PVAL valp;
- PCOL colp;
- XXBASE *xbp;
- PTDBDOX tdbp;
-
- if (!ptdb)
- return RC_FX;
- if (!((PTDBASE)ptdb)->GetDef()->Indexable()) {
- sprintf(g->Message, "Table %s is not indexable", ptdb->GetName());
- return RC_FX;
- } else
- tdbp= (PTDBDOX)ptdb;
-
- // Set reference values and index operator
- if (!tdbp->To_Link || !tdbp->To_Kindex) {
- sprintf(g->Message, "Index not initialized for table %s", tdbp->Name);
- return RC_FX;
- } else
- xbp= (XXBASE*)tdbp->To_Kindex;
-
- if (key) {
- for (n= 0; n < tdbp->Knum; n++) {
- colp= (PCOL)tdbp->To_Key_Col[n];
-
- if (colp->GetColUse(U_NULLS))
- kp++; // Skip null byte
-
- valp= tdbp->To_Link[n]->GetValue();
-
- if (!valp->IsTypeNum()) {
- if (colp->GetColUse(U_VAR)) {
- lg= *(short*)kp;
- kp+= sizeof(short);
- valp->SetValue_char(kp, (int)lg);
- } else
- valp->SetValue_char(kp, valp->GetClen());
-
- } else
- valp->SetBinValue((void*)kp);
-
- kp+= valp->GetClen();
-
- if (len == kp - (char*)key) {
- n++;
- break;
- } else if (len < kp - (char*)key) {
- strcpy(g->Message, "Key buffer is too small");
- return RC_FX;
- } // endif len
-
- } // endfor n
-
- xbp->SetNval(n);
- } // endif key
-
- xbp->SetOp(op);
- xbp->SetNth(0);
-
- if ((rc= (RCODE)tdbp->ReadDB(g)) == RC_OK)
- rc= EvalColumns(g, tdbp);
-
- return rc;
- } // end of CntIndexRead
-
-/***********************************************************************/
-/* Return the number of rows matching given values. */
-/***********************************************************************/
-int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len,
- bool *incl, key_part_map *kmap)
- {
- const uchar *p, *kp;
- int i, n, k[2];
- short lg;
- bool b;
- PVAL valp;
- PCOL colp;
- PTDBDOX tdbp;
- XXBASE *xbp;
-
- if (!ptdb)
- return -1;
- else if (!((PTDBASE)ptdb)->GetDef()->Indexable()) {
- sprintf(g->Message, "Table %s is not indexable", ptdb->GetName());
- DBUG_PRINT("Range", (g->Message));
- return -1;
- } else
- tdbp= (PTDBDOX)ptdb;
-
- if (!tdbp->To_Link || !tdbp->To_Kindex) {
- sprintf(g->Message, "Index not initialized for table %s", tdbp->Name);
- DBUG_PRINT("Range", (g->Message));
- return -1;
- } else
- xbp= (XXBASE*)tdbp->To_Kindex;
-
- for (b= false, i= 0; i < 2; i++) {
- p= kp= key[i];
-
- if (kp) {
- for (n= 0; n < tdbp->Knum; n++) {
- if (kmap[i] & (key_part_map)(1 << n)) {
- if (b == true)
- // Cannot do indexing with missing intermediate key
- return -1;
-
- colp= (PCOL)tdbp->To_Key_Col[n];
-
- if (colp->GetColUse(U_NULLS))
- p++; // Skip null byte ???
-
- valp= tdbp->To_Link[n]->GetValue();
-
- if (!valp->IsTypeNum()) {
- if (colp->GetColUse(U_VAR)) {
- lg= *(short*)p;
- p+= sizeof(short);
- valp->SetValue_char((char*)p, (int)lg);
- } else
- valp->SetValue_char((char*)p, valp->GetClen());
-
- } else
- valp->SetBinValue((void*)p);
-
- if (xtrace) {
- char bf[32];
- printf("i=%d n=%d key=%s\n", i, n, valp->GetCharString(bf));
- } // endif xtrace
-
- p+= valp->GetClen();
-
- if (len[i] == p - kp) {
- n++;
- break;
- } else if (len[i] < (unsigned)(p - kp)) {
- strcpy(g->Message, "Key buffer is too small");
- return -1;
- } // endif len
-
- } else
- b= true;
-
- } // endfor n
-
- xbp->SetNval(n);
-
- if (xtrace)
- printf("xbp=%p Nval=%d i=%d incl=%d\n", xbp, n, i, incl[i]);
-
- k[i]= xbp->Range(g, i + 1, incl[i]);
- } else
- k[i]= (i) ? xbp->GetNum_K() : 0;
-
- } // endfor i
-
- if (xtrace)
- printf("k1=%d k0=%d\n", k[1], k[0]);
-
- return k[1] - k[0];
- } // end of CntIndexRange
+/* Copyright (C) Olivier Bertrand 2004 - 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/***********************************************************************/ +/* Author Olivier BERTRAND bertrandop@gmail.com 2004-2012 */ +/* */ +/* WHAT THIS PROGRAM DOES: */ +/* ----------------------- */ +/* This program are the CONNECT general purpose semantic routines. */ +/***********************************************************************/ +#ifdef __GNUC__ +#pragma implementation // gcc: Class implementation +#endif + +/***********************************************************************/ +/* Include application header files */ +/* */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB applic. declarations. */ +/***********************************************************************/ +#define MYSQL_SERVER 1 +#define DONT_DEFINE_VOID +#include "handler.h" +#undef OFFSET + +typedef class ha_connect *PHC; + +#include "global.h" +#include "plgdbsem.h" +#include "xobject.h" +#include "connect.h" +#include "tabcol.h" +#include "catalog.h" +#include "ha_connect.h" +#include "mycat.h" + +#define my_strupr(p) my_caseup_str(default_charset_info, (p)); +#define my_strlwr(p) my_casedn_str(default_charset_info, (p)); +#define my_stricmp(a, b) my_strcasecmp(default_charset_info, (a), (b)) + +/***********************************************************************/ +/* DB static variables. */ +/***********************************************************************/ +extern int xtrace; + +/***********************************************************************/ +/* Routines called internally by semantic routines. */ +/***********************************************************************/ +void CntEndDB(PGLOBAL); +RCODE EvalColumns(PGLOBAL g, PTDB tdbp); + +/***********************************************************************/ +/* MySQL routines called externally by semantic routines. */ +/***********************************************************************/ +int rename_file_ext(const char *from, const char *to,const char *ext); + +/***********************************************************************/ +/* CntExit: CONNECT termination routine. */ +/***********************************************************************/ +PGLOBAL CntExit(PGLOBAL g) + { + if (g) { + PDBUSER dup= PlgGetUser(g); + + CntEndDB(g); + PlugExit(g); + + if (dup->Catalog) { + delete dup->Catalog; + dup->Catalog= NULL; + } // endif + + free(dup); + g= NULL; + } // endif g + + return g; + } // end of CntExit + +/***********************************************************************/ +/* CntEndDB: DB termination semantic routine. */ +/***********************************************************************/ +void CntEndDB(PGLOBAL g) + { + PDBUSER dbuserp= PlgGetUser(g); + + if (dbuserp) { + if (dbuserp->Catalog) { + delete dbuserp->Catalog; + dbuserp->Catalog= NULL; + } // endif Catalog + + *dbuserp->Name= '\0'; +// *dbuserp->Work= '\0'; + } // endif dbuserp + + } // end of CntEndDB + +/***********************************************************************/ +/* CntCheckDB: Initialize a DB application session. */ +/* Note: because MySQL does not call a storage handler when a user */ +/* executes a use db command, a check must be done before an SQL */ +/* command is executed to check whether we are still working on the */ +/* current database, and if not to load the newly used database. */ +/***********************************************************************/ +bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname) + { + bool rc= false; + PDBUSER dbuserp= PlgGetUser(g); + + if (xtrace) { + printf("CntCheckDB: dbuserp=%p\n", dbuserp); + } // endif xtrace + + if (!dbuserp || !handler) + return true; + + if (xtrace) + printf("cat=%p oldhandler=%p newhandler=%p\n", dbuserp->Catalog, + (dbuserp->Catalog) ? ((MYCAT*)dbuserp->Catalog)->GetHandler() : NULL, + handler); + + if (dbuserp->Catalog) { +// ((MYCAT *)dbuserp->Catalog)->SetHandler(handler); done later + ((MYCAT *)dbuserp->Catalog)->SetDataPath(g, pathname); + return false; // Nothing else to do + } // endif Catalog + + // Copy new database name in dbuser block + strncpy(dbuserp->Name, "???", sizeof(dbuserp->Name) - 1); + + dbuserp->Vtdbno= 0; // Init of TDB numbers + + /*********************************************************************/ + /* Now allocate and initialize the Database Catalog. */ + /*********************************************************************/ + dbuserp->Step= MSG(READY); + + if (!(dbuserp->Catalog= new MYCAT(handler))) + return true; + + ((MYCAT *)dbuserp->Catalog)->SetDataPath(g, pathname); + dbuserp->UseTemp= TMP_YES; // Must use temporary file + + /*********************************************************************/ + /* All is correct. */ + /*********************************************************************/ + sprintf(g->Message, MSG(DATABASE_LOADED), "???"); + + if (xtrace) + printf("msg=%s\n", g->Message); + + return rc; + } // end of CntCheckDB + +/***********************************************************************/ +/* CntInfo: Get table info. */ +/* Returns valid: true if this is a table info. */ +/***********************************************************************/ +bool CntInfo(PGLOBAL g, PTDB tp, PXF info) + { + bool b; + PTDBDOS tdbp= (PTDBDOS)tp; + + if (tdbp) { + b= tdbp->GetFtype() != RECFM_NAF; + info->data_file_length= (b) ? (ulonglong)tdbp->GetFileLength(g) : 0; + info->records= (unsigned)tdbp->GetMaxSize(g); +// info->mean_rec_length= tdbp->GetLrecl(); + info->mean_rec_length= 0; + info->data_file_name= (b) ? tdbp->GetFile(g) : NULL; + return true; + } else { + info->data_file_length= 0; + info->records= 0; + info->mean_rec_length= 0; + info->data_file_name= NULL; + return false; + } // endif tdbp + + } // end of CntInfo + +/***********************************************************************/ +/* GetTDB: Get the table description block of a CONNECT table. */ +/***********************************************************************/ +PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h) + { + int rc; + PTDB tdbp; + PTABLE tabp; + PDBUSER dup= PlgGetUser(g); + PCATLG cat= (dup) ? dup->Catalog : NULL; // Safe over longjmp + + if (xtrace) + printf("CntGetTDB: name=%s mode=%d cat=%p\n", name, mode, cat); + + if (!cat) + return NULL; + + // Save stack and allocation environment and prepare error return + if (g->jump_level == MAX_JUMP) { + strcpy(g->Message, MSG(TOO_MANY_JUMPS)); + return NULL; + } // endif jump_level + + if ((rc= setjmp(g->jumper[++g->jump_level])) != 0) { + tdbp= NULL; + goto err; + } // endif rc + + // Get table object from the catalog + tabp= new(g) XTAB(name); + + if (xtrace) + printf("CntGetTDB: tabp=%p\n", tabp); + + // Perhaps this should be made thread safe + ((MYCAT*)cat)->SetHandler(h); + + if (!(tdbp= cat->GetTable(g, tabp, mode))) + printf("CntGetTDB: %s\n", g->Message); + + err: + if (xtrace) + printf("Returning tdbp=%p mode=%d\n", tdbp, mode); + + g->jump_level--; + return tdbp; + } // end of CntGetTDB + +/***********************************************************************/ +/* OPENTAB: Open a Table. */ +/***********************************************************************/ +bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2, + bool del, PHC h) + { + char *p; + int i, n; + PCOL colp; + PCOLUMN cp; + PDBUSER dup= PlgGetUser(g); + + if (xtrace) + printf("CntOpenTable: tdbp=%p mode=%d\n", tdbp, mode); + + if (!tdbp) { + strcpy(g->Message, "Null tdbp"); + printf("CntOpenTable: %s\n", g->Message); + return true; + } // endif tdbp + + if (!c1) + // Allocate all column blocks for that table + tdbp->ColDB(g, NULL, 0); + else for (p= c1; *p; p+= n) { + // Allocate only used column blocks + if (xtrace) + printf("Allocating column %s\n", p); + + if (*p == '*') { + // This is a special column + cp= new(g) COLUMN(p + 1); + cp->SetTo_Table(tdbp->GetTable()); + colp= ((PTDBASE)tdbp)->InsertSpcBlk(g, cp); + } else + colp= tdbp->ColDB(g, p, 0); + + if (!colp) { + sprintf(g->Message, "Column %s not found in %s", p, tdbp->GetName()); + return true; + } // endif colp + + n= strlen(p) + 1; + } // endfor p + + for (i= 0, colp= tdbp->GetColumns(); colp; i++, colp= colp->GetNext()) { + if (colp->InitValue(g)) + return true; + + if (mode == MODE_INSERT) + if (colp->SetBuffer(g, colp->GetValue(), true, true)) + return true; + + colp->AddColUse(U_P); // For PLG tables + } // endfor colp + + // Now do open the physical table + tdbp->SetMode(mode); + + if (del && ((PTDBASE)tdbp)->GetFtype() != RECFM_NAF) { + // To avoid erasing the table when doing a partial delete + // make a fake Next + PDOSDEF ddp= new(g) DOSDEF; + PTDB tp= new(g) TDBDOS(ddp, NULL); + tdbp->SetNext(tp); + dup->Check &= ~CHK_DELETE; + } // endif del + + + if (xtrace) + printf("About to open the table: tdbp=%p\n", tdbp); + + if (mode != MODE_ANY) { + if (tdbp->OpenDB(g)) { + printf("%s\n", g->Message); + return true; + } else + tdbp->SetNext(NULL); + + } // endif mode + + /*********************************************************************/ + /* In Update mode, the updated column blocks must be distinct from */ + /* the read column blocks. So make a copy of the TDB and allocate */ + /* its column blocks in mode write (required by XML tables). */ + /*********************************************************************/ + if (mode == MODE_UPDATE) { + PTDBASE utp; + + if (!(utp= (PTDBASE)tdbp->Duplicate(g))) { + sprintf(g->Message, MSG(INV_UPDT_TABLE), tdbp->GetName()); + return true; + } // endif tp + + if (!c2) + // Allocate all column blocks for that table + utp->ColDB(g, NULL, 0); + else for (p= c2; *p; p+= n) { + // Allocate only used column blocks + utp->ColDB(g, p, 0); + n= strlen(p) + 1; + } // endfor p + + for (i= 0, colp= utp->GetColumns(); colp; i++, colp= colp->GetNext()) { + if (colp->InitValue(g)) + return true; + + if (colp->SetBuffer(g, colp->GetValue(), true, true)) + return true; + + } // endfor colp + + // Attach the updated columns list to the main table + ((PTDBASE)tdbp)->SetSetCols(utp->GetColumns()); + } else if (tdbp && mode == MODE_INSERT) + ((PTDBASE)tdbp)->SetSetCols(tdbp->GetColumns()); + + if (xtrace) + printf("Opening table %s in mode %d tdbp=%p\n", + tdbp->GetName(), mode, tdbp); + + return false; + } // end of CntOpenTable + +/***********************************************************************/ +/* Rewind a table by reopening it. */ +/***********************************************************************/ +bool CntRewindTable(PGLOBAL g, PTDB tdbp) +{ + if (!tdbp) + return true; + + tdbp->OpenDB(g); + return false; +} // end of CntRewindTable + +/***********************************************************************/ +/* Evaluate all columns after a record is read. */ +/***********************************************************************/ +RCODE EvalColumns(PGLOBAL g, PTDB tdbp) + { + RCODE rc= RC_OK; + PCOL colp; + + // Save stack and allocation environment and prepare error return + if (g->jump_level == MAX_JUMP) { + if (xtrace) { + strcpy(g->Message, MSG(TOO_MANY_JUMPS)); + printf("EvalColumns: %s\n", g->Message); + } // endif + + return RC_FX; + } // endif jump_level + + if (setjmp(g->jumper[++g->jump_level]) != 0) { + if (xtrace) + printf("Error reading columns: %s\n", g->Message); + + rc= RC_FX; + goto err; + } // endif rc + + for (colp= tdbp->GetColumns(); rc == RC_OK && colp; + colp= colp->GetNext()) { + colp->Reset(); + + // Virtual columns are computed by MariaDB + if (!colp->GetColUse(U_VIRTUAL)) + if (colp->Eval(g)) + rc= RC_FX; + + } // endfor colp + + err: + g->jump_level--; + return rc; + } // end of EvalColumns + +/***********************************************************************/ +/* ReadNext: Read next record sequentially. */ +/***********************************************************************/ +RCODE CntReadNext(PGLOBAL g, PTDB tdbp) + { + RCODE rc; + + if (!tdbp) + return RC_FX; + else if (((PTDBASE)tdbp)->GetKindex()) { + // Reading sequencially an indexed table. This happens after the + // handler function records_in_range was called and MySQL decides + // to quit using the index (!!!) Drop the index. + for (PCOL colp= tdbp->GetColumns(); colp; colp= colp->GetNext()) + colp->SetKcol(NULL); + + ((PTDBASE)tdbp)->SetKindex(NULL); + } // endif index + + while ((rc= (RCODE)tdbp->ReadDB(g)) == RC_NF) ; + + return (rc != RC_OK) ? rc : EvalColumns(g, tdbp); + } // end of CntReadNext + +/***********************************************************************/ +/* WriteRow: Insert a new row into a table. */ +/***********************************************************************/ +RCODE CntWriteRow(PGLOBAL g, PTDB tdbp) + { + RCODE rc; + PCOL colp; + PTDBASE tp= (PTDBASE)tdbp; + + if (!tdbp) + return RC_FX; + + // Save stack and allocation environment and prepare error return + if (g->jump_level == MAX_JUMP) { + strcpy(g->Message, MSG(TOO_MANY_JUMPS)); + return RC_FX; + } // endif jump_level + + if (setjmp(g->jumper[++g->jump_level]) != 0) { + printf("%s\n", g->Message); + rc= RC_FX; + goto err; + } // endif rc + + // Store column values in table write buffer(s) + for (colp= tp->GetSetCols(); colp; colp= colp->GetNext()) + if (!colp->GetColUse(U_VIRTUAL)) + colp->WriteColumn(g); + +// if (tdbp->GetMode() == MODE_INSERT) +// tbxp->SetModified(true); + + // Return result code from write operation + rc= (RCODE)tdbp->WriteDB(g); + + err: + g->jump_level--; + return rc; + } // end of CntWriteRow + +/***********************************************************************/ +/* UpdateRow: Update a row into a table. */ +/***********************************************************************/ +RCODE CntUpdateRow(PGLOBAL g, PTDB tdbp) + { + if (!tdbp || tdbp->GetMode() != MODE_UPDATE) + return RC_FX; + + // Return result code from write operation + return CntWriteRow(g, tdbp); + } // end of CntUpdateRow + +/***********************************************************************/ +/* DeleteRow: Delete a row from a table. */ +/***********************************************************************/ +RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all) + { + RCODE rc; + + if (!tdbp || tdbp->GetMode() != MODE_DELETE) + return RC_FX; +// else +// ((PTDBDOX)tdbp)->SetModified(true); + + if (((PTDBASE)tdbp)->GetDef()->Indexable() && all) + ((PTDBDOS)tdbp)->Cardinal= 0; + + // Return result code from delete operation + // Note: if all, this call will be done when closing the table + rc= (RCODE)tdbp->DeleteDB(g, (all) ? RC_FX : RC_OK); + return rc; + } // end of CntDeleteRow + +/***********************************************************************/ +/* CLOSETAB: Close a table. */ +/***********************************************************************/ +int CntCloseTable(PGLOBAL g, PTDB tdbp) + { + int rc= RC_OK; + TDBDOX *tbxp= NULL; + + if (!tdbp) + return rc; // Already done + + if (xtrace) + printf("CntCloseTable: tdbp=%p mode=%d\n", tdbp, tdbp->GetMode()); + + /*********************************************************************/ + /* This will close the table file(s) and also finalize write */ + /* operations such as Insert, Update, or Delete. */ + /*********************************************************************/ + if (tdbp->GetMode() == MODE_DELETE) + rc= tdbp->DeleteDB(g, RC_EF); // Specific A.M. delete routine + + // Prepare error return + if (g->jump_level == MAX_JUMP) { + strcpy(g->Message, MSG(TOO_MANY_JUMPS)); + rc= RC_FX; + goto err; + } // endif + + if ((rc = setjmp(g->jumper[++g->jump_level])) != 0) { + g->jump_level--; + goto err; + } // endif + + tdbp->CloseDB(g); + + g->jump_level--; + + if (xtrace > 1) + printf("Table %s closed\n", tdbp->GetName()); + +//if (!((PTDBDOX)tdbp)->GetModified()) +// return 0; + + if (tdbp->GetMode() == MODE_READ || tdbp->GetMode() == MODE_ANY) + return 0; + + if (xtrace > 1) + printf("About to reset opt\n"); + + // Make all the eventual indexes + tbxp= (TDBDOX*)tdbp; + tbxp->SetKindex(NULL); + tbxp->To_Key_Col= NULL; + rc= tbxp->ResetTableOpt(g, ((PTDBASE)tdbp)->GetDef()->Indexable()); + + err: + if (xtrace > 1) + printf("Done rc=%d\n", rc); + + return (rc == RC_OK || rc == RC_INFO) ? 0 : rc; + } // end of CntCloseTable + +/***********************************************************************/ +/* Load and initialize the use of an index. */ +/* This is the condition(s) for doing indexing. */ +/* Note: FIX table are not reset here to Nrec= 1. */ +/***********************************************************************/ +int CntIndexInit(PGLOBAL g, PTDB ptdb, int id) + { + int k; + PCOL colp; + PVAL valp; + PKXBASE xp; + PXLOAD pxp; + PIXDEF xdp; + XKPDEF *kdp; + PTDBDOX tdbp; + PCOLDEF cdp; + DOXDEF *dfp; + + if (!ptdb) + return -1; + else if (!((PTDBASE)ptdb)->GetDef()->Indexable()) { + sprintf(g->Message, "Table %s is not indexable", ptdb->GetName()); + return 0; + } else + tdbp= (PTDBDOX)ptdb; + + dfp= (DOXDEF*)tdbp->To_Def; + +//if (!(k= colp->GetKey())) +// if (colp->GetOpt() >= 2) { +// strcpy(g->Message, "Not a valid indexed column"); +// return -1; +// } else + // This is a pseudo indexed sorted block optimized column +// return 0; + + if (tdbp->To_Kindex) + if (((XXBASE*)tdbp->To_Kindex)->GetID() == id) { + tdbp->To_Kindex->Reset(); // Same index + return (tdbp->To_Kindex->IsMul()) ? 2 : 1; + } else { + tdbp->To_Kindex->Close(); + tdbp->To_Kindex= NULL; + } // endif colp + + for (xdp= dfp->To_Indx; xdp; xdp= xdp->GetNext()) + if (xdp->GetID() == id) + break; + + if (!xdp) { + sprintf(g->Message, "Wrong index ID %d", id); + return 0; + } // endif xdp + + // Allocate the key columns definition block + tdbp->Knum= xdp->GetNparts(); + tdbp->To_Key_Col= (PCOL*)PlugSubAlloc(g, NULL, tdbp->Knum * sizeof(PCOL)); + + // Get the key column description list + for (k= 0, kdp= (XKPDEF*)xdp->GetToKeyParts(); kdp; kdp= (XKPDEF*)kdp->Next) + if (!(colp= tdbp->ColDB(g, kdp->Name, 0)) || colp->InitValue(g)) { + sprintf(g->Message, "Wrong column %s", kdp->Name); + return 0; + } else + tdbp->To_Key_Col[k++]= colp; + +#if defined(_DEBUG) + if (k != tdbp->Knum) { + sprintf(g->Message, "Key part number mismatch for %s", + xdp->GetName()); + return 0; + } // endif k +#endif // _DEBUG + + // Allocate the pseudo constants that will contain the key values + tdbp->To_Link= (PXOB*)PlugSubAlloc(g, NULL, tdbp->Knum * sizeof(PXOB)); + + for (k= 0, kdp= (XKPDEF*)xdp->GetToKeyParts(); + kdp; k++, kdp= (XKPDEF*)kdp->Next) { + cdp= tdbp->Key(k)->GetCdp(); + valp= AllocateValue(g, cdp->GetType(), cdp->GetLength()); + tdbp->To_Link[k]= new(g) CONSTANT(valp); + +//if (kdp->Klen && tdbp->To_Link[k]->GetResultType() == TYPE_STRING) +// ((XCOLBLK*)tdbp->To_Link[k])->SetLength(kdp->Klen); + +//((PCOL)tdbp->To_Link[k])->InitValue(g); + } // endfor k + + // Make the index on xdp + if (!xdp->IsAuto()) { + if (dfp->Huge) + pxp= new(g) XHUGE; + else + pxp= new(g) XFILE; + + if (tdbp->Knum == 1) // Single index + xp= new(g) XINDXS(tdbp, xdp, pxp, tdbp->To_Key_Col, tdbp->To_Link); + else // Multi-Column index + xp= new(g) XINDEX(tdbp, xdp, pxp, tdbp->To_Key_Col, tdbp->To_Link); + + } else // Column contains same values as ROWID + xp= new(g) XXROW(tdbp); + + if (xp->Init(g)) + return 0; + + tdbp->To_Kindex= xp; + return (xp->IsMul()) ? 2 : 1; + } // end of CntIndexInit + +/***********************************************************************/ +/* IndexRead: fetch a record having the index value. */ +/***********************************************************************/ +RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op, + const void *key, int len) + { + char *kp= (char*)key; + int n; + short lg; + RCODE rc; + PVAL valp; + PCOL colp; + XXBASE *xbp; + PTDBDOX tdbp; + + if (!ptdb) + return RC_FX; + if (!((PTDBASE)ptdb)->GetDef()->Indexable()) { + sprintf(g->Message, "Table %s is not indexable", ptdb->GetName()); + return RC_FX; + } else + tdbp= (PTDBDOX)ptdb; + + // Set reference values and index operator + if (!tdbp->To_Link || !tdbp->To_Kindex) { + sprintf(g->Message, "Index not initialized for table %s", tdbp->Name); + return RC_FX; + } else + xbp= (XXBASE*)tdbp->To_Kindex; + + if (key) { + for (n= 0; n < tdbp->Knum; n++) { + colp= (PCOL)tdbp->To_Key_Col[n]; + + if (colp->GetColUse(U_NULLS)) + kp++; // Skip null byte + + valp= tdbp->To_Link[n]->GetValue(); + + if (!valp->IsTypeNum()) { + if (colp->GetColUse(U_VAR)) { + lg= *(short*)kp; + kp+= sizeof(short); + valp->SetValue_char(kp, (int)lg); + } else + valp->SetValue_char(kp, valp->GetClen()); + + } else + valp->SetBinValue((void*)kp); + + kp+= valp->GetClen(); + + if (len == kp - (char*)key) { + n++; + break; + } else if (len < kp - (char*)key) { + strcpy(g->Message, "Key buffer is too small"); + return RC_FX; + } // endif len + + } // endfor n + + xbp->SetNval(n); + } // endif key + + xbp->SetOp(op); + xbp->SetNth(0); + + if ((rc= (RCODE)tdbp->ReadDB(g)) == RC_OK) + rc= EvalColumns(g, tdbp); + + return rc; + } // end of CntIndexRead + +/***********************************************************************/ +/* Return the number of rows matching given values. */ +/***********************************************************************/ +int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len, + bool *incl, key_part_map *kmap) + { + const uchar *p, *kp; + int i, n, k[2]; + short lg; + bool b; + PVAL valp; + PCOL colp; + PTDBDOX tdbp; + XXBASE *xbp; + + if (!ptdb) + return -1; + else if (!((PTDBASE)ptdb)->GetDef()->Indexable()) { + sprintf(g->Message, "Table %s is not indexable", ptdb->GetName()); + DBUG_PRINT("Range", (g->Message)); + return -1; + } else + tdbp= (PTDBDOX)ptdb; + + if (!tdbp->To_Link || !tdbp->To_Kindex) { + sprintf(g->Message, "Index not initialized for table %s", tdbp->Name); + DBUG_PRINT("Range", (g->Message)); + return -1; + } else + xbp= (XXBASE*)tdbp->To_Kindex; + + for (b= false, i= 0; i < 2; i++) { + p= kp= key[i]; + + if (kp) { + for (n= 0; n < tdbp->Knum; n++) { + if (kmap[i] & (key_part_map)(1 << n)) { + if (b == true) + // Cannot do indexing with missing intermediate key + return -1; + + colp= (PCOL)tdbp->To_Key_Col[n]; + + if (colp->GetColUse(U_NULLS)) + p++; // Skip null byte ??? + + valp= tdbp->To_Link[n]->GetValue(); + + if (!valp->IsTypeNum()) { + if (colp->GetColUse(U_VAR)) { + lg= *(short*)p; + p+= sizeof(short); + valp->SetValue_char((char*)p, (int)lg); + } else + valp->SetValue_char((char*)p, valp->GetClen()); + + } else + valp->SetBinValue((void*)p); + + if (xtrace) { + char bf[32]; + printf("i=%d n=%d key=%s\n", i, n, valp->GetCharString(bf)); + } // endif xtrace + + p+= valp->GetClen(); + + if (len[i] == p - kp) { + n++; + break; + } else if (len[i] < (unsigned)(p - kp)) { + strcpy(g->Message, "Key buffer is too small"); + return -1; + } // endif len + + } else + b= true; + + } // endfor n + + xbp->SetNval(n); + + if (xtrace) + printf("xbp=%p Nval=%d i=%d incl=%d\n", xbp, n, i, incl[i]); + + k[i]= xbp->Range(g, i + 1, incl[i]); + } else + k[i]= (i) ? xbp->GetNum_K() : 0; + + } // endfor i + + if (xtrace) + printf("k1=%d k0=%d\n", k[1], k[0]); + + return k[1] - k[0]; + } // end of CntIndexRange |