PRODUCT : Paradox Engine NUMBER : 1168 VERSION : 3.0 OS : All DATE : October 22, 1993 PAGE : 1/8 TITLE : A temporary workaround for a failure in PXSrchFld(). /* ---------------------------------------------------------------- *\ It has been brought to our attention that doing a PXSrchFld with either the SEARCHFIRST or CLOSESTRECORD parameter will fail in certain circumstances. Our QA department has an example of this and is working on a solution. We have created this workaround to use in the meantime. The workaround is to do a CLOSESTRECORD search in place of the SEARCHFIRST search. A CLOSESTRECORD search will leave the record cursor on the first record that has a value greater than the search value and return PXERR_RECNOTFOUND if an exact match is not found. In some cases a CLOSESTRECORD search will treat an exact match as the first value greater than the search value ( the problem that we are trying to get around ). What this workaround does is manually compare the search value to the value in the current record when PXERR_RECNOTFOUND is returned. How to use this function: ========================= Link this module into your application and add the following lines to the end of your pxengine.h file ( it has to be at the end because we do not want to get rid of the prototype to PXSrchFld within the header file - we still need to call it from within our function ): PXCODE PXSrch( TABLEHANDLE tblHandle, RECORDHANDLE recHandle, FIELDHANDLE fldHandle, int mode ) ; #define PXSrchFld PXSrch Doing this prototypes the PXSrch function and will replace all of your calls to PXSrchFld with calls to PXSrch. This function is stack intensize, so make sure that you have sufficient stack space available. The applications stack space is PRODUCT : Paradox Engine NUMBER : 1168 VERSION : 3.0 OS : All DATE : October 22, 1993 PAGE : 2/8 TITLE : A temporary workaround for a failure in PXSrchFld(). increased within this module. You can also decrease the stack space required by dynamically allocating the local variables. You can define the variable DEBUG in order to determine when you enter the special parts of the PXSrch function, using either -DDEBUG at the command line while compiling, or under 'Options | Compiler | Code generation - defines' in the IDE. Using with the Database Framework ( DBF ): ========================================== - The Database Frameworks will have to be compiled with the modified header file ( see above ) and pxsrch.c will have to be a part of the application. - There is also an incompatibility with using BCursor::searchIndex when doing a pxSearchFirst search. The problem that can present itself is that PXSrch will change the internal record cursor, but BCursor::searchIndex will not change the BCursors current object when a pxSearchFirst search is done. There are two workaround to this: change your searches from pxSearchFirst to pxClosestRecord, or your will have to change a line of code in bcursor.cpp. This change is required because PXSrch will internally do a PXSrchFld with the CLOSESTRECORD parameter, which will change the current record even if a record is not found. Line 1018: if (! lastError || (mode==pxClosestRecord && lastError==PXERR_RECNOTFOUND)) curStatus = atRecord; Change to: if ( ( ! lastError ) || ( (mode==pxClosestRecord ) || (mode==pxSearchFirst ) ) && (lastError==PXERR_RECNOTFOUND) )) curStatus = atRecord; Differences between PXSrch and PXSrchFld: ========================================= PRODUCT : Paradox Engine NUMBER : 1168 VERSION : 3.0 OS : All DATE : October 22, 1993 PAGE : 3/8 TITLE : A temporary workaround for a failure in PXSrchFld(). - PXSrch will move the current record cursor as described for a CLOSESTRECORD search when doing a SEARCHFIRST. - A number of different error messages could be returned because of all the engine calls that occur in PXSrch that would not be returned from PXSrchFld. - A SEARCHFIRST can return PXERR_ENDOFTABLE in PXSrch, which it would not in PXSrchFld. The reason for this is to let you know when the record cursor is at the end of the table, not at the first record greater than the value that you are searching for. You can change this behavior by searching for PXERR_ENDOFTABLE and uncomment the 'return(PXERR_RECNOTFOUND) ;' statement. Limitations: ============ PXSrch will not work on composite or case insensitive indexes, where it returns PXERR_INVFIELDHANDLE (which can be at the beginning or PXSrch). There is no way for us to determine which fields are part of a composite secondary index ( or of a case insensitive index ). What is needed is a routine similar to PXSrch that knows which fields are part of your secondary index and does the manual comparison on those fields ( or use strcmpi on a case-insensitive index ). \* ---------------------------------------------------------------- */ // PXSRCH.C // Use the following as a seperate file #include #include #include #include #include "pxengine.h" // We do not want to change the calls to PXSrchFld within PXSrch. // Would cause recursive calls, hand, crash, or abort your program.. PRODUCT : Paradox Engine NUMBER : 1168 VERSION : 3.0 OS : All DATE : October 22, 1993 PAGE : 4/8 TITLE : A temporary workaround for a failure in PXSrchFld(). #undef PXSrchFld extern unsigned _stklen = 8192U; // This function is stack intensive #define SIGFIG 0.00000000000001 // How close you want the comparison // Between two Doubles #define MAXALPHASIZE 256 PXCODE PXSrch( TABLEHANDLE tblHandle, RECORDHANDLE recHandle, FIELDHANDLE fldHandle, int mode ) { PXCODE pxErr; RECORDHANDLE recHandleTemp; double numfld[2]; // Numeric and currency Data char charfld[2][256]; // Char Data short shortfld[2] ; // Short Data TDATE datefld[2] ; // Date Data char fldType[6] ; // Type of the searched for field if ( fldHandle > 255 ) // Check for composite or case-insensitive { // index. return( PXERR_INVFIELDHANDLE ); // PXSrch will not work on a // composite or a //case-insensitive index. } switch( mode ) { // we assume SEARCHNEXT to work properly case SEARCHNEXT: return( PXSrchFld( tblHandle, recHandle, fldHandle, SEARCHNEXT ) ) ; case SEARCHFIRST: case CLOSESTRECORD: // call PXSrchFld pxErr = PXSrchFld(tblHandle, recHandle, fldHandle, CLOSESTRECORD); // if success, we found the record, return if (pxErr == PXSUCCESS) return pxErr; // if not success, test to see if we found the record else PRODUCT : Paradox Engine NUMBER : 1168 VERSION : 3.0 OS : All DATE : October 22, 1993 PAGE : 5/8 TITLE : A temporary workaround for a failure in PXSrchFld(). { if ( pxErr == PXERR_RECNOTFOUND ) { #ifdef DEBUG printf("\nUsing special PXSrch operations") ; #endif pxErr = PXFldType( tblHandle, fldHandle, 6, fldType ); if (pxErr != PXSUCCESS) return pxErr; // Open a local, temporary record buffer pxErr = PXRecBufOpen( tblHandle, &recHandleTemp ); if (pxErr != PXSUCCESS) return pxErr; // Get the current record, save to new record handle pxErr = PXRecGet( tblHandle, recHandleTemp ); if (pxErr != PXSUCCESS) { PXRecBufClose( recHandleTemp ) ; return pxErr; } // do a manual comparison using the following steps: // Get the value from the passed in record buffer switch( fldType[0] ) { case 'A': if ( ( pxErr = PXGetAlpha( recHandle, fldHandle, MAXALPHASIZE, charfld[0] ) ) != PXSUCCESS ) break ; // we use break so that we only have // to do cleanup in one location if ( ( pxErr = PXGetAlpha( recHandleTemp, fldHandle, MAXALPHASIZE, charfld[1] ) ) != PXSUCCESS ) break ; // close temporary record buffer PRODUCT : Paradox Engine NUMBER : 1168 VERSION : 3.0 OS : All DATE : October 22, 1993 PAGE : 6/8 TITLE : A temporary workaround for a failure in PXSrchFld(). PXRecBufClose( recHandleTemp ) ; // strcmp() returns 0 if strings are equal if ( !strcmp( charfld[0], charfld[1] ) ) return( PXSUCCESS ) ; else return( PXERR_RECNOTFOUND ) ; case 'D': if ( (pxErr = PXGetDate( recHandle, fldHandle, &datefld[0] ) ) != PXSUCCESS ) break ; if ( (pxErr = PXGetDate( recHandleTemp, fldHandle, &datefld[1] ) ) != PXSUCCESS ) break ; PXRecBufClose( recHandleTemp ) ; // Date values are merely longs, // so do integer compare if (datefld[0] == datefld[1]) return ( PXSUCCESS); else return ( PXERR_RECNOTFOUND ); case 'N': case '$': if( ( pxErr = PXGetDoub( recHandle, fldHandle, &numfld[0] ) ) != PXSUCCESS ) break ; if( ( pxErr = PXGetDoub( recHandleTemp, fldHandle, &numfld[1] ) ) != PXSUCCESS ) break ; PXRecBufClose( recHandleTemp ) ; // Test if either value was blank // Here we are treating two blank fields as not equal if ( ( ISBLANKDOUBLE( numfld[0] ) ) || ( ISBLANKDOUBLE( numfld[1] ) ) ) PRODUCT : Paradox Engine NUMBER : 1168 VERSION : 3.0 OS : All DATE : October 22, 1993 PAGE : 7/8 TITLE : A temporary workaround for a failure in PXSrchFld(). { return( PXERR_RECNOTFOUND ) ; } // We use this method for comparing floating point // numbers because of the way floats are represented // in binary. For example, we cannot guarantee if // (.100 - .23) == .67 is going to return true because // .23 might be .2299998 as represented internally. numfld[0] = fabs(numfld[0] - numfld[1]); if ( numfld[0] < SIGFIG ) return( PXSUCCESS ) ; else return( PXERR_RECNOTFOUND ) ; case 'S': if ( ( pxErr = PXGetShort( recHandle, fldHandle, &shortfld[0] ) ) != PXSUCCESS ) break ; if ( ( pxErr = PXGetShort( recHandleTemp, fldHandle, &shortfld[1] ) ) != PXSUCCESS ) break ; PXRecBufClose( recHandleTemp ) ; if ( shortfld[0] == shortfld[1] ) return( PXSUCCESS ); else return( PXERR_RECNOTFOUND ) ; } // end switch (fldtype[0]) PXRecBufClose( recHandleTemp );// Do close in only one return( pxErr ) ; // location } // end if pxErr == PXERR_RECNOTFOUND if ( pxErr == PXERR_ENDOFTABLE ) { if ( mode == SEARCHFIRST ) { // Uncomment out the next line if you want // PXERR_RECNOTFOUND // returned by SEARCHFIRST if the cursor is left at the PRODUCT : Paradox Engine NUMBER : 1168 VERSION : 3.0 OS : All DATE : October 22, 1993 PAGE : 8/8 TITLE : A temporary workaround for a failure in PXSrchFld(). // end of the table ( PXSrchFld with the SEARCHFIRST // parameter will not return PXERR_ENDOFTABLE ). // return( PXERR_RECNOTFOUND ) ; } } return( pxErr ) ; } // end else (PXSrchFld != PXSUCCESS) } // end switch (mode) return pxErr; } // In case this code is added to the middle of an engine module #define PXSrchFld PXSrch DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.