/************* TabFmt C++ Program Source Code File (.CPP) **************/ /* PROGRAM NAME: TABFMT */ /* ------------- */ /* Version 3.9.3 */ /* */ /* COPYRIGHT: */ /* ---------- */ /* (C) Copyright to the author Olivier BERTRAND 2001 - 2019 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ /* This program are the TABFMT classes DB execution routines. */ /* The base class CSV is comma separated files. */ /* FMT (Formatted) files are those having a complex internal record */ /* format described in the Format keyword of their definition. */ /***********************************************************************/
/***********************************************************************/ /* Include relevant MariaDB header file. */ /***********************************************************************/ #include"my_global.h"
/***********************************************************************/ /* 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"mycat.h" #include"filamap.h" #ifdefined(GZ_SUPPORT) #include"filamgz.h" #endif// GZ_SUPPORT #ifdefined(ZIP_SUPPORT) #include"filamzip.h" #endif// ZIP_SUPPORT #include"tabfmt.h" #include"tabmul.h" #define NO_FUNC #include"plgcnx.h"// For DB types #include"resource.h" #include"m_string.h"
/***********************************************************************/ /* This should be an option. */ /***********************************************************************/ #define MAXCOL 200/* Default max column nb in result */ #define TYPE_UNKNOWN 12/* Must be greater than other types */
/***********************************************************************/ /* CSVColumns: constructs the result blocks containing the description */ /* of all the columns of a CSV file that will be retrieved by #GetData.*/ /* Note: the algorithm to set the type is based on the internal values */ /* of types (TYPE_STRING < TYPE_DOUBLE < TYPE_INT) (1 < 2 < 7). */ /* If these values are changed, this will have to be revisited. */ /***********************************************************************/
PQRYRES CSVColumns(PGLOBAL g, PCSZ dp, PTOS topt, bool info)
{ staticint buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING,
TYPE_INT, TYPE_INT, TYPE_SHORT}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME,
FLD_PREC, FLD_LENGTH, FLD_SCALE}; staticunsignedint length[] = {6, 6, 8, 10, 10, 6}; constchar *fn; char sep, q; int rc, mxr; bool hdr; char *p, *colname[MAXCOL], dechar, buf[16]; int i, imax, hmax, n, nerr, phase, blank, digit, dec, type; int ncol = sizeof(buftyp) / sizeof(int); int num_read = 0, num_max = 10000000; // Statistics int len[MAXCOL], typ[MAXCOL], prc[MAXCOL];
PCSVDEF tdp;
PTDBCSV tcvp;
PTDBASE tdbp;
PQRYRES qrp;
PCOLRES crp;
if (info) {
imax = hmax = 0;
length[0] = 128; goto skipit;
} // endif info
/*********************************************************************/ /* Open the CSV file. */ /*********************************************************************/ if (tdbp->OpenDB(g)) return NULL;
if (hdr) { /*******************************************************************/ /* Make the column names from the first line. */ /*******************************************************************/
phase = 0;
if ((rc = tdbp->ReadDB(g)) == RC_OK) {
p = PlgDBDup(g, tcvp->To_Line);
//skip leading blanks for (; *p == ' '; p++) ;
if (q && *p == q) { // Header is quoted
p++;
phase = 1;
} // endif q
/*******************************************************************/ /* Make the test for field lengths. */ /*******************************************************************/
i = n = phase = blank = digit = dec = 0;
for (p = tcvp->To_Line; *p; p++) if (*p == sep) { if (phase != 1) { if (i == MAXCOL - 1) {
snprintf(g->Message, sizeof(g->Message), MSG(TOO_MANY_FIELDS), num_read, fn); goto err;
} // endif i
// isdigit cannot be used here because of debug assert if (!strchr("0123456789", *p)) { if (!digit && *p == dechar)
dec = 1; // Decimal point found elseif (blank || !(*p == '-' || *p == '+'))
digit = 1;
skipit: if (trace(1))
htrc("CSVColumns: imax=%d hmax=%d len=%d\n",
imax, hmax, length[0]);
/*********************************************************************/ /* Allocate the structures used to refer to the result set. */ /*********************************************************************/
qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3,
buftyp, fldtyp, length, false, false); if (info || !qrp) return qrp;
qrp->Nblin = imax;
/*********************************************************************/ /* Now get the results into blocks. */ /*********************************************************************/ for (i = 0; i < imax; i++) { if (i >= hmax) {
snprintf(buf, sizeof(buf), "COL%.3d", i+1);
p = buf;
} else
p = colname[i];
if (typ[i] == TYPE_UNKNOWN) // Void column
typ[i] = TYPE_STRING;
crp = qrp->Colresp; // Column Name
crp->Kdata->SetValue(p, i);
crp = crp->Next; // Data Type
crp->Kdata->SetValue(typ[i], i);
crp = crp->Next; // Type Name
crp->Kdata->SetValue(GetTypeName(typ[i]), i);
crp = crp->Next; // Precision
crp->Kdata->SetValue(len[i], i);
crp = crp->Next; // Length
crp->Kdata->SetValue(len[i], i);
crp = crp->Next; // Scale (precision)
crp->Kdata->SetValue(prc[i], i);
} // endfor i
/*********************************************************************/ /* Return the result pointer for use by GetData routines. */ /*********************************************************************/ return qrp;
err:
tdbp->CloseDB(g); return NULL;
} // end of CSVCColumns
/* --------------------------- Class CSVDEF -------------------------- */
/*******************************************************************/ /* Allocate a TDB of the proper type. */ /* Column blocks will be allocated only when needed. */ /*******************************************************************/ if (!Fmtd)
tdbp = new(g) TDBCSV(this, txfp); else
tdbp = new(g) TDBFMT(this, txfp);
if (Multiple)
tdbp = new(g) TDBMUL(tdbp); else /*****************************************************************/ /* For block tables, get eventually saved optimization values. */ /*****************************************************************/ if (tdbp->GetBlockValues(g)) {
PushWarning(g, tdbp); // return NULL; // causes a crash when deleting index
} else { if (IsOptimized()) { if (map) {
txfp = new(g) MBKFAM(this);
} elseif (Compressed) { #ifdefined(GZ_SUPPORT) if (Compressed == 1)
txfp = new(g) ZBKFAM(this); else {
txfp->SetBlkPos(To_Pos);
((PZLBFAM)txfp)->SetOptimized(To_Pos != NULL);
} // endelse #else
snprintf(g->Message, sizeof(g->Message), MSG(NO_FEAT_SUPPORT), "GZ"); return NULL; #endif
} else
txfp = new(g) BLKFAM(this);
// Method
PTDB TDBCSV::Clone(PTABS t)
{
PTDB tp;
PCSVCOL cp1, cp2;
PGLOBAL g = t->G; // Is this really useful ???
tp = new(g) TDBCSV(g, this);
for (cp1 = (PCSVCOL)Columns; cp1; cp1 = (PCSVCOL)cp1->GetNext()) {
cp2 = new(g) CSVCOL(cp1, tp); // Make a copy
NewPointer(t, cp1, cp2);
} // endfor cp1
return tp;
} // end of Clone
/***********************************************************************/ /* Allocate CSV column description block. */ /***********************************************************************/
PCOL TDBCSV::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{ returnnew(g) CSVCOL(g, cdp, this, cprec, n);
} // end of MakeCol
/***********************************************************************/ /* Check whether the number of errors is greater than the maximum. */ /***********************************************************************/ bool TDBCSV::CheckErr(void)
{ return (++Nerr) > Maxerr;
} // end of CheckErr
/***********************************************************************/ /* CSV EstimatedLength. Returns an estimated minimum line length. */ /***********************************************************************/ int TDBCSV::EstimatedLength(void)
{ int n = 0;
PCOLDEF cdp;
if (trace(1))
htrc("EstimatedLength: Fields=%d Columns=%p\n", Fields, Columns);
for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) if (!cdp->IsSpecial() && !cdp->IsVirtual()) // A true column
n++;
return --n; // Number of separators if all fields are null
} // end of Estimated Length
#if0 /***********************************************************************/ /* CSV tables needs the use temporary files for Update. */ /***********************************************************************/ bool TDBCSV::IsUsingTemp(PGLOBAL g)
{ return (Use_Temp == TMP_YES || Use_Temp == TMP_FORCE ||
(Use_Temp == TMP_AUTO && Mode == MODE_UPDATE));
} // end of IsUsingTemp #endif// 0 (Same as TDBDOS one)
/***********************************************************************/ /* CSV Access Method opening routine. */ /* First allocate the Offset and Fldlen arrays according to the */ /* greatest field used in that query. Then call the DOS opening fnc. */ /***********************************************************************/ bool TDBCSV::OpenDB(PGLOBAL g)
{ bool rc = false;
PCOLDEF cdp;
PDOSDEF tdp = (PDOSDEF)To_Def;
if (Use != USE_OPEN && (Columns || Mode == MODE_UPDATE)) { // Allocate the storage used to read (or write) records int i, len;
PCSVCOL colp;
if (!Fields) { // May have been set in TABFMT::OpenDB if (Mode != MODE_UPDATE && Mode != MODE_INSERT) { for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next) if (!colp->IsSpecial() && !colp->IsVirtual())
Fields = MY_MAX(Fields, (int)colp->Fldnum);
if (Columns)
Fields++; // Fldnum was 0 based
} else for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) if (!cdp->IsSpecial() && !cdp->IsVirtual())
Fields++;
}
if (!rc && Mode == MODE_UPDATE && To_Kindex) // Because KINDEX::Init is executed in mode READ, we must restore // the Fldlen array that was modified when reading the table file. for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
Fldlen[cdp->GetOffset() - 1] = cdp->GetLength();
return rc;
} // end of OpenDB
/***********************************************************************/ /* SkipHeader: Physically skip first header line if applicable. */ /* This is called from TDBDOS::OpenDB and must be executed before */ /* Kindex construction if the file is accessed using an index. */ /***********************************************************************/ bool TDBCSV::SkipHeader(PGLOBAL g)
{ int len = GetFileLength(g); bool rc = false;
#ifdefined(_DEBUG) if (len < 0) returntrue; #endif// _DEBUG
if (Header) { if (Mode == MODE_INSERT) { if (!len) { // New file, the header line must be constructed and written int i, n = 0; int hlen = 0; bool q = Qot && Quoted > 0;
PCOLDEF cdp; char *pos, *end;
// Estimate the length of the header list for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) {
hlen += (1 + strlen(cdp->GetName()));
hlen += ((q) ? 2 : 0);
n++; // Calculate the number of columns
} // endfor cdp
// File is empty, write a header record
memset(To_Line, 0, Lrecl);
pos= To_Line;
end= To_Line + Lrecl-1;
// The column order in the file is given by the offset value for (i = 1; i <= n; i++) for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) if (cdp->GetOffset() == i) { if (q && pos < end)
*pos++= Qot;
// Find the offsets and lengths of the columns for this row for (i = 0; i < Fields; i++) { if (!bad) { if (Qot && *p2 == Qot) { // Quoted field //for (n = 0, p1 = ++p2; (p = strchr(p1, Qot)); p1 = p + 2) // if (*(p + 1) == Qot) // n++; // Doubled internal quotes // else // break; // Final quote
for (n = 0, p = ++p2; p; p++) if (*p == Qot || *p == '\\') { if (*(++p) == Qot)
n++; // Escaped internal quotes elseif (*(p - 1) == Qot) break; // Final quote
} // endif *p
if (p) { //len = p++ - p2;
len = (int)(p - p2 - 1);
// if (Sep != ' ') // for (; *p == ' '; p++) ; // Skip blanks
if (*p != Sep && i != Fields - 1) { // Should be the separator if (CheckErr()) {
snprintf(g->Message, sizeof(g->Message), MSG(MISSING_FIELD),
i+1, Name, RowNumber(g)); return RC_FX;
} elseif (Accept)
bad = true; else return RC_NF;
} // endif p
if (n) { int j, k;
// Suppress the escape of internal quotes for (j = k = 0; j < len; j++, k++) { if (p2[j] == Qot || (p2[j] == '\\' && p2[j + 1] == Qot))
j++; // skip escape char elseif (p2[j] == '\\')
p2[k++] = p2[j++]; // avoid \\Qot
/***********************************************************************/ /* Prepare the line to write. */ /***********************************************************************/ bool TDBCSV::PrepareWriting(PGLOBAL g)
{ char sep[2], qot[2]; int i, nlen, oldlen = strlen(To_Line);
// Before writing the line we must check its length if ((nlen = CheckWrite(g)) < 0) returntrue;
// Before writing the line we must make it
sep[0] = Sep;
sep[1] = '\0';
qot[0] = Qot;
qot[1] = '\0';
*To_Line = '\0';
for (i = 0; i < Fields; i++) { if (i)
safe_strcat(To_Line, Lrecl, sep);
if (Field[i]) { if (!strlen(Field[i])) { // Generally null fields are not quoted if (Quoted > 2) { // Except if explicitly required
safe_strcat(To_Line, Lrecl, qot);
safe_strcat(To_Line, Lrecl, qot);
}
} elseif (Qot && (strchr(Field[i], Sep) || *Field[i] == Qot
|| Quoted > 1 || (Quoted == 1 && !Fldtyp[i]))) { if (strchr(Field[i], Qot)) { // Field contains quotes that must be doubled int j, k = strlen(To_Line), n = strlen(Field[i]);
To_Line[k++] = Qot;
for (j = 0; j < n; j++) { if (Field[i][j] == Qot)
To_Line[k++] = Qot;
if (Mode == MODE_UPDATE && nlen < oldlen
&& !((PDOSFAM)Txfp)->GetUseTemp()) { // In Update mode with no temp file, line length must not change
To_Line[nlen] = Sep;
for (nlen++; nlen < oldlen; nlen++)
To_Line[nlen] = ' ';
To_Line[nlen] = '\0';
} // endif
if (trace(2))
htrc("Write: line is=%s", To_Line);
returnfalse;
} // end of PrepareWriting
/***********************************************************************/ /* Data Base write routine CSV file access method. */ /***********************************************************************/ int TDBCSV::WriteDB(PGLOBAL g)
{ // Before writing the line we must check and prepare it if (PrepareWriting(g)) return RC_FX;
/*********************************************************************/ /* Now start the writing process. */ /*********************************************************************/ return Txfp->WriteBuffer(g);
} // end of WriteDB
/***********************************************************************/ /* Check whether a new line fit in the file lrecl size. */ /***********************************************************************/ int TDBCSV::CheckWrite(PGLOBAL g)
{ int maxlen, n, nlen = (Fields - 1);
if (trace(2))
htrc("CheckWrite: R%d Mode=%d\n", Tdb_No, Mode);
// Before writing the line we must check its length
maxlen = (Mode == MODE_UPDATE && !Txfp->GetUseTemp())
? strlen(To_Line) : Lrecl;
// Check whether record is too int for (int i = 0; i < Fields; i++)
{ if (Field[i]) { if (!(n = strlen(Field[i])))
n += (Quoted > 2 ? 2 : 0); elseif (strchr(Field[i], Sep) || (Qot && *Field[i] == Qot)
|| Quoted > 1 || (Quoted == 1 && !Fldtyp[i]))
{ if (!Qot) {
snprintf(g->Message, sizeof(g->Message), MSG(SEP_IN_FIELD), i + 1); return -1;
} else { // Quotes inside a quoted field must be doubled char *p1, *p2;
/***********************************************************************/ /* FMT EstimatedLength. Returns an estimated minimum line length. */ /* The big problem here is how can we estimate that minimum ? */ /***********************************************************************/ int TDBFMT::EstimatedLength(void)
{ // This is rather stupid !!! return ((PDOSDEF)To_Def)->GetEnding() + (int)((Lrecl / 10) + 1);
} // end of EstimatedLength
if (Use != USE_OPEN && Columns) { // Make the formats used to read records
PSZ pfm; int i, n;
PCSVCOL colp;
PCOLDEF cdp;
PDOSDEF tdp = (PDOSDEF)To_Def;
for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next) if (!colp->IsSpecial() && !colp->IsVirtual()) // a true column
Fields = MY_MAX(Fields, (int)colp->Fldnum);
// Get the column formats for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) if (!cdp->IsSpecial() && !cdp->IsVirtual()
&& (i = cdp->GetOffset() - 1) < Fields) { if (!(pfm = cdp->GetFmt())) {
snprintf(g->Message, sizeof(g->Message), MSG(NO_FLD_FORMAT), i + 1, Name); returntrue;
} // endif pfm
// Roughly check the Fmt format if ((n = strlen(pfm) - 2) < 4) {
snprintf(g->Message, sizeof(g->Message), MSG(BAD_FLD_FORMAT), i + 1, Name); returntrue;
} // endif n
FldFormat[i] = (PSZ)PlugSubAlloc(g, NULL, n + 5);
safe_strcpy(FldFormat[i], n + 5, pfm);
if (!strcmp(pfm + n, "%m")) { // This is a field that can be missing. Flag it so it can // be handled with special processing.
FldFormat[i][n+1] = 'n'; // To have sscanf normal processing
FmtTest[i] = 2;
} elseif (i+1 < Fields && strcmp(pfm + n, "%n")) { // There are trailing characters after the field contents // add a marker for the next field start position.
safe_strcat(FldFormat[i], n + 5, "%n");
FmtTest[i] = 1;
} // endif's
} // endif i
} // endif Use
return TDBCSV::OpenDB(g);
} // end of OpenDB
/***********************************************************************/ /* ReadBuffer: Physical read routine for the FMT access method. */ /***********************************************************************/ int TDBFMT::ReadBuffer(PGLOBAL g)
{ int i, len, n, deb, fin, nwp, pos = 0, rc; bool bad = false;
if (trace(2))
htrc("FMT: Row %d is '%s' rc=%d\n", Linenum, To_Line, rc);
// Find the offsets and lengths of the columns for this row for (i = 0; i < Fields; i++) { if (!bad) {
deb = fin = -1;
if (!FldFormat[i]) {
n = 0;
} elseif (FmtTest[i] == 1) {
nwp = -1;
n = sscanf(To_Line + pos, FldFormat[i], &deb, To_Fld, &fin, &nwp);
} else {
n = sscanf(To_Line + pos, FldFormat[i], &deb, To_Fld, &fin);
if (n != 1 && (deb >= 0 || i == Fields - 1) && FmtTest[i] == 2) { // Missing optional field, not an error
n = 1;
if (i == Fields - 1)
fin = deb = 0; else
fin = deb;
} // endif n
nwp = fin;
} // endif i
if (n != 1 || deb < 0 || fin < 0 || nwp < 0) { // This is to avoid a very strange sscanf bug occuring // with fields that ends with a null character. // This bug causes subsequent sscanf to return in error, // so next lines are not parsed correctly.
sscanf("a", "%*c"); // Seems to reset things Ok
if (CheckErr()) {
snprintf(g->Message, sizeof(g->Message), MSG(BAD_LINEFLD_FMT), Linenum, i + 1, Name); return RC_FX;
} elseif (Accept)
bad = true; else return RC_NF;
} // endif n...
} // endif !bad
if (!bad) {
Offset[i] = pos + deb;
len = fin - deb;
} else {
nwp = 0;
Offset[i] = pos;
len = 0;
} // endif bad
/***********************************************************************/ /* CSVCOL public constructor */ /***********************************************************************/
CSVCOL::CSVCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
: DOSCOL(g, cdp, tdbp, cprec, i, "CSV")
{
Fldnum = Deplac - 1;
Deplac = 0;
} // end of CSVCOL constructor
/***********************************************************************/ /* CSVCOL constructor used for copying columns. */ /* tdbp is the pointer to the new table descriptor. */ /***********************************************************************/
CSVCOL::CSVCOL(CSVCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
{
Fldnum = col1->Fldnum;
} // end of CSVCOL copy constructor
/***********************************************************************/ /* VarSize: This function tells UpdateDB whether or not the block */ /* optimization file must be redone if this column is updated, even */ /* it is not sorted or clustered. This applies to a blocked table, */ /* because if it is updated using a temporary file, the block size */ /* may be modified. */ /***********************************************************************/ bool CSVCOL::VarSize(void)
{
PTXF txfp = ((PTDBCSV)To_Tdb)->Txfp;
if (txfp->IsBlocked() && txfp->GetUseTemp()) // Blocked table using a temporary file returntrue; else returnfalse;
} // end VarSize
/***********************************************************************/ /* ReadColumn: call DOSCOL::ReadColumn after having set the offet */ /* and length of the field to read as calculated by TDBCSV::ReadDB. */ /***********************************************************************/ void CSVCOL::ReadColumn(PGLOBAL g)
{ int rc;
PTDBCSV tdbp = (PTDBCSV)To_Tdb;
/*********************************************************************/ /* If physical reading of the line was deferred, do it now. */ /*********************************************************************/ if (!tdbp->IsRead()) if ((rc = tdbp->ReadBuffer(g)) != RC_OK) { if (rc == RC_EF)
snprintf(g->Message, sizeof(g->Message), MSG(INV_DEF_READ), rc);
throw34;
} // endif
if (tdbp->Mode != MODE_UPDATE) { int colen = Long; // Column length
// Set the field offset and length for this row
Deplac = tdbp->Offset[Fldnum]; // Field offset Long = tdbp->Fldlen[Fldnum]; // Field length
if (Long > colen && tdbp->CheckErr()) { Long = colen; // Restore column length
snprintf(g->Message, sizeof(g->Message), MSG(FLD_TOO_LNG_FOR),
Fldnum + 1, Name, To_Tdb->RowNumber(g), tdbp->GetFile(g)); throw34;
} // endif Long
// Now do the reading
DOSCOL::ReadColumn(g);
// Restore column length Long = colen;
} else { // Mode Update // Field have been copied in TDB Field array
PSZ fp = tdbp->Field[Fldnum];
if (Dsp) for (int i = 0; fp[i]; i++) if (fp[i] == Dsp)
fp[i] = '.';
Value->SetValue_psz(fp);
// Set null when applicable if (Nullable)
Value->SetNull(Value->IsZero());
} // endif Mode
} // end of ReadColumn
/***********************************************************************/ /* WriteColumn: The column is written in TDBCSV matching Field. */ /***********************************************************************/ void CSVCOL::WriteColumn(PGLOBAL g)
{ char *p; int n, flen;
PTDBCSV tdbp = (PTDBCSV)To_Tdb;
if (trace(2))
htrc("CSV WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
Name, tdbp->GetTdb_No(), ColUse, Status);
/*********************************************************************/ /* Check whether the new value has to be converted to Buf_Type. */ /*********************************************************************/ if (Value != To_Val)
Value->SetValue_pval(To_Val, false); // Convert the updated value
/*********************************************************************/ /* Get the string representation of the column value. */ /*********************************************************************/
p = Value->GetCharString(Buf);
n = strlen(p);
if (trace(2))
htrc("new length(%p)=%d\n", p, n);
if (n > flen) {
snprintf(g->Message, sizeof(g->Message), MSG(BAD_FLD_LENGTH), Name, p, n,
tdbp->RowNumber(g), tdbp->GetFile(g)); throw34;
} elseif (Dsp) for (int i = 0; p[i]; i++) if (p[i] == '.')
p[i] = Dsp;
if (trace(2))
htrc("buffer=%s\n", p);
/*********************************************************************/ /* Updating must be done also during the first pass so writing the */ /* updated record can be checked for acceptable record length. */ /*********************************************************************/ if (Fldnum < 0) { // This can happen for wrong offset value in XDB files
snprintf(g->Message, sizeof(g->Message), MSG(BAD_FIELD_RANK), Fldnum + 1, Name); throw34;
} else
strncpy(tdbp->Field[Fldnum], p, flen);
if (trace(2))
htrc(" col written: '%s'\n", p);
} // end of WriteColumn
/* ---------------------------TDBCCL class --------------------------- */
/***********************************************************************/ /* TDBCCL class constructor. */ /***********************************************************************/
TDBCCL::TDBCCL(PCSVDEF tdp) : TDBCAT(tdp)
{
Topt = tdp->GetTopt();
} // end of TDBCCL constructor
/***********************************************************************/ /* GetResult: Get the list the CSV file columns. */ /***********************************************************************/
PQRYRES TDBCCL::GetResult(PGLOBAL g)
{ return CSVColumns(g, ((PTABDEF)To_Def)->GetPath(), Topt, false);
} // end of GetResult
/* ------------------------ End of TabFmt ---------------------------- */
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.22Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.