Work with Salesforce Data Cloud Data in FoxPro



Load Salesforce Data Cloud data into a FoxPro database. This article includes full code and a walk-through of the process.

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

Connect to Salesforce Data Cloud 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).

Salesforce Data Cloud supports authentication via the OAuth standard.

OAuth

Set AuthScheme to OAuth.

Desktop Applications

CData provides an embedded OAuth application that simplifies authentication at the desktop.

You can also authenticate from the desktop via a custom OAuth application, which you configure and register at the Salesforce Data Cloud console. For further information, see Creating a Custom OAuth App in the Help documentation.

Before you connect, set these properties:

  • InitiateOAuth: GETANDREFRESH. You can use InitiateOAuth to avoid repeating the OAuth exchange and manually setting the OAuthAccessToken.
  • OAuthClientId (custom applications only): The Client ID assigned when you registered your custom OAuth application.
  • OAuthClientSecret (custom applications only): The Client Secret assigned when you registered your custom OAuth application.

When you connect, the driver opens Salesforce Data Cloud's OAuth endpoint in your default browser. Log in and grant permissions to the application.

The driver then completes the OAuth process as follows:

  • Extracts the access token from the callback URL.
  • Obtains a new access token when the old one expires.
  • Saves OAuth values in OAuthSettingsLocation so that they persist across connections.
  • For other OAuth methods, including Web Applications and Headless Machines, refer to the Help documentation.

    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 SalesforceDataCloud Source", "TESTDB", .f.

    Below is the process that the program follows:

    1. Create a new FoxPro database.
    2. Open a connection to Salesforce Data Cloud 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 Salesforce Data Cloud 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
    

Ready to get started?

Download a free trial of the Salesforce Data Cloud ODBC Driver to get started:

 Download Now

Learn more:

Salesforce Data Cloud Icon Salesforce Data Cloud ODBC Driver

The Salesforce Data Cloud ODBC Driver is a powerful tool that allows you to connect with live data from Salesforce Data Cloud, directly from any applications that support ODBC connectivity.

Access Salesforce Data Cloud data like you would a database - read, write, and update Salesforce Data Cloud 0, etc. through a standard ODBC Driver interface.