summaryrefslogtreecommitdiff
path: root/src/sql/xbcrix.cpp
blob: b24782e63f684e8f30bfe293345e56665fa971cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
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 */