bool TDBPIVOT::FindDefaultColumns(PGLOBAL g) { PCOLDEF cdp; PTABDEF defp = Tdbp->GetDef(); if (!Fncol) { for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext()) if (!Picol || stricmp(Picol, cdp->GetName())) Fncol = cdp->GetName(); if (!Fncol) { strcpy(g->Message, MSG(NO_DEF_FNCCOL)); return true; } // endif Fncol } // endif Fncol if (!Picol) { // Find default Picol as the last one not equal to Fncol for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext()) if (stricmp(Fncol, cdp->GetName())) Picol = cdp->GetName(); if (!Picol) { strcpy(g->Message, MSG(NO_DEF_PIVOTCOL)); return true; } // endif Picol } // endif Picol return false; } // end of FindDefaultColumns
PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num) { int i; PCOLDEF cdp; PCOL cp, colp = NULL, cprec = NULL; if (trace) htrc("ColDB: am=%d colname=%s tabname=%s num=%d\n", GetAmType(), SVP(name), Name, num); for (cdp = To_Def->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++) if ((!name && !num) || (name && !stricmp(cdp->GetName(), name)) || num == i) { /*****************************************************************/ /* Check for existence of desired column. */ /* Also find where to insert the new block. */ /*****************************************************************/ for (cp = Columns; cp; cp = cp->GetNext()) if ((num && cp->GetIndex() == i) || (name && !stricmp(cp->GetName(), name))) break; // Found else if (cp->GetIndex() < i) cprec = cp; if (trace) htrc("cdp(%d).Name=%s cp=%p\n", i, cdp->GetName(), cp); /*****************************************************************/ /* Now take care of Column Description Block. */ /*****************************************************************/ if (cp) colp = cp; else if (!(cdp->Flags & U_SPECIAL)) colp = MakeCol(g, cdp, cprec, i); else if (Mode != MODE_INSERT) colp = InsertSpcBlk(g, cdp); if (trace) htrc("colp=%p\n", colp); if (name || num) break; else if (colp && !colp->IsSpecial()) cprec = colp; } // endif Name return (colp); } // end of ColDB
bool TDBASE::IsSpecial(PSZ name) { for (PCOLDEF cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) if (!stricmp(cdp->GetName(), name) && (cdp->Flags & U_SPECIAL)) return true; // Special column to ignore while inserting return false; // Not found or not special or not inserting } // end of IsSpecial
PCOL TDBASE::InsertSpcBlk(PGLOBAL g, PCOLDEF cdp) { //char *name = cdp->GetName(); char *name = cdp->GetFmt(); PCOLUMN cp; PCOL colp; cp= new(g) COLUMN(cdp->GetName()); if (! To_Table) { strcpy(g->Message, "Cannot make special column: To_Table is NULL"); return NULL; } else cp->SetTo_Table(To_Table); if (!stricmp(name, "FILEID") || !stricmp(name, "FDISK") || !stricmp(name, "FPATH") || !stricmp(name, "FNAME") || !stricmp(name, "FTYPE") || !stricmp(name, "SERVID")) { if (!To_Def || !(To_Def->GetPseudo() & 2)) { sprintf(g->Message, MSG(BAD_SPEC_COLUMN)); return NULL; } // endif Pseudo if (!stricmp(name, "FILEID")) colp = new(g) FIDBLK(cp, OP_XX); else if (!stricmp(name, "FDISK")) colp = new(g) FIDBLK(cp, OP_FDISK); else if (!stricmp(name, "FPATH")) colp = new(g) FIDBLK(cp, OP_FPATH); else if (!stricmp(name, "FNAME")) colp = new(g) FIDBLK(cp, OP_FNAME); else if (!stricmp(name, "FTYPE")) colp = new(g) FIDBLK(cp, OP_FTYPE); else colp = new(g) SIDBLK(cp); } else if (!stricmp(name, "TABID")) { colp = new(g) TIDBLK(cp); } else if (!stricmp(name, "PARTID")) { colp = new(g) PRTBLK(cp); //} else if (!stricmp(name, "CONID")) { // colp = new(g) CIDBLK(cp); } else if (!stricmp(name, "ROWID")) { colp = new(g) RIDBLK(cp, false); } else if (!stricmp(name, "ROWNUM")) { colp = new(g) RIDBLK(cp, true); } else { sprintf(g->Message, MSG(BAD_SPECIAL_COL), name); return NULL; } // endif's name if (!(colp = InsertSpecialColumn(colp))) { sprintf(g->Message, MSG(BAD_SPECIAL_COL), name); return NULL; } // endif Insert return (colp); } // end of InsertSpcBlk
PCOL TDBXCL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) { PCOL colp; if (!stricmp(cdp->GetName(), Xcolumn)) { Xcolp = new(g) XCLCOL(g, cdp, this, cprec, n); colp = Xcolp; } else colp = new(g) PRXCOL(cdp, this, cprec, n); return colp; } // end of MakeCol
PCOL TDBOCCUR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) { PCOL colp = NULL; if (!stricmp(cdp->GetName(), Rcolumn)) { // Allocate a RANK column colp = new(g) RANKCOL(cdp, this, n); } else if (!stricmp(cdp->GetName(), Xcolumn)) { // Allocate the OCCUR column colp = Xcolp = new(g) OCCURCOL(cdp, this, n); } else return new(g) PRXCOL(cdp, this, cprec, n); if (cprec) { colp->SetNext(cprec->GetNext()); cprec->SetNext(colp); } else { colp->SetNext(Columns); Columns = colp; } // endif cprec return colp; } // end of MakeCol
bool TDBPIVOT::GetSourceTable(PGLOBAL g) { if (Tdbp) return false; // Already done if (!Tabsrc && Tabname) { // Get the table description block of this table if (!(Tdbp = GetSubTable(g, ((PPIVOTDEF)To_Def)->Tablep, true))) return true; if (!GBdone) { char *colist; PCOLDEF cdp; if (FindDefaultColumns(g)) return true; // Locate the suballocated colist (size is not known yet) *(colist = (char*)PlugSubAlloc(g, NULL, 0)) = 0; // Make the column list for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) if (!cdp->GetOffset()) strcat(strcat(colist, cdp->GetName()), ", "); // Add the Pivot column at the end of the list strcat(colist, Picol); // Now we know how much was suballocated PlugSubAlloc(g, NULL, strlen(colist) + 1); // Locate the source string (size is not known yet) Tabsrc = (char*)PlugSubAlloc(g, NULL, 0); // Start making the definition strcat(strcat(strcpy(Tabsrc, "SELECT "), colist), ", "); // Make it suitable for Pivot by doing the group by strcat(strcat(Tabsrc, Function), "("); strcat(strcat(strcat(Tabsrc, Fncol), ") "), Fncol); strcat(strcat(Tabsrc, " FROM "), Tabname); strcat(strcat(Tabsrc, " GROUP BY "), colist); if (Tdbp->IsView()) // Until MariaDB bug is fixed strcat(strcat(Tabsrc, " ORDER BY "), colist); // Now we know how much was suballocated PlugSubAlloc(g, NULL, strlen(Tabsrc) + 1); } // endif !GBdone } else if (!Tabsrc) { strcpy(g->Message, MSG(SRC_TABLE_UNDEF)); return true; } // endif if (Tabsrc) { // Get the new table description block of this source table PTABLE tablep = new(g) XTAB("whatever", Tabsrc); tablep->SetQualifier(Database); if (!(Tdbp = GetSubTable(g, tablep, true))) return true; } // endif Tabsrc return false; } // end of GetSourceTable
bool TDBCSV::SkipHeader(PGLOBAL g) { int len = GetFileLength(g); bool rc = false; #if defined(_DEBUG) if (len < 0) return true; #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; // 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 if (hlen > Lrecl) { sprintf(g->Message, MSG(LRECL_TOO_SMALL), hlen); return true; } // endif hlen // File is empty, write a header record memset(To_Line, 0, Lrecl); // 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) To_Line[strlen(To_Line)] = Qot; strcat(To_Line, cdp->GetName()); if (q) To_Line[strlen(To_Line)] = Qot; if (i < n) To_Line[strlen(To_Line)] = Sep; } // endif Offset rc = (Txfp->WriteBuffer(g) == RC_FX); } // endif !FileLength } else if (Mode == MODE_DELETE) { if (len) rc = (Txfp->SkipRecord(g, true) == RC_FX); } else if (len) // !Insert && !Delete rc = (Txfp->SkipRecord(g, false) == RC_FX || Txfp->RecordPos(g)); } // endif Header return rc; } // end of SkipHeader
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->IsVirtual()) Fields++; Offset = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields); Fldlen = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields); if (Mode == MODE_INSERT || Mode == MODE_UPDATE) { Field = (PSZ*)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields); Fldtyp = (bool*)PlugSubAlloc(g, NULL, sizeof(bool) * Fields); } // endif Mode for (i = 0; i < Fields; i++) { Offset[i] = 0; Fldlen[i] = 0; if (Field) { Field[i] = NULL; Fldtyp[i] = false; } // endif Field } // endfor i if (Field) // Prepare writing fields if (Mode != MODE_UPDATE) { for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next) if (!colp->IsSpecial() && !colp->IsVirtual()) { i = colp->Fldnum; len = colp->GetLength(); Field[i] = (PSZ)PlugSubAlloc(g, NULL, len + 1); Field[i][len] = '\0'; Fldlen[i] = len; Fldtyp[i] = IsTypeNum(colp->GetResultType()); } // endif colp } else // MODE_UPDATE for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) if (!cdp->IsVirtual()) { i = cdp->GetOffset() - 1; len = cdp->GetLength(); Field[i] = (PSZ)PlugSubAlloc(g, NULL, len + 1); Field[i][len] = '\0'; Fldlen[i] = len; Fldtyp[i] = IsTypeNum(cdp->GetType()); } // endif cdp } // endif Use if (Header) { // Check that the Lrecl is at least equal to the header line length int headlen = 0; PCOLDEF cdp; PDOSDEF tdp = (PDOSDEF)To_Def; for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) headlen += strlen(cdp->GetName()) + 3; // 3 if names are quoted if (headlen > Lrecl) { Lrecl = headlen; Txfp->Lrecl = headlen; } // endif headlen } // endif Header Nerr = 0; rc = TDBDOS::OpenDB(g); 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
bool DBFFAM::AllocateBuffer(PGLOBAL g) { char c; int rc; MODE mode = Tdbp->GetMode(); Buflen = Blksize; To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen); if (mode == MODE_INSERT) { #if defined(WIN32) /************************************************************************/ /* Now we can revert to binary mode in particular because the eventual */ /* writing of a new header must be done in binary mode to avoid */ /* translating 0A bytes (LF) into 0D0A (CRLF) by Windows in text mode. */ /************************************************************************/ if (_setmode(_fileno(Stream), _O_BINARY) == -1) { sprintf(g->Message, MSG(BIN_MODE_FAIL), strerror(errno)); return true; } // endif setmode #endif // WIN32 /************************************************************************/ /* If this is a new file, the header must be generated. */ /************************************************************************/ int len = GetFileLength(g); if (!len) { // Make the header for this DBF table file struct tm *datm; int hlen, n = 0; ushort reclen = 1; time_t t; DBFHEADER *header; DESCRIPTOR *descp; PCOLDEF cdp; PDOSDEF tdp = (PDOSDEF)Tdbp->GetDef(); // Count the number of columns for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) if (!(cdp->Flags & U_SPECIAL)) { reclen += cdp->GetLong(); n++; } // endif Flags if (Lrecl != reclen) { sprintf(g->Message, MSG(BAD_LRECL), Lrecl, reclen); return true; } // endif Lrecl hlen = HEADLEN * (n + 1) + 2; header = (DBFHEADER*)PlugSubAlloc(g, NULL, hlen); memset(header, 0, hlen); header->Version = DBFTYPE; t = time(NULL) - (time_t)DTVAL::GetShift(); datm = gmtime(&t); header->Filedate[0] = datm->tm_year - 100; header->Filedate[1] = datm->tm_mon + 1; header->Filedate[2] = datm->tm_mday; header->Headlen = (ushort)hlen; header->Reclen = (ushort)reclen; descp = (DESCRIPTOR*)header; // Currently only standard Xbase types are supported for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext()) if (!(cdp->Flags & U_SPECIAL)) { descp++; switch ((c = *GetFormatType(cdp->GetType()))) { case 'S': // Short integer case 'L': // Large (big) integer case 'T': // Tiny integer c = 'N'; // Numeric case 'N': // Numeric (integer) case 'F': // Float (double) descp->Decimals = (uchar)cdp->F.Prec; case 'C': // Char case 'D': // Date break; default: // Should never happen sprintf(g->Message, "Unsupported DBF type %c for column %s", c, cdp->GetName()); return true; } // endswitch c strncpy(descp->Name, cdp->GetName(), 11); descp->Type = c; descp->Length = (uchar)cdp->GetLong(); } // endif Flags *(char*)(++descp) = EOH; // Now write the header if (fwrite(header, 1, hlen, Stream) != (unsigned)hlen) { sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno)); return true; } // endif fwrite Records = 0; Headlen = hlen; } else if (len < 0) return true; // Error in GetFileLength /************************************************************************/ /* For Insert the buffer must be prepared. */ /************************************************************************/ memset(To_Buf, ' ', Buflen); Rbuf = Nrec; // To be used by WriteDB } else if (UseTemp) { // Allocate a separate buffer so block reading can be kept Dbflen = Nrec; DelBuf = PlugSubAlloc(g, NULL, Blksize); } // endif's if (!Headlen) { /************************************************************************/ /* Here is a good place to process the DBF file header */ /************************************************************************/ DBFHEADER header; if ((rc = dbfhead(g, Stream, Tdbp->GetFile(g), &header)) == RC_OK) { if (Lrecl != (int)header.Reclen) { sprintf(g->Message, MSG(BAD_LRECL), Lrecl, header.Reclen); return true; } // endif Lrecl Records = (int)header.Records; Headlen = (int)header.Headlen; } else if (rc == RC_NF) { Records = 0; Headlen = 0; } else // RC_FX return true; // Error in dbfhead } // endif Headlen /**************************************************************************/ /* Position the file at the begining of the data. */ /**************************************************************************/ if (Tdbp->GetMode() == MODE_INSERT) rc = fseek(Stream, 0, SEEK_END); else rc = fseek(Stream, Headlen, SEEK_SET); if (rc) { sprintf(g->Message, MSG(BAD_DBF_FILE), Tdbp->GetFile(g)); return true; } // endif fseek return false; } // end of AllocateBuffer