summaryrefslogtreecommitdiff
path: root/src/sql
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql')
-rwxr-xr-xsrc/sql/xbcrix.cpp279
-rwxr-xr-xsrc/sql/xbcrtbl.cpp256
-rwxr-xr-xsrc/sql/xbdrpix.cpp143
-rwxr-xr-xsrc/sql/xbdrptbl.cpp125
-rwxr-xr-xsrc/sql/xbinsert.cpp190
-rwxr-xr-xsrc/sql/xbset.cpp91
-rwxr-xr-xsrc/sql/xbsql.cpp143
7 files changed, 1227 insertions, 0 deletions
diff --git a/src/sql/xbcrix.cpp b/src/sql/xbcrix.cpp
new file mode 100755
index 0000000..b24782e
--- /dev/null
+++ b/src/sql/xbcrix.cpp
@@ -0,0 +1,279 @@
+/* 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{
+
+
+/***********************************************************************/
+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;
+
+ try{
+
+ // std::cout << "xbSql::CreateIx()\n" ;
+
+ // 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 = 20;
+ throw iRc;
+ }
+ }
+
+ #ifdef XB_NDX_SUPPORT
+ if( sIxType == "NDX" ){
+ xbFile f( xbase );
+ f.SetFileName( sIxName );
+ if( f.FileExists()){
+ iErrorStop = 30;
+ 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 = 40;
+ throw iRc;
+ }
+ }
+ if( dbf == NULL ){
+ iErrorStop = 50;
+ iRc = XB_FILE_NOT_FOUND;
+ throw iRc;
+ }
+ sCmd.Ltrunc( ulPos );
+
+ // std::cout << "cp1 ulPos = " << ulPos << " scmd = " << sCmd << "\n";
+
+ //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] == ',' ){
+ 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 + 7 );
+ sFilter.Trim();
+ }
+ }
+// std::cout << "sCmd - FILTER = [" << sFilter << "]\n";
+
+ #ifdef XB_LOCKING_SUPPORT
+ if(( iRc = dbf->LockTable( XB_LOCK )) != XB_NO_ERROR ){
+ iErrorStop = 60;
+ throw iRc;
+ }
+ #endif // XB_LOCKING_SUPPORT
+
+// std::cout << "SqlCreateIndex() - ixtype = " << sIxType << "\n";
+
+ xbIx *pIx;
+ void *vpTag;
+
+ if(( iRc = dbf->CreateTag( sIxType, sIxName, sKeyExpression, sFilter, bDesc, bUnique, xbFalse, &pIx, &vpTag )) != XB_NO_ERROR ){
+ iErrorStop = 70;
+ throw iRc;
+ }
+// std::cout << "SqlCreateIndex() - back from tag create\n";
+ #ifdef XB_NDX_SUPPORT
+ if( sIxType == "NDX"){
+ sCmd.Ltrunc( ulPos );
+ sCmd.Trim();
+ if( sCmd.Len() > 0 ){
+ sCmd.ToUpperCase();
+ if( sCmd.Pos( "ASSOCIATE" )){
+ if(( iRc = dbf->AssociateIndex( "NDX", sIxName, 0 )) != XB_NO_ERROR ){
+ iErrorStop = 80;
+ throw iRc;
+ }
+ }
+ }
+ }
+ if( sIxType == "NDX"){
+ if(( iRc = pIx->Reindex( &vpTag )) != XB_NO_ERROR ){
+ iErrorStop = 100;
+ throw iRc;
+ }
+ }
+ #endif // XB_NDX_SUPPORT
+
+ #ifdef XB_LOCKING_SUPPORT
+ if(( iRc = dbf->LockTable( XB_UNLOCK )) != XB_NO_ERROR ){
+ iErrorStop = 140;
+ throw iRc;
+ }
+ #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
+ dbf->LockTable( XB_UNLOCK );
+ #endif // XB_LOCKING_SUPPORT
+
+ return iRc;
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbcrtbl.cpp b/src/sql/xbcrtbl.cpp
new file mode 100755
index 0000000..4193d01
--- /dev/null
+++ b/src/sql/xbcrtbl.cpp
@@ -0,0 +1,256 @@
+/* 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 fields 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;
+
+ try{
+ // retrieve table name
+ s.ExtractElement( sCmdLine, '(', 1, 0 );
+ sTableName.ExtractElement( s, ' ', 3, 0 );
+ sTableName.Trim();
+
+ // std::cout << "Tablename = [" << sTableName << "]\n";
+
+
+ // determine if it already exists
+ xbFile f( xbase );
+ f.SetFileName( sTableName );
+ if( f.FileExists() ){
+ iErrorStop = 10;
+ 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();
+ //std::cout << "s = [" << s << "]\n";
+
+
+ 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 = 20;
+ 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 = 30;
+ iRc = XB_INVALID_FIELD_LEN;
+ throw iRc;
+ }
+ s.Ltrunc( lPos );
+ if( iAttribCnt == 1 )
+ lPos = s.Pos( ')' );
+ else
+ lPos = s.Pos( ',' );
+
+ sAttrib1.Assign( s, 1, lPos-1 );
+ sAttrib1.Trim();
+ s.Ltrunc( lPos );
+
+ if( iAttribCnt > 1 ){
+ lPos = s.Pos( ')' );
+ sAttrib2.Assign( s, 1, lPos-1 );
+ 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 XB_DBF3_SUPPORT
+ dbf = new xbDbf3( xbase );
+ #endif
+ if(( iRc = dbf->CreateTable( sTableName, "", schema, 0, XB_MULTI_USER )) != XB_NO_ERROR ){
+ iErrorStop = 50;
+ 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/xbdrpix.cpp b/src/sql/xbdrpix.cpp
new file mode 100755
index 0000000..9e3bc3b
--- /dev/null
+++ b/src/sql/xbdrpix.cpp
@@ -0,0 +1,143 @@
+/* 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{
+
+
+/***********************************************************************/
+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 = 10;
+ 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 = 20;
+ throw iRc;
+ }
+ }
+ if( dbf == NULL ){
+ iErrorStop = 40;
+ iRc = XB_FILE_NOT_FOUND;
+ throw iRc;
+ }
+
+ #ifdef XB_LOCKING_SUPPORT
+ if(( iRc = dbf->LockTable( XB_LOCK )) != XB_NO_ERROR ){
+ iErrorStop = 50;
+ throw iRc;
+ }
+ #endif // XB_LOCKING_SUPPORT
+
+ iRc = dbf->DeleteTag( "NDX", sIxName );
+ if( iRc == XB_FILE_NOT_FOUND && !bIfExists ){
+ iErrorStop = 60;
+ throw( iRc );
+ } else if( iRc != XB_NO_ERROR ){
+ iErrorStop = 70;
+ 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;
+}
+
+/***********************************************************************/
+} /* namespace */
+#endif /* XB_SQL_SUPPORT */
+
diff --git a/src/sql/xbdrptbl.cpp b/src/sql/xbdrptbl.cpp
new file mode 100755
index 0000000..e2cfa9d
--- /dev/null
+++ b/src/sql/xbdrptbl.cpp
@@ -0,0 +1,125 @@
+/* xbdrptbl.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::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 = 10;
+ 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 );
+ if( iRc != XB_NO_ERROR ){
+ if( iRc == XB_FILE_NOT_FOUND && bIfExists ){
+ return XB_NO_ERROR;
+ } else {
+ iErrorStop = 20;
+ throw iRc;
+ }
+ }
+ }
+ if( dbf == NULL ){
+ iErrorStop = 40;
+ iRc = XB_OPEN_ERROR;
+ throw iRc;
+ }
+
+ if(( dbf->DeleteTable()) != XB_NO_ERROR ){
+ iErrorStop = 50;
+ throw iRc;
+ }
+
+ }
+
+ 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..1095202
--- /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 = 10;
+ throw iRc;
+ }
+ }
+
+ if( !dbf ){
+ iErrorStop = 20;
+ 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 = 30;
+ 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 = 40;
+ throw iRc;
+ }
+ if(( iRc = dbf->GetFieldType( iFldNo, cFldType )) != XB_NO_ERROR ){
+ iErrorStop = 50;
+ 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 = 100;
+ throw iRc;
+ }
+ break;
+
+ case 'D':
+ // assumes input date format of yyyy-mm-dd
+ if( sFieldData.Len() != 10 || sFieldData[5] != '-' || sFieldData[8] != '-' ){
+ iErrorStop = 110;
+ 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 = 120;
+ throw iRc;
+ }
+ break;
+
+ case 'M':
+ llMemoFieldNos.InsertAtFront( iFldNo );
+ llMemoFieldData.InsertAtFront( sFieldData );
+ break;
+
+ default:
+ iErrorStop= 150;
+ iRc = XB_INVALID_FIELD_TYPE;
+ throw iRc;
+ }
+ }
+
+ if(( iRc = dbf->AppendRecord()) != XB_NO_ERROR ){
+ iErrorStop = 300;
+ 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 = 400;
+ throw iRc;
+ }
+ llN = llN->GetNextNode();
+ llD = llD->GetNextNode();
+ }
+
+ if(( iRc == dbf->Commit()) != XB_NO_ERROR ){
+ iErrorStop = 500;
+ 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/xbset.cpp b/src/sql/xbset.cpp
new file mode 100755
index 0000000..98de309
--- /dev/null
+++ b/src/sql/xbset.cpp
@@ -0,0 +1,91 @@
+/* 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 = 10;
+ throw iRc;
+ }
+ } else {
+ if(( iRc = uda.UpdTokenForKey( sKey, sToken )) != XB_NO_ERROR ){
+ iErrorStop = 10;
+ 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..25cd2c8
--- /dev/null
+++ b/src/sql/xbsql.cpp
@@ -0,0 +1,143 @@
+/* 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 == "CREATE" ){
+
+ xbString sNode2;
+ sNode2.ExtractElement( sCmd.Str(), ' ', 2, 0 );
+ sNode2.ToUpperCase();
+ sNode2.Trim();
+ if( sNode2 == "TABLE" )
+ iRc = SqlCreateTable( sCmd );
+ else if( sNode2 == "INDEX" || sNode2 == "UNIQUE" )
+ iRc = SqlCreateIndex( sCmd );
+
+ 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 );
+
+ else if( sNode2 == "INDEX" )
+ iRc = SqlDropIndex( 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 << "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 */