diff options
author | Alexander Barkov <bar@mnogosearch.org> | 2013-02-07 13:34:27 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mnogosearch.org> | 2013-02-07 13:34:27 +0400 |
commit | 30c4b0ebc24fe0106e146b1f6577a4150e71e258 (patch) | |
tree | 592673d8c2f5b418833c3ee5fcfeb9dbf4ba1681 /storage/connect/tabtbl.cpp | |
parent | 60c4cab3bd00621cc03afb1be6de01c8fab0c5f0 (diff) | |
download | mariadb-git-30c4b0ebc24fe0106e146b1f6577a4150e71e258.tar.gz |
- Fixing TAB to 2 spaces
- Fixing line endings from "\r\n" to "\n"
Diffstat (limited to 'storage/connect/tabtbl.cpp')
-rw-r--r-- | storage/connect/tabtbl.cpp | 1554 |
1 files changed, 777 insertions, 777 deletions
diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp index 9f4bb8a05a8..4abdb7aa681 100644 --- a/storage/connect/tabtbl.cpp +++ b/storage/connect/tabtbl.cpp @@ -1,777 +1,777 @@ -/************* TabTbl C++ Program Source Code File (.CPP) **************/
-/* PROGRAM NAME: TABTBL */
-/* ------------- */
-/* Version 1.3 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to PlugDB Software Development 2008-2012 */
-/* Author: Olivier BERTRAND */
-/* */
-/* WHAT THIS PROGRAM DOES: */
-/* ----------------------- */
-/* This program are the TDBTBL class DB routines. */
-/* */
-/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
-/* -------------------------------------- */
-/* */
-/* REQUIRED FILES: */
-/* --------------- */
-/* TABTBL.CPP - Source code */
-/* PLGDBSEM.H - DB application declaration file */
-/* TABDOS.H - TABDOS classes declaration file */
-/* TABTBL.H - TABTBL classes declaration file */
-/* GLOBAL.H - Global declaration file */
-/* */
-/* REQUIRED LIBRARIES: */
-/* ------------------- */
-/* Large model C library */
-/* */
-/* REQUIRED PROGRAMS: */
-/* ------------------ */
-/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
-/* */
-/***********************************************************************/
-
-/***********************************************************************/
-/* Include relevant section of system dependant header files. */
-/***********************************************************************/
-//#include "sql_base.h"
-#include "my_global.h"
-#if defined(WIN32)
-#include <stdlib.h>
-#include <stdio.h>
-#if defined(__BORLANDC__)
-#define __MFC_COMPAT__ // To define min/max as macro
-#endif
-//#include <windows.h>
-#else
-#if defined(UNIX)
-#include <fnmatch.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "osutil.h"
-#else
-//#include <io.h>
-#endif
-//#include <fcntl.h>
-#endif
-
-/***********************************************************************/
-/* Include application header files: */
-/***********************************************************************/
-#include "table.h" // MySQL table definitions
-#include "global.h" // global declarations
-#include "plgdbsem.h" // DB application declarations
-#include "reldef.h" // DB definition declares
-//#include "filter.h" // FILTER classes dcls
-#include "filamtxt.h"
-#include "tabcol.h"
-#include "tabdos.h" // TDBDOS and DOSCOL class dcls
-#include "tabtbl.h" // TDBTBL and TBLCOL classes dcls
-#include "ha_connect.h"
-#include "mycat.h" // For GetHandler
-
-extern "C" int trace;
-
-int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags);
-
-/* ---------------------------- Class TBLDEF ---------------------------- */
-
-/**************************************************************************/
-/* Constructor. */
-/**************************************************************************/
-TBLDEF::TBLDEF(void)
- {
- To_Tables = NULL;
- Ntables = 0;
- Pseudo = 3;
- } // end of TBLDEF constructor
-
-/**************************************************************************/
-/* DefineAM: define specific AM block values from XDB file. */
-/**************************************************************************/
-bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
- {
- char *tablist, *dbname;
-
- Desc = "Table list table";
- tablist = Cat->GetStringCatInfo(g, Name, "Tablist", "");
- dbname = Cat->GetStringCatInfo(g, Name, "Database", NULL);
- Ntables = 0;
-
- if (*tablist) {
- char *p, *pn, *pdb;
- PTBL *ptbl = &To_Tables, tbl;
-
- for (pdb = tablist; ;) {
- if ((p = strchr(pdb, ',')))
- *p = 0;
-
- // Analyze the table name, it has the format:
- // [dbname.]tabname
- if ((pn = strchr(pdb, '.'))) {
- *pn++ = 0;
- } else {
- pn = pdb;
- pdb = dbname;
- } // endif p
-
- // Allocate the TBLIST block for that table
- tbl = (PTBL)PlugSubAlloc(g, NULL, sizeof(TBLIST));
- tbl->Next = NULL;
- tbl->Name = pn;
- tbl->DB = pdb;
-
- if (trace)
- htrc("TBL: Name=%s db=%s\n", tbl->Name, SVP(tbl->DB));
-
- // Link the blocks
- *ptbl = tbl;
- ptbl = &tbl->Next;
- Ntables++;
-
- if (p)
- pdb = pn + strlen(pn) + 1;
- else
- break;
-
- } // endfor pdb
-
- Maxerr = Cat->GetIntCatInfo(Name, "Maxerr", 0);
- Accept = (Cat->GetBoolCatInfo(Name, "Accept", 0) != 0);
- } // endif fsec || tablist
-
- return FALSE;
- } // end of DefineAM
-
-/***********************************************************************/
-/* GetTable: makes a new Table Description Block. */
-/***********************************************************************/
-PTDB TBLDEF::GetTable(PGLOBAL g, MODE m)
- {
- PTDB tdbp;
-
- /*********************************************************************/
- /* Allocate a TDB of the proper type. */
- /* Column blocks will be allocated only when needed. */
- /*********************************************************************/
- tdbp = new(g) TDBTBL(this);
-
- return tdbp;
- } // end of GetTable
-
-/* ------------------------- Class TDBTBL ---------------------------- */
-
-/***********************************************************************/
-/* TDBTBL constructors. */
-/***********************************************************************/
-TDBTBL::TDBTBL(PTBLDEF tdp) : TDBASE(tdp)
- {
- Tablist = NULL;
- CurTable = NULL;
- Tdbp = NULL;
- Accept = tdp->Accept;
- Maxerr = tdp->Maxerr;
- Nbf = 0;
- Rows = 0;
- Crp = 0;
-// NTables = 0;
-// iTable = 0;
- } // end of TDBTBL standard constructor
-
-/***********************************************************************/
-/* Allocate TBL column description block. */
-/***********************************************************************/
-PCOL TDBTBL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
- {
- return new(g) TBLCOL(cdp, this, cprec, n);
- } // end of MakeCol
-
-/***********************************************************************/
-/* InsertSpecialColumn: Put a special column ahead of the column list.*/
-/***********************************************************************/
-PCOL TDBTBL::InsertSpecialColumn(PGLOBAL g, PCOL scp)
- {
- PCOL colp;
-
- if (!scp->IsSpecial())
- return NULL;
-
- if (scp->GetAmType() == TYPE_AM_TABID)
- // This special column is handled locally
- colp = new((TIDBLK*)scp) TBTBLK(scp->GetValue());
- else // Other special columns are treated normally
- colp = scp;
-
- colp->SetNext(Columns);
- Columns = colp;
- return colp;
- } // end of InsertSpecialColumn
-
-/***********************************************************************/
-/* Get the PTDB of a table of the list. */
-/***********************************************************************/
-PTDB TDBTBL::GetSubTable(PGLOBAL g, PTBL tblp, PTABLE tabp)
- {
- char *db, key[128];
- uint k, flags;
- PTDB tdbp = NULL;
- TABLE_LIST table_list;
- TABLE_SHARE *s;
- PCATLG cat = To_Def->GetCat();
- PHC hc = ((MYCAT*)cat)->GetHandler();
- THD *thd = (hc->GetTable())->in_use;
-
- if (!thd)
- return NULL; // Should not happen anymore
-
- if (tblp->DB)
- db = tblp->DB;
- else
- db = (char*)hc->GetDBName(NULL);
-
- table_list.init_one_table(db, strlen(db),
- tblp->Name, strlen(tblp->Name),
- NULL, TL_IGNORE);
- k = sprintf(key, "%s\0%s\0", db, tblp->Name);
-
- if (!(s = alloc_table_share(&table_list, key, k))) {
- strcpy(g->Message, "Error allocating share\n");
- return NULL;
- } // endif s
-
-// 1 8 16
-//flags = READ_ALL | DONT_OPEN_TABLES | DONT_OPEN_MASTER_REG;
-//flags = 25;
- flags = 24;
-
- if (!open_table_def(thd, s, flags)) {
- hc->tshp = s;
- tdbp = cat->GetTable(g, tabp);
- hc->tshp = NULL;
- } else
- sprintf(g->Message, "Error %d opening share\n", s->error);
-
- if (trace && tdbp)
- htrc("Subtable %s in %s\n",
- tblp->Name, SVP(((PTDBASE)tdbp)->GetDef()->GetDB()));
-
- free_table_share(s);
- return tdbp;
- } // end of GetSubTable
-
-/***********************************************************************/
-/* Initializes the table table list. */
-/***********************************************************************/
-bool TDBTBL::InitTableList(PGLOBAL g)
- {
- char *colname;
- int n, colpos;
- PTBL tblp;
- PTABLE tabp;
- PTDB tdbp;
- PCOL colp;
- PTBLDEF tdp = (PTBLDEF)To_Def;
-
-// PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
-
- for (n = 0, tblp = tdp->GetTables(); tblp; tblp = tblp->Next) {
- if (TestFil(g, To_Filter, tblp)) {
- // Table or named view
- tabp = new(g) XTAB(tblp->Name);
- tabp->SetQualifier(tblp->DB);
-
- // Get the table description block of this table
- if (!(tdbp = GetSubTable(g, tblp, tabp))) {
- if (++Nbf > Maxerr)
- return TRUE; // Error return
- else
- continue; // Skip this table
-
- } // endif tdbp
-
- // We must allocate subtable columns before GetMaxSize is called
- // because some (PLG, ODBC?) need to have their columns attached.
- // Real initialization will be done later.
- for (PCOL cp = Columns; cp; cp = cp->GetNext())
- if (!cp->IsSpecial()) {
- colname = cp->GetName();
- colpos = ((PTBLCOL)cp)->Colnum;
-
- // We try first to get the column by name
- if (!(colp = tdbp->ColDB(g, colname, 0)) && colpos)
- // When unsuccessful, if a column number was specified
- // try to get the column by its position in the table
- colp = tdbp->ColDB(g, NULL, colpos);
-
- if (!colp) {
- if (!Accept) {
- sprintf(g->Message, MSG(NO_MATCHING_COL),
- colname, tdbp->GetName());
- return TRUE; // Error return
- } // endif !Accept
-
- } else // this is needed in particular by PLG tables
- colp->SetColUse(cp->GetColUse());
-
- } // endif !special
-
- if (Tablist)
- Tablist->Link(tabp);
- else
- Tablist = tabp;
-
- n++;
- } // endif filp
-
- } // endfor tblp
-
-//NumTables = n;
- To_Filter = NULL; // To avoid doing it several times
- return FALSE;
- } // end of InitTableList
-
-/***********************************************************************/
-/* Test the tablename against the pseudo "local" filter. */
-/***********************************************************************/
-bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTBL tblp)
- {
- char *fil, op[8], tn[NAME_LEN];
- bool neg;
-
- if (!filp)
- return TRUE;
- else if (strstr(filp, " OR ") || strstr(filp, " AND "))
- return TRUE; // Not handled yet
- else
- fil = filp + (*filp == '(' ? 1 : 0);
-
- if (sscanf(fil, "TABID %s", op) != 1)
- return TRUE; // ignore invalid filter
-
- if ((neg = !strcmp(op, "NOT")))
- strcpy(op, "IN");
-
- if (!strcmp(op, "=")) {
- // Temporarily, filter must be "TABID = 'value'" only
- if (sscanf(fil, "TABID = '%[^']'", tn) != 1)
- return TRUE; // ignore invalid filter
-
- return !stricmp(tn, tblp->Name);
- } else if (!strcmp(op, "IN")) {
- char *p, *tnl = (char*)PlugSubAlloc(g, NULL, strlen(fil) - 10);
- int n;
-
- if (neg)
- n = sscanf(fil, "TABID NOT IN (%[^)])", tnl);
- else
- n = sscanf(fil, "TABID IN (%[^)])", tnl);
-
- if (n != 1)
- return TRUE; // ignore invalid filter
-
- while (tnl) {
- if ((p = strchr(tnl, ',')))
- *p++ = 0;
-
- if (sscanf(tnl, "'%[^']'", tn) != 1)
- return TRUE; // ignore invalid filter
- else if (!stricmp(tn, tblp->Name))
- return !neg; // Found
-
- tnl = p;
- } // endwhile
-
- return neg; // Not found
- } // endif op
-
- return TRUE; // invalid operator
- } // end of TestFil
-
-/***********************************************************************/
-/* TBL GetProgMax: get the max value for progress information. */
-/***********************************************************************/
-int TDBTBL::GetProgMax(PGLOBAL g)
- {
- PTABLE tblp;
- int n, pmx = 0;
-
- if (!Tablist && InitTableList(g))
- return -1;
-
- for (tblp = Tablist; tblp; tblp = tblp->GetNext())
- if ((n = tblp->GetTo_Tdb()->GetProgMax(g)) > 0)
- pmx += n;
-
- return pmx;
- } // end of GetProgMax
-
-/***********************************************************************/
-/* TBL GetProgCur: get the current value for progress information. */
-/***********************************************************************/
-int TDBTBL::GetProgCur(void)
- {
- return Crp + Tdbp->GetProgCur();
- } // end of GetProgCur
-
-#if 0
-/***********************************************************************/
-/* TBL Cardinality: returns table cardinality in number of rows. */
-/* This function can be called with a null argument to test the */
-/* availability of Cardinality implementation (1 yes, 0 no). */
-/* Can be used on Multiple FIX table only. */
-/***********************************************************************/
-int TDBTBL::Cardinality(PGLOBAL g)
- {
- if (!g)
- return Tdbp->Cardinality(g);
-
- if (!Tablist && InitTableList(g))
- return -1;
-
- int n, card = 0;
-
- for (int i = 0; i < NumFiles; i++) {
- Tdbp->SetFile(g, Filenames[i]);
- Tdbp->ResetSize();
-
- if ((n = Tdbp->Cardinality(g)) < 0) {
-// strcpy(g->Message, MSG(BAD_CARDINALITY));
- return -1;
- } // endif n
-
- card += n;
- } // endfor i
-
- return card;
- } // end of Cardinality
-#endif // 0
-
-/***********************************************************************/
-/* Sum up the sizes of all sub-tables. */
-/***********************************************************************/
-int TDBTBL::GetMaxSize(PGLOBAL g)
- {
- if (MaxSize < 0) {
- PTABLE tblp;
- int mxsz;
-
- if (!Tablist && InitTableList(g))
- return 0; // Cannot be calculated at this stage
-
-// if (Use == USE_OPEN) {
-// strcpy(g->Message, MSG(MAXSIZE_ERROR));
-// return -1;
-// } else
- MaxSize = 0;
-
- for (tblp = Tablist; tblp; tblp = tblp->GetNext()) {
- if ((mxsz = tblp->GetTo_Tdb()->GetMaxSize(g)) < 0) {
- MaxSize = -1;
- return mxsz;
- } // endif mxsz
-
- MaxSize += mxsz;
- } // endfor i
-
- } // endif MaxSize
-
- return MaxSize;
- } // end of GetMaxSize
-
-/***********************************************************************/
-/* Reset read/write position values. */
-/***********************************************************************/
-void TDBTBL::ResetDB(void)
- {
- for (PCOL colp = Columns; colp; colp = colp->GetNext())
- if (colp->GetAmType() == TYPE_AM_TABID)
- colp->COLBLK::Reset();
-
- for (PTABLE tblp = Tablist; tblp; tblp = tblp->GetNext())
- ((PTDBASE)tblp->GetTo_Tdb())->ResetDB();
-
- Tdbp = (PTDBASE)Tablist->GetTo_Tdb();
- Crp = 0;
- } // end of ResetDB
-
-/***********************************************************************/
-/* Returns RowId if b is false or Rownum if b is true. */
-/***********************************************************************/
-int TDBTBL::RowNumber(PGLOBAL g, bool b)
- {
- return Tdbp->RowNumber(g) + ((b) ? 0 : Rows);
- } // end of RowNumber
-
-/***********************************************************************/
-/* TBL Access Method opening routine. */
-/* Open first file, other will be opened sequencially when reading. */
-/***********************************************************************/
-bool TDBTBL::OpenDB(PGLOBAL g)
- {
- if (trace)
- htrc("TBL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
- this, Tdb_No, Use, To_Key_Col, Mode);
-
- if (Use == USE_OPEN) {
- /*******************************************************************/
- /* Table already open, replace it at its beginning. */
- /*******************************************************************/
- ResetDB();
- return Tdbp->OpenDB(g); // Re-open fist table
- } // endif use
-
-#if 0
- /*********************************************************************/
- /* Direct access needed for join or sorting. */
- /*********************************************************************/
- if (NeedIndexing(g)) {
- // Direct access of TBL tables is not implemented yet
- strcpy(g->Message, MSG(NO_MUL_DIR_ACC));
- return TRUE;
- } // endif NeedIndexing
-#endif // 0
-
- /*********************************************************************/
- /* When GetMaxsize was called, To_Filter was not set yet. */
- /*********************************************************************/
- if (To_Filter && Tablist) {
- Tablist = NULL;
- Nbf = 0;
- } // endif To_Filter
-
- /*********************************************************************/
- /* Open the first table of the list. */
- /*********************************************************************/
- if (!Tablist && InitTableList(g)) // done in GetMaxSize
- return TRUE;
-
- if ((CurTable = Tablist)) {
- Tdbp = (PTDBASE)CurTable->GetTo_Tdb();
- Tdbp->SetMode(Mode);
-// Tdbp->ResetDB();
-// Tdbp->ResetSize();
-
- // Check and initialize the subtable columns
- for (PCOL cp = Columns; cp; cp = cp->GetNext())
- if (cp->GetAmType() == TYPE_AM_TABID)
- cp->COLBLK::Reset();
- else if (((PTBLCOL)cp)->Init(g))
- return TRUE;
-
- if (trace)
- htrc("Opening subtable %s\n", Tdbp->GetName());
-
- // Now we can safely open the table
- if (Tdbp->OpenDB(g))
- return TRUE;
-
- } // endif *Tablist
-
- Use = USE_OPEN;
- return FALSE;
- } // end of OpenDB
-
-/***********************************************************************/
-/* ReadDB: Data Base read routine for MUL access method. */
-/***********************************************************************/
-int TDBTBL::ReadDB(PGLOBAL g)
- {
- int rc;
-
- if (!CurTable)
- return RC_EF;
- else if (To_Kindex) {
- /*******************************************************************/
- /* Reading is by an index table. */
- /*******************************************************************/
- strcpy(g->Message, MSG(NO_INDEX_READ));
- rc = RC_FX;
- } else {
- /*******************************************************************/
- /* Now start the reading process. */
- /*******************************************************************/
- retry:
- rc = Tdbp->ReadDB(g);
-
- if (rc == RC_EF) {
- // Total number of rows met so far
- Rows += Tdbp->RowNumber(g) - 1;
- Crp += Tdbp->GetProgMax(g);
-
- if ((CurTable = CurTable->GetNext())) {
- /***************************************************************/
- /* Continue reading from next table file. */
- /***************************************************************/
- Tdbp->CloseDB(g);
- Tdbp = (PTDBASE)CurTable->GetTo_Tdb();
-
- // Check and initialize the subtable columns
- for (PCOL cp = Columns; cp; cp = cp->GetNext())
- if (cp->GetAmType() == TYPE_AM_TABID)
- cp->COLBLK::Reset();
- else if (((PTBLCOL)cp)->Init(g))
- return RC_FX;
-
- if (trace)
- htrc("Opening subtable %s\n", Tdbp->GetName());
-
- // Now we can safely open the table
- if (Tdbp->OpenDB(g)) // Open next table
- return RC_FX;
-
- goto retry;
- } // endif iFile
-
- } else if (rc == RC_FX)
- strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")");
-
- } // endif To_Kindex
-
- return rc;
- } // end of ReadDB
-
-/***********************************************************************/
-/* Data Base write routine for MUL access method. */
-/***********************************************************************/
-int TDBTBL::WriteDB(PGLOBAL g)
- {
- strcpy(g->Message, MSG(TABMUL_READONLY));
- return RC_FX; // NIY
- } // end of WriteDB
-
-/***********************************************************************/
-/* Data Base delete line routine for MUL access method. */
-/***********************************************************************/
-int TDBTBL::DeleteDB(PGLOBAL g, int irc)
- {
- strcpy(g->Message, MSG(TABMUL_READONLY));
- return RC_FX; // NIY
- } // end of DeleteDB
-
-/***********************************************************************/
-/* Data Base close routine for MUL access method. */
-/***********************************************************************/
-void TDBTBL::CloseDB(PGLOBAL g)
- {
- if (Tdbp)
- Tdbp->CloseDB(g);
-
- } // end of CloseDB
-
-/* ---------------------------- TBLCOL ------------------------------- */
-
-/***********************************************************************/
-/* TBLCOL public constructor. */
-/***********************************************************************/
-TBLCOL::TBLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
- : COLBLK(cdp, tdbp, i)
- {
- if (cprec) {
- Next = cprec->GetNext();
- cprec->SetNext(this);
- } else {
- Next = tdbp->GetColumns();
- tdbp->SetColumns(this);
- } // endif cprec
-
- // Set additional Dos access method information for column.
- Long = cdp->GetLong(); // ???
-//strcpy(F_Date, cdp->F_Date);
- Colp = NULL;
- To_Val = NULL;
- Pseudo = FALSE;
- Colnum = cdp->GetOffset(); // If columns are retrieved by number
-
- if (trace)
- htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
-
- } // end of TBLCOL constructor
-
-#if 0
-/***********************************************************************/
-/* TBLCOL public constructor. */
-/***********************************************************************/
-TBLCOL::TBLCOL(SPCBLK *scp, PTDB tdbp) : COLBLK(scp->GetName(), tdbp, 0)
- {
- // Set additional TBL access method information for pseudo column.
- Is_Key = Was_Key = scp->IsKey();
- Long = scp->GetLength();
- Buf_Type = scp->GetResultType();
- *Format.Type = (Buf_Type == TYPE_INT) ? 'N' : 'C';
- Format.Length = Long;
- Colp = NULL;
- To_Val = NULL;
- Pseudo = TRUE;
- } // end of TBLCOL constructor
-
-/***********************************************************************/
-/* TBLCOL constructor used for copying columns. */
-/* tdbp is the pointer to the new table descriptor. */
-/***********************************************************************/
-TBLCOL::TBLCOL(TBLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
- {
- Long = col1->Long;
- Colp = col1->Colp;
- To_Val = col1->To_Val;
- Pseudo = col1->Pseudo;
- } // end of TBLCOL copy constructor
-#endif
-
-/***********************************************************************/
-/* TBLCOL initialization routine. */
-/* Look for the matching column in the current table. */
-/***********************************************************************/
-bool TBLCOL::Init(PGLOBAL g)
- {
- PTDBTBL tdbp = (PTDBTBL)To_Tdb;
-
- To_Val = NULL;
-
- if (!(Colp = tdbp->Tdbp->ColDB(g, Name, 0)) && Colnum)
- Colp = tdbp->Tdbp->ColDB(g, NULL, Colnum);
-
- if (Colp) {
- Colp->InitValue(g); // May not have been done elsewhere
- To_Val = Colp->GetValue();
- } else if (!tdbp->Accept) {
- sprintf(g->Message, MSG(NO_MATCHING_COL), Name, tdbp->Tdbp->GetName());
- return TRUE;
- } else
- Value->Reset();
-
- return FALSE;
- } // end of Init
-
-/***********************************************************************/
-/* ReadColumn: */
-/***********************************************************************/
-void TBLCOL::ReadColumn(PGLOBAL g)
- {
- if (trace)
- htrc("TBL ReadColumn: name=%s\n", Name);
-
- if (Colp) {
- Colp->ReadColumn(g);
- Value->SetValue_pval(To_Val);
- } // endif Colp
-
- } // end of ReadColumn
-
-/* ---------------------------- TBTBLK ------------------------------- */
-
-/***********************************************************************/
-/* ReadColumn: */
-/***********************************************************************/
-void TBTBLK::ReadColumn(PGLOBAL g)
- {
- if (trace)
- htrc("TBT ReadColumn: name=%s\n", Name);
-
- Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName());
- } // end of ReadColumn
-
-/* ------------------------------------------------------------------- */
+/************* TabTbl C++ Program Source Code File (.CPP) **************/ +/* PROGRAM NAME: TABTBL */ +/* ------------- */ +/* Version 1.3 */ +/* */ +/* COPYRIGHT: */ +/* ---------- */ +/* (C) Copyright to PlugDB Software Development 2008-2012 */ +/* Author: Olivier BERTRAND */ +/* */ +/* WHAT THIS PROGRAM DOES: */ +/* ----------------------- */ +/* This program are the TDBTBL class DB routines. */ +/* */ +/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */ +/* -------------------------------------- */ +/* */ +/* REQUIRED FILES: */ +/* --------------- */ +/* TABTBL.CPP - Source code */ +/* PLGDBSEM.H - DB application declaration file */ +/* TABDOS.H - TABDOS classes declaration file */ +/* TABTBL.H - TABTBL classes declaration file */ +/* GLOBAL.H - Global declaration file */ +/* */ +/* REQUIRED LIBRARIES: */ +/* ------------------- */ +/* Large model C library */ +/* */ +/* REQUIRED PROGRAMS: */ +/* ------------------ */ +/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */ +/* */ +/***********************************************************************/ + +/***********************************************************************/ +/* Include relevant section of system dependant header files. */ +/***********************************************************************/ +//#include "sql_base.h" +#include "my_global.h" +#if defined(WIN32) +#include <stdlib.h> +#include <stdio.h> +#if defined(__BORLANDC__) +#define __MFC_COMPAT__ // To define min/max as macro +#endif +//#include <windows.h> +#else +#if defined(UNIX) +#include <fnmatch.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "osutil.h" +#else +//#include <io.h> +#endif +//#include <fcntl.h> +#endif + +/***********************************************************************/ +/* Include application header files: */ +/***********************************************************************/ +#include "table.h" // MySQL table definitions +#include "global.h" // global declarations +#include "plgdbsem.h" // DB application declarations +#include "reldef.h" // DB definition declares +//#include "filter.h" // FILTER classes dcls +#include "filamtxt.h" +#include "tabcol.h" +#include "tabdos.h" // TDBDOS and DOSCOL class dcls +#include "tabtbl.h" // TDBTBL and TBLCOL classes dcls +#include "ha_connect.h" +#include "mycat.h" // For GetHandler + +extern "C" int trace; + +int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags); + +/* ---------------------------- Class TBLDEF ---------------------------- */ + +/**************************************************************************/ +/* Constructor. */ +/**************************************************************************/ +TBLDEF::TBLDEF(void) + { + To_Tables = NULL; + Ntables = 0; + Pseudo = 3; + } // end of TBLDEF constructor + +/**************************************************************************/ +/* DefineAM: define specific AM block values from XDB file. */ +/**************************************************************************/ +bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) + { + char *tablist, *dbname; + + Desc = "Table list table"; + tablist = Cat->GetStringCatInfo(g, Name, "Tablist", ""); + dbname = Cat->GetStringCatInfo(g, Name, "Database", NULL); + Ntables = 0; + + if (*tablist) { + char *p, *pn, *pdb; + PTBL *ptbl = &To_Tables, tbl; + + for (pdb = tablist; ;) { + if ((p = strchr(pdb, ','))) + *p = 0; + + // Analyze the table name, it has the format: + // [dbname.]tabname + if ((pn = strchr(pdb, '.'))) { + *pn++ = 0; + } else { + pn = pdb; + pdb = dbname; + } // endif p + + // Allocate the TBLIST block for that table + tbl = (PTBL)PlugSubAlloc(g, NULL, sizeof(TBLIST)); + tbl->Next = NULL; + tbl->Name = pn; + tbl->DB = pdb; + + if (trace) + htrc("TBL: Name=%s db=%s\n", tbl->Name, SVP(tbl->DB)); + + // Link the blocks + *ptbl = tbl; + ptbl = &tbl->Next; + Ntables++; + + if (p) + pdb = pn + strlen(pn) + 1; + else + break; + + } // endfor pdb + + Maxerr = Cat->GetIntCatInfo(Name, "Maxerr", 0); + Accept = (Cat->GetBoolCatInfo(Name, "Accept", 0) != 0); + } // endif fsec || tablist + + return FALSE; + } // end of DefineAM + +/***********************************************************************/ +/* GetTable: makes a new Table Description Block. */ +/***********************************************************************/ +PTDB TBLDEF::GetTable(PGLOBAL g, MODE m) + { + PTDB tdbp; + + /*********************************************************************/ + /* Allocate a TDB of the proper type. */ + /* Column blocks will be allocated only when needed. */ + /*********************************************************************/ + tdbp = new(g) TDBTBL(this); + + return tdbp; + } // end of GetTable + +/* ------------------------- Class TDBTBL ---------------------------- */ + +/***********************************************************************/ +/* TDBTBL constructors. */ +/***********************************************************************/ +TDBTBL::TDBTBL(PTBLDEF tdp) : TDBASE(tdp) + { + Tablist = NULL; + CurTable = NULL; + Tdbp = NULL; + Accept = tdp->Accept; + Maxerr = tdp->Maxerr; + Nbf = 0; + Rows = 0; + Crp = 0; +// NTables = 0; +// iTable = 0; + } // end of TDBTBL standard constructor + +/***********************************************************************/ +/* Allocate TBL column description block. */ +/***********************************************************************/ +PCOL TDBTBL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) + { + return new(g) TBLCOL(cdp, this, cprec, n); + } // end of MakeCol + +/***********************************************************************/ +/* InsertSpecialColumn: Put a special column ahead of the column list.*/ +/***********************************************************************/ +PCOL TDBTBL::InsertSpecialColumn(PGLOBAL g, PCOL scp) + { + PCOL colp; + + if (!scp->IsSpecial()) + return NULL; + + if (scp->GetAmType() == TYPE_AM_TABID) + // This special column is handled locally + colp = new((TIDBLK*)scp) TBTBLK(scp->GetValue()); + else // Other special columns are treated normally + colp = scp; + + colp->SetNext(Columns); + Columns = colp; + return colp; + } // end of InsertSpecialColumn + +/***********************************************************************/ +/* Get the PTDB of a table of the list. */ +/***********************************************************************/ +PTDB TDBTBL::GetSubTable(PGLOBAL g, PTBL tblp, PTABLE tabp) + { + char *db, key[128]; + uint k, flags; + PTDB tdbp = NULL; + TABLE_LIST table_list; + TABLE_SHARE *s; + PCATLG cat = To_Def->GetCat(); + PHC hc = ((MYCAT*)cat)->GetHandler(); + THD *thd = (hc->GetTable())->in_use; + + if (!thd) + return NULL; // Should not happen anymore + + if (tblp->DB) + db = tblp->DB; + else + db = (char*)hc->GetDBName(NULL); + + table_list.init_one_table(db, strlen(db), + tblp->Name, strlen(tblp->Name), + NULL, TL_IGNORE); + k = sprintf(key, "%s\0%s\0", db, tblp->Name); + + if (!(s = alloc_table_share(&table_list, key, k))) { + strcpy(g->Message, "Error allocating share\n"); + return NULL; + } // endif s + +// 1 8 16 +//flags = READ_ALL | DONT_OPEN_TABLES | DONT_OPEN_MASTER_REG; +//flags = 25; + flags = 24; + + if (!open_table_def(thd, s, flags)) { + hc->tshp = s; + tdbp = cat->GetTable(g, tabp); + hc->tshp = NULL; + } else + sprintf(g->Message, "Error %d opening share\n", s->error); + + if (trace && tdbp) + htrc("Subtable %s in %s\n", + tblp->Name, SVP(((PTDBASE)tdbp)->GetDef()->GetDB())); + + free_table_share(s); + return tdbp; + } // end of GetSubTable + +/***********************************************************************/ +/* Initializes the table table list. */ +/***********************************************************************/ +bool TDBTBL::InitTableList(PGLOBAL g) + { + char *colname; + int n, colpos; + PTBL tblp; + PTABLE tabp; + PTDB tdbp; + PCOL colp; + PTBLDEF tdp = (PTBLDEF)To_Def; + +// PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath()); + + for (n = 0, tblp = tdp->GetTables(); tblp; tblp = tblp->Next) { + if (TestFil(g, To_Filter, tblp)) { + // Table or named view + tabp = new(g) XTAB(tblp->Name); + tabp->SetQualifier(tblp->DB); + + // Get the table description block of this table + if (!(tdbp = GetSubTable(g, tblp, tabp))) { + if (++Nbf > Maxerr) + return TRUE; // Error return + else + continue; // Skip this table + + } // endif tdbp + + // We must allocate subtable columns before GetMaxSize is called + // because some (PLG, ODBC?) need to have their columns attached. + // Real initialization will be done later. + for (PCOL cp = Columns; cp; cp = cp->GetNext()) + if (!cp->IsSpecial()) { + colname = cp->GetName(); + colpos = ((PTBLCOL)cp)->Colnum; + + // We try first to get the column by name + if (!(colp = tdbp->ColDB(g, colname, 0)) && colpos) + // When unsuccessful, if a column number was specified + // try to get the column by its position in the table + colp = tdbp->ColDB(g, NULL, colpos); + + if (!colp) { + if (!Accept) { + sprintf(g->Message, MSG(NO_MATCHING_COL), + colname, tdbp->GetName()); + return TRUE; // Error return + } // endif !Accept + + } else // this is needed in particular by PLG tables + colp->SetColUse(cp->GetColUse()); + + } // endif !special + + if (Tablist) + Tablist->Link(tabp); + else + Tablist = tabp; + + n++; + } // endif filp + + } // endfor tblp + +//NumTables = n; + To_Filter = NULL; // To avoid doing it several times + return FALSE; + } // end of InitTableList + +/***********************************************************************/ +/* Test the tablename against the pseudo "local" filter. */ +/***********************************************************************/ +bool TDBTBL::TestFil(PGLOBAL g, PFIL filp, PTBL tblp) + { + char *fil, op[8], tn[NAME_LEN]; + bool neg; + + if (!filp) + return TRUE; + else if (strstr(filp, " OR ") || strstr(filp, " AND ")) + return TRUE; // Not handled yet + else + fil = filp + (*filp == '(' ? 1 : 0); + + if (sscanf(fil, "TABID %s", op) != 1) + return TRUE; // ignore invalid filter + + if ((neg = !strcmp(op, "NOT"))) + strcpy(op, "IN"); + + if (!strcmp(op, "=")) { + // Temporarily, filter must be "TABID = 'value'" only + if (sscanf(fil, "TABID = '%[^']'", tn) != 1) + return TRUE; // ignore invalid filter + + return !stricmp(tn, tblp->Name); + } else if (!strcmp(op, "IN")) { + char *p, *tnl = (char*)PlugSubAlloc(g, NULL, strlen(fil) - 10); + int n; + + if (neg) + n = sscanf(fil, "TABID NOT IN (%[^)])", tnl); + else + n = sscanf(fil, "TABID IN (%[^)])", tnl); + + if (n != 1) + return TRUE; // ignore invalid filter + + while (tnl) { + if ((p = strchr(tnl, ','))) + *p++ = 0; + + if (sscanf(tnl, "'%[^']'", tn) != 1) + return TRUE; // ignore invalid filter + else if (!stricmp(tn, tblp->Name)) + return !neg; // Found + + tnl = p; + } // endwhile + + return neg; // Not found + } // endif op + + return TRUE; // invalid operator + } // end of TestFil + +/***********************************************************************/ +/* TBL GetProgMax: get the max value for progress information. */ +/***********************************************************************/ +int TDBTBL::GetProgMax(PGLOBAL g) + { + PTABLE tblp; + int n, pmx = 0; + + if (!Tablist && InitTableList(g)) + return -1; + + for (tblp = Tablist; tblp; tblp = tblp->GetNext()) + if ((n = tblp->GetTo_Tdb()->GetProgMax(g)) > 0) + pmx += n; + + return pmx; + } // end of GetProgMax + +/***********************************************************************/ +/* TBL GetProgCur: get the current value for progress information. */ +/***********************************************************************/ +int TDBTBL::GetProgCur(void) + { + return Crp + Tdbp->GetProgCur(); + } // end of GetProgCur + +#if 0 +/***********************************************************************/ +/* TBL Cardinality: returns table cardinality in number of rows. */ +/* This function can be called with a null argument to test the */ +/* availability of Cardinality implementation (1 yes, 0 no). */ +/* Can be used on Multiple FIX table only. */ +/***********************************************************************/ +int TDBTBL::Cardinality(PGLOBAL g) + { + if (!g) + return Tdbp->Cardinality(g); + + if (!Tablist && InitTableList(g)) + return -1; + + int n, card = 0; + + for (int i = 0; i < NumFiles; i++) { + Tdbp->SetFile(g, Filenames[i]); + Tdbp->ResetSize(); + + if ((n = Tdbp->Cardinality(g)) < 0) { +// strcpy(g->Message, MSG(BAD_CARDINALITY)); + return -1; + } // endif n + + card += n; + } // endfor i + + return card; + } // end of Cardinality +#endif // 0 + +/***********************************************************************/ +/* Sum up the sizes of all sub-tables. */ +/***********************************************************************/ +int TDBTBL::GetMaxSize(PGLOBAL g) + { + if (MaxSize < 0) { + PTABLE tblp; + int mxsz; + + if (!Tablist && InitTableList(g)) + return 0; // Cannot be calculated at this stage + +// if (Use == USE_OPEN) { +// strcpy(g->Message, MSG(MAXSIZE_ERROR)); +// return -1; +// } else + MaxSize = 0; + + for (tblp = Tablist; tblp; tblp = tblp->GetNext()) { + if ((mxsz = tblp->GetTo_Tdb()->GetMaxSize(g)) < 0) { + MaxSize = -1; + return mxsz; + } // endif mxsz + + MaxSize += mxsz; + } // endfor i + + } // endif MaxSize + + return MaxSize; + } // end of GetMaxSize + +/***********************************************************************/ +/* Reset read/write position values. */ +/***********************************************************************/ +void TDBTBL::ResetDB(void) + { + for (PCOL colp = Columns; colp; colp = colp->GetNext()) + if (colp->GetAmType() == TYPE_AM_TABID) + colp->COLBLK::Reset(); + + for (PTABLE tblp = Tablist; tblp; tblp = tblp->GetNext()) + ((PTDBASE)tblp->GetTo_Tdb())->ResetDB(); + + Tdbp = (PTDBASE)Tablist->GetTo_Tdb(); + Crp = 0; + } // end of ResetDB + +/***********************************************************************/ +/* Returns RowId if b is false or Rownum if b is true. */ +/***********************************************************************/ +int TDBTBL::RowNumber(PGLOBAL g, bool b) + { + return Tdbp->RowNumber(g) + ((b) ? 0 : Rows); + } // end of RowNumber + +/***********************************************************************/ +/* TBL Access Method opening routine. */ +/* Open first file, other will be opened sequencially when reading. */ +/***********************************************************************/ +bool TDBTBL::OpenDB(PGLOBAL g) + { + if (trace) + htrc("TBL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n", + this, Tdb_No, Use, To_Key_Col, Mode); + + if (Use == USE_OPEN) { + /*******************************************************************/ + /* Table already open, replace it at its beginning. */ + /*******************************************************************/ + ResetDB(); + return Tdbp->OpenDB(g); // Re-open fist table + } // endif use + +#if 0 + /*********************************************************************/ + /* Direct access needed for join or sorting. */ + /*********************************************************************/ + if (NeedIndexing(g)) { + // Direct access of TBL tables is not implemented yet + strcpy(g->Message, MSG(NO_MUL_DIR_ACC)); + return TRUE; + } // endif NeedIndexing +#endif // 0 + + /*********************************************************************/ + /* When GetMaxsize was called, To_Filter was not set yet. */ + /*********************************************************************/ + if (To_Filter && Tablist) { + Tablist = NULL; + Nbf = 0; + } // endif To_Filter + + /*********************************************************************/ + /* Open the first table of the list. */ + /*********************************************************************/ + if (!Tablist && InitTableList(g)) // done in GetMaxSize + return TRUE; + + if ((CurTable = Tablist)) { + Tdbp = (PTDBASE)CurTable->GetTo_Tdb(); + Tdbp->SetMode(Mode); +// Tdbp->ResetDB(); +// Tdbp->ResetSize(); + + // Check and initialize the subtable columns + for (PCOL cp = Columns; cp; cp = cp->GetNext()) + if (cp->GetAmType() == TYPE_AM_TABID) + cp->COLBLK::Reset(); + else if (((PTBLCOL)cp)->Init(g)) + return TRUE; + + if (trace) + htrc("Opening subtable %s\n", Tdbp->GetName()); + + // Now we can safely open the table + if (Tdbp->OpenDB(g)) + return TRUE; + + } // endif *Tablist + + Use = USE_OPEN; + return FALSE; + } // end of OpenDB + +/***********************************************************************/ +/* ReadDB: Data Base read routine for MUL access method. */ +/***********************************************************************/ +int TDBTBL::ReadDB(PGLOBAL g) + { + int rc; + + if (!CurTable) + return RC_EF; + else if (To_Kindex) { + /*******************************************************************/ + /* Reading is by an index table. */ + /*******************************************************************/ + strcpy(g->Message, MSG(NO_INDEX_READ)); + rc = RC_FX; + } else { + /*******************************************************************/ + /* Now start the reading process. */ + /*******************************************************************/ + retry: + rc = Tdbp->ReadDB(g); + + if (rc == RC_EF) { + // Total number of rows met so far + Rows += Tdbp->RowNumber(g) - 1; + Crp += Tdbp->GetProgMax(g); + + if ((CurTable = CurTable->GetNext())) { + /***************************************************************/ + /* Continue reading from next table file. */ + /***************************************************************/ + Tdbp->CloseDB(g); + Tdbp = (PTDBASE)CurTable->GetTo_Tdb(); + + // Check and initialize the subtable columns + for (PCOL cp = Columns; cp; cp = cp->GetNext()) + if (cp->GetAmType() == TYPE_AM_TABID) + cp->COLBLK::Reset(); + else if (((PTBLCOL)cp)->Init(g)) + return RC_FX; + + if (trace) + htrc("Opening subtable %s\n", Tdbp->GetName()); + + // Now we can safely open the table + if (Tdbp->OpenDB(g)) // Open next table + return RC_FX; + + goto retry; + } // endif iFile + + } else if (rc == RC_FX) + strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")"); + + } // endif To_Kindex + + return rc; + } // end of ReadDB + +/***********************************************************************/ +/* Data Base write routine for MUL access method. */ +/***********************************************************************/ +int TDBTBL::WriteDB(PGLOBAL g) + { + strcpy(g->Message, MSG(TABMUL_READONLY)); + return RC_FX; // NIY + } // end of WriteDB + +/***********************************************************************/ +/* Data Base delete line routine for MUL access method. */ +/***********************************************************************/ +int TDBTBL::DeleteDB(PGLOBAL g, int irc) + { + strcpy(g->Message, MSG(TABMUL_READONLY)); + return RC_FX; // NIY + } // end of DeleteDB + +/***********************************************************************/ +/* Data Base close routine for MUL access method. */ +/***********************************************************************/ +void TDBTBL::CloseDB(PGLOBAL g) + { + if (Tdbp) + Tdbp->CloseDB(g); + + } // end of CloseDB + +/* ---------------------------- TBLCOL ------------------------------- */ + +/***********************************************************************/ +/* TBLCOL public constructor. */ +/***********************************************************************/ +TBLCOL::TBLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am) + : COLBLK(cdp, tdbp, i) + { + if (cprec) { + Next = cprec->GetNext(); + cprec->SetNext(this); + } else { + Next = tdbp->GetColumns(); + tdbp->SetColumns(this); + } // endif cprec + + // Set additional Dos access method information for column. + Long = cdp->GetLong(); // ??? +//strcpy(F_Date, cdp->F_Date); + Colp = NULL; + To_Val = NULL; + Pseudo = FALSE; + Colnum = cdp->GetOffset(); // If columns are retrieved by number + + if (trace) + htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this); + + } // end of TBLCOL constructor + +#if 0 +/***********************************************************************/ +/* TBLCOL public constructor. */ +/***********************************************************************/ +TBLCOL::TBLCOL(SPCBLK *scp, PTDB tdbp) : COLBLK(scp->GetName(), tdbp, 0) + { + // Set additional TBL access method information for pseudo column. + Is_Key = Was_Key = scp->IsKey(); + Long = scp->GetLength(); + Buf_Type = scp->GetResultType(); + *Format.Type = (Buf_Type == TYPE_INT) ? 'N' : 'C'; + Format.Length = Long; + Colp = NULL; + To_Val = NULL; + Pseudo = TRUE; + } // end of TBLCOL constructor + +/***********************************************************************/ +/* TBLCOL constructor used for copying columns. */ +/* tdbp is the pointer to the new table descriptor. */ +/***********************************************************************/ +TBLCOL::TBLCOL(TBLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) + { + Long = col1->Long; + Colp = col1->Colp; + To_Val = col1->To_Val; + Pseudo = col1->Pseudo; + } // end of TBLCOL copy constructor +#endif + +/***********************************************************************/ +/* TBLCOL initialization routine. */ +/* Look for the matching column in the current table. */ +/***********************************************************************/ +bool TBLCOL::Init(PGLOBAL g) + { + PTDBTBL tdbp = (PTDBTBL)To_Tdb; + + To_Val = NULL; + + if (!(Colp = tdbp->Tdbp->ColDB(g, Name, 0)) && Colnum) + Colp = tdbp->Tdbp->ColDB(g, NULL, Colnum); + + if (Colp) { + Colp->InitValue(g); // May not have been done elsewhere + To_Val = Colp->GetValue(); + } else if (!tdbp->Accept) { + sprintf(g->Message, MSG(NO_MATCHING_COL), Name, tdbp->Tdbp->GetName()); + return TRUE; + } else + Value->Reset(); + + return FALSE; + } // end of Init + +/***********************************************************************/ +/* ReadColumn: */ +/***********************************************************************/ +void TBLCOL::ReadColumn(PGLOBAL g) + { + if (trace) + htrc("TBL ReadColumn: name=%s\n", Name); + + if (Colp) { + Colp->ReadColumn(g); + Value->SetValue_pval(To_Val); + } // endif Colp + + } // end of ReadColumn + +/* ---------------------------- TBTBLK ------------------------------- */ + +/***********************************************************************/ +/* ReadColumn: */ +/***********************************************************************/ +void TBTBLK::ReadColumn(PGLOBAL g) + { + if (trace) + htrc("TBT ReadColumn: name=%s\n", Name); + + Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName()); + } // end of ReadColumn + +/* ------------------------------------------------------------------- */ |