ODBC drivers >

JDBC drivers >

Bridges, gateways >

Other >

All products

Connect JDBC to any ODBC driver

Connect JDBC to Microsoft Access

Cross-platform or cross-architecture access to any ODBC driver

ODBC access to any JDBC driver

Connect dbExpress applications to any ODBC driver

Connect XML applications to any ODBC driver

Access mutiple ODBC data sources from one SQL statement

Create custom ODBC drivers

Bespoke data access requirements

In the pipeline

Support

Resources

Quick start

Licensing

Knowledge Base

User Guides

Company

About Us

Careers & Partners

Download ODBC Drivers for

Oracle, SQL Server, Salesforce, MongoDB, Access, Derby, InterBase, DB2, & more.

Learn More
/**********************************************************************
* FILENAME : UsingKeysetCursors.c
*
* DESCRIPTION :
* Shows use of SQLSetPos with keyset driven cursor type and
* SQLFetchScroll() to read and update data in a rowset.
*
* Illustrates the use of SQL_FETCH_NEXT, SQL_FETCH_FIRST,
* SQL_FETCH_LAST, SQL_FETCH_PRIOR, SQL_FETCH_ABSOLUTE and
* SQL_FETCH_RELATIVE to retrieve data with UPDATE, DELETE and INSERT
* operations to change data in the rowset.
*
* A rowset array size of 10 is used (+1 extra for an insert record)
*
* ODBC USAGE :
* Sets the statement handle attributes ...
*
* SQLSetStmtAttr() with - SQL_ATTR_CURSOR_TYPE = SQL_CURSOR_KEYSET_DRIVEN
* - SQL_ATTR_ROW_BIND_TYPE = SQL_BIND_BY_COLUMN
* - SQL_ATTR_ROW_ARRAY_SIZE = 10
* - SQL_ATTR_ROW_STATUS_PTR = pointer to row status
* array
* - SQL_ATTR_CONCURRENCY = SQL_CONCUR_LOCK
* SQLBindCol() - to bind data array for current rowset
* SQLExecuteDirect() - execute SELECT from TestTBL1
* SQLFetchScroll() with - to retrieve rowset according to action requested
* (SQL_FETCH_FIRST, etc)
* SQLSetPos() - to set the cursor position in the rowset
* (for update, delete and insert)
*/
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqlext.h>
#include <string.h>
#include "util.c"
#define QUIT 0
#define INSERT 0
#define UPDATE 1
#define DELETE 2
#define LAST 3
#define UPDATE_ROW 100
#define DELETE_ROW 101
#define INSERT_ROW 102
#define REFRESH_ROW 103
#define QUIT 0
#define TRUE 1
#define FALSE 0
#define PERSONID_LEN 2
#define LASTNAME_LEN 255
#define FIRSTNAME_LEN 255
#define ADDRESS_LEN 255
#define CITY_LEN 255
#define DATA_ARRAY_SIZE 11
// Data and size arrays NOTE difference with Bulk Operations
// where structure is used
SQLUINTEGER PersonID[DATA_ARRAY_SIZE];
SQLCHAR FirstName[DATA_ARRAY_SIZE][255];
SQLCHAR LastName[DATA_ARRAY_SIZE][255];
SQLCHAR Address[DATA_ARRAY_SIZE][255];
SQLCHAR City[DATA_ARRAY_SIZE][255];
SQLLEN PersonIDLenArr[DATA_ARRAY_SIZE];
SQLLEN FirstNameLenArr[DATA_ARRAY_SIZE];
SQLLEN LastNameLenArr[DATA_ARRAY_SIZE];
SQLLEN AddressLenArr[DATA_ARRAY_SIZE];
SQLLEN CityLenArr[DATA_ARRAY_SIZE];
// RowStatusArray values (for reference)
// SQL_ROW_SUCCESS 0
// SQL_ROW_DELETED 1
// SQL_ROW_UPDATED 2
// SQL_ROW_NOROW 3
// SQL_ROW_ADDED 4
// SQL_ROW_ERROR 5
// (ODBCVER >= 0x0300)
// SQL_ROW_SUCCESS_WITH_INFO	 6
// SQL_ROW_PROCEED		 0
// SQL_ROW_IGNORE		 1
// SQLFetchScroll() actions (for reference)
//#define SQL_FETCH_NEXT 1 - fetch next rowset
//#define SQL_FETCH_FIRST 2 - fetch first rowset
//#define SQL_FETCH_LAST 3 - fetch last rowset
//#define SQL_FETCH_PRIOR 4 - fetch rowset prior to current rowset
//#define SQL_FETCH_ABSOLUTE 5 - fetch rowset starting at row within
// the table
//#define SQL_FETCH_RELATIVE 6 - fetch rowset starting at row within
// current rowset
SQLUSMALLINT RowStatusArray[DATA_ARRAY_SIZE], Action, RowNum;
SQLUSMALLINT NumUpdates = 0, NumInserts = 0, NumDeletes = 0;
SQLLEN BindOffset = 0;
SQLLEN RowsFetched = 0;
SQLLEN Concurrency = SQL_CONCUR_LOCK;
SQLHENV henv = SQL_NULL_HENV; 	// Environment handle
SQLHDBC hdbc = SQL_NULL_HDBC; 	// Connection handle
SQLHSTMT hstmt = SQL_NULL_HSTMT; 	// Statement handle
SQLRETURN retcode;
SQLLEN rowCount;
//
// Display row status array and rowset data array
//
void DisplayCustData() {
 int i;
 // Display RowStatusArray
 for (i=0; i<DATA_ARRAY_SIZE; i++) {
 printf ("%i, ", (int)RowStatusArray[i]);
 }
 printf ("\n");
 for (i=0; i<DATA_ARRAY_SIZE; i++) {
 printf ("Record %i - ", i);
 printf ("%i ,", (int)PersonID[i]);
 printf ("%.10s ,", (char *)FirstName[i]);
 printf ("%.10s ,", (char *)LastName[i]);
 printf ("%.10s ,", (char *)Address[i]);
 printf ("%.10s\n", (char *)City[i]);
 }
 return;
}
//
// Function to get next action
//
int GetAction(SQLUSMALLINT *pStatusArray,
 SQLUSMALLINT *pAction,
 SQLUSMALLINT* pRowNum) {
 // Display cust data array
 printf ("Current Data: \n");
 DisplayCustData();
 printf ("QUIT(0), \n");
 printf ("LIST : NEXT(1), FIRST(2), LAST(3), PRIOR(4), ABS(5), REL(6)\n");
 printf ("OR : UPDATE(100) DELETE(101) INSERT(102) REFRESH(103)\n");
 getInt ("Select Action", (int *) pAction, 'N', 0);
 // Row number only used for SQL_FETCH_ABSOLUTE and SQL_FETCH_RELATIVE
 if (*pAction == SQL_FETCH_ABSOLUTE || *pAction == SQL_FETCH_RELATIVE) {
 getInt ("Select ABS/REL Row Number", (int *) pRowNum, 'N', 0);
 } else {
 *pRowNum=0;
 }
 return 1;
}
//
// Clear a number of rows in the rowset data array
//
void clearBuffers (int index, int rows) {
 int i;
 for (i=index;i<index+rows;i++) {
 RowStatusArray[i]=SQL_ROW_NOROW;
 }
 printf ("Clear Buffers : %i, %i\n", index, rows);
 for (i=index;i<index+rows;i++) {
 PersonID[i]=0;
 memset(FirstName[i], ' ', FIRSTNAME_LEN);
 memset(LastName[i], ' ', LASTNAME_LEN);
 memset(Address[i], ' ', ADDRESS_LEN);
 memset(City[i], ' ', CITY_LEN);
 }
}
//
// If performing an Update or Delete, prompts for record number/index of
// record to process in the data array. Requests new data for update or
// insert. Data for inserts is returned in an extra row at the end of
// the rowset data array.
//
SQLUSMALLINT GetNewCustData(base) {
 int srcOffset;
 SQLCHAR strFirstName[FIRSTNAME_LEN];
 SQLCHAR strLastName[LASTNAME_LEN];
 SQLCHAR strAddress[ADDRESS_LEN];
 SQLCHAR strCity[CITY_LEN];
 char reply=' ';
 // Update record
 if (base==UPDATE) {
 getInt ("Enter Record No (0 - 9)", &srcOffset, 'N', 0);
 if (srcOffset<DATA_ARRAY_SIZE) {
 // Ask for new FirstName
 printf ("Current First Name : %.20s\n", FirstName[srcOffset]);
 memset(strFirstName, ' ', FIRSTNAME_LEN);
 reply=getStr ("New First Name ", strFirstName, FIRSTNAME_LEN, 'N');
 // Move new FirstName into Update area and remove NULL
 memset(FirstName[srcOffset], ' ', FIRSTNAME_LEN);
 strFirstName[strlen(strFirstName)]= ' ';
 memcpy(FirstName[srcOffset], strFirstName, FIRSTNAME_LEN);
 // Set lengths for Update to lengths of fields
 PersonIDLenArr[srcOffset]=SQL_COLUMN_IGNORE;
 FirstNameLenArr[srcOffset]=FIRSTNAME_LEN;
 LastNameLenArr[srcOffset]=LASTNAME_LEN;
 AddressLenArr[srcOffset]=ADDRESS_LEN;
 CityLenArr[srcOffset]=CITY_LEN;
 // Return row number of update record
 return srcOffset+1;
 }
 }
 // Insert record
 if (base==INSERT) {
 // Clear insert buffer
 clearBuffers (DATA_ARRAY_SIZE-1, 1);
 // Ask for new FirstName
 memset(strFirstName, ' ', FIRSTNAME_LEN);
 reply=getStr ("New First Name ", strFirstName, FIRSTNAME_LEN, 'N');
 memset(FirstName[DATA_ARRAY_SIZE-1], ' ', FIRSTNAME_LEN);
 strFirstName[strlen(strFirstName)]= ' ';
 memcpy(FirstName[DATA_ARRAY_SIZE-1], strFirstName, FIRSTNAME_LEN);
 // Ask for new LastName
 memset(strLastName, ' ', LASTNAME_LEN);
 reply=getStr ("New Last Name ", strLastName, LASTNAME_LEN, 'N');
 memset(LastName[DATA_ARRAY_SIZE-1], ' ', LASTNAME_LEN);
 strLastName[strlen(strLastName)]= ' ';
 memcpy(LastName[DATA_ARRAY_SIZE-1], strLastName, LASTNAME_LEN);
 // Ask for new Address
 memset(strAddress, ' ', ADDRESS_LEN);
 reply=getStr ("New Address ", strAddress, ADDRESS_LEN, 'N');
 memset(Address[DATA_ARRAY_SIZE-1], ' ', ADDRESS_LEN);
 strAddress[strlen(strAddress)]= ' ';
 memcpy(Address[DATA_ARRAY_SIZE-1], strAddress, ADDRESS_LEN);
 // Ask for new City
 memset(strCity, ' ', CITY_LEN);
 reply=getStr ("New City ", strCity, CITY_LEN, 'N');
 memset(City[DATA_ARRAY_SIZE-1], ' ', CITY_LEN);
 strCity[strlen(strCity)]= ' ';
 memcpy(City[DATA_ARRAY_SIZE-1], strCity, CITY_LEN);
 // Set lengths for Insert to lengths of fields
 PersonIDLenArr[DATA_ARRAY_SIZE-1]=SQL_COLUMN_IGNORE;
 FirstNameLenArr[DATA_ARRAY_SIZE-1]=FIRSTNAME_LEN;
 LastNameLenArr[DATA_ARRAY_SIZE-1]=LASTNAME_LEN;
 AddressLenArr[DATA_ARRAY_SIZE-1]=ADDRESS_LEN;
 CityLenArr[DATA_ARRAY_SIZE-1]=CITY_LEN;
 // Return row number of update record
 return DATA_ARRAY_SIZE;
 }
 // Delete record
 if (base==DELETE) {
 getInt ("Enter Record No (0 - 9)", &srcOffset, 'N', 0);
 if (srcOffset<DATA_ARRAY_SIZE) {
 // return row number of record to delete
 printf ("Deleting row %i\n", srcOffset+1);
 return srcOffset+1;
 }
 }
 return -1;
}
// Display row being inserted, updated or deleted
void DisplayRow(int action, int RowNum) {
 if (action==UPDATE) {
 printf ("Updating Row %i\n", RowNum);
 }
 if (action==INSERT) {
 printf ("Inserting Row %i\n", RowNum);
 }
 if (action==DELETE) {
 printf ("Deleting Row %i\n", RowNum);
 }
 printf ("Record : %.10s,", FirstName[RowNum-1]);
 printf ("'%.10s',", FirstName[RowNum-1]);
 printf ("'%.10s',", LastName[RowNum-1]);
 printf ("'%.10s',", Address[RowNum-1]);
 printf ("'%.10s'\n", City[RowNum-1]);
}
int main () {
 int i;
 retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
 CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_ENV)",
 henv, SQL_HANDLE_ENV);
 retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
 (SQLPOINTER*)SQL_OV_ODBC3, 0);
 CHECK_ERROR(retcode, "SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)",
 henv, SQL_HANDLE_ENV);
 retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
 CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_DBC)",
 hdbc, SQL_HANDLE_DBC);
 retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
 CHECK_ERROR(retcode, "SQLSetConnectAttr(SQL_LOGIN_TIMEOUT)",
 hdbc, SQL_HANDLE_DBC);
 retcode = SQLConnect(hdbc, (SQLCHAR*) "DATASOURCE", SQL_NTS,
 (SQLCHAR*) NULL, 0, NULL, 0);
 CHECK_ERROR(retcode, "SQLConnect(DATASOURCE)", hdbc, SQL_HANDLE_DBC);
 // Set to autocommit
 retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)TRUE,0);
 CHECK_ERROR(retcode, "SQLSetConnectAttr(SQL_ATTR_AUTOCOMMIT)",
 hdbc, SQL_HANDLE_DBC);
 retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
 CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_STMT)",
 hstmt, SQL_HANDLE_STMT);
 // Set the following statement attributes:
 // SQL_ATTR_CURSOR_TYPE: Keyset-driven
 // SQL_ATTR_ROW_BIND_TYPE: SQL_BIND_BY_COLUMN
 // SQL_ATTR_ROW_ARRAY_SIZE: 10
 // SQL_ATTR_ROW_STATUS_PTR: Points to RowStatusArray
 // SQL_ATTR_CONCURRENCY: Sets Concurrency
 // (because default is READ ONLY)
 retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE,
 (SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN, 0);
 retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE,
 SQL_BIND_BY_COLUMN, 0);
 retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE,
 (SQLPOINTER)10, 0);
 retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR,
 RowStatusArray, 0);
 retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY,
 (SQLPOINTER)SQL_CONCUR_LOCK ,0); // not in Microsoft example
 // Bind arrays to the PersonID, FirstName, LastName, Address,
 // and City columns.
 retcode = SQLBindCol(hstmt, 1, SQL_C_ULONG,
 &PersonID, 0,
 PersonIDLenArr);
 retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR,
 FirstName, sizeof(FirstName[0]),
 FirstNameLenArr);
 retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR,
 LastName, sizeof(LastName[0]),
 LastNameLenArr);
 retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR,
 Address, sizeof(Address[0]),
 AddressLenArr);
 retcode = SQLBindCol(hstmt, 5, SQL_C_CHAR,
 City, sizeof(City[0]),
 CityLenArr);
 // Execute a statement to retrieve rows from the Persons table.
 retcode = SQLExecDirect(hstmt, (SQLCHAR*)
 "SELECT PersonID, FirstName, LastName, Address, City "
 "FROM TestTBL1", SQL_NTS);
 // Fetch and display the first 3 rows.
 retcode = SQLFetchScroll(hstmt, SQL_FETCH_FIRST, 0);
 if (retcode == SQL_NO_DATA) {
 printf ("SQL_NO_DATA\n");
 }
 // Call GetAction to get an action and a row number from the user.
 while (GetAction(RowStatusArray, &Action, &RowNum)) {
 if (Action==0) break;
 if (Action==REFRESH_ROW) {
 Action=SQL_FETCH_FIRST;
 }
 switch (Action) {
 case SQL_FETCH_NEXT:
 case SQL_FETCH_PRIOR:
 case SQL_FETCH_FIRST:
 case SQL_FETCH_LAST:
 case SQL_FETCH_ABSOLUTE:
 case SQL_FETCH_RELATIVE:
 clearBuffers (0, DATA_ARRAY_SIZE);
 // Fetch and display the requested data.
 retcode = SQLFetchScroll(hstmt, Action, RowNum);
 if (retcode == SQL_NO_DATA) {
 printf ("SQL_NO_DATA\n");
 }
 break;
 // SQLRowCount returns the number of rows affected by an
 // UPDATE, INSERT, or DELETE statement;
 // an SQL_ADD, SQL_UPDATE_BY_BOOKMARK, or SQL_
 // DELETE_BY_BOOKMARK operation in SQLBulkOperations;
 // or an SQL_UPDATE or SQL_DELETE operation in SQLSetPos.
 case UPDATE_ROW:
 RowNum = GetNewCustData(UPDATE);
 DisplayRow(UPDATE, RowNum);
 SQLSetPos(hstmt, RowNum, SQL_UPDATE, SQL_LOCK_NO_CHANGE);
 SQLRowCount (hstmt, &rowCount);
 printf ("Rows Effected %i\n", (int) rowCount);
 break;
 case DELETE_ROW:
 RowNum = GetNewCustData(DELETE);
 DisplayRow(DELETE, RowNum);
 SQLSetPos(hstmt, RowNum, SQL_DELETE, SQL_LOCK_NO_CHANGE);
 SQLRowCount (hstmt, &rowCount);
 printf ("Rows Effected %i\n", (int) rowCount);
 clearBuffers (RowNum-1, 1);
 break;
 case INSERT_ROW:
 RowNum = GetNewCustData(INSERT);
 DisplayRow(INSERT, 11);
 retcode = SQLSetPos(hstmt, 11, SQL_ADD, SQL_LOCK_NO_CHANGE);
 if (retcode != SQL_SUCCESS &&
 retcode != SQL_SUCCESS_WITH_INFO) {
 extract_error("SQLSetPos - INSERT ROW",
 hstmt, SQL_HANDLE_STMT);
 } else {
 SQLRowCount (hstmt, &rowCount);
 printf ("Rows Effected %i\n", (int) rowCount);
 }
 clearBuffers (10, 1);
 break;
 }
 }
exit:
 printf ("\nComplete.\n");
 // Free handles
 // Statement
 if (hstmt != SQL_NULL_HSTMT)
 SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
 // Connection
 if (hdbc != SQL_NULL_HDBC) {
 SQLDisconnect(hdbc);
 SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
 }
 // Environment
 if (henv != SQL_NULL_HENV)
 SQLFreeHandle(SQL_HANDLE_ENV, henv);
 return 0;
}

Further information

Download ODBC Drivers for

Oracle, SQL Server, Salesforce, MongoDB, Access, Derby, InterBase, DB2, & more.

Learn More
Share:

AltStyle によって変換されたページ (->オリジナル) /