====================================================================== Using Visual Basic Data Controls with the SQL Engine 2.0 ====================================================================== Introducing the R:BASE SQL Engine 2.0 With the release of the R:BASE SQL Engine 2.0, programming R:BASE applications in a Windows environment using Visual Basic is easier than ever. The new release of the SQL Engine is ODBC Level 1 compliant and supports Visual Basic's data control. The data control makes it possible to create Visual Basic applications that connect to an R:BASE database and retrieve records without programming. The data control performs the following functions: Connects an R:BASE database Retrieves a group of records based on any valid SQL query Passes data to bound controls for display or update Facilitates built-in error checking Disconnects from the database on exit In the past, these tasks required programming code. The data control eliminates much of the code and therefore reduces development time significantly. Accessing R:BASE is very straightforward - you can spend time developing the look of your application rather than writing the code. You need the Professional edition of Visual Basic 3.0, since the Standard edition does not have the data control. This article demonstrates techniques for using the data control and shows forms you can create with little or no Visual Basic code. Set Up the ODBC Administrator In order to use the data control, the data source (the R:BASE database name), must be added through the ODBC Administrator. The ODBC Administrator icon was installed into the SQL Engine program group. Start the ODBC Administrator and select Add. Choose the driver named "R:BASE45_16". Then enter the database name as prompted. Be sure to specify the complete drive and path name for the database; for example: C:\rbsqlapi\samples\dbs\contact The data source (the R:BASE database name) is added to the file ODBC.INI. During installation of the SQL Engine, the driver information was added to the ODBCINST.INI file. Refer to page 3-7 of the SQL Engine User's Manual for more information about setting up ODBC. Define Properties for the Visual Basic Data Control The data control is the Visual Basic object that connects to your R:BASE database and identifies the data to retrieve. Text boxes are the objects that hold the column data - one text box per column. The properties of the text box refer back to the data control. A form can have one or more data controls. You can even connect multiple R:BASE databases by using different data controls. Place a data control object on your form by double-clicking on the data control icon on the tool bar. The database and table are set through data control properties. To display the properties for a data control, click on the data control, then choose Windows|Properties from the Visual Basic menu. Or, if the Properties window is already displayed, select it. You must set three properties for the data control: Connect, Options and RecordSource. These properties can be set at design time or runtime. However, if they are not set at design time, some programming code needs to be written. Refer to the Visual Basic reference manuals for examples. The DatabaseName property is left blank; it is not applicable to connecting an R:BASE database. The Connect Property The Connect property passes information to the Engine that is necessary for connecting to the database, which is connected through ODBC. The following arguments can be included in the Connect property: ODBC - Indicates that the database is an ODBC data source DSN - The path and name of the database UID - The userid of the person using the database PWD - The userid password, if applicable For example: ODBC;DSN=c:\rbsqlapi\samples\dbs\contact;UID=none;PWD=none Note that each argument is separated by a semi-colon (;). The only argument that is required is ODBC;. Any of the remaining arguments that are not specified at design time can be explicitly set during run time. The arguments that are not set at design time or run time will be prompted for at run time. When you enter just "ODBC;" in the Connect property, the menu of installed Data Sources displays and you can pick the database name. When the userid/password box displays, enter a userid if applicable. To set up your application so that it will not prompt but automatically connect to a database, include all parameters as part of the Connect property. If no userid or password is defined, enter "NONE". Since the RecordSource property specifies a table name, you should include at least the database name in the Connect property. That makes sure your users don't select the wrong database from the ODBC Data Sources list. If you have no passwords assigned on the database, include the UID and PWD arguments as well so that your users won't be prompted at all. The RecordSource Property The RecordSource property defines a group of records from a table. Valid record sources consist of the name of a database table or the text of a SQL query. One of the nice features about the RecordSource property is that it can be dynamically changed while an application is running. This, of course, takes a couple of lines of code, but is fairly straightforward. The easiest way to set up the RecordSource is to simply enter a table name. Alternatively, you can use a SELECT command. For example: SELECT * FROM employees You can use any SELECT command that you can enter at the R>, although some require use of the SQL pass-through that is set with the Options property. For complex, multi-table queries, it is better to create a view in R:BASE and then select from the view in the RecordSource property. A view must be used with the SQL pass-through. The Options Property The Options property sets properties for the data (recordset) retrieved by the data control. The default value for the Options property is 0. This value allows the recordset to be modified. Make sure the Options property is set to 0 when designing an application where users will insert new rows, delete rows, or edit data. Setting the Options property to 64 enables SQL pass-through (DB_SQLPASSTHROUGH). The SQL command is passed directly to the underlying database engine for processing; Visual Basic does not try to process or interpret the command. Using the SQL pass-through allows you to build more complex SELECT commands, use R:BASE SuperMath functions and even use R:BASE command abbreviations (such as SEL instead of SELECT). Accessing data from an R:BASE view requires the Options property be set to 64. The recordset cannot be modified when the Options property is set to 64. Bound Controls Bound controls are Visual Basic objects that can receive information passed to them via the data control. Bound control means that the object is connected to another object. If the data displayed in these objects is changed, the table is automatically updated when a new record is selected (when Options property of the data control is set to 0). This makes it possible to design forms that view and edit data without program code. A text box is the bound control that is generally used with a data control. The properties that must be set for the text box are the DataField and the DataSource. Unlike the properties of the data control, these properties must be set at design time. DataSource Property The DataSource property contains the name of the data control supplying the data. Specifying the DataSource binds the text box to the data control. If the data control has been placed on the form, double-clicking on the DataSource property will automatically fill in a valid data control name. If more than one data control exists, successively double-clicking will display additional data controls associated with the form. DataField Property The DataField property contains the name of one of the columns returned by the table specified in the RecordSource property of the data control. Each bound object (text box) can contain only one field from the record source. If the DataSource property is filled in, double-clicking on the DataField produces a list of columns from the table and database specified by the data control. Example 1: A Multi-Table Form with a Two-Table Select This first example is a multi-table form based on the customer and contact tables in the Concomp sample database. This form contains one data control and is easy to create with a multi-table SQL query using SQL pass-through (Options=64). The best part about this example is that it requires absolutely no programming code. Just follow the steps below. 1. Begin Visual Basic and start with a new form. 2. Place a data control object on the form and define the properties as follows: Connect ODBC;DSN=C:\rbfiles\Concomp;UID="none";PWD="none" Options 64 (Numeric option specifying DB_SQLPASSTHROUGH) RecordSource SEL t1.custid, t1.company, t1.custaddress, + t1.custcity,t1.custstate, t1.custzip, t1.custphone, + (t2.contlname + ',' & t2.contfname), t2.contphone, t2.continfo FROM + customer t1, contact t2 WHERE t1.custid = t2.custid Notice the RecordSource property looks just like the SELECT command you enter at the R> prompt in R:BASE, including command abbreviations, expressions, and correlation names. 3. Add text boxes for each field returned by the query and adjust the properties as follows: DataSource Data1 (the Name of the data control) DataField one of the fields returned by the query, for example custid. The DataField property indicates which field displays in the located text box. Locate a text box and specify the appropriate DataField property for each column selected in the RecordSource. When done, your form should look similar to figure 1. That's all there is to it. Run the form and test it out by scrolling through the records. Because SQL pass-through was used, the data is not editable. Example 2: A Multi-Table Form that Links Two Data Controls The first form example was fairly limited. In order to change to a new customer and view the contacts associated with it, you must scroll through all of the records. This second form, on the other hand, allows the user to change to a different customer and view all contacts associated with that customer. This second example is more complex in that it requires two data controls to be set and a few lines of program code. As each new company is selected by clicking on the data control arrows, a new value for the RecordSource property is set by using the Visual Basic REFRESH method. When the user clicks on the data control associated with the customer table, the text box containing the customer id number, custid, changes. To capture the new id and retrieve the matching records from the contact table, enter the following code as a change procedure for the custid text box. This code executes whenever the custid value changes. 'Capture the new value of custid for the next record in the customer table Vcustid$ = Text1.text 'Redefine the RecordSource for Data2 using the new value of the custid Data2.Recordsource = "SEL * FROM contact WHERE custid = " + Vcustid$ 'Create the new recordset Data2.Refresh 1. Set up the form as in figure n and add the above code to the Change action on the text box for custid 2. Define the RecordSource and Options for each data control: Data1.RecordSource = customer Data1.Options = 0 Data2.RecordSource = SEL (contlname + "," & contfname), contphone, continfo FROM contact Data1.Options = 64 The data in the Customer table can be modified; the data in the Contact table is read only. Example 3: A Visual Basic Gateway For many years, users of R:BASE have wanted to be able to simultaneously connect to two R:BASE databases and be able to transfer data between them, but there was no way to connect to two databases at the same time. The Visual Basic data control now makes this easy to do. This third example uses a data control to connect to one database and custom code to connect to a second database. Using the data control, a record in the source database is selected and subsequently inserted into a destination table of the same name in a second database. Since this form uses SQL Engine function calls, the HEADER.BAS and SQLAPI.BAS files that come with the SQL Engine must be included in the project. For information about the SQL Engine functions, refer to your SQL Engine documentation. Follow the steps below to set up the form. Set Up The Source Database 1. Starting with a new form, add the SQLAPI.BAS and HEADER.BAS files to the project. 2. Set up a data control and edit the properties as described above in Examples 1 and 2 to specify the database and table. 3. Set up the text boxes and edit the properties to bind the text boxes to columns returned by the RecordSource. Set Up The Destination Database 1. Add text boxes for each field that will be transferred to the destination database. These text boxes are not associated with a data control, so no special properties need to be set. 2. Add command buttons to connect the database, insert the row and then disconnect the database. Add the associated code as shown below. Code For Form Load action Panel3D1.Caption = "C:\rbfiles\concomp OPEN" Command2.Enabled = False Command3.Enabled = False Code for Connect command button Sub Command1_Click () Mousepointer = 11 ' First allocate an environment handle retcode = SQLAllocEnv(phenv&) If retcode <> SQLSuccess Then MsgBox "SQLAllocEnv Failed" End If 'Next allocate a connection handle retcode = SQLAllocConnect(phenv&, hdbc&) If retcode <> SQLSuccess Then MsgBox "SQLAllocConnect Failed" End If 'Get the name of the database and create the connect string szDSN$ = InputBox$("Enter database name", "Connect Database", "c:\rbfiles\transfer\concomp2") szUID$ = "NONE" cbUID% = Len(szUID$) szAuthStr$ = "NONE" cbAuthStr% = Len(szAuthStr$) cbDSN% = Len(szDSN$) Mousepointer = 0 'Connect the database retcode = SQLConnect(hdbc&, szDSN$, cbDSN%, szUID$, cbUID%, szAuthStr$, cbAuthStr%) If retcode <> SQLSuccess Then retcode = SQLError(phenv&, hdbc&, phstmt&, szSqlState$, pfNativeError&, szErrorMsg$, cbErrorMsgMax%, pcbErrorMsg%) Else Command1.Enabled = False Command2.Enabled = True Command3.Enabled = True Panel3D2.Caption = "c:\rbfiles\transfer\concomp2 OPEN" End If Mousepointer = 0 End Sub Code For Insert command button Sub Command2_Click () 'If user selects "Insert Row", the values are displayed in the 'destination database section of the form Text5.Text = Text1.Text Text6.Text = Text2.Text Text7.Text = Text3.Text Text8.Text = Text4.Text 'Build the Values list used in the INSERT command. The current 'record in the source database is placed into variables vcustid$ = "(" + Text1.Text + "," vcontlname$ = Text2.Text + "," vcontfname$ = Text3.Text + "," vcontphone$ = Text4.Text + ")" vresp% = MsgBox("Insert new row...are you sure?", 4) If vresp% = 6 Then 'Allocate the statement handle retcode = SQLAllocStmt(hdbc&, phstmt&) If retcode <> SQLSuccess Then MsgBox "SQLAllocStmt Failed" Else 'Build the command szSqlStr$ = "INSERT INTO CONTACT (custid, contlname, contfname, contphone) VALUES " + vcustid$ + vcontlname$ + vcontfname$ + vcontphone$ cbSqlStr& = Len(szSqlStr$) 'Insert the row retcode = SQLExecDirect(phstmt&, szSqlStr$, cbSqlStr&) If retcode <> SQLSuccess Then MsgBox "INSERT Failed", 48 retcode = SQLError(phenv&, hdbc&, phstmt&, szSqlState$, pfNativeError&, szErrorMsg$, cbErrorMsgMax%, pcbErrorMsg%) Else MsgBox "Successful Insert of 1 Row", 64 End If 'Free the statement handle retcode = SQLFreeStmt(phstmt&, SQL_DROP) If retcode <> SQLSuccess Then MsgBox "SQLFreeStmt Failed" Else Text5.Text = "" Text6.Text = "" Text7.Text = "" Text8.Text = "" End If End If End If End Sub Code For Disconnect command button Sub Command3_Click () retcode = SQLDisconnect(hdbc&) If retcode <> SQLSuccess Then MsgBox "SQLDisConnect Failed" End If retcode = SQLFreeConnect(hdbc&) If retcode <> SQLSuccess Then MsgBox "SQLFreeConnect Failed" Else Command1.Enabled = True Command2.Enabled = False Command3.Enabled = False Panel3D2.Caption = "c:\rbfiles\transfer\concomp2 CLOSED" End If End Sub 3. Add error checking as necessary. The SQL Engine sample application has an error checking sub-routine you can use as a template. At runtime, the data control builds a recordset and binds the columns to the text boxes. Code connects to the second database when the "Open DB" command button is clicked. When the "Insert Row" command button is clicked, values are transferred to the destination text boxes. Based on these values, an SQLExecDirect command string is built that inserts the row into the destination database. Of course, many different variations of this form may be used to transfer data from a source database to a destination database. Evaluate your business situation and change the form and code accordingly. Review the R:BASE SQL Engine 2.0 README.TXT file for additional information on using Visual Basic data controls.