Ready to get started?

Learn more about Sage US Connectivity Solutions

Learn More

Work with Sage US Data in FoxPro

Load Sage US data into a FoxPro database. This article includes full code and a walk-through of the process.

The CData ODBC Driver for Sage US enables you to access Sage US data using the ODBC standard. You can use the CData ODBC Driver for Sage US to integrate Sage US data into your FoxPro project. The procedure below provides a walk-through of the included code sample, which saves Sage US data into tables in a FoxPro database.

Connect to Sage US as an ODBC Data Source

If you have not already, first specify connection properties in an ODBC DSN (data source name). This is the last step of the driver installation. You can use the Microsoft ODBC Data Source Administrator to create and configure ODBC DSNs.

NOTE: Set the 'Map To WVarchar' connection property to FALSE (FoxPro uses the ODBC W API and returns the WCHAR for the value type).

The Application Id and Company Name connection string options are required to connect to Sage as a data source. You can obtain an Application Id by contacting Sage directly to request access to the Sage 50 SDK.

Sage must be installed on the machine. The Sage.Peachtree.API.dll and Sage.Peachtree.API.Resolver.dll assemblies are required. These assemblies are installed with Sage in C:\Program Files\Sage\Peachtree\API\. Additionally, the Sage SDK requires .NET Framework 4.0 and is only compatible with 32-bit applications. To use the Sage SDK in Visual Studio, set the Platform Target property to "x86" in Project -> Properties -> Build.

You must authorize the application to access company data: To authorize your application to access Sage, restart the Sage application, open the company you want to access, and connect with your application. You will then be prompted to set access permissions for the application in the resulting dialog.

While the compiled executable will require authorization only once, during development you may need to follow this process to reauthorize a new build. To avoid restarting the Sage application when developing with Visual Studio, click Build -> Configuration Manager and uncheck "Build" for your project.

Connect and Transfer

To get started, add the code sample to a new project. You can execute the following command to save all tables without displaying them:

DO C:\Temp\sqldump.prg WITH "CData Sage50US Source", "TESTDB", .f.

Below is the process that the program follows:

  1. Create a new FoxPro database.
  2. Open a connection to Sage US data with the line below:

    m.hSQLconnection = SQLCONNECT(m.cODBCDSN)
  3. If the connection was successful, you can now retrieve the list of tables using the SQLTABLES function. The code below saves the list of tables in sys_tables.dbf:

    WAIT WINDOW "Fetching tables for data source '" + m.cODBCDSN + "'..." NOWAIT NOCLEAR m.nSQLTABLES = SQLTABLES(m.hSQLconnection) IF lUseDistinctConnections WAIT WINDOW "Closing ODBC Connection for data source '" + m.cODBCDSN + "'..." NOWAIT NOCLEAR SQLDISCONNECT(m.hSQLconnection) m.hSQLconnection = 0 * SQLCONNECT needs to be called again ENDIF IF m.nSQLTABLES > 0 * create local table containing list of tables in db COPY TO (m.cImportData + "sys_tables") USE * convert each table to DBF USE (m.cImportData + "sys_tables") ALTER TABLE DBF("sys_tables") ; ADD COLUMN records i ; ADD COLUMN dbfname m
  4. Scan over each table, saving it to a DBF file. The function ODBCtoDBF stores the table in a DBF file and then opens a grid if the lBrowse parameter is set to true: FUNCTION ODBCtoDBF (cTableName as String, cTableType as String, lBrowse as Logical, lhSQLConnection as Integer) WAIT WINDOW ; "Converting " + m.cTableType + ' "' + m.cTableName + '" to DBF...' ; NOWAIT NOCLEAR ACTIVATE SCREEN * strip characters incompatible with FoxPro out of the name of the DBF file m.cTableAlias = "" m.nTableNameLen = LEN(m.cTableName) m.nTableNameStart = 1 FOR m.nTableNameStart = 1 TO m.nTableNameLen m.cCharacter = SUBSTR(m.cTableName, m.nTableNameStart, 1) IF !ISALPHA(m.cCharacter) .and. (m.nTableNameStart = 1 .or. !ISDIGIT(m.cCharacter)) m.cTableAlias = m.cTableAlias + "_" ELSE m.cTableAlias = m.cTableAlias + m.cCharacter ENDIF ENDFOR m.cFromTable = m.cTableName m.cTempViewAlias = m.cTableType + "_" + m.cTableAlias LOCAL loException as Exception LOCAL lnResultSets TRY * run query m.lnResultSets = SQLEXEC(m.lhSQLConnection, ; "SELECT * FROM " + m.cFromTable, ; m.cTempViewAlias, ; aSQLResult) IF m.lnResultSets#1 SET STEP ON ENDIF ACTIVATE SCREEN CATCH TO m.loException ACTIVATE SCREEN ? "Error opening " + m.cTempViewAlias + ":" ? m.loException.Message ? m.loException.Details ENDTRY IF !USED(m.cTempViewAlias) RETURN ENDIF * copy records from view cursor to disk SELECT * FROM (m.cTempViewAlias) ; INTO TABLE (m.cImportData + m.cTableAlias) IF USED(m.cTableAlias) ACTIVATE SCREEN FLUSH && flush the buffer to write the data to disk IF m.lBrowse * pop the table up on screen SELECT (m.cTableAlias) BROWSE NORMAL NOMODIFY NOWAIT ACTIVATE SCREEN ELSE * close on-disk table for now USE IN (m.cTableAlias) ACTIVATE SCREEN ENDIF ENDIF IF USED(m.cTempViewAlias) USE IN &cTempViewAlias && close SQL view ACTIVATE SCREEN ENDIF WAIT CLEAR ENDFUNC
  5. You can now save tables of Sage US data as DBF files.

Below is the full code, in FoxPro 9 syntax:

PARAMETERS cODBCDSN, cDatabaseName, lBrowseAfterConvert * cODBCDSN The ODBC data source name, used for the name of the folder where the DBF tables are stored. * cDatabaseName The name of the FoxPro database to use. This database is created if it does not exist. The default is DATABASE_NAME. * * lBrowseAfterConvert If ".t." display each table with the BROWSE command after importing it. If ".f." close each table before moving on to the next one. #define ODBC_DATASOURCE "DataSourceName" #define DATABASE_NAME "odbcdata" m.m_tpath = ".\" && root directory for data ON ERROR SET SAFETY OFF IF VARTYPE(m.cODBCDSN)#"C" .or. EMPTY(m.cODBCDSN) m.cODBCDSN = ODBC_DATASOURCE ENDIF IF VARTYPE(m.cDatabaseName)#"C" .or. EMPTY(m.cDatabaseName) m.cDatabaseName = DATABASE_NAME ENDIF m.cImportData = m.cODBCDSN + "\" CLOSE TABLES ALL CLOSE DATABASES ALL IF !DIRECTORY(m.cImportData) MKDIR (m.cImportData) ENDIF CREATE DATABASE (m.cDatabaseName) CREATE CONNECTION (m.cDatabaseName) DATASOURCE (m.cODBCDSN) DATABASE (m.cDatabaseName) WAIT WINDOW "Opening ODBC Connection for data source '" + m.cODBCDSN + "'..." NOWAIT NOCLEAR m.hSQLconnection = SQLCONNECT(m.cODBCDSN) IF m.hSQLconnection > 0 * Connection successful; get list of tables WAIT WINDOW "Fetching tables for data source '" + m.cODBCDSN + "'..." NOWAIT NOCLEAR m.nSQLTABLES = SQLTABLES(m.hSQLconnection) IF m.nSQLTABLES > 0 * Create local table containing list of tables in db COPY TO (m.cImportData + "sys_tables") USE * Convert each table to DBF USE (m.cImportData + "sys_tables") ALTER TABLE DBF("sys_tables") ; ADD COLUMN records i ; ADD COLUMN dbfname m SCAN m.cCurrentTable = TRIM(sys_tables.table_name) m.cCurrentTableType = TRIM(sys_tables.table_type) && Valid values are "SYSTEMTABLE", "TABLE", and "VIEW". IF m.cCurrentTableType = "TABLE" or m.cCurrentTableType = "VIEW" ODBCtoDBF(m.cCurrentTable, m.cCurrentTableType, m.lBrowseAfterConvert, m.hSQLConnection) ELSE ACTIVATE SCREEN ? "ERROR:", m.cCurrentTable, "Couldn't open ODBC connection." =MESSAGEBOX("couldn't open data source " + m.cODBCDSN + " for table " + m.cCurrentTable + ".") ENDIF ENDSCAN BROWSE NORMAL NOWAIT ELSE =MESSAGEBOX("No tables found in data source " + m.cODBCDSN + ".") SET STEP ON ENDIF SQLDISCONNECT(m.hSQLconnection) ELSE =MESSAGEBOX("Could not open data source " + m.cODBCDSN + ".") SET STEP ON ENDIF FUNCTION ODBCtoDBF (cTableName as String, cTableType as String, lBrowse as Logical, lhSQLConnection as Integer) WAIT WINDOW ; "Converting " + m.cTableType + ' "' + m.cTableName + '" to DBF...' ; NOWAIT NOCLEAR ACTIVATE SCREEN * Strip characters incompatible with FoxPro out of the name of the DBF file m.cTableAlias = "" m.nTableNameLen = LEN(m.cTableName) m.nTableNameStart = 1 FOR m.nTableNameStart = 1 TO m.nTableNameLen m.cCharacter = SUBSTR(m.cTableName, m.nTableNameStart, 1) IF !ISALPHA(m.cCharacter) .and. (m.nTableNameStart = 1 .or. !ISDIGIT(m.cCharacter)) m.cTableAlias = m.cTableAlias + "_" ELSE m.cTableAlias = m.cTableAlias + m.cCharacter ENDIF ENDFOR m.cFromTable = m.cTableName m.cTempViewAlias = m.cTableType + "_" + m.cTableAlias LOCAL loException as Exception LOCAL lnResultSets TRY * Run query m.lnResultSets = SQLEXEC(m.lhSQLConnection, ; "SELECT * FROM " + m.cFromTable, ; m.cTempViewAlias, ; aSQLResult) IF m.lnResultSets#1 SET STEP ON ENDIF ACTIVATE SCREEN CATCH TO m.loException ACTIVATE SCREEN ? "Error opening " + m.cTempViewAlias + ":" ? m.loException.Message ? m.loException.Details ENDTRY IF !USED(m.cTempViewAlias) RETURN ENDIF * Copy records from view cursor to disk SELECT * FROM (m.cTempViewAlias) ; INTO TABLE (m.cImportData + m.cTableAlias) IF USED(m.cTableAlias) ACTIVATE SCREEN FLUSH && Flush the buffer to write the data to disk IF m.lBrowse * Display the table on screen SELECT (m.cTableAlias) BROWSE NORMAL NOMODIFY NOWAIT ACTIVATE SCREEN ELSE * Close on-disk table USE IN (m.cTableAlias) ACTIVATE SCREEN ENDIF ENDIF IF USED(m.cTempViewAlias) USE IN &cTempViewAlias && Close SQL view ACTIVATE SCREEN ENDIF WAIT CLEAR ENDFUNC