summaryrefslogtreecommitdiff
path: root/src/sql
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql')
-rwxr-xr-xsrc/sql/xbalttbl.cpp120
-rwxr-xr-xsrc/sql/xbcrix.cpp301
-rwxr-xr-xsrc/sql/xbcrtbl.cpp274
-rwxr-xr-xsrc/sql/xbdelete.cpp148
-rwxr-xr-xsrc/sql/xbdrpix.cpp155
-rwxr-xr-xsrc/sql/xbdrptbl.cpp129
-rwxr-xr-xsrc/sql/xbinsert.cpp190
-rwxr-xr-xsrc/sql/xbselect.cpp97
-rwxr-xr-xsrc/sql/xbset.cpp90
-rwxr-xr-xsrc/sql/xbsql.cpp176
-rwxr-xr-xsrc/sql/xbstmt.cpp679
11 files changed, 2359 insertions, 0 deletions
diff --git a/src/sql/xbalttbl.cpp b/src/sql/xbalttbl.cpp
new file mode 100755
index 0000000..8a36b46
--- /dev/null
+++ b/src/sql/xbalttbl.cpp
@@ -0,0 +1,120 @@
+/* xbslttbl.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+
+/***********************************************************************/
+xbInt16 xbSql::SqlAlterTable( const xbString &sCmdLine ){
+
+ // expected format:
+ // ALTER TABLE tablename.DBF RENAME TO newtablename.DBF
+
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbString sTableName = "";
+ xbUInt32 ulPos = 0;
+ xbString sCmd = sCmdLine;
+ xbString sNode = "";
+
+ xbString sSrcTbl;
+ xbString sTrgTbl;
+ xbDbf * dbf = NULL;
+
+ try{
+
+// std::cout << "xbSql::SqlAlterTable( " << sCmdLine.Str() << " )\n";
+
+ // drop off the first node "DROP"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // drop off the second node "TABLE"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // pull off the source table
+ sSrcTbl.ExtractElement( sCmd, ' ', 1, 0 );
+ sSrcTbl.Trim();
+
+ // pull off the action
+ sNode.ExtractElement( sCmd, ' ', 2, 0 );
+ sNode.Trim();
+ sNode.ToUpperCase();
+ if( sNode != "RENAME" ){
+ iErrorStop = 100;
+ iRc = XB_SYNTAX_ERROR;
+ throw iRc;
+ }
+
+ // pull off "TO"
+ sNode.ExtractElement( sCmd, ' ', 3, 0 );
+ sNode.Trim();
+ sNode.ToUpperCase();
+ if( sNode != "TO" ){
+ iErrorStop = 110;
+ iRc = XB_SYNTAX_ERROR;
+ throw iRc;
+ }
+
+ sTrgTbl.ExtractElement( sCmd, ' ', 4, 0 );
+ sTrgTbl.Trim();
+
+// std::cout << "source table name = " << sSrcTbl.Str() << "\n";
+// std::cout << "target table name = " << sTrgTbl.Str() << "\n";
+
+ // if not open, attempt to open it
+ dbf = xbase->GetDbfPtr( sSrcTbl );
+
+ if( !dbf ){
+ if(( iRc = xbase->OpenHighestVersion( sSrcTbl, "", &dbf )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
+ }
+ if( !dbf ){
+ iErrorStop = 130;
+ iRc = XB_DBF_FILE_NOT_OPEN;
+ throw iRc;
+ }
+
+ if(( iRc = dbf->Rename( sTrgTbl )) != XB_NO_ERROR ){
+ iErrorStop = 140;
+ throw iRc;
+ }
+
+ }
+
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbSql::SqlAlterTable() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+
+ return iRc;
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbcrix.cpp b/src/sql/xbcrix.cpp
new file mode 100755
index 0000000..8efdc39
--- /dev/null
+++ b/src/sql/xbcrix.cpp
@@ -0,0 +1,301 @@
+/* xbcrix.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+
+/***********************************************************************/
+#ifdef XB_INDEX_SUPPORT
+xbInt16 xbSql::SqlCreateIndex( const xbString &sCmdLine ){
+
+ // std::cout << "CREATE INDEX " << sCmdLine << std::endl;
+
+ // expected format to create an Dbase 3, NDX index:
+ // CREATE INDEX ixname.ndx ON tablename.dbf ( EXPRESSION ) [ASSOCIATE]
+
+ // expected format to create an Dbase 4, tag on an MDX index:
+ // CREATE [UNIQUE] INDEX tagname ON tablename.dbf ( EXPRESSION ) [DESC] [FILTER .NOT. DELETED()]
+
+ // The ASSOCIATE parameter is specific to Xbase64 library, it is used to associate
+ // a non production (NDX) index file to a dbf file so it will be automatically
+ // opened with the dbf file whenever the dbf file is opened by the xbase64 routines.
+
+ // The [ASSOCIATE] parameter is not used with MDX production indices
+
+ // This method first looks for ".NDX" in the file name to determine if an NDX
+ // index should be created.
+ // if .NDX is not in the filename, it looks in the uda for "IXTYPE" for either
+ // NDX or MDX to detmermine the index type to create
+ // if IXTYPE not found, create an MDX tag
+
+ // The optional DESC parameter defines an entire index key as descending. This is
+ // different than other SQL implementations where specific fields can be descending.
+
+ // The optional FILTER parameter is specific to the XBASE64 library, is it used to
+ // assign a filter to a tag in an MDX style index. Everything to the right of
+ // the keyword FILTER is considered part of the filter.
+
+ // The original DBASE indices used to '+' to create an index on more than one field
+ // ie: FIELD1+FIELD2+FIELD3
+ // SQL uses commas: ie: FIELD1, FIELD2, FIELD3
+ // The Xbase library supports either '+' or ',' when creating mutli field indices.
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbString sTableName;
+ xbString sIxName;
+ xbString sIxType;
+ xbUInt32 ulPos;
+ xbString sCmd = sCmdLine;
+ xbString sNode;
+ xbBool bUnique = xbFalse;
+ xbDbf * dbf = NULL;
+ xbBool bTableLocked = xbFalse;
+
+ try{
+
+ // drop off the first node
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ sNode.ExtractElement( sCmd, ' ', 1, 0 );
+ sNode.ToUpperCase();
+
+ if( sNode == "UNIQUE" ){
+ //std::cout << "unique ix\n";
+ bUnique = xbTrue;
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+ }
+
+ // go past the index keyword
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // pull the index name off the cmd line
+ sIxName.ExtractElement( sCmd, ' ', 1, 0 );
+
+ #ifdef XB_NDX_SUPPORT
+ xbString sTemp = sIxName;
+ sTemp.ToUpperCase();
+ ulPos = sTemp.Pos( ".NDX" );
+ if(ulPos == (sTemp.Len() - 3) )
+ sIxType = "NDX";
+ #endif // XB_NDX_SUPPORT
+
+ if( sIxType == "" ){
+ if(( iRc = uda.GetTokenForKey( "IXTYPE", sIxType )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ }
+
+ #ifdef XB_NDX_SUPPORT
+ if( sIxType == "NDX" ){
+ xbFile f( xbase );
+ f.SetFileName( sIxName );
+ if( f.FileExists()){
+
+ iErrorStop = 110;
+ iRc = XB_FILE_EXISTS;
+ throw iRc;
+ }
+ }
+ #endif // XB_NDX_SUPPORT
+
+ // skip past index name
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // skip past "ON"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // get the table name
+ ulPos = sCmd.Pos( '(' );
+ sTableName.ExtractElement( sCmd, '(', 1, 0 );
+ sTableName.Trim();
+
+ xbFile fDbf( xbase );
+ fDbf.SetFileName( sTableName );
+
+ // if not open, attempt to open it
+ dbf = xbase->GetDbfPtr( fDbf.GetFqFileName());
+
+ if( !dbf ){
+ if(( iRc = xbase->OpenHighestVersion( sTableName, "", &dbf )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
+ }
+
+ if( dbf == NULL ){
+ iErrorStop = 130;
+ iRc = XB_FILE_NOT_FOUND;
+ throw iRc;
+ }
+ sCmd.Ltrunc( ulPos );
+
+ //ulPos = sCmd.GetLastPos( ')' );
+ xbString sKeyExpression;
+ xbBool bDone = xbFalse;
+ xbUInt32 lPos = 1;
+ xbInt16 iParenCtr = 0;
+
+ while( !bDone && lPos < sCmd.Len()){
+ if( sCmd[lPos] == '(' ){
+ iParenCtr++;
+ sKeyExpression.Append( sCmd[lPos] );
+ } else if( sCmd[lPos] == ')' ){
+ if( iParenCtr > 0 ){
+ iParenCtr--;
+ sKeyExpression.Append( sCmd[lPos] );
+ } else {
+ bDone = xbTrue;
+ }
+ } else if( sCmd[lPos] == ',' && iParenCtr == 0 ){
+ sKeyExpression.Append( '+' );
+ } else if( sCmd[lPos] != ' ' ){
+ sKeyExpression.Append( sCmd[lPos] );
+ }
+ lPos++;
+ }
+
+ // std::cout << "Key Expression =[" << sKeyExpression << "]\n";
+ sCmd.Ltrunc( lPos );
+ sCmd.Trim();
+
+ xbBool bDesc = xbFalse;
+ // std::cout << "sCmd - looking for DESC [" << sCmd << "]\n";
+ if( sCmd.Len() > 4 ){
+ sNode = sCmd;
+ sNode.ToUpperCase();
+ ulPos = sNode.Pos( "DESC" );
+ if( ulPos > 0 ){
+ bDesc = xbTrue;
+ sCmd.Ltrunc( 4 );
+ sCmd.Trim();
+ std::cout << "Descending\n";
+ }
+ }
+
+ // std::cout << "sCmd - looking for FILTER stuff [" << sCmd << "]\n";
+ xbString sFilter;
+ if( sCmd.Len() > 6 ){
+ sNode = sCmd;
+ sNode.ToUpperCase();
+ ulPos = sNode.Pos( "FILTER" );
+ if( ulPos > 0 ){
+ sFilter = sCmd;
+ sFilter.Ltrunc( ulPos + 6 );
+ sFilter.Trim();
+ }
+ }
+ // std::cout << "sCmd - FILTER = [" << sFilter << "]\n";
+
+ #ifdef XB_LOCKING_SUPPORT
+ if(( iRc = dbf->LockTable( XB_LOCK )) != XB_NO_ERROR ){
+ iErrorStop = 140;
+ throw iRc;
+ } else {
+ bTableLocked = xbTrue;
+ }
+ #endif // XB_LOCKING_SUPPORT
+
+ xbIx *pIx;
+ void *vpTag;
+
+ if(( iRc = dbf->CreateTag( sIxType, sIxName, sKeyExpression, sFilter, bDesc, bUnique, xbFalse, &pIx, &vpTag )) != XB_NO_ERROR ){
+ iErrorStop = 150;
+ throw iRc;
+ }
+
+ #ifdef XB_NDX_SUPPORT
+ xbBool bAssociate = xbFalse;
+ if( sIxType == "NDX"){
+ sCmd.Ltrunc( ulPos );
+ sCmd.Trim();
+ if( sCmd.Len() > 0 ){
+ sCmd.ToUpperCase();
+ if( sCmd.Pos( "ASSOCIATE" )){
+ bAssociate = xbTrue;
+ if(( iRc = dbf->AssociateIndex( "NDX", sIxName, 0 )) != XB_NO_ERROR ){
+ iErrorStop = 160;
+ throw iRc;
+ }
+ }
+ }
+ }
+ #endif // XB_NDX_SUPPORT
+
+ iRc = dbf->Reindex( 2, 1, &pIx, &vpTag );
+
+ #ifdef XB_NDX_SUPPORT
+ if( iRc != XB_NO_ERROR && sIxType == "NDX" && bAssociate ){
+ xbInt16 iRc2;
+ if(( iRc2 = dbf->AssociateIndex( "NDX", sIxName, 1 )) != XB_NO_ERROR ){
+ iErrorStop = 180;
+ throw iRc2;
+ }
+ iErrorStop = 190;
+ throw iRc;
+ }
+ #endif // XB_NDX_SUPPORT
+
+ if( iRc != XB_NO_ERROR ){
+ iErrorStop = 200;
+ throw iRc;
+ }
+
+
+ #ifdef XB_LOCKING_SUPPORT
+ if( bTableLocked ){
+ if(( iRc = dbf->LockTable( XB_UNLOCK )) != XB_NO_ERROR ){
+ iErrorStop = 210;
+ throw iRc;
+ } else {
+ bTableLocked = xbFalse;
+ }
+ }
+ #endif // XB_LOCKING_SUPPORT
+
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbSql::SqlCreateIndex() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ #ifdef XB_LOCKING_SUPPORT
+ if( bTableLocked && dbf )
+ dbf->LockTable( XB_UNLOCK );
+ #endif // XB_LOCKING_SUPPORT
+
+ return iRc;
+}
+#endif // XB_INDEX_SUPPORT
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbcrtbl.cpp b/src/sql/xbcrtbl.cpp
new file mode 100755
index 0000000..e22b0b5
--- /dev/null
+++ b/src/sql/xbcrtbl.cpp
@@ -0,0 +1,274 @@
+/* xbcrtbl.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2019,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+
+/***********************************************************************/
+xbInt16 xbSql::SqlCreateTable( const xbString &sCmdLine ){
+
+
+ // std::cout << "CREATE TABLE " << sCmdLine << std::endl;
+
+ // expected format:
+ // CREATE TABLE tablename.dbf (Field1 CHAR(10), INTFLD1 INTEGER, ... )
+
+ // supported field types
+ //
+ // SQL TYPE XBASE Field Type
+ // -------- ----------------
+ // SMALLINT NUMERIC(6,0)
+ // INTEGER NUMERIC(11,0)
+ // DECIMAL(x,y) NUMERIC(x+1,y)
+ // NUMERIC(x,y) NUMERIC(x,y)
+ // FLOAT(x,y) FLOAT(x,y)
+ // CHAR(n) CHARACTER(n)
+ // DATE DATE
+ // VARCHAR MEMO
+ // LOGICAL LOGICAL
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbString sTableName;
+ xbString sFieldName;
+ xbString sDataType;
+ xbString sAttrib1;
+ xbString sAttrib2;
+ xbString sLlEntry;
+ xbInt16 iType = 0;
+ xbInt16 iAttribCnt; // number of attributes for a given data type
+ xbString s;
+ xbUInt32 lPos = 0;
+ xbUInt32 lSpPos = 0; // space position
+ xbUInt32 lCmPos = 0; // comma position
+ xbUInt32 lLpPos = 0; // left paren position
+ xbLinkList<xbString> ll;
+ xbSchema *schema = NULL;
+ xbString sMsg;
+ xbString sWork;
+
+ try{
+ // retrieve table name
+ s.ExtractElement( sCmdLine, '(', 1, 0 );
+ sTableName.ExtractElement( s, ' ', 3, 0 );
+ sTableName.Trim();
+
+// std::cout << "Create table - Tablename = [" << sTableName.Str() << "]\n";
+// std::cout << "Cm line = [" << sCmdLine.Str() << "]\n";
+
+ // determine if it already exists
+ xbFile f( xbase );
+ f.SetFileName( sTableName );
+ if( f.FileExists() ){
+ iErrorStop = 100;
+ iRc = XB_FILE_EXISTS;
+ throw iRc;
+ }
+
+ // build out table structure with parms from the sql string
+ lPos = sCmdLine.Pos( '(' );
+ s = sCmdLine;
+ s.Ltrunc( lPos );
+ s.Trim();
+
+ // remove the last byte, should be a )
+ s.Remove( s.Len(), 1 );
+
+ s.Trim();
+
+ xbBool bDone = xbFalse;
+ xbInt16 iLoop = 0;
+ while( !bDone && iLoop++ < 255 ){
+ sFieldName.ExtractElement( s, ' ', 1 , 0 );
+ lPos = sFieldName.Len();
+ sFieldName.Trim();
+ if( sFieldName.Len() > 10 )
+ sFieldName.Mid( 1, 10 ); // shrink to 10 buytes if too big
+
+ //std::cout << "field name=[" << sFieldName << "]\n";
+ s.Ltrunc( lPos + 1 );
+ s.Ltrim();
+ //std::cout << "remainder after field name removed = [" << s << "]\n";
+
+ // Data type is delimited with either a space, comma or left paren
+ lPos = 9999999;
+ lSpPos = s.Pos( ' ' );
+ lCmPos = s.Pos( ',' );
+ lLpPos = s.Pos( '(' );
+ if( lSpPos != 0 ) lPos = lSpPos;
+ if( lCmPos != 0 && lCmPos < lPos ) lPos = lCmPos;
+ if( lLpPos != 0 && lLpPos < lPos ) lPos = lLpPos;
+
+ //sMsg.Sprintf( "SpPos=[%d] CmPos=[%d] LpPos=[%d] lPos=[%d]", lSpPos, lCmPos, lLpPos, lPos );
+ //std::cout << sMsg << "\n";
+
+ sDataType.Assign( s, 1, lPos-1 );
+
+ //std::cout << "DataType=[" << sDataType << "]\n";
+ if( sDataType == "CHAR" )
+ iAttribCnt = 1;
+ else if( sDataType == "DECIMAL" || sDataType == "NUMERIC" || sDataType == "FLOAT" )
+ iAttribCnt = 2;
+ else if( sDataType == "SMALLINT" || sDataType == "INTEGER" || sDataType == "DATE" || sDataType == "VARCHAR" || sDataType == "LOGICAL" )
+ iAttribCnt = 0;
+ else{
+ iErrorStop = 110;
+ iRc = XB_INVALID_FIELD_TYPE;
+ throw iRc;
+ }
+
+ sAttrib1 = "";
+ sAttrib2 = "0";
+
+ if( iAttribCnt == 0 ){
+ s.Ltrunc( sDataType.Len());
+
+ } else if( iAttribCnt > 0 ){
+ lPos = s.Pos( '(' );
+ if( lPos <= 0 ){
+ iErrorStop = 120;
+ iRc = XB_INVALID_FIELD_LEN;
+ throw iRc;
+ }
+ s.Ltrunc( lPos );
+
+ lPos = s.Pos( ')' );
+ if( lPos <= 0 ){
+ iErrorStop = 130;
+ iRc = XB_INVALID_FIELD_LEN;
+ throw iRc;
+ }
+ sWork.Assign( s, 1, lPos - 1);
+ sWork.Trim();
+
+ if( iAttribCnt == 1 ){
+ sAttrib1 = sWork;
+ } else {
+
+ lCmPos = sWork.Pos( ',' );
+ if( lCmPos <= 0 ){
+ iErrorStop = 140;
+ iRc = XB_INVALID_FIELD_LEN;
+ throw iRc;
+ }
+
+ sAttrib1.Assign( sWork, 1, lCmPos - 1);
+ sAttrib1.Trim();
+
+ sWork.Ltrunc( lCmPos );
+ sAttrib2 = sWork;
+ sAttrib2.Trim();
+
+ }
+ s.Ltrunc( lPos );
+ }
+
+ s.Ltrim();
+ s.ZapLeadingChar( ',' );
+ s.Ltrim();
+
+ if( sDataType == "CHAR" ){
+ iType = XB_CHAR_FLD;
+ } else if( sDataType == "DECIMAL" ){
+ xbInt32 lVal = atol( sAttrib1.Str()) + 1;
+ sAttrib1.Sprintf( "%d", lVal );
+ iType = XB_NUMERIC_FLD;
+ } else if( sDataType == "SMALLINT" ){
+ sAttrib1 = "6";
+ iType = XB_NUMERIC_FLD;
+ } else if( sDataType == "INTEGER" ){
+ sAttrib1 = "11";
+ iType = XB_NUMERIC_FLD;
+ } else if( sDataType == "NUMERIC" ){
+ iType = XB_NUMERIC_FLD;
+ } else if( sDataType == "FLOAT" ) {
+ iType = XB_FLOAT_FLD;
+ } else if( sDataType == "DATE" ){
+ iType = XB_DATE_FLD;
+ sAttrib1 = "8";
+ } else if( sDataType == "VARCHAR" ){
+ iType = XB_MEMO_FLD;
+ sAttrib1 = "10";
+ } else if( sDataType == "LOGICAL" ){
+ iType = XB_LOGICAL_FLD;
+ sAttrib1 = "1";
+ }
+ sLlEntry.Sprintf( "%s,%s,%c,%s,%s", sFieldName.Str(), sDataType.Str(), iType, sAttrib1.Str(), sAttrib2.Str());
+ ll.InsertAtEnd( sLlEntry );
+
+ if( s.Len() == 0 )
+ bDone = xbTrue;
+ }
+
+ schema = (xbSchema *) calloc( ll.GetNodeCnt()+1, sizeof( xbSchema ));
+ xbLinkListNode<xbString> * llN = ll.GetHeadNode();
+ xbUInt32 ulCnt = ll.GetNodeCnt();
+
+ char *pTrg;
+ for( xbUInt32 i = 0; i < ulCnt; i++ ){
+ s = llN->GetKey();
+ sFieldName.ExtractElement( s, ',', 1 , 0 );
+ pTrg = schema[i].cFieldName;
+ for( xbUInt32 j = 0; j < sFieldName.Len(); j++ )
+ *pTrg++ = sFieldName[j+1];
+ sDataType.ExtractElement( s, ',', 3, 0 );
+ schema[i].cType = sDataType[1];
+ sAttrib1.ExtractElement( s, ',', 4, 0 );
+ schema[i].iFieldLen = atoi( sAttrib1.Str());
+ sAttrib2.ExtractElement( s, ',', 5, 0 );
+ schema[i].iNoOfDecs = atoi( sAttrib2.Str());
+ llN = llN->GetNextNode();
+ }
+
+ // create the table
+ xbDbf * dbf = NULL;
+ #ifdef XB_DBF4_SUPPORT
+ dbf = new xbDbf4( xbase );
+ #elif defined (XB_DBF3_SUPPORT)
+ dbf = new xbDbf3( xbase );
+ #endif
+
+ if(( iRc = dbf->CreateTable( sTableName, "", schema, 0, XB_MULTI_USER )) != XB_NO_ERROR ){
+ iErrorStop = 150;
+ throw iRc;
+ }
+ free( schema );
+
+ ll.Clear();
+
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ if( sFieldName.Len() > 0 )
+ sMsg.Sprintf( "xbSql::SqlCreateTbl() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s] field = [%s]", iErrorStop, iRc, sTableName.Str(), sFieldName.Str() );
+ else
+ sMsg.Sprintf( "xbSql::SqlCreateTbl() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
+
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ if( schema ) free( schema );
+ }
+
+ return iRc;
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbdelete.cpp b/src/sql/xbdelete.cpp
new file mode 100755
index 0000000..9bd4279
--- /dev/null
+++ b/src/sql/xbdelete.cpp
@@ -0,0 +1,148 @@
+/* xbdelete.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+
+/***********************************************************************/
+xbInt16 xbSql::SqlDelete( const xbString &sCmdLine ){
+
+ // expected format:
+ // DELETE FROM tablename.DBF [WHERE expression]
+
+
+ xbInt16 iRc = 0;
+ xbInt16 iRc2 = 0;
+ xbInt16 iErrorStop = 0;
+ xbString sTableName = "";
+ xbUInt32 ulPos = 0;
+ xbString sCmd = sCmdLine;
+ xbString sNode = "";
+ xbString sFilter;
+ xbInt16 iDelOpt = 0;
+
+ xbString sTable;
+ xbDbf * dbf = NULL;
+
+ try{
+
+// std::cout << "xbSql::SqlDelete( " << sCmdLine.Str() << " )\n";
+
+ sNode.ExtractElement( sCmd, ' ', 1, 0 );
+ sNode.Trim();
+ sNode.ToUpperCase();
+ if( sNode == "UNDELETE" )
+ iDelOpt = 1;
+
+ // pull off the action
+ sNode.ExtractElement( sCmd, ' ', 2, 0 );
+ sNode.Trim();
+ sNode.ToUpperCase();
+ if( sNode != "FROM" ){
+ iErrorStop = 100;
+ iRc = XB_SYNTAX_ERROR;
+ throw iRc;
+ }
+
+ // pull off the table name
+ sTable.ExtractElement( sCmd, ' ', 3, 0 );
+ sTable.Trim();
+
+ // pull off the "WHERE" statement if it exists
+ sNode.ExtractElement( sCmd, ' ', 4, 0 );
+ sNode.Trim();
+ sNode.ToUpperCase();
+ if( sNode == "WHERE" ){
+ ulPos = sCmd.Pos( "WHERE" );
+ sFilter = sCmd;
+ sFilter.Ltrunc( ulPos + 5 );
+ }
+
+ // if not open, attempt to open it
+ dbf = xbase->GetDbfPtr( sTable );
+ if( !dbf ){
+ if(( iRc = xbase->OpenHighestVersion( sTable, "", &dbf )) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+ }
+ if( !dbf ){
+ iErrorStop = 120;
+ iRc = XB_DBF_FILE_NOT_OPEN;
+ throw iRc;
+ }
+
+ if( sFilter == "" ){
+ if(( iRc = dbf->DeleteAll( iDelOpt )) != XB_NO_ERROR ){
+ iErrorStop = 130;
+ throw iRc;
+ }
+ } else {
+
+ xbFilter f( dbf );
+ if(( iRc = f.Set( sFilter )) != XB_NO_ERROR ){
+ iErrorStop = 150;
+ throw iRc;
+ }
+
+ iRc2 = f.GetFirstRecord( XB_ALL_RECS );
+ while( iRc2 == XB_NO_ERROR ){
+ if( iDelOpt == 0 ){
+ if( !dbf->RecordDeleted()){
+ if(( iRc = dbf->DeleteRecord()) != XB_NO_ERROR ){
+ iErrorStop = 160;
+ throw iRc;
+ }
+ if(( iRc = dbf->Commit()) != XB_NO_ERROR ){
+ iErrorStop = 170;
+ throw iRc;
+ }
+ }
+
+ } else { // undelete
+ if( dbf->RecordDeleted()){
+ if(( iRc = dbf->UndeleteRecord()) != XB_NO_ERROR ){
+ iErrorStop = 180;
+ throw iRc;
+ }
+ if(( iRc = dbf->Commit()) != XB_NO_ERROR ){
+ iErrorStop = 190;
+ throw iRc;
+ }
+ }
+ }
+ iRc2 = f.GetNextRecord();
+ }
+ }
+ }
+
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbSql::SqlDelete() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+
+ return iRc;
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbdrpix.cpp b/src/sql/xbdrpix.cpp
new file mode 100755
index 0000000..2815264
--- /dev/null
+++ b/src/sql/xbdrpix.cpp
@@ -0,0 +1,155 @@
+/* xbdrpix.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+#ifdef XB_INDEX_SUPPORT
+/***********************************************************************/
+xbInt16 xbSql::SqlDropIndex( const xbString &sCmdLine ){
+
+ // std::cout << "DROP INDEX [" << sCmdLine << "]\n";
+
+ // expected format:
+ // DROP INDEX [IF EXISTS] ixname.ndx ON tablename.dbf
+
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbString sTableName;
+ xbString sIxName;
+ xbUInt32 ulPos;
+ xbString sCmd = sCmdLine;
+ xbString sNode;
+ xbBool bIfExists = xbFalse;
+ xbDbf * dbf = NULL;
+
+ try{
+
+ // drop off the first node "DROP"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // drop off the second node "INDEX"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ sNode.ExtractElement( sCmd, ' ', 1, 0 );
+ sNode.Trim();
+ sNode.ToUpperCase();
+
+ if( sNode == "IF" ){
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+ sNode.ExtractElement( sCmd, ' ', 1, 0 );
+ sNode.Trim();
+ sNode.ToUpperCase();
+ if( sNode != "EXISTS" ){
+ iErrorStop = 100;
+ iRc = XB_SYNTAX_ERROR;
+ throw iRc;
+ } else {
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+ bIfExists = xbTrue;
+ }
+ }
+
+ // get the index name
+ sIxName.ExtractElement( sCmd, ' ', 1, 0 );
+ sIxName.Trim();
+
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // go past "ON"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ sTableName = sCmd;
+ sTableName.Trim();
+
+ xbFile fDbf( xbase );
+ fDbf.SetFileName( sTableName );
+
+ // if not open, attempt to open it
+ dbf = xbase->GetDbfPtr( fDbf.GetFqFileName());
+ if( !dbf ){
+ if(( iRc = xbase->OpenHighestVersion( sTableName, "", &dbf )) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+ }
+ if( dbf == NULL ){
+ iErrorStop = 120;
+ iRc = XB_FILE_NOT_FOUND;
+ throw iRc;
+ }
+
+ #ifdef XB_LOCKING_SUPPORT
+ if(( iRc = dbf->LockTable( XB_LOCK )) != XB_NO_ERROR ){
+ iErrorStop = 130;
+ throw iRc;
+ }
+ #endif // XB_LOCKING_SUPPORT
+
+ ulPos = sIxName.Pos( ".NDX" );
+ if( ulPos > 0 ){
+ iRc = dbf->DeleteTag( "NDX", sIxName );
+ if( iRc == XB_FILE_NOT_FOUND && !bIfExists ){
+ iErrorStop = 140;
+ throw( iRc );
+ } else if( iRc != XB_NO_ERROR ){
+ iErrorStop = 150;
+ throw iRc;
+ }
+ } else { // assuming MDX tag
+ iRc = dbf->DeleteTag( "MDX", sIxName );
+ if( iRc == XB_FILE_NOT_FOUND && !bIfExists ){
+ iErrorStop = 160;
+ throw( iRc );
+ } else if( iRc != XB_NO_ERROR ){
+ iErrorStop = 170;
+ throw iRc;
+ }
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbSql::SqlDropIndex() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+
+ #ifdef XB_LOCKING_SUPPORT
+ dbf->LockTable( XB_UNLOCK );
+ #endif // XB_LOCKING_SUPPORT
+
+ return iRc;
+}
+#endif // XB_INDEX_SUPPORT
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbdrptbl.cpp b/src/sql/xbdrptbl.cpp
new file mode 100755
index 0000000..ee3e325
--- /dev/null
+++ b/src/sql/xbdrptbl.cpp
@@ -0,0 +1,129 @@
+/* xbdrptbl.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022,2023 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+
+/***********************************************************************/
+xbInt16 xbSql::SqlDropTable( const xbString &sCmdLine ){
+
+ // std::cout << "DROP TABLE [" << sCmdLine << "]\n";
+ // expected format:
+ // DROP TABLE [IF EXISTS] tablename.dbf
+
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbString sTableName = "";
+ xbUInt32 ulPos = 0;
+ xbString sCmd = sCmdLine;
+ xbString sNode = "";
+ xbBool bIfExists = xbFalse;
+ xbDbf * dbf = NULL;
+
+ try{
+
+ // drop off the first node "DROP"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ // drop off the second node "TABLE"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ sNode.ExtractElement( sCmd, ' ', 1, 0 );
+ sNode.Trim();
+ sNode.ToUpperCase();
+
+ if( sNode == "IF" ){
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+ sNode.ExtractElement( sCmd, ' ', 1, 0 );
+ sNode.Trim();
+ sNode.ToUpperCase();
+ if( sNode != "EXISTS" ){
+ iErrorStop = 100;
+ iRc = XB_SYNTAX_ERROR;
+ throw iRc;
+ } else {
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+ bIfExists = xbTrue;
+ }
+ }
+
+ // get the table name
+ sTableName.ExtractElement( sCmd, ' ', 1, 0 );
+ sTableName.Trim();
+
+ xbFile fDbf( xbase );
+ fDbf.SetFileName( sTableName );
+
+ if( bIfExists && ! fDbf.FileExists())
+ return XB_NO_ERROR;
+
+ // if not open, attempt to open it
+ dbf = xbase->GetDbfPtr( fDbf.GetFqFileName());
+
+ if( !dbf ){
+
+ //dbf = xbase->Open( sTableName, iRc );
+ iRc = xbase->OpenHighestVersion( sTableName, "", &dbf );
+ if( iRc != XB_NO_ERROR ){
+ if( iRc == XB_FILE_NOT_FOUND && bIfExists ){
+ return XB_NO_ERROR;
+ } else {
+ iErrorStop = 110;
+ throw iRc;
+ }
+ }
+ }
+ if( dbf == NULL ){
+ iErrorStop = 120;
+ iRc = XB_OPEN_ERROR;
+ throw iRc;
+ }
+
+ if(( dbf->DeleteTable()) != XB_NO_ERROR ){
+ iErrorStop = 130;
+ throw iRc;
+ }
+
+ delete dbf;
+ // dbf = NULL;
+ }
+
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbSql::SqlDropTable() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s]", iErrorStop, iRc, sTableName.Str() );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+
+ return iRc;
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbinsert.cpp b/src/sql/xbinsert.cpp
new file mode 100755
index 0000000..835f9e6
--- /dev/null
+++ b/src/sql/xbinsert.cpp
@@ -0,0 +1,190 @@
+/* xbinsert.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+
+/***********************************************************************/
+xbInt16 xbSql::SqlInsert( const xbString &sCmdLine ){
+
+ // expected format:
+ // INSERT INTO tablename (field1, field2, field3,...) VALUES ( 'charval', numval, 'what is the correct odbc date format to use? CCYYMMDD');
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbString sTableName;
+ xbDbf * dbf = NULL;
+
+ xbString sWork1;
+ xbString sFieldList;
+ xbString sDataList;
+ xbString sFieldName;
+ xbString sFieldData;
+
+ // queue the memo data to post after the append occurs
+ // dbase does not support usage of memo fields with insert commands
+ xbLinkList <xbInt16> llMemoFieldNos;
+ xbLinkList <xbString> llMemoFieldData;
+
+ try{
+ // retrieve table name
+ sTableName.ExtractElement( sCmdLine, ' ', 3, 0 );
+ sTableName.Trim();
+
+ // if not open, attempt to open it
+ dbf = xbase->GetDbfPtr( sTableName );
+
+ if( !dbf ){
+ if(( iRc = xbase->OpenHighestVersion( sTableName, "", &dbf )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ }
+
+ if( !dbf ){
+ iErrorStop = 110;
+ iRc = XB_FILE_NOT_FOUND;
+ throw iRc;
+ }
+
+ // blank the record buffer
+ dbf->BlankRecord();
+
+ sWork1.ExtractElement( sCmdLine, ')', 1, 0 );
+ sFieldList.ExtractElement( sWork1, '(', 2, 0 );
+
+ sDataList.ExtractElement( sCmdLine, '(', 3, 0 );
+ sDataList.Trim();
+ sDataList.ZapTrailingChar( ')' );
+
+ xbUInt32 iFldCnt = sFieldList.CountChar( ',' );
+ xbUInt32 iDataCnt = sDataList.CountChar( ',', 1 );
+
+ // verify there are the same count in the field list and values list
+ if( iFldCnt != iDataCnt ){
+ iErrorStop = 120;
+ iRc = XB_SYNTAX_ERROR;
+ throw iRc;
+ }
+
+ iFldCnt++;
+ xbInt16 iFldNo = -1;
+ char cFldType = 0x00;
+ for( xbUInt32 i = 1; i <= iFldCnt; i++ ){
+ sFieldName.ExtractElement( sFieldList, ',', i, 0 );
+ sFieldName.Trim();
+ if(( iRc = dbf->GetFieldNo( sFieldName, iFldNo )) != XB_NO_ERROR ){
+ iErrorStop = 130;
+ throw iRc;
+ }
+ if(( iRc = dbf->GetFieldType( iFldNo, cFldType )) != XB_NO_ERROR ){
+ iErrorStop = 140;
+ throw iRc;
+ }
+
+ // get the field data here
+ sFieldData.ExtractElement( sDataList, ',', i, 1 );
+ sFieldData.Trim();
+
+ // remove beginning and ending quotes
+ if(( sFieldData[1] == '\'' && sFieldData[sFieldData.Len()] == '\'') || (sFieldData[1] == '"' && sFieldData[sFieldData.Len()] == '"' )){
+ sFieldData.Remove( sFieldData.Len(), 1 );
+ sFieldData.Remove( 1, 1 );
+ }
+
+ switch( cFldType ){
+ case 'C':
+ case 'N':
+ case 'L':
+ if(( iRc = dbf->PutField( iFldNo, sFieldData )) != XB_NO_ERROR ){
+ iErrorStop = 150;
+ throw iRc;
+ }
+ break;
+
+ case 'D':
+ // assumes input date format of yyyy-mm-dd
+ if( sFieldData.Len() != 10 || sFieldData[5] != '-' || sFieldData[8] != '-' ){
+ iErrorStop = 160;
+ iRc = XB_INVALID_DATA;
+ throw iRc;
+ }
+ sWork1 = sFieldData;
+ sWork1.Remove( 8, 1 );
+ sWork1.Remove( 5, 1 );
+ if(( iRc = dbf->PutField( iFldNo, sWork1 )) != XB_NO_ERROR ){
+ iErrorStop = 170;
+ throw iRc;
+ }
+ break;
+
+ case 'M':
+ llMemoFieldNos.InsertAtFront( iFldNo );
+ llMemoFieldData.InsertAtFront( sFieldData );
+ break;
+
+ default:
+ iErrorStop= 180;
+ iRc = XB_INVALID_FIELD_TYPE;
+ throw iRc;
+ }
+ }
+
+ if(( iRc = dbf->AppendRecord()) != XB_NO_ERROR ){
+ iErrorStop = 190;
+ throw iRc;
+ }
+
+ // Add any memo fields
+ xbLinkListNode<xbInt16> * llN = llMemoFieldNos.GetHeadNode();
+ xbLinkListNode<xbString> * llD = llMemoFieldData.GetHeadNode();
+ xbUInt32 ulCnt = llMemoFieldNos.GetNodeCnt();
+ for( xbUInt32 i = 0; i < ulCnt; i++ ){
+ iFldNo = llN->GetKey();
+ sFieldData = llD->GetKey();
+ if(( iRc = dbf->UpdateMemoField( iFldNo, sFieldData )) != XB_NO_ERROR ){
+ iErrorStop = 200;
+ throw iRc;
+ }
+ llN = llN->GetNextNode();
+ llD = llD->GetNextNode();
+ }
+
+ if(( iRc = dbf->Commit()) != XB_NO_ERROR ){
+ iErrorStop = 210;
+ throw iRc;
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ xbase->WriteLogMessage( sCmdLine );
+ sMsg.Sprintf( "xbSql::SqlInsert() Exception Caught. Error Stop = [%d] rc = [%d] table = [%s] field = [%s] data = [%s]", iErrorStop, iRc, sTableName.Str(), sFieldName.Str(), sFieldData.Str() );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ if( dbf )
+ dbf->Abort();
+ }
+ return iRc;
+
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbselect.cpp b/src/sql/xbselect.cpp
new file mode 100755
index 0000000..7f12e99
--- /dev/null
+++ b/src/sql/xbselect.cpp
@@ -0,0 +1,97 @@
+/* xbset.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+
+/***********************************************************************/
+xbInt16 xbStmt::ExecuteQuery( const xbString &sCmdLine ){
+
+ std::cout << "xbStmt::ExecuteQuery() - SELECT [" << sCmdLine << "]\n";
+ // expected format:
+ // SELECT
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ // xbUInt32 ulPos;
+
+ try{
+
+ if(( iRc = ParseStmt( sCmdLine )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+
+/*
+ xbString sCmd = sCmdLine;
+ sCmd.Trim();
+ sCmd.ZapTrailingChar( ';' );
+ sCmd.Trim();
+
+ // drop off the first node "SET"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ xbString sNode1 = sCmd;
+ sNode1.ToUpperCase();
+
+ if( sNode1 == "SET" ) {
+ uda.DumpUda();
+
+ } else {
+
+ xbString sKey;
+ sKey.ExtractElement( sCmd, '=', 1, 0 );
+ sKey.Trim();
+
+ xbString sToken;
+ sToken.ExtractElement( sCmd, '=', 2, 0 );
+ sToken.Trim();
+
+
+ if( sToken == '^' ){
+ if(( iRc = uda.DelTokenForKey( sKey )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ } else {
+ if(( iRc = uda.UpdTokenForKey( sKey, sToken )) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+ }
+ }
+*/
+
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbStmt::ExecuteQuery() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+
+ return iRc;
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbset.cpp b/src/sql/xbset.cpp
new file mode 100755
index 0000000..d0e8821
--- /dev/null
+++ b/src/sql/xbset.cpp
@@ -0,0 +1,90 @@
+/* xbset.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+
+/***********************************************************************/
+xbInt16 xbSql::SqlSet( const xbString &sCmdLine ){
+
+ // std::cout << "SET [" << sCmdLine << "]\n";
+ // expected format:
+ // SET ATTRIBUTE = DATAVALUE
+ // SET ATTRIBUTE = ^ (to delete an entry)
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbUInt32 ulPos;
+
+ try{
+
+ xbString sCmd = sCmdLine;
+ sCmd.Trim();
+ sCmd.ZapTrailingChar( ';' );
+ sCmd.Trim();
+
+ // drop off the first node "SET"
+ ulPos = sCmd.Pos( ' ' );
+ sCmd.Ltrunc( ulPos );
+ sCmd.Ltrim();
+
+ xbString sNode1 = sCmd;
+ sNode1.ToUpperCase();
+
+ if( sNode1 == "SET" ) {
+ uda.DumpUda();
+
+ } else {
+
+ xbString sKey;
+ sKey.ExtractElement( sCmd, '=', 1, 0 );
+ sKey.Trim();
+
+ xbString sToken;
+ sToken.ExtractElement( sCmd, '=', 2, 0 );
+ sToken.Trim();
+
+
+ if( sToken == '^' ){
+ if(( iRc = uda.DelTokenForKey( sKey )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ } else {
+ if(( iRc = uda.UpdTokenForKey( sKey, sToken )) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+ }
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbSql::SqlSet() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+
+ return iRc;
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbsql.cpp b/src/sql/xbsql.cpp
new file mode 100755
index 0000000..12d3379
--- /dev/null
+++ b/src/sql/xbsql.cpp
@@ -0,0 +1,176 @@
+/* xbsql.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+/***********************************************************************/
+xbSql::xbSql( xbXBase *x ){
+ xbase = x;
+ xbString sIxType;
+
+ #ifdef XB_MDX_SUPPORT
+ sIxType = "MDX";
+ #endif
+
+ #ifdef XB_NDX_SUPPORT
+ if( sIxType == "" )
+ sIxType = "NDX";
+ #endif
+
+ if( sIxType != "" )
+ uda.AddTokenForKey( "IXTYPE", sIxType );
+
+}
+/***********************************************************************/
+xbSql::~xbSql(){
+}
+
+/***********************************************************************/
+xbInt16 xbSql::ExecuteNonQuery( const xbString &sCmdLine ) {
+
+// std::cout << "\n\n\nExecute() " << sCmdLine.Str() << "\n";
+
+ xbInt16 iRc = XB_NO_ERROR;
+ xbString sCmd = sCmdLine;
+
+ sCmd.Trim();
+ xbString sNode1;
+ sNode1.ExtractElement( sCmd.Str(), ' ', 1, 0 );
+ sNode1.ToUpperCase();
+ sNode1.Trim();
+
+// std::cout << "node 1 = " << sNode1.Str() << std::endl;
+
+ if( sNode1 == "ALTER" ){
+ xbString sNode2;
+ sNode2.ExtractElement( sCmd.Str(), ' ', 2, 0 );
+ sNode2.ToUpperCase();
+ sNode2.Trim();
+
+ if( sNode2 == "TABLE" )
+ iRc = SqlAlterTable( sCmd );
+ else
+ iRc = XB_INVALID_FUNCTION;
+
+
+
+ } else if( sNode1 == "CREATE" ){
+
+ xbString sNode2;
+ sNode2.ExtractElement( sCmd.Str(), ' ', 2, 0 );
+ sNode2.ToUpperCase();
+ sNode2.Trim();
+ if( sNode2 == "TABLE" )
+ iRc = SqlCreateTable( sCmd );
+
+ #ifdef XB_INDEX_SUPPORT
+ else if( sNode2 == "INDEX" || sNode2 == "UNIQUE" )
+ iRc = SqlCreateIndex( sCmd );
+ #endif // XB_INDEX_SUPPORT
+
+ else
+ iRc = XB_INVALID_FUNCTION;
+
+ } else if( sNode1 == "DROP" ){
+
+ xbString sNode2;
+ sNode2.ExtractElement( sCmd.Str(), ' ', 2, 0 );
+ sNode2.ToUpperCase();
+ sNode2.Trim();
+
+ if( sNode2 == "TABLE" )
+ iRc = SqlDropTable( sCmd );
+
+ #ifdef XB_INDEX_SUPPORT
+ else if( sNode2 == "INDEX" )
+ iRc = SqlDropIndex( sCmd );
+ #endif // XB_INDEX_SUPPORT
+
+ else
+ iRc = XB_INVALID_FUNCTION;
+
+ } else if( sNode1 == "DELETE" || sNode1 == "UNDELETE" ){
+
+ iRc = SqlDelete( sCmd );
+
+
+ } else if( sNode1 == "HELP" )
+ SqlHelp();
+
+ else if( sNode1 == "INSERT" ){
+ iRc = SqlInsert( sCmd );
+
+ // else if( sNode1 == "UPDATE" )
+ // iRc = SqlUpdate( sCmd );
+ }
+
+ else if( sNode1 == "USE" )
+ iRc = SqlUse( sCmd );
+
+ else if( sNode1 == "SET" )
+ iRc = SqlSet( sCmd );
+
+ else
+ return XB_INVALID_FUNCTION;
+
+ return iRc;
+}
+
+/***********************************************************************/
+xbXBase *xbSql::GetXbasePtr() const {
+ return xbase;
+}
+
+
+/***********************************************************************/
+void xbSql::SqlHelp() const {
+ std::cout << "************************" << std::endl;
+ std::cout << "Valid XBase SQL commands" << std::endl << std::endl;
+ std::cout << "HELP" << std::endl;
+
+ std::cout << "ALTER TABLE tablename.DBF RENAME TO newtablename.DBF" << std::endl;
+ std::cout << "CREATE INDEX ixname.NDX ON tablename.dbf ( EXPRESSION ) [ASSOCIATE]" << std::endl;
+ std::cout << "CREATE [UNIQUE] INDEX tagname ON tablename.dbf ( EXPRESSION ) [DESC] [FILTER .NOT. DELETED()]" << std::endl;
+ std::cout << "CREATE TABLE tablename.DBF (Field1 CHAR(10), INTFLD1 INTEGER, ... )" << std::endl;
+ std::cout << "DELETE FROM tablename.DBF [WHERE expression]" << std::endl;
+ std::cout << "DROP INDEX [IF EXISTS] ixname.NDX ON tablename.DBF" << std::endl;
+ std::cout << "DROP TABLE [IF EXISTS] tablename.DBF" << std::endl;
+ std::cout << "INSERT INTO tablename (field1, field2, field3,...) VALUES ( 'charval', numval, {MM/DD/YY})" << std::endl;
+ std::cout << "SELECT FIELD1,FIELD2... FROM TABLE.DBF [WHERE expression] [ORDER BY TAG TAGNAME" << std::endl;
+ std::cout << "SET ATTRIBUTE = DATAVALUE" << std::endl;
+ std::cout << "SET ATTRIBUTE = ^ (to delete an entry)" << std::endl;
+ std::cout << "USE /dir/to/dbf/tables" << std::endl;
+ std::cout << "CREATE TABLE" << std::endl << std::endl << std::endl;
+}
+
+/***********************************************************************/
+xbInt16 xbSql::SqlUse( const xbString &sCmdLine ){
+
+ xbString sNode2;
+ sNode2.ExtractElement( sCmdLine.Str(), ' ', 2, 0 );
+ sNode2.Trim();
+ xbase->SetDataDirectory( sNode2 );
+// std::cout << "USE " << sNode2 << std::endl;
+ return XB_NO_ERROR;
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbstmt.cpp b/src/sql/xbstmt.cpp
new file mode 100755
index 0000000..61c84fd
--- /dev/null
+++ b/src/sql/xbstmt.cpp
@@ -0,0 +1,679 @@
+/* xbsql.cpp
+
+XBase64 Software Library
+
+Copyright (c) 1997,2003,2014,2022 Gary A Kunkel
+
+The xb64 software library is covered under the terms of the GPL Version 3, 2007 license.
+
+Email Contact:
+
+ XDB-devel@lists.sourceforge.net
+ XDB-users@lists.sourceforge.net
+
+*/
+
+#include "xbase.h"
+
+#ifdef XB_SQL_SUPPORT
+
+namespace xb{
+
+/***********************************************************************/
+xbStmt::xbStmt( xbXBase *x ){
+ xbase = x;
+ pTblList = NULL;
+ fl = NULL;
+ ulFromPos = 0;
+ ulWherePos = 0;
+ ulOrderByPos = 0;
+ ulGroupByPos = 0;
+ ulHavingPos = 0;
+}
+
+/***********************************************************************/
+xbStmt::~xbStmt(){
+
+ std::cout << "xbStmt::~xbStmt() - need to release all allocated structures and memory here\n";
+
+}
+
+/***********************************************************************/
+xbInt16 xbStmt::CvtSqlExp2DbaseExp( const xbString &sExpIn, xbString &sExpOut ){
+
+ // convert Ansi SQL expression to a DBase compatible expression
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+
+ try{
+
+ // convert tablename.fieldname to tablename->fieldname
+ sExpOut = sExpIn[1];
+ xbUInt32 ulPos = 2;
+ while( ulPos < sExpIn.Len() ){
+ if( sExpIn[ulPos] == '.' && sExpIn[ulPos-1] != ' ' && sExpIn[ulPos+1] != ' ' )
+ sExpOut += "->";
+ else
+ sExpOut += sExpIn[ulPos];
+ ulPos++;
+ }
+ sExpOut += sExpIn[ulPos];
+
+ sExpOut.Replace( " AND ", " .AND. ", 0 );
+ sExpOut.Replace( " and ", " .AND. ", 0 );
+ sExpOut.Replace( " OR ", " .OR. ", 0 );
+ sExpOut.Replace( " or ", " .OR. ", 0 );
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbStmt::CvtSqlExp2DbaseExp() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+
+/***********************************************************************/
+#ifdef XB_DEBUG_SUPPORT
+xbInt16 xbStmt::DumpStmtInternals(){
+
+ std::cout << "************** Dump Statment Internals ***************" << std::endl;
+ std::cout << "Statement [" << sStmt << "]\n";
+ std::cout << "Fields [" << sFields << "]\n";
+ std::cout << "From [" << sFrom << "]\n";
+ std::cout << "Where [" << sWhere << "]\n";
+ std::cout << "Order By [" << sOrderBy << "]\n";
+ std::cout << "Group By [" << sGroupBy << "]\n";
+ std::cout << "Having [" << sHaving << "]\n";
+
+ xbTblJoin *p = pTblList;
+ if( p ){
+ std::cout << "Tbl List\n";
+ std::cout << "Type,Name,Alias,Exp\n";
+ while( p ){
+ std::cout << p->cJoinType << "," << p->sTableName.Str() << "," << p->sAlias.Str() << "," << p->sJoinExp.Str() << "\n";
+ p = p->next;
+ }
+ }
+ std::cout << "*************** End of Internals ************" << std::endl;
+ return 0;
+}
+
+xbInt16 xbStmt::Test(){
+ xbString s;
+
+ s = "(ABC)";
+ std::cout << "[" << s.Str() << "][" << GetParenCnt( s ) << "]\n";
+ s = "(ABC) )";
+ std::cout << "[" << s.Str() << "][" << GetParenCnt( s ) << "]\n";
+ s = "(";
+ std::cout << "[" << s.Str() << "][" << GetParenCnt( s ) << "]\n";
+ s = "( (";
+ std::cout << "[" << s.Str() << "][" << GetParenCnt( s ) << "]\n";
+ s = "aaa)";
+ std::cout << "[" << s.Str() << "][" << GetParenCnt( s ) << "]\n";
+ s = "aaa";
+ std::cout << "[" << s.Str() << "][" << GetParenCnt( s ) << "]\n";
+
+ return 0;
+
+}
+#endif // XB_DEBUG_SUPPORT
+
+
+/***********************************************************************/
+xbInt16 xbStmt::GetNextFromSeg( const xbString &sLineIn, xbString &sFromSegOut ){
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbInt16 iParenCtr = 0;
+ xbUInt32 ulPos = 1;
+ xbUInt32 ulTsp = 0; // token start position
+ xbBool bDone = xbFalse;
+ xbString sToken;
+
+ try{
+ sFromSegOut = "";
+ while( !bDone ){
+ ulTsp = GetNextToken( sLineIn, sToken, ulPos );
+ if( sToken == "" ){
+ bDone = xbTrue;
+
+ } else {
+ iParenCtr += GetParenCnt( sToken );
+ if( iParenCtr == 0 && ulPos > 1 ){
+ sToken.ToUpperCase();
+ if( sToken == "LEFT" || sToken == "RIGHT" || sToken == "FULL" ||
+ sToken == "INNER" || sToken == "OUTER" || sToken[1] == '(' ){
+ bDone = xbTrue;
+ }
+ }
+ }
+ ulPos += (sToken.Len() + 1);
+ }
+ if( ulTsp > 1 )
+ sFromSegOut.Assign( sLineIn, 1, ulTsp - 2 );
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbStmt::GetNextFromSeg() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+/***********************************************************************/
+
+xbUInt32 xbStmt::GetNextToken( const xbString &sCmdLineIn, xbString &sTokenOut, xbUInt32 ulStartPos ){
+
+ // input
+ // sCmdLine - Entire Command line
+ // ulStartPos - Where to start searching for the next token
+ // returns the position of the beginning of the token in the main command line
+
+ xbUInt32 ul = ulStartPos;
+ xbUInt32 ulTokenStartPos = 0;
+ sTokenOut = "";
+
+ while( ul <= sCmdLineIn.Len() && sCmdLineIn[ul] == ' ' )
+ ul++;
+ ulTokenStartPos = ul;
+
+ while( ul <= sCmdLineIn.Len() && sCmdLineIn[ul] != ' ' ){
+ sTokenOut += sCmdLineIn[ul];
+ ul++;
+ }
+
+ return ulTokenStartPos;
+}
+/***********************************************************************/
+xbInt16 xbStmt::GetParenCnt( const xbString &sToken ){
+
+ xbInt16 iParenCnt = 0;
+
+ for( xbUInt32 i = 1; i <= sToken.Len(); i++ ){
+ if( sToken[i] == '(' )
+ iParenCnt++;
+ else if( sToken[i] == ')' )
+ iParenCnt--;
+ }
+ return iParenCnt;
+}
+
+
+/***********************************************************************/
+xbInt16 xbStmt::ParseFromStmt( const xbString &sFromLine ){
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbBool bDone = xbFalse;
+ xbString sFromSeg;
+ xbString sLine = sFromLine;
+
+ try{
+ std::cout << "ParseFromSeg [" << sFromLine.Str() << "]\n";
+
+ while( !bDone ){
+ if(( iRc = GetNextFromSeg( sLine, sFromSeg)) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ if( sFromSeg.Len() == 0 ){
+ bDone = xbTrue;
+ } else {
+ if(( iRc = ProcessFromSeg( sFromSeg )) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+ sLine.Ltrunc( sFromSeg.Len() );
+ sLine.Ltrim();
+ }
+ }
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbStmt::ParseFromSeg() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+
+ return iRc;
+}
+/***********************************************************************/
+xbInt16 xbStmt::ParseStmt( const xbString &sCmdLine ){
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ xbInt16 iParenCnt = 0;
+ xbUInt32 ulStartPos = 7;
+ xbUInt32 ulLen = 0;
+
+
+ xbBool bFromFound = xbFalse;
+ xbBool bWhereFound = xbFalse;
+ xbBool bOrderByFound = xbFalse;
+ xbBool bGroupByFound = xbFalse;
+ xbBool bHavingFound = xbFalse;
+ xbBool bDone = xbFalse;
+
+ xbString sToken;
+
+ sStmt.Set( sCmdLine );
+ sStmt.Trim();
+
+ try{
+
+ std::cout << "ParseStmt - [" << sStmt << "]\n";
+
+ xbUInt32 ulPos = ulStartPos;
+
+ while( !bFromFound && !bDone ){
+ ulPos = GetNextToken( sStmt, sToken, ulPos );
+ if( sToken == "" ){
+ bDone = xbTrue;
+ } else {
+ iParenCnt += GetParenCnt( sToken );
+ if( iParenCnt == 0 ){
+ sToken.ToUpperCase();
+ if( sToken == "FROM" ){
+ bFromFound = xbTrue;
+ ulFromPos = ulPos;
+ sFrom.Assign( sStmt, ulFromPos );
+ }
+ }
+ ulPos += sToken.Len() + 1;
+ }
+ }
+
+ // look for the where clause
+ if( bFromFound )
+ ulPos = ulFromPos + 5;
+ else
+ ulPos = ulStartPos;
+
+ bDone = xbFalse;
+ while( !bWhereFound && !bDone ){
+ ulPos = GetNextToken( sStmt, sToken, ulPos );
+ if( sToken == "" ){
+ bDone = xbTrue;
+ } else {
+ iParenCnt += GetParenCnt( sToken );
+ if( iParenCnt == 0 ){
+ sToken.ToUpperCase();
+ if( sToken == "WHERE" ){
+ bWhereFound = xbTrue;
+ ulWherePos = ulPos;
+ sWhere.Assign( sStmt, ulWherePos+6 );
+ }
+ }
+ ulPos += sToken.Len() + 1;
+ }
+ }
+
+
+ // look for the order clause
+ if( bWhereFound )
+ ulPos = ulWherePos + 6;
+ else if( bFromFound )
+ ulPos = ulFromPos + 5;
+ else
+ ulPos = ulStartPos;
+
+ bDone = xbFalse;
+ while( !bOrderByFound && !bDone ){
+ ulPos = GetNextToken( sStmt, sToken, ulPos );
+ if( sToken == "" ){
+ bDone = xbTrue;
+ } else {
+ iParenCnt += GetParenCnt( sToken );
+ if( iParenCnt == 0 ){
+ sToken.ToUpperCase();
+ if( sToken == "ORDER" ){
+ xbString sToken2;
+ xbUInt32 ulPos2 = GetNextToken( sStmt, sToken2, ulPos + 6 );
+ if( sToken2 != "" ){
+ sToken2.ToUpperCase();
+ if( sToken2 == "BY" ){
+ bOrderByFound = xbTrue;
+ ulOrderByPos = ulPos;
+ sOrderBy.Assign( sStmt, ulPos2 + 3 );
+ }
+ }
+ }
+ }
+ ulPos += sToken.Len() + 1;
+ }
+ }
+
+
+ bDone = xbFalse;
+ while( !bGroupByFound && !bDone ){
+ ulPos = GetNextToken( sStmt, sToken, ulPos );
+ if( sToken == "" ){
+ bDone = xbTrue;
+ } else {
+ iParenCnt += GetParenCnt( sToken );
+ if( iParenCnt == 0 ){
+ sToken.ToUpperCase();
+ if( sToken == "GROUP" ){
+ xbString sToken2;
+ xbUInt32 ulPos2 = GetNextToken( sStmt, sToken2, ulPos + 6 );
+ if( sToken2 != "" ){
+ sToken2.ToUpperCase();
+ if( sToken2 == "BY" ){
+ bGroupByFound = xbTrue;
+ ulGroupByPos = ulPos;
+ sGroupBy.Assign( sStmt, ulPos2 + 3 );
+ }
+ }
+ }
+ }
+ ulPos += sToken.Len() + 1;
+ }
+ }
+
+ bDone = xbFalse;
+ while( !bHavingFound && !bDone ){
+ ulPos = GetNextToken( sStmt, sToken, ulPos );
+ if( sToken == "" ){
+ bDone = xbTrue;
+ } else {
+ iParenCnt += GetParenCnt( sToken );
+ if( iParenCnt == 0 ){
+ sToken.ToUpperCase();
+ if( sToken == "HAVING" ){
+ bHavingFound = xbTrue;
+ ulHavingPos = ulPos;
+ sHaving.Assign( sStmt, ulHavingPos + 7 );
+ }
+ }
+ ulPos += sToken.Len() + 1;
+ }
+ }
+
+
+ // do the fields part
+ if( bFromFound )
+ ulLen = ulFromPos - 7;
+ else if( bWhereFound )
+ ulLen = ulWherePos - 7;
+ else if( bOrderByFound )
+ ulLen = ulOrderByPos - 7;
+ else if( bGroupByFound )
+ ulLen = ulGroupByPos - 7;
+ else if( bHavingFound )
+ ulLen = ulHavingPos - 7;
+ else
+ ulLen = sStmt.Len() - 7;
+ sFields.Assign( sStmt, 7, ulLen );
+ sFields.Trim();
+
+ // do the FROM part
+ if( bFromFound ){
+ if( bWhereFound )
+ ulLen = ulWherePos - ulFromPos;
+ else if( bOrderByFound )
+ ulLen = ulOrderByPos - ulFromPos;
+ else if( bGroupByFound )
+ ulLen = ulGroupByPos - ulFromPos;
+ else if( bHavingFound )
+ ulLen = ulHavingPos - ulFromPos;
+ else
+ ulLen = sStmt.Len() - ulFromPos;
+ sFrom.Resize( ulLen );
+ sFrom.Trim();
+
+ }
+
+
+ // do the WHERE part
+ if( bWhereFound ){
+ ulLen = 0;
+ if( bOrderByFound )
+ ulLen = ulOrderByPos - ulWherePos - 6;
+ else if( bGroupByFound )
+ ulLen = ulGroupByPos - ulWherePos - 6;
+ else if( bHavingFound )
+ ulLen = ulHavingPos - ulWherePos - 6;
+
+ if( ulLen > 0 )
+ sWhere.Resize( ulLen );
+ sWhere.Trim();
+ }
+
+ // FIXME if there is more than one space between ORDER and BY then this doesn't work quite right
+ // do the ORDER BY part
+ if( bOrderByFound ){
+ if( bGroupByFound )
+ ulLen = ulGroupByPos - ulOrderByPos - 9;
+ else if( bHavingFound )
+ ulLen = ulHavingPos - ulOrderByPos - 9;
+ else
+ ulLen = sStmt.Len() - ulOrderByPos - 9;
+ sOrderBy.Resize( ulLen );
+ sOrderBy.Trim();
+ }
+
+ // FIXME if there is more than one space between ORDER and BY then this doesn't work quite right
+ // do the GROUP BY part
+ if( bGroupByFound ){
+ if( bHavingFound )
+ ulLen = ulHavingPos - ulGroupByPos - 9;
+ else
+ ulLen = sStmt.Len() - ulGroupByPos - 9;
+ sGroupBy.Resize( ulLen );
+ sGroupBy.Trim();
+ }
+
+ if( bFromFound ){
+ if(( iRc = ParseFromStmt( sFrom )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ }
+
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbStmt::ParseStmt() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+
+ return iRc;
+}
+
+/***********************************************************************/
+xbInt16 xbStmt::ProcessFromSeg( const xbString &sFromSeg ){
+
+
+ xbInt16 iRc = 0;
+ xbInt16 iErrorStop = 0;
+ char cType = ' ';
+ xbString sToken;
+ xbString sTable;
+ xbString sAlias;
+ xbString sWork;
+ xbString sExp;
+ xbUInt32 iPos;
+ xbBool bDone;
+ xbExp * pJoinExp = NULL;
+
+ try{
+
+ std::cout << "ProcessFromSeg for segment [" << sFromSeg.Str() << "]\n";
+
+ GetNextToken( sFromSeg, sToken, 1 );
+ sToken.ToUpperCase();
+
+ std::cout << "sToken1 = [" << sToken.Str() << "]\n";
+
+ if( sToken == "FROM" ){
+ // FROM has to be the first statement, and exist only once
+ if( pTblList ){
+ iErrorStop = 100;
+ iRc = XB_PARSE_ERROR;
+ throw iRc;
+ }
+ cType = 'M';
+ } else if( sToken == "LEFT" )
+ cType = 'L';
+ else if( sToken == "RIGHT" )
+ cType = 'R';
+ else if( sToken == "RIGHT" )
+ cType = 'R';
+ else if( sToken == "INNER" )
+ cType = 'I';
+ else if( sToken == "OUTER" || sToken == "FULL" )
+ cType = 'O';
+ else if( sToken[1] == '(' )
+ cType = 'Q';
+ else{
+ iErrorStop = 100;
+ iRc = XB_PARSE_ERROR;
+ throw iRc;
+ }
+
+
+ if( cType == 'M' ){
+ // expecting "FROM table" or "FROM table alias"
+ iPos = GetNextToken( sFromSeg, sToken, 5 );
+ sTable = sToken;
+
+ iPos = GetNextToken( sFromSeg, sToken, iPos + sToken.Len() + 1 );
+ if( sToken.Len() > 0 )
+ sAlias = sToken;
+ else
+ sAlias = "";
+
+ sWork = sToken;
+ sWork.ToUpperCase();
+ iPos = sWork.Pos( ".DBF" );
+ if( iPos == 0 )
+ sTable += ".DBF";
+
+ // std::cout << "table = [" << sTable.Str() << "] alias = [" << sAlias.Str() << "]\n";
+
+ } else if( cType != 'Q' ){
+ sWork = sFromSeg;
+ sWork.ToUpperCase();
+ iPos = sWork.Pos( " ON " );
+ if( iPos == 0 ){
+ iErrorStop = 110;
+ iRc = XB_PARSE_ERROR;
+ throw iRc;
+ }
+ bDone = xbFalse;
+
+ sWork.Assign( sFromSeg, iPos + 4 );
+ CvtSqlExp2DbaseExp( sWork, sExp );
+ sExp.Trim();
+ std::cout << "ON = [" << sExp.Str() << "]\n";
+
+
+ // need to get past the keywords LEFT, FULL, OUTER, RIGHT, INNER and get the table name here
+ iPos = sToken.Len() + 1;
+ while( !bDone ){
+ iPos = GetNextToken( sFromSeg, sToken, iPos );
+ sWork = sToken;
+ sWork.ToUpperCase();
+ if( sWork != "LEFT" && sWork != "RIGHT" && sWork != "INNER" && sWork != "OUTER" && sWork != "FULL" && sWork != "JOIN" )
+ bDone = xbTrue;
+ else
+ iPos += (sWork.Len() + 1);
+ }
+
+ sTable = sToken;
+ GetNextToken( sFromSeg, sAlias, iPos + sTable.Len() + 1 );
+ sWork.ToUpperCase();
+ iPos = sWork.Pos( ".DBF" );
+ if( iPos == 0 )
+ sTable += ".DBF";
+ sWork = sAlias;
+ sWork.ToUpperCase();
+ if( sWork == "ON" )
+ sAlias = "";
+ }
+
+
+ // open table
+ //std::cout << "attempting to open table " << sTable.Str() << "\n";
+ xbDbf *d = NULL;
+ if(( iRc = xbase->OpenHighestVersion( sTable, sAlias, &d )) != XB_NO_ERROR ){
+ iErrorStop = 120;
+ throw iRc;
+ }
+
+
+
+ // build out table linkage expression
+ if( cType == 'M' )
+ sExp = "MASTER";
+ else if( cType == 'L' ){
+ pJoinExp = new xbExp( xbase );
+
+ // std::cout << "Parsing expression [" << sExp.Str() << "]\n";
+ if(( iRc = pJoinExp->ParseExpression( d, sExp )) != XB_NO_ERROR ){
+ iErrorStop = 130;
+ throw iRc;
+ }
+ }
+
+
+ // attach to correct location in list
+
+
+ // update the UpdateJoinList routine as appropriate
+// if(( iRc = UpdateJoinList( cType, sTable, sAlias, NULL, NULL, NULL, NULL )) != XB_NO_ERROR ){
+
+ if(( iRc = UpdateJoinList( cType, sTable, sAlias, sExp, d, pJoinExp )) != XB_NO_ERROR ){
+ iErrorStop = 110;
+ throw iRc;
+ }
+
+
+ }
+ catch (xbInt16 iRc ){
+ xbString sMsg;
+ sMsg.Sprintf( "xbStmt::ProcessFromSeg() Exception Caught. Error Stop = [%d] rc = [%d]", iErrorStop, iRc );
+ xbase->WriteLogMessage( sMsg.Str() );
+ xbase->WriteLogMessage( GetErrorMessage( iRc ));
+ }
+ return iRc;
+}
+
+/***********************************************************************/
+xbInt16 xbStmt::UpdateJoinList( char cType, const xbString &sTableName, const xbString &sAlias, const xbString &sExp, xbDbf *d, xbExp *e ){
+// xbTag *t ){
+
+
+ std::cout << "Update join list for table " << sTableName.Str() << "\n";
+
+ xbTblJoin *pTj;
+ if(( pTj = (xbTblJoin *) calloc( 1, sizeof( xbTblJoin ))) == NULL )
+ return XB_NO_MEMORY;
+
+ pTj->cJoinType = cType;
+ pTj->sTableName.Set( sTableName );
+ pTj->sAlias.Set( sAlias );
+ pTj->sJoinExp.Set( sExp );
+ pTj->pDbf = d;
+ pTj->pLinkExp = e;
+
+/*
+
+ pTj->pTag = t;
+*/
+
+ if( cType == 'M' )
+ pTblList = pTj;
+
+ return 0;
+}
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+