summaryrefslogtreecommitdiffstats
path: root/storage/connect/tabext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/connect/tabext.cpp')
-rw-r--r--storage/connect/tabext.cpp720
1 files changed, 720 insertions, 0 deletions
diff --git a/storage/connect/tabext.cpp b/storage/connect/tabext.cpp
new file mode 100644
index 00000000..212d27f0
--- /dev/null
+++ b/storage/connect/tabext.cpp
@@ -0,0 +1,720 @@
+/************* Tabext C++ Functions Source Code File (.CPP) ************/
+/* Name: TABEXT.CPP Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2019 */
+/* */
+/* This file contains the TBX, TDB and OPJOIN classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#define MYSQL_SERVER 1
+#include "my_global.h"
+#include "sql_class.h"
+#include "sql_servers.h"
+#include "sql_string.h"
+#if !defined(_WIN32)
+#include "osutil.h"
+#endif
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/* xobject.h is header containing XOBJECT derived classes declares. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "ha_connect.h"
+
+/* -------------------------- Class CONDFIL -------------------------- */
+
+/***********************************************************************/
+/* CONDFIL Constructor. */
+/***********************************************************************/
+CONDFIL::CONDFIL(uint idx, AMT type)
+{
+//Cond = cond;
+ Idx = idx;
+ Type = type;
+ Op = OP_XX;
+ Cmds = NULL;
+ Alist = NULL;
+ All = true;
+ Bd = false;
+ Hv = false;
+ Body = NULL,
+ Having = NULL;
+} // end of CONDFIL constructor
+
+/***********************************************************************/
+/* Make and allocate the alias list. */
+/***********************************************************************/
+int CONDFIL::Init(PGLOBAL g, PHC hc)
+{
+ PTOS options = hc->GetTableOptionStruct();
+ char *p, *cn, *cal, *alt = NULL;
+ int rc = RC_OK;
+ bool h;
+
+ if (options)
+ alt = (char*)GetListOption(g, "Alias", options->oplist, NULL);
+
+ while (alt) {
+ if (!(p = strchr(alt, '='))) {
+ strcpy(g->Message, "Invalid alias list");
+ rc = RC_FX;
+ break;
+ } // endif !p
+
+ cal = alt; // Alias
+ *p++ = 0;
+
+ if ((h = *p == '*')) {
+ rc = RC_INFO;
+ p++;
+ } // endif h
+
+ cn = p; // Remote column name
+
+ if ((alt = strchr(p, ';')))
+ *alt++ = 0;
+
+ if (*cn == 0)
+ cn = alt;
+
+ Alist = new(g) ALIAS(Alist, cn, cal, h);
+ } // endwhile alt
+
+ return rc;
+} // end of Init
+
+/***********************************************************************/
+/* Make and allocate the alias list. */
+/***********************************************************************/
+const char *CONDFIL::Chk(const char *fln, bool *h)
+{
+ for (PAL pal = Alist; pal; pal = pal->Next)
+ if (!stricmp(fln, pal->Alias)) {
+ *h = pal->Having;
+ return pal->Name;
+ } // endif fln
+
+ *h = false;
+ return fln;
+} // end of Chk
+
+/* --------------------------- Class EXTDEF -------------------------- */
+
+/***********************************************************************/
+/* EXTDEF Constructor. */
+/***********************************************************************/
+EXTDEF::EXTDEF(void)
+{
+ Tabname = Tabschema = Username = Password = Tabcat = Tabtyp = NULL;
+ Colpat = Srcdef = Qchar = Qrystr = Sep = Phpos = NULL;
+ Options = Cto = Qto = Quoted = Maxerr = Maxres = Memory = 0;
+ Scrollable = Xsrc = false;
+} // end of EXTDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool EXTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+ if (g->Createas) {
+ strcpy(g->Message,
+ "Multiple-table UPDATE/DELETE commands are not supported");
+ return true;
+ } // endif multi
+
+ Desc = NULL;
+ Tabname = GetStringCatInfo(g, "Name",
+ (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
+ Tabname = GetStringCatInfo(g, "Tabname", Tabname);
+ Tabschema = GetStringCatInfo(g, "Dbname", NULL);
+ Tabschema = GetStringCatInfo(g, "Schema", Tabschema);
+ Tabcat = GetStringCatInfo(g, "Qualifier", NULL);
+ Tabcat = GetStringCatInfo(g, "Catalog", Tabcat);
+ Username = GetStringCatInfo(g, "User", NULL);
+ Password = GetStringCatInfo(g, "Password", NULL);
+
+ if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL)))
+ Read_Only = true;
+
+ Qrystr = GetStringCatInfo(g, "Query_String", "?");
+ Sep = GetStringCatInfo(g, "Separator", NULL);
+//Alias = GetStringCatInfo(g, "Alias", NULL);
+ Phpos = GetStringCatInfo(g, "Phpos", NULL);
+ Xsrc = GetBoolCatInfo("Execsrc", FALSE);
+ Maxerr = GetIntCatInfo("Maxerr", 0);
+ Maxres = GetIntCatInfo("Maxres", 0);
+ Quoted = GetIntCatInfo("Quoted", 0);
+ Options = 0;
+ Cto = 0;
+ Qto = 0;
+
+ if ((Scrollable = GetBoolCatInfo("Scrollable", false)) && !Elemt)
+ Elemt = 1; // Cannot merge SQLFetch and SQLExtendedFetch
+
+ if (Catfunc == FNC_COL)
+ Colpat = GetStringCatInfo(g, "Colpat", NULL);
+
+ if (Catfunc == FNC_TABLE)
+ Tabtyp = GetStringCatInfo(g, "Tabtype", NULL);
+
+ // Memory was Boolean, it is now integer
+ if (!(Memory = GetIntCatInfo("Memory", 0)))
+ Memory = GetBoolCatInfo("Memory", false) ? 1 : 0;
+
+ Pseudo = 2; // FILID is Ok but not ROWID
+ return false;
+} // end of DefineAM
+
+/* ---------------------------TDBEXT class --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBEXT class. */
+/***********************************************************************/
+TDBEXT::TDBEXT(EXTDEF *tdp) : TDB(tdp)
+{
+ Qrp = NULL;
+
+ if (tdp) {
+ TableName = tdp->Tabname;
+ Schema = tdp->Tabschema;
+ User = tdp->Username;
+ Pwd = tdp->Password;
+ Catalog = tdp->Tabcat;
+ Srcdef = tdp->Srcdef;
+ Qrystr = tdp->Qrystr;
+ Sep = tdp->GetSep();
+ Options = tdp->Options;
+ Cto = tdp->Cto;
+ Qto = tdp->Qto;
+ Quoted = MY_MAX(0, tdp->GetQuoted());
+ Rows = tdp->GetElemt();
+ Memory = tdp->Memory;
+ Scrollable = tdp->Scrollable;
+ } else {
+ TableName = NULL;
+ Schema = NULL;
+ User = NULL;
+ Pwd = NULL;
+ Catalog = NULL;
+ Srcdef = NULL;
+ Qrystr = NULL;
+ Sep = 0;
+ Options = 0;
+ Cto = 0;
+ Qto = 0;
+ Quoted = 0;
+ Rows = 0;
+ Memory = 0;
+ Scrollable = false;
+ } // endif tdp
+
+ Quote = NULL;
+ Query = NULL;
+ Count = NULL;
+ //Where = NULL;
+ MulConn = NULL;
+ DBQ = NULL;
+ Qrp = NULL;
+ Fpos = 0;
+ Curpos = 0;
+ AftRows = 0;
+ CurNum = 0;
+ Rbuf = 0;
+ BufSize = 0;
+ Nparm = 0;
+ Ncol = 0;
+ Placed = false;
+} // end of TDBEXT constructor
+
+TDBEXT::TDBEXT(PTDBEXT tdbp) : TDB(tdbp)
+{
+ Qrp = tdbp->Qrp;
+ TableName = tdbp->TableName;
+ Schema = tdbp->Schema;
+ User = tdbp->User;
+ Pwd = tdbp->Pwd;
+ Catalog = tdbp->Catalog;
+ Srcdef = tdbp->Srcdef;
+ Qrystr = tdbp->Qrystr;
+ Sep = tdbp->Sep;
+ Options = tdbp->Options;
+ Cto = tdbp->Cto;
+ Qto = tdbp->Qto;
+ Quoted = tdbp->Quoted;
+ Rows = tdbp->Rows;
+ Memory = tdbp->Memory;
+ Scrollable = tdbp->Scrollable;
+ Quote = tdbp->Quote;
+ Query = tdbp->Query;
+ Count = tdbp->Count;
+ //Where = tdbp->Where;
+ MulConn = tdbp->MulConn;
+ DBQ = tdbp->DBQ;
+ Fpos = 0;
+ Curpos = 0;
+ AftRows = 0;
+ CurNum = 0;
+ Rbuf = 0;
+ BufSize = tdbp->BufSize;
+ Nparm = tdbp->Nparm;
+ Ncol = tdbp->Ncol;
+ Placed = false;
+} // end of TDBEXT copy constructor
+
+/******************************************************************/
+/* Convert an UTF-8 string to latin characters. */
+/******************************************************************/
+int TDBEXT::Decode(PCSZ txt, char *buf, size_t n)
+{
+ uint dummy_errors;
+ uint32 len = copy_and_convert(buf, n, &my_charset_latin1,
+ txt, strlen(txt),
+ &my_charset_utf8mb3_general_ci,
+ &dummy_errors);
+ buf[len] = '\0';
+ return 0;
+} // end of Decode
+
+/***********************************************************************/
+/* MakeSrcdef: make the SQL statement from SRDEF option. */
+/***********************************************************************/
+bool TDBEXT::MakeSrcdef(PGLOBAL g)
+{
+ char *catp = strstr(Srcdef, "%s");
+
+ if (catp) {
+ char *fil1 = 0, *fil2;
+ PCSZ ph = ((EXTDEF*)To_Def)->Phpos;
+
+ if (!ph)
+ ph = (strstr(catp + 2, "%s")) ? "WH" : "W";
+
+ if (stricmp(ph, "H")) {
+ fil1 = (To_CondFil && *To_CondFil->Body)
+ ? To_CondFil->Body : PlugDup(g, "1=1");
+ } // endif ph
+
+ if (stricmp(ph, "W")) {
+ fil2 = (To_CondFil && To_CondFil->Having && *To_CondFil->Having)
+ ? To_CondFil->Having : PlugDup(g, "1=1");
+ } // endif ph
+
+ if (!stricmp(ph, "W")) {
+ Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1));
+ Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1));
+ } else if (!stricmp(ph, "WH")) {
+ Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
+ Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1, fil2));
+ } else if (!stricmp(ph, "H")) {
+ Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil2));
+ Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2));
+ } else if (!stricmp(ph, "HW")) {
+ Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
+ Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2, fil1));
+ } else {
+ strcpy(g->Message, "MakeSQL: Wrong place holders specification");
+ return true;
+ } // endif's ph
+
+ } else
+ Query = new(g)STRING(g, 0, Srcdef);
+
+ return false;
+} // end of MakeSrcdef
+
+ /***********************************************************************/
+ /* MakeSQL: make the SQL statement use with remote connection. */
+ /* TODO: when implementing remote filtering, column only used in */
+ /* local filter should be removed from column list. */
+ /***********************************************************************/
+bool TDBEXT::MakeSQL(PGLOBAL g, bool cnt)
+{
+ PCSZ schmp = NULL;
+ char *catp = NULL, buf[NAM_LEN * 3];
+ int len;
+ bool first = true;
+ PCOL colp;
+
+ if (Srcdef)
+ return MakeSrcdef(g);
+
+ // Allocate the string used to contain the Query
+ Query = new(g)STRING(g, 1023, "SELECT ");
+
+ if (!cnt) {
+ if (Columns) {
+ // Normal SQL statement to retrieve results
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (!colp->IsSpecial()) {
+ if (!first)
+ Query->Append(", ");
+ else
+ first = false;
+
+ // Column name can be encoded in UTF-8
+ Decode(colp->GetName(), buf, sizeof(buf));
+
+ if (Quote) {
+ // Put column name between identifier quotes in case in contains blanks
+ Query->Append(Quote);
+ Query->Append(buf);
+ Query->Append(Quote);
+ } else
+ Query->Append(buf);
+
+ ((PEXTCOL)colp)->SetRank(++Ncol);
+ } // endif colp
+
+ } else
+ // !Columns can occur for queries such that sql count(*) from...
+ // for which we will count the rows from sql * from...
+ Query->Append('*');
+
+ } else
+ // SQL statement used to retrieve the size of the result
+ Query->Append("count(*)");
+
+ Query->Append(" FROM ");
+
+ if (Catalog && *Catalog)
+ catp = Catalog;
+
+ //if (tablep->GetSchema())
+ // schmp = (char*)tablep->GetSchema();
+ //else
+ if (Schema && *Schema)
+ schmp = Schema;
+
+ if (catp) {
+ Query->Append(catp);
+
+ if (schmp) {
+ Query->Append('.');
+ Query->Append(schmp);
+ } // endif schmp
+
+ Query->Append('.');
+ } else if (schmp) {
+ Query->Append(schmp);
+ Query->Append('.');
+ } // endif schmp
+
+ // Table name can be encoded in UTF-8
+ Decode(TableName, buf, sizeof(buf));
+
+ if (Quote) {
+ // Put table name between identifier quotes in case in contains blanks
+ Query->Append(Quote);
+ Query->Append(buf);
+ Query->Append(Quote);
+ } else
+ Query->Append(buf);
+
+ len = Query->GetLength();
+
+ if (To_CondFil) {
+ if (Mode == MODE_READ) {
+ Query->Append(" WHERE ");
+ Query->Append(To_CondFil->Body);
+ len = Query->GetLength() + 1;
+ } else
+ len += (strlen(To_CondFil->Body) + 256);
+
+ } else
+ len += ((Mode == MODE_READX) ? 256 : 1);
+
+ if (Query->IsTruncated()) {
+ strcpy(g->Message, "MakeSQL: Out of memory");
+ return true;
+ } else
+ Query->Resize(len);
+
+ if (trace(33))
+ htrc("Query=%s\n", Query->GetStr());
+
+ return false;
+} // end of MakeSQL
+
+/***********************************************************************/
+/* Remove the NAME_CONST functions that are added by procedures. */
+/***********************************************************************/
+void TDBEXT::RemoveConst(PGLOBAL g, char *stmt)
+{
+ char *p, *p2;
+ char val[1025], nval[1025];
+ int n, nc;
+
+ while ((p = strstr(stmt, "NAME_CONST")))
+ {
+ if ((n = sscanf(p, "%*[^,],%1024[^)])%n", val, &nc))) {
+ if (trace(33))
+ htrc("p=%s\nn=%d val=%s nc=%d\n", p, n, val, nc);
+
+ *p = 0;
+
+ if ((p2 = strstr(val, "'"))) {
+ if ((n = sscanf(p2, "%*['\\]%1024[^'\\]", nval))) {
+ if (trace(33))
+ htrc("p2=%s\nn=%d nval=%s\n", p2, n, nval);
+
+ strcat(strcat(strcat(strcat(stmt, "'"), nval), "'"), p + nc);
+ } else
+ break;
+
+ } else
+ strcat(strcat(strcat(strcat(stmt, "("), val), ")"), p + nc);
+
+ if (trace(33))
+ htrc("stmt=%s\n", stmt);
+
+ } else
+ break;
+ }
+ return;
+} // end of RemoveConst
+
+/***********************************************************************/
+/* MakeCommand: make the Update or Delete statement to send to the */
+/* MySQL server. Limited to remote values and filtering. */
+/***********************************************************************/
+bool TDBEXT::MakeCommand(PGLOBAL g)
+{
+ PCSZ schmp = NULL;
+ char *p, *stmt, name[132], *body = NULL;
+ char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
+ bool qtd = Quoted > 0;
+ char q = qtd ? *Quote : ' ';
+ int i = 0, k = 0;
+
+ // Make a lower case copy of the originale query and change
+ // back ticks to the data source identifier quoting character
+ do {
+ qrystr[i] = (Qrystr[i] == '`') ? q : tolower(Qrystr[i]);
+ } while (Qrystr[i++]);
+
+ if (To_CondFil && (p = strstr(qrystr, " where "))) {
+ p[7] = 0; // Remove where clause
+ Qrystr[(p - qrystr) + 7] = 0;
+ body = To_CondFil->Body;
+ stmt = (char*)PlugSubAlloc(g, NULL, strlen(qrystr)
+ + strlen(body) + 64);
+ } else
+ stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+
+ // Check whether the table name is equal to a keyword
+ // If so, it must be quoted in the original query
+ strlwr(strcat(strcat(strcpy(name, " "), Name), " "));
+
+ if (strstr(" update delete low_priority ignore quick from ", name)) {
+ if (Quote) {
+ strlwr(strcat(strcat(strcpy(name, Quote), Name), Quote));
+ k += 2;
+ } else {
+ strcpy(g->Message, "Quoted must be specified");
+ return true;
+ } // endif Quote
+
+ } else
+ strlwr(strcpy(name, Name)); // Not a keyword
+
+ if ((p = strstr(qrystr, name))) {
+ for (i = 0; i < p - qrystr; i++)
+ stmt[i] = (Qrystr[i] == '`') ? q : Qrystr[i];
+
+ stmt[i] = 0;
+
+ k += i + (int)strlen(Name);
+
+ if (Schema && *Schema)
+ schmp = Schema;
+
+ if (qtd && *(p - 1) == ' ') {
+ if (schmp)
+ strcat(strcat(stmt, schmp), ".");
+
+ strcat(strcat(strcat(stmt, Quote), TableName), Quote);
+ } else {
+ if (schmp) {
+ if (qtd && *(p - 1) != ' ') {
+ stmt[i - 1] = 0;
+ strcat(strcat(strcat(stmt, schmp), "."), Quote);
+ } else
+ strcat(strcat(stmt, schmp), ".");
+
+ } // endif schmp
+
+ strcat(stmt, TableName);
+ } // endif's
+
+ i = (int)strlen(stmt);
+
+ do {
+ stmt[i++] = (Qrystr[k] == '`') ? q : Qrystr[k];
+ } while (Qrystr[k++]);
+
+ RemoveConst(g, stmt);
+
+ if (body)
+ strcat(stmt, body);
+
+ } else {
+ sprintf(g->Message, "Cannot use this %s command",
+ (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
+ return true;
+ } // endif p
+
+ if (trace(33))
+ htrc("Command=%s\n", stmt);
+
+ Query = new(g)STRING(g, 0, stmt);
+ return (!Query->GetSize());
+} // end of MakeCommand
+
+/***********************************************************************/
+/* GetRecpos: return the position of last read record. */
+/***********************************************************************/
+int TDBEXT::GetRecpos(void)
+{
+ return Fpos;
+} // end of GetRecpos
+
+/***********************************************************************/
+/* ODBC GetMaxSize: returns table size estimate in number of lines. */
+/***********************************************************************/
+int TDBEXT::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0) {
+ if (Mode == MODE_DELETE)
+ // Return 0 in mode DELETE in case of delete all.
+ MaxSize = 0;
+ else if (!Cardinality(NULL))
+ MaxSize = 10; // To make MySQL happy
+ else if ((MaxSize = Cardinality(g)) < 0)
+ MaxSize = 12; // So we can see an error occurred
+
+ } // endif MaxSize
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* Return max size value. */
+/***********************************************************************/
+int TDBEXT::GetProgMax(PGLOBAL g)
+{
+ return GetMaxSize(g);
+} // end of GetProgMax
+
+/* ---------------------------EXTCOL class --------------------------- */
+
+/***********************************************************************/
+/* EXTCOL public constructor. */
+/***********************************************************************/
+EXTCOL::EXTCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : COLBLK(cdp, tdbp, i)
+{
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ if (trace(1))
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ // Set additional remote access method information for column.
+ Crp = NULL;
+ Long = Precision;
+ To_Val = NULL;
+ Bufp = NULL;
+ Blkp = NULL;
+ Rank = 0; // Not known yet
+} // end of JDBCCOL constructor
+
+/***********************************************************************/
+/* EXTCOL private constructor. */
+/***********************************************************************/
+EXTCOL::EXTCOL(void) : COLBLK()
+{
+ Crp = NULL;
+ Buf_Type = TYPE_INT; // This is a count(*) column
+
+ // Set additional Dos access method information for column.
+ Long = sizeof(int);
+ To_Val = NULL;
+ Bufp = NULL;
+ Blkp = NULL;
+ Rank = 1;
+} // end of EXTCOL constructor
+
+/***********************************************************************/
+/* EXTCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+EXTCOL::EXTCOL(PEXTCOL col1, PTDB tdbp) : COLBLK(col1, tdbp)
+{
+ Crp = col1->Crp;
+ Long = col1->Long;
+ To_Val = col1->To_Val;
+ Bufp = col1->Bufp;
+ Blkp = col1->Blkp;
+ Rank = col1->Rank;
+} // end of JDBCCOL copy constructor
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool EXTCOL::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)
+ // 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
+
+ // 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
+