You are on page 1of 147

Edition 2.

DataDirect
®

for OLE DB

Getting Started
© 1999 MERANT. All rights reserved. Printed in the U.S.A.

INTERSOLV, DataDirect, APS, Maintenance Workbench, PVCS, TechGnosis,


SequeLink, and Middleware are registered trademarks of MERANT. PVCS
SiteSync, INTERSOLV Messaging, DataDirect Connect ODBC, DataDirect
Connect OLE DB, DataDirect Reflector, WebDBLink, Client/Server MiddleWare,
PVCS VM Server, PVCS Dimensions, PVCS Process Manager, PVCS Version
Manager, PVCS Tracker, and PVCS TrackerLink are trademarks of MERANT.
Micro Focus is a registered trademark and Net Express is a trademark of
MERANT International Limited. Other company or product names mentioned
herein may be trademarks or registered trademarks of their respective
companies.

No part of this publication, with the exception of the software product user
documentation contained on a CD-ROM, may be copied, photocopied,
reproduced, transmitted, transcribed, or reduced to any electronic medium or
machine-readable form without prior written consent of MERANT.

Licensees may duplicate the software product user documentation contained


on a CD-ROM, but only to the extent necessary to support the users
authorized access to the software under the license agreement. Any
reproduction of the documentation, regardless of whether the
documentation is reproduced in whole or in part, must be accompanied by
this copyright statement in its entirety, without modification.

U.S. GOVERNMENT RESTRICTED RIGHTS. It is acknowledged that the Software


and the Documentation were developed at private expense, that no part is in
the public domain, and that the Software and Documentation are Commercial
Computer Software provided with RESTRICTED RIGHTS under Federal
Acquisition Regulations and agency supplements to them. Use, duplication or
disclosure by the U.S. Government is subject to restrictions as set forth in
subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer Software
clause at DFAR 252.227-7013 et. seq. or subparagraphs (c)(1) and (2) of the
Commercial Computer Software Restricted Rights at FAR 52.227-19, as
applicable. Contractor is MERANT, 701 East Middlefield Road, Mountain View,
California 94043. Rights are reserved under copyright laws of the United
States with respect to unpublished portions of the Software.

MERANT
701 East Middlefield Road
Mountain View, California 94043
3

Table of Contents

Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
What Is DataDirect for OLE DB? . . . . . . . . . . . . . . . . . . . . . . . . 7
Using This Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Other Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Conventions Used in This Guide . . . . . . . . . . . . . . . . . . . . . . . . 11
Typographical Conventions. . . . . . . . . . . . . . . . . . . . . . . . . 11
Mouse Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Keyboard Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

Contacting Technical Support . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1 Universal Data Access with


DataDirect for OLE DB. . . . . . . . . . . . . . . . . . . . . . . . 17
OLE DB Connects You to More Data . . . . . . . . . . . . . . . . . . . . 18
Using the OLE DB Interface for Data Access . . . . . . . . . . . 19
Connecting to Data through
Connect OLE DB Data Providers . . . . . . . . . . . . . . . . . . . . . 21
Connecting to Data through
SequeLink OLE DB Edition. . . . . . . . . . . . . . . . . . . . . . . . . . 24

OLE DB Makes Data More Useful . . . . . . . . . . . . . . . . . . . . . . . 26


Making SQL Queries to Nonrelational Data Stores
with OLE DB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Connecting to DataDirect Reflector . . . . . . . . . . . . . . . . . . 28
Making SQL Queries to Relational Data Stores
with OLE DB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

DataDirect OLE DB Solutions: Examples and Advantages. . . . 32


Using ODBC Applications with DataDirect
Connect OLE DB Components. . . . . . . . . . . . . . . . . . . . . . . . . . 35

Getting Started with DataDirect for OLE DB


4

Summary of DataDirect for OLE DB


Components and Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

2 Using DataDirect OLE DB Components . . . . . . . . . . 39


Business Application Users and DataDirect
OLE DB Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Using Connect OLE DB Nonrelational Data Providers . . . 42
Using Connect OLE DB Providers and the
SequeLink OLE DB Provider . . . . . . . . . . . . . . . . . . . . . . . . 44
Using Connect ODBC/OLE DB Adapter . . . . . . . . . . . . . . . 47
Using DataDirect Reflector . . . . . . . . . . . . . . . . . . . . . . . . 49

Database Administrators and Reflector . . . . . . . . . . . . . . . . . 53


Application Developers and DataDirect
OLE DB Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Coding for the SequeLink OLE DB Provider and
Connect OLE DB Providers . . . . . . . . . . . . . . . . . . . . . . . . . 58
Coding for Reflector. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Sample ADO Data Consumer Call to Reflector . . . . . . . . . 62
Summary of OLE DB Application Flow . . . . . . . . . . . . . . . 62
OLE DB Programming Resources . . . . . . . . . . . . . . . . . . . . 63

A OLE DB and ADO Programming Samples . . . . . . . . 65


Using the OLE DB Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Objects and Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Finding and Instantiating a DSO . . . . . . . . . . . . . . . . . . . . 78
Building Commands with Command Objects . . . . . . . . . . 79
Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
ErrorObjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
CheckBook Data Consumer Sample Code. . . . . . . . . . . . . 87

ActiveX Data Objects (ADO) . . . . . . . . . . . . . . . . . . . . . . . . . . 89


The Connection Object . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
The Command Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
The Parameter Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
The Recordset Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

Getting Started with DataDirect for OLE DB


5

The Field Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94


The Error Object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Using the Connection Object . . . . . . . . . . . . . . . . . . . . . . . 95
Using the Recordset Object. . . . . . . . . . . . . . . . . . . . . . . . . 95
Using the Command Object . . . . . . . . . . . . . . . . . . . . . . . . 97
Leveraging OLE DB and ADO . . . . . . . . . . . . . . . . . . . . . . . 98

Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99

B OLE DB Data Providers and Data Access


Over the Web. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Overview of Web-based Data Access with
OLE DB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
How Does the Web Client Make a Query?. . . . . . . . . . . . . 118
How Does the Web Server Process the Query? . . . . . . . . . 120

C Comparing OLE DB and ODBC Features. . . . . . . . . . 123


Initializing the Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Initializing a Data Source Object . . . . . . . . . . . . . . . . . . . . . . . 124
Getting a Session and Executing a Command . . . . . . . . . . . . . 126
Executing a Command. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Retrieving a Row of Data from a Result Set . . . . . . . . . . . 128
Describing Query Results. . . . . . . . . . . . . . . . . . . . . . . . . . . 130
Accessors and Descriptor Handles. . . . . . . . . . . . . . . . . . . . 130

Locating a Data Source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

Getting Started with DataDirect for OLE DB


6

Getting Started with DataDirect for OLE DB


7

Preface

This book is your introduction to INTERSOLV® DataDirect® for


OLE DB. Read on to find out more about these DataDirect
products:

■ Connect OLE DB™ , including Reflector™


■ SequeLink® OLE DB Edition™

What Is DataDirect for OLE DB?


Using OLE DB technology, INTERSOLV has created solutions that
enable users of business applications to access all data in a
business transparently, wherever the data is located and in
whatever format it exists. From email files to DBMS data to
mainframe records, OLE DB technology enables business
applications to get to the data and manipulate it to meet user
needs.
Features DataDirect’s OLE DB solutions provide components that give you:

■ Access through OLE DB to more data, including nonrelational


data stores like email and relational data stores like Oracle

■ Access through OLE DB to relational data in a highly scalable,


client/server architecture

■ The ability to make SQL requests to non-SQL data stores


through OLE DB

■ Streamlined design and improved performance of your


OLE DB business applications

■ Portability of your OLE DB business applications

Getting Started with DataDirect for OLE DB


8 Preface

Product The DataDirect for OLE DB products and their components are:
components
■ Connect OLE DB. This product includes a suite of data
providers for the most popular relational databases, like
Oracle, Informix, Sybase, and Lotus Notes. In addition, it
includes OLE DB data providers for nonrelational data stores,
like Microsoft Exchange, Microsoft Mail, and Lotus Mail.

■ Reflector. This product is an OLE DB service component that


processes SQL queries and provides the value-added services
of a global metadata catalog, persistent views, and scrollable
cursors.

■ SequeLink OLE DB Edition. This product offers the SequeLink


Server and SequeLink OLE DB Edition Client, which is a thin
client that provides OLE DB database access through the
SequeLink OLE DB Provider. The provider can connect from
the SequeLink Client to multiple SequeLink Services managed
by SequeLink Server. All the major databases supported by
SequeLink Server are available to the user’s OLE DB
applications through the SequeLink OLE DB Provider.

Using This Guide


Audience and This guide assumes that you are familiar with accessing a
prerequisite database through an end-user application.
knowledge
How this guide is This guide contains two chapters that describe OLE DB, Universal
organized Data Access (UDA), and how DataDirect’s OLE DB components
relate to them.

Getting Started with DataDirect for OLE DB


Other Documentation 9

Other Documentation
In addition to this book, the following documentation is
available:

Connect OLE DB:


■ DataDirect Connect OLE DB Installation Guide
■ DataDirect Connect OLE DB User’s Guide and Reference
■ DataDirect Reflector User’s Guide and Reference

SequeLink OLE DB Edition:


■ SequeLink OLE DB Edition Client Installation Guide
■ SequeLink Server Installation Guide
■ SequeLink OLE DB Provider Reference
■ SequeLink Administrator’s Guide
■ SequeLink Error Codes and Messages Reference

The following table provides information about your DataDirect


for OLE DB documentation and a guide for finding the
information you need to perform any further tasks.

For information about... Go to...


Installing the DataDirect product Instructions are available on the
Online Documents DataDirect CD and on the Web site.
Installing Connect OLE DB product DataDirect Connect OLE DB Installation
components Guide
Connect OLE DB Data Providers
ODBC/OLE DB Adapter
Reflector
Using Connect OLE DB data providers DataDirect Connect OLE DB User’s Guide
and ODBC/OLE DB Adapter; and Reference; online help for Connect
developing applications for Connect OLE DB components
OLE DB components Getting Started with DataDirect for
OLE DB

Getting Started with DataDirect for OLE DB


10 Preface

For information about... Go to...


Defining and managing Reflector data DataDirect Reflector User’s Guide and
sources; developing applications for Reference and online help
Reflector Getting Started with DataDirect for
OLE DB
Troubleshooting Connect OLE DB Online help for Connect OLE DB
components; online help for Reflector
Installing SequeLink Server SequeLink Server Installation Guide
Installing SequeLink OLE DB Edition SequeLink OLE DB Edition Client
Client Installation Guide
Planning, configuring, and SequeLink Administrator’s Guide
administering your system and
network for SequeLink; creating and
managing data sources; using
SequeLink with your database
Troubleshooting SequeLink and SequeLink Error Codes and Messages
referencing error codes Reference
Using the SequeLink OLE DB Provider SequeLink OLE DB Provider Reference
Getting Started with DataDirect for
OLE DB

Getting Started with DataDirect for OLE DB


Conventions Used in This Guide 11

Conventions Used in This Guide


The following sections describe the typography, terminology,
and other conventions used in this guide.

Typographical Conventions
This guide uses the following typographical conventions:

Convention Explanation
italics Introduces new terms with which you may not be
familiar, and is used occasionally for emphasis.
bold Emphasizes important information. Also indicates
button, menu, and icon names on which you can act.
For example, click Next.
UPPERCASE Indicates the name of a file. For operating
environments that use case-sensitive filenames, the
correct capitalization is used in information specific
to those environments.
Also indicates keys or key combinations that you can
use. For example, press the ENTER key.
monospace Indicates syntax examples, values that you specify, or
results that you receive.
monospaced Indicates names that are placeholders for values that
italics you specify. For example, filename.

forward slash / Separates menus and their associated commands. For


example, Select File / Copy means that you should
select Copy from the File menu.
The slash also separates directory levels when
specifying locations under UNIX.
vertical rule | Indicates an “OR” separator used to delineate items.

Getting Started with DataDirect for OLE DB


12 Preface

Convention Explanation
brackets [ ] Indicates optional items. For example, in the
following statement: SELECT [DISTINCT], DISTINCT is
an optional keyword.
Also indicates sections of the Windows Registry.
braces { } Indicates that you must select one item. For example,
{yes | no} means that you must specify either yes or
no.
ellipsis . . . Indicates that the immediately preceding item can
be repeated any number of times in succession. An
ellipsis following a closing bracket indicates that all
information in that unit can be repeated.

Mouse Conventions
This action… Means to…
Click Point to an object with the mouse pointer and
momentarily press the left mouse button.
Double-click Press the left mouse button twice.
Right-click Momentarily press the right mouse button.
Drag Press and hold the left mouse button while
dragging item(s) to another part of the screen.
SHIFT+Click Click an object to select it; then, press and hold
the SHIFT key. Click another object to select the
intervening series of objects.
CTRL+Click Press and hold the CTRL key; then, click a
selection. This lets you select or deselect any
combination of objects.

Keyboard Conventions
Select menu items by using the mouse or pressing ALT+ the key
letter of the menu name or item.

Getting Started with DataDirect for OLE DB


Contacting Technical Support 13

Contacting Technical Support


INTERSOLV provides technical support for all registered users of
DataDirect OLE DB products, including limited installation
support, for the first 30 days. For support after that time, contact
us using one of the following methods or purchase further
support by enrolling in the SupportNet program. For more
information about SupportNet, contact your sales
representative.

World Wide http://www.intersolv.com/support


Web
The INTERSOLV Web site provides the latest support information
through SupportNet Online, our global service network that
provides access to valuable tools and information. Our
SupportNet users access information using the Web, automatic
email notification, newsgroups, and regional user groups.
SupportNet Online includes a knowledge base that allows you to
search on keywords for technical bulletins and other
information. You also can download product fixes for your
DataDirect products.

Internet

Australia and New australia_answerline@intersolv.com


Zealand
EMEA int_datadirect_answerline@intersolv.com
Japan jpn_answerline@intersolv.co.jp
USA and Canada datadirect_answerline@intersolv.com

Telephone

Australia 1 800 335 664 or 8:30-5:30 p.m. Local Melbourne Time (LMT)
9816 9977 for
Melbourne Metro
Belgium 0800 724 61 9:00-6:30 p.m. CET

Getting Started with DataDirect for OLE DB


14 Preface

France 0800 91 56 07 9:00-6:30 p.m. CET


Germany 0130 822 496 or 9:00-6:30 p.m. CET
+44 1727 812898
Japan 81-3-5401-9660 9:00-12:00, 1:00-5:00 p.m. JST
The Netherlands 0800 022 1609 9:00-6:30 p.m. CET
New Zealand 1 800 335 664 8:30-5:30 p.m. LMT
United Kingdom +44 1727 811881 8:00-5:30 p.m. GMT
and Ireland
USA and Canada 1 800 443 1601 8:30-8:00 p.m. EST

Fax and Mail


Information

Fax US 1 919 461 4527


Fax International +32-15-320919
Mail 1500 Perimeter Park Drive, Suite 100, Morrisville, NC 27560 USA

When you contact us, make sure that you can provide the
following information:

■ The product serial number located on the Product


Registration Information card or on a product serial number
card in your package. The number will be checked to verify
your support eligibility. If you do not have a SupportNet
contract, we will ask you to speak with a sales representative.

■ Your name and organization. For a first-time call, you may be


asked for full customer information, including location and
contact details.

■ The version number of your DataDirect product.

■ The type and version of your operating system.

■ Any third-party software or other environment information


required to understand the problem.

Getting Started with DataDirect for OLE DB


Contacting Technical Support 15

■ A brief description of the problem, including any error


messages that you have received, and the steps preceding
the occurrence of the problem. Depending on the complexity
of the problem, you may be asked to submit an example so
that we can recreate the problem.

■ An assessment of the severity level of the problem.

Getting Started with DataDirect for OLE DB


16 Preface

Getting Started with DataDirect for OLE DB


17

1 Universal Data Access with


DataDirect for OLE DB

Companies need to use data that is stored in a variety of formats


such as text files, electronic mail (email), spreadsheets, and
database tables. Improving access to this data can directly affect
business success on a daily basis.

DataDirect OLE DB products use OLE DB technology to improve


data access by connecting business users to all of their data
stores and providing them with a highly scalable, client/server
architecture for OLE DB access. In addition, some DataDirect
OLE DB components provide specialized services, like SQL query
processing, against data stores that cannot perform the
processing themselves.

Most important, DataDirect OLE DB data connectivity products


do not require a business to change the way it stores data. Data
does not need to be integrated into a single database or
migrated to a more powerful DBMS. Organizations can avoid
the complexity of extracting data from different data stores and
integrating it into a single data store. DataDirect OLE DB
products will connect users to data through OLE DB to any
supported data store, anywhere the data is stored, providing
true Universal Data Access (UDA).

Getting Started with DataDirect for OLE DB


18 Chapter 1 Universal Data Access with DataDirect for OLE DB

DataDirect OLE DB products can:

■ Connect your users to more data, in both simple and


distributed computing environments

■ Give users greater control over manipulating that data


without requiring changes to your existing database
technology

■ Leverage your current investment in ODBC technology while


upgrading to OLE DB technology

This chapter introduces OLE DB technology and explains how


DataDirect OLE DB products take advantage of it to connect you
to data stores. The rest of this book describes how people in a
business can use DataDirect OLE DB products.

Note: DataDirect OLE DB products are frequently updated with


new components. Call INTERSOLV for the current availability of
DataDirect OLE DB components.

OLE DB Connects You to More Data


While working with business applications, users frequently need
access to data that is stored outside of the application. In some
cases a user needs to read the data; in other cases, a user needs to
change the data or copy it. This section describes how OLE DB
gives users working in a business application the ability to access
a variety of data stores.

Getting Started with DataDirect for OLE DB


OLE DB Connects You to More Data 19

Using the OLE DB Interface for Data


Access
To give users universal access to external data stores, business
applications must be able to access the external data store, read
the data, and copy or modify it. To do this, applications must
either recognize the format of the stored data, or else they must
operate through a middleware program that understands the
data format.

For example, a financial report designer application might use a


middleware ODBC driver to access data in an Oracle database.
Such a middleware program:

■ Accepts requests for data from the business application


■ Accesses the data from the data store
■ Returns the data to the application

Data access through middleware requires a common language


of communication, or interface, between the data requester (the
application) and the middleware program. The more powerful
the interface, the better the communication achieved.

Microsoft’s OLE DB is a powerful interface that is supported by


many commercially available applications. In addition to using
these commercial applications for OLE DB, businesses can also
write customized applications that use the OLE DB interface for
data access. When OLE DB is the interface used for data access,
the business application is called the OLE DB data consumer, and
the middleware program is called the OLE DB data provider.
Figure 1-1 on page 20 shows how the OLE DB data provider and
the data consumer use a common interface to communicate.

Getting Started with DataDirect for OLE DB


20 Chapter 1 Universal Data Access with DataDirect for OLE DB

Figure 1-1. Data Consumer, Data Provider, and Data Store

Business Data
Application Consumer

Interface
to Data Data
Consumer Provider

Interface
to Data
Store

Data Data Store

Note that the data provider and the data store must also
communicate using a common interface. This interface is always
determined by the data store’s format.

An OLE DB data provider uses OLE DB to communicate with a


data consumer and uses the interface supported by an individual
data store to communicate with that data store.

Getting Started with DataDirect for OLE DB


OLE DB Connects You to More Data 21

Connecting to Data through Connect


OLE DB Data Providers
It is the job of the OLE DB data provider to convert OLE DB data
requests received from the data consumer to the native format
of the data store. Each data store used by a business may have a
unique native format. In this case, a business application may
need to use a number of different OLE DB data providers for
data access, one for each unique, data store native format.

Although data can be stored in a variety of formats, these


formats fall into two broad categories:

■ Relational data. This data is stored in a database that is


governed by a Database Management System (DBMS). The
DBMS presents the data as tables that consist of rows and
columns. Typically, a DBMS supports SQL to retrieve and
update the data. The DBMS also manages user access to the
data. Sybase and Oracle are examples of a DBMS that stores
relational data.

■ Nonrelational data. This data is stored in a file system rather


than tables of rows and columns. These systems usually do
not provide a way to sort and retrieve the data in their files
beyond simple text searching. Email and word processor files
are examples of nonrelational data stores.

DataDirect Connect OLE DB offers OLE DB data providers for


nonrelational data stores (such as Microsoft Exchange and Lotus
Notes databases) and relational data stores (such as Oracle and
Sybase). These OLE DB data providers are referred to in this book
as Connect OLE DB Data Providers.

Getting Started with DataDirect for OLE DB


22 Chapter 1 Universal Data Access with DataDirect for OLE DB

As Figure 1-2 on page 23 shows, a data consumer using Connect


OLE DB Providers can send the same request to access both
relational and nonrelational data. In addition, by sending data
access requests through the Connect OLE DB Providers, a data
consumer only needs to support one interface (OLE DB). It does
not have to support any of the native formats used by individual
data stores.
Letting Connect OLE DB Data Providers make the connections to
Product the individual data stores offers these benefits:
Advantages
■ Access to more data, including nonrelational data

■ Streamlined design and improved performance of the OLE DB


data consumer application

■ Portability of the OLE DB consumer application to multiple


data stores

Note: You can also use your ODBC-based applications with the
Connect OLE DB Data Providers by going through the Connect
ODBC/OLE DB Adapter. The Adapter gives you access to OLE DB
functionality through your current ODBC technology. For more
information, see “Using ODBC Applications with DataDirect
Connect OLE DB Components” on page 35.

Getting Started with DataDirect for OLE DB


OLE DB Connects You to More Data 23

Figure 1-2. Data Consumer Using Connect OLE DB Data Providers

User Application
(Data Consumer)
Sybase
Relational
Data Store

Oracle
Connect OLE DB Relational
OLE DB for Sybase Provider Data Store
Request

Data Source Connect OLE DB


Connections for Oracle8 Provider

1 2 3 4

Connect OLE DB
for Exchange
Provider

Exchange
Connect OLE DB Nonrelational
for Notes Provider Data Store

Lotus Notes
Nonrelational
Data Store

Getting Started with DataDirect for OLE DB


24 Chapter 1 Universal Data Access with DataDirect for OLE DB

Connecting to Data through SequeLink


OLE DB Edition
SequeLink OLE DB Edition is an enterprise-wide OLE DB solution
for complex, distributed computing environments. These
environments typically require scalable, client/server software
that can allow many users to connect to a variety of databases
with optimum performance.

With SequeLink OLE DB Edition, the thin SequeLink OLE DB


Edition Client needs only the SequeLink OLE DB Provider for
OLE DB access. You do not have to install multiple data providers
on the client to access multiple databases.

Through the SequeLink OLE DB Provider, OLE DB-based


applications can access any database supported by SequeLink
Server on the server side. Because SequeLink Server supports the
major relational databases, including databases on legacy
systems, an enterprise can migrate to the latest OLE DB
application technology and still be able to access their legacy
system data through SequeLink OLE DB Edition.

As Figure 1-3 on page 25 shows, SequeLink Server supports DB2


on OS/390. This means that multiple users in an enterprise who
rely, for example, on a Microsoft Office OLE DB-based application
for their daily work, can increase their access to data stores. If
these users have SequeLink OLE DB Edition available to them,
they can also use their Office applications with the SequeLink
OLE DB Provider to access DB2 data on an OS/390 mainframe
computer. The SequeLink client/server architecture allows them
to use one OLE DB-based application to integrate data from
diverse computing resources and data stores, including legacy
data.

Getting Started with DataDirect for OLE DB


OLE DB Connects You to More Data 25

Figure 1-3. Data Consumer Using SequeLink OLE DB Edition

User Application
(Data Consumer)

OLE DB
Request

SequeLink OLE DB
Provider
SequeLink Server Receives Request and
Manages Data Source Connections to
Multiple Databases on Multiple Platforms

SequeLink Server SequeLink Server SequeLink Server SequeLink Server


for Windows NT for UNIX for AS/400 for OS/390

Data Source
Connections

Any database Any database Any database Any database


supported by supported by supported by supported by
this SequeLink this SequeLink this SequeLink this SequeLink
Server Server Server Server

Getting Started with DataDirect for OLE DB


26 Chapter 1 Universal Data Access with DataDirect for OLE DB

Using SequeLink OLE DB Edition for data access through your


Product OLE DB-based applications offers these benefits:
Advantages
■ Thin client can use the latest OLE DB-based applications

■ Scalable, multi-user access to a variety of databases on


multiple server platforms

■ Ability to access data on legacy systems on a user-friendly,


client desktop, without requiring gateway software

OLE DB Makes Data More Useful


Having more data available, such as email, is important. To add
value to this data, however, it is equally important to be able to
use it in complex ways. For example, a data consumer could use
an OLE DB data provider to make a simple data request, such as
reading a list of files in Mary Smith’s email Sales folder. It would
be much more useful, however, to be able to retrieve a list of
email files from her Sales folder that are sorted for a particular
company product during a particular period of time.

In addition, this data would be most useful if retrieved in a


tabular format that could be incorporated into reports and
spreadsheets. Requesting sorted data to be returned in such a
table would be a request for complex data.

OLE DB is a powerful interface because it can send and receive


complex data. Yet, it is simple enough to convert complex data
requests from a consumer to the low-level logic that a
nonrelational data store can understand. On one hand, data
consumers that need to make complex data requests can use
OLE DB to represent those requests. On the other hand, OLE DB
data providers can retrieve data from both relational and
nonrelational data stores, process the data to the required level
of complexity using OLE DB, then return the data to a consumer.

Getting Started with DataDirect for OLE DB


OLE DB Makes Data More Useful 27

Making SQL Queries to Nonrelational


Data Stores with OLE DB
Structured Query Language (SQL) is often used by business
applications to read, retrieve, and update complex data in a
relational data store such as Sybase. Some business applications
can communicate directly with a data store and send SQL
requests to it. In this case, the application must make the
requests in the interface required by that particular data store,
and the data store must support SQL processing.

Other business applications use the ODBC interface to send a


SQL request to a number of data stores, using ODBC drivers as
middleware. These drivers communicate with each of the data
stores in their native formats. Both of these communication
methods require data stores that support SQL processing.

OLE DB, however, offers data consumers the capability of using


SQL to make requests for data and returning the results in
tabular form even if:

■ The data store’s native format does not support SQL


processing.

■ The data store is nonrelational (data is not stored as tables).

OLE DB achieves this by separating the stages of data access into


individual software components (data providers and service
components). OLE DB is the only database API standard that
allows decoupling of SQL processing from the data providers
that actually access the database. This architecture enables an
SQL service component to exist separately from the data
providers. DataDirect offers Reflector as a Connect OLE DB SQL
service component.

A major benefit of this decoupling is that a data consumer can


perform complex data queries on nonrelational data stores by
passing SQL strings through one SQL service component. This
component can then provide SQL capability to numerous OLE DB

Getting Started with DataDirect for OLE DB


28 Chapter 1 Universal Data Access with DataDirect for OLE DB

data providers that are designed for accessing individual data


stores, but cannot process SQL. Unlike an ODBC driver, each data
provider does not have to carry the overhead of supporting SQL
processing.

For example, consumers could make SQL requests to sort, update,


and join data in a Microsoft Exchange file system and in a Sybase
database. In addition, the query results could be returned to the
data consumer in tabular format that can be used directly for
reporting and spreadsheet calculations.

Connecting to DataDirect Reflector


To enable a data consumer to perform complex processing, like
SQL queries against a variety of data stores, a number of OLE DB
interface objects must be implemented by the middleware
components to communicate with both the data consumer and
the data store. For SQL query processing, the SQL string
containing the data access request must be passed by the data
consumer through a high level OLE DB Command object in an
OLE DB middleware component. The Command object processes
the SQL query so that it can be understood by other, lower level
middleware components. These other components deliver the
request to the data store.

In OLE DB, the SQL query processing done by the OLE DB


Command object can be performed by a distinct OLE DB
middleware component called a service component. OLE DB
service components specialize in a some type of data
manipulation, thereby freeing the data consumer, the data
provider, and the data store from performing this job.

Getting Started with DataDirect for OLE DB


OLE DB Makes Data More Useful 29

In the case of an SQL query processor service component, the


SQL query is processed so that it can be understood by the
OLE DB provider that communicates with the data store. Service
components still require data providers to manage the
communication with the data store. In fact, a service component
is an OLE DB component that consumes the data of an OLE DB
data provider.
DataDirect Reflector is an OLE DB service component that
Product processes SQL queries. It can be used by any data consumer that
Advantages uses OLE DB. It can also be used by any application that uses
ODBC and the DataDirect Connect ODBC/OLE DB Adapter.
Reflector is designed to be used with any OLE DB nonrelational
data providers, for example Connect OLE DB for Microsoft
Exchange. Together, these DataDirect OLE DB components give
data consumers complete SQL query processing functionality
and access to nonrelational data stores that do not themselves
support SQL processing.

Figure 1-4 on page 31 illustrates how Reflector works with data


consumers and Connect OLE DB Data Providers.

Note: While Reflector is not required for SQL processing with


relational data providers, there are cases where using Reflector
can be an advantage. For example, using Reflector with a
relational data provider can enhance SQL processing if the DBMS
supports only minimal SQL grammar. Reflector can also support
views, reusable business logic, and scrollable cursors, which an
OLE DB data provider for the DBMS may not support.

Getting Started with DataDirect for OLE DB


30 Chapter 1 Universal Data Access with DataDirect for OLE DB

Making SQL Queries to Relational Data


Stores with OLE DB
If a data store supports SQL processing, like the Oracle DBMS
does, then an OLE DB data consumer can maximize performance
by using a data provider that also supports SQL. In this case, a SQL
service component would not be required to process the SQL
query (see Figure 1-4 on page 31).

Remember that an OLE DB-based application can also connect to


a DBMS through MSDASQL and an ODBC driver. However, using a
Connect OLE DB relational data provider or the SequeLink
OLE DB Provider instead (if these components support the
database), offers the following important advantages:

■ Improved performance

■ Support for additional features, like scrollable cursors, that


are not supported by all ODBC drivers

■ Improved integration with the OLE DB specification because


all connections are mediated through OLE DB

■ Improved maintainability because there is one connection


component, the relational data provider, meaning no
dependency on a third-party vendor for updates

■ Data source configuration with user interfaces that are


tailored to the OLE DB capabilities of the data provider,
instead of an ODBC driver

For a DBMS that does not have a native, relational data provider
available, using MSDASQL with an ODBC driver remains a good
solution. It allows a business to migrate to OLE DB technology,
and it can easily be used in the same environment with other
OLE DB components, including Connect OLE DB data providers,
SequeLink OLE DB Edition, and Reflector.

Getting Started with DataDirect for OLE DB


OLE DB Makes Data More Useful 31

Figure 1-4. SQL Query Processing through DataDirect OLE DB Data Providers and
the Reflector Service Component

Connect OLE DB Data Providers process requests


from the data consumer, connect to requested data
stores (which process the SQL), access the data, and
The Data Consumer return it to the data consumer.
uses SQL through
OLE DB interfaces to Connect OLE DB Relational
send data requests Relational Data Data Stores
and receive results. Providers (SQL Processors)

SequeLink
SequeLink OLE DB Server
Provider
SequeLink Multiple Relational
User Application Server is Data Stores on
(Data Consumer) Available for Multiple Platforms
Multiple (SQL Processors)
Platforms

Reflector Service
Component

Connect OLE DB Nonrelational


The SQL Service Component Nonrelational Data Data Stores
processes SQL from the data Providers (No SQL Processors)
consumer, reads data from
the Connect OLE DB Data
Providers, coordinates the
results, and returns them to
the consumer.

Getting Started with DataDirect for OLE DB


32 Chapter 1 Universal Data Access with DataDirect for OLE DB

DataDirect OLE DB Solutions: Examples and


Advantages
DataDirect OLE DB solutions can provide data access that was
previously unavailable for businesses. The following examples
illustrate some typical OLE DB solutions for data access.
Health Care The health care industry stores customer information in
databases like Lotus Notes and reports customer problems
through internal email, like Microsoft Exchange. Yet this data is
typically difficult to search through because these data stores do
not support SQL-based sorting. Now, Connect OLE DB for Lotus
Notes, Connect OLE DB for Microsoft Exchange, and Reflector can
be used by an OLE DB-based application to find data about a
particular customer from these data stores. DataDirect Connect
ODBC/OLE DB Adapter and any ODBC-based application can also
use Reflector with these data providers to access this data.
Manufacturing In manufacturing, sales representatives use email systems like
Microsoft Mail to report critical customer needs for parts. Other
databases like Lotus Notes may store information about parts
that are available. Yet it is currently impossible to query these
data stores for a particular part number to match availability with
need. Connect OLE DB for Microsoft Mail, Connect OLE DB for
Lotus Notes, and Reflector can be used by an OLE DB data
consumer to perform this search. In addition, the same data
consumer can use Connect OLE DB Relational Providers to query
databases like Oracle and Sybase, which typically contain
customer account information. DataDirect Connect ODBC/OLE DB
Adapter and any ODBC-based application can also use these data
providers to access this data.

Getting Started with DataDirect for OLE DB


DataDirect OLE DB Solutions: Examples and Advantages 33

Insurance Many insurance companies are large enterprises with multiple


database users. They typically require a client/server architecture
that can scale to their significant needs for concurrent, multi-
user access to a variety of databases, including databases like
DB2 on OS/390, without sacrificing performance. Increasingly,
these companies are attempting to deploy integrated desktop
applications that combine the power of desktop productivity
tools with mainframe data, so that both in-house and field office
agents can respond to their customers. Yet database application
developers in these companies are faced with very different
programming models for making these different environments
work together. By writing OLE DB-based applications,
developers can use SequeLink OLE DB Edition to connect their
enterprise’s multi-user, client/server computing environment to a
variety of the most powerful databases, including databases on
legacy systems.
Communications Across all businesses, email is becoming a mission-critical
information source. Yet it is currently impossible to perform a
simple query that would produce all the email traffic in a given
month for a business's top ten customers. Connect OLE DB for
MAPI and Reflector can be used by an OLE DB-based application
to perform this search on Microsoft Exchange, Microsoft Mail,
Lotus Mail, and Lotus cc:Mail data stores. An ODBC-based
application can also perform this search by going through the
DataDirect Connect ODBC/OLE DB Adapter (described in “Using
ODBC Applications with DataDirect Connect OLE DB
Components” on page 35).

Getting Started with DataDirect for OLE DB


34 Chapter 1 Universal Data Access with DataDirect for OLE DB

Using SequeLink OLE DB Edition, Connect OLE DB data providers,


Product Reflector, and the Connect ODBC/OLE DB Adapter as separate
Advantages components improves data access in the following ways:

■ Reusability of data consumers and ODBC-based applications.


With Connect OLE DB Data Providers and the ODBC/OLE DB
Adapter, the same data consumer or ODBC-based application
can be used to access a variety of data formats. Business
applications do not have to be customized for accessing a
data store’s native format. If a business moves data to a
different data store, the consumer can still be used to access
that data.

■ Increased usefulness of business data. The ability to use SQL


requests to sort, join, and retrieve data across multiple data
stores, including legacy databases, increases the quantity and
quality of information used in a business. Data stores and
their associated OLE DB Providers can be added or
reconfigured to meet business needs without requiring
changes to the data consumers.

■ Simplicity of data consumers. Data consumers do not need to


know where data is located. They only need to make a single
SQL request to access the data. The SequeLink or Connect
OLE DB Provider and Reflector components are responsible
for processing the SQL, connecting to the data stores,
formatting data in tables, and returning it to the consumer.

■ Increased availability of business data. Because a single data


consumer can access a variety of data stores, fewer
customized business applications need to be supported by a
business. Users can work faster and get to more data in a
single work session with one consumer application.

■ Flexible architecture of service components. As more OLE DB


service components become available, they can be added
directly to a business’s data access capabilities. This
component-based architecture extends the usefulness of data
consumers and OLE DB data providers without requiring
additional coding to them.

Getting Started with DataDirect for OLE DB


Using ODBC Applications with DataDirect Connect OLE DB Components 35

Using ODBC Applications with DataDirect


Connect OLE DB Components
Today, many businesses rely on commercial or custom
applications that access a DBMS through ODBC middleware.
These applications use an ODBC driver to:

■ Connect to the DBMS


■ Accept SQL requests from the ODBC-based application
■ Pass the request to the DBMS, processing it first, if required
■ Return table data from the DBMS to the application

After investing in ODBC-based applications and ODBC drivers,


businesses want to continue to be able to use them. As data
access technology moves to more powerful interfaces like
OLE DB, however, businesses will also want to take advantage of
the universal data access capabilities OLE DB middleware offers.

To enable businesses to use their current ODBC technology while


moving to OLE DB technology, DataDirect offers the Connect
ODBC/OLE DB Adapter. The Connect ODBC/OLE DB Adapter
accepts ODBC calls, including SQL requests, from an ODBC-based
application and processes them for use by an OLE DB component
that supports SQL (for example, a service component like
Reflector or a relational data provider for the Oracle DBMS).

As Figure 1-5 on page 36 shows, the Connect ODBC/OLE DB


Adapter lets a business use its existing ODBC-based applications
to migrate its data access to the more powerful OLE DB
environment. A business can integrate its ODBC technology into
OLE DB without affecting current business practices.

Getting Started with DataDirect for OLE DB


36 Chapter 1 Universal Data Access with DataDirect for OLE DB

Figure 1-5. How Businesses Can Use the Connect ODBC/OLE DB Adapter

ODBC User Applications

ODBC DBMS
Driver (SQL Support)

ODBC ODBC DBMS


SQL Request Driver (SQL Support)

Connect ODBC DBMS


Driver (SQL Support)
ODBC/OLE DB
Adapter

OLE DB
Reflector SQL Relational Provider
Service Component

Connect OLE DB Connect OLE DB


for Exchange for Notes
Provider Provider

Microsoft Lotus Notes


Exchange Database

Getting Started with DataDirect for OLE DB


Summary of DataDirect for OLE DB Components and Features 37

Using the Connect ODBC/OLE DB Adapter, ODBC-based


Product applications can:
Advantages
■ Connect to more data. They can use an OLE DB service
component such as Reflector, and an OLE DB data provider
such as one of the Connect OLE DB Data Providers to access
nonrelational data stores, while continuing to use their
ODBC drivers for relational database access.

■ Migrate to OLE DB technology. They can migrate directly to


OLE DB relational data providers to access relational data
stores through OLE DB technology.

Summary of DataDirect for OLE DB


Components and Features
DataDirect for OLE DB components and the features they
support are described in Table 1-1 on page 38. See Chapter 2 for
an overview of how these components can be used.

Note: SequeLink OLE DB Edition, Connect OLE DB Relational and


Nonrelational Data Providers and Reflector Service Component
work with any OLE DB-based data consumer, as well as other
non-DataDirect OLE DB components. For information about the
minimum level of OLE DB interface support required by a
particular DataDirect OLE DB component, see the
documentation for that product.

Getting Started with DataDirect for OLE DB


38 Chapter 1 Universal Data Access with DataDirect for OLE DB

Table 1-1. Summary of DataDirect OLE DB Components and Features

DataDirect OLE DB
Component Description of Features
Connect ODBC/OLE DB Transparently migrates ODBC technology to OLE DB by
Adapter connecting ODBC-based applications to OLE DB relational data
providers and service components.
Connect OLE DB for MAPI Connects a data consumer or other OLE DB component to the
Data Provider MAPI-based data stores of Microsoft Exchange, Microsoft Mail,
Lotus Mail, and Lotus cc:Mail.
Connect OLE DB for Notes Connects a data consumer or other OLE DB component to any
Data Provider Lotus Notes database.
Reflector Service Accepts OLE DB-based SQL queries from a data consumer and
Component processes them for execution by an OLE DB data provider. It
also formats and returns the results from the OLE DB data
provider to the data consumer. Reflector supports persistent
views, provides a metadata catalog, and supports scrollable
cursors across all types of data.
Connect OLE DB Connects a data consumer or other OLE DB component to a
Relational Data Providers DBMS. Each DBMS has its own Connect OLE DB Data Provider.
SequeLink OLE DB Edition Connects a data consumer on the thin SequeLink client to
SequeLink Server, which can connect to any database
supported by SequeLink Server. SequeLink Server is available
for Windows NT, UNIX, AS/400, and OS/390. SequeLink Server
supports the leading databases, including databases on legacy
systems. SequeLink uses only a single OLE DB Provider on the
client to access all supported relational databases on the server.

Getting Started with DataDirect for OLE DB


39

2 Using DataDirect OLE DB


Components

Business DataDirect for OLE DB offers middleware components. These


application users components provide data processing services to business
application users and connect them to data stores. These users
interact with DataDirect OLE DB products in the same way they
currently work with data sources and ODBC drivers. In most
cases, little action is required by users because these products are
middleware that work in the background to provide connectivity
as transparently as possible.

All DataDirect OLE DB components require some configuration:

■ Connect OLE DB for Notes and Connect OLE DB for MAPI


require minimal configuration

■ ODBC/OLE DB Adapter requires data source configuration


using Microsoft’s ODBC Administrator

■ Connect OLE DB Relational Data Providers require data


source configuration using the INTERSOLV OLE DB
Administrator (similar to ODBC data source setup)

■ Reflector requires data source configuration using the


INTERSOLV OLE DB Administrator

■ The SequeLink OLE DB Provider requires data source


configuration using the INTERSOLV OLE DB Administrator
(similar to ODBC data source setup) and using the SequeLink
Connection Administration Tool (CAT).

Getting Started with DataDirect for OLE DB


40 Chapter 2 Using DataDirect OLE DB Components

DBAs: For many business environments, the required setup is minimal,


installation and and business application users can perform installation and
configuration configuration tasks on their local computers. In complex business
environments, diverse groups of users may need to be set up for
data access across a variety of data stores that are available
locally, across a network, or managed through an enterprise-wide
client/server architecture.

For example, a business might want to configure a data source


designed specifically for users who are accounting personnel. This
data source might be configured with an accounting user ID for
accessing the Account1 schema that exists in an Oracle database
located on a network server. In addition, predefined SQL views
may be set up for another group of users, for example,
Managers. This group may require its own data source and
schema to access data on another enterprise database.

This more complex data source configuration may require


planning and database configuration experience. Database
administrators (DBAs) and other information technology
specialists typically perform configuration tasks like these.
Application Some businesses write and support their own applications for
developers data access. Application developers may need to write
OLE DB based data consumers and data providers that can use
DataDirect OLE DB components. To develop these applications,
they need to know what programming tools can be used. They
also need to know which OLE DB interfaces are supported by
DataDirect OLE DB components and how to invoke these
interfaces.

This chapter gives an overview of how business application users,


DBAs, and application developers can use DataDirect OLE DB
components. For more detailed information on using a
component, refer to the documentation for that product.

Getting Started with DataDirect for OLE DB


41

Table 2-1 summarizes DataDirect OLE DB component installation


and configuration tasks and lists the users who typically perform
those tasks.

Table 2-1. Using DataDirect OLE DB Components: Users and Their Typical Tasks

Business
Application Application
Task Performed Users DBA Developer
Install ODBC/OLE DB Adapter and configure *
Adapter data sources
Install Connect OLE DB for MAPI and configure *
MAPI profiles
Install Connect OLE DB for Notes and configure *
Notes server locations
Install Connect OLE DB Relational Data Providers *
and configure provider data sources
Install Reflector and configure simple Reflector data *
sources
Configure complex Reflector data sources *
Install SequeLink OLE DB Edition Client and *
configure data sources for the SequeLInk OLE DB
Provider
Install SequeLink OLE DB Edition Server and *
configure SequeLink data sources that will be used
by the SequeLink OLE DB Provider
Write OLE DB applications that use DataDirect *
OLE DB components

Getting Started with DataDirect for OLE DB


42 Chapter 2 Using DataDirect OLE DB Components

Business Application Users and DataDirect


OLE DB Components
If you are a user of business applications, you connect to different
data stores to access the data you need. If Connect OLE DB Data
Providers are available to you, you will be able to access
previously unavailable data stores through your OLE DB based
applications (for example, email files, data in a Lotus Notes
database, and data in an Oracle8 database). If, in addition,
DataDirect Reflector is available, you will be able to make SQL
queries against these data stores even if they do not support SQL.

If the SequeLink OLE DB Edition Client is available to you, you can


access all the databases supported by SequeLink Server, using the
SequeLink OLE DB Provider on the client.

DataDirect OLE DB components work in the background to


connect you to these data stores. The next sections introduce you
to using these components; for more details about using them,
refer to the documentation for a particular component.

Using Connect OLE DB Nonrelational


Data Providers
After you install Connect OLE DB for MAPI or Connect OLE DB for
Notes data providers, your OLE DB-based business applications
(data consumers) automatically detect them on your system. If
Connect OLE DB for MAPI is installed, your data consumer will
offer you a way to select Connect OLE DB for MAPI as a data
provider for connecting to an email data store that uses MAPI.
For example, Connect OLE DB for MAPI functions as a data
provider for the following data stores:

■ Microsoft Exchange
■ Microsoft Mail

Getting Started with DataDirect for OLE DB


Business Application Users and DataDirect OLE DB Components 43

■ Lotus Mail
■ Lotus cc:Mail
Connect OLE DB If you select Connect OLE DB for MAPI as your provider, you can
for MAPI retrieve information about the email in your mail folders. This
information is returned to you as a table of rows and columns
(see Table 2-2 on page 43 for an example). You can read and
copy this tabular data into reports. Connect OLE DB for MAPI
does not support writing to this data, however, so you cannot
change it in the email data store.

The database concepts of catalog, table, and row are used to


organize this data. For example, the catalog is the file location
of your email, which is specified in your email profile. The tables
are the individual folders in your email data, like the Inbox
folder. When you query for specific information about the email
in your inbox, the information is returned in the rows and
columns of a table.

For example, you could query for a row from the Inbox table
that identifies an incoming message, the sender of the message,
and the date it was sent, as shown in Table 2-2.

Table 2-2. Email Data Returned by Connect OLE DB for MAPI

Message Identifier Sender Date Sent


0x2000 John Doe 01/01/97

Connect OLE DB If you have installed Connect OLE DB for Notes, you will need to
for Notes tell it where your Lotus Notes databases are located. You
perform this configuration task with the Connect OLE DB for
Notes Administrator window (for details on using this window,
refer to Connect OLE DB User’s Guide and Reference). You can
also perform this task if you are trying to make a connection to a
Reflector data source that uses Connect OLE DB for Notes as the
underlying data provider. In this case, you can configure through
the Reflector Data Sources window (Figure 2-5 on page 51).

Getting Started with DataDirect for OLE DB


44 Chapter 2 Using DataDirect OLE DB Components

After you install Connect OLE DB for Notes, the data consumers
you use will list Connect OLE DB for Notes as a provider that you
can select for connecting to a Lotus Notes database. If you select
the Connect OLE DB for Notes data provider, a login window may
be displayed. After you log in, Connect OLE DB for Notes
connects you and you can query the Notes database for data.
Connect OLE DB for Notes returns the requested data.

For example, you can ask for a table showing the Notes databases
you have access to on a particular server or on the local client
system. Connect OLE DB for Notes considers each Notes database
to be a catalog.

Table 2-3 shows a sample of the data you can retrieve from a
Lotus Notes database using Connect OLE DB for Notes.

Table 2-3. Lotus Notes Data Returned by Connect OLE DB for


Notes

CATALOG_NAME DESCRIPTION
MAIL\JSMITH.NSF Jane Smith
ISupport.NSF Information Systems
Support Requests

Using Connect OLE DB Providers and


the SequeLink OLE DB Provider
If you installed the SequeLink OLE DB Edition Client (which
includes the SequeLink OLE DB Provider) or a Connect OLE DB
Relational Provider, the provider will automatically be available
to the data consumers you use. This means that you can request a
connection to the provider through your consumer.

Getting Started with DataDirect for OLE DB


Business Application Users and DataDirect OLE DB Components 45

To use any of these providers, you must first set up a data source
for the provider. Data sources for these providers are set up
using the INTERSOLV OLE DB Administrator. The Administrator
displays the names of the data sources you define and their
properties. It also lets you make changes to a data source.

The data sources available to you depend on the DataDirect


OLE DB component you have installed. The Administrator
displays a Data Sources folder for each component you have
installed (see Figure 2-1).

Figure 2-1. INTERSOLV OLE DB Administrator Window

Getting Started with DataDirect for OLE DB


46 Chapter 2 Using DataDirect OLE DB Components

When you set up a new data source for a provider or modify an


existing data source, the Administrator starts the Setup Assistant
for that provider. The Assistant displays the provider’s data source
setup window with online help to guide you through data source
setup tasks.

For example, Figure 2-2 shows the Setup Assistant window for
Connect OLE DB for Oracle data sources. These setup windows
are similar to the data source setup windows for DataDirect
ODBC database drivers.

Figure 2-2. Connect OLE DB for Oracle Data Source Setup


Assistant Window

Getting Started with DataDirect for OLE DB


Business Application Users and DataDirect OLE DB Components 47

Using Connect ODBC/OLE DB Adapter


If you installed the Connect ODBC/OLE DB Adapter, your
ODBC based business applications can use it to make SQL queries
against relational and nonrelational data stores for which you
have data providers. To support SQL queries, the
Connect ODBC OLE DB Adapter requires an underlying OLE DB
component that is SQL enabled. For example, you can use
DataDirect Reflector as the SQL service component together
with any underlying data provider. You can also use an
SQL enabled data provider with the Connect ODBC/OLE DB
Adapter, such as one of the Connect OLE DB Relational Data
Providers.

Note: SequeLink OLE DB Edition Client does not include the


Connect ODBC/OLE DB Adapter.

After you install the Connect ODBC/OLE DB Adapter, you need to


configure data sources for it using the window shown in Figure
2-3 on page 48. You access this window through the Microsoft
ODBC Administrator. Data source configuration is similar to
configuring a data source for a DataDirect Connect ODBC
database driver. Instead of configuring a connection to a data
store, however, you configure the Connect ODBC/OLE DB
Adapter to connect to an underlying OLE DB data provider or
service component that is SQL-enabled. If needed, your DBA or
system administrator can help you specify information for a
network connection.
Connecting to For example, to configure an ODBC data source for the Connect
Reflector data ODBC/OLE DB Adapter that connects to a Reflector data source,
sources you:

■ Specify an ODBC data source name. This is the data source


you will select in your ODBC-based application.

■ Give a description of the data store you want to access (for


example, Microsoft Exchange or Lotus Notes data).

Getting Started with DataDirect for OLE DB


48 Chapter 2 Using DataDirect OLE DB Components

■ Specify Reflector as the OLE DB provider you are using with


this data source connection.

■ Specify a Reflector data source name.

Figure 2-3. Connect ODBC/OLE DB Adapter Driver Setup Window

Getting Started with DataDirect for OLE DB


Business Application Users and DataDirect OLE DB Components 49

SQL queries on After configuration, your ODBC-based application will list the
data stores new ODBC data source as an available connection. If you select
it, your connection goes through the Connect ODBC/OLE DB
Adapter to the Reflector Data Sources window (Figure 2-5 on
page 51).

This window lets you connect to the Reflector data source


specified in the Provider Data Source field on the Adapter Driver
Setup window. You can also modify some data source properties
before connecting, should you require it. Once connected, you
can begin making queries.

Using DataDirect Reflector


Reflector is an OLE DB service component. It lets you send SQL
queries to data stores to which you can connect with an OLE DB
data provider. Reflector uses the OLE DB data provider to
communicate with the data store.
Define a Reflector After you install Reflector, your OLE DB-based business
data source application will list it as a provider that you can use to make a
data source connection. To tell Reflector how to connect,
however, you must define a Reflector data source.

There are two ways you can define a Reflector data source:

■ Before connection, using the Reflector Setup Assistant


(Figure 2-4 on page 50), which is part of the INTERSOLV
OLE DB Administrator (Figure 2-1 on page 45). If you
configure a data source through the Administrator’s Setup
Assistant, the information for the data source is
automatically displayed in the fields of the Reflector Data
Sources window when that data source is selected at
connection time.

Getting Started with DataDirect for OLE DB


50 Chapter 2 Using DataDirect OLE DB Components

Figure 2-4. Reflector Setup Assistant Window

Getting Started with DataDirect for OLE DB


Business Application Users and DataDirect OLE DB Components 51

■ At connection time, using the Reflector Data Sources


window. After you select Reflector in your business
application’s list of provider connections, the Reflector Data
Sources window is displayed (Figure 2-5). Use it to select an
existing Reflector data source or define a new one.

Figure 2-5. Reflector Data Sources Window

Getting Started with DataDirect for OLE DB


52 Chapter 2 Using DataDirect OLE DB Components

To define a simple data source with either the Reflector Data


Sources window or the Reflector Setup Assistant in the
Administrator you specify:

■ A Reflector data source name.

■ A name for the connection.

■ An OLE DB data provider to use for the connection. The


OLE DB data provider must be installed on your system. At
this time, you also set the provider’s properties to suit your
connection needs. For example, you specify the data store to
which you will connect, like Microsoft Exchange.
Use a Reflector When defining your data sources, you can include an existing
data source with a Reflector catalog. Using a catalog makes the data source more
catalog flexible because it lets you:

■ Use Reflector schemas


■ Create and store predefined queries as Reflector SQL views
■ Use Reflector synonyms
Create Reflector Reflector Setup Assistant guides you through the task of creating
catalogs a new Reflector catalog and schemas for the catalog.

Reflector automatically installs:

■ A FoxPro database on your local machine


■ The MSDASQL OLE DB data provider that can connect to the
FoxPro catalog

Reflector uses this provider and database for its system


information. You can also use this database to store a Reflector
catalog that you create.

Note: You can use another database and OLE DB data provider
for the Reflector catalogs you create. However, the database
must be a relational database, and the OLE DB data provider
must support reading and writing of SQL.

Getting Started with DataDirect for OLE DB


Database Administrators and Reflector 53

Make SQL queries Once you connect to a Reflector data source, you can use your
with Reflector business application to make SQL queries against the data store
data sources defined in that data source. For example, you could use Reflector
to query your Microsoft Exchange inbox for all email messages
you received from John Doe, sorted by the date you received
them. If you are connecting through a Reflector catalog, you can
create and store SQL views of that data.

Database Administrators and Reflector


If a business uses complex data source connections with catalogs,
schemas, predefined SQL views, and synonyms, a DBA may be
the individual who configures data sources with Reflector Setup
Assistant in the INTERSOLV OLE DB Administrator. For example, a
business may have a number of different user groups such that
each group needs to access specific catalogs, schemas, and
predefined views for data stores on network servers.

In cases like this, DBAs are usually the individuals who:

■ Plan the user groups and connections for these data sources
■ Define a Reflector catalog and schemas for each data source
■ Assign group user IDs for login to data stores
■ Create SQL queries and store them as Reflector views
Defining Reflector You define Reflector data sources and create Reflector catalogs
data sources with through the Reflector Setup Assistant in the INTERSOLV OLE DB
catalogs Administrator. You can create a catalog for a data source while
you are defining the data source. You can also create catalogs
independently, and then later select one for a data source when
you define it.

The Administrator graphically displays your data source and


catalog configurations and updates them dynamically (Figure 2-
1 on page 45). This information is organized along the model of
the Windows Registry Editor. For example, if you double-click an

Getting Started with DataDirect for OLE DB


54 Chapter 2 Using DataDirect OLE DB Components

object on the left pane, information about the object is displayed


in the right pane. If you right-click an object in the left pane,
pop-up menus are displayed with actions you can select for the
object.

You can also modify an object by selecting it, then selecting an


action on one of the menus. The menus also allow you to create
data sources and catalogs. Reflector Setup Assistant quickly and
easily guides you through the tasks of creating data sources,
catalogs, and schemas.

Reflector data sources that use a catalog and schema must be


defined before business application users can connect to the data
stores they need. After installation and data source definitions
are complete, database administrators may also need to provide
users and application developers with some of the configuration
information they need to connect to data stores.

Getting Started with DataDirect for OLE DB


Database Administrators and Reflector 55

Figure 2-6 shows a sample Setup Assistant window for defining a


catalog. You can start the Reflector Setup Assistant from the
Tools menu.

Figure 2-6. Creating a Reflector Catalog with Reflector Setup Assistant

Getting Started with DataDirect for OLE DB


56 Chapter 2 Using DataDirect OLE DB Components

Application Developers and DataDirect


OLE DB Components
To take advantage of OLE DB technology, developers may want
to write data consumers or data providers that can use
DataDirect OLE DB components for data access. Developers
working with OLE DB-based programs and DataDirect OLE DB
components must be familiar with the Microsoft OLE DB
specification and object-oriented programming techniques.
Typical development tools for creating data consumers and data
providers are Visual Basic and Visual Basic Script, and C++.

In addition, developers should also be familiar with Microsoft’s


ActiveX Data Objects (ADO) Application Programming Interface
(API). ADO is the API recommended for making calls to OLE DB
data providers and service components from within a data
consumer. For most business needs, ADO is the easiest and fastest
method to use.
OLE DB Using ADO, data consumers can make calls to OLE DB objects.
programming These calls communicate data access requests to OLE DB data
overview providers and service components. To make calls successfully, a
data consumer developer needs to know which OLE DB objects
are available from (exposed by) these providers. More specifically,
a developer needs to know which interfaces of the objects are
exposed by the providers.

An OLE DB object’s interfaces define the programming structure


used by the object to communicate. The interfaces also define the
kind of information that the object can return to programs that
make calls to it. Some of an object’s interfaces are mandatory and
must be exposed by the provider, if the object is exposed. Other
interfaces are optional.

Getting Started with DataDirect for OLE DB


Application Developers and DataDirect OLE DB Components 57

The following list describes some of the OLE DB objects that can
be exposed by a provider, as explained in the Microsoft OLE DB
Software Developer’s Kit:

■ Commands. These objects execute a text command, such as


an SQL statement. If the text command specifies a rowset,
such as an SQL Select statement, the command is a factory for
the rowset. A single session can create multiple commands.
These objects have ten interfaces; six are mandatory.

■ Data Source Objects. These objects contain the machinery to


connect to a data source, such as a file or a DBMS. They are a
factory for sessions. They have eight interfaces; four are
mandatory.

■ Enumerators. These objects search for available data sources


and other enumerators. Consumers that are not customized
for a particular data source use enumerators to search for a
data source to use. Enumerators have five interfaces; two are
mandatory.

■ Errors. These objects can be created by any interface on any


OLE DB object. They contain additional information about an
error, including an optional custom error object. They have
two interfaces; both are mandatory.

■ Rowsets. These objects expose data in tabular format. A


special case of a rowset is an index. Rowsets can be created
from the session or the command. They have fourteen
interfaces; five are mandatory.

■ Sessions. These objects provide a context for transactions


and can be implicitly or explicitly transacted. A single data
source object can create multiple sessions. Sessions are a
factory for transactions, commands, and rowsets. Sessions
have twelve interfaces; three are mandatory.

■ Transactions. These objects are used when committing or


aborting nested transactions at other than the lowest level.
They have three interfaces; two are mandatory.

Getting Started with DataDirect for OLE DB


58 Chapter 2 Using DataDirect OLE DB Components

Not all providers and service components support all OLE DB


objects and their interfaces. Details about the objects and
interfaces supported by DataDirect OLE DB components are
described in the documentation for each component. The next
sections give an overview of the programming requirements for
DataDirect OLE DB components. For additional ADO and OLE DB
programming information, see the appendixes. You can also refer
to documentation from Microsoft.

Coding for the SequeLink OLE DB


Provider and Connect OLE DB Providers
The SequeLink OLE DB Provider and Connect OLE DB Relational
Providers support the following OLE DB objects:

■ Command
■ Data Source
■ Enumerator
■ Error
■ Multiple Results
■ Rowset
■ Session
■ Transaction
■ TransactionOption

Connect OLE DB Nonrelational Providers support the following


OLE DB objects:

■ Data Source
■ Error
■ Rowset
■ Session

All mandatory interfaces for these objects are supported. In


addition, some optional interfaces are supported. For more
information, refer to the SequeLink OLE DB Provider Reference
and the Connect OLE DB User’s Guide and Reference.

Getting Started with DataDirect for OLE DB


Application Developers and DataDirect OLE DB Components 59

By calling these objects through their exposed interfaces, a data


consumer can use an OLE DB data provider to locate and return
data in the form of a table. The SequeLink OLE DB Provider and
the Connect OLE DB Relational Data Providers support the same
SQL query functionality (through OLE DB objects) that is
available with ODBC-based applications and ODBC database
drivers.

Connect OLE DB for MAPI and Connect OLE DB for Notes


support simple queries for read-only rowset data. For example,
email systems store user information in catalogs that these
Connect OLE DB providers can access. This means a data
consumer can use the provider to call a user’s email system and
read a list of the email folder types and a description of each
type.

The provider would return this list as a table of rows and


columns. Connect OLE DB for MAPI data provider would return
the list as a table that looks like the example in Table 2-4:

Table 2-4. Sample Information Returned by Connect OLE DB for


MAPI

Catalog Name Description


Personal Folders Default incoming message folders
Finance All finance related messages

If an SQL query processor (such as Reflector) is available for the


nonrelational data providers, the data consumer can pass SQL
statements that request subsetted information from the email
system. For example, a data consumer could request a list of all
mail messages that were sent to a particular user that also shows
all of the other recipients of each mail message.

Getting Started with DataDirect for OLE DB


60 Chapter 2 Using DataDirect OLE DB Components

After the SQL query is processed by Reflector and sent to the


Connect OLE DB for MAPI data provider, it can return a table like
Table 2-5:

Table 2-5. Sample Query Information Returned by


Connect OLE DB for MAPI

Message Subject Recipients


Department Meeting Mary Smith
Department Meeting John Brown
Department Meeting Susan King
Response To Customer 10 Mary Smith
Response To Customer 10 Susan King
Response To Customer 10 Arthur Jones

Coding for Reflector


DataDirect Reflector is an SQL service component for the data
consumer application. It is also a consumer of the information
returned by the underlying OLE DB data provider that Reflector
uses to connect to the data store. Because Reflector is both a
provider and a consumer, developers writing a data consumer or
a data provider for Reflector need to know the:

■ OLE DB objects and interfaces supported by Reflector

■ OLE DB objects Reflector requires the underlying provider to


support

■ OLE DB objects Reflector does not require from the


underlying provider but can leverage if the provider supports
the objects

■ SQL query syntax that Reflector supports

Getting Started with DataDirect for OLE DB


Application Developers and DataDirect OLE DB Components 61

OLE DB objects Reflector supports the following objects for data consumers:
supported
■ Data Source Object
■ Sessions
■ Transactions (if supported by the underlying data provider)
■ Commands
■ Rowsets
■ Errors
■ Custom Error (standard OLE DB error object extension)

For a complete list of the supported interfaces, refer to


DataDirect Reflector User’s Guide and Reference.
OLE DB objects To communicate with an OLE DB data provider, Reflector
required requires the provider to support a subset of the interfaces in the
following objects:

■ Data Source Object


■ Sessions
■ Rowsets
■ Errors

For a complete list of the required interfaces, refer to DataDirect


Reflector User’s Guide and Reference.
SQL Syntax DataDirect Reflector supports a superset of the ANSI SQL-92
Supported Entry grammar. The query processor works with relational and
nonrelational data stores and includes support for views.
Reflector supports several scalar functions and the following SQL
statements:

Alter Table Delete Insert


Create Index Drop View Update
Create Table Drop View Update
Create View Drop Table

Note: The support for SQL statements depends on the level of


their support in the underlying data provider.

Getting Started with DataDirect for OLE DB


62 Chapter 2 Using DataDirect OLE DB Components

Sample ADO Data Consumer Call to


Reflector
The following example uses Microsoft Visual Basic Scripting code
to generate a Recordset from a Reflector data source:
Create the ADO set rstMain = CreateObject("ADODB.Recordset")
RecordSet object

Open the rstMain.Open "SELECT * FROM Inbox where PR_SENDER


recordset with a = ’ken griffey’",
query
Specify the "provider=Reflector;Data Source=Exchange Srv1;"
provider and data
source

Summary of OLE DB Application Flow


Whether ADO or direct OLE DB is used, the flow of control in a
typical OLE DB consumer that calls an OLE DB data provider or
service component would be:

1 Initialize OLE.

2 Connect (initialize a Data Source Object and a Session Object).

3 Open a Rowset (this can be done with or without using SQL).

4 Process the resulting Rowset.

5 Disconnect (release objects and uninitialize OLE).

Getting Started with DataDirect for OLE DB


Application Developers and DataDirect OLE DB Components 63

OLE DB Programming Resources


For examples of ADO and direct OLE DB code, see Appendix A,
“OLE DB and ADO Programming Samples,” on page 65.

For information about programming Web-based data access


applications that use OLE DB data providers, see Appendix B,
“OLE DB Data Providers and Data Access Over the Web,” on
page 117.

For information about the similarities and differences between


OLE DB and ODBC programming, see Appendix C, “Comparing
OLE DB and ODBC Features,” on page 123.

More information about OLE DB programming is available in


Microsoft’s OLE DB Specification. Microsoft also provides
extensive information about ADO and OLE DB on its World Wide
Web site.

Getting Started with DataDirect for OLE DB


65

A OLE DB and ADO


Programming Samples

This appendix merely skims the surface of what the Microsoft


OLE DB Software Developer’s Kit (SDK) and ADO have to offer.
The OLE DB SDK contains sample code, libraries, include files,
and most important of all, some very complete documentation.
In particular, you must read the specification defining a set of
common interfaces exposed by component objects for accessing
and manipulating data regardless of where it is stored.

Using the OLE DB Interface


Notes on this section:

■ This section contains information taken directly from "Talk to


Any Database the COM Way Using the OLE DB Interface," by
Stephen Rauch and is reprinted with permission from
Microsoft Systems Journal, July 1996, copyright 1996 Miller
Freeman Inc. All rights reserved. You can find more
information about this publication at the following World
Wide Web address:

http://www.microsoft.com/msj

■ The information in this section is recommended as a useful


introduction to the concepts of OLE DB programming. Actual
implementation of the samples may require updating to the
latest version of the OLE DB functional specification.

Getting Started with DataDirect for OLE DB


66 Appendix A OLE DB and ADO Programming Samples

■ This section only includes descriptions of OLE DB objects and


interfaces that are supported by DataDirect Reflector. Refer to
the original article for the information about objects and
interfaces that is not included here.

■ This section introduces you to OLE DB objects and their


interfaces, focusing mainly on the mandatory interfaces data
and service providers must implement. Next, it considers
finding and locating data and service components (also called
service providers in this appendix), then introduces some
functionality you can add to data and service providers that
makes them more robust. A sample data consumer
application and data provider are also included.

■ OLE DB is large and very flexible, so it is impossible to cover all


of the interfaces and functionality in detail. To understand
the information in this section, you should have a good
understanding of both OLE and database technologies. It is
also helpful if you understand ODBC, SQL, and Microsoft’s
Data Access Objects (DAO). OLE DB database concepts and
objects are similar to ODBC and DAO.

Objects and Interfaces


The OLE DB specification introduces approximately 55 new
interfaces. They are grouped into seven object types: DataSource,
DBSession, Command, Rowset, Index, ErrorObject, and
Transaction. An object type is defined as a set of interfaces an
object must expose and a set of interfaces it’s encouraged to
expose. For example, the Rowset object type is defined by a
group of interfaces a data consumer may interact with to
manipulate tabular data. To play the role of a Rowset, an object
must implement the IRowset, IAccessor, IRowsetInfo, and
IColumnsInfo interfaces. Optionally, a data or service provider can
implement a host of other related interfaces, as described in the
SDK.

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 67

Developers need not be overwhelmed by the number of objects


and interfaces. Providing a specification generic enough to
access all types of data without compromising the functionality
of the data provider is a monumental task. However, it’s also
obvious that a full SQL DBMS data provider is going to offer
considerably more functionality than a data provider for a text
file. Therefore, you don’t have to implement all of these
interfaces.

In developing OLE DB, Microsoft looked at similarities between


providers and produced a base level of interfaces.

Base-Level Interfaces
Base-level interfaces are the minimum set of objects and
interfaces both data and service providers must support. A
simple data provider that doesn’t support transactions or queries
through Command objects need only support only the required
interfaces, while more sophisticated data and service providers
will build on this foundation.

All data and service providers must support a Data Source Object
(DSO). A DSO represents a connection to a data source through
which you can operate on its data. The DSO is also the initial
object instantiated by calling CoCreateInstance for a given
OLE DB data or service provider’s CLSID or by binding to a
moniker. A DSO creates multiple sessions via DBSession objects
within a single connection context. Once instantiated, a data
consumer must always initialize a DSO with the
IDBInitialize::Initialize member function. Attempting to use a
DSO that lacks required scope or authentication information will
return an error. Scope includes information such as the name
and location of the data source and authentication information
if the data is not in an authenticated security environment. This
information is provided by a data consumer through the
IDBInitialize::Initialize member function.

Getting Started with DataDirect for OLE DB


68 Appendix A OLE DB and ADO Programming Samples

Because a generic consumer like a query processor (which is also a


service provider) may potentially use your data provider without
any knowledge of its implementation, it’s important to provide
information about the properties of your data provider and how
to build and execute queries. A data consumer can obtain this
information through the IDBInfo interface. The
IDBInfo::GetPropertyInfo member function returns information
about the data source. Such information includes—but is not
limited to—DBMS name, version, supported syntax (outer joins
and alter table), capabilities (bookmarks and retaining abilities),
and maximum lengths or sizes.

IDBInfo::GetKeywords and IDBInfo::GetLiteralInfo let you build


commands that extract data from data sources and providers.
These functions provide the keywords that are unique to the
provider and information about the literals used in text
commands.

If a DSO supports the IPersistFile interface, you can persist its


connection status, scope, and properties. You can optionally
(based on properties) persist the authentication information to a
file, although this may be dangerous since storing password
information in a file invites hackers. Note, however, that when
you persist a DSO you are not persisting any active sessions,
Command objects, or Rowset objects (which are discussed later);
loading the persisted file yields a DSO in the same state as when
the DSO was created.

As you will notice in the next few paragraphs, many interfaces


either contain the word Rowset or return a Rowset. That's
because they all revolve around the Rowset object. A Rowset
object makes data available to a data consumer. With a Rowset
object and its interfaces, a data consumer can navigate through
rows of data and add, change, and delete data within a data
source.

Calling IDBCreateSession::CreateSession, which is supported by


the DSO, creates a DBSession object. You can access data from a
table, create and execute queries, manage transactions, and

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 69

create a table or index through this object. At a minimum, all


DBSession objects must support an IOpenRowset interface.
Through IOpenRowset::OpenRowset, a data consumer generates
a Rowset, making available data from an individual table. A
Rowset generated through the IOpenRowset interface creates a
result set from the SQL query SELECT * FROM TABLENAME
where TABLENAME is supplied by a data consumer.

Optionally, simple data providers can allow for definition of


tables and indexes through two related interfaces,
ITableDefinition and IIndexDefinition, which allow the provider
to create a table or index without the overhead of supporting a
data definition language. IOpenRowset, ITableDefinition, and
IIndexDefinition can be used to create a simple data provider
that exposes raw data to data consumers for browsing in a very
simple and direct fashion.

If the IDBSchemaRowset interface is exposed by a data or service


provider, data consumers can get information about the
database without knowing its structure. For example, you might
have a SQL Server™ database that organizes each database into
a set of schemas with tables and queries for each schema or a
Microsoft Access 2.0 database that has a container of tables and
a container of queries.

Reading a Table Sequentially


There are many ways a data consumer can access data from a
data provider, such as reading a table sequentially, direct
positioning in a rowset, and scrolling. Support for these different
methods of data navigation depends on the interfaces a data
provider supports. All Rowset objects support a minimal set of
mandatory interfaces to access data. That minimum set includes
IAccessor, IColumnsInfo, IRowsetInfo, and IRowset.

Let's take a look at the steps required to read a table


sequentially. Assume that you, the data consumer, already have
a Rowset object. You created the Rowset object by using either

Getting Started with DataDirect for OLE DB


70 Appendix A OLE DB and ADO Programming Samples

IOpenRowset::OpenRowset exposed by the DBSession object or


ICommand::Execute implemented by a Command object.
IOpenRowset deals with the simpler case of retrieving all data
from a table. ICommand gets a Rowset that meets a specific data
definition or data-manipulation statement. Executing either of
these functions returns a pointer to an IRowset interface,
pIRowset, which is the most common interface used to read data
sequentially.

First, you need to get some information about the column names
and column types. You’ll use this information to create bindings,
which is the next step. With the IRowsetInfo::GetProperties
member function, you can obtain information that describes the
capabilities of the Rowset through properties supported by a
Rowset: bookmarks, scrolling backwards, the maximum number
of open rows that can be active at the same time, and about 60
other properties. Individual Rowsets created by the same data or
service provider may have different properties depending on
how the Rowset was created and if it applies to the current
circumstances. For example, a data provider’s ability to support
the property might be affected by the current transaction or the
current query. This will become clearer when Command objects
are discussed.

There are approximately 70 Rowset properties defined in the


OLE DB specification. If you are building a data or service
provider, you can add additional properties to describe special
capabilities of your Rowsets. You can also retrieve other objects
associated with the Rowset through the IRowsetInfo interface.
IRowsetInfo::GetSpecification returns a pointer to the object that
created the Rowset. This object is usually, but not necessarily, a
Command object. Given a Command object, you can get the
command text used to create the Rowset. If a DBSession object is
returned, you can get schema information and transaction
interfaces. IRowsetInfo::GetSpecification provides an additional
method for a data consumer to gain additional information
about the Rowset.

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 71

The IColumnsInfo interface provides the necessary methods for a


data consumer to determine the metadata, or characteristics, of
the columns in the Rowset. From either the metadata or the
command specification that generated the Rowset
(IRowsetInfo::GetSpecification), a data consumer can determine
which columns it needs from the Rowset.
IColumnsInfo::GetColumnInfo returns the most commonly used
metadata (column ID, column name, ordinal number of column,
data type, and so on). If you already know the name or property
identifier for the columns you want to use, then calling the
IColumnsInfo::MapColumnIDs member function will retrieve the
column ordinals.

Creating Bindings
Now that you know something about the Rowset, you must
create bindings. A binding associates a piece of memory in the
data consumer’s buffer with a column of data in a Rowset. It
consists of matching some persistent name or identifier of the
logical column to its physical ordering in the current Rowset. For
example, if a SQL statement like

SELECT orderID, customerID, Shipname FROM ORDERS


WHERE ...

is executed to yield a Rowset, then you could bind to the second


column to retrieve the customerID. For the lifetime of the
Rowset, columns always have a fixed ordinal, which begins with
1 and represents the order in which the columns appear in an
array returned from IColumnsInfo::GetColumnInfo.

The structure DBBINDING, which is defined in the OLE DB header


file OLEDB.H, describes the relationship between a field in a data
consumer’s structured buffer and the value of a field in a
Rowset. As the example below shows, each binding must have at
least one of the following parts: value, length, and status.

Getting Started with DataDirect for OLE DB


72 Appendix A OLE DB and ADO Programming Samples

typedef struct tagDBBINDING


{
DBCOLUMNPART dwPart; // Value | Length | Status
DBPARAMIO eParamIO; // How Accessor is used
// (Input/Output parameter)
ULONG iColumn; // Row Column Ordinal
ULONG dwType; // DBTYPE of Consumer Structure
ITypeInfo __RPC_FAR
*pTypeInfo; // COM abstract data type
DBNUMERIC __RPC_FAR *pNum; // Contains values for properties
ULONG obValue; // Offset of value consumer’s struct
ULONG cbMaxLen; // Size of consumer’s field
DBOBJECT *pObject; // Information for binding to an
// OLE object
ULONG obLength; // Offset of length consumer’s
struct
ULONG obStatus; // Offset of status consumer’s
struct
} DBBINDING;

Value is specified by dwType, cbMaxLen, and obValue, which


indicate what the data consumer’s structure is expecting, how
much space is available to hold it, and where in the data
consumer’s buffer the value should be placed. The dwType forms
an implied coercion. The OLE DB specification says Accessors are
only obligated to transfer data in the type exposed as the type of
a column in the Rowset; additional coercions are optional.

Length indicates the true length of the data and is useful mainly
on variable-length data types. On fixed-length data types it is set
to the actual width on a read from a Rowset and ignored on a
write. On variable-length data types, length reports the true, full
length of the data on reads, and is taken as an override of the
true size on write.

The status part of the binding lets a data consumer get status
information when reading from or writing to a Rowset. Status
can indicate whether the value is null upon a read, if the value
suffered any change upon coercion, and any error state.

Figure A-1 on page 73 shows how to create bindings that map


the data in each column of a rowset to locations in a data

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 73

consumer’s data buffer. Notice the use of the pColumnInfo


argument in defining the binding information. Information
contained in pColumnInfo is obtained by calling
IColumnsInfo::GetColumnInfo.

Figure A-1. Binding Creation

Getting Started with DataDirect for OLE DB


74 Appendix A OLE DB and ADO Programming Samples

Creating Accessors
Now that you have established the bindings, you need to gather
them in an Accessor, which reads data from and optionally writes
data to a data provider. Accessors contain information or code to
pack and unpack rows held by the data provider. You use them
like handles on the access members of a row, helping the row to
“crack” its contents and deliver the columns you bound in the
previous step.

You can create an Accessor at any time during the running of a


Rowset although it must be created before getting data from a
data or service provider. Remember, the columns fetched by the
Rowset are determined by a query from a command or through
the IOpenRowset::OpenRowset member function, not the
Accessor.

An Accessor is created by a data consumer using


IAccessor::CreateAccessor, which is prototyped as follows:

HRESULT CreateAccessor (DBACCESSORFLAGS dwAccessorFlags,


ULONG cBindings,
const DBBINDING rgBindings[],
ULONG cbRowSize,
ULONG* pulErrorBinding,
HACCESSOR *phAccessor);

The parameters are explained in Figure A-2 on page 75.

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 75

Figure A-2. CreateAccessor Parameters

To create an Accessor based on the binding information


described in Figure A-1 on page 73, a call to ::CreateAccessor
would look like this:

HACCESSOR hAccessor;
hr = pIAccessor->CreateAccessor(DBACCESSOR_READ |
DBACCESSOR_ROWDATA,
cBind, rgBind, 0,
NULL, &hAccessor );

After creating and successfully obtaining a handle to an


Accessor, the next step is to fetch rows. Fetching is the process in
which a data consumer makes a request to a data provider to
obtain (fetch) some number of rows from a data source. Rows
are fetched with methods such as IRowset::GetNextRows,
IRowsetLocate::GetRowsAt,
IRowsetLocate::GetRowsByBookmarks, and
IRowsetScroll::GetRowsAtRatio (these are defined in the OLE DB
specification). Each method returns handles to the rows
expressed as a handle HROW. Figure A-3 on page 76 shows an
example using the IRowset::GetNextRows method, which returns
an array of HROWs in the last parameter, rghRows.

Getting Started with DataDirect for OLE DB


76 Appendix A OLE DB and ADO Programming Samples

Figure A-3. Getting Data from a Rowset

GetNextRows does not give you the data yet. Calling


IRowset::GetData will actually get the data from rows that were
returned to you from the prior call to IRowset::GetNextRows.

IRowset::GetData is prototyped as follows:

HRESULT GetData (HROW hRow, HACCESSOR hAccessor,


void *pData);

HROW hRow [in] is the handle of the row from which you get the
data, and HACCESSOR hAccessor [in] is the handle of the
Accessor you want to use. void *pData [out] represents a
pointer to a buffer allocated by the data consumer in which to
return the data.

A data provider uses the bindings in the Accessor to determine


how to return the data. For each binding in the Accessor, GetData
obtains the data for the specified column of the row indicated by
hRow. Next, it coerces or translates the data according to the data

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 77

type in the binding. Then it places the coerced data in the data
consumer’s structure at the offset specified in the binding,
truncated if necessary to match the value of cbMaxLen in the
column binding.

You can call GetData any number of times. In each call, you can
pass the same values, a different Accessor, a different pointer to
a buffer, or different values for both. This means you can get as
many copies of the data as you want, and you can get them in
different types if alternate coercions are provided by a data
provider.

Releasing Rows

Rows are held and references are counted by a data provider


until the data consumer releases the rows. You release rows with
the IRowset::ReleaseRows member function. ReleaseRows
decreases the reference count of the specified rows passed to
the function; call ReleaseRows once for each time a row was
retrieved. For example, if the row was retrieved three times,
ReleaseRows must be called three times. When the reference
count decreases to zero, the row is truly released.

Finally, when you are finished with the Rowset, you must release
the Accessor. IAccessor::ReleaseAccessor releases the Accessor
and all the resources associated with it. The data consumer must
also release the Rowset with IRowset::Release after releasing the
Accessor.

Other Means of Reading Rowsets

Now you know how to read a Rowset sequentially. There are


other methods of accessing data from a Rowset, and all depend
on the properties and interfaces supported by a data provider.
These include IRowsetLocate and IRowsetScroll. IRowsetLocate
moves to arbitrary rows of a Rowset. IRowsetScroll moves to
exact or approximate positions in a moveable Rowset depending
on properties of the Rowset. It is likely to be used heavily for

Getting Started with DataDirect for OLE DB


78 Appendix A OLE DB and ADO Programming Samples

support of visible scrolling lists. The IRowset interface also defines


interfaces for adding, updating, and deleting Rowsets. These
interfaces are implemented in the sample application.

Finding and Instantiating a DSO


The base-level interfaces and functionality have now been
defined. The next step is to add additional functionality. If you’re
building a data or service provider, you will want to expose some
of these advanced features to build a more robust provider.
Before defining additional functionality, it is important to
understand how a data consumer finds and instantiates a DSO.

Like all COM components, OLE DB data and service providers are
found in the registration database. Information about OLE DB
data and service providers is kept in the registration database
using the standard OLE Component Categories structure, which
allows OLE components to become members of arbitrary
categories. It also permits OLE components to describe
themselves in enough detail that they do not have to be
instantiated. Instantiation may be expensive or may require
connection to a remote machine, so it should be avoided if
possible.

Utilizing this model, a data consumer can locate and directly


instantiate a data or service provider's DSO—the data consumer
can read information from the registry to determine the correct
data provider to load for a given instance of data. The data
consumer can also obtain a list of enumerators. An enumerator is
a COM server that implements IDBEnumerateSources. Not all
providers are enumerators, and not all enumerators are
providers. Finally, a data consumer can obtain a list of service
providers, which are COM servers that enhance a provider in
some way. Typically, a service provider exposes a subset of OLE DB
interfaces. For example, a query processor might query over
several data providers.

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 79

In most cases, an application built to consume data from a


specific data provider will locate and directly instantiate an
OLE DB data provider or service provider. General data
consumers will ordinarily use a standard enumerator, included as
part of the SDK, that reads the enumerators out of the registry.
Because each provider may support IDBEnumerateSources, there
can be many enumerators. Thus, the standard enumerator forms
the root of a hierarchy of IDBEnumerateSources.

How does an enumerator work? A general data consumer calls


CoCreateInstance to instantiate the standard enumerator.
IDBEnumerateSources::Sources provides a Rowset that contains
the name of the data source, a parse name, a description of the
data source, and the properties of the data source. A
DBSOURCE_ISENUMERATOR property means the data source
supports IDBEnumerateSources. The DBSOURCE_ISPARENT
property is set if the data source is parented to the data source
that just called IDBEnumerateSources::Sources. This allows the
client to go backward through the enumeration. In a file-system
model this is equivalent to the double dot command (..) . A
data consumer can then navigate through data sources just like
a file system.

Once a data consumer locates the data source in the Rowset, it


can extract the parse name string and, using IParseDisplayName,
obtain the moniker associated with the data source. A general
data consumer will use the moniker with the standard
IMoniker::BindToObject member function to bind to the object
with which it is identified.

Building Commands with Command


Objects
By now you should be able to create a pretty good application
that can find and retrieve data from a simple data provider, so
let’s look at some additional functionality that more

Getting Started with DataDirect for OLE DB


80 Appendix A OLE DB and ADO Programming Samples

sophisticated data providers may provide. If you’re building a


data provider, probably the first thing you will want to add is
support for building commands. Commands are queries that are
built and executed to retrieve data from a data source. A data
provider that supports building and executing more sophisticated
queries is certainly more robust than just opening a table, which
is all the base-level interfaces and objects support. This is because
a query enables a data consumer to ask for specific data versus
sifting through the raw data.

Commands and their properties are encapsulated in Command


objects, which are created through the IDBCreateCommand
interface supported by the DBSession object. At a minimum, a
Command object supports the ICommand, IAccessor,
ICommandText, IColumnsInfo, and ICommandProperties
interfaces. Through these interfaces a data consumer builds and
executes commands that result in a Rowset.

Before building a query, a data consumer must learn how to


query a particular data provider. This is where the information
from the IDBInfo interface supported by the DSO comes in.
Remember that a data consumer can learn the supported syntax,
capabilities, keywords, and literal information supported by a
data provider. If you are developing a specialized data consumer
that always accesses data from a specific data provider, you may
know how to build a query that accesses data from the provider.
The information on this should be provided by the data
provider’s development group in a specification. If you are
building a generic data consumer that can query any data
provider and want to take full advantage of the provider’s
capabilities, you will definitely use this interface to build queries.
If you need to know column metadata, you can use the functions
supported by the IColumnsInfo interface.

Assuming that the data consumer’s programmer read the


specification and that the consumer knows how to build the
query, it creates a Command object through the DBSession object
by invoking the member function

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 81

IDBCreateCommand::CreateCommand, which returns a pointer


to a Command object interface, in this case ICommandText.

ICommandText *pCommandText;

hr = pIDBCreateCommand::CreateCommand
(NULL, IID_ICommandText,
(IUnknown **) &pCommandText);

pIDBCreateCommand -> Release ();

The first parameter to IDBCreateCommand::CreateCommand,


IUnknown*punkOuter, points to the controlling IUnknown
interface if the new command is created as part of an aggregate.
It is a null pointer if the command is not part of an aggregate.

Once the data consumer obtains a pointer to the ICommandText


interface, it creates and sets a text command. A textual
command is typically a SQL expression for example,

SELECT orderID, customerID, Shipname FROM ORDERS WHERE ...

that is set explicitly through the ICommandText interface by the


method ICommandText::SetCommandText. Because there are
many dialects of SQL and potentially other languages, textual
command formulations require not only the actual text but also
an indicator of the language and its dialect (for example, ANSI
SQL-92, Access SQL, or T-SQL). Thus, the
ICommandText::SetCommandText method has two parameters:

REFGUID rguidDialect
const LPWSTR pwszCommand

The pwszCommand parameter is the actual text of the command.


The rguidDialect parameter is a GUID that specifies the
language and dialect used by the text. For example, a call to
ICommandText::SetCommandText might look like this:

pICommandText->SetCommandText (DBGUID_SQL92,
"SELECT * FROM CUSTOMERS ORDER BY CITY");

Getting Started with DataDirect for OLE DB


82 Appendix A OLE DB and ADO Programming Samples

There is a complete list of dialect GUIDs defined in the OLE DB


specification. If you are building a data provider, be aware that
you can define GUIDs for your own dialects as well. Not all data
providers will support all dialects; in fact, most data providers will
support only one dialect.

Before you execute the command, you may want to register with
the Command object the properties you want supported by the
Rowsets returned by ICommand::Execute. By setting properties, a
data consumer can ask for the exact functionality it wants. This
affects how a Rowset is implemented by a data provider. It is also
how a data consumer can get the functionality it wants with
associated performance trade-offs. You can register with the
ICommandProperties::SetProperties function.

Invoking ICommandText::Execute will generate a Rowset based


on the command specified as an argument in the
ICommandText::SetCommandText member function. ::Execute is
prototyped as follows:

HRESULT Execute (IUnknown *rgpUnkOuters[],


REFIID riid, DBPARAMS *pParams,
HCHAPTER *phChapter, BOOL
fResume,
ULONG *pcRowsets,
IUnknown ***prgpRowsets,
WCHAR **ppRowsetNames);

Figure A-4 on page 83 describes the parameters.

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 83

Figure A-4. Execute() Parameters

For your command, a call to ICommandText::Execute returning


an IRowset interface pointer would look like this:

HRESULT hr;

ULONG ulRowsets = 0;

IRowset **rgpRowsets = NULL;

hr = pCommandTree->Execute (NULL, IID_IRowset,


NULL, NULL, FALSE, &ulRowsets,(IUnknown
***)&rgpRowsets);

This gives you a Rowset interface and lets you manipulate the
data using the Rowset cotypes.

Getting Started with DataDirect for OLE DB


84 Appendix A OLE DB and ADO Programming Samples

Transactions
OLE DB has defined a set of interfaces and an object to support
simple, nested, and coordinated transactions. Any data that is
read, added, changed, deleted, or updated can be transacted.
Transaction support is provided through the ITransactionLocal
interface supported by the DBSession object. Any data provider
that supports transactions must support this interface.

Without transaction support, all work done under the scope of


the DBSession object is immediately committed on each method
call. When a DBSession object enters a local or coordinated
transaction, all work done by the DBSession or the Command and
Rowset objects associated with the DBSession is part of a
transaction. A data consumer calls
ITransactionLocal::StartTransaction to begin a transaction on the
DBSession object. It is also through this interface that a data
consumer commits or aborts the unit of work performed within a
transaction’s scope.

For those data providers that support nested transactions, calling


ITransactionLocal::StartTransaction with an existing transaction
active on the DBSession returns a new transaction nested within
the active transaction. Changes made within the innermost
transaction are completely invisible to its outer transaction until
the inner transaction is committed or aborted.

Data providers that support extended transaction functionality


implement a Transaction object. The Transaction object supports
the ITransaction interface for committing or aborting a
transaction directly, allowing a data consumer to commit or abort
at a transaction level other than the current level of a nested
transaction. Another feature of the Transaction object is event
notification; IConnectionPointContainer may be supported as a
notifications sink for the ITransactionOutcomeEvents interface
implemented by a data consumer. ITransactionOutcomeEvents,
an interface defined in the OLE Transactions specification,
provides the capability for a data consumer to monitor the

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 85

outcome of transaction events. When a commit or abort is


processed, a data provider notifies each registered
ITransactionOutcome interface of the transaction’s outcome.

Finally, a data provider that supports the ITransactionJoin


interface can participate in coordinated transactions. Calling the
ITransactionJoin::JoinTransaction method enlists the DBSession
into a coordinated transaction. Once a data consumer joins a
coordinated transaction, it calls the transaction coordinator’s
ITransaction::Commit or ITransaction::Abort method to commit
or abort the transaction.

ErrorObjects
The last object and set of interfaces to introduce before moving
to the sample application is the ErrorObject and its interfaces.
ErrorObjects are optional; they don’t have to be implemented by
a data service provider.

ErrorObjects are an extension of the OLE automation error-


handling interfaces, which include ICreateErrorInfo, IErrorInfo,
and ISupportErrorInfo. Through these interfaces, an object can
provide error-related information to a consumer of the object.
This includes a text description of the error, the GUID for the
interface that defined the error, help context ID, help file name,
and the ProgID of the class or application that returned the
error.

One of the shortcomings of the OLE automation error-handling


interfaces is their inability to return multiple error records from a
single call. For example, a data consumer might call into a query
processor, which calls down into several data providers. If an
error occurs in a data provider, how does the query processor
add its own error information to the data provider’s error before
returning to the data consumer? To solve this problem, OLE DB
extends the OLE automation error objects by adding the ability
for an ErrorObject to contain multiple error objects.

Getting Started with DataDirect for OLE DB


86 Appendix A OLE DB and ADO Programming Samples

Records in OLE DB ErrorObjects are numbered starting at zero


and new error records are added to the top of the list. When an
error record is retrieved, it is extracted from the list in LIFO order.
Therefore, consumers of the object can start with the highest
level of error information and then retrieve increasingly detailed
information.

Each error record is composed of three parts, an ERRORINFO


structure, error parameters, and a pointer to a custom
ErrorObject. The ERRORINFO structure returns most of the basic
information associated with an error.

typedef struct tagERRORINFO {


HRESULT hrError;
DWORD dwMinor; // A provider-specific error code
CLSID clsid; // The class ID of the object that
// returned the error.
IID iid; // The IID of the interface that
// generated the error
DISPID dispid; // Indicates the method that
// returned the error
} ERRORINFO;

Error parameters, which are provider-specific values, are


substituted into error messages by a provider-specific error
lookup service through the member functions supported by
IErrorInfo. For example, the provider might associate the error
message

Cannot open table <param1>.

with the dwMinor value relating to an error code in the data


provider’s specification. Error parameters supply the name of the
table that could not be opened.

In addition to the ERRORINFO structure and parameters, a


custom ErrorObject is associated with each error record. A custom
ErrorObject is the mechanism by which OLE DB ErrorObjects are
extensible, allowing you to create your own provider-specific
ErrorObject. Your ErrorObject’s interface pointer is stored in the
record.

Getting Started with DataDirect for OLE DB


Using the OLE DB Interface 87

As you can see, this model is very extensible, giving a data


consumer lots of error information that can be provided to the
user. The IErrorInfo and IErrorRecords interfaces are self-
explanatory and there is plenty of sample code in the OLE DB
specification.

CheckBook Data Consumer Sample


Code
Note: As of this writing, you can download the sample code
described in this section from the World Wide Web at:

http://www.microsoft.com/data

The CheckBook sample from Visual C++® is used to demonstrate


OLE DB. CheckBook illustrates how to implement a record-based
document. It writes the data to an MS-DOS file with a
CHKBOOK-specific file format and on a per-record basis rather
than on a load/save basis. Written to the file is the check number
(which is automatically assigned by the application), the date the
check was written, who it was written to, a memo, and the
amount. The application supports retrieving, editing, and
adding records. Keeping the same functionality as the
CheckBook sample, the application was modified so it uses
OLE DB to access the data store, which in this case is a flat file. As
you can see, you can access any data no matter how it is stored.

To convert the application into two components, a data


consumer and simple data provider, the file access functions
(basically the CDocument CChkBookDoc class) were removed
and a data provider was created from it. The data provider is an
in-process server implementing the base-level interfaces
described earlier.

The new CDocument-based class uses the OLE DB interfaces to


consume data from the data provider (see Figure A-6 on page
100). When you open a document with OnOpenDocument, the

Getting Started with DataDirect for OLE DB


88 Appendix A OLE DB and ADO Programming Samples

application immediately calls CoCreateInstance to instantiate the


data provider and initializes the data provider by providing the
file name entered by the user.

The original CheckBook application accessed all data from the


flat file when the file is opened—no commands here—and
displayed it in two views. This is exactly what the OLE DB
CheckBook application does; after initializing the data provider,
the CheckBook data consumer creates a DBSession and opens a
Rowset using the IOpenRowset::OpenRowset member function.
The data consumer then goes into a loop (see the
CCheckbookDoc::GetNextRows member function), fetching and
getting the data directly from the data provider and storing the
check information in a CObList.

In this example the HROWs are held so that the HROW is


available for an individual check when the user updates it. This
simplification was made since the example holds onto a relatively
small number of rows at a time and the provider does not
support bookmarks. General-purpose consumers should attempt
to use bookmarks rather than hRows to hold onto a row
whenever possible, since hRows require that the provider do
some caching and are generally more heavyweight than
bookmarks.

The OLE DB CheckBook application adds new rows, which are


checks, at the end of the flat file by calling the
IRowsetNewRow::SetNewData member function in
CCheckbookDoc::AddNewCheck. Using an Accessor and a pointer
to the new data values, the data consumer calls SetNewData,
which returns an HROW of the newly added row. After getting
the new HROW, it is added to the CObList just in case the user
wants to change the check before closing the application.

By providing an Accessor and an HROW from an open Rowset,


you can change the data associated with the HROW by using the
IRowsetChange::SetData member function. In
CCheckbookDoc::UpdateData,this interface is used to update
changes made on the check.

Getting Started with DataDirect for OLE DB


ActiveX Data Objects (ADO) 89

How do you run the application? First you have to register


CheckBook’s data provider. The data provider is a self-registering
in-process server and may also be registered using the
REGSRV32.EXE tool.

REGSVR32 CHECKDP.DLL

Create your own checkbook through the application, or use the


MYCHECKBOOK.CHB file provided with the sample application
and the source code to the data consumer. To start the
application, run

CHECKBOOK.EXE

ActiveX Data Objects (ADO)


This section contains information taken directly from "Manage
Data from Myriad Sources with the Universal Data Access
Interfaces," by Stephen Rauch and is reprinted with permission
from Microsoft Systems Journal, September 1997, copyright 1997
Miller Freeman Inc. All rights reserved. You can find more
information about this publication at the following World Wide
Web address:

http://www.microsoft.com/msj

The one thing to remember is that OLE DB is the foundation.


OLE DB consumers consume OLE DB interfaces and interact with
OLE DB service components and OLE DB providers. ADO is an
OLE DB consumer.

ADO looks very similar to Data Access Objects (DAO) and Remote
Data Objects (RDO) because Microsoft took the best features of
both models and put them together in a common programming
model. The most important points to make here are that ADO is
easy to use, language-independent, and provides extensible
interfaces for programmatic access to all types of data.

Getting Started with DataDirect for OLE DB


90 Appendix A OLE DB and ADO Programming Samples

Since ADO consumes OLE DB interfaces, whose sole purpose is to


expose native functionality from diverse types of data stores, you
can get to all types of data through ADO. ADO was designed as a
set of interfaces that would be common for any high-level data
access library that is going to supply a common programming
model. And it really is easy to use. Language-independent means
that ADO is an automation server that supports dual interfaces.
Dual interfaces means that ADO supports an IDispatch as well as
a VTBL interface, so that applications written in Visual Basic, C++,
and Java can bind directly to the VTBL interface and get fast
performance. Scripting languages can use the same objects
through IDispatch.

All objects in ADO (see Figure A-5 on page 91) can be instantiated
on their own, except the Error and Field objects. The hierarchy of
objects found in previous models like DAO and RDO is de-
emphasized in the ADO model to allow greater flexibility in
reusing objects in different contexts. For example, you can create
a Command object, associate and execute it against one
connection, then associate it with a different connection and re-
execute it. This approach also paves the way for you to create
specialized objects (defined at design time) and temporary,
unattached recordsets.

Getting Started with DataDirect for OLE DB


ActiveX Data Objects (ADO) 91

Figure A-5. ADO Object Model

Imagine a specialized Recordset object that’s made to handle


any results returned from a data store. It can basically determine,
through metadata calls, all of the column information and all
the columns that are there, build a recordset, and hand it to you.
But those metadata calls can take a little time during runtime.
This is where ADO comes in. Because objects in ADO can be
instantiated on their own, you can use it to do things like design
a Recordset object that is specialized for a certain query against
your back-end database at design time. Thus, at design time a
tool can capture information about the metadata of all of the
columns, and at runtime a Recordset can be opened and
immediately bind and start fetching, eliminating metadata calls
during runtime.

The Connection Object


The Connection object represents a unique session with a data
source. In the case of a client/server database system, it may be
equivalent to an actual network connection to the server. It’s

Getting Started with DataDirect for OLE DB


92 Appendix A OLE DB and ADO Programming Samples

probably the object that you start with when working with any
database management system. It allows for things like
customization of connection options (such as your isolation level)
and starting and ending transactions. The Connection object also
allows you to execute commands such as a query or SQL
statement. To execute any kind of command, you use the Execute
method of the Connection object. If the command returns rows, a
default Recordset object is created and returned.

The Command Object


The Command object is analogous to QueryDef in the DAO
model and the prepared statement in the RDO model. It
represents a command (also known as a query or statement) that
can be processed by the data source. You use Command objects
to obtain records and create a Recordset object, to execute a bulk
operation, or to manipulate the structure of a database.
Depending on the capabilities of the OLE DB provider, it can also
handle parameters. The Command interface is actually optional
in ADO since some OLE DB providers will not implement
command execution functionality. Note that the Command data
type is not a required object type to implement a generic OLE DB
provider. The Command object is implemented in ADO; it doesn’t
do anything if it’s communicating with an OLE DB provider that
does not support command functionality.

Commands can be simple SQL statements (or some other


language the OLE DB provider recognizes) or calls to stored
procedures in the database. Commands can then be executed
using the Command’s Execute method, or you can create a
Recordset object and associate it with the Command object when
opening a cursor.

The Command object includes a collection of Parameter objects.


If the provider can support commands with parameters, the
parameters collection will contain one Parameter object for each
parameter in the command. Unlike in DAO and RDO, you can

Getting Started with DataDirect for OLE DB


ActiveX Data Objects (ADO) 93

create Parameter objects and explicitly add them to the


parameters collection. This allows you to use well-known
parameterized commands so you can avoid the sometimes very
expensive operation of having the OLE DB provider populate the
parameters collection automatically based on the retrieval of
information from system catalogs.

The Parameter Object


Parameter objects represent parameters associated with
parameterized queries, or the in/out arguments or return values
of stored procedures on a Command object. The Parameter
object is intended as a sort of parameter marker in a command
for when you are working with things like output arguments or
a command that you want to prepare. Command objects have a
prepared property because, if you are going to execute
something a whole bunch of times, even if you are just changing
part of the where clause, it’s better for you to create a Command
object and prepare it. The OLE DB provider will make sure that it
is very efficient.

The Recordset Object


The Recordset object is your cursor of data. The big difference in
ADO is that the Recordset can be used as a data buffer.
Traditionally, a Recordset was a way of issuing a query, getting a
resultset, and reiterating over the resultset. With ADO, once you
have the results, there is no reason why you can’t treat it as a
data buffer, separating it from the connection to the database,
and passing it around safely to other applications or within
different areas in an application. This means that the Recordset
object manages changes to the recordset, buffering rows that
have changed and those that have not, maintaining the old
values with the new values. When you’re ready to commit the
changes, you can re-associate the Recordset with a Connection

Getting Started with DataDirect for OLE DB


94 Appendix A OLE DB and ADO Programming Samples

and use the automated method call UpdateBatch. UpdateBatch


packages, inserts, and deletes the updates and sends them to the
data store.

If you’re more of a stored procedure type of person and don’t


like the idea of exposing your base tables, you can still work with
the enhancements made to the Recordset because Microsoft
exposed varying types of status, such as which rows have changed
and which rows haven’t. When an application hands a data
buffer back to you, you can take a look through it and call your
own stored procedure calls. You get a nice way of encapsulating
a set of data and moving it around your system (regardless if it is
distributed, across a network, or around a bunch of DLLs) without
having to worry about connections or exposing your data
directly.

Additional changes to the Recordset object include


improvements for removing unnecessary things, adding optional
arguments that reduce the number of lines of code for common
scenarios, and changing defaults that don’t make sense in today’s
technologies.

The Field Object


The Field object represents a column in a recordset that you can
use to obtain values, modify values, and learn about column
metadata.

The Error Object


The Error object contains details about data access errors
pertaining to a single operation involving ADO. For those
instances where an OLE DB provider returns more than one error,
ADO will raise the most descriptive error as a runtime error in
Visual Basic or an OLE exception.

Getting Started with DataDirect for OLE DB


ActiveX Data Objects (ADO) 95

Using the Connection Object


The code below shows how to use the Connection object:

Dim con As New Connection


con.Open "dsn", "usr", "pwd"
con.Execute "<sql>"

The first line is how you would typically instantiate a Connection


object in Visual Basic. If you are using a scripting language, just
replace it with a CreateObject call. In the ADO model you will
notice Open and Close metaphors for objects that have an Open
and Close state like a Connection object. To open a connection
to a data source, just call the Open method and pass a data
source name, user, and password as separate arguments. To
execute a random statement, use the Execute method.

Those of you who remember DAO and RDO will remember there
used to be a separate execute from OpenRecordSet, and you
always had to know if you were going to get results or not to
use one or the other. In the ADO model, Microsoft cleaned that
up. All you really need is one Execute method—you don't need
to know which one or whether you are going to get results or
not. If there are results returned from the query, the Execute
method will return a Recordset object. If there are no results
returned from the query, it will return nothing. Microsoft has
eliminated a lot of the bulk from the model.

Using the Recordset Object


The Recordset object is just as easy to do a simple Open on.
Notice that, instead of using the Connection object and opening
the Recordset, the Recordset is actually being created by itself.

Getting Started with DataDirect for OLE DB


96 Appendix A OLE DB and ADO Programming Samples

Dim rs As New Recordset


rs.MaxRows = 100
rs.Open "<sql>", "<con.string>", adOpenKeyset

While Not rs.EOF


.
.
.

rs.MoveNext
WEnd

In the earlier models, you had to go through a hierarchy of


objects and set certain properties of a cursor before the cursor
was open and before the query was executed. For example,
MaxRows had to be set before the query was executed because
the data source needed to know when to chop off the results. In
the older model, you had to have a tree of instances and you had
to put those things on higher-level objects, even though they
didn’t belong there. There was always confusion as to which
object inherited from which, and which one was used when you
didn’t set one. What Microsoft has done in the ADO model is
eliminate the problem by placing the properties affecting the
recordset and the cursor on the Recordset object. Now you can
do things like set MaxRows = 100, open the database, or execute
a statement by just calling the Open method on the Recordset,
just as you call Open on the Connection object.

The above code sample shows the Open statement taking some
optional arguments. These arguments are optional because there
are properties on the Recordset that are equivalent to them.
What Microsoft did is give you some shorthand. Using the
shorthand is a definite performance gain, especially when used
with scripting languages.This example is passing in a generic SQL
statement, a source that is represented as a Connection object,
and constantly informing the Recordset object to use a Keyset
cursor when it is opened.

Getting Started with DataDirect for OLE DB


ActiveX Data Objects (ADO) 97

Using the Command Object


Like the Recordset object, the Command object is instantiable
without having to go through a hierarchy of objects. You can
associate it with any Connection object. Commands live on their
own, so you can use a Command with a Connection object and
execute over here, then associate the Command with another
Connection object and execute it over there. The Command
object is not tied to one Connection object for its entire lifetime
and it can travel with different connections.

The following code sample sets the ActiveConnection property


to a connection string; again, it could be set to a Connection
object as well. Then it sets the CommandText, which is just a SQL
string if you are accessing a SQL database. Remember, since
OLE DB providers can be built to provide data from
nonrelational data stores, the CommandText can be any text
that an OLE DB provider can understand.

Dim cmd As New Command

cmd.ActiveConnection = "<con.string>"
cmd.CommandText = "<sql>"

cmd.Parameters(0) = <value>
cmd.Execute

cmd.Parameters(0) = <value>
cmd.Execute

As the example shows, if you had a parameter marker in the SQL


statement, you would set the parameters by using this type of
syntax, just like QueryDefs and prepared statements. Next you
would set its value, and finally call Execute. Parameter objects
are also a way to capture output parameters and can be marked
as a direction of I/O. If the Parameter object is an output
argument and the Command object is a stored procedure call,
the result would be in the Parameter object.

Getting Started with DataDirect for OLE DB


98 Appendix A OLE DB and ADO Programming Samples

For more information on ADO, you can visit

http://www.microsoft.com/data

ADO is also distributed with ASP for use with the Microsoft
Internet Information Server (IIS) and the OLE DB Software
Development Kit.

Leveraging OLE DB and ADO


Let’s take a look at how OLE DB and ADO would be used in an
existing application. Today, your typical monolithic application
contains a number of different things. It generally contains a user
interface and a set of business rules that govern how to access
different types of data. It might have a client/cursor component
in the application if it’s talking to SQL data (and that SQL data
doesn’t support going backwards but your user interface does).
The application may have a query processor for talking to a type
of data that does not have a query processor in it. It probably has
a number of different proprietary interfaces to get to various
different data stores. In short, the application is hard to write,
maintain, and extend due to the number of proprietary
interfaces needed and the code necessary to fill in functionality
not provided by the different types of data stores.

Suppose that the application is getting some data from an ISAM


data store and some data from a SQL database. It has two
different proprietary interfaces: one is the Btrieve interface and
the other is OCI to talk to Oracle. You have a monolithic
application that has multiple interfaces tied to specific APIs. If
you want to point this application at Microsoft SQL Server, you
have to add another interface. If the development group writing
the application was smart enough to use ODBC to get to Oracle
and Microsoft SQL Server, then at least you have one interface to
get to relational databases, but you still need to add a new
interface to get to, say, spreadsheet data.

Getting Started with DataDirect for OLE DB


Conclusion 99

The first step is to replace those proprietary APIs with ADO.


Because ADO will consume any OLE DB provider, once you write
to it you can get to not just ISAM and SQL data, but also things
like HTML pages, email data, spreadsheet data, log file data,
and a host of other information through a single interface. You
can access new types of data without having to add anything to
the application. The application is simpler to write because you
only have to learn one interface, and it is more versatile because
it can talk to more types of data.

Conclusion
The goal of OLE DB is to give applications uniform access to data
stored in DBMS and non-DBMS applications. Using OLE DB,
applications can take advantage of the benefits of database
technology without having to transfer data from its place of
origin to a DBMS.

If you don’t already have the OLE DB specification, get your


hands on it. The openness of the specification and the promise
of accessing any type of data—no matter where or how it is
stored—is information at your fingertips.

Getting Started with DataDirect for OLE DB


100 Appendix A OLE DB and ADO Programming Samples

Figure A-6. Checkbook: Sample Data Consumer © 1997 Microsoft Corporation. All
rights reserved.

///////////////////////////////////////////////////////////////////
// CHECKBOOKDOC.CPP
//
////////////////////////////////////////////////////////////////
#include "stdafx.h"

#define DBINITCONSTANTS
#include "oledb.h"
#include "viewhints.h"
#include "row.h"
#include "Checkbook.h"
#include "CheckbookDoc.h"
#include "checkview.h"
#include "ledgerview.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////
// CCheckbookDoc
IMPLEMENT_DYNCREATE(CCheckbookDoc,CDocument)

BEGIN_MESSAGE_MAP(CCheckbookDoc,CDocument)
//{{AFX_MSG_MAP(CCheckbookDoc)
ON_COMMAND(ID_EDIT_NEW_CHECK, OnNewCheck)
ON_COMMAND(ID_NEXT_CHECK, OnNextCheck)
ON_UPDATE_COMMAND_UI(ID_NEXT_CHECK, OnUpdateNextCheck)
ON_COMMAND(ID_PREV_CHECK, OnPrevCheck)
ON_UPDATE_COMMAND_UI(ID_PREV_CHECK, OnUpdatePrevCheck)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BEGIN_DISPATCH_MAP(CCheckbookDoc, CDocument)
//{{AFX_DISPATCH_MAP(CCheckbookDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
/////////////////////////////////////////////////////////////////

Getting Started with DataDirect for OLE DB


Conclusion 101

// CCheckbookDoc construction/destruction CCheckbookDoc::CCheckbookDoc()


{
// Initialize variables
m_pIDBInitialize = NULL;
m_pIRowset = NULL;
m_pIAccessor = NULL;
m_hAccessor = NULL;
m_nActiveRecord = 0;
m_cColumns = 0;
m_pColumnInfo = NULL;
m_ulMaxRowSize = 0;
}
CCheckbookDoc::~CCheckbookDoc()
{
// Cleanup all of the interfaces and Rows CleanUp();
}
// Release all interfaces that may have been retrieved from the data provider and frees up
// memory that may have been allocated to hold Row data.
void CCheckbookDoc::CleanUp()
{
if (m_pColumnInfo != NULL)
{
CoTaskMemFree (m_pColumnInfo);
m_pColumnInfo = NULL;
}
// Release the accessor
if (m_pIAccessor != NULL)
{
if (m_hAccessor != NULL)
{
m_pIAccessor->ReleaseAccessor(m_hAccessor);
m_hAccessor = NULL;
}
m_pIAccessor->Release();
m_pIAccessor = NULL;
}
// Take care of the ulIndexset nterface and any rows that may
// have been retrieved from the data provider.
if (m_pIRowset != NULL)
{
CRow *pRow = NULL;
POSITION pos = NULL;
// Release all rows held by the data provider
ReleaseRows();

Getting Started with DataDirect for OLE DB


102 Appendix A OLE DB and ADO Programming Samples

// Cleaup the memory that was used to hold the check information in the CObList
m_oblRows.
while ((pos = m_oblRows.GetHeadPosition())
!= NULL)
{
pRow = (CRow *)m_oblRows.GetAt(pos);
m_oblRows.RemoveAt(pos);
if (pRow != NULL)
delete pRow;
}
// Release the rowset interface m_pIRowset->Release();
m_pIRowset = NULL;
}
// Un-Initialize the DSO if (m_pIDBInitialize != NULL)
{
m_pIDBInitialize -> Uninitialize();
m_pIDBInitialize->Release();
m_pIDBInitialize = NULL;
}
}
/////////////////////////////////////////////////////////////////
// CCheckbookDoc diagnostics

#ifdef _DEBUG
void CCheckbookDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CCheckbookDoc::Dump(CDumpContext&dc) const
{
CDocument::Dump(dc);
}
#endif
//_DEBUG
/////////////////////////////////////////////////////////////////
// CCheckbookDoc commands
BOOL CCheckbookDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
HRESULT hr = S_OK;
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
// We have the file name, lets get the CLSID for the Check
// Book Data Provider so that an instance can be created.
CLSID CLSID_OLEDBObject;

Getting Started with DataDirect for OLE DB


Conclusion 103

if (CLSIDFromProgID(OLESTR("CHKBOOKDP.DSO.1"), &CLSID_OLEDBObject) != S_OK)


{
// Can’t get CLSID for OLEDB object ProgID
AfxMessageBox (IDS_FAILED_CLSIDProgID);
return FALSE;
}
// Create an instance of the DSO, obtaining the IDBInitialize interface.
if (CoCreateInstance(CLSID_OLEDBObject, NULL, CLSCTX_SERVER,
IID_IDBInitialize, (LPVOID *)&m_pIDBInitialize) !=S_OK)
{
// Could not instantiate the CheckBook DSO
AfxMessageBox (IDS_FAILED_DSO_INSTANTIATE);
return FALSE;
}
// The next step is to initialize the data provider. During initialization, the
// dataprovider will open or create the checkbook file as necessary.
if ((hr = InitializeDSO(lpszPathName)) =--= S_OK)
{
// Get a Rowset Interface from the data provider
if ((hr = GetRowsetInterface()) =--= S_OK)
{
// Get column information used for the bindings
if ((hr = GetColumnInfo()) =--= S_OK)
{
// Now that the data consumer has the column
// information, set up the DBBINDING structure.
if ((hr = SetupBindings()) =--= S_OK)
{
// Create an Accessor for getting the check
// book data from the data provider.
if ((hr = CreateAccessor()) =--= S_OK)
{
// Fetch all of the data from the data provider
if ((hr = GetData ()) =--= S_OK)
{
// Update both the Check and Ledger views.
UpdateAllViews (NULL, VIEWHINT_GET_ALL_DATA);
}
}
}
}
}
}
if (hr != S_OK)

Getting Started with DataDirect for OLE DB


104 Appendix A OLE DB and ADO Programming Samples

{
// There was a failure, cleanup all interfaces and do not create the document
CleanUp();
return FALSE;
}
return TRUE;
}
// initializes the Check Book data provider by providing the file
// name of the check book .chb file.
HRESULT CCheckbookDoc::InitializeDSO (LPCTSTR lpszPathName)
{
HRESULT hr = S_OK;
GUID rgOptionIDs[1];
VARIANT rgOptionVals[1];
VariantInit(&rgOptionVals[0]);

rgOptionIDs[0] = DBINIT_OPT_NAME;
rgOptionVals[0].vt = VT_BSTR;
CString strPathName = lpszPathName;
rgOptionVals[0].bstrVal = strPathName.AllocSysString();

hr = m_pIDBInitialize->Initialize (1, rgOptionIDs, rgOptionVals);


if (hr != S_OK)
AfxMessageBox(IDS_FAILED_DSO_INITIALIZE);
return hr;
}
// Obtain a Rowset interface from the check book data provider. The ulIndexset
// interface is saved for future uses such as retrieving,updating and adding new checks.
HRESULT CCheckbookDoc::GetRowsetInterface ()
{
HRESULT hr = S_OK;
// Create a DSSession object
IDBCreateSession *pIDBCreateSession = NULL;
hr = m_pIDBInitialize->QueryInterface(IID_IDBCreateSession,
(void **)&pIDBCreateSession);

if (hr =--= S_OK)


{
// From the DBSession object, get the IOpenRowset interface
IOpenRowset *pIOpenRowset = NULL;
hr = pIDBCreateSession ->CreateSession(NULL, IID_IOpenRowset,
(IUnknown **)&pIOpenRowset);
pIDBCreateSession -> Release();
if (hr =--= S_OK)

Getting Started with DataDirect for OLE DB


Conclusion 105

{
hr = pIOpenRowset -> OpenRowset(NULL, NULL, 0, NULL, IID_IRowset, NULL,
(IUnknown **)&m_pIRowset);
pIOpenRowset -> Release();
}
}
return hr;
}
// Retrieves an IAccessor interface and create an accessor that is used for reading
// and writing checks.
HRESULT CCheckbookDoc::CreateAccessor ()
{
HRESULT hr = S_OK;
hr = m_pIRowset -> QueryInterface(IID_IAccessor, (void **)&m_pIAccessor);
if (hr =--= S_OK)
{
ULONG ulErrorBinding = (ULONG)-1L;
hr = m_pIAccessor->CreateAccessor(DBACCESSOR_READWRITE | DBACCESSOR_ROWDATA,
m_ulBindings, m_prgBindings, 0,
&ulErrorBinding, &m_hAccessor);
}
return hr;
}
// Releases all of the HROWS from within the data provider.
HRESULT CCheckbookDoc::ReleaseRows()
{
ASSERT (m_pIRowset);
ULONG ulRows;
HRESULT hr = S_OK;
HROW *prghRows = NULL;
ulRows = m_oblRows.GetCount();
prghRows = (HROW *) CoTaskMemAlloc((sizeof (HROW *)) * ulRows);
if (prghRows != NULL)
{
HROW *pTempRow;
pTempRow = prghRows;
POSITION pos = NULL;
CRow *pRow = NULL;
for (ULONG ulIndex = 0; ulIndex < ulRows; ulIndex++)
{
pos = m_oblRows.FindIndex (ulIndex);
pRow = (CRow *)m_oblRows.GetAt(pos);
*pTempRow++ = pRow -> m_hRow;
}

Getting Started with DataDirect for OLE DB


106 Appendix A OLE DB and ADO Programming Samples

hr = m_pIRowset -> ReleaseRows(ulRows, prghRows, NULL, NULL);


CoTaskMemFree(prghRows);
}
else
hr = E_OUTOFMEMORY;
return hr;
}
// Retrieves a specific check from the CObList and returns the check in a CRow.
BOOL CCheckbookDoc::GetRow (ULONG ulIndex, CRow **pRow)
{
POSITION pos = NULL;
pos = m_oblRows.FindIndex (ulIndex);
if (pos != NULL)
{
*pRow = (CRow *)m_oblRows.GetAt(pos);
return TRUE;
}
return FALSE;
}
// Retrieves check information based on the index into the "checkbook."
BOOL CCheckbookDoc::GetCheck
(ULONG ulIndex, UINT& nCheckNo, DWORD& dwCents, CString& strPayTo, CString& strDate,
CString& strMemo)
{
CRow *pRow;
if (GetRow(ulIndex, &pRow))
{
COLUMNDATA *pColumn;
ASSERT (offsetof(COLUMNDATA, dwLength) =--= 0);
for (ULONG ulIndex=0; ulIndex < m_ulBindings; ulIndex++)
{
pColumn = (COLUMNDATA *) (pRow -> m_pData +
m_prgBindings[ulIndex].obLength);
switch (m_prgBindings[ulIndex].iColumn)
{
case CB_CHECKNO_ORDINAL:
nCheckNo = *(unsigned int *)
pColumn->bData;
break;
case CB_AMOUNT_ORDINAL:
dwCents = *(unsigned long *)
pColumn->bData;
break;
case CB_PAYTO_ORDINAL:

Getting Started with DataDirect for OLE DB


Conclusion 107

strPayTo = (const TCHAR *) &pColumn->bData;


break;
case CB_DATE_ORDINAL:
strDate = (const TCHAR *) &pColumn->bData;
break;
case CB_MEMO_ORDINAL:
strMemo = (const TCHAR *) &pColumn->bData;
break;
}
}
return TRUE;
}
return FALSE;
}
// Updates the active check with the values passed into the member function by using the
// data providers ulIndexsetChange interface.
HRESULT CCheckbookDoc::UpdateData(CView* pSourceView, UINT nCheckNo, DWORD dwCents,
LPCTSTR lpszPayTo, LPCTSTR lpszDate, LPCTSTR lpszMemo)
{
ASSERT (m_pIRowset);
HRESULT hr = S_OK;
IRowsetChange *pIRowsetChange = NULL;
hr = m_pIRowset->QueryInterface(IID_IRowsetChange, (void **)&pIRowsetChange);
if (hr =--= S_OK)
{
CRow *pRow;
if (GetRow(m_nActiveRecord, &pRow))
{
BYTE *pRowData = NULL;
pRowData = (BYTE *) CoTaskMemAlloc (m_ulMaxRowSize);
if (!pRowData)
return E_OUTOFMEMORY;
memcpy(pRowData, pRow -> m_pData, sizeof(*pRowData));
if (S_OK =--= (CopyCheckDataIntoBuffer (pRowData, nCheckNo, dwCents,
lpszPayTo, lpszDate, lpszMemo)))
{
if ((hr = pIRowsetChange -> SetData (pRow -> m_hRow,
m_hAccessor, (const void *)pRowData)) =--= S_OK)
{
memcpy((BYTE *)pRow -> m_pData, (BYTE *)pRowData,
m_ulMaxRowSize);
UpdateAllViews(pSourceView, VIEWHINT_UPDATE_CHECK, NULL);
}
}

Getting Started with DataDirect for OLE DB


108 Appendix A OLE DB and ADO Programming Samples

CoTaskMemFree((void *) pRowData);
}
}
pIRowsetChange -> Release();
return hr;
}
// Function creates a new record by using the ulIndexsetNewRow interface supported by the
// data provider. The new row is added to the CObList and the views are updated
// accordingly.
HRESULT CCheckbookDoc::AddNewCheck()
{
BYTE *pRowData = NULL;
HROW *prghRows = NULL;
HRESULT hr = S_OK;
ASSERT (m_pIRowset);
ASSERT (m_hAccessor);
ASSERT (m_pColumnInfo);
ASSERT (m_ulMaxRowSize != 0);
pRowData = (BYTE *) CoTaskMemAlloc (m_ulMaxRowSize);
if (!pRowData)
return E_OUTOFMEMORY;
IRowsetNewRow *pIRowsetNewRow = NULL;
hr = m_pIRowset->QueryInterface(IID_IRowsetNewRow, (void **)&pIRowsetNewRow);
if (hr =--= S_OK)
{
HROW phRow = NULL;
if ((hr = pIRowsetNewRow -> SetNewData (NULL, m_hAccessor, pRowData,
&phRow)) =--= S_OK)
{
StoreRowData (phRow, pRowData);
// Make this the active check and update the ledger view.
m_nActiveRecord = m_oblRows.GetCount() - 1;
UpdateAllViews(NULL, VIEWHINT_ADD_CHECK);
}
else
CoTaskMemFree (pRowData);
pIRowsetNewRow -> Release();
}
return S_OK;
}
BOOL CCheckbookDoc::MaybeCommitDirtyCheck()
{
CView *pView;
POSITION pos = GetFirstViewPosition();

Getting Started with DataDirect for OLE DB


Conclusion 109

while (pos != NULL)


{
pView = GetNextView(pos);
CCheckView *pCheckView = DYNAMIC_DOWNCAST(CCheckView, pView);
if (pCheckView != NULL)
return pCheckView->MaybeCommitDirtyCheck();
}
return TRUE;
}
// When the user changes the check selection in the ledger view, this member
// function is called to update the check view.
void CCheckbookDoc::ChangeSelectionToCheck(CLedgerView *pLedgerView, ULONG ulIndex)
{
if (!MaybeCommitDirtyCheck())
return;
m_nActiveRecord = ulIndex;
UpdateAllViews (pLedgerView, NULL);
}
// When the user uses the toolbar or menu items to move through the checks,
// this member function is calledto update the view appropriately.
void CCheckbookDoc::ChangeSelectionNextCheckNo(BOOL bNext)
{
if (bNext)
{
if (m_nActiveRecord < (GetNumberOfRows() - 1))
{
if (!MaybeCommitDirtyCheck())
return;
++m_nActiveRecord;
UpdateAllViews(NULL, VIEWHINT_NEXT_CHECK, NULL);
}
}
else
{
if (m_nActiveRecord > 0)
{
if (!MaybeCommitDirtyCheck())
return;
--m_nActiveRecord;
UpdateAllViews(NULL, VIEWHINT_NEXT_CHECK, NULL);
}
}
}
////////////////////////////////////////////////////////

Getting Started with DataDirect for OLE DB


110 Appendix A OLE DB and ADO Programming Samples

// Commands
void CCheckbookDoc::OnNewCheck()
{
// Before creating a new record,which will become the new selection, ask the user
// whether he or she wants to commit data entered in the check view for the
// previously selected check.
if (!MaybeCommitDirtyCheck())
return;
AddNewCheck();
}
void CCheckbookDoc::OnNextCheck()
{
ChangeSelectionNextCheckNo(TRUE);
}
void CCheckbookDoc::OnUpdateNextCheck(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_nActiveRecord < (GetNumberOfRows() - 1));
}
void CCheckbookDoc::OnPrevCheck()
{
ChangeSelectionNextCheckNo(FALSE);
}
void CCheckbookDoc::OnUpdatePrevCheck(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_nActiveRecord > 0);
}
// Function retieves column information from the data provider.
HRESULT CCheckbookDoc::GetColumnInfo ()
{
ASSERT (m_pIRowset);
ULONG pcColumns;
HRESULT hr = S_OK;
DBCOLUMNINFO *prgInfo = NULL;
WCHAR *ppStringsBuffer = NULL;
// Get an interface pointer to IColumnsInfo
IColumnsInfo *pIColumnsInfo = NULL;
hr = m_pIRowset -> QueryInterface(IID_IColumnsInfo,(void **)&pIColumnsInfo);
if (hr =--= S_OK)
{
// Get the Column Information
hr = pIColumnsInfo -> GetColumnInfo(&pcColumns,(DBCOLUMNINFO **)&prgInfo,
(WCHAR **)&ppStringsBuffer);
pIColumnsInfo -> Release();
if (hr =--= S_OK)

Getting Started with DataDirect for OLE DB


Conclusion 111

{
m_cColumns = pcColumns;
m_pColumnInfo = prgInfo;
CoTaskMemFree (ppStringsBuffer);
ppStringsBuffer = NULL;
}
}
return hr;
}
// Function creates bindings that map the data in the rowset’s columns
// to the check book data consumers buffer.
HRESULT CCheckbookDoc::SetupBindings ()
{
ASSERT (m_pColumnInfo);
UINT cBinding = 0;
DWORD dwOffset = 0;
// Since the check book data consumer displays all information about a check, and
// that’s all that the data provider provides, get all of the data.
for (ULONG ulIndex=0; ulIndex < m_cColumns; ulIndex++)
{
m_prgBindings[cBinding].dwPart = DBCOLUMNPART_VALUE |
DBCOLUMNPART_LENGTH | DBCOLUMNPART_STATUS;
m_prgBindings[cBinding].eParamIO= DBPARAMIO_NOTPARAM;
m_prgBindings[cBinding].iColumn= m_pColumnInfo[ulIndex].iNumber;
m_prgBindings[cBinding].dwType= m_pColumnInfo[ulIndex].dwType;
m_prgBindings[cBinding].pTypeInfo= m_pColumnInfo[ulIndex].pTypeInfo;
m_prgBindings[cBinding].pNum= NULL;
m_prgBindings[cBinding].obValue= dwOffset + offsetof(COLUMNDATA,bData);
m_prgBindings[cBinding].obLength= dwOffset + offsetof(COLUMNDATA, dwLength);
m_prgBindings[cBinding].obStatus= dwOffset + offsetof(COLUMNDATA, dwStatus);
m_prgBindings[cBinding].cbMaxLen=
m_pColumnInfo[ulIndex].dwType=--=
DBTYPE_STR ? m_pColumnInfo[ulIndex].cbMaxLength +
sizeof(char) : m_pColumnInfo[ulIndex].cbMaxLength;
m_prgBindings[cBinding].pObject.pUnkOuter = NULL;
m_prgBindings[cBinding].pObject.iid = IID_NULL;
m_prgBindings[cBinding].pObject.pbc = NULL;
dwOffset += m_prgBindings[cBinding].cbMaxLen + offsetof
(COLUMNDATA, bData); cBinding++;
}
m_ulBindings = cBinding;
m_ulMaxRowSize = dwOffset;
return S_OK;
}

Getting Started with DataDirect for OLE DB


112 Appendix A OLE DB and ADO Programming Samples

HRESULT CCheckbookDoc::GetData ()
{
HRESULT hr = S_OK;
HROW *prghRows = NULL;
BYTE *pRowData = NULL;
ULONG ulRowsObtained;
ASSERT (m_pIRowset);
ASSERT (m_hAccessor);
ASSERT (m_pColumnInfo);
while (TRUE)
{
hr = m_pIRowset->GetNextRows(0, 0, 20, &ulRowsObtained, &prghRows);
if (FAILED(hr))
return hr;
// check to see the data provider returned any rows
if (ulRowsObtained =--= 0)
break;
// For each row, get the checkbook data from the ata provider
for (ULONG ulIndex = 0; ulIndex < ulRowsObtained; ulIndex++ )
{
pRowData = (BYTE *) CoTaskMemAlloc(m_ulMaxRowSize);
if (!pRowData)
return E_OUTOFMEMORY;
hr = m_pIRowset->GetData(prghRows[ulIndex], m_hAccessor, pRowData );
if (FAILED(hr))
{
// Free the task memory allocated by the data provider
CoTaskMemFree(prghRows);
if (pRowData)
CoTaskMemFree(pRowData);
return hr;
}
StoreRowData (prghRows[ulIndex], pRowData);
m_nActiveRecord = m_oblRows.GetCount() - 1;
}
// Free the task memory allocated by the data provider
CoTaskMemFree(prghRows);
prghRows = NULL;
}
return S_OK;
}
HRESULT CCheckbookDoc::StoreRowData
(HROW phRow, BYTE *pData)
{

Getting Started with DataDirect for OLE DB


Conclusion 113

CRow *pRow = NULL;


HRESULT hr = S_OK;
COLUMNDATA* pColumn;
DWORD dwStatus, dwLength;
ASSERT (offsetof(COLUMNDATA, dwLength) =--= 0);
pRow = new CRow;
if (pRow =--= NULL)
return E_OUTOFMEMORY;
// Do some coersion error checking first before storing the data
for (ULONG ulIndex=0; ulIndex < m_ulBindings; ulIndex++)
{
pColumn = (COLUMNDATA *) (pData + m_prgBindings[ulIndex].obLength);
dwStatus = pColumn->dwStatus;
dwLength = pColumn->dwLength;
if (dwStatus =--= DBCOLUMNSTATUS_CANTCOERCE)
// Have a problem, therefore return an error
hr = E_UNEXPECTED;
else

{
switch (m_prgBindings[ulIndex].dwType)
{
case DBTYPE_UI8:
// Make sure this is the Amount Column
if (!m_prgBindings[ulIndex].iColumn =--=
CB_AMOUNT_ORDINAL)
hr = E_UNEXPECTED;
break;
case DBTYPE_UI4:
// Make sure this is the Check Number Column
if (!m_prgBindings[ulIndex].iColumn =--=
CB_CHECKNO_ORDINAL)
hr = E_UNEXPECTED;
break;
case DBTYPE_STR:
// Process the string related columns
if (!(m_prgBindings[ulIndex].iColumn =--=
CB_PAYTO_ORDINAL ||
m_prgBindings[ulIndex].iColumn =--= CB_DATE_ORDINAL ||
m_prgBindings[ulIndex].iColumn =--= CB_MEMO_ORDINAL))
hr = E_UNEXPECTED;
break;
default:
hr = E_UNEXPECTED;

Getting Started with DataDirect for OLE DB


114 Appendix A OLE DB and ADO Programming Samples

break;
}
if (hr != S_OK)
break;
}
}
if (hr != S_OK)
delete pRow;
else
{
// Save the check information i a CObList
pRow -> m_hRow = phRow;
pRow -> m_pData = pData;
m_oblRows.AddTail (pRow);
}
return hr;
}
HRESULT CCheckbookDoc::CopyCheckDataIntoBuffer BYTE *pData, UINT nCheckNo,
DWORD dwCents, LPCTSTR lpszPayTo, LPCTSTR lpszDate, LPCTSTR
lpszMemo)
{
HRESULT hr = S_OK;
COLUMNDATA* pColumn;
DWORD dwStatus, dwLength;
ASSERT (offsetof(COLUMNDATA, dwLength) =--= 0);
for (ULONG ulIndex=0; ulIndex < m_ulBindings; ulIndex++)
{
pColumn = (COLUMNDATA *) (pData +
m_prgBindings[ulIndex].obLength);
dwStatus = pColumn->dwStatus;
dwLength = pColumn->dwLength;
switch (m_prgBindings[ulIndex].dwType)
{
case DBTYPE_UI8:
if (m_prgBindings[ulIndex].iColumn =--=
CB_AMOUNT_ORDINAL)
*(unsigned long *)pColumn->bData = dwCents;
else
hr = E_UNEXPECTED;
break;
case DBTYPE_UI4:
if (m_prgBindings[ulIndex].iColumn =--=
CB_CHECKNO_ORDINAL)
*(unsigned int *)pColumn->bData = nCheckNo;

Getting Started with DataDirect for OLE DB


Conclusion 115

else
hr = E_UNEXPECTED;
break;
case DBTYPE_STR:
if (m_prgBindings[ulIndex].iColumn =--=
CB_PAYTO_ORDINAL)
_tcscpy((TCHAR *) &pColumn->bData,lpszPayTo);
else if (m_prgBindings[ulIndex].iColumn =--=
CB_DATE_ORDINAL)
_tcscpy((TCHAR *) &pColumn->bData, lpszDate);
else if(m_prgBindings[ulIndex].iColumn =--=
CB_MEMO_ORDINAL)
_tcscpy((TCHAR *) &pColumn->bData, lpszMemo);
else
hr = E_UNEXPECTED;
break;
default:
hr = E_UNEXPECTED;
break;
}
if (hr != S_OK)
break;
}
return hr;
}

Getting Started with DataDirect for OLE DB


117

B OLE DB Data Providers and


Data Access Over the Web

DataDirect Connect OLE DB data providers support data access


through a Web browser application using the OLE DB-based
components available from Microsoft. These Microsoft
components include:

■ Remote Data Services (RDS) objects. These programming


objects are a subset of the ActiveX Data Objects (ADO). RDS
objects are designed specifically for creating Web-based data
access applications. RDS objects can accept data queries from
a Web page and send them to Internet Information Server
(IIS) running on a Web server. RDS is included in Internet
Explorer 4.0.

■ Internet Information Server (IIS). This server includes a


complete set of tools, including RDS and Internet
Information Server API (ISAPI), for building data access Web
applications.

■ Windows NT Server 4.0. This server supports RDS and the


other tools available through IIS.

This appendix introduces the model of data access over the Web
using OLE DB data providers. You can find specific information
about implementing a Web-based data access solution from the
Microsoft World Wide Web site.

Getting Started with DataDirect for OLE DB


118 Appendix B OLE DB Data Providers and Data Access Over the Web

Overview of Web-based Data Access with


OLE DB
Data access over the Web requires communication of data
requests between a Web client and a Web server, and between a
Web server and a data store (see Figure B-1 on page 119). If
OLE DB data providers are used to access the data stores, the data
requests, or queries, from the Web client must be formulated
using the OLE DB interface.

In addition, the queries and their results must be transportable


using the HTTP Web transport protocol. Finally, the results
returned from the data store must be interpreted and displayed
at the Web client in a tabular format. These requirements are
described in more detail in the following sections.

How Does the Web Client Make a


Query?
The user’s client Web browser provides an HTML form or a Web
application that lets the user enter a query and submit it. The
HTML form or Web application uses client programming
elements to send the user’s query through HTPP transport
protocol and call a program on the Web server that can process
the query.

Web Client Requirements


■ Internet Explorer 4.0 or higher Web browser

■ HTML form or Web application available on a Web page


accessible to the browser

Getting Started with DataDirect for OLE DB


Overview of Web-based Data Access with OLE DB 119

■ Microsoft Remote Data Services (RDS) objects. On the client,


RDS can:

• Send the query to the Web server using HTTP transport


protocol

• Display data records in the client Web browser when the


records are returned from the Web server

Figure B-1. Overview of Data Access Over the Web Using OLE DB Data Providers

Web Client Browser Web Server Data Stores

DBMS
2 4

1 3 5

1 Users submit queries from their local Web browsers.


2 HTTP protocol is used to transmit queries and results.
3 Web server programs receive client queries, establish connections
to data stores through OLE DB data providers, receive results from
data providers, and return results to Web client.
4 OLE DB data providers access data stores, receive results of
queries, return data in OLE DB Rowset format to Web server
programs.
5 Relational and nonrelational data stores that can be accessed
through OLE DB data providers.

Getting Started with DataDirect for OLE DB


120 Appendix B OLE DB Data Providers and Data Access Over the Web

How Does the Web Server Process the


Query?
The Web server contains objects that provide read and write
access to data sources. These objects are used to contain the
client query and pass it to the appropriate OLE DB data provider.
The objects also accept the results returned from the data
provider and send them back to the RDS components on the Web
client.

Web Server Requirements


■ Microsoft Windows NT Server 4.0 or higher

■ Microsoft Internet Information Server (IIS) for Web-specific


data access functions

■ OLE DB data providers configured for data sources that access


available data stores

■ Microsoft Remote Data Services (RDS) objects. On the server,


RDS uses IIS to:

• Send the query to the OLE DB data provider


• Receive results from the data provider and send them over
HTTP to RDS components on the Client, where they are
interpreted, formatted and displayed in the client Web
browser

Getting Started with DataDirect for OLE DB


Overview of Web-based Data Access with OLE DB 121

Figure B-2 shows the Web configuration required to access data


through OLE DB data providers.

Figure B-2. Components Required to Use OLE DB Providers over the Web

User enters Internet


query Information Server
(IIS) and Remote
Data Services (RDS) DBMS
receive query from
Remote Data Client and send to
Services (RDS)
1 OLE DB Providers
pass query
to server
DBMS
OLE DB Providers
Web Client receive queries
HTML Page from server and
send to data stores

Microsoft Windows NT
DBMS
Server 4.0 or higher
Data Stores

Getting Started with DataDirect for OLE DB


122 Appendix B OLE DB Data Providers and Data Access Over the Web

Getting Started with DataDirect for OLE DB


123

C Comparing OLE DB and


ODBC Features

The goal of this appendix is to aid Open Database Connectivity


(ODBC) programmers in understanding and using OLE DB. It
discusses the relationship of ODBC calls to corresponding OLE DB
methods and the related programming issues.

The material that follows in this appendix is derived from the


White Paper OLE DB for the ODBC Programmer by Microsoft
Corporation, and is used with the permission of Microsoft.

ODBC and OLE DB each provide a rich application programming


interface for the database developer. OLE and the component
object model present the ODBC developer with an entirely new
way of writing. The ODBC developer, familiar with procedural
programming, must become comfortable with the world of OLE
objects and the interface negotiation required to manipulate
those objects.

In addition, OLE DB often presents a new implementation of


familiar development concepts like tabular data structures. The
ODBC developer will need to rethink application structure to
make effective use of OLE DB’s sessions, property sets, rowsets,
and accessors.

Becoming comfortable with OLE objects is a first step toward


successful OLE application development. The information
presented builds on the ODBC database developer’s existing
knowledge to smooth the introduction to this new and different
technology.

Getting Started with DataDirect for OLE DB


124 Appendix C Comparing OLE DB and ODBC Features

Initializing the Environment


In ODBC, the application generally dynamically links to the ODBC
Driver Manager (ODBC32.DLL). The Driver Manager loads and
directs calls to the appropriate driver.

In OLE DB, initialization of the environment is achieved by a call


to OleInitialize, which initializes the OLE library. After the OLE
library is initialized, the proper data provider is loaded by the
system according to its class ID, and calls are made directly to the
provider.

Initializing a Data Source Object


The data source object exposes the IDBInitialize and
IDBProperties interfaces that contain the methods to connect to a
data source. The authentication information such as user ID,
password, and the name of the data source are specified as
properties of the data source object by calling
IDBProperties::SetProperties. The method IDBInitialize::Initialize
uses the specified properties to connect to the data source.

Getting Started with DataDirect for OLE DB


Initializing a Data Source Object 125

Table C-1 compares the steps required to initialize a data source


object.

Table C-1. Differences in Establishing a Connection

ODBC OLE DB
1 Call SQLAllocHandle to allocate a 1 Build an array of property structures
connection handle. describing the authentication
information, such as user ID,
2 Build a connection string containing
password, and the name of the data
keywords for authentication
source, as well as the level of
information, such as user ID,
prompting and the application’s
password, and the name of the data
window handle when appropriate.
source.
2 Call IDBProperties::SetProperties to
3 Call SQLDriverConnect providing the
set initialization properties.
connection string and other
information, such as level of 3 Call IDBInitialize::Initialize to
prompting and the application’s initialize the data source object.
window handle where appropriate.

The primary differences can be summarized as follows:

■ OLE DB uses a well-defined set of property structures to


represent the initialization and connection information,
rather than building/parsing keywords within a connection
string.

■ The set of property structures are used for all of the


initialization and connection information.

■ The set of available initialization properties can be queried


through IDBProperties::GetPropertyInfo.

Getting Started with DataDirect for OLE DB


126 Appendix C Comparing OLE DB and ODBC Features

■ Setting the initialization properties is separate from actually


initializing (connecting) the data source. This allows the
consumer to set, persist, and retrieve connection information
without initializing (connecting) the data source.

■ Rather than returning a connection string, the user can simply


request the current set of initialization property values.

Getting a Session and Executing a Command


The data source object exposes the IDBCreateSession interface
through which a session object can be created. A session defines
transaction scope and acts mainly as a command generator by
supporting the IDBCreateCommand interface. Commands
contain a DML query or a DDL definition. The execution of a row-
returning command yields a rowset object.

The session object in OLE DB is similar to the ODBC connection


handle. The connection handle in ODBC, however, is used for
establishing connections as well as scoping transactions, so the
application must allocate and connect a separate connection
handle for each concurrent transaction. In OLE DB, you can have
multiple session objects on one initialized data source object,
which means you can have multiple concurrent transactions
without having to make multiple connections (where necessary,
the data provider makes additional connections using the
connection information provided in the initialization of the data
source object).

The command object in OLE DB is similar to the ODBC statement


handle in the unexecuted state. Like the ODBC connection
handle, which can have several statement handles, a session
object can have several command objects.

Getting Started with DataDirect for OLE DB


Getting a Session and Executing a Command 127

Executing a Command
Table C-2 summarizes the steps to execute a command:

Table C-2. Comparing Executing a Command

ODBC Application Steps OLE DB Consumer Steps


1 Call SQLAllocHandle to allocate a 1 Calls IDBCreateCommand to create a
statement. command.

2 Call SQLSetStmtAttr to set various 2 Calls ICommandProperties::SetProperties


attributes that affect how the to set various attributes that affect how
command is executed (such as the command is executed (such as query
query time-out) and how the time-out), as well as requesting properties
cursor is opened (such as to be supported by the resulting rowset.
scrollability, updatability, and so Typical properties include scrollability,
on). updatability, the number of active row
handles a consumer can hold at one time,
3 Call SQLPrepare if it wants to
sensitivity to changes outside the rowset,
prepare the statement for
and so on.
repeated execution.
3 Calls ICommandText::SetCommandText to
4 Call SQLExecute or SQLExecDirect
specify the command text, along with a
to execute the query.
GUID representing the command’s dialect.
The standard dialect for ANSI SQL
commands is DBGUID_DBSQL.

4 Calls ICommandPrepare::Prepare if it
wants to prepare the query for repeated
execution.

5 Calls ICommandText::Execute to execute


the command.

Getting Started with DataDirect for OLE DB


128 Appendix C Comparing OLE DB and ODBC Features

Retrieving a Row of Data from a Result


Set
The data provider manages the row buffers on behalf of the
consumer. Rows are fetched from the data source into this row
buffer using methods such as IRowset::GetNextRows,
IRowsetLocate::GetRowsAt, and
IRowsetLocate::GetRowsByBookmark. These methods are similar
to SQLExtendedFetch in ODBC, except that instead of reading the
data into the applications buffers, these functions read the data
into the shared data object and return row handles (hRows) to
the fetched data.

The data consumer accesses the data from these row handles
using IRowset::GetData. IRowset::GetData takes an accessor that
maps fields of the row to and/or from fields in a structure on the
consumer side. The types of the fields in the data consumer’s
structure are indicated by the bindings in the accessor, and
IRowset::GetData makes any necessary conversions between the
buffered data and the consumer’s data structure. If GetData
encounters an error, it sets the status value for the column to the
appropriate error.

Getting Started with DataDirect for OLE DB


Getting a Session and Executing a Command 129

Table C-3 summarizes the steps in retrieving a row of data from a


result set:

Table C-3. Retrieving a Row of Data

ODBC OLE DB Consumer


1 Calls SQLBindCol to bind the 1 Calls IAccessor::CreateAccessor to
columns of the result set to storage specify binding information if not
locations, if not already done. already done.

2 Calls SQLFetch to move to the next 2 Calls IRowset::GetNextRows to


row and retrieve data for all bound retrieve the next set of row handles.
columns.
3 Calls IRowset::GetData to retrieve the
3 Calls SQLGetData to retrieve data data from the row handles according
from unbound columns. to the bindings specified by the
accessor.

IRowset::GetData is similar to SQLGetData in ODBC, except that


IRowset::GetData:

■ Can be called for any held row handle, not just the current
row

■ Allows the retrieval of multiple columns in a single call

■ Can return an interface to a live OLE object, not just a binary


large object (BLOB)

■ Can be used to return a pointer to data within the provider


rather than a copy of the data

■ Returns an interface to a stream over the object rather than


retrieve long data through multiple calls to SQLGetData

Getting Started with DataDirect for OLE DB


130 Appendix C Comparing OLE DB and ODBC Features

Describing Query Results


Table C-4 compares the methods for describing the results of a
query.

Table C-4. Describing Query Results

ODBC Application OLE DB Application


■ Calls SQLNumResultCols to find out ■ Calls IColumnsInfo or IColumnsRowset
the number of columns in the result to describe the columns in the rowset.
set.

■ Calls SQLDescribeCol or
SQLColAttribute to describe each
column in the result set.

In OLE DB, the consumer can also call IRowsetInfo to get


information about properties supported on the rowset. This is
similar to calling SQLGetStmtAttr on an executed statement
handle in ODBC.

Accessors and Descriptor Handles


Accessors in OLE DB are similar to descriptor handles in ODBC.
Each represents a reusable, extensible set of binding information
for multiple columns of a result set or parameters to a statement.
Multiple accessors can be created for a single rowset, just as
multiple descriptors can be used on a single result set. Accessors
can be created on a command object so that they can be shared
between multiple rowsets the same way that descriptors can be
shared between multiple result sets (hStmts).

The main difference between descriptors and accessors is that


SQLSetDescField is called multiple times to set individual
properties for each column represented by the descriptor, while

Getting Started with DataDirect for OLE DB


Locating a Data Source 131

all of the binding information for an accessor is built into an


array of binding structures that is passed in a single call to
CreateAccessor. This is partially addressed in ODBC by the
presence of concise functions, such as SQLBindCol and
SQLSetDescRec, that allow the application to specify the most
common subset of binding information in a single call per
column.

Table C-5. Accessors and Descriptors

To use an ODBC descriptor handle, the To use an OLE DB accessor, the


application application
■ Calls SQLAllocHandle to allocate a ■ Creates an array of binding structures,
descriptor handle. each describing the binding
information for a single column.
■ Calls SQLSetDescField for each piece
of binding information on each ■ Calls CreateAccessor to create an
column. accessor handle using the binding
information.

Locating a Data Source


In ODBC, the application generally calls SQLDataSources to
enumerate the different ODBC data sources installed on the
computer. The application can also call SQLDrivers to enumerate
the specific drivers and connect to them directly, without a data
source. ODBC version 3.0 defines the concept of a file DSN,
which is a data source definition that lives as a file in the file
system.

In OLE DB, consumers can browse for data sources using an


enumerator. Enumerators provide a recursive, hierarchical model
for browsing data sources. This model is similar to browsing for
files in the file system, where a folder is represented by an
enumerator and a file is represented by a data source. Just as

Getting Started with DataDirect for OLE DB


132 Appendix C Comparing OLE DB and ODBC Features

folders can enumerate other folders as well as files, an


enumerator can enumerate other enumerators as well as data
sources.

A root enumerator provided as part of the OLE DB SDK generates


a rowset of available data providers and enumerators. Binding to
a data source returns an uninitialized data source object for that
data source.

Once created, a data source object can be persisted as a file in the


file system. Binding a file moniker to one of these persisted data
sources generates an uninitialized data source object with a
particular state, such as a data source name or location. Persisted
data sources are equivalent to file DSNs in ODBC version 3.0. The
consumer must still initialize the data source object after it is
loaded.

Getting Started with DataDirect for OLE DB


Glossary 133

Glossary

accessors In OLE DB, a collection of information that describes how


data is stored in the consumer’s buffer. It contains the
binding information for one or more columns or
parameters. Consumers can use more than one accessor
or a single accessor can define the mapping between a
structure and multiple columns or parameters. Accessors
are similar to descriptor handles in ODBC.

ActiveX Data Objects A high level object-oriented database API built on


(ADO) OLE DB. Microsoft’s automation server exposes a
high-level set of database programming objects to the
Visual Basic, Java, or C++ programmer on top of an
OLE DB data source. ADO can be used to create business
applications that access OLE DB data sources.

ANSI American National Standards Institute.

attribute pairs Values that control various aspects of the provider’s


connection and interaction with the database. The
values can be entered in a provider string.

autocommit mode A transaction commit mode in which all actions taken in


a transaction are committed immediately after they are
performed. Contrast with manual-commit mode.

Backus-Naur Form A language that is used to describe another language.


(BNF)

Binary Large Object Any binary or character data larger than a certain
(BLOB) number of bytes (for example, the MAPI documentation
defines a range of 4 KB to 16 KB). In OLE DB, BLOBs are
generally sent and retrieved from the data source in
parts.

Getting Started with DataDirect for OLE DB


134 Glossary

binding In OLE DB, the association of a piece of memory in the


data consumer’s buffer with a column of data in a
Rowset. The caller supplies this information to describe a
data structure with offsets for each value.

bookmark A value that identifies a row in a rowset. Bookmarks are


saved by the consumer and used later in the life of a
rowset to retrieve a particular row.

Cartesian product The Cartesian product of a set of n tables is the table


consisting of all possible rows r such that r is the
concatenation of a row from the first table, a row from
the second table ...and a row in the nth table.

catalog A database object that contains one or more schemas.

COM Component Object Model (COM). Microsoft’s general


architecture for component-based software. An OLE
object-oriented model that defines how objects interact
within a single process or between processes. In COM,
clients have access to an object through interfaces
implemented on an object.

COM object An object that conforms to the OLE Component Object


Model (COM). A COM object is an instance of an object
definition, which specifies the object's data and one or
more implementations of interfaces on the object. Clients
interact with a COM object only through its interfaces.

commit To make the changes in a transaction permanent.

Component Object A way to define a group of COM objects, such as rowsets


Type (CoType) or commands, that have similar characteristics. All COM
objects that belong to a particular CoType must expose
the mandatory interfaces in that CoType. In addition,
they can expose the optional interfaces in the CoType and
any interfaces not in the CoType.

Getting Started with DataDirect for OLE DB


Glossary 135

component software An environment where users can add features to


applications by buying additional components.

connection A definition that specifies an OLE DB provider and the


associated provider properties that are required to
connect to a specific data store. For example, the user ID,
data source name, and password might be required.
These values would be specified in the connection.

connection point An OLE DB relational provider uses connection points


(notification sinks) to notify a consumer of an event with
IConnectionPoint.

To receive notifications, the consumer must implement


IRowsetNotify, and register it on a connection point with
the data provider. When a specified event occurs, the
client application must perform an action with the
notification.

consumer See data consumer.

container A collection of messages or address information, such as


an address book or distribution list. MAPI stores address
and message information in containers. Because each
folder or subfolder in a Messages store is defined as a
container of messages, an OLE DB provider for MAPI can
consider folders to be tables or rowsets.

CoType Component Object Type. A way to define a group of


COM objects, such as rowsets or commands, that have
similar characteristics.

Getting Started with DataDirect for OLE DB


136 Glossary

data consumer Application code that uses data presented through an


OLE DB interface. Such code is said to consume an OLE DB
interface. OLE DB components like data providers and
service components can also be consumers if they
consume other providers.

Data Definition One of the components of SQL. DDL is concerned with


Language (DDL) commands that create and maintain the database, for
example, Create Table and Drop Table.

Data Manipulation Text commands that manipulate data, as opposed to


Language (DML) defining data. Examples include the SQL statements
Insert, Update, Delete, and Select.

data provider An OLE DB provider, such as one of the DataDirect


OLE DB components, that exposes data.

data source A collection of all the information necessary to connect to


a data store. OLE DB data sources can include a provider
name, a database name, or a catalog name and a schema
name. The connection information required for a data
source is determined by the OLE DB components used to
make the connection and the data store they are
connecting to.

data store The data that the user wants to access, such as the data in
a database, file, or array. A data store owns data and
exposes its data in a tabular form as a rowset over a
native data format. Data stores can include a full SQL
DBMS, an ISAM file, or a text file or data stream.

data type The type of a piece of data. The data type of a consumer
variable, a parameter, or a column is identified by a type
indicator.

Getting Started with DataDirect for OLE DB


Glossary 137

Database Manage- A layer of software between the physical database and


ment System (DBMS) the user. The DBMS manages all access to the database.
An OLE DB data provider can be built directly on top of a
DBMS or as a layer between the DBMS and the data
consumer.

DCOM Distributed Component Object Model (DCOM). An


extension to Microsoft’s general architecture for
component-based software. DCOM supports
communication between COM components, such as
ActiveX controls and Java applets, that are distributed
over a network.

DDL Data definition language.

direct connection A connection that does not use a catalog. A direct


connection is faster than a data source connection that
uses a catalog, because it does not have to wait for the
system to look up information. However, a direct
connection cannot access views.

DML Data manipulation language.

enumerator An OLE DB object that searches for data sources and


other enumerators.

error object An object that contains detailed information about an


error.

event An action taken by a provider, of which the provider


notifies the consumer. For example, the provider notifies
the consumer when a row is added or a column is
deleted.

fetch To retrieve one or more rows from the data store and
instantiate them in a rowset.

Getting Started with DataDirect for OLE DB


138 Glossary

file moniker A persistent file name that contains information that can
be used to identify objects that are saved as files. It is
based on a path in the file system.

foreign key One or more columns that match the primary key in
another table.

Globally Unique A 16-byte value that uniquely identifies something,


Identifier (GUID) usually the software that implements one or more COM
objects or an interface on one of those objects.

GUID Globally Unique Identifier.

index rowset A rowset built over an index in a data source. It is usually


used with a rowset built over a base table in the same
data source.

infix operator An operator that appears between two operands.

initialize To change the state of an enumerator or data source


object so that it can be used to access data. For example,
initializing a data source object might require the data
provider to open a data file or connect to a database.

instantiate To create an instance of a COM object. For example, to


change the state of a data source object so that it can be
used to access data. Initializing a data source object might
require the data provider to open a data file or connect
to a database.

interface A group of semantically related functions that provide


access to a COM object. Each OLE DB interface defines a
contract that allows objects to interact according to the
Component Object Model (COM). While OLE DB provides
many interface implementations, most interfaces can also
be implemented by developers designing OLE DB
applications.

Getting Started with DataDirect for OLE DB


Glossary 139

key One or more columns whose values uniquely identify a


row.

manual-commit mode A transaction commit mode in which transactions must


be committed or terminated by calling
ITransaction::Commit or ITransaction::Abort.

manufactured schema A schema generated by the Reflector OLE DB component


that consists of the Connection Name, the pound sign
(#), and the local schema that contains the table.

Messaging Applica- Microsoft’s method of sending electronic mail across a


tion Programming local area network (LAN).
Interface (MAPI)

metadata Data that describes a parameter in a text command or a


column in a rowset. For example, the data type, length,
and updatability of a column.

method In object-oriented programming, a function in an


interface.

middleware Software that mediates the communication between an


application and a data store. The middleware provides
an interface that manages the differences in the
application’s and the data store’s data formats.

moniker A COM object that contains information that can be


used to create and initialize an instance of a specific
COM object. A client can use a moniker to locate that
object, activate it when necessary, and get a pointer to
one of the object’s interfaces.

Clients of COM objects can create and initialize the


objects without using a moniker. However, using a
moniker can simplify complex initialization operations
for the client.

Getting Started with DataDirect for OLE DB


140 Glossary

nonrelational data Data that is not stored with logical relationships attached
to it. For example, email data and word processing files
are nonrelational data. Contrast with relational data.

nonrelational A database that stores nonrelational data. Examples


database include Lotus Notes and hierarchical data in ISAM files,
IMS, and DL/I.

notification A call, using OLE notification sinks (IConnectionPoint),


from a data provider to notify a consumer that an event is
occurring. When the event occurs, the client application
must perform an action with the notification. The
consumer must implement IRowsetNotify and register it
on a connection point with the data provider.

The provider performs the notification, but does not


expect or wait for a response.

notification sink An object that implements the notification interface.

object Compiled code that provides a service to the rest of the


system. Within an OLE DB context, an object is the same
as a component.

Object Linking and Microsoft’s object-based technology for sharing


Embedding (OLE) information and services across machine and process
boundaries.

ODBC Microsoft’s Open Database Connectivity (ODBC)


specification. The ODBC specification for an Application
Programming Interface (API) allows applications to access
multiple database systems using Structured Query
Language (SQL). For detailed information on ODBC, refer
to the Microsoft programming documentation on ODBC.

Getting Started with DataDirect for OLE DB


Glossary 141

OLE DB A set of interfaces that exposes data from a variety of


data sources using COM. OLE DB enables
standards-based access to both relational and
nonrelational data stores through reusable components.
For detailed information on OLE DB, refer to the
Microsoft programming documentation on OLE DB.

OLE DB Automation An error object that conforms to the standards specified


error object for such objects by OLE Automation.

OLE DB error object An error object used by OLE DB to return an error.


OLE DB error objects are an extension of OLE DB
Automation error objects.

persist To save the current state of a COM object, such as to a


file. In OLE DB, only data source objects can be persisted.
Objects can be restored from their persisted state, saving
initialization steps.

phase A step in a sequence of notifications caused by a single


event. The sequence of notifications is similar to the
phases in a two-phase commit protocol.

postfix operator An operator that is preceded by its operands.

primary key One or more columns that uniquely identify a row in


a table.

property Attributes of an OLE DB object. For example, the


maximum number of rows in a rowset that can be active
at one time.

property group The set of all properties that apply to a particular OLE DB
object. For example, the Rowset property group specifies
whether a rowset supports bookmarks and whether it
can fetch backwards.

Getting Started with DataDirect for OLE DB


142 Glossary

provider A COM object that implements the OLE DB interfaces and


methods. See data provider and service component.

query processor Given a statement in some query language (that is, SQL),
a query processor determines a query plan for a
statement, executes the query plan, and returns a
result set.

RDB Relational database.

relational data Data that is stored with logical relationships attached to


it. For example, databases like Oracle and Sybase contain
relational data. Contrast with nonrelational data.

relational database A database that exposes its data as a two-dimensional


table, that is, using rows and columns. Examples include
Oracle and Informix.

relational data A data provider for a relational database. Examples


provider include Connect OLE DB for Oracle and the SequeLink
OLE DB Provider.

rowset An OLE DB COM object that exposes data in tabular


format. A rowset comprises a set of rows in which each
row has columns of data.

schema A collection of logical structures of data, or schema


objects. A schema is owned by a database user and has
the same name as that user ID. Each user ID owns a single
schema. Schema objects, which include tables and views,
can be created and manipulated with SQL.

schema rowset A predefined rowset that provides information about the


structure of a database.

SDK Software Development Kit.

Getting Started with DataDirect for OLE DB


Glossary 143

service component An OLE DB component that exposes OLE DB interfaces


for complex data processing services. For example, a
query processor component exposes OLE DB interfaces
for processing SQL strings sent by applications (data
consumers). This type of service provider is a query
processor. The query processor’s OLE DB interfaces accept
complex SQL strings from applications and process them
to an OLE DB level that can be understood by an
underlying OLE DB provider. This data provider can then
process the converted SQL request to the target data
store and return the results to the query processor. The
query processor then converts these results to the
complex data format expected by the requesting
application. As the intermediary between the
application and the underlying data provider, a service
provider acts as both a data provider and a data
consumer.

In version 1.5 and earlier of the Microsoft OLE DB


specification, this component was called a service
provider.

service provider (OLE DB 1.0 and OLE DB 1.5) An OLE DB component that
exposes OLE DB interfaces for complex data processing
services. See service component.

A MAPI service provider is a shared library that


implements MAPI service provider interfaces to a
message store or address book.

session An OLE DB object that serves as the context for a


transaction.

SQL Structured Query Language. A language used by


relational databases to query, update, and manage data.

Getting Started with DataDirect for OLE DB


144 Glossary

table A database object that formats data as rows and columns.


Data in the rows and columns are related. The nature of
their relationship is specified by the user who requests
the data.

token The smallest independent unit of meaning as defined by


a lexical analyzer or a parser.

transaction A logical unit of work. Consumers use transactions to


define units of work with atomicity, concurrency,
isolation, and durability properties within a provider. You
can use transactions to specify isolation levels, which
enables more flexible access to data among concurrent
consumers.

type indicator An integer value that is passed to or returned from an


OLE DB method to indicate the data type of a consumer
variable, a parameter, or a column.

Unicode Worldwide character encoding standard from the


Unicode Consortium. String parameters for all COM
interface methods are passed as Unicode rather than
ANSI strings, except for getting and setting ANSI data
that resides in tables. Alternatively, the component can
return actual data as ANSI strings. If the data consumer
requests a different binding for a particular property, the
OLE DB component can perform the appropriate
conversion using the OLE DB conversion routines.

Universal Data Access A Microsoft strategy based on ADO, OLE DB, and ODBC
(UDA) that lets users get to data in different data stores through
a common set of interfaces, regardless of where the data
resides or what type of data it is.

view A named, derived virtual table that represents the result


set of a query. A view appears as a table to the user.

Getting Started with DataDirect for OLE DB


Glossary 145

Virtual Table An in-memory relational data cache that exposes OLE DB


Manager (VTM) interfaces for data access and manipulation. The VTM
consumes as well as exposes OLE DB interfaces.

zombie A state in which the only valid consumer action on a


COM object is generally to release that object.

Getting Started with DataDirect for OLE DB


146 Glossary

Getting Started with DataDirect for OLE DB


Index 147

Index

A D
accessor data access through OLE DB 19
creating 74 data source
using in OLE DB 130 defining with Reflector 49
ActiveX Data Objects (ADO) 89 locating 131
ADO, sample data consumer call 62 data source object, initializing 124
DataDirect for OLE DB,overview 7
DataDirect OLE DB components
advantages 32
B examples of use 32
summary of products and features 37
bindings, creating 71 descriptor handles 130
books, for DataDirect OLE DB products 9 documentation, related 9

C E
Command object 97 Error object 94
Connect OLE DB ErrorObject 85
basics 21 executing a command 126
overview of Connect OLE DB
Nonrelational Data Providers 42
Connect OLE DB for MAPI 42
Connect OLE DB for MAPI typical tasks 41 F
Connect OLE DB for Notes 42
Connect OLE DB for Notes typical tasks 41 Field object 94
Connect OLE DB Relational Providers,
using 44
Connection object 91, 95
contacting Technical Support 13 G
Conventions used in this manual 11
creating bindings 71 getting a session 126

Getting Started with DataDirect for OLE DB


148 Index

I initializing the environment 124


overview of the basics 18
programming samples 65
initializing using for data access 19
data source object 124
the environment 124
interfaces
base-level 67
new for OLE DB 66
P
Introduction to DataDirect for OLE DB 7
Parameter object 93

L R
leveraging OLE DB and ADO 98
Recordset object 93, 95
Reflector
data source definitions 49
M database administrator uses 53
introducing 49
overview 29
Manual conventions 11 sample ADO data consumer call 62
typical tasks 41
retrieving a row of data 128
rowset
O methods of reading 77
minimum requirement 68
object releasing rows 77
ADO 89
Command 97
command 92
Connection 91, 95 S
Error 94
Field 94 schema 142
Parameter 93 SequeLink OLE DB Edition
Recordset 93, 95 basic concepts 24
objects and interfaces description 8
base-level interfaces 67 SequeLink OLE DB Provider
introducing OLE DB 66 and OLE DB technology 24
OLE DB using 44
advantages 26 service component, overview 28
and Connect OLE DB Data Providers 21
and SequeLink OLE DB Edition 24
comparing to ODBC 123

Getting Started with DataDirect for OLE DB


Index 149

SQL
making requests to nonrelational data
stores 27
making requests to relational data
stores 30
SupportNet 13

T
Technical Support, contacting 13
transactions, overview 84

W
Web data access and OLE DB data
providers 117
WWW, using to contact technical support 13

Getting Started with DataDirect for OLE DB

You might also like