Mertech BTR2SQL comes with a software development kit (SDK) that gives you access to extended Btrieve functionality. The SDK contains a runtime dll and migration dll for each backend (MS SQL, Oracle or PostgreSQL). The SDK also contains header files to define the constants and structures required for advanced programming and it contains detailed documentation and examples.

The BTR2SQL SDK is installed in the <Program Files>\Mertech Data Systems\DB Drivers\Btrieve\sdk directory.

The SDK documentation can be viewed in your browser by selecting the SDK shortcut in the Mertech’s ISDBC Drivers for Btrieve group of the Windows Start menu (or by opening index.html in the<Program Files>\Mertech Data Systems\DB Drivers\Btrieve\sdk\docs directory).

The SDK documentation contains:



Main Page

Overview of the SDK.


Hyperlinks to information about the types, definitions, constants, structures, and functions (grouped by category) in the SDK.

Classes: Class List

Classes, structures, unions and interfaces with brief descriptions.

Classes: Class Members

An alphabetical list of all class members with links to the classes they belong to and where they are defined.


A description of each header file in the sdk/include subdirectory.

Note: Other header files are available in the sdk/samples subdirectory.


Example code that can be viewed in the browser.

Note: Other code samples can be found in the sdk/samples directory.

Additional documentation for the SDK is provided in this chapter.

Runtime dll with extended APIs

During the migration process, you replace the Btrieve runtime dll (wbtrv32.dll or later version called w3btrv7.dll) with the Mertech runtime dll of the same name. The Mertech runtime dll codes the standard Btrieve operations (for example, B_OPEN) so that they will work with the selected SQL backend. This means your application can access the SQL backend without any changes to your existing code or BTRCALLs.

In addition to the standard Btrieve operations, the Mertech runtime dll includes extended APIs to:

How do I use the extended APIs?

The runtime dll is dynamically linked to your application when the application is loaded, so the extended APIs are automatically available and accessible just like the standard Btrieve operations through the BTRV/BTRCALL function interface. Simply use the provided constants (or the operation code) and structures defined in the mds_btrieve header. For example:

#include <mds_btrieve.h>

MDS_SQL_LOGIN loginInfo = {"WIN-P6C\\SQLEXPRESS", "btrtest", "mertech",
  "btrtest", ""};

status = BTRCALL(B_SQL_LOGIN, NULL, &loginInfo, &(dataLen=sizeof(loginInfo)), NULL, 0, 0);

Direct call interfaces are also available for some of the extended APIs. For example you can encrypt a password by calling:

#include <mds_btrieve.h>:

status = BTRCALL(B_ENCRYPT_PASSWORD, NULL databuf, &datalen, keybuf, 0, 0);

Or, you can call MdsEncryptPassword directly:

#include <mds_btrieve.h>

status = MdsEncryptPassword(password, encpw, encpwlen);

Migration dll

The migration dll (sql_btr.dll, ora_btr.dll, or pgs_btr.dll) includes all the standard and extended Btrieve functions plus functions to write your own migration interface.

How do I use the migration APIs?

In order to use the migration APIs, the migration dll must be dynamically linked at runtime using LoadLibrary and the function addresses must be obtained using GetProcAddress. This is done for you in the BtrieveFile class, which is a simple wrapper class capable of loading any dll. The BtrieveFile class is defined in BtrieveFile.h. An MS SQL code extract is shown below. For additional examples, see the samplesmigration subdirectory.

#include <BtrieveFile.h>

void useMdsMigrateOneTable()


 BtrieveFile\* pBF = new BtrieveFile("sql_btr.dll");

 MDSRESULT status;

 static const char ddfLocation[] = "c:\pvsw\demodata\";

 static const char tableName[] = "billing";

 status = pBF->MdsMigrateOneTable(ddfLocation, tableName, MDS_MIG_FULL, NULL);

} //useMigrateOneTable()

Supported Btrieve API Functions

BTR2SQL fully supports all Btrieve API functions with the exception of the functions listed below, which are not required in a relational database.

Functions that are not supported






Split an existing Btrieve data file over an additional drive. Operation is ignored, status 0 is returned.



Assign owner name and optionally encrypt Btrieve data file. Operation is ignored, status 0 is returned. Owner names can be implemented through SQL security by porting a file to a different login.



Clear owner name for a Btrieve data file. Operation is ignored, status 0 is returned.



Place the specified file in or remove the file from continuous operation mode, for use in system backups. Operation is ignored, status 0 is returned.



Login to a Btrieve database.

Operation is not supported, returns B_INVALID_FUNCTION(1).

The BTR2SQL sdk has a new API, B_SQL_LOGIN (10015), to login to an SQL server.



This operation bias code is ignored.

Additional MDS status codes

MDS_errGeneric = 18000 ///Unknown
MDS_errNotLoggedIn = 18001
MDS_errTableNotFound = 18002
MDS_errInvalidTableName = 18003
MDS_errInvalidColumnNumber = 18004
MDS_errInvalidColumnName = 18005
MDS_errInvalidDataType = 18006
MDS_errDuplicateColumnName = 18007
MDS_errInvalidDataSize = 18008
MDS_errInvalidColumnOrder = 18009
MDS_errInvalidIndexName = 18010
MDS_errStringTooShort = 18011
MDS_errDirectoryError = 18012
MDS_errDuplicateTable = 18013
MDS_errISRNotSupported = 18014
MDS_errInvalidDatabaseName = 18015
MDS_errXmlMissingElement = 18016 ///< Required Element missing from XML
MDS_errXmlMissingAttribute = 18017 ///< Required Attribute missing from XML
MDS_errXmlIncorrectDriver = 18018 ///< XML indicated an incorrect driver target
MDS_errXmlInvalidValue = 18019 ///< Invalid value for an XML attribute

Extended DDF Data Types

Btrieve natively supports about 28 basic data types. fieldext.ddf was introduced to augment this list and support a number of other interesting types. BTR2SQL reads this information and makes a wiser choice for the type used in SQL. For instance, in addition to the standard B_DATE type, there are several Julian based date formats and dates in various string forms. All of these are migrated to a real DATE type in SQL instead of a generic string or integer as defined in field.ddf. Pervasive’s pedtconv.dll is utilized to do the data conversions. This dll can be found in the Pervasive SDK downloaded from their website.

  • See also SDK documentation: Modules tab > Btrieve Types


The B_CREATE syntax was expanded so your application can provide the name of a pre-existing INT file to use as a pattern when creating a new table on the SQL server.


The original B_CREATE syntax is:

status = BTRCALL(B_CREATE, NULL dataBuffer, &dataLength, keyBuffer, 0, 0);

Where keyBuffer is <filename>

The only information available to the driver for creating a new file was the filename and indexes. The driver had to examine the indexes to determine there was a field of a particular data type and size at some specific offset in the record. However, the driver could not determine the names of all of the fields, so you might end up with a table such as:

CREATE TABLE cust1_dat (mds_field1 int, mds_filler1 binary(10), mds_field2
varchar(50), mds_filler2 binary(500))

Auto template option

B_CREATE was later expanded to make use of an existing int file (

When an application issues a B_CREATE, if an INT file already exists for the file, the driver compares its contents with the index definitions in the new create structure. If they match, the driver uses the definition in the INT file to create the table on the server. If the INT file does not look compatible, it is ignored and you are stuck with the MDS_FIELDx and MDS_FILLERx field names.

Several flags control the way the auto template option works. The ‘flag’ becomes the keyNumber for the operation.




Overwrite the existing table; ignoring the definition in the existing INT file



Overwrite the existing table; force usage of the existing INT file (ignore FILESPEC in databuffer)



Do not overwrite the existing table; force usage of existing INT file (ignore FILESPEC in dataBuffer)


The B_CREATE syntax using the auto template option is:

status = BTRCALL(B_CREATE, NULL dataBuffer, &dataLength, keyBuffer, keyNumber, 0);

Where keyNumber is one of the above flags.

INT File template option

The latest enhancement to B_CREATE expands the contents of keyBuffer to include the new filename (as before), the template filename, and the table name to be created on the server. Now you can specify an INT file for an existing file that has a pattern you want to use to create the new file. For example you can create bar.btr with the same structure (but different table name) as foo.btr.

The new B_CREATE syntax is:


status = BTRCALL(B_CREATE, NULL dataBuffer, &dataLength, keyBuffer, keyNumber, 0);

Where keyNumber dataBufferis one of the above flags and keyBuffer is:

<filename> \| <template filename> \| <table name>

If a pipe character ( ‘|’ ) appears in the keyBuffer, <template filename> is assumed to be the next (required) string. The second pipe and <table name> are optional. If not included, the driver defaults to filename_ext for the table name.

A space on either side of the pipe is ignored. Quotes around any sub-string are removed. Quotes around the entire string are not supported. Quotes on the interior of any sub-string causes an invalid filename error.

All forms of filenames are supported for both the filename and template parts of the string. This includes just a filename (relative to the “current directory”), current directory relative paths (.pathfilename or ..pathfilename), root relative paths (pathfilename), full paths (c:datafilename) and UNC paths (serversharepathfilename).


  • An INI file in the folder where the template filename is specified is read. So it is possible for the template INT file to be in a different folder than what is directly specified for the template file.

  • If the template filename does not exist, a status 12 is returned.

  • A new INT file is created for the new filename with contents that match the template INT but using the new table name.

  • If the new filename INT exists when the create call is made, it is ignored/erased and the template INT is used just as if the new file INT had not been there.

  • If the new filename INT exists and is marked as Permanent, a FileAlreadyExists error is returned.

  • The template INT should be marked as Permanent.

Example 1

Your Magic (or non-Magic) application has a DB table “custmain.mcf” with table name “Customers Main”. Custmain.mcf exists in C:MyAppData and C:MyAppDatamds.ini has an entry: INT-Folder=..intfiles

During migration to SQL, table “Customers Main” and are created.

The application later wants to access a new customer table with the same definition as “Customers Main”. C:MyAppData is the current folder at runtime.

1. The application opens ‘cust1.dat | custmain.mcf | Cust – John Smith’.

2. does not exist so the driver returns status 12.

  1. Magic then issues a B_CREATE passing the same path string as before.

4. The driver reads into the usual internal file classes and updates the table name to “Cust – John Smith” and the physical name to “cust1.dat”.

5. The driver then issues a call to Create Table to on SQL backend, creates, and returns success.

  1. Magic reissues the open and continues successfully.

Example 2

You can also use this new B_CREATE option in a multi-xxx (company, customer, site, etc.) environment where you utilize the same schema in multiple folders (one for each customer for instance).





      intfiles_mssql(all files marked as Permanent and OS Read/Only attribute set)

      intfiles_ora(all files marked as Permanent and OS Read/Only attribute set)


        mds.ini(says intfiles=..intfiles_mssql and ..intfiles_ora, prefix=cust1_)


        mds.ini(says intfiles=..intfiles_mssql and ..intfiles_ora, prefix=cust2_)


        mds.ini(says intfiles=..intfiles_mssql and ..intfiles_ora, prefix=cust3_)

When either B_OPEN or B_CREATE references one of the customer files (for example, “c:myappdatacust1people.btr”), the driver looks at the INI file to determine where the INT files are located and then opens the INT file for the required server type (for example, “”).

So, rather than having thousands of INT files in each of the customer folders (all having the same contents), the INI file directs the driver to a common location for the INTs.

Creating temporary files

When the EOY Report is generated, various data is collected into a temporary file. The definition for this table, ReportTemplate.mkd, is in the DDFs. Use the Migration Utility to generate the corresponding INT file,

When the application executes a B_CREATE(“eoyreport_2014090901011545.mkd | ReportTemplate.mkd | EOYReportData_2014090901011545″), the Mertech driver reads, creates a new table EOYReportData_2014090901011545 and generates a new INT file,

Later, when B_DROP_TABLE is called, the INT file and the table on the SQL backend are removed.

Avoid OS calls

Some applications manipulate the data files directly with OS calls by copying an existing data file and deleting the file when done. These direct operations are not supported by the drivers. Instead, you must fully rely on the B_CREATE API to create the temporary table and B_DROP_TABLE to remove the table when it is no longer needed.

Multi-user scenarios

Extra precaution must be taken to avoid multiple processes from using the same temporary file simultaneously. With Btrieve, the temp file could be created locally and thus each client could have a dedicated file. Now that the table is created in a shared SQL resource, multiple clients have access to the same table.

Several options are available to avoid this problem.

  • Assign a globally unique filename (like a timestamp or guid for the filename) each time a temp table is created. This option does not use an INT file as the template for creating the table.

  • Create the INT file for the temporary file. Then, use the extended B_ CREATE syntax to specify a new filename each time a temporary table is created (see examples under the B_CREATE API).

  • Create the INT file for the temporary file. Assign each installation a dedicated prefix (e.g. Region1, Region2, Region3) or postfix. Make a copy of the temp file for each installation and add the assigned prefix (e.g., INT) or postfix to the file. Then, restrict each region to using the assigned filename (e.g., Region1_Temp) in B_CREATE calls (see examples under the B_CREATE API).

NOTE: In all cases, make sure to use the B_DROP_TABLE API to delete stale temp tables.

Access rights

SQL administrators can be very strict when assigning access rights to users. For example, they may insist that users do not have Create Table permission. Without Create Table permission, users cannot create temporary files on the server.

One solution to this problem is to assign a different login for temporary tables. The main application data can be accessed under a login that has Read/Write access. The temporary data can be accessed under a login that does not have access to the main data but does have Create Table permission.

The easiest way to assign a different login for temporary tables is to place the temporary files in a separate directory and setup the mds.ini file in that folder to use the assigned login.

Main Data Files Directory: C:\MyApp\DATA

mds.ini (UseTrustedConnection=no, User=mydomain\me, Password=b7fba9c0e1b0f217)





Temporary Files Directory: C:\MyApp\TEMP

mds.ini (UseTrustedConnection=no, User=mydomain\temp, Password=9dc42401d47a3fd0)




NOTE: A user name and password stored in an INT file override settings in the mds.ini file.

SQL Login and Direct Query Execution

The Embedded SQL API can be used to run SQL Queries directly to the SQL backend. The advantage of using the Embedded SQL API together with the regular BTRCALL API instead of technologies such as ADO is that no new connection to the server is opened. This also allows for the nesting of embedded SQL commands together with standard BTRCALL functions in the same transaction.

All string data should be passed and will be returned as null terminated strings.

  • See also SDK documentation: Modules tab > SQL Login and Direct Query Execution


Retrieves or sets the maximum number of open cursors in use by the driver. A higher number of cursors allow the driver to cache a lot of queries into open tables, but leads to higher resource usage on the server.


Opens a new cursor that is used to execute commands. The position block parameter contains a handle to the cursor.


Closes a previously opened cursor.


Prepare SQL Statement for execution.


Execute a (previously prepared) SQL statement.

B_SQL_FETCH (10005)

Fetch the next row from a previously executed query. If there are no more rows, then the return value is zero.

B_SQL_BIND (10006)

Binding parameters are used in conjunction with other queries with parameters (queries such as ‘SELECT * FROM CUSTOMER WHERE CUSTOMER_ID = ?’). The query is prepared once and can then be executed multiple times by repeatedly rebinding (by calling B_SQL_BIND) and re-executing it (by calling B_SQL_EXECUTE). If there are multiple parameters in the query, then call B_SQL_BIND once for each parameter in order before calling B_SQL_EXECUTE. This process can then be repeated again, with calls to B_SQL_BIND, followed by a new call to B_SQL_EXECUTE).


Returns (as the return code) the number of columns in the most recently executed query.


Get number of rows returned from the previously executed SQL statement. In certain cases, the number of rows cannot be determined in advance, whereby the return value is zero.


Retrieves the name and size of a given column in a result set from a previously executed query. The name is returned in the dataBuffer and the size is the return value of the function.


Returns the data in a column in the current row. All fields are returned as strings.


Starts a transaction in the database.

B_SQL_COMMIT (10012)

Commits a previously started transaction.


Aborts a previously started transaction, rolling back any changes done since the start of the transaction.


Returns the native SQL error for the last failed operation.

B_SQL_LOGIN (10015)

Programmatically login to an SQL Server to suppress the popup login dialog box. The format of the login structure is:

char server[30];
char username[30];
char password[30];
char database[30];
char schema[30]; /\* only used by B_SQL_GET_LOGIN \*/

If the UserName and Password members are zero-length strings, trusted connections will be used in MS SQL Server.

B_SQL_LOGOUT (10016)

Programmatically logs out from an SQL Server. If no server name is provided, then a logoff will be sent to all of the servers to which the driver is currently connected.


Retrieve the login information for the file identified.

For the given file, return the Server, Database name, User name and password used to login with. This information could have originally come from the .INT, .INI, save information in the registry, or from the Login dialog box.

_SQL_ATTACH (10018)

Attach a database to a current SQL Server instance.

B_SQL_DETACH (10019)

Detach a database from a current SQL Server instance.


Create a new LocalDB instance.


Remove a LocalDB instance.


Return the localized description for a LocalDB error. Use this function to retrieve the error details when a B_SQL_LDB_ call fails


Get information for a LocalDB instance, such as whether it exists, version information, whether it is running, and so on.


Return all the LocalDB instances with a specified version.


Return information for a specified LocalDB version.


Return all LocalDB versions available on a computer.


Share a specified LocalDB instance.


Start a specified LocalDB instance.


Enable API tracing for a user.


Stop a specified LocalDB instance from running.


Disable API tracing for a user.


Stop sharing a specified LocalDB instance.

Fast Inserts

The Fast Insert APIs allow an application to use native SQL backend functionality to get data into a table as fast as possible. They also allow a full 32-bit data buffer to support variable length records (normally containing Note or BLOB data) which usually require Chunk operations after the B_INSERT.

  • See also SDK documentation: Modules tab > Fast Inserts

Inserting variable length data

If the table has variable length records then there are three options for delivering the variable portion:

  1. The entire record is in memory in one structure (no matter the size). Pass the entire structure to the B_FAST_INSERT with appropriate dataLength. Set the keyBuffer to NULL. This is the fastest method.

  2. Variable data still needs to be read and the length is known. Pass a pointer to a callback routine in callBack and length of the “BLOB” in chunkDataLen.

  3. Variable data is not in memory; the length is not yet known Pass a 0 in the chunkDataLen value and allow the chunk callback to dynamically read the data during the Fast Insert.

If the application does not want to submit all variable length data together with the fixed portion in B_FAST_INSERT (option 1), pass an MDS_FAST_INSERT structure in the key buffer, and set the key buffer length to the size of the structure. The values of the structure are shown in options 2 and 3.

The callback function is repeatedly called to allow the application to fill up the variable data portion of the record. The function should return the number of bytes of variable data it has copied into the “data” parameter each time, or zero to indicate completion.


Begin Fast Insert Mode.


Specify the bulk copy batch parameters in the MDS_FAST_INSERT_MSSQL structure.


  long batchSize; // Number of rows per transaction
  long kbytesPerBatch;// Kilobytes Sent per Batch
  long rowsPerBatch; // Rows Sent per Batch
  long indexOrder; // Btrieve index number data is ordered by
  bool lockTable; // Table will be locked with TABLOCK if True
const long NoIndexOrder = -1;

NOTE: Only FastInserts operations should be performed until the EndFastInsert is complete. Regular B_Insert operations may produce unpredictable results.


Insert a record in Bulk / Fast mode.


typedef void (__stdcall \*MDS_CHUNKCALLBACK)
(CHAR*\* data, LONG\* size);

   MDS_CHUNKCALLBACK callBack; // Callback function for retrieving
 variable length portion of record (chunks)
   long chunkDataLen; // Known Length of variable portion (chunk)


Stop Fast Insert mode and commit new data to the database.

Driver Trace Control

Several functions are available to control the trace output and allow the application to add information to the trace.

  • See also SDK documentation: Modules tab > Driver Trace Control


Enable tracing and define the filename and level of information.


Retrieve current settings of trace file.


Start tracing (after perhaps pausing it for a while).


Pause the trace output.

B_TRACE_MSG (5042)

Send a message or comment to the trace file.

Schema Functions (DTI Function Support)

Sometimes an application needs to add new tables to the database or modify existing tables or other changes to the schema. Pervasive.SQL provided the Distributed Tuning Interface (DTI) for this purpose. BTR2SQL introduces similar APIs. All are found in mds_btrieve.h.

  • See also SDK documentation: Modules tab > Schema Functions


MDSRESULT                        const char *      lpszName

Establish the current database. This function sets the current database in the SQL Server.


                                  MDS_COLUMNMAP  *  columnList,
                                  WORD              columnCount

Create a new table in the server as well as set up the definition file (.int).

NOTE: Index creation is handled through the regular Btrieve API B_BUILD_INDEX.


MDSRESULT MdsAddFields(         const char  *     fileLocation,
                                MDS_COLUMNMAP  *  columnList,
                                WORD              columnCount

Add new fields to the end of an existing table and update the definition files on the client.


MDSRESULT MdsGetFileInfo(          const char  *      fileLocation,
                                   const bool         IncludeSqlData,
                                   MDS_TABLEINFO  *   tableProps,
                                   MDS_COLUMNMAP  *   columnList,
                                   WORD               columnCount

Add new fields to the end of an existing table and update the definition files on the client.

Renaming tables and files

The following APIs are available to rename files and tables.

NOTE: All of the parameters (except table name in MdsRenameTable) reference the originally named Btrieve data filename, NOT the INT filename. So, when you issue a request to rename “Billing.mkd” (which does not actually exist), the driver actually renames


MDSRESULT MdsRenameTable(             const CHAR  *       fileLocation,
                                      const CHAR  *       newTableName

Rename an existing table on the server as well as the definition file (.INT) on the client. For example, the following code renames table “receipts_2014” to “2014 Receipts” on the server and updates the TABLE_NAME in the receipts_2014_mkd.INT file.

char oldFileName[] = "receipts_2014.mkd";
char newTableName[] = "2014 Receipts";
MdsRenameTable (oldFileName, newTableName);


MDSRESULT MdsRenameFile(         const CHAR  *    fileLocation,
                                 const CHAR  *    newTableName

Rename the local data file (i.e., the INT file).  Use MdsRenameTable and MdsRenameFile together to accomplish both. For example, the following code renames file “receipts_2014_mkd.INT” to “2014 Receipts_mkd.INT”.

FileName[] = "receipts_2014.mkd";

char newFileName[] = "2014 Receipts.mkd";

MdsRenameFile (oldFileName, newFileName);


B_RENAME_FILE is also available; it is a subfunction of B_CREATE. B_RENAME_FILE renames the local data file (i.e., the INT file). For example, the following code renames file “receipts_mkd.INT” to “receipts_2014_mkd.INT”.

#define `B_RENAME_FILE  (B_CREATE) // = 14
#define B_KEY_RENAME_FILE = -127

char oldFileName[] = "receipts.mkd";

char newFileName[] = "receipts_2014.mkd";

strcpy(databuf, oldFileName);

strcpy(keybuf, newFileName);

BTRCALL(\ `B_RENAME_FILE <file:///C:\Program%20Files%20(x86)\Mertech%20Data%20Systems\DB%20Drivers\Btrieve\sdk\docs\group___mds_header.html#gb7d407fd5c937f583f9c5814ac6e230d>`__, posBlock, databuf, &datalen, keybuf, B_KEY_RENAME_FILE);

In summary

Renames Server Table

Renames Local Data File (the INT file)










Deleting tables and files


MDSRESULT               const CHAR  *   fileLocation
MdsDropTable(           )

Delete an existing table on the server and remove the definition file (.INT) on the client. The .INT is not removed if it has PERMANENT_INT set to YES. For example, the following code removes the “Billing” table.

MdsDropTable ("Demodata\\Billing.mkd")


MDSRESULT           const CHAR  *    fileLocation
MdsDeleteFile(      )

Delete the local INT file (call after using MdsDropTable). For example, the following code deletes the “Billing_mkd.INT” file “.

MdsDeleteFile ("Demodata\\Billing.mkd")


Drop the SQL table and remove the INT file. If present, the actual MicroKernel file and the definition in the DDFs (or XML source files) remain.

NOTE: To prevent an INT file from being deleted when a table is dropped, you can set the PERMANENT_INT token in the INT file to YES (the default setting is NO). This is useful if for example, you want to drop and then later recreate a file using the same structure.

#define `B_DROP_FILE (B_OPEN + 3000)

char FileName[] = "receipts.mkd";

strcpy(keybuf, FileName);



B_DELETE_FILE is also available; it is a subfunction of B_CREATE. It drops the SQL table and deletes the INT file.

#define `B_DELETE_FILE  (B_CREATE) // = 14

#define B_KEY_DELETE_FILE = -128

char FileName[] = "receipts.mkd";

strcpy(databuf, FileName);

BTRCALL(\ `B_DELETE_FILE <file:///C:\Program%20Files%20(x86)\Mertech%20Data%20Systems\DB%20Drivers\Btrieve\sdk\docs\group___mds_header.html#gb7d407fd5c937f583f9c5814ac6e230d>`__, posBlock, databuf, &datalen, NULL, B_KEY_DELETE_FILE);

In summary

Renames Server Table

Renames Local Data File (the INT file)













Truncating files


Truncate file (delete all records).

#define `B_TRUNCATE_FILE  (B_OPEN + 2000)

char FileName[] = "receipts.mkd";


strcpy(keybuf, FileName);


Migration Functions

If you would like to write your own interface or have more control over migrating files from Btrieve to SQL, you can use these migration functions. They make it easy to migrate the entire database in one call, migrate certain tables with different settings, or migrate one table at a time.

  • See also SDK documentation: Modules tab > Migration Functions


MDSRESULT MdsPrepareDB (            const char*           ddfLocation,
                                    const char*           tableName,
                                    MdsMigrationControl   whatToDo,                                                   whatToDo,
                                    const char*           xmlConfig,
                                    MDS_MIGCALLBACK       callback

Setup the server and/or database with needed objects for running your Btrieve application. Depending on the server, create stored procedures, views, etc. as needed to properly support the Mertech driver. Generally, the Mertech driver will not be able to function correctly until the server and specific database have been initialized with a few objects. This is normally done by the migration tool. This API needs to be called before running the application.


MDSRESULT MdsMigrateOneTable(       const char*             ddfLocation,
                                    const char*             tableName,
                                    MdsMigrationControl     whatToDo,
                                    const char*            xmlConfig,
                                    MDS_MIGCALLBACK         callback

Migrate a table from Btrieve to SQL.


MDSRESULT MdsMigrateAllTablesInDdfs(                const char*               ddfLocation,
                                                    MdsMigrationControl       whatToDo,
                                                    const char*               xmlConfig,
                                                    MDS_MIGCALLBACK           callback

Migrate a database from Btrieve to SQL.


MDSRESULT MdsMigrateAllTablesInConfig(              const char*               ddfLocation,
                                                    MdsMigrationControl       whatToDo,
                                                    const char*               xmlConfig,
                                                    MDS_MIGCALLBACK           callback

Migrate multiple tables from Btrieve to SQL.

Additional Btrieve APIs

These additional APIs augment the standard Btrieve API and are implemented in the same manner – utilizing the familiar BTRV() or BTRCALL() functions. A direct call interface is also available for some of the APIs.

  • See also the SDK documentation: Modules tab > Extended Btrieve API, Modules tab > Version Information¸ Modules tab > Choosing Fields to Fetch

B_ENCRYPT_PASSWORD (3005) )**or **MdsEncryptPassword

const MDSRESULT MdsEncryptPassword      char *           password,
                                        char *           encryptpwd,
                                        unsigned short   encryptpwdlen

Encrypt a password for usage in an mds.INI file

B_SET_MDS_OPTION (3017) )**or **MdsSetOption

const MDSRESULT MdsSetOption(          unsigned short   option,
                                       * char *         value

Set the value of an option specific to the BTR2SQL driver (deprecated, use MdsSetSetting)


const MDSRESULT MdsSetSetting (       char *             foldername,

                                      char *             settingname,
                                      char *             values

Set a global or folder-specific value for an option for the current BTR2SQL driver.


const MDSRESULT MdsGetSetting(            char *             foldername,

                                          char *             settingname,
                                          char *             values

                                          unsigned short    valueSize

Retrieve the value of an option for the current BTR2SQL driver.


const MDSRESULT MdsGetError(            char *            errorDesc,
                                        WORD*           size

Retrieve the last error message. This function can be called to retrieve a detailed error message (usually the message generated by the database server) after an error code has been received from an operation.


Used to determine whether or not a file has been migrated to an SQL Backend.

NOTE: This function does not verify the existence on the server or validity of the table. It simply indicates that the Btrieve file was migrated (the .INT file exists). It is possible that the SQL table may have been removed.

B_FAST_STAT (5015)

This is the same as a B_STAT(15) except the record count is not returned.

B_STAT is a common operation to perform after the B_OPEN — especially for Btrieve class wrappers. The operation usually includes the current record count for the file. Obtaining the number of rows in a table in SQL is a relatively slow process. So, if the application does not need this extra piece of information, utilize the B_FAST_STAT instead.


Retrieve information about the Mertech driver or attached SQL backend.

The Extended Version function can do two things: retrieve information about the Mertech driver (version, dll name, etc.) or retrieve a version string from the active SQL server. Making this call against the Pervasive access dll causes a return code of 1. So this is a useful way to know if your application is running against a Btrieve or a SQL backend.


Control which fields are retrieved from the server.

This is very useful for performance especially for large records. This API allows the application, without dealing with GetExtended buffers, to narrow the list of fields that are retrieved from the server.

Accessing Both Btrieve and SQL Backends

Consider the following scenario. During the migration process, some files are left in Btrieve, while others are migrated to an SQL backend. This could be an interim step during the migration process to test the migration. Or, a decision may have been made to leave private tables in Btrieve on the local machine, while common tables are stored on a central SQL Server. The Mertech drivers support this scenario.

Rather than replacing the Pervasive dll with the Mertech dll of the same name, an application needs to load Pervasive’s wbtrv32.dll and one of the Mertech migration dlls (sql_btr.dll, ora_btr.dll, or pgs_btr.dll ) to simultaneously access the Btrieve and SQL backend.

Load the required Mertech dll (MS SQL in the example). Then, declare a function to be called in place of BTRCALL when accessing the MS SQL backend. For example:

#include <BtrieveFile.h>

// Load Pervasive's Btrieve access dll

BtrieveFile\* btrieve = new BtrieveFile("w3btrv7.dll");

// Load Mertech's MicrosoftSQL library

BtrieveFile\* mssql = new BtrieveFile("sql_btr.dll");

// Open an old Btrieve file

bStat = btrieve->BTRCALL(B_OPEN, NULL, &(datalen=0), FILE_NAME, MAX_KEY_BUF_SIZE, 0);

// Open a Btrieve file migrated to MSSQL

bStat = mssql->BTRCALL(B_OPEN, NULL, &(datalen=0), FILE_NAME2, MAX_KEY_BUF_SIZE, 0);

By loading the different dlls explicitly, the application is able to access the BTRCALL function from each; providing access to both Pervasive Btrieve files and SQL-migrated files.

You can also use this same method to access multiple SQL backends. For example, load the sql_btr.dll and the ora_btr.dll to simultaneously access MS SQL and Oracle backends.

Note: The INT files that are produced during migration are specific to each SQL backend so you will need to create a folder for each backend and provide an MDS.INI (sample in the SDK) that specifies the INT-Folder location and login information for each server.

Visual Basic Linking:

For MS SQL Server:

Declare Function **BTRCALL_MSSQL** Lib "sql_btr.dll" Alias "BTRCALL" (ByVal OP, ByVal Pb$, Db As Any, DL As Integer, ByRef Kb As Any, ByVal Kl, ByVal Kn)As Integer

For Oracle:

Declare Function **BTRCALL_Oracle** Lib "ora_btr.dll" Alias "BTRCALL" (ByVal OP, ByVal Pb$, Db As Any, DL As Integer, ByRef Kb As Any, ByVal Kl, ByVal Kn)As Integer

For PostgreSQL:

Declare Function **BTRCALL_PGSQL** Lib "pgs_btr.dll" Alias "BTRCALL" (ByVal OP, ByVal Pb$, Db As Any, DL As Integer, ByRef Kb As Any, ByVal Kl, ByVal Kn)As Integer

With these additional definitions, the application can call the original BTRCALL() function to access Btrieve as well as for example BTRCALL_ORACLE () to access an Oracle backend.