mariadb/storage/connect/tabsys.cpp
Sergei Golubchik 5ae2656b69 Squashed commit of connect/10.0:
commit c545d544378483bf68c4fb713cd4ec872d0df2c4
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Tue Mar 27 23:13:14 2018 +0200

    - Fix MDEV-15577 CONNECT engine JDBC remote index prevents UPDATE
      Fixed in TDBJDBC::OpenDB because query can be null for updates
      modified:   storage/connect/tabjdbc.cpp

commit c4f1fe2e8e74566e9c3296f435448d9f5c718b23
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Wed Mar 14 12:21:17 2018 +0100

    - Fix MDEV-15429 CONNECT engine JDBC handling Postgresql UUID type
      Also handle Postgresql sending type VARCHAR for TEXT column and
      setting length to b x7FFFFFF when the length is unknown.
      modified:   storage/connect/Client.java
      modified:   storage/connect/JavaWrappers.jar
      modified:   storage/connect/JdbcInterface.java
      modified:   storage/connect/PostgresqlInterface.java
      modified:   storage/connect/global.h
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/jdbconn.cpp
      modified:   storage/connect/jdbconn.h
      modified:   storage/connect/mysql-test/connect/r/jdbc_postgresql.result
      modified:   storage/connect/mysql-test/connect/t/jdbc_postgresql.test
      modified:   storage/connect/mysql-test/connect/t/jdbconn.inc
      modified:   storage/connect/plgdbsem.h
      modified:   storage/connect/tabjdbc.cpp
      modified:   storage/connect/tabjdbc.h
      added:      storage/connect/mysql-test/connect/std_data/JavaWrappers.jar

commit 3068bb4882a316c6c32c624609db2bf24ae3ad40
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Mon Feb 26 19:40:27 2018 +0100

    Revert to old cmake file to avoid compile error

commit da8c1c0bd6a327fd03bd321be3170f468122ef67
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Mon Feb 26 16:13:39 2018 +0100

    - Remove warning on not used tabtyp variable in connect_assisted_discovery
      modified:   storage/connect/ha_connect.cc

    - Fix a bug causing CONNECT to loop when expanding a JSON column
      when the expanded column value is null or void array.
    - Adding the FullArray option to JSON tables.
    - Skipping expanded JSON lines when the expanded column value is null.
      modified:   storage/connect/connect.cc
      modified:   storage/connect/tabdos.h
      modified:   storage/connect/tabjson.cpp
      modified:   storage/connect/tabjson.h

    - Fix MDEV-13353 No file privilege for ODBC, JDBC, MONGO, MAC, WMI file types.
      modified:   storage/connect/ha_connect.cc

    - Make some Json UDFs  to accept a non JSON item as 1st parameter.
      modified:   storage/connect/json.cpp
      modified:   storage/connect/json.h
      modified:   storage/connect/jsonudf.cpp
      modified:   storage/connect/jsonudf.h

    - Update Json UDF tests to cope with above changes.
      modified:   storage/connect/mysql-test/connect/r/json_udf.result
      modified:   storage/connect/mysql-test/connect/r/json_udf_bin.result
      modified:   storage/connect/mysql-test/connect/r/vcol.result
      modified:   storage/connect/mysql-test/connect/t/json_udf.test
      modified:   storage/connect/mysql-test/connect/t/vcol.test

    - Fix some compiler warning treated as error
      PlugSubAlloc no more exported because it does throw.
      modified:   storage/connect/global.h
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/jsonudf.cpp
      modified:   storage/connect/tabjson.cpp
      modified:   storage/connect/tabjson.h

    - Other files modified (?) when going back to wrong merge
      modified:   storage/connect/CMakeLists.txt
      modified:   storage/connect/array.cpp
      modified:   storage/connect/colblk.cpp
      modified:   storage/connect/connect.cc
      modified:   storage/connect/csort.cpp
      modified:   storage/connect/domdoc.cpp
      modified:   storage/connect/filamap.cpp
      modified:   storage/connect/filamgz.cpp
      modified:   storage/connect/filamtxt.cpp
      modified:   storage/connect/filamzip.cpp
      modified:   storage/connect/filter.cpp
      modified:   storage/connect/fmdlex.c
      modified:   storage/connect/jdbconn.cpp
      modified:   storage/connect/macutil.cpp
      modified:   storage/connect/myconn.cpp
      modified:   storage/connect/odbconn.cpp
      modified:   storage/connect/plgdbutl.cpp
      modified:   storage/connect/plugutil.cpp
      modified:   storage/connect/preparse.h
      modified:   storage/connect/rcmsg.c
      modified:   storage/connect/rcmsg.h
      modified:   storage/connect/reldef.cpp
      modified:   storage/connect/tabdos.cpp
      modified:   storage/connect/tabfmt.cpp
      modified:   storage/connect/tabmac.cpp
      modified:   storage/connect/tabmul.cpp
      modified:   storage/connect/tabmysql.cpp
      modified:   storage/connect/tabmysql.h
      modified:   storage/connect/tabodbc.cpp
      modified:   storage/connect/tabtbl.cpp
      modified:   storage/connect/tabxml.cpp
      modified:   storage/connect/value.cpp
      modified:   storage/connect/xobject.cpp

commit 5095628b31ed8c94bd7c794c6b0162894a9040b1
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Tue Feb 13 14:29:00 2018 +0100

    - Fix a bug causing CONNECT to loop when expanding a JSON column
      when the expanded column value is null or void array.
    - Adding the FullArray option to JSON tables.
    - Skipping expanded JSON lines when the expanded column value is null.
      modified:   storage/connect/connect.cc
      modified:   storage/connect/tabdos.h
      modified:   storage/connect/tabjson.cpp
      modified:   storage/connect/tabjson.h

commit 9896174328da42016735630c893fd09eb128b48e
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Fri Feb 2 15:48:57 2018 +0100

    - Remove warning on not used tabtyp variable in connect_assisted_discovery
      modified:   storage/connect/ha_connect.cc

commit d7e254c05f88173eb04d8dafc813013eb42ccdbe
Author: Olivier Bertrand <bertrandop@gmail.com>
Date:   Wed Jan 31 14:42:45 2018 +0100

    - Use delayed load for the MongoDB C Drive on Windows
      modified:   storage/connect/CMakeLists.txt
      modified:   storage/connect/cmgoconn.cpp
      modified:   storage/connect/ha_connect.cc

    - Add FORCE to the connect_type_conv enum values
      This will translate binary values to TYPE_STRING
      modified:   storage/connect/checklvl.h
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/odbconn.cpp

    - Change the connect_xtrace variable to from int to set
      modified:   storage/connect/array.cpp
      modified:   storage/connect/blkfil.cpp
      modified:   storage/connect/block.h
      modified:   storage/connect/cmgoconn.cpp
      modified:   storage/connect/colblk.cpp
      modified:   storage/connect/connect.cc
      modified:   storage/connect/filamap.cpp
      modified:   storage/connect/filamdbf.cpp
      modified:   storage/connect/filamfix.cpp
      modified:   storage/connect/filamgz.cpp
      modified:   storage/connect/filamtxt.cpp
      modified:   storage/connect/filamvct.cpp
      modified:   storage/connect/filamzip.cpp
      modified:   storage/connect/filter.cpp
      modified:   storage/connect/global.h
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/inihandl.cpp
      modified:   storage/connect/javaconn.cpp
      modified:   storage/connect/jdbconn.cpp
      modified:   storage/connect/jmgfam.cpp
      modified:   storage/connect/jmgoconn.cpp
      modified:   storage/connect/json.cpp
      modified:   storage/connect/jsonudf.cpp
      modified:   storage/connect/libdoc.cpp
      modified:   storage/connect/mongo.cpp
      modified:   storage/connect/mycat.cc
      modified:   storage/connect/myconn.cpp
      modified:   storage/connect/odbconn.cpp
      modified:   storage/connect/plgdbutl.cpp
      modified:   storage/connect/plugutil.cpp
      modified:   storage/connect/reldef.cpp
      modified:   storage/connect/tabcol.cpp
      modified:   storage/connect/tabdos.cpp
      modified:   storage/connect/tabext.cpp
      modified:   storage/connect/tabfix.cpp
      modified:   storage/connect/tabfmt.cpp
      modified:   storage/connect/tabjdbc.cpp
      modified:   storage/connect/tabjson.cpp
      modified:   storage/connect/table.cpp
      modified:   storage/connect/tabmul.cpp
      modified:   storage/connect/tabmysql.cpp
      modified:   storage/connect/tabodbc.cpp
      modified:   storage/connect/tabpivot.cpp
      modified:   storage/connect/tabsys.cpp
      modified:   storage/connect/tabtbl.cpp
      modified:   storage/connect/tabutil.cpp
      modified:   storage/connect/tabvct.cpp
      modified:   storage/connect/tabwmi.cpp
      modified:   storage/connect/tabxml.cpp
      modified:   storage/connect/user_connect.cc
      modified:   storage/connect/valblk.cpp
      modified:   storage/connect/value.cpp
      modified:   storage/connect/xindex.cpp

    - Restore connect_enable_mongo variable (but undocumented)
      modified:   storage/connect/ha_connect.cc
      modified:   storage/connect/mycat.cc
      modified:   storage/connect/mysql-test/connect/r/json_java_2.result
      modified:   storage/connect/mysql-test/connect/r/json_java_3.result
      modified:   storage/connect/mysql-test/connect/r/json_mongo_c.result
      modified:   storage/connect/mysql-test/connect/r/mongo_c.result
      modified:   storage/connect/mysql-test/connect/r/mongo_java_2.result
      modified:   storage/connect/mysql-test/connect/r/mongo_java_3.result
      modified:   storage/connect/mysql-test/connect/r/tbl_thread.result
      modified:   storage/connect/mysql-test/connect/t/mongo.inc
      modified:   storage/connect/mysql-test/connect/t/mongo_test.inc
      modified:   storage/connect/mysql-test/connect/t/tbl_thread.test
2018-04-26 14:15:18 +02:00

884 lines
29 KiB
C++

/************* TabSys C++ Program Source Code File (.CPP) **************/
/* PROGRAM NAME: TABSYS */
/* ------------- */
/* Version 2.4 */
/* */
/* Author Olivier BERTRAND 2004-2017 */
/* */
/* This program are the INI/CFG tables classes. */
/***********************************************************************/
/***********************************************************************/
/* Include relevant sections of the System header files. */
/***********************************************************************/
#include "my_global.h"
#if defined(__WIN__)
#if defined(__BORLANDC__)
#define __MFC_COMPAT__ // To define min/max as macro
#endif // __BORLANDC__
//#include <windows.h>
#else // !__WIN__
#if defined(UNIX)
#include <errno.h>
#include <unistd.h>
#else // !UNIX
#include <io.h>
#endif // !UNIX
#include <fcntl.h>
#endif // !__WIN__
/***********************************************************************/
/* Include application header files: */
/* global.h is header containing all global declarations. */
/* plgdbsem.h is header containing the DB application declarations. */
/* tabdos.h is header containing the TABDOS class declarations. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "reldef.h"
#if !defined(__WIN__)
#include "osutil.h"
#endif // !__WIN__
#include "filamtxt.h"
#include "tabdos.h"
#include "tabsys.h"
#include "tabmul.h"
#include "inihandl.h"
#define CSZ 36 // Column section name length
#define CDZ 256 // Column definition length
#if !defined(__WIN__)
#define GetPrivateProfileSectionNames(S,L,I) \
GetPrivateProfileString(NULL,NULL,"",S,L,I)
#endif // !__WIN__
/* -------------- Implementation of the INI classes ------------------ */
/***********************************************************************/
/* Constructor. */
/***********************************************************************/
INIDEF::INIDEF(void)
{
Pseudo = 3;
Fn = NULL;
Xname = NULL;
Layout = '?';
Ln = 0;
} // end of INIDEF constructor
/***********************************************************************/
/* DefineAM: define specific AM block values from XDB file. */
/***********************************************************************/
bool INIDEF::DefineAM(PGLOBAL g, LPCSTR, int)
{
char buf[8];
Fn = GetStringCatInfo(g, "Filename", NULL);
GetCharCatInfo("Layout", "C", buf, sizeof(buf));
Layout = toupper(*buf);
if (Fn) {
char *p = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
PlugSetPath(p, Fn, GetPath());
Fn = p;
} else {
strcpy(g->Message, MSG(MISSING_FNAME));
return true;
} // endif Fn
Ln = GetSizeCatInfo("Secsize", "8K");
Desc = Fn;
return false;
} // end of DefineAM
/***********************************************************************/
/* GetTable: makes a new TDB of the proper type. */
/***********************************************************************/
PTDB INIDEF::GetTable(PGLOBAL g, MODE)
{
PTDBASE tdbp;
if (Layout == 'C')
tdbp = new(g) TDBINI(this);
else
tdbp = new(g) TDBXIN(this);
if (Multiple)
tdbp = new(g) TDBMUL(tdbp); // No block optimization yet
return tdbp;
} // end of GetTable
#if 0
/***********************************************************************/
/* DeleteTableFile: Delete INI table files using platform API. */
/***********************************************************************/
bool INIDEF::DeleteTableFile(PGLOBAL g)
{
char filename[_MAX_PATH];
bool rc;
// Delete the INI table file if not protected
if (!IsReadOnly()) {
PlugSetPath(filename, Fn, GetPath());
#if defined(__WIN__)
rc = !DeleteFile(filename);
#else // UNIX
rc = remove(filename);
#endif // UNIX
} else
rc =true;
return rc; // Return true if error
} // end of DeleteTableFile
#endif // 0
/* ------------------------------------------------------------------- */
/***********************************************************************/
/* Implementation of the TDBINI class. */
/***********************************************************************/
TDBINI::TDBINI(PINIDEF tdp) : TDBASE(tdp)
{
Ifile = tdp->Fn;
Seclist = NULL;
Section = NULL;
Seclen = tdp->Ln;
N = 0;
} // end of TDBINI constructor
TDBINI::TDBINI(PTDBINI tdbp) : TDBASE(tdbp)
{
Ifile = tdbp->Ifile;
Seclist = tdbp->Seclist;
Section = tdbp->Section;
Seclen = tdbp->Seclen;
N = tdbp->N;
} // end of TDBINI copy constructor
// Is this really useful ???
PTDB TDBINI::Clone(PTABS t)
{
PTDB tp;
PINICOL cp1, cp2;
PGLOBAL g = t->G;
tp = new(g) TDBINI(this);
for (cp1 = (PINICOL)Columns; cp1; cp1 = (PINICOL)cp1->GetNext()) {
cp2 = new(g) INICOL(cp1, tp); // Make a copy
NewPointer(t, cp1, cp2);
} // endfor cp1
return tp;
} // end of Clone
/***********************************************************************/
/* Get the section list from the INI file. */
/***********************************************************************/
char *TDBINI::GetSeclist(PGLOBAL g)
{
if (trace(1))
htrc("GetSeclist: Seclist=%p\n", Seclist);
if (!Seclist) {
// Result will be retrieved from the INI file
Seclist = (char*)PlugSubAlloc(g, NULL, Seclen);
GetPrivateProfileSectionNames(Seclist, Seclen, Ifile);
} // endif Seclist
return Seclist;
} // end of GetSeclist
/***********************************************************************/
/* Allocate INI column description block. */
/***********************************************************************/
PCOL TDBINI::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
return new(g) INICOL(cdp, this, cprec, n);
} // end of MakeCol
/***********************************************************************/
/* INI Cardinality: returns the number of sections in the INI file. */
/***********************************************************************/
int TDBINI::Cardinality(PGLOBAL g)
{
if (!g)
return 1;
if (Cardinal < 0) {
// Count the number of sections from the section list
char *p = GetSeclist(g);
Cardinal = 0;
if (p)
for (; *p; p += (strlen(p) + 1))
Cardinal++;
} // endif Cardinal
return Cardinal;
} // end of Cardinality
/***********************************************************************/
/* INI GetMaxSize: returns the table cardinality. */
/***********************************************************************/
int TDBINI::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0)
MaxSize = Cardinality(g);
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* INI Access Method opening routine. */
/***********************************************************************/
bool TDBINI::OpenDB(PGLOBAL g)
{
PINICOL colp;
if (Use == USE_OPEN) {
#if 0
if (To_Kindex)
/*****************************************************************/
/* Table is to be accessed through a sorted index table. */
/*****************************************************************/
To_Kindex->Reset();
#endif // 0
Section = NULL;
N = 0;
return false;
} // endif use
/*********************************************************************/
/* OpenDB: initialize the INI file processing. */
/*********************************************************************/
GetSeclist(g);
Use = USE_OPEN; // Do it now in case we are recursively called
/*********************************************************************/
/* Allocate the buffers that will contain key values. */
/*********************************************************************/
for (colp = (PINICOL)Columns; colp; colp = (PINICOL)colp->GetNext())
if (!colp->IsSpecial()) // Not a pseudo column
colp->AllocBuf(g);
if (trace(1))
htrc("INI OpenDB: seclist=%s seclen=%d ifile=%s\n",
Seclist, Seclen, Ifile);
return false;
} // end of OpenDB
/***********************************************************************/
/* Data Base read routine for INI access method. */
/***********************************************************************/
int TDBINI::ReadDB(PGLOBAL)
{
/*********************************************************************/
/* Now start the pseudo reading process. */
/*********************************************************************/
if (!Section)
Section = Seclist;
else
Section += (strlen(Section) + 1);
if (trace(2))
htrc("INI ReadDB: section=%s N=%d\n", Section, N);
N++;
return (*Section) ? RC_OK : RC_EF;
} // end of ReadDB
/***********************************************************************/
/* WriteDB: Data Base write routine for INI access methods. */
/***********************************************************************/
int TDBINI::WriteDB(PGLOBAL)
{
// This is to check that section name was given when inserting
if (Mode == MODE_INSERT)
Section = NULL;
// Nothing else to do because all was done in WriteColumn
return RC_OK;
} // end of WriteDB
/***********************************************************************/
/* Data Base delete line routine for INI access methods. */
/***********************************************************************/
int TDBINI::DeleteDB(PGLOBAL g, int irc)
{
switch (irc) {
case RC_EF:
break;
case RC_FX:
while (ReadDB(g) == RC_OK)
if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) {
sprintf(g->Message, "Error %d accessing %s",
GetLastError(), Ifile);
return RC_FX;
} // endif
break;
default:
if (!Section) {
strcpy(g->Message, MSG(NO_SECTION_NAME));
return RC_FX;
} else
if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) {
sprintf(g->Message, "Error %d accessing %s",
GetLastError(), Ifile);
return RC_FX;
} // endif rc
} // endswitch irc
return RC_OK;
} // end of DeleteDB
/***********************************************************************/
/* Data Base close routine for INI access methods. */
/***********************************************************************/
void TDBINI::CloseDB(PGLOBAL)
{
#if !defined(__WIN__)
PROFILE_Close(Ifile);
#endif // !__WIN__
} // end of CloseDB
// ------------------------ INICOL functions ----------------------------
/***********************************************************************/
/* INICOL public constructor. */
/***********************************************************************/
INICOL::INICOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ)
: COLBLK(cdp, tdbp, i)
{
if (cprec) {
Next = cprec->GetNext();
cprec->SetNext(this);
} else {
Next = tdbp->GetColumns();
tdbp->SetColumns(this);
} // endif cprec
// Set additional INI access method information for column.
Valbuf = NULL;
Flag = cdp->GetOffset();
Long = cdp->GetLong();
To_Val = NULL;
} // end of INICOL constructor
/***********************************************************************/
/* INICOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
INICOL::INICOL(INICOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
{
Valbuf = col1->Valbuf;
Flag = col1->Flag;
Long = col1->Long;
To_Val = col1->To_Val;
} // end of INICOL copy constructor
/***********************************************************************/
/* Allocate a buffer of the proper size. */
/***********************************************************************/
void INICOL::AllocBuf(PGLOBAL g)
{
if (!Valbuf)
Valbuf = (char*)PlugSubAlloc(g, NULL, Long + 1);
} // end of AllocBuf
/***********************************************************************/
/* SetBuffer: prepare a column block for write operation. */
/***********************************************************************/
bool INICOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
{
if (!(To_Val = value)) {
sprintf(g->Message, MSG(VALUE_ERROR), Name);
return true;
} else if (Buf_Type == value->GetType()) {
// Values are of the (good) column type
if (Buf_Type == TYPE_DATE) {
// If any of the date values is formatted
// output format must be set for the receiving table
if (GetDomain() || ((DTVAL *)value)->IsFormatted())
goto newval; // This will make a new value;
} else if (Buf_Type == TYPE_DOUBLE || Buf_Type == TYPE_DECIM)
// Float values must be written with the correct (column) precision
// Note: maybe this should be forced by ShowValue instead of this ?
value->SetPrec(GetScale());
Value = value; // Directly access the external value
} else {
// Values are not of the (good) column type
if (check) {
sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
GetTypeName(Buf_Type), GetTypeName(value->GetType()));
return true;
} // endif check
newval:
if (InitValue(g)) // Allocate the matching value block
return true;
} // endif's Value, Buf_Type
// Allocate the internal value buffer
AllocBuf(g);
// Because Colblk's have been made from a copy of the original TDB in
// case of Update, we must reset them to point to the original one.
if (To_Tdb->GetOrig())
To_Tdb = (PTDB)To_Tdb->GetOrig();
// Set the Column
Status = (ok) ? BUF_EMPTY : BUF_NO;
return false;
} // end of SetBuffer
/***********************************************************************/
/* ReadColumn: what this routine does is to access the key buffer set */
/* from the corresponding section, extract from it the key value */
/* corresponding to this column name and convert it to buffer type. */
/***********************************************************************/
void INICOL::ReadColumn(PGLOBAL)
{
PTDBINI tdbp = (PTDBINI)To_Tdb;
if (trace(2))
htrc("INI ReadColumn: col %s R%d flag=%d\n",
Name, tdbp->GetTdb_No(), Flag);
/*********************************************************************/
/* Get the key value from the INI file. */
/*********************************************************************/
switch (Flag) {
case 1:
strncpy(Valbuf, tdbp->Section, Long); // Section name
Valbuf[Long] = '\0';
break;
default:
GetPrivateProfileString(tdbp->Section, Name, "\b",
Valbuf, Long + 1, tdbp->Ifile);
break;
} // endswitch Flag
// Missing keys are interpreted as null values
if (!strcmp(Valbuf, "\b")) {
if (Nullable)
Value->SetNull(true);
Value->Reset(); // Null value
} else
Value->SetValue_psz(Valbuf);
} // end of ReadColumn
/***********************************************************************/
/* WriteColumn: what this routine does is to access the last line */
/* read from the corresponding table, and rewrite the field */
/* corresponding to this column from the column buffer and type. */
/***********************************************************************/
void INICOL::WriteColumn(PGLOBAL g)
{
char *p;
bool rc;
PTDBINI tdbp = (PTDBINI)To_Tdb;
if (trace(2))
htrc("INI WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
Name, tdbp->GetTdb_No(), ColUse, Status);
/*********************************************************************/
/* Get the string representation of Value according to column type. */
/*********************************************************************/
if (Value != To_Val)
Value->SetValue_pval(To_Val, false); // Convert the updated value
// Null key are missing keys
if (Value->IsNull())
return;
p = Value->GetCharString(Valbuf);
if (strlen(p) > (unsigned)Long) {
sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
throw 31;
} else if (Flag == 1) {
if (tdbp->Mode == MODE_UPDATE) {
strcpy(g->Message, MSG(NO_SEC_UPDATE));
throw 31;
} else if (*p) {
tdbp->Section = p;
} else
tdbp->Section = NULL;
return;
} else if (!tdbp->Section) {
strcpy(g->Message, MSG(SEC_NAME_FIRST));
throw 31;
} // endif's
/*********************************************************************/
/* Updating must be done only when not in checking pass. */
/*********************************************************************/
if (Status) {
rc = WritePrivateProfileString(tdbp->Section, Name, p, tdbp->Ifile);
if (!rc) {
sprintf(g->Message, "Error %d writing to %s",
GetLastError(), tdbp->Ifile);
throw 31;
} // endif rc
} // endif Status
} // end of WriteColumn
/* ------------------------------------------------------------------- */
/***********************************************************************/
/* Implementation of the TDBXIN class. */
/***********************************************************************/
TDBXIN::TDBXIN(PINIDEF tdp) : TDBINI(tdp)
{
Keylist = NULL;
Keycur = NULL;
Keylen = Seclen;
Oldsec = -1;
} // end of TDBXIN constructor
TDBXIN::TDBXIN(PTDBXIN tdbp) : TDBINI(tdbp)
{
Keylist = tdbp->Keylist;
Keycur = tdbp->Keycur;
Keylen = tdbp->Keylen;
Oldsec = tdbp->Oldsec;
} // end of TDBXIN copy constructor
// Is this really useful ???
PTDB TDBXIN::Clone(PTABS t)
{
PTDB tp;
PXINCOL cp1, cp2;
PGLOBAL g = t->G;
tp = new(g) TDBXIN(this);
for (cp1 = (PXINCOL)Columns; cp1; cp1 = (PXINCOL)cp1->GetNext()) {
cp2 = new(g) XINCOL(cp1, tp); // Make a copy
NewPointer(t, cp1, cp2);
} // endfor cp1
return tp;
} // end of Clone
/***********************************************************************/
/* Get the key list from the INI file. */
/***********************************************************************/
char *TDBXIN::GetKeylist(PGLOBAL g, char *sec)
{
if (!Keylist)
Keylist = (char*)PlugSubAlloc(g, NULL, Keylen);
GetPrivateProfileString(sec, NULL, "", Keylist, Keylen, Ifile);
return Keylist;
} // end of GetKeylist
/***********************************************************************/
/* Allocate XIN column description block. */
/***********************************************************************/
PCOL TDBXIN::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
return new(g) XINCOL(cdp, this, cprec, n);
} // end of MakeCol
/***********************************************************************/
/* XIN Cardinality: returns the number of keys in the XIN file. */
/***********************************************************************/
int TDBXIN::Cardinality(PGLOBAL g)
{
if (!g)
return 1;
if (Cardinal < 0) {
// Count the number of keys from the section list
char *k, *p = GetSeclist(g);
Cardinal = 0;
if (p)
for (; *p; p += (strlen(p) + 1))
for (k = GetKeylist(g, p); *k; k += (strlen(k) + 1))
Cardinal++;
} // endif Cardinal
return Cardinal;
} // end of Cardinality
/***********************************************************************/
/* Record position is Section+Key. */
/***********************************************************************/
int TDBXIN::GetRecpos(void)
{
union {
short X[2]; // Section and Key offsets
int Xpos; // File position
}; // end of union
X[0] = (short)(Section - Seclist);
X[1] = (short)(Keycur - Keylist);
return Xpos;
} // end of GetRecpos
/***********************************************************************/
/* Record position is Section+Key. */
/***********************************************************************/
bool TDBXIN::SetRecpos(PGLOBAL g, int recpos)
{
union {
short X[2]; // Section and Key offsets
int Xpos; // File position
}; // end of union
Xpos = recpos;
if (X[0] != Oldsec) {
Section = Seclist + X[0];
Keycur = GetKeylist(g, Section) + X[1];
Oldsec = X[0];
} else
Keycur = Keylist + X[1];
return false;
} // end of SetRecpos
/***********************************************************************/
/* XIN Access Method opening routine. */
/***********************************************************************/
bool TDBXIN::OpenDB(PGLOBAL g)
{
Oldsec = -1; // To replace the table at its beginning
return TDBINI::OpenDB(g);
} // end of OpenDB
/***********************************************************************/
/* Data Base read routine for XIN access method. */
/***********************************************************************/
int TDBXIN::ReadDB(PGLOBAL g)
{
/*********************************************************************/
/* Now start the pseudo reading process. */
/*********************************************************************/
#if 0 // XIN tables are not indexable
if (To_Kindex) {
/*******************************************************************/
/* Reading is by an index table. */
/*******************************************************************/
int recpos = To_Kindex->Fetch(g);
switch (recpos) {
case -1: // End of file reached
return RC_EF;
case -2: // No match for join
return RC_NF;
case -3: // Same record as last non null one
return RC_OK;
default:
SetRecpos(g, recpos);
} // endswitch recpos
} else {
#endif // 0
do {
if (!Keycur || !*Keycur) {
if (!Section)
Section = Seclist;
else
Section += (strlen(Section) + 1);
if (*Section)
Keycur = GetKeylist(g, Section);
else
return RC_EF;
} else
Keycur += (strlen(Keycur) + 1);
} while (!*Keycur);
N++;
//} // endif To_Kindex
return RC_OK;
} // end of ReadDB
/***********************************************************************/
/* WriteDB: Data Base write routine for XIN access methods. */
/***********************************************************************/
int TDBXIN::WriteDB(PGLOBAL)
{
// To check that section and key names were given when inserting
if (Mode == MODE_INSERT) {
Section = NULL;
Keycur = NULL;
} // endif Mode
// Nothing else to do because all was done in WriteColumn
return RC_OK;
} // end of WriteDB
/***********************************************************************/
/* Data Base delete line routine for XIN access methods. */
/***********************************************************************/
int TDBXIN::DeleteDB(PGLOBAL g, int irc)
{
if (irc == RC_EF) {
} else if (irc == RC_FX) {
for (Section = Seclist; *Section; Section += (strlen(Section) + 1))
if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) {
sprintf(g->Message, "Error %d accessing %s",
GetLastError(), Ifile);
return RC_FX;
} // endif
} else if (!Section) {
strcpy(g->Message, MSG(NO_SECTION_NAME));
return RC_FX;
} else
if (!WritePrivateProfileString(Section, Keycur, NULL, Ifile)) {
sprintf(g->Message, "Error %d accessing %s",
GetLastError(), Ifile);
return RC_FX;
} // endif
return RC_OK;
} // end of DeleteDB
// ------------------------ XINCOL functions ----------------------------
/***********************************************************************/
/* XINCOL public constructor. */
/***********************************************************************/
XINCOL::XINCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
: INICOL(cdp, tdbp, cprec, i, am)
{
} // end of XINCOL constructor
/***********************************************************************/
/* XINCOL constructor used for copying columns. */
/* tdbp is the pointer to the new table descriptor. */
/***********************************************************************/
XINCOL::XINCOL(XINCOL *col1, PTDB tdbp) : INICOL(col1, tdbp)
{
} // end of XINCOL copy constructor
/***********************************************************************/
/* ReadColumn: what this routine does is to access the key buffer set */
/* from the corresponding section, extract from it the key value */
/* corresponding to this column name and convert it to buffer type. */
/***********************************************************************/
void XINCOL::ReadColumn(PGLOBAL)
{
PTDBXIN tdbp = (PTDBXIN)To_Tdb;
/*********************************************************************/
/* Get the key value from the XIN file. */
/*********************************************************************/
switch (Flag) {
case 1:
strncpy(Valbuf, tdbp->Section, Long); // Section name
Valbuf[Long] = '\0';
break;
case 2:
strncpy(Valbuf, tdbp->Keycur, Long); // Key name
Valbuf[Long] = '\0';
break;
default:
GetPrivateProfileString(tdbp->Section, tdbp->Keycur, "",
Valbuf, Long + 1, tdbp->Ifile);
break;
} // endswitch Flag
Value->SetValue_psz(Valbuf);
} // end of ReadColumn
/***********************************************************************/
/* WriteColumn: what this routine does is to access the last line */
/* read from the corresponding table, and rewrite the field */
/* corresponding to this column from the column buffer and type. */
/***********************************************************************/
void XINCOL::WriteColumn(PGLOBAL g)
{
char *p;
bool rc;
PTDBXIN tdbp = (PTDBXIN)To_Tdb;
if (trace(2))
htrc("XIN WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
Name, tdbp->GetTdb_No(), ColUse, Status);
/*********************************************************************/
/* Get the string representation of Value according to column type. */
/*********************************************************************/
if (Value != To_Val)
Value->SetValue_pval(To_Val, false); // Convert the updated value
p = Value->GetCharString(Valbuf);
if (strlen(p) > (unsigned)Long) {
sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
throw 31;
} else if (Flag == 1) {
if (tdbp->Mode == MODE_UPDATE) {
strcpy(g->Message, MSG(NO_SEC_UPDATE));
throw 31;
} else if (*p) {
tdbp->Section = p;
} else
tdbp->Section = NULL;
return;
} else if (Flag == 2) {
if (tdbp->Mode == MODE_UPDATE) {
strcpy(g->Message, MSG(NO_KEY_UPDATE));
throw 31;
} else if (*p) {
tdbp->Keycur = p;
} else
tdbp->Keycur = NULL;
return;
} else if (!tdbp->Section || !tdbp->Keycur) {
strcpy(g->Message, MSG(SEC_KEY_FIRST));
throw 31;
} // endif's
/*********************************************************************/
/* Updating must be done only when not in checking pass. */
/*********************************************************************/
if (Status) {
rc = WritePrivateProfileString(tdbp->Section, tdbp->Keycur, p, tdbp->Ifile);
if (!rc) {
sprintf(g->Message, "Error %d writing to %s",
GetLastError(), tdbp->Ifile);
throw 31;
} // endif rc
} // endif Status
} // end of WriteColumn
/* ------------------------ End of System ---------------------------- */