Guide to Migrating Sybase Application Interfaces to SQL Server 2008

SQL Server Technical Article

Writers: Yuri Rusakov (DB Best Technologies), Alexander Pavlov (DB Best Technologies), Yuri Kovtun (DB Best Technologies)

Technical Reviewer: Dmitry Balin (DB Best Technologies)

Published:

Applies to: SQL Server 2008

Summary: This white paper describes methods of migrating applications with Sybase interfaces to SQL Server. We cover both Open Standard APIs (ODBC, JDBC, OLE DB, ADO.Net) and proprietary APIs (CT-Library, DB-Library).

Created by: DB Best Technologies LLC

P.O. Box 7461, Bellevue, WA 98008

Tel.: (408) 202-4567

E-mail: [email protected]

Web: www.dbbest.com

Copyright This is a preliminary document and may be changed substantially prior to final commercial release of the software described herein.

The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication.

This White Paper is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS DOCUMENT.

Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

Unless otherwise noted, the example companies, organizations, products, domain names, e- mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, email address, logo, person, place or event is intended or should be inferred.

© 2010 Microsoft Corporation. All rights reserved.

Microsoft and SQL Server are registered trademarks of Microsoft Corporation in the United States and other countries.

The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

2

Contents

Copyright ...... 2 Introduction ...... 4 Conversion of Open Standard Application Interfaces ...... 5 Overview ...... 5 JDBC ...... 5 ODBC ...... 5 OLE DB ...... 6 ADO.NET ...... 8 Driver versions ...... 9 Open Client Libraries to ODBC Migration ...... 11 Overview ...... 11 Main Migration Steps ...... 11 CT-Library Schema migration ...... 12 Header files mapping ...... 12 Routine mapping ...... 12 Type and structure mapping...... 17 DB-Library Schema migration ...... 20 Overview ...... 20 Header files mapping ...... 20 Routine mapping ...... 20 Type and structure mapping...... 25 Other Types of Migration ...... 27 Using FreeTDS tool to migrate CT Library and DB Library applications to SQL Server ...... 27 Migration of Open Client Embedded SQL ...... 27 Migration of ASE Job Scheduler objects ...... 28 Conversion of Transact-SQL statements which are embedded in applications ...... 28 Conclusion ...... 30 About DB Best Technologies ...... 30

3

Introduction

DB Best Technologies, Inc. created several white papers which cover migration of databases, such as Oracle or Sybase ASE, to SQL Server 2008. However, in most of the cases there is also a necessity to change database access code in an application connecting to the migrated database.

The task is easiest when the application uses a database interface designed to serve many database servers. In this white paper we discuss Open Database Connectivity (ODBC), Java Database Connectivity (JDBC), Object Linking and Embedding Database (OLE DB) and ActiveX Data Objects for .NET (ADO.NET). Migration of such interfaces can be as simple as changing the database driver and/or connection strings.

More complicated are the cases when we use proprietary interfaces of one database vendor, which do not provide connectivity to SQL Server 2008. Examples are Sybase ASE CT-Library and DB-Library. In this paper we describe how to change the application code to use SQL Server compatible ODBC interface.

4

Conversion of Open Standard Application Interfaces

Overview

In this section we discuss methods of redirecting multi-database interfaces of Sybase Adaptive Server Enterprise (ASE) applications to SQL Server 2008.

Note that the application code may contain pieces of SQL strings, which are sent to the database and which may not be compatible with SQL Server after the interface was redirected. In such cases, we should convert the embedded SQL according to the rules of SQL conversion.

JDBC

To convert a JDBC application, we need to change name of loaded JDBC driver class and modify its URL accordingly.

Examples:

JDBC connection to Sybase ASE:

Class.forName(“com.sybase.jdbc.SybDrive”); String url = "jdbc:sybase:Tds:sybase_server_name:5000/test_base”; Connection dbc = DriverManager.getConnection(url, login, password);

See below the changes necessary to make this code connect to SQL Server. The class name of SQL Server driver should be specified as a parameter of Class.forName() method, and getConnection method of the loaded class should follow the URL syntax for SQL Server.

Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDriver”); String url = “jdbc:sqlserver://sql_server_name:1433”; Connection dbc = DriverManager.getConnection(url, login, password);

ODBC

ODBC is a universal interface, which means we can change the servers just by specifying another Data Source Name. See below a typical example of switching the database in ODBC connect code.

5

ODBC connection to Sybase:

SQLRETURN retcode; SQLHENV env; SQLHDBC dbc; retcode = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env ); retcode = SQLSetEnvAttr( env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); retcode = SQLAllocHandle( SQL_HANDLE_DBC, env, &dbc ); retcode = SQLConnect(dbc, (SQLCHAR*) "sybase_DataSource_name", SQL_NTS, (SQLCHAR*) "sybase_login", SQL_NTS, (SQLCHAR*) "sybase_password", SQL_NTS);

ODBC connection to SQL Server:

SQLRETURN retcode; SQLHENV env; SQLHDBC dbc; retcode = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env ); retcode = SQLSetEnvAttr( env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); retcode = SQLAllocHandle( SQL_HANDLE_DBC, env, &dbc ); retcode = SQLConnect(dbc, (SQLCHAR*) "mssql_DataSource_name", SQL_NTS, (SQLCHAR*) "mssql_login", SQL_NTS, (SQLCHAR*) "mssql_password", SQL_NTS);

OLE DB

To establish a connection with a data source we need to create an instance of OLE DB provider, which exposes interfaces of the data source, and then to perform initialization of this instance. To do that, we should use function CoCreateInstance with OLE DB provider class ID as the first parameter. Next, we initialize the data source using array of structures DBPROP. In the simplest case, we need to specify four properties: prompt level, DSN name, user name and password.

The difference between OLE DB connections for different databases is in OLE DB provider object and object initialization parameters.

Connecting to Sybase ASE with OLE DB:

#include "msdasql.h"

6

… IDBInitialize* pIDBInitialize = NULL; HRESULT hr; hr = CoCreateInstance(CLSID_MSDASQL, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void**)&pIDBInitialize); … InitProperties[0].dwPropertyID = DBPROP_INIT_PROMPT; InitProperties[0].vValue.vt = VT_I2; InitProperties[0].vValue.iVal = DBPROMPT_NOPROMPT; InitProperties[1].dwPropertyID = DBPROP_INIT_DATASOURCE; InitProperties[1].vValue.vt = VT_BSTR; InitProperties[1].vValue.bstrVal = SysAllocString(OLESTR("sybase_DataSource_name")); InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID; InitProperties[2].vValue.vt = VT_BSTR; InitProperties[2].vValue.bstrVal = SysAllocString(OLESTR("sybase _login")); InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD; InitProperties[3].vValue.vt = VT_BSTR; InitProperties[3].vValue.bstrVal = SysAllocString(OLESTR("sybase _password"));

Connecting to SQL Server using OLE DB:

#include "msdasql.h" … IDBInitialize* pIDBInitialize = NULL; HRESULT hr; hr = CoCreateInstance(CLSID_MSDASQL, NULL, CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void**)&pIDBInitialize); … InitProperties[0].dwPropertyID = DBPROP_INIT_PROMPT; InitProperties[0].vValue.vt = VT_I2; InitProperties[0].vValue.iVal = DBPROMPT_NOPROMPT; InitProperties[1].dwPropertyID = DBPROP_INIT_DATASOURCE; InitProperties[1].vValue.vt = VT_BSTR; InitProperties[1].vValue.bstrVal = SysAllocString(OLESTR("mssql_DataSource_name")); InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID; InitProperties[2].vValue.vt = VT_BSTR; InitProperties[2].vValue.bstrVal = SysAllocString(OLESTR("mssql_login")); InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD; InitProperties[3].vValue.vt = VT_BSTR;

7

InitProperties[3].vValue.bstrVal = SysAllocString(OLESTR("mssql_password"));

When using ATL library, we should choose class CDataSource for connection to a database. Databases differ by parameters of Open() method.

CDataSource dsDSN; HRESULT hr;

// Connecting to Sybase ASE with ATL OLE DB:

hr = dsDSN.Open(_T("MSDASQL"), “sybase_DataSource_name”, "sybase_login", "sybase_password");

// Connecting to SQL Server with ATL OLE DB:

hr = dsDSN.Open(_T("MSDASQL"), “mssql_DataSource_name”, "mssql_login", "mssql_password");

ADO.NET

ADO.NET architecture uses data providers to access a database. There are various implementations of the .NET interfaces for different DBMSes. For example, connections to SQL Server are handled by special class SqlConnection. Each provider includes its own set of .NET framework classes in a separate namespace. When performing migration, we should replace calls to objects of one namespace to the calls of SQL Server provider. The only exception is ODBC and OLE DB providers, which by definition are compatible with multiple databases.

When the original provider uses System.Data.Odbc, the Sybase to SQL Server migration may be as simple as replacement of the connection string.

An example of Sybase connection:

OdbcConnection connection = new OdbcConnection( "Driver={SYBASE ASE ODBC Driver};Srvr=myServerAddress;Uid=myUsername;Pwd=myPassword;"); connection.Open();

Equivalent SQL Server connection:

OdbcConnection connection = new OdbcConnection(

8

"Driver={SQL Server};Server=(local);Trusted_Connection=Yes;Database=AdventureWorks; "); connection.Open();

Similarly, we replace the connection string in case of ADO.NET OLE DB provider.

Sybase OLE DB connection:

OleDbConnection connection = new OleDbConnection( "Provider=Sybase.ASEOLEDBProvider;Srvr=myASEserver,5000;Catalog=myData Base;User Id=myUsername;Password=myPassword;"); connection.Open();

SQL Server connection:

OleDbConnection connection = new OleDbConnection( "Provider=SQLOLEDB;Server=myServerAddress;Database=myDataBase;Uid=myUs ername; Pwd=myPassword;"); connection.Open();

When the source code uses Oracle specific provider defined in System.Data.AseClient, we will need to replace the class names with their counterparts in System.Data.SqlClient.

Sybase connection:

AseConnection connection = new AseConnection (connectionString); connection.Open();

SQL Server connection:

SqlConnection connection = new SqlConnection(connectionString); connection.Open();

Driver versions

We suggest to use this driver in case of JDBC conversion: http://www.microsoft.com/downloads/details.aspx?familyid=99B21B65-E98F-4A61-B811- 19912601FDC9&displaylang=en

You can take Microsoft SQL Server OLE DB Provider and ODBC driver from Microsoft Data Access Components (MDAC) :

9 http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=6c050fe3-c795- 4b7d-b037-185d0506396c

ADO.NET Data Provider for SQL Server is shipped as a part of MDAC or as a part of .NET Framework.

.

10

Open Client Libraries to ODBC Migration

Overview

Following are the basic, high-level steps for migrating a Sybase Open Client Libraries interfaces to SQL Server ODBC interface and what you must know about converting interface routines.

Main Migration Steps

From the point of view of the client program both Sybase Open Client and ODBC represent a set of the modules connected to program, containing the description of necessary types and functions for use of opportunities of the corresponding interface. Base functionality of libraries is identical and realizes necessary commands for performance of operations of initialization of the driver, connection to a database server, execute SQL statement, fetching of results and closings of connection. Converting a Sybase Open Client Libraries program to its SQL Server ODBC equivalent generally involves the following steps: 1. Replace Open Client Libraries header file names with the ODBC header file names. 2. Plan the code conversion. Client application code can be split roughly into the following categories:  Initialization and cleanup code;  Code that opens a connection;  Error and message handlers;  Code that sends commands;  Code that processes results;  Finalization code; 3. Perform the conversion: Replace or remove Open Client Libraries declarations, as appropriate. Replace Open Client Libraries function calls with their ODBC equivalents, changing program logic as necessary.

11

CT-Library Schema migration This section explains mappings and differences between CT-Library and ODBC modules, commands and types.

Header files mapping The following table displays the list of required header C files for the use CT-Library and ODBC API.

CT-Library ODBC #include #include #include

Routine mapping The following table displays the commands, used in typical execution steps of CT-Library and ODBC applications, and their correspondence.

CT-Library ODBC STEP 1: Set Up The Client-Library STEP 1: Connect To The Data Source Programming Environment cs_ctx_alloc Allocate a context structure. cs_config Set any CS-Library properties for the context. ct_init SQLAllocHandle(ENV) Initialize Client-Library. Load the Driver Manager and allocate the environment handle. Driver Manager allocates a structure in which to store information about the environment, and returns the environment handle. ct_config SQLSetEnvAttr Set Client-Library properties for the Sets attributes that govern aspects of context. environments.

STEP 2: Define Error Handling

12 cs_config(CS_MESSAGE_CB) Replace with SQLGetDiagField and Install a CS-Library error callback. SQLGetDiagRec function calls in the return code handlers.

SQLGetDiagField Returns the current value of a field of a record of the diagnostic data structure (associated with a specified handle) that contains error, warning, and status information. SQLGetDiagRec Returns the current values of multiple fields of a diagnostic record that contains error, warning, and status information. Unlike SQLGetDiagField, which returns one diagnostic field per call, SQLGetDiagRec returns several commonly used fields of a diagnostic record, including the SQLSTATE, the native error code, and the diagnostic message text. ct_callback Install a client or server message callback. Ct_callback installs Client-Library callback routines, which are application routines that Client-Library calls automatically when a triggering event of the appropriate type occurs.

STEP 3: Connect To A Server ct_con_alloc SQLAllocHandle(DBC) Allocate a connection structure. Allocate a connection handle. Driver Manager allocates a structure in which to store information about the connection and returns the connection handle. ct_con_props SQLSetConnectAttr Set any properties in the connection Sets attributes that govern aspects of structure. connections. Some connection attributes must be set before the application attempts to connect, others can be set after the connection has completed.

13 ct_connect SQLConnect or SQLDriverConnect or Open a connection to a server. SQLBrowseConnect SQLConnect establishes connections to a driver and a data source. ct_options Set any server options for this connection.

STEP 4: Send A Language Command STEP 2: Initialize The Application To The Server ct_cmd_alloc SQLAllocHandle(STMT) Allocate a command structure. Driver Manager allocates a structure in which to store information about the statement and calls SQLAllocHandle in the driver with the SQL_HANDLE_STMT option. The driver allocates its own structure in which to store information about the statement and returns the driver statement handle to the Driver Manager. The Driver Manager returns the Driver Manager statement handle. ct_cmd_props SQLSetStmtAttr Set, retrieve, or clear command structure Sets attributes related to a statement. properties.

STEP 3: Build And Execute An SQL Statement ct_command SQLPrepare Define a command. Prepares an SQL string for execution. ct_param or ct_setparam SQLBindParameter Define a command parameter. Binds a buffer to a parameter marker in an SQL statement. ct_send SQLExecute Sends the command text to the server, Executes a prepared statement, using the which parses, compiles, and executes it. current values of the parameter marker variables.

STEP 5: Process The Results Of The STEP 4: Fetch The Results; Fetch The

14

Command Row Count ct_results Set up result data to be processed. Defines type of command result: • Values that indicate command status; • Values that indicate fetchable results; • Values that indicate information is available. ct_res_info SQLNumResultCols Retrieve current result set or command Returns the number of columns in a result information. set. The possible returned information: If this is 0, the statement did not create a • The number of the command that result set, if it is any other number, the generated the current result set; statement did create a result set. • The number of compute clauses in the SQLRowCount current command; Returns the number of rows affected by an • The number of items in the current UPDATE, INSERT, or DELETE statement. result set; If a batch of SQL statements is executed, • The number of columns specified in the the count of affected rows might be a total order-by clause of the current command; count for all statements in the batch or individual counts for each statement in the • The number of rows affected by the batch. current command; and others. ct_describe SQLDescribeCol Return a description of result data. Returns the result descriptor — column An application can use ct_describe to name, type, column size, decimal digits, retrieve a description of a regular result and nullability — for one column in the column, a return parameter, a stored result set. procedure return status number, or a compute column. An application can call ct_res_info to find out how many result items are present in the current result set. An application generally needs to call ct_describe to describe a result data item before it binds the result item to a program variable using ct_bind. ct_bind SQLBindCol Bind server results to program variables Binds application data buffers to columns

15

When the application calls ct_fetch to in the result set. fetch the result data, it is copied into this variables. ct_fetch SQLFetch Fetch result data. Fetches the next rowset of data from the result set and returns data for all bound columns. SQLGetData Retrieves data for a single column in the result set. It can be called multiple times to retrieve variable-length data in parts. The application now calls SQLFetch to retrieve the first row of data and place the data from that row in the variables bound with SQLBindCol. If there is any long data in the row, it then calls SQLGetData to retrieve that data. The application continues to call SQLFetch and SQLGetData to retrieve additional data. After it has finished fetching data, it calls SQLCloseCursor to close the cursor.

SQLCloseCursor Closes a cursor that has been opened on a statement and discards pending results.

STEP 5: Commit The Transaction The application performs this step only if it set the transaction commit mode to manual-commit; if the transaction commit mode is auto-commit, which is the default, the transaction is automatically committed when the statement is executed SQLEndTran Requests a commit or rollback operation for all active operations on all statements associated with a connection.

STEP 6: Finish STEP 6: Disconnect From The Data Source ct_cmd_drop SQLFreeHandle(STMT) Deallocate a command structure. Free the statement. Driver releases the

16

structure used to store information about the statement. ct_close SQLDisconnect Close a connection. Frees any statements that are allocated on ct_con_drop the connection and disconnects the driver from the data source. Deallocate connection structure.

ct_exit SQLFreeHandle(DBC) Exit Client-Library for a specific context. Free the connection. Driver releases the Closes and deallocates any open structure used to store information about connections and cleans up internal Client- the connection. Library data space. cs_ctx_drop SQLFreeHandle(ENV) Deallocates a context structure. Frees the environment handle. Driver releases the structure used to store information about the environment.

Type and structure mapping The following table displays the correspondence of types and structures of CT-Library to types and structures of ODBC:

CT-Library ODBC Structures CS_CONTEXT HENV Context structure. Environment handle.

CS_CONNECTION HDBC Connection structure. Connection handle.

CS_COMMAND HSTMT Command structure. Statement handle.

Types Numeric types CS_TINYINT SQLSCHAR (SQL_C_STINYINT) tinyint

17

CS_SMALLINT SQLSMALLINT (SQL_C_SSHORT) smallint CS_USMALLINT SQLUSMALLINT (SQL_C_USHORT) usmallint CS_INT SQLINTEGER (SQL_C_SLONG) int CS_UINT SQLUINTEGER (SQL_C_ULONG) uint CS_BIGINT SQLBIGINT (SQL_C_SBIGINT) bigint CS_UBIGINT SQLUBIGINT (SQL_C_UBIGINT) ubigint CS_DECIMAL SQL_NUMERIC_STRUCT (SQL_C_NUMERIC) decimal structure CS_NUMERIC SQL_NUMERIC_STRUCT (SQL_C_NUMERIC) numeric structure CS_FLOAT SQLDOUBLE, SQLFLOAT (SQL_C_DOUBLE) float CS_REAL SQLREAL (SQL_C_FLOAT) real Money types CS_MONEY SQL_NUMERIC_STRUCT (SQL_C_NUMERIC) money structure CS_MONEY4 SQL_NUMERIC_STRUCT (SQL_C_NUMERIC) smallmoney structure Character types CS_CHAR SQLCHAR (SQL_C_CHAR) char varchar CS_UNICHAR SQLWCHAR (SQL_C_WCHAR) unichar univarchar Datetime types CS_DATE SQL_DATE_STRUCT (SQL_C_TYPE_DATE) date structure CS_TIME SQL_TIME_STRUCT (SQL_C_TYPE_TIME) time structure CS_DATETIME SQL_TIMESTAMP_STRUCT datetime (SQL_C_TYPE_TIMESTAMP) structure CS_DATETIME4 SQL_TIMESTAMP_STRUCT

18 smalldatetime (SQL_C_TYPE_TIMESTAMP) structure Bit types CS_BIT SQLCHAR (SQL_C_BIT) bit Binary types CS_BINARY SQLCHAR (SQL_C_BINARY) binary varbinary Text and image types CS_TEXT SQLCHAR (SQL_C_CHAR) text CS_UNITEXT SQLWCHAR (SQL_C_WCHAR) unitext CS_IMAGE SQLCHAR (SQL_C_BINARY) image

19

DB-Library Schema migration

Overview This section explains mappings and differences between DB-Library and ODBC modules, commands and types.

Header files mapping The following table displays the list of required header C files for the use DB-Library and ODBC API.

DB-Library ODBC #include #include #include #include #include

Routine mapping The following table displays the commands, used in typical execution steps of DB-Library and ODBC applications, and their correspondence.

DB-Library ODBC STEP 1: Initialization STEP 1: Connect To The Data Source dbinit() SQLAllocHandle(ENV) Initialize DB-Library. Load the Driver Manager and allocate the environment handle. Driver Manager allocates a structure in which to store information about the environment, and returns the environment handle. dbsetversion(dbproc, version) SQLSetEnvAttr Specify the version level for desired Sets attributes that govern aspects of behavior. environments.

STEP 2: Define Error Handling dberrhandle(handler) Replace with SQLGetDiagField and SQLGetDiagRec function calls in the return Install DB-Library error callback function. code handlers. dbmsghandle(handler) SQLGetDiagField Install DB-Library server message callback Returns the current value of a field of a function.

20

record of the diagnostic data structure (associated with a specified handle) that contains error, warning, and status information. SQLGetDiagRec Returns the current values of multiple fields of a diagnostic record that contains error, warning, and status information. Unlike SQLGetDiagField, which returns one diagnostic field per call, SQLGetDiagRec returns several commonly used fields of a diagnostic record, including the SQLSTATE, the native error code, and the diagnostic message text.

STEP 3: Connect To A Server dblogin() SQLAllocHandle(DBC) Allocate a LOGINREC for use in dbopen. Allocate a connection handle. Driver Manager allocates a structure in which to store information about the connection and returns the connection handle.

DBSETLUSER(loginrec, username) SQLSetConnectAttr Set the username in the LOGINREC Sets attributes that govern aspects of structure. connections. DBSETLPWD(loginrec, password) Some connection attributes must be set before the application attempts to connect, Set the user server password in the others can be set after the connection has LOGINREC structure. completed. DBSETLAPP(loginrec, application) Set the application name in the LOGINREC structure. dbopen(loginrec, server) SQLConnect or SQLDriverConnect or SQLBrowseConnect Connect to a server (and allocate the SQLConnect establishes connections to a DBPROCESS). driver and a data source.

STEP 4: Send A Language Command STEP 2: Initialize The Application To The Server SQLAllocHandle(STMT) Driver Manager allocates a structure in which to store information about the statement and calls SQLAllocHandle in the driver with the SQL_HANDLE_STMT option. The driver allocates its own structure in

21

which to store information about the statement and returns the driver statement handle to the Driver Manager. The Driver Manager returns the Driver Manager statement handle.

SQLSetStmtAttr Sets attributes related to a statement.

STEP 3: Build And Execute An SQL Statement dbfcmd(dbproc, string, args...) SQLPrepare Format text and add to the DBPROCESS Prepares an SQL string for execution. command buffer. dbcmd(dbproc, string) Add text to the DBPROCESS command buffer. dbrpcinit(dbproc, rpc_name, option) Initialize an RPC. dbrpcparam(dbproc, paramname, SQLBindParameter status, type, maxlen, datalen, data) Binds a buffer to a parameter marker in an Add a parameter to an RPC. SQL statement. dbsqlexec(dbproc) SQLExecute Send a command batch to the server for Executes a prepared statement, using the execution. current values of the parameter marker dbrpcsend(dbproc) variables.

Send an RPC call to the server for execution.

STEP 5: Process The Results Of The STEP 4: Fetch The Results; Fetch The Command Row Count dbresults Sets up the results of the next query. dbnumalts SQLNumResultCols Returns the number of columns in a Returns the number of columns in a result compute row. set. dbnumcols If this is 0, the statement did not create a result set, if it is any other number, the Determines the number of regular columns statement did create a result set. for the current set of results. SQLRowCount dbnumrets Returns the number of rows affected by an Determines the number of return parameter

22 values generated by a stored procedure. UPDATE, INSERT, or DELETE statement. DBCOUNT If a batch of SQL statements is executed, the count of affected rows might be a total Returns the number of rows affected by a count for all statements in the batch or Transact-SQL command. individual counts for each statement in the DBCURCMD batch. Returns the number of the current logical command. dbaltlen SQLDescribeCol Returns the maximum length of the data for Returns the result descriptor — column a particular compute column. name, type, column size, decimal digits, and dbalttype nullability — for one column in the result set.

Returns the datatype for a compute column. dbaltutype Returns the user-defined datatype for a compute column. dbcollen Returns the maximum length of the data in a regular result column. dbcolname Returns the name of a regular result column. dbcoltype Returns the datatype for a regular result column. dbcolutype Returns the user-defined datatype for a regular result column. dbretname Determines the name of the stored procedure parameter associated with a particular return parameter value. dbrettype Determines the datatype of a return parameter value generated by a stored procedure. dbaltbind, dbaltbind_ps SQLBindCol Binds a compute column to a program Binds application data buffers to columns in variable. the result set. dbbind, dbbind_ps Binds a regular result column to a program variable.

23 dbnextrow SQLFetch Reads the next result row. Fetches the next rowset of data from the result set and returns data for all bound columns. SQLGetData Retrieves data for a single column in the result set. It can be called multiple times to retrieve variable-length data in parts. The application now calls SQLFetch to retrieve the first row of data and place the data from that row in the variables bound with SQLBindCol. If there is any long data in the row, it then calls SQLGetData to retrieve that data. The application continues to call SQLFetch and SQLGetData to retrieve additional data. After it has finished fetching data, it calls SQLCloseCursor to close the cursor.

SQLCloseCursor Closes a cursor that has been opened on a statement and discards pending results.

STEP 5: Commit The Transaction The application performs this step only if it set the transaction commit mode to manual- commit; if the transaction commit mode is auto-commit, which is the default, the transaction is automatically committed when the statement is executed SQLEndTran Requests a commit or rollback operation for all active operations on all statements associated with a connection.

STEP 6: Cleanup STEP 6: Disconnect From The Data Source SQLFreeHandle(STMT) Free the statement. Driver releases the structure used to store information about the statement. dbclose(dbproc) SQLDisconnect Close and deallocate a DBPROCESS Frees any statements that are allocated on structure. the connection and disconnects the driver from the data source.

24

dbexit() SQLFreeHandle(DBC) Close and deallocate all DBPROCESS Free the connection. Driver releases the structures and clean up any structures structure used to store information about the initialized by dbinit. connection.

SQLFreeHandle(ENV) Frees the environment handle. Driver releases the structure used to store information about the environment.

Type and structure mapping The following table displays the correspondence of types and structures of DB-Library to types and structures of ODBC:

DB-Library ODBC Structures LOGINREC HDBC Contains typical login Connection handle information

DBPROCESS HSTMT Through the DBPROCESS, Statement handle commands are sent to the server and query results are returned to the application

Types Numeric types SYBINT1 SQLSCHAR (SQL_C_STINYINT) 1-byte integer SYBINT2 SQLSMALLINT (SQL_C_SSHORT) 2-byte integer SYBINT4 SQLINTEGER (SQL_C_SLONG) 4-byte integer SYBDECIMAL SQL_NUMERIC_STRUCT (SQL_C_NUMERIC) decimal type structure SYBNUMERIC SQL_NUMERIC_STRUCT (SQL_C_NUMERIC) numeric type structure SYBFLT8 SQLDOUBLE, SQLFLOAT (SQL_C_DOUBLE)

25

8-byte float type SYBREAL SQLREAL (SQL_C_FLOAT) 4-byte float type Money types SYBMONEY SQL_NUMERIC_STRUCT (SQL_C_NUMERIC) money type structure SYBMONEY4 SQL_NUMERIC_STRUCT (SQL_C_NUMERIC) 4-byte money type structure Character types SYBCHAR SQLCHAR (SQL_C_CHAR) char type Datetime types SYBDATETIME SQL_TIMESTAMP_STRUCT datetime type (SQL_C_TYPE_TIMESTAMP) structure SYBDATETIME4 SQL_TIMESTAMP_STRUCT 4-byte datetime type (SQL_C_TYPE_TIMESTAMP) structure Bit types SYBBIT SQLCHAR (SQL_C_BIT) bit type Binary types SYBBINARY SQLCHAR (SQL_C_BINARY) binary type Text and image types SYBTEXT SQLCHAR (SQL_C_CHAR) text type SYBIMAGE SQLCHAR (SQL_C_BINARY) image type

26

Other Types of Migration

This section covers migration of several Sybase features related to application programming and products using connection to Sybase.

Using FreeTDS tool to migrate CT Library and DB Library applications to SQL Server

FreeTDS libraries can be used for redirecting Sybase client applications to SQL Server. FreeTDS provides implementations of DB-Library, CT-Library and ODBC driver, allowing many Sybase client applications that use these interfaces to communicate with Microsoft SQL Server. You can download the source code for FreeTDS from the Web site (http://www.freetds.org) and then build, install, and configure it for your target platform.

Take into account that FreeTDS is an open source project and is still very much a work in progress. Although much of the core functionality is available, you may find it necessary to either implement any missing functionality in the FreeTDS libraries that your application requires, or modify your application to avoid these features.

Migration of Open Client Embedded SQL

Sybase Embedded SQL is a superset of Transact-SQL that lets place Transact-SQL statements in application programs written in C.

Open Client Embedded SQL enables to create programs that access and update Adaptive Server data. Embedded SQL programmers write SQL statements directly into an application program written in C. A preprocessing program — the Embedded SQL precompiler — processes the completed application program, resulting in a program that the host language can compile. The program is linked with Open Client Client-Library before it is executed.

Embedded SQL is one of the two programming methods Sybase provides for accessing Adaptive Server. The other programming method is the call-level interface. With the call-level interface, you place Client-Library calls directly into an application program, then link with Client- Library.

Embedded SQL statements can be placed anywhere in a host program and mixed with host language statements. All Embedded SQL statements must begin with the keywords EXEC SQL and end with a semicolon (;). After you write an Embedded SQL program, run it through the precompiler, which translates the Embedded SQL statements into Client-Library function calls.

27

To migrate Sybase C application with Embedded SQL on SQL Server, we suggest replace Open Client Embedded SQL statements with ODBC routine calls.

Migration of ASE Job Scheduler objects

The SQL Server counterpart of Sybase ASE Job Scheduler is the SQL Server Agent jobs. Like Sybase Job Scheduler the SQL Server Agent allows you to create and schedule jobs, and to share jobs and schedules. At the same time SQL Server Agent provides more functionality to job and schedule management.

You can use SQL Server Agent jobs to automate routine administrative tasks and run them on a recurring basis, making administration more efficient.

A job is a specified series of operations performed sequentially by SQL Server Agent. A job can perform a wide range of activities, including running Transact-SQL scripts, command-line applications, Microsoft ActiveX scripts, Integration Services packages, Analysis Services commands and queries, or Replication tasks. Jobs can run repetitive tasks or those that can be scheduled, and they can automatically notify users of job status by generating alerts, thereby greatly simplifying SQL Server administration. You can run a job manually, or you can configure it to run according to a schedule or in response to alerts.

Conversion of Transact-SQL statements which are embedded in applications

You can use the Statements branch in SSMA for Sybase to convert SQL strings embedded in the user's application code by executing the following steps:

1. In Sybase tree, select the required database and schema and execute Add Statement command from the Statements branch context menu to create new Statement window. 2. Cut the statement from the application (or reconstruct it if the statement is built according to an algorithm). 3. Paste it into the Statement window. 4. Execute Convert Schema. 5. Paste the result back into the proper place in the application code.

28

Temporary tables in code can create problems when their definitions are absent in the module you are converting. Generally, you should convert the module where a temporary table is created before converting the modules from which the temporary table is referenced. That way, SSMA is able to remember the table definition and to use it properly.

29

Conclusion

This migration guide can give you some hints about migration of Sybase-based applications to SQL Server. We discussed typical solutions for most commonly used Sybase application interfaces.

About DB Best Technologies DB Best Technologies is a leading provider of database and application migration services and custom software development. We have been focused on heterogeneous database environments (SQL Server, Oracle, Sybase, DB2, MySQL) since starting at 2002 in Silicon Valley. Today, with over 75 employees in the United States and Europe, we develop database tools and provide services to customers worldwide.

DB Best developed migration tools to automate conversion between SQL dialects. In 2005 Microsoft acquired this technology, which later became a family of SQL Server Migration Assistant (SSMA) products. We continue to develop new versions of SSMA, and support Microsoft customers who are migrating to SQL Server.

We also provide migration services covering all major steps of a typical migration project: complexity assessment, schema conversion, data migration, application conversion, testing, integration, deployment, performance tuning, training, and support.

For more details, visit us at www.dbbest.com, e-mail us at [email protected], or call 1-408-202- 4567.

For more information: http://www.microsoft.com/sqlserver/: SQL Server Web site http://technet.microsoft.com/en-us/sqlserver/: SQL Server TechCenter http://msdn.microsoft.com/en-us/sqlserver/: SQL Server DevCenter

Did this paper help you? Please give us your feedback. Tell us on a scale of 1 (poor) to 5 (excellent), how would you rate this paper and why have you given it this rating? For example:

 Are you rating it high due to having good examples, excellent screen shots, clear writing, or another reason?  Are you rating it low due to poor examples, fuzzy screen shots, or unclear writing?

This feedback will help us improve the quality of white papers we release.

Send feedback.

30