0% found this document useful (0 votes)
5K views

ADO

Uploaded by

Xander Rodriguez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5K views

ADO

Uploaded by

Xander Rodriguez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7264

Contents

Programming to interact with SQL Server


Welcome to SQL Server >
SQL Server drivers
Driver feature support matrix
SQL Server driver history
SQL data developer
ADO.NET
Microsoft ADO.NET for SQL Server
Getting started
Step 1: Configure development environment
Step 2: Create a SQL database
Step 3: Proof of concept connecting to SQL
Step 4: Connect resiliently to SQL
Overview
Microsoft.Data.SqlClient namespace
Download
Support lifecycle
Enable event tracing
AppContext switches
Troubleshooting guide
Finding additional information
Data Type Mappings In ADO.NET
SQL Server Data Type Mappings
Floating-Point Numbers
Retrieving and Modifying Data In ADO.NET
Connecting To Data Source
Establishing Connection
Connection Events
Connection Strings
Connection String Builders
Connection Strings And Configuration Files
Connection String Syntax
Protecting Connection Information
Connection Pooling
SQL Server Connection Pooling (ADO.NET)
Commands and Parameters
Executing a Command
Configuring Parameters
Generating Commands with CommandBuilders
Obtaining a Single Value from a Database
Using Commands to Modify Data
Updating Data in a Data Source
Performing Catalog Operations
DataAdapters and DataReaders
Retrieve data by a DataReader
Populate a DataSet from a DataAdapter
DataAdapter parameters
Add existing constraints to a DataSet
DataAdapter, DataTable, and DataColumn mappings
Paging through a query result
Update data sources with DataAdapters
Handle DataAdapter events
Batch operations using DataAdapters
Transactions and concurrency
Local transactions
Distributed transactions
System.Transactions integration with SQL Server
Optimistic concurrency
Retrieving database schema information
GetSchema and schema collections
Schema restrictions
Common schema collections
SQL Server schema collections
Configurable retry logic
Introduction
Internal providers
Core APIs
Configuration file
DbProviderFactories
Obtain a SqlClientFactory
Diagnostic counters
Event counters
Performance counters
Retrieve identity or autonumber values
Retrieve binary data
Modify data with stored procedures
Data tracing in SqlClient
Asynchronous programming
SqlClient streaming support
SQL Server and ADO.NET
SQL Server security
Authentication
Azure Active Directory authentication
Application security scenarios
Writing secure dynamic SQL
SQL Server Express security
SQL Server data types and ADO.NET
SqlTypes and the DataSet
Handling null values
Comparing GUID and uniqueidentifier values
Date and time data
Large UDTs
XML data in SQL Server
SQL XML column values
Specifying XML values as parameters
SQL Server binary and large-value data
Modifying large-value (max) data in ADO.NET
FILESTREAM data
Inserting an image from a file
SQL Server data operations in ADO.NET
Bulk copy operations in SQL Server
Bulk copy example setup
Single bulk copy operations
Multiple bulk copy operations
Transaction and bulk copy operations
Order hints for bulk copy operations
Multiple Active Result Sets (MARS)
Enabling Multiple Active Result Sets
Manipulating data
Asynchronous operations
Windows applications using callbacks
ASP.NET applications using wait handles
Polling in console applications
Table-valued parameters
SQL Server features and ADO.NET
Enumerating instances of SQL Server (ADO.NET)
Provider statistics for SQL Server
SQL Server Express user instances
Database mirroring in SQL Server
The context connection
Query notifications in SQL Server
Enabling query notifications
SqlDependency in an ASP.NET application
Detecting changes with SqlDependency
SqlCommand execution with a SqlNotificationRequest
Snapshot isolation in SQL Server
SqlClient support for high availability, disaster recovery
SqlClient support for LocalDB
SqlClient support for Always Encrypted
Develop a .NET application using Always Encrypted with secure enclaves
Using Azure Key Vault with Always Encrypted
Using Azure Key Vault with Always Encrypted with secure enclaves
Data Discovery and Classification in SqlClient
JDBC
Microsoft JDBC Driver for SQL Server
Getting started
Step 1: Configure development environment
Step 2: Create a SQL database
Step 3: Proof of concept connecting to SQL
Overview
Download
Release notes
System requirements
Support matrix
Using the driver
Parsing results
Using useFMTOnly
Understanding Java EE support
Deploying the driver
Finding additional information
Frequently asked questions (FAQ)
Feature dependencies
API reference
ISQLServerCallableStatement Interface
ISQLServerConnection Interface
ISQLServerDataSource Interface
ISQLServerPreparedStatement Interface
ISQLServerResultSet Interface
ISQLServerStatement Interface
DateTimeOffset Class
DateTimeOffset Members
DateTimeOffset Methods
compareTo Method (DateTimeOffset)
equals Method (DateTimeOffset)
getMinutesOffset Method (DateTimeOffset)
getTimestamp Method (DateTimeOffset)
hashCode Method (DateTimeOffset)
toString Method (DateTimeOffset)
valueOf Method (DateTimeOffset)
valueOf Method (java.sql.Timestamp, int)
valueOf Method (java.sql.Timestamp, java.util.Calendar)
SQLServerBlob Class
SQLServerBlob Members
SQLServerBlob Constructors
SQLServerBlob Constructor (SQLServerConnection, byte)
SQLServerBlob Methods
free Method (SQLServerBlob)
getBinaryStream Method (SQLServerBlob)
getBinaryStream Method ()
getBytes Method (SQLServerBlob)
length Method (SQLServerBlob)
position Method (SQLServerBlob)
position Method (java.sql.Blob, long)
position Method (byte, long)
setBinaryStream Method (SQLServerBlob)
setBytes Method (SQLServerBlob)
setBytes Method (long, byte)
setBytes Method (long, byte, int, int)
truncate Method (SQLServerBlob)
SQLServerCallableStatement Class
SQLServerCallableStatement Members
SQLServerCallableStatement Methods
getArray Method (SQLServerCallableStatement)
getArray Method (int)
getArray Method (java.lang.String)
getAsciiStream Method (SQLServerCallableStatement)
getAsciiStream (int)
getAsciiStream (java.lang.String)
getBigDecimal Method (SQLServerCallableStatement)
getBigDecimal Method (int)
getBigDecimal Method (int, int)
getBigDecimal Method (java.lang.String)
getBigDecimal Method (java.lang.String, int)
getBinaryStream Method (SQLServerCallableStatement)
getBinaryStream (int)
getBinaryStream (java.lang.String)
getBlob Method (SQLServerCallableStatement)
getBlob Method (int)
getBlob Method (java.lang.String)
getBoolean Method (SQLServerCallableStatement)
getBoolean Method (int)
getBoolean Method (java.lang.String)
getByte Method (SQLServerCallableStatement)
getByte Method (int)
getByte Method (java.lang.String)
getBytes Method (SQLServerCallableStatement)
getBytes Method (int)
getBytes Method (java.lang.String)
getCharacterStream Method (SQLServerCallableStatement)
getCharacterStream (int)
getCharacterStream (java.lang.String)
getClob Method (SQLServerCallableStatement)
getClob Method (int)
getClob Method (java.lang.String)
getDate Method (SQLServerCallableStatement)
getDate Method (int)
getDate Method (int, java.util.Calendar)
getDate Method (java.lang.String)
getDate Method (java.lang.String, java.util.Calendar)
getDateTimeOffset Method (SQLServerCallableStatement)
getDateTimeOffset Method (int)
getDateTimeOffset Method (String)
getDouble Method (SQLServerCallableStatement)
getDouble Method (int)
getDouble Method (java.lang.String)
getFloat Method (SQLServerCallableStatement)
getFloat Method (int)
getFloat Method (java.lang.String)
getInt Method (SQLServerCallableStatement)
getInt Method (int)
getInt Method (java.lang.String)
getLong Method (SQLServerCallableStatement)
getLong Method (int)
getLong Method (java.lang.String)
getNCharacterStream Method (SQLServerCallableStatement)
getNCharacterStream Method (int)
getNCharacterStream Method (java.lang.String)
getNClob Method (SQLServerCallableStatement)
getNClob Method (int)
getNClob Method (java.lang.String)
getNString Method (SQLServerCallableStatement)
getNString Method (int)
getNString Method (java.lang.String)
getObject Method (SQLServerCallableStatement)
getObject Method (int)
getObject Method (int, java.util.Map)
getObject Method (java.lang.String)
getObject Method (java.lang.String, java.util.Map)
getRef Method (SQLServerCallableStatement)
getRef Method (int)
getRef Method (java.lang.String)
getShort Method (SQLServerCallableStatement)
getShort Method (int)
getShort Method (java.lang.String)
getSQLXML Method (SQLServerCallableStatement)
getSQLXML Method (int)
getSQLXML Method (java.lang.String)
getString Method (SQLServerCallableStatement)
getString Method (int)
getString Method (java.lang.String)
getTime Method (SQLServerCallableStatement)
getTime Method (int)
getTime Method (int, java.util.Calendar)
getTime Method (java.lang.String)
getTime Method (java.lang.String, java.util.Calendar)
getTimestamp Method (SQLServerCallableStatement)
getTimestamp Method (int)
getTimestamp Method (int, java.util.Calendar)
getTimestamp Method (java.lang.String)
getTimestamp Method (java.lang.String, java.util.Calendar)
getURL Method (SQLServerCallableStatement)
getURL Method (int)
getURL Method (java.lang.String)
isWrapperFor Method (SQLServerCallableStatement)
registerOutParameter Method (SQLServerCallableStatement)
registerOutParameter Method (int, int)
registerOutParameter Method (int, int, int)
registerOutParameter Method (int, int, java.lang.String)
registerOutParameter Method (java.lang.String, int)
registerOutParameter Method (java.lang.String, int, int)
registerOutParameter Method (java.lang.String, int, java.lang.String)
setAsciiStream (SQLServerCallableStatement)
setAsciiStream Method (java.lang.String, java.io.InputStream)
setAsciiStream Method (java.lang.String, java.io.InputStream, int)
setAsciiStream Method (java.lang.String, java.io.InputStream, long)
setBigDecimal Method (SQLServerCallableStatement)
setBinaryStream (SQLServerCallableStatement)
setBinaryStream Method (java.lang.String, java.io.InputStream)
setBinaryStream Method (java.lang.String, java.io.InputStream, int)
setBinaryStream Method (java.lang.String, java.io.InputStream, long)
setBoolean Method (SQLServerCallableStatement)
setByte Method (SQLServerCallableStatement)
setBytes Method (SQLServerCallableStatement)
setCharacterStream Method (SQLServerCallableStatement)
setCharacterStream Method (java.lang.String, java.io.Reader)
setCharacterStream Method (java.lang.String, java.io.Reader, int)
setCharacterStream Method (java.lang.String, java.io.Reader, long)
setClob Method (SQLServerCallableStatement)
setClob Method (java.lang.String, java.sql.Clob)
setClob Method (java.lang.String, java.io.Reader)
setClob Method (java.lang.String, java.io.Reader, long)
setDate Method (SQLServerCallableStatement)
setDate Method (java.lang.String, java.sql.Date)
setDate Method (java.lang.String, java.sql.Date, java.util.Calendar)
setDateTimeOffset Method (SQLServerCallableStatement)
setDouble Method (SQLServerCallableStatement)
setFloat Method (SQLServerCallableStatement)
setInt Method (SQLServerCallableStatement)
setLong Method (SQLServerCallableStatement)
setNCharacterStream Method (SQLServerCallableStatement)
setNCharacterStream Method (java.lang.String, java.io.Reader)
setNCharacterStream Method (java.lang.String, java.io.Reader, long)
setNClob Method (SQLServerCallableStatement)
setNClob Method (java.lang.String, java.sql.NClob)
setNClob Method (java.lang.String, java.io.Reader)
setNClob Method (java.lang.String, java.io.Reader, long)
setNull Method (SQLServerCallableStatement)
setNull Method (java.lang.String, int)
setNull Method (java.lang.String, int, java.lang.String)
setNString Method (SQLServerCallableStatement)
setObject Method (SQLServerCallableStatement)
setObject Method (java.lang.String, java.lang.Object)
setObject Method (java.lang.String, java.lang.Object, int)
setObject Method (java.lang.String, java.lang.Object, int, int)
setShort Method (SQLServerCallableStatement)
setSQLXML Method (SQLServerCallableStatement)
setString Method (SQLServerCallableStatement)
setTime Method (SQLServerCallableStatement)
setTime Method (java.lang.String, java.sql.Time)
setTime Method (java.lang.String, java.sql.Time, java.util.Calendar)
setTimestamp Method (SQLServerCallableStatement)
setTimestamp Method (java.lang.String, java.sql.Timestamp)
setTimestamp Method (java.lang.String, java.sql.Timestamp, java.util.Calendar)
setURL Method (SQLServerCallableStatement)
wasNull Method (SQLServerCallableStatement)
unwrap Method (SQLServerCallableStatement)
SQLServerClob Class
SQLServerClob Members
SQLServerClob Constructors
SQLServerClob Constructor (SQLServerConnection, java.lang.String)
SQLServerClob Methods
free Method (SQLServerClob)
getAsciiStream Method (SQLServerClob)
getCharacterStream Method (SQLServerClob)
getCharacterStream Method ()
getCharacterStream Method (long, long)
getSubString Method (SQLServerClob)
length Method (SQLServerClob)
position Method (SQLServerClob)
position Method (java.sql.Clob, long)
position Method (java.lang.String, long)
setAsciiStream Method (SQLServerClob)
setCharacterStream Method (SQLServerClob)
setString Method (SQLServerClob)
setString Method (long, java.lang.String)
setString Method (long, java.lang.String, int, int)
truncate Method (SQLServerClob)
SQLServerConnection Class
SQLServerConnection Members
SQLServerConnection Methods
clearWarnings Method (SQLServerConnection)
close Method (SQLServerConnection)
closeUnreferencedPreparedStatementHandles Method (SQLServerConnection)
commit Method (SQLServerConnection)
createBlob Method (SQLServerConnection)
createClob Method (SQLServerConnection)
createNClob Method (SQLServerConnection)
createStatement Method (SQLServerConnection)
createStatement Method ()
createStatement Method (int, int)
createStatement Method (int, int, int)
createSQLXML Method (SQLServerConnection)
getAutoCommit Method (SQLServerConnection)
getCatalog Method (SQLServerConnection)
getClientConnectionID Method (SQLServerConnection)
getClientInfo Method (SQLServerConnection)
getClientInfo Method ()
getClientInfo Method (java.lang.String)
getDisableStatementPooling Method (SQLServerConnection)
getDiscardedServerPreparedStatementCount Method (SQLServerConnection)
getEnablePrepareOnFirstPreparedStatementCall Method
(SQLServerConnection)
getHoldability Method (SQLServerConnection)
getMetaData Method (SQLServerConnection)
getServerPreparedStatementDiscardThreshold Method (SQLServerConnection)
getStatementHandleCacheEntryCount Method (SQLServerConnection)
getStatementPoolingCacheSize Method (SQLServerConnection)
getTransactionIsolation Method (SQLServerConnection)
getTypeMap Method (SQLServerConnection)
getWarnings Method (SQLServerConnection)
isClosed Method (SQLServerConnection)
isReadOnly Method (SQLServerConnection)
isStatementPoolingEnabled Method (SQLServerConnection)
isValid Method (SQLServerConnection)
nativeSQL Method (SQLServerConnection)
prepareCall Method (SQLServerConnection)
prepareCall Method (java.lang.String)
prepareCall Method (java.lang.String, int, int)
prepareCall Method (java.lang.String, int, int, int)
prepareStatement Method (SQLServerConnection)
prepareStatement Method (java.lang.String)
prepareStatement Method (java.lang.String, int)
prepareStatement Method (java.lang.String, int, int)
prepareStatement Method (java.lang.String, int, int, int)
prepareStatement Method (java.lang.String, java.lang.String)
releaseSavepoint Method (SQLServerConnection)
rollback Method (SQLServerConnection)
rollback Method ()
rollback Method (java.sql.Savepoint)
setAutoCommit Method (SQLServerConnection)
setCatalog Method (SQLServerConnection)
setClientInfo Method (SQLServerConnection)
setClientInfo Method (java.util.Properties)
setClientInfo Method (java.lang.String, java.lang.String)
setDisableStatementPooling Method (SQLServerConnection)
setEnablePrepareOnFirstPreparedStatementCall Method
(SQLServerConnection)
setHoldability Method (SQLServerConnection)
setReadOnly Method (SQLServerConnection)
setSavepoint Method (SQLServerConnection)
setSavepoint Method ()
setSavepoint Method (java.lang.String)
setServerPreparedStatementDiscardThreshold Method (SQLServerConnection)
setStatementPoolingCacheSize Method (SQLServerConnection)
setTransactionIsolation Method (SQLServerConnection)
setTypeMap Method (SQLServerConnection)
ISQLServerConnection Fields
TRANSACTION_SNAPSHOT Field (SQLServerConnection)
SQLServerConnectionPoolDataSource Class
SQLServerConnectionPoolDataSource Members
SQLServerConnectionPoolDataSource Constructors
SQLServerConnectionPoolDataSource Constructor ()
SQLServerConnectionPoolDataSource Methods
getPooledConnection Method (SQLServerConnectionPoolDataSource)
getPooledConnection Method ()
getPooledConnection Method (java.lang.String, java.lang.String)
getReference Method (SQLServerConnectionPoolDataSource)
isWrapperFor Method (SQLServerConnectionPoolDataSource)
unwrap Method (SQLServerConnectionPoolDataSource)
SQLServerDatabaseMetaData Class
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Methods
allProceduresAreCallable Method (SQLServerDatabaseMetaData)
allTablesAreSelectable Method (SQLServerDatabaseMetaData)
autoCommitFailureClosesAllResultSets Method (SQLServerDatabaseMetaData)
dataDefinitionCausesTransactionCommit Method
(SQLServerDatabaseMetaData)
dataDefinitionIgnoredInTransactions Method (SQLServerDatabaseMetaData)
deletesAreDetected Method (SQLServerDatabaseMetaData)
doesMaxRowSizeIncludeBlobs Method (SQLServerDatabaseMetaData)
getAttributes Method (SQLServerDatabaseMetaData)
getBestRowIdentifier Method (SQLServerDatabaseMetaData)
getCatalogs Method (SQLServerDatabaseMetaData)
getCatalogSeparator Method (SQLServerDatabaseMetaData)
getCatalogTerm Method (SQLServerDatabaseMetaData)
getClientInfoProperties Method (SQLServerDatabaseMetaData)
getColumnPrivileges Method (SQLServerDatabaseMetaData)
getColumns Method (SQLServerDatabaseMetaData)
getConnection Method (SQLServerDatabaseMetaData)
getCrossReference Method (SQLServerDatabaseMetaData)
getDatabaseMajorVersion Method (SQLServerDatabaseMetaData)
getDatabaseMinorVersion Method (SQLServerDatabaseMetaData)
getDatabaseProductName Method (SQLServerDatabaseMetaData)
getDatabaseProductVersion Method (SQLServerDatabaseMetaData)
getDefaultTransactionIsolation Method (SQLServerDatabaseMetaData)
getDriverMajorVersion Method (SQLServerDatabaseMetaData)
getDriverMinorVersion Method (SQLServerDatabaseMetaData)
getDriverName Method (SQLServerDatabaseMetaData)
getDriverVersion Method (SQLServerDatabaseMetaData)
getExportedKeys Method (SQLServerDatabaseMetaData)
getExtraNameCharacters Method (SQLServerDatabaseMetaData)
getFunctions Method (SQLServerDatabaseMetaData)
getFunctionColumns Method (SQLServerDatabaseMetaData)
getIdentifierQuoteString Method (SQLServerDatabaseMetaData)
getImportedKeys Method (SQLServerDatabaseMetaData)
getIndexInfo Method (SQLServerDatabaseMetaData)
getJDBCMajorVersion Method (SQLServerDatabaseMetaData)
getJDBCMinorVersion Method (SQLServerDatabaseMetaData)
getMaxBinaryLiteralLength Method (SQLServerDatabaseMetaData)
getMaxCatalogNameLength Method (SQLServerDatabaseMetaData)
getMaxCharLiteralLength Method (SQLServerDatabaseMetaData)
getMaxColumnNameLength Method (SQLServerDatabaseMetaData)
getMaxColumnsInGroupBy Method (SQLServerDatabaseMetaData)
getMaxColumnsInIndex Method (SQLServerDatabaseMetaData)
getMaxColumnsInOrderBy Method (SQLServerDatabaseMetaData)
getMaxColumnsInSelect Method (SQLServerDatabaseMetaData)
getMaxColumnsInTable Method (SQLServerDatabaseMetaData)
getMaxConnections Method (SQLServerDatabaseMetaData)
getMaxCursorNameLength Method (SQLServerDatabaseMetaData)
getMaxIndexLength Method (SQLServerDatabaseMetaData)
getMaxProcedureNameLength Method (SQLServerDatabaseMetaData)
getMaxRowSize Method (SQLServerDatabaseMetaData)
getMaxSchemaNameLength Method (SQLServerDatabaseMetaData)
getMaxStatementLength Method (SQLServerDatabaseMetaData)
getMaxStatements Method (SQLServerDatabaseMetaData)
getMaxTableNameLength Method (SQLServerDatabaseMetaData)
getMaxTablesInSelect Method (SQLServerDatabaseMetaData)
getMaxUserNameLength Method (SQLServerDatabaseMetaData)
getNumericFunctions Method (SQLServerDatabaseMetaData)
getPrimaryKeys Method (SQLServerDatabaseMetaData)
getProcedureColumns Method (SQLServerDatabaseMetaData)
getProcedures Method (SQLServerDatabaseMetaData)
getProcedureTerm Method (SQLServerDatabaseMetaData)
getResultSetHoldability Method (SQLServerDatabaseMetaData)
getRowIdLifetime Method (SQLServerDatabaseMetaData)
getSchemas Method (SQLServerDatabaseMetaData)
getSchemas Method ()
getSchemas Method (String, String)
getSchemaTerm Method (SQLServerDatabaseMetaData)
getSearchStringEscape Method (SQLServerDatabaseMetaData)
getSQLKeywords Method (SQLServerDatabaseMetaData)
getSQLStateType Method (SQLServerDatabaseMetaData)
getStringFunctions Method (SQLServerDatabaseMetaData)
getSuperTables Method (SQLServerDatabaseMetaData)
getSuperTypes Method (SQLServerDatabaseMetaData)
getSystemFunctions Method (SQLServerDatabaseMetaData)
getTablePrivileges Method (SQLServerDatabaseMetaData)
getTables Method (SQLServerDatabaseMetaData)
getTableTypes Method (SQLServerDatabaseMetaData)
getTimeDateFunctions Method (SQLServerDatabaseMetaData)
getTypeInfo Method (SQLServerDatabaseMetaData)
getUDTs Method (SQLServerDatabaseMetaData)
getURL Method (SQLServerDatabaseMetaData)
getUserName Method (SQLServerDatabaseMetaData)
getVersionColumns Method (SQLServerDatabaseMetaData)
insertsAreDetected Method (SQLServerDatabaseMetaData)
isCatalogAtStart Method (SQLServerDatabaseMetaData)
isReadOnly Method (SQLServerDatabaseMetaData)
locatorsUpdateCopy Method (SQLServerDatabaseMetaData)
nullPlusNonNullIsNull Method (SQLServerDatabaseMetaData)
nullsAreSortedAtEnd Method (SQLServerDatabaseMetaData)
nullsAreSortedAtStart Method (SQLServerDatabaseMetaData)
nullsAreSortedHigh Method (SQLServerDatabaseMetaData)
nullsAreSortedLow Method (SQLServerDatabaseMetaData)
othersDeletesAreVisible Method (SQLServerDatabaseMetaData)
othersInsertsAreVisible Method (SQLServerDatabaseMetaData)
othersUpdatesAreVisible Method (SQLServerDatabaseMetaData)
ownDeletesAreVisible Method (SQLServerDatabaseMetaData)
ownInsertsAreVisible Method (SQLServerDatabaseMetaData)
ownUpdatesAreVisible Method (SQLServerDatabaseMetaData)
storesLowerCaseIdentifiers Method (SQLServerDatabaseMetaData)
storesLowerCaseQuotedIdentifiers Method (SQLServerDatabaseMetaData)
storesMixedCaseIdentifiers Method (SQLServerDatabaseMetaData)
storesMixedCaseQuotedIdentifiers Method (SQLServerDatabaseMetaData)
storesUpperCaseIdentifiers Method (SQLServerDatabaseMetaData)
storesUpperCaseQuotedIdentifiers Method (SQLServerDatabaseMetaData)
supportsAlterTableWithAddColumn Method (SQLServerDatabaseMetaData)
supportsAlterTableWithDropColumn Method (SQLServerDatabaseMetaData)
supportsANSI92EntryLevelSQL Method (SQLServerDatabaseMetaData)
supportsANSI92FullSQL Method (SQLServerDatabaseMetaData)
supportsANSI92IntermediateSQL Method (SQLServerDatabaseMetaData)
supportsBatchUpdates Method (SQLServerDatabaseMetaData)
supportsCatalogsInDataManipulation Method (SQLServerDatabaseMetaData)
supportsCatalogsInIndexDefinitions Method (SQLServerDatabaseMetaData)
supportsCatalogsInPrivilegeDefinitions Method (SQLServerDatabaseMetaData)
supportsCatalogsInProcedureCalls Method (SQLServerDatabaseMetaData)
supportsCatalogsInTableDefinitions Method (SQLServerDatabaseMetaData)
supportsColumnAliasing Method (SQLServerDatabaseMetaData)
supportsConvert Method (SQLServerDatabaseMetaData)
supportsConvert Method ()
supportsConvert Method (int, int)
supportsCoreSQLGrammar Method (SQLServerDatabaseMetaData)
supportsCorrelatedSubqueries Method (SQLServerDatabaseMetaData)
supportsDataDefinitionAndDataManipulationTransactions Method
(SQLServerDatabaseMetaData)
supportsDataManipulationTransactionsOnly Method
(SQLServerDatabaseMetaData)
supportsDifferentTableCorrelationNames Method
(SQLServerDatabaseMetaData)
supportsExpressionsInOrderBy Method (SQLServerDatabaseMetaData)
supportsExtendedSQLGrammar Method (SQLServerDatabaseMetaData)
supportsFullOuterJoins Method (SQLServerDatabaseMetaData)
supportsGetGeneratedKeys Method (SQLServerDatabaseMetaData)
supportsGroupBy Method (SQLServerDatabaseMetaData)
supportsGroupByBeyondSelect Method (SQLServerDatabaseMetaData)
supportsGroupByUnrelated Method (SQLServerDatabaseMetaData)
supportsIntegrityEnhancementFacility Method (SQLServerDatabaseMetaData)
supportsLikeEscapeClause Method (SQLServerDatabaseMetaData)
supportsLimitedOuterJoins Method (SQLServerDatabaseMetaData)
supportsMinimumSQLGrammar Method (SQLServerDatabaseMetaData)
supportsMixedCaseIdentifiers Method (SQLServerDatabaseMetaData)
supportsMixedCaseQuotedIdentifiers Method (SQLServerDatabaseMetaData)
supportsMultipleOpenResults Method (SQLServerDatabaseMetaData)
supportsMultipleResultSets Method (SQLServerDatabaseMetaData)
supportsMultipleTransactions Method (SQLServerDatabaseMetaData)
supportsNamedParameters Method (SQLServerDatabaseMetaData)
supportsNonNullableColumns Method (SQLServerDatabaseMetaData)
supportsOpenCursorsAcrossCommit Method (SQLServerDatabaseMetaData)
supportsOpenCursorsAcrossRollback Method (SQLServerDatabaseMetaData)
supportsOpenStatementsAcrossCommit Method (SQLServerDatabaseMetaData)
supportsOpenStatementsAcrossRollback Method
(SQLServerDatabaseMetaData)
supportsOrderByUnrelated Method (SQLServerDatabaseMetaData)
supportsOuterJoins Method (SQLServerDatabaseMetaData)
supportsPositionedDelete Method (SQLServerDatabaseMetaData)
supportsPositionedUpdate Method (SQLServerDatabaseMetaData)
supportsResultSetConcurrency Method (SQLServerDatabaseMetaData)
supportsResultSetHoldability Method (SQLServerDatabaseMetaData)
supportsResultSetType Method (SQLServerDatabaseMetaData)
supportsSavepoints Method (SQLServerDatabaseMetaData)
supportsSchemasInDataManipulation Method (SQLServerDatabaseMetaData)
supportsSchemasInIndexDefinitions Method (SQLServerDatabaseMetaData)
supportsSchemasInPrivilegeDefinitions Method (SQLServerDatabaseMetaData)
supportsSchemasInProcedureCalls Method (SQLServerDatabaseMetaData)
supportsSchemasInTableDefinitions Method (SQLServerDatabaseMetaData)
supportsSelectForUpdate Method (SQLServerDatabaseMetaData)
supportsStatementPooling Method (SQLServerDatabaseMetaData)
supportsStoredProcedures Method (SQLServerDatabaseMetaData)
supportsStoredFunctionsUsingCallSyntax Method
(SQLServerDatabaseMetaData)
supportsSubqueriesInComparisons Method (SQLServerDatabaseMetaData)
supportsSubqueriesInExists Method (SQLServerDatabaseMetaData)
supportsSubqueriesInIns Method (SQLServerDatabaseMetaData)
supportsSubqueriesInQuantifieds Method (SQLServerDatabaseMetaData)
supportsTableCorrelationNames Method (SQLServerDatabaseMetaData)
supportsTransactionIsolationLevel Method (SQLServerDatabaseMetaData)
supportsTransactions Method (SQLServerDatabaseMetaData)
supportsUnion Method (SQLServerDatabaseMetaData)
supportsUnionAll Method (SQLServerDatabaseMetaData)
updatesAreDetected Method (SQLServerDatabaseMetaData)
usesLocalFilePerTable Method (SQLServerDatabaseMetaData)
usesLocalFiles Method (SQLServerDatabaseMetaData)
SQLServerDataSource Class
SQLServerDataSource Members
SQLServerDataSource Constructors
SQLServerDataSource Constructor ()
SQLServerDataSource Methods
getApplicationIntent Method (SQLServerDataSource)
getApplicationName Method (SQLServerDataSource)
getConnection Method (SQLServerDataSource)
getConnection Method ()
getConnection Method (java.lang.String, java.lang.String)
getDatabaseName Method (SQLServerDataSource)
getDescription Method (SQLServerDataSource)
getDisableStatementPooling Method (SQLServerDataSource)
getEnablePrepareOnFirstPreparedStatementCall Method
(SQLServerDataSource)
getEncrypt Method (SQLServerDataSource)
getFailoverPartner Method (SQLServerDataSource)
getHostNameInCertificate Method (SQLServerDataSource)
getInstanceName Method (SQLServerDataSource)
getLastUpdateCount Method (SQLServerDataSource)
getLockTimeout Method (SQLServerDataSource)
getLoginTimeout Method (SQLServerDataSource)
getLogWriter Method (SQLServerDataSource)
getMultiSubnetFailover Method (SQLServerDataSource)
getPacketSize Method (SQLServerDataSource)
getPortNumber Method (SQLServerDataSource)
getReference Method (SQLServerDataSource)
getResponseBuffering Method (SQLServerDataSource)
getSelectMethod Method (SQLServerDataSource)
getSendStringParametersAsUnicode Method (SQLServerDataSource)
getServerName Method (SQLServerDataSource)
getServerPreparedStatementDiscardThreshold Method (SQLServerDataSource)
getStatementPoolingCacheSize Method (SQLServerDataSource)
getTrustManagerClass Method (SQLServerDataSource)
getTrustManagerConstructorArg Method (SQLServerDataSource)
getTrustServerCertificate Method (SQLServerDataSource)
getTrustStore Method (SQLServerDataSource)
getURL Method (SQLServerDataSource)
getSendTimeAsDatetime Method (SQLServerDataSource)
getUser Method (SQLServerDataSource)
getWorkstationID Method (SQLServerDataSource)
getXopenStates Method (SQLServerDataSource)
isWrapperFor Method (SQLServerDataSource)
setApplicationIntent Method (SQLServerDataSource)
setApplicationName Method (SQLServerDataSource)
setAuthenticationScheme (SQLServerDataSource)
setDatabaseName Method (SQLServerDataSource)
setDescription Method (SQLServerDataSource)
setDisableStatementPooling Method (SQLServerDataSource)
setEnablePrepareOnFirstPreparedStatementCall Method
(SQLServerDataSource)
setEncrypt Method (SQLServerDataSource)
setFailoverPartner Method (SQLServerDataSource)
setHostNameInCertificate Method (SQLServerDataSource)
setInstanceName Method (SQLServerDataSource)
setIntegratedSecurity Method (SQLServerDataSource)
setLastUpdateCount Method (SQLServerDataSource)
setLockTimeout Method (SQLServerDataSource)
setLoginTimeout Method (SQLServerDataSource)
setLogWriter Method (SQLServerDataSource)
setMultiSubnetFailover Method (SQLServerDataSource)
setPacketSize Method (SQLServerDataSource)
setPassword Method (SQLServerDataSource)
setPortNumber Method (SQLServerDataSource)
setResponseBuffering Method (SQLServerDataSource)
setSelectMethod Method (SQLServerDataSource)
setSendStringParametersAsUnicode Method (SQLServerDataSource)
setSendTimeAsDatetime Method (SQLServerDataSource)
setServerName Method (SQLServerDataSource)
setServerPreparedStatementDiscardThreshold Method (SQLServerDataSource)
setStatementPoolingCacheSize Method (SQLServerDataSource)
setTrustManagerClass Method (SQLServerDataSource)
setTrustManagerConstructorArg Method (SQLServerDataSource)
setTrustServerCertificate Method (SQLServerDataSource)
setTrustStore Method (SQLServerDataSource)
setTrustStorePassword Method (SQLServerDataSource)
setURL Method (SQLServerDataSource)
setUser Method (SQLServerDataSource)
setWorkstationID Method (SQLServerDataSource)
setXopenStates Method (SQLServerDataSource)
unwrap Method (SQLServerDataSource)
SQLServerDataSourceObjectFactory Class
SQLServerDataSourceObjectFactory Members
SQLServerDataSourceObjectFactory Constructors
SQLServerDataSourceObjectFactory Constructor ()
SQLServerDataSourceObjectFactory Methods
getObjectInstance Method (SQLServerDataSourceObjectFactory)
SQLServerDriver Class
SQLServerDriver Members
SQLServerDriver Constructors
SQLServerDriver Constructor ()
SQLServerDriver Methods
acceptsURL Method (SQLServerDriver)
connect Method (SQLServerDriver)
getMajorVersion Method (SQLServerDriver)
getMinorVersion Method (SQLServerDriver)
getPropertyInfo Method (SQLServerDriver)
jdbcCompliant Method (SQLServerDriver)
SQLServerException Class
SQLServerException Members
SQLServerException Constructors
SQLServerException Method (java.lang.Object, java.lang.String, java.lang.String,
int, boolean) (SQLServerDriver)
SQLServerException Method (java.lang.Object, java.lang.String, java.lang.String,
StreamError, boolean) (SQLServerDriver)
SQLServerException Method (java.lang.String, SQLState, DriverError,
java.lang.Throwable) (SQLServerDriver)
SQLServerException Method (java.lang.String, java.lang.String, int,
java.lang.Throwable) (SQLServerDriver)
SQLServerException Method (java.lang.String, java.lang.Throwable)
(SQLServerDriver)
SQLServerException Methods
SQLServerNClob Class
SQLServerNClob Members
SQLServerNClob Methods
free Method (SQLServerNClob)
getAsciiStream Method (SQLServerNClob)
getCharacterStream Method (SQLServerNClob)
getCharacterStream Method (long, long) (SQLServerNClob)
getSubString Method (SQLServerNClob)
length Method (SQLServerNClob)
position Method (SQLServerNClob)
position Method (java.sql.NClob, long)
position Method (java.lang.String, long) (SQLServerNClob)
setAsciiStream Method (SQLServerNClob)
setCharacterStream Method (SQLServerNClob)
setString Method (SQLServerNClob)
setString Method (long, java.lang.String) (SQLServerNClob)
setString Method (long, java.lang.String, int, int) (SQLServerNClob)
truncate Method (SQLServerNClob)
SQLServerParameterMetaData Class
SQLServerParameterMetaData Members
SQLServerParameterMetaData Methods
getParameterClassName Method (SQLServerParameterMetaData)
getParameterCount Method (SQLServerParameterMetaData)
getParameterMode Method (SQLServerParameterMetaData)
getParameterType Method (SQLServerParameterMetaData)
getParameterTypeName Method (SQLServerParameterMetaData)
getPrecision Method (SQLServerParameterMetaData)
getScale Method (SQLServerParameterMetaData)
isNullable Method (SQLServerParameterMetaData)
isSigned Method (SQLServerParameterMetaData)
SQLServerPooledConnection Class
SQLServerPooledConnection Members
SQLServerPooledConnection Methods
addConnectionEventListener Method (SQLServerPooledConnection)
close Method (SQLServerPooledConnection)
getConnection Method (SQLServerPooledConnection)
removeConnectionEventListener Method (SQLServerPooledConnection)
SQLServerPreparedStatement Class
SQLServerPreparedStatement Members
SQLServerPreparedStatement Methods
addBatch Method (SQLServerPreparedStatement)
addBatch Method ()
addBatch Method (java.lang.String)
clearBatch Method (SQLServerPreparedStatement)
clearParameters Method (SQLServerPreparedStatement)
close Method (SQLServerPreparedStatement)
execute Method (SQLServerPreparedStatement)
execute Method ()
execute Method (java.lang.String)
executeBatch Method (SQLServerPreparedStatement)
executeQuery Method (SQLServerPreparedStatement)
executeQuery Method ()
executeQuery Method (java.lang.String)
executeUpdate Method (SQLServerPreparedStatement)
executeUpdate Method ()
executeUpdate Method (java.lang.String, int[])
executeUpdate Method (java.lang.String)
getMetaData Method (SQLServerPreparedStatement)
getParameterMetaData Method (SQLServerPreparedStatement)
isWrapperFor Method (SQLServerPreparedStatement)
setArray Method (SQLServerPreparedStatement)
setAsciiStream Method (SQLServerPreparedStatement)
setAsciiStream Method (int, java.io.InputStream)
setAsciiStream Method (int, java.io.InputStream, int)
setAsciiStream Method (int, java.io.InputStream, long)
setBigDecimal Method (SQLServerPreparedStatement)
setBinaryStream Method (SQLServerPreparedStatement)
setBinaryStream Method (int, java.io.InputStream)
setBinaryStream Method (int, java.io.InputStream, int)
setBinaryStream Method (int, java.io.InputStream, long)
setBlob Method (SQLServerPreparedStatement)
setBoolean Method (SQLServerPreparedStatement)
setByte Method (SQLServerPreparedStatement)
setBytes Method (SQLServerPreparedStatement)
setCharacterStream Method (SQLServerPreparedStatement)
setCharacterStream Method (int, java.io.Reader)
setCharacterStream Method (int, java.io.Reader, int)
setCharacterStream Method (int, java.io.Reader, long)
setClob Method (SQLServerPreparedStatement)
setClob Method (int, java.io.Reader)
setClob Method (int, java.sql.Clob)
setClob Method (int, java.io.Reader, long)
setDate Method (SQLServerPreparedStatement)
setDate Method (int, java.sql.Date)
setDate Method (int, java.sql.Date, java.util.Calendar)
setDouble Method (SQLServerPreparedStatement)
setDateTimeOffset Method (SQLServerPreparedStatement)
setFloat Method (SQLServerPreparedStatement)
setInt Method (SQLServerPreparedStatement)
setLong Method (SQLServerPreparedStatement)
setNCharacterStream Method (SQLServerPreparedStatement)
setNCharacterStream Method (int, java.io.Reader)
setNCharacterStream Method (int, java.io.Reader, long)
setNClob Method (SQLServerPreparedStatement)
setNClob Method (int, java.sql.NClob)
setNClob Method (int, java.io.Reader)
setNClob Method (int, java.io.Reader, long)
setNString Method (int, java.lang.String)
setNull Method (SQLServerPreparedStatement)
setNull Method (int, int)
setNull Method (int, int, java.lang.String)
setObject Method (SQLServerPreparedStatement)
setObject Method (int, java.lang.Object)
setObject Method (int, java.lang.Object, int)
setObject Method (int, java.lang.Object, int, int)
setRef Method (SQLServerPreparedStatement)
setShort Method (SQLServerPreparedStatement)
setSQLXML Method (SQLServerPreparedStatement)
setString Method (SQLServerPreparedStatement)
setTime Method (SQLServerPreparedStatement)
setTime Method (int, java.sql.Time)
setTime Method (int, java.sql.Time, java.util.Calendar)
setTimestamp Method (SQLServerPreparedStatement)
setTimestamp Method (int, java.sql.Timestamp)
setTimestamp Method (int, java.sql.Timestamp, java.util.Calendar)
setUnicodeStream Method (SQLServerPreparedStatement)
setURL Method (SQLServerPreparedStatement)
unwrap Method (SQLServerPreparedStatement)
SQLServerResource Class
SQLServerResource Members
SQLServerResource Constructors
SQLServerResource Constructor ()
SQLServerResource Methods
getContents Method (SQLServerResource)
SQLServerResultSet Class
SQLServerResultSet Members
SQLServerResultSet Methods
absolute Method (SQLServerResultSet)
afterLast Method (SQLServerResultSet)
beforeFirst Method (SQLServerResultSet)
cancelRowUpdates Method (SQLServerResultSet)
clearWarnings Method (SQLServerResultSet)
close Method (SQLServerResultSet)
deleteRow Method (SQLServerResultSet)
finalize Method (SQLServerResultSet)
findColumn Method (SQLServerResultSet)
first Method (SQLServerResultSet)
getArray Method (SQLServerResultSet)
getArray Method (int) (SQLServerResultSet)
getArray Method (java.lang.String) (SQLServerResultSet)
getAsciiStream Method (SQLServerResultSet)
getAsciiStream Method (int)
getAsciiStream Method (java.lang.String)
getBigDecimal Method (SQLServerResultSet)
getBigDecimal Method (int) (SQLServerResultSet)
getBigDecimal Method (int, int) (SQLServerResultSet)
getBigDecimal Method (java.lang.String) (SQLServerResultSet)
getBigDecimal Method (java.lang.String, int) (SQLServerResultSet)
getBinaryStream Method (SQLServerResultSet)
getBinaryStream Method (int)
getBinaryStream Method (long, long)
getBinaryStream Method (java.lang.String)
getBlob Method (SQLServerResultSet)
getBlob Method (int) (SQLServerResultSet)
getBlob Method (java.lang.String) (SQLServerResultSet)
getBoolean Method (SQLServerResultSet)
getBoolean Method (int) (SQLServerResultSet)
getBoolean Method (java.lang.String) (SQLServerResultSet)
getByte Method (SQLServerResultSet)
getByte Method (int) (SQLServerResultSet)
getByte Method (java.lang.String) (SQLServerResultSet)
getBytes Method (SQLServerResultSet)
getBytes Method (int) (SQLServerResultSet)
getBytes Method (java.lang.String) (SQLServerResultSet)
getCharacterStream Method (SQLServerResultSet)
getCharacterStream Method (int)
getCharacterStream Method (java.lang.String)
getCharacterStream Method () (SQLServerNClob)
getClob Method (SQLServerResultSet)
getClob Method (int) (SQLServerResultSet)
getClob Method (java.lang.String) (SQLServerResultSet)
getConcurrency Method (SQLServerResultSet)
getCursorName Method (SQLServerResultSet)
getDate Method (SQLServerResultSet)
getDate Method (int) (SQLServerResultSet)
getDate Method (int, java.util.Calendar) (SQLServerResultSet)
getDate Method (java.lang.String) (SQLServerResultSet)
getDate Method (java.lang.String, java.util.Calendar) (SQLServerResultSet)
getDateTimeOffset (SQLServerResultSet)
getDateTimeOffset(int)
getDateTimeOffset(java.lang.string)
getDouble Method (SQLServerResultSet)
getDouble Method (int) (SQLServerResultSet)
getDouble Method (java.lang.String) (SQLServerResultSet)
getFetchDirection Method (SQLServerResultSet)
getFetchSize Method (SQLServerResultSet)
getFloat Method (SQLServerResultSet)
getFloat Method (int) (SQLServerResultSet)
getFloat Method (java.lang.String) (SQLServerResultSet)
getHoldability Method (SQLServerResultSet)
getInt Method (SQLServerResultSet)
getInt Method (int) (SQLServerResultSet)
getInt Method (java.lang.String) (SQLServerResultSet)
getLong Method (SQLServerResultSet)
getLong Method (int) (SQLServerResultSet)
getLong Method (java.lang.String) (SQLServerResultSet)
getMetaData Method (SQLServerResultSet)
getNCharacterStream Method (SQLServerResultSet)
getNCharacterStream Method (int) (SQLServerResultSet)
getNCharacterStream Method (java.lang.String) (SQLServerResultSet)
getNClob Method (SQLServerResultSet)
getNClob Method (int) (SQLServerResultSet)
getNClob Method (java.lang.String) (SQLServerResultSet)
getNString Method (SQLServerResultSet)
getNString Method (int) (SQLServerResultSet)
getNString Method (java.lang.String) (SQLServerResultSet)
getObject Method (SQLServerResultSet)
getObject Method (int) (SQLServerResultSet)
getObject Method (int, java.util.Map) (SQLServerResultSet)
getObject Method (java.lang.String) (SQLServerResultSet)
getObject Method (java.lang.String, java.util.Map) (SQLServerResultSet)
getRef Method (SQLServerResultSet)
getRef Method (int) (SQLServerResultSet)
getRef Method (java.lang.String) (SQLServerResultSet)
getRow Method (SQLServerResultSet)
getShort Method (SQLServerResultSet)
getShort Method (int) (SQLServerResultSet)
getShort Method (java.lang.String) (SQLServerResultSet)
getSQLXML Method (SQLServerResultSet)
getSQLXML Method (int) (SQLServerResultSet)
getSQLXML Method (java.lang.String) (SQLServerResultSet)
getStatement Method (SQLServerResultSet)
getString Method (SQLServerResultSet)
getString Method (int) (SQLServerResultSet)
getString Method (java.lang.String) (SQLServerResultSet)
getTime Method (SQLServerResultSet)
getTime Method (int) (SQLServerResultSet)
getTime Method (int, java.util.Calendar) (SQLServerResultSet)
getTime Method (java.lang.String) (SQLServerResultSet)
getTime Method (java.lang.String, java.util.Calendar) (SQLServerResultSet)
getTimestamp Method (SQLServerResultSet)
getTimestamp Method (int) (SQLServerResultSet)
getTimestamp Method (int, java.util.Calendar) (SQLServerResultSet)
getTimestamp Method (java.lang.String) (SQLServerResultSet)
getTimestamp Method (java.lang.String, java.util.Calendar)
(SQLServerResultSet)
getType Method (SQLServerResultSet)
getUnicodeStream Method (SQLServerResultSet)
getUnicodeStream Method (int)
getUnicodeStream Method (java.lang.String)
getURL Method (SQLServerResultSet)
getURL Method (int) (SQLServerResultSet)
getURL Method (java.lang.String) (SQLServerResultSet)
getWarnings Method (SQLServerResultSet)
insertRow Method (SQLServerResultSet)
isAfterLast Method (SQLServerResultSet)
isBeforeFirst Method (SQLServerResultSet)
isClosed Method (SQLServerResultSet)
isFirst Method (SQLServerResultSet)
isLast Method (SQLServerResultSet)
last Method (SQLServerResultSet)
moveToCurrentRow Method (SQLServerResultSet)
moveToInsertRow Method (SQLServerResultSet)
next Method (SQLServerResultSet)
previous Method (SQLServerResultSet)
refreshRow Method (SQLServerResultSet)
relative Method (SQLServerResultSet)
rowDeleted Method (SQLServerResultSet)
rowInserted Method (SQLServerResultSet)
rowUpdated Method (SQLServerResultSet)
setFetchDirection Method (SQLServerResultSet)
setFetchSize Method (SQLServerResultSet)
updateArray Method (SQLServerResultSet)
updateArray Method (int, java.sql.Array)
updateArray Method (java.lang.String, java.sql.Array)
updateAsciiStream Method (SQLServerResultSet)
updateAsciiStream Method (int, java.io.InputStream)
updateAsciiStream Method (int, java.io.InputStream, int)
updateAsciiStream Method (int, java.io.InputStream, long)
updateAsciiStream Method (java.lang.String, java.io.InputStream)
updateAsciiStream Method (java.lang.String, java.io.InputStream, int)
updateAsciiStream Method (java.lang.String, java.io.InputStream, long)
updateBigDecimal Method (SQLServerResultSet)
updateBigDecimal Method (int, java.math.BigDecimal)
updateBigDecimal Method (java.lang.String, java.math.BigDecimal)
updateBinaryStream Method (SQLServerResultSet)
updateBinaryStream Method (int, java.io.InputStream)
updateBinaryStream Method (int, java.io.InputStream, int)
updateBinaryStream Method (int, java.io.InputStream, long)
updateBinaryStream Method (java.lang.String, java.io.InputStream)
updateBinaryStream Method (java.lang.String, java.io.InputStream, int)
updateBinaryStream Method (java.lang.String, java.io.InputStream, long)
updateBlob Method (SQLServerResultSet)
updateBlob Method (int, java.sql.Blob)
updateBlob Method (int, java.io.InputStream)
updateBlob Method (int, java.io.InputStream, long)
updateBlob Method (java.lang.String, java.sql.Blob)
updateBlob Method (java.lang.String, java.io.InputStream)
updateBlob Method (java.lang.String, java.io.InputStream, long)
updateBoolean Method (SQLServerResultSet)
updateBoolean Method (int, boolean)
updateBoolean Method (java.lang.String, boolean)
updateByte Method (SQLServerResultSet)
updateByte Method (int, byte)
updateByte Method (java.lang.String, byte)
updateBytes Method (SQLServerResultSet)
updateBytes Method (int, byte)
updateBytes Method (java.lang.String, byte)
updateCharacterStream Method (SQLServerResultSet)
updateCharacterStream Method (int, java.io.Reader)
updateCharacterStream Method (int, java.io.Reader, int)
updateCharacterStream Method (int, java.io.Reader, long)
updateCharacterStream Method (java.lang.String, java.io.Reader)
updateCharacterStream Method (java.lang.String, java.io.Reader, int)
updateCharacterStream Method (java.lang.String, java.io.Reader, long)
updateClob Method (SQLServerResultSet)
updateClob Method (int, java.sql.Clob)
updateClob Method (int, java.io.Reader)
updateClob Method (int, java.io.Reader, long)
updateClob Method (java.lang.String, java.sql.Clob)
updateClob Method (java.lang.String, java.io.Reader)
updateClob Method (java.lang.String, java.io.Reader, long)
updateDate Method (SQLServerResultSet)
updateDate Method (int, java.sql.Date)
updateDate Method (java.lang.String, java.sql.Date)
updateDateTimeOffset (SQLServerResultSet)
updateDateTimeOffset(int, microsoft.sql.DateTimeOffset)
(SQLServerResultSet)
updateDateTimeOffset(string, microsoft.sql.DateTimeOffset)
(SQLServerResultSet)
updateDouble Method (SQLServerResultSet)
updateDouble Method (int, double)
updateDouble Method (java.lang.String, double)
updateFloat Method (SQLServerResultSet)
updateFloat Method (int, float)
updateFloat Method (java.lang.String, float)
updateInt Method (SQLServerResultSet)
updateInt Method (int, int)
updateInt Method (java.lang.String, int)
updateLong Method (SQLServerResultSet)
updateLong Method (int, long)
updateLong Method (java.lang.String, long)
updateNCharacterStream Method (SQLServerResultSet)
updateNCharacterStream Method (int, java.io.Reader)
updateNCharacterStream Method (int, java.io.Reader, long)
updateNCharacterStream Method (java.lang.String, java.io.Reader)
updateNCharacterStream Method (java.lang.String, java.io.Reader, long)
updateNClob Method (SQLServerResultSet)
updateNClob Method (int, java.sql.NClob)
updateNClob Method (int, java.io.Reader)
updateNClob Method (int, java.io.Reader, long)
updateNClob Method (java.lang.String, java.sql.NClob)
updateNClob Method (java.lang.String, java.io.Reader)
updateNClob Method (java.lang.String, java.io.Reader, long)
updateNString Method (SQLServerResultSet)
updateNString Method (int, java.lang.String)
updateNString Method (java.lang.String, java.lang.String)
updateNull Method (SQLServerResultSet)
updateNull Method (int)
updateNull Method (java.lang.String)
updateObject Method (SQLServerResultSet)
updateObject Method (int, java.lang.Object)
updateObject Method (int, java.lang.Object, int)
updateObject Method (java.lang.String, java.lang.Object)
updateObject Method (java.lang.String, java.lang.Object, int)
updateRef Method (SQLServerResultSet)
updateRef Method (int, java.sql.Ref)
updateRef Method (java.lang.String, java.sql.Ref)
updateRow Method (SQLServerResultSet)
updateShort Method (SQLServerResultSet)
updateShort Method (int, short)
updateShort Method (java.lang.String, short)
updateSQLXML Method (SQLServerResultSet)
updateSQLXML Method (int, java.sql.SQLXML)
updateSQLXML Method (java.lang.String, java.sql.SQLXML)
updateString Method (SQLServerResultSet)
updateString Method (int, java.lang.String)
updateString Method (java.lang.String, java.lang.String)
updateTime Method (SQLServerResultSet)
updateTime Method (int, java.sql.Time)
updateTime Method (java.lang.String, java.sql.Time)
updateTimestamp Method (SQLServerResultSet)
updateTimestamp Method (int, java.sql.Timestamp)
updateTimestamp Method (java.lang.String, java.sql.Timestamp)
wasNull Method (SQLServerResultSet)
SQLServerResultSet Fields
CONCUR_SS_OPTIMISTIC_CC Field (SQLServerResultSet)
CONCUR_SS_OPTIMISTIC_CCVAL Field (SQLServerResultSet)
CONCUR_SS_SCROLL_LOCKS Field (SQLServerResultSet)
TYPE_SS_DIRECT_FORWARD_ONLY Field (SQLServerResultSet)
TYPE_SS_SCROLL_DYNAMIC Field (SQLServerResultSet)
TYPE_SS_SCROLL_KEYSET Field (SQLServerResultSet)
TYPE_SS_SCROLL_STATIC Field (SQLServerResultSet)
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY Field (SQLServerResultSet)
SQLServerResultSetMetaData Class
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Methods
getCatalogName Method (SQLServerResultSetMetaData)
getColumnClassName Method (SQLServerResultSetMetaData)
getColumnCount Method (SQLServerResultSetMetaData)
getColumnDisplaySize Method (SQLServerResultSetMetaData)
getColumnLabel Method (SQLServerResultSetMetaData)
getColumnName Method (SQLServerResultSetMetaData)
getColumnType Method (SQLServerResultSetMetaData)
getColumnTypeName Method (SQLServerResultSetMetaData)
getPrecision Method (SQLServerResultSetMetaData)
getScale Method (SQLServerResultSetMetaData)
getSchemaName Method (SQLServerResultSetMetaData)
getTableName Method (SQLServerResultSetMetaData)
isAutoIncrement Method (SQLServerResultSetMetaData)
isCaseSensitive Method (SQLServerResultSetMetaData)
isCurrency Method (SQLServerResultSetMetaData)
isDefinitelyWritable Method (SQLServerResultSetMetaData)
isNullable Method (SQLServerResultSetMetaData)
isReadOnly Method (SQLServerResultSetMetaData)
isSearchable Method (SQLServerResultSetMetaData)
isSigned Method (SQLServerResultSetMetaData)
isSparseColumnSet Method (SQLServerResultSetMetaData)
isWritable Method (SQLServerResultSetMetaData)
SQLServerSavepoint Class
SQLServerSavepoint Members
SQLServerSavepoint Constructors
SQLServerSavepoint Constructor (SQLServerConnection, java.lang.StringName)
SQLServerSavepoint Methods
getLabel Method (SQLServerSavepoint)
getSavepointId Method (SQLServerSavepoint)
getSavepointName Method (SQLServerSavepoint)
isNamed Method (SQLServerSavepoint)
SQLServerStatement Class
SQLServerStatement Members
SQLServerStatement Methods
addBatch Method (SQLServerStatement)
cancel Method (SQLServerStatement)
clearBatch Method (SQLServerStatement)
clearWarnings Method (SQLServerStatement)
close Method (SQLServerStatement)
execute Method (SQLServerStatement)
execute Method (java.lang.String) (SQLServerStatement)
execute Method (java.lang.String, int)
execute Method (java.lang.String, java.lang.String)
executeBatch Method (SQLServerStatement)
executeQuery Method (SQLServerStatement)
executeUpdate Method (SQLServerStatement)
executeUpdate Method (java.lang.String) (SQLServerStatement)
executeUpdate Method (java.lang.String, int)
executeUpdate Method (java.lang.String, java.lang.String)
getConnection Method (SQLServerStatement)
getFetchDirection Method (SQLServerStatement)
getFetchSize Method (SQLServerStatement)
getGeneratedKeys Method (SQLServerStatement)
getMaxFieldSize Method (SQLServerStatement)
getMaxRows Method (SQLServerStatement)
getMoreResults Method (SQLServerStatement)
getMoreResults Method ()
getMoreResults Method (int)
getQueryTimeout Method (SQLServerStatement)
getResponseBuffering Method (SQLServerStatement)
getResultSet Method (SQLServerStatement)
getResultSetConcurrency Method (SQLServerStatement)
getResultSetHoldability Method (SQLServerStatement)
getResultSetType Method (SQLServerStatement)
getUpdateCount Method (SQLServerStatement)
getWarnings Method (SQLServerStatement)
isClosed Method (SQLServerStatement)
isPoolable Method (SQLServerStatement)
isWrapperFor Method (SQLServerStatement)
setCursorName Method (SQLServerStatement)
setDateTimeOffset(int, java.sql.DateTimeOffset)
setEscapeProcessing Method (SQLServerStatement)
setFetchDirection Method (SQLServerStatement)
setFetchSize Method (SQLServerStatement)
setMaxFieldSize Method (SQLServerStatement)
setMaxRows Method (SQLServerStatement)
setPoolable Method (SQLServerStatement)
setResponseBuffering Method (SQLServerStatement)
setQueryTimeout Method (SQLServerStatement)
unwrap Method (SQLServerStatement)
SQLServerXAConnection Class
SQLServerXAConnection Members
SQLServerXAConnection Methods
getXAResource Method (SQLServerXAConnection)
SQLServerXADataSource Class
SQLServerXADataSource Members
SQLServerXADataSource Constructors
SQLServerXADataSource Constructor ()
SQLServerXADataSource Methods
getReference Method (SQLServerXADataSource)
getXAConnection Method (SQLServerXADataSource)
getXAConnection Method ()
getXAConnection Method (java.lang.String, java.lang.String)
isWrapperFor Method (SQLServerXADataSource)
unwrap Method (SQLServerXADataSource)
SQLServerXAResource Class
SQLServerXAResource Members
SQLServerXAResource Methods
commit Method (SQLServerXAResource)
end Method (SQLServerXAResource)
forget Method (SQLServerXAResource)
getTransactionTimeout Method (SQLServerXAResource)
isSameRM Method (SQLServerXAResource)
prepare Method (SQLServerXAResource)
recover Method (SQLServerXAResource)
rollback Method (SQLServerXAResource)
setTransactionTimeout Method (SQLServerXAResource)
start Method (SQLServerXAResource)
SQLServerXAResource Fields
SSTRANSTIGHTLYCPLD Field (SQLServerXAResource)
Securing applications
Securing connection strings
Validating user input
Application security
Using encryption
Understanding encryption support
Connecting with encryption
Configuring the client for encryption
FIPS mode
Improving performance and reliability
Closing objects when not in use
Managing transaction size
Working with statements and result sets
Using adaptive buffering
Sparse columns
Prepared statement metadata caching
Diagnosing problems
Handling errors
Getting the driver version
Tracing driver operation
Troubleshooting connectivity
Accessing diagnostic information in the extended events log
Application code samples
Connecting and retrieving data
Connection URL sample
Data source sample
Working with data types (JDBC)
Basic data types sample
SQLXML data type sample
Spatial data types sample
Working with result sets
Retrieving result set data sample
Modifying result set data sample
Caching result set data sample
Working with large data
Reading large data sample
Reading large data with stored procedures sample
Updating large data sample
Data discovery and classification sample
Compliance and legal
JDBC 4.1 compliance
JDBC 4.2 compliance
JDBC 4.3 compliance
Programming guide
Connecting to SQL
Understanding JDBC data types
Using statements
Managing result sets
Performing transactions
Handling metadata
Using Always Encrypted
Using Always Encrypted with secure enclaves
Guide articles
Connections
Setting the data source properties
Setting the connection properties
Working with a connection
Connect to an Azure SQL database
Connection resiliency
Building the Connection URL
Using connection pooling
Authentication
Using Kerberos integrated authentication
Using Azure Active Directory authentication
Using NTLM authentication
Client certificate authentication for loopback
Data types
Using basic data types
Understanding data type differences
Understanding data type conversions
Using advanced data types
Using SQL_variant data type
Using spatial data types
User defined types
Configuring how java.sql.Time values are sent
Programming with SQLXML
Supporting XML data
SQLXML interface
Using statements with SQL
Using an SQL statement with no parameters
Using an SQL statement with parameters
Using an SQL statement to modify database objects
Using an SQL statement to modify data
Statements with stored procedures
Using statements with stored procedures
Using a stored procedure with no parameters
Using a stored procedure with input parameters
Using a stored procedure with output parameters
Using a stored procedure with a return status
Using a stored procedure with an update count
Using table-valued parameters
Handling complex statements
Using multiple result sets
Using parameter metadata
Using result set metadata
Transactions
Understanding transactions
Understanding XA transactions
Using holdability
Using savepoints
Understanding row locking
Understanding concurrency control
International features
National character set support
Using database metadata
Always Encrypted API reference
Support for high availability, disaster recovery
Using auto generated keys
Using database mirroring
Understanding cursor types
Understanding isolation levels
Wrappers and interfaces
Using bulk copy
Using bulk copy API for batch insert operation
Performing batch operations
Using SQL escape sequences
Azure Key Vault samples
Azure Key Vault sample (version 9.2)
Azure Key Vault sample (version 7.0, 8.0)
Azure Key Vault sample (version 6.2.2)
Azure Key Vault sample (version 6.0.0)
Node.js
Node.js Driver for SQL Server
Step 1: Configure development environment
Step 2: Create a SQL database
Step 3: Proof of concept connecting to SQL
ODBC
Microsoft ODBC Driver for SQL Server
Download
Linux and macOS
System requirements
Install the Driver Manager
Install the ODBC Driver (Linux)
Install the ODBC Driver (macOS)
Feature guides
Connecting from Linux or macOS
Data Access Tracing on Linux and macOS
High Availability and Disaster Recovery
Programming Guidelines
Tools
Connecting with bcp
Connecting with sqlcmd
Using Integrated Authentication
Release notes
Release notes (mssql-tools)
Known issues
Frequently asked questions (FAQ)
Windows
Microsoft ODBC Driver for SQL Server on Windows
Features
Release notes
System requirements, installation, and driver files
Feature guides
Driver-aware connection pooling
Asynchronous execution (notification method) sample
Help topics
Data Source Wizard screen 1
Data Source Wizard screen 2
Data Source Wizard screen 3
Data Source Wizard screen 4
SQL Server Login dialog
Feature guides
Connection resiliency
Custom Keystore Providers
DSN and Connection String Keywords and Attributes
Using Always Encrypted
Using Azure Active Directory
Using Transparent Network IP Resolution
Data Classification
Using XA Transactions
Bug Fixes
C / C++ sample application
ODBC advanced
Microsoft Open Database Connectivity (ODBC)
ODBC Programmer's Reference
What's New in ODBC 3.8
Sample ODBC Program
Introduction to ODBC
ODBC Overview
Introduction to SQL and ODBC
ODBC Architecture
ODBC 64-Bit Information
Developing Applications
ODBC Fundamentals
Basic ODBC Application Steps
Connecting to a Data Source or Driver
Catalog Functions
SQL Statements
Executing Statements ODBC
Retrieving Results (Basic)
Retrieving Results (Advanced)
Updating Data Overview
Descriptors
Transactions ODBC
Diagnostics
Interoperability
Programming Considerations
Installing and Configuring the ODBC Software
Installing ODBC Components
Configuring Data Sources
Installation and Configuration Components Reference
ODBC Header Files
Registry Entries for ODBC Components
Registry Entries for Data Sources
Developing an ODBC Driver
ODBC Driver Architecture
Upgrading a 3.5 Driver to a 3.8 Driver
Developing Connection-Pool Awareness in an ODBC Driver
Notification of Asynchronous Function Completion
API Reference
Function Summary
ODBC API Reference
Setup DLL API Reference
Installer DLL API Reference Function
Translation DLL API Reference
ODBC Service Provider Interface (SPI) Reference
ODBC Appendixes
Appendix A: ODBC Error Codes
Appendix B: ODBC State Transition Tables
Appendix C: SQL Grammar
Appendix D: Data Types
Appendix E: Scalar Functions
Appendix F: ODBC Cursor Library
Appendix G: Driver Guidelines for Backward Compatibility
ODBC Data Source Administrator
About Drivers and Data Sources
Managing Data Sources
Setting Tracing Options
Setting ODBC Connection Pooling Options
Viewing Drivers
Microsoft-Supplied ODBC Drivers
Using 16-Bit and 32-Bit Applications with 32-Bit Drivers
Using 16-Bit Applications with 32-Bit Drivers
Using 32-Bit Applications with 32-Bit Drivers
Microsoft ODBC Desktop Database Drivers
Desktop Database Drivers Architecture
History of the Desktop Database Drivers
Product Support
Implementing Desktop Database Drivers
Microsoft Access Driver Programming Considerations
Microsoft Excel Driver Programming Considerations
Paradox Driver Programming Considerations
dBASE Driver Programming Considerations
Text File Driver Programming Considerations
Additional Supported ODBC SQL Grammar
Limitations
ODBC Errors
Supported ODBC API Functions
ODBC Driver for Oracle
ODBC Driver for Oracle User's Guide
ODBC Driver for Oracle Programmer's Reference
Visual FoxPro ODBC Driver
Driver Architecture Overview
Visual FoxPro Terminology
Installing and Configuring
Using the Visual FoxPro ODBC Driver
Visual FoxPro ODBC Driver Programmer's Reference
ODBC Functions and the Visual FoxPro ODBC Driver
Visual FoxPro Language Reference
ODBC Glossary
ODBC Test
ODBCconf.exe
OLE DB
Microsoft OLE DB Driver for SQL Server
Download
Release notes
MSOLEDBSQL major version differences
System requirements
When to use OLE DB Driver
Finding more information
Features
Accessing Diagnostic Information in the Extended Events Log
Changing Passwords Programmatically
Date and Time Improvements
FILESTREAM Support
Large CLR User-Defined Types
Metadata Discovery
Performing Asynchronous Operations
Performing Bulk Copy Operations
Service Principal Name (SPN) Support in Client Connections
Sparse Columns Support in OLE DB Driver for SQL Server
OLE DB Driver for SQL Server Support for High Availability, Disaster Recovery
OLE DB Driver for SQL Server Support for LocalDB
Table-Valued Parameters (OLE DB Driver for SQL Server)
Using Azure Active Directory
Using Data Classification
Using Database Mirroring
Encryption and certificate validation
Idle Connection Resiliency
Using Large Value Types
Using Multiple Active Result Sets (MARS)
Using Transparent Network IP Resolution
Using User-Defined Types
Using XML Data Types
UTF-16 Support in OLE DB Driver for SQL Server
UTF-8 Support in OLE DB Driver for SQL Server
Working with Query Notifications
Working with Snapshot Isolation
Applications
Components of OLE DB Driver for SQL Server
Installing OLE DB Driver for SQL Server
Support policies for OLE DB Driver for SQL Server
Updating an application from SQL Server 2005 Native Client
Updating an application to OLE DB Driver for SQL Server from MDAC
Using ADO with OLE DB Driver for SQL Server
Using connection string keywords with OLE DB Driver for SQL Server
Using the OLE DB Driver for SQL Server header and library files
OLE DB programming
Specific Areas
Creating OLE DB Driver for SQL Server applications
About OLE DB Properties
Establishing a Connection to a Data Source
Executing a Command
Processing Results
Using the OUTPUT Clause with OLE DB in OLE DB Driver for SQL Server
OLE DB data source objects
Data Source Information Properties
Data Source Properties
Initialization and Authorization Properties
Persisted Data Source Objects
Session Properties - OLE DB Driver for SQL Server
Sessions
Commands
Command Parameters
Command Syntax
Commands Generating Multiple-Rowset Results
Preparing Commands
Using IMultipleResults to Process Multiple Result Sets
Rowsets
Bookmarks
Creating a Rowset with IOpenRowset
Creating Rowsets with ICommand::Execute
Fetching a Single Row with IRow
Fetching BLOB Data Using IRow::GetColumns and ISequentialStream
Fetching BLOB Data Using IRow::Open and ISequentialStream
Fetching Rows - Next Fetch Position
Fetching Rows
Rowset Properties and Behaviors
Rowsets and SQL Server Cursors
Updating Data in Rowsets - Resynchronizing Rows
Updating Data in Rowsets
Updating Data in SQL Server Cursors
Using IRow::GetColumns
Blobs
Getting Large Data
Setting Large Data
Streaming Support for BLOB Output Parameters
Tables and indexes
Adding a Column to a SQL Server Table
Creating SQL Server Indexes
Creating SQL Server Tables
Dropping a SQL Server Index
Dropping a SQL Server Table
Removing a Column from a SQL Server Table
Data types
Data Type Mapping in ITableDefinition
Data Type Mapping in Rowsets and Parameters
SSVARIANT Structure
Table-valued parameters
Executing Commands Containing Table-Valued Parameters
Inserting Data into Table-Valued Parameters
OLE DB Table-Valued Parameter Type Support (Methods)
OLE DB Table-Valued Parameter Type Support (Properties)
OLE DB Table-Valued Parameter Type Support
Schema Rowsets Changed for OLE DB Table-Valued Parameters
Table-Valued Parameter Rowset Creation
Table-Valued Parameter Type Discovery
Date and time improvements
Bulk Copy Changes for Enhanced Date and Time Types
Comparability for IRowsetFind
Conversions
Conversions Performed from Client to Server
Conversions Performed from Server to Client
Data Type Support for OLE DB Date and Time Improvements
Metadata - Date and Time and Schema Rowsets
Metadata - Parameter and Rowset
OLE DB API Support for Date and Time Enhancements
Transactions
Isolation Levels
Supporting Distributed Transactions
Supporting Local Transactions
Errors
Information in Error Interfaces
Retrieving Error Information
Return Codes
SQL Server Error Detail
SQL Server Message Results
Interfaces
IBCPSession
IBCPSession::BCPColFmt
IBCPSession::BCPColumns
IBCPSession::BCPControl
IBCPSession::BCPDone
IBCPSession::BCPExec
IBCPSession::BCPInit
IBCPSession::BCPReadFmt
IBCPSession::BCPWriteFmt
IBCPSession2
IBCPSession2::BCPSetBulkMode
IColumnsRowset
ICommand
ICommandWithParameters
IDBProperties
IRowsetFastLoad
IRowsetFastLoad::Commit
IRowsetFastLoad::InsertRow
ISQLServerErrorInfo::GetErrorInfo
ISSAbort::Abort
ISSAsynchStatus
ISSAsynchStatus::Abort
ISSAsynchStatus::GetStatus
ISSAsynchStatus::WaitForAsynchCompletion
ISSCommandWithParameters
ISSCommandWithParameters::GetParameterProperties
ISSCommandWithParameters::SetParameterProperties
ISSDataClassification
ISSDataClassification
ISSDataClassification::GetSensitivityClassification
How to
Results
Execute a User-Defined Function and Process Return Code
Execute Stored Procedure with ODBC CALL and Process Output
Execute Stored Procedure with RPC and Process Output
Fetch Rows from a Result Set
Filestream
Read a FILESTREAM Column to File Using IBCPSession
Retrieve Data from a FILESTREAM Column Using ISequentialStream
Send Data to a FILESTREAM Column Using IRowsetFastUpload
Send Data to FILESTREAM - ISequentialStream Bound to ICommandText
Bulk Copy Data Using IRowsetFastLoad
Change a SQL Server Authentication User Password
Display Column and Catalog Metadata for Sparse Columns
Enumerate OLE DB Data Sources
Fetch Columns Using IRow::GetColumns
Fetch Columns Using IRow::GetColumns (or IRow::Open) and ISequentialStream
Integrated Kerberos Authentication
Obtain a FAST_FORWARD Cursor
Retrieve Rows Using Bookmarks
Send BLOB Data to SQL SERVER Using IROWSETFASTLOAD and
ISEQUENTIALSTREAM
Set Large Data
Use Enhanced Date and Time Features
Use Large CLR UDTs
Use Table-Valued Parameters
Large CLR User-Defined Types
Schema Rowset Support
Schema Rowsets - Distributed Query Support
Schema Rowsets - LINKEDSERVERS Rowset
Service Principal Names (SPNs) in Client Connections
Sparse Columns Support
Stored Procedures - Calling
Stored Procedures - Running
Stored Procedures
Help topics
SQL Server Login Dialog
Universal Data Link (UDL) configuration
PHP
Microsoft Drivers for PHP for SQL Server
Getting started
Step 1: Configure development environment
Step 2: Create a SQL database
Step 3: Proof of concept connecting to SQL
Step 4: Connect resiliently to SQL
Overview
Download
Installation on Linux and macOS
Release notes
System requirements
Support matrix
Loading the drivers
Configuring IIS
Support resources
About code samples
Programming guide
Connecting to the Server
How to: Connect Using Windows Authentication
How to: Connect Using SQL Server Authentication
How to: Connect Using Azure Active Directory Authentication
How to: Connect on a Specified Port
Connection Pooling
How to: Disable Multiple Active Result Sets (MARS)
Connection Options
Support for LocalDB
Support for High Availability, Disaster Recovery
Connecting to Microsoft Azure SQL Database
Connection Resiliency
Comparing Execution Functions
Direct Statement Execution and Prepared Statement Execution in the PDO_SQLSRV
Driver
Retrieving Data
Retrieving Data as a Stream Using the SQLSRV Driver
Data Types with Stream Support Using the SQLSRV Driver
How to: Retrieve Character Data as a Stream Using the SQLSRV Driver
How to: Retrieve Binary Data as a Stream Using the SQLSRV Driver
Using Directional Parameters
How to: Specify Parameter Direction Using the SQLSRV Driver
How to: Retrieve Output Parameters Using the SQLSRV Driver
How to: Retrieve Input and Output Parameters Using the SQLSRV Driver
Specifying a Cursor Type and Selecting Rows
Cursor Types (SQLSRV Driver)
Cursor Types (PDO_SQLSRV Driver)
How to: Retrieve Date and Time Types as Strings Using the SQLSRV Driver
How to: Retrieve Date and Time Types as PHP Datetime Objects Using the
PDO_SQLSRV Driver
Formatting Decimal Strings and Money Values (SQLSRV Driver)
Formatting Decimal Strings and Money Values (PDO_SQLSRV Driver)
Updating Data
How to: Perform Parameterized Queries
How to: Send Data as a Stream
How to: Perform Transactions
Converting Data Types
Default SQL Server Data Types
Default PHP Data Types
How to: Specify SQL Server Data Types When Using the SQLSRV Driver
How to: Specify PHP Data Types
How to: Send and Retrieve UTF-8 Data Using Built-In UTF-8 Support
How to: Send and Retrieve ASCII Data in Linux and macOS
Handling Errors and Warnings
How to: Configure Error and Warning Handling Using the SQLSRV Driver
How to: Handle Errors and Warnings Using the SQLSRV Driver
Logging Activity
Using Always Encrypted with the PHP Drivers for SQL Server
Always Encrypted with secure enclaves with the PHP Drivers for SQL Server
Use table-valued parameters (PHP)
Non-System Locale Settings
Constants (Microsoft Drivers for PHP for SQL Server)
SQLSRV Driver API Reference
sqlsrv_begin_transaction
sqlsrv_cancel
sqlsrv_client_info
sqlsrv_close
sqlsrv_commit
sqlsrv_configure
sqlsrv_connect
sqlsrv_errors
sqlsrv_execute
sqlsrv_fetch
sqlsrv_fetch_array
sqlsrv_fetch_object
sqlsrv_field_metadata
sqlsrv_free_stmt
sqlsrv_get_config
sqlsrv_get_field
sqlsrv_has_rows
sqlsrv_next_result
sqlsrv_num_fields
sqlsrv_num_rows
sqlsrv_prepare
sqlsrv_query
sqlsrv_rollback
sqlsrv_rows_affected
sqlsrv_send_stream_data
sqlsrv_server_info
PDO_SQLSRV Driver Reference
PDO Class
PDO::__construct
PDO::beginTransaction
PDO::commit
PDO::errorCode
PDO::errorInfo
PDO::exec
PDO::getAttribute
PDO::getAvailableDrivers
PDO::lastInsertId
PDO::prepare
PDO::query
PDO::quote
PDO::rollback
PDO::setAttribute
PDOStatement Class
PDOStatement::bindColumn
PDOStatement::bindParam
PDOStatement::bindValue
PDOStatement::closeCursor
PDOStatement::columnCount
PDOStatement::debugDumpParams
PDOStatement::errorCode
PDOStatement::errorInfo
PDOStatement::execute
PDOStatement::fetch
PDOStatement::fetchAll
PDOStatement::fetchColumn
PDOStatement::fetchObject
PDOStatement::getAttribute
PDOStatement::getColumnMeta
PDOStatement::nextRowset
PDOStatement::rowCount
PDOStatement::setAttribute
PDOStatement::setFetchMode
Security considerations
Code samples
Example application (PDO_SQLSRV)
Example application (SQLSRV)
Python
Python Driver for SQL Server
Python SQL Driver - pyodbc
Step 1: Configure development environment
Step 2: Create a SQL database
Step 3: Proof of concept connecting to SQL
Python SQL Driver - pymssql
Step 1: Configure development environment
Step 2: Create a SQL database
Step 3: Proof of concept connecting to SQL
Ruby
Ruby Driver for SQL Server
Step 1: Configure development environment
Step 2: Create a SQL database
Step 3: Proof of concept connecting to SQL
Spark
Connector for SQL Server
ADO
Microsoft ActiveX Data Objects (ADO)
ADO Programmer's Guide
ADO Fundamentals
ADO Objects and Collections
HelloData: A Simple ADO Application
Comments on HelloData
HelloData Code
OLE DB Providers (ADO)
Data Providers
Service Providers and Components
Errors (ADO)
Getting Data
Connecting to Data Sources
Using a Connection Object
Using a Recordset Object
Creating a Connection String
Specifying Connection Properties
Controlling Transactions (ADO)
Preparing and Executing Commands
Command Object Overview
Creating and Executing a Simple Command
Command Object Parameters
Calling a Stored Procedure with a Command
Calling a Stored Procedure as a Method on a Connection object
Named Commands
Passing Parameters to a Named Command
Receiving Results
Receiving Multiple Recordsets
Examining Data
Current Record and Size of Recordset
Boundaries of a Recordset
Navigating Through Data
Jumping to a Record
More Ways to Move in a Recordset
Using Bookmarks
Using Pages
Recordset Positioning
Sample Recordset for Examining Data
JScript Code Example to Return a Recordset
Understanding Recordset Structure
The Fields Collection
The Field Object
Working with Recordsets
Editing Data
Editing Existing Records
Adding Records
Adding Records Using AddNew
Adding Multiple Fields
Determining Edit Mode
Using AddNew in Immediate and Batch Modes
Determining What is Supported
Deleting Records Using the Delete Method
Alternatives: Using SQL Statements
Updating and Persisting Data
Updating Data
Immediate Mode
Batch Mode
Sending the Updates: UpdateBatch Method
Filtering for Updated Records
Dealing with Failed Updates
Detecting and Resolving Conflicts
Disconnecting and Reconnecting the Recordset
Updating JOINed Results: Unique Table
Transaction Processing
Persisting Data
More About Recordset Persistence
Persisting Filtered and Hierarchical Recordsets
Persisting Records in XML Format
XML Persistence Format
Namespaces
Schema Section
Data Section
Hierarchical Recordsets in XML
Recordset Dynamic Properties in XML
XSLT Transformations
Saving to the XML DOM Object
XML Security Considerations
XML Recordset Persistence Scenario
Error Handling
ADO Errors
ADO Error Reference
Provider Errors
Field-Related Error Information
Recordset-Related Error Information
Handling Errors In Other Languages
Handling Errors in VBScript
Handling Errors in Visual C++
Handling Errors in JScript
Anticipating Errors
Handling ADO Events
ADO Event Handler Summary
Types of Events
Event Parameters
How Event Handlers Work Together
ADO Event Instantiation by Language
ADO Event Instantiation: Visual Basic
ADO Event Instantiation: Visual C++
ADO Event Instantiation: VBScript
ADO Event Instantiation: JScript
ADO Event Instantiation: ADO and WFC
Understanding Cursors and Locks
What is a Cursor?
Types of Cursors (ADO)
Forward-Only Cursors
Static Cursors
Keyset Cursors
Dynamic Cursors
The Significance of Cursor Location
The Microsoft Cursor Service for OLE DB
What is a Lock?
Types of Locks
Using CacheSize
Cursor and Lock Characteristics
Data Shaping
Data Shaping Overview
Data Shaping Example
Visual Basic Example of Data Shaping
Reshaping
Grandchild Aggregates
Parameterized Commands with Intervening COMPUTE Commands
Persisting Hierarchical Recordsets
Required Providers for Data Shaping
Shape Commands in General
Aggregate Functions, the CALC Function, and the NEW Keyword
Issuing Commands to the Underlying Data Provider
Shape APPEND Clause
Operation of Non-Parameterized Commands
Operation of Parameterized Commands
Hybrid Commands
Intervening Shape COMPUTE Clauses
Shape COMPUTE Clause
Fabricating Hierarchical Recordsets
Accessing Rows in a Hierarchical Recordset
Formal Shape Grammar
Visual Basic for Applications functions
Records and Streams
Streams and Persistence
Command Streams
Retrieving Result Sets into Streams
Using ADO for Internet Publishing
The OLE DB Provider for Internet Publishing
Internet Publishing Scenario
Step 1: Set Up the Visual Basic Project
Step 2: Initialize the Main List Box
Step 3: Populate the Fields List Box
Step 4: Populate the Details Text Box
Absolute and Relative URLs
Records and Provider-Supplied Fields
ADO Extensions for Data Definition Language and Security (ADOX)
ADOX Fundamentals
Provider Support for ADOX (ADO)
ADO MD Fundamentals
Using ADO with ADO MD
Overview of Multidimensional Schemas and Data
Programming with ADO MD
Working with Multidimensional Data
ADO (Multidimensional) (ADO MD)
Remote Data Service (RDS)
RDS Fundamentals
Solutions for Remote Data Access
Basic RDS Programming Model
RDS Programming Model in Detail
RDS Programming Model with Objects
RDS Object Model Summary
RDS Scenario
System Requirements for the Address Book Application
Running the Address Book SQL Script
Running the Address Book Sample Application
Address Book Data-Binding Object
Address Book Command Buttons
Address Book Navigation Buttons
RDS Tutorial
Step 1: Specify a Server Program (RDS Tutorial)
Step 2: Invoke the Server Program (RDS Tutorial)
Step 3: Server Obtains a Recordset (RDS Tutorial)
Step 4: Server Returns the Recordset (RDS Tutorial)
Step 5: DataControl is Made Usable (RDS Tutorial)
Step 6: Changes are Sent to the Server (RDS Tutorial)
RDS Tutorial (VBScript)
RDS Usage and Security
Configuring RDS
Granting Guest Privileges to a Web Server Computer
Registering a Custom Business Object
Marking Business Objects as Safe for Scripting
Registering Business Objects on the Client for Use with DCOM
Setting DCOM Stream Marshaling Format
Enabling a DLL to Run on DCOM
Configuring Virtual Servers on IIS
Securing RDS Applications
Configuring DataFactory for Safe or Unrestricted Modes
Using Related Technologies with RDS
Using RDS with ODBC Connection Pooling
Running Business Objects in Component Services
DataFactory Customization
Understanding the Customization File
Customization File Connect Section
Customization File SQL Section
Customization File UserList Section
Customization File Logs Section
Required Client Settings
Writing Your Own Customized Handler
Troubleshooting RDS
Configuring RDS on Windows 2000
Internet Server Error: Access Denied
RDS Returns "Stream Not Read" Error
Deadlocks with Read Repeatable Isolation Level
Ensuring Sufficient TempDB Space
Minimizing Log File Space Usage
Appendix A: Providers
Microsoft Cursor Service for OLE DB
OLE DB Persistence Provider
OLE DB Provider for Active Directory Service
OLE DB Provider for Internet Publishing
OLE DB Provider for Jet
OLE DB Provider for Microsoft Indexing Service
OLE DB Provider for ODBC
OLE DB Provider for Oracle
OLE DB Provider for SQL Server
OLE DB Remoting Provider
OLE DB Simple Provider
Microsoft Data Shaping Service for OLE DB
Appendix B: ADO Errors
ADO Error Codes
DataControl Error Codes
Internet Explorer Error Codes
Internet Information Services Error Codes
Appendix C: Programming with ADO
ADO Java Class Wrappers
Using ADO with Microsoft Visual Basic
Using the Microsoft SDK for Java
Using ADO with Scripting Languages
VBScript ADO Programming
JScript ADO Programming
Using ADO with Microsoft Visual C++
Visual C++ ADO Programming
Visual C++ Extensions Example
Visual C++ Extensions for ADO
Visual C++ Extensions Header
Using Visual C++ Extensions
Appendix D: ADO Samples
Referencing the ADO Libraries In a Visual C++ Application
Referencing the ADO Libraries In a Visual Basic 6 Application
ADO Introduction
ADO Security Design Issues
ADO History
Referencing the ADO Libraries
Prerequisites for Using the ADO Documentation
ADO Technology Table
ADO Task Table
ADO Glossary
ADO Code Examples
Type Property (ADO Stream)
Prepared Property Example (VC++)
ObjectProxy (ADO - WFC Syntax)
Connection Object Properties, Methods, Events
RecordTypeEnum
MoveRecordOptionsEnum
Refresh Method Example (VB)
CompareBookmarks Method Example (VB)
SeekEnum
ADCPROP_ASYNCTHREADPRIORITY_ENUM
Connection Object (ADO)
Recordset Object (ADO)
Execute, Requery, Clear Example (VB)
Save Method
Begin, Commit, Rollback - TransComplete
EventStatusEnum
PersistFormatEnum
AddNew Method Example (JScript)
CancelUpdate Method (ADO)
Number Property (ADO)
Append Method (ADO)
Execute Method (ADO Command)
CommandStream Property (ADO)
Open and Close Methods Example (VC++)
IsolationLevel Property
ActiveConnection, CommandText, CommandTimeout (JScript)
Filter and RecordCount Properties Example (VB)
XactAttributeEnum
Size Property (ADO Parameter)
PositionEnum
Stream (Visual C++ Syntax Index with import)
PageSize Property (ADO)
Charset Property (ADO)
Prepared Property Example (VB)
Status Property Example (Recordset) (VB)
Item Property (ADO)
Source Property Example (VC++)
CacheSize Property Example (VC++)
Cancel Method (ADO)
FieldStatusEnum
Parameter Object
ADCPROP_AUTORECALC_ENUM
Stream (ADO for Visual C++ Syntax)
Save and Open Methods Example (VB)
AbsolutePage Property (ADO)
WillExecute Event (ADO)
ConnectionEvents (Visual C++ Syntax Index with import)
AddNew Method Example (VBScript)
CancelBatch Method (ADO)
Record Object (ADO)
Version Property (ADO)
ActiveConnection, CommandText, CommandTimeout (VB)
Record Object Properties, Methods, and Events
Position Property (ADO)
Count Property (ADO)
WillConnect Event (ADO)
Provider and DefaultDatabase Properties Example (VC++)
Requery Method
ADO Dynamic Properties
WillChangeRecordset and RecordsetChangeComplete Events (ADO)
Direction Property
BeginTrans, CommitTrans, and RollbackTrans Methods (ADO)
AddNew Method Example (VB)
ResyncEnum
Resync Method Example (VC++)
GetRows Method Example (JScript)
LockTypeEnum
Open Method (ADO Stream)
Unique Table, Unique Schema, Unique Catalog)
ADO Objects and Interfaces
CompareBookmarks Method (ADO)
ADO for Visual C++ Syntax Index for COM
Parameter (ADO - WFC Syntax)
Name Property (ADO)
StreamReadEnum
Command (ADO for Visual C++ Syntax)
Error Object Properties, Methods, and Events
Command (Visual C++ Syntax Index with import)
Update and CancelUpdate Methods Example (VC++)
WillChangeRecord and RecordChangeComplete Events (ADO)
Connection (ADO for Visual C++ Syntax)
Optimize Property Example (VC++)
put_OLEDBCommand Method
CommandType Property (ADO)
ADO Enumerated Constants
ConnectionString, ConnectionTimeout Example (VC++)
ParameterDirectionEnum
AppendChunk Method (ADO)
CommandTimeout Property (ADO)
OriginalValue and UnderlyingValue Example (VC++)
Prompt Property-Dynamic (ADO)
Record (ADO for Visual C++ Syntax)
AbsolutePosition and CursorLocation Example (VB)
DeleteRecord and MoveRecord Example (VB)
AppendChunk and GetChunk Example (VB)
AbsolutePosition and CursorLocation Example (JScript)
ActualSize and DefinedSize Example (VB)
ConnectOptionEnum
ADO API Reference
ReadText Method
FieldEnum
ActiveCommand Property Example (JScript)
StreamWriteEnum
BOF, EOF, and Bookmark Example (VC++)
Recordset (ADO - WFC Syntax)
UpdateBatch and CancelBatch Methods Example (VC++)
ADCPROP_UPDATERESYNC_ENUM
CompareEnum
Find Method Example (VB)
Record (Visual C++ Syntax Index with import)
CopyRecord Method (ADO)
NativeError Property (ADO)
Filter and RecordCount Example (VC++)
RecordsetEvents (Visual C++ Syntax Index with import)
StayInSync Property Example (VB)
BOF, EOF, and Bookmark Properties Example (VB)
CursorType Property (ADO)
PageCount Property (ADO)
ADO Collections
Append and CreateParameter Example (VC++)
CopyTo Method (ADO)
Item Property Example (VB)
GetChildren Method (ADO)
CursorType, LockType,Edit Mode Example (VC++)
Property Object (ADO)
FilterGroupEnum
LoadFromFile Method (ADO)
NextRecordset Method Example (VB)
Field Object
Recordset (ADO for Visual C++ Syntax)
MaxRecords Property Example (VC++)
ADO Code Examples in Visual C++
MarshalOptions Property Example (VB)
GetRowsOptionEnum
Find Method Example (JScript)
Execute, Requery, and Clear Example (VC++)
IDSOShapeExtensions Interface
Clone Method (ADO)
Type Property Example (Field) (VB)
Attributes Property (ADO)
CursorLocationEnum
Resync Method Example (VB)
Open Method (ADO Record)
NextRecordset Method (ADO)
BeginTrans, CommitTrans, and RollbackTrans Example (VB)
AddNew Method (ADO)
MoveFirst, MoveLast, MoveNext, MovePrevious Methods (ADO)
Type Property Example (Property) (VC++)
Optimize Property-Dynamic (ADO)
Size Property (ADO Stream)
MarshalOptions Property Example (VC++)
ADO Methods
FetchComplete Event (ADO)
CacheSize Property Example (VB)
Error (ADO - WFC Syntax)
EditMode Property
Error Object
ADO - WFC Syntax Index
Source Property (ADO Recordset)
Command Object (ADO)
GetRows Method Example (VB)
State Property Example (VB)
RowPosition Property (ADO)
AddNew Method Example (VC++)
NumericScale and Precision Example (VB)
Stream Object Properties, Methods, Events
Stat Method
LockType Property (ADO)
PropertyAttributesEnum
CreateParameter Method (ADO)
DataSpace (ADO - WFC Syntax)
ErrorValueEnum
Flush Method (ADO)
ADOStreamConstruction Interface
IsolationLevel and Mode Example (VC++)
GetString Method (ADO)
MoveFirst, MoveLast, MoveNext Example (VBScript)
Field (Visual C++ Syntax Index with import)
RecordOpenOptionsEnum
IsolationLevelEnum
Connection (ADO - WFC Syntax)
Status Property (ADO Field)
Fields Collection Properties, Methods, Events
NextRecordset Method Example (VC++)
Chapter Property (ADO)
SaveToFile Method
Type Property (ADO)
Update Resync Property-Dynamic (ADO)
ConnectionTimeout Property (ADO)
StreamOpenOptionsEnum
OpenSchema Method
Read Method
RecordCount Property (ADO)
ActiveCommand Property Example (VC++)
SearchDirectionEnum
ADO Dynamic Property Index
Property (Visual C++ Syntax Index with import)
Mode Property (ADO)
Filter Property
MoveFirst, MoveLast, MoveNext, MovePrevious Example (VC++)
ParameterAttributesEnum
Cancel Method Example (VC++)
Field (ADO - WFC Syntax)
EventReasonEnum
Rowset Property (ADO)
Delete Method Example (VC++)
Source Property Example (VB)
Fields Collection (ADO)
Clone Method Example (VC++)
WriteText Method
AbsolutePosition Property (ADO)
RecordType Property (ADO)
ADO Code Examples VBScript
Delete Method Example (VBScript)
EOS and LineSeparator Properties Example (VB)
Parameter (ADO for Visual C++ Syntax)
Resync Method
ActualSize Property (ADO)
Version Property Example (VB)
SetEOS Method
OpenSchema Method Example (VC++)
FieldAttributeEnum
OriginalValue Property (ADO)
Supports Method Example (VC++)
RecordCreateOptionsEnum
MoveRecord Method (ADO)
Parameter (Visual C++ Syntax Index with import)
Update Method
Collections (ADO for Visual C++ Syntax)
Read, ReadText, Write, WriteText Methods Example (VB)
Reshape Name Property-Dynamic (ADO)
ExecuteOptionEnum
Filter and RecordCount Example (JScript)
Provider and DefaultDatabase Example (VB)
Open and Close Methods Example (VBScript)
Open Method (ADO Connection)
Optimize Property Example (VB)
ParentURL Property (ADO)
Clone Method Example (VB)
Parameters Collection Properties, Events
MaxRecords Property Example (VB)
ExecuteComplete Event (ADO)
CopyRecord, CopyTo, and SaveToFile Example (VB)
Errors Collection Properties, Methods, aEvents
ParentRow Property (ADO)
Description, HelpContext, HelpFile, NativeError Example (VB)
Cancel Method Example (VB)
AbsolutePage, PageCount, PageSize Example (VB)
GetDataProviderDSO Method
Find Method Example (VC++)
SaveOptionsEnum
ADO for Visual C++ Syntax Index with import
Sort Property Example (VC++)
EOS Property
Seek Method and Index Property Example (VC++)
ConnectComplete and Disconnect Events (ADO)
Move Method Example (VB)
NumericScale and Precision Properties Example (VC++)
BookmarkEnum
Find Method (ADO)
Update and CancelUpdate Methods Example (VB)
Count Property Example (VC++)
Parameter Object Properties, Methods
Description, HelpContext, HelpFile Example (VC++)
ActiveConnection Property (ADO)
ADORecordConstruction Interface
AppendChunk and GetChunk Methods Example (VC++)
Execute, Requery, and Clear Example (JScript)
RecordStatusEnum
StayInSync Property
Resync Command Property-Dynamic (ADO)
CursorOptionEnum
ConnectionString, ConnectionTimeout Example (VB)
CommandText Property (ADO)
GetString Method Example (VC++)
Description Property
CommandTypeEnum
ADO Object Model
BeginTrans, CommitTrans, and RollbackTrans (VC++)
Stream Property
CacheSize Property (ADO)
Parameters Collection (ADO)
AbsolutePosition and CursorLocation Example (VC++)
Value Property (ADO)
Bookmark Property (ADO)
EndOfRecordset Event (ADO)
Append and CreateParameter Methods Example (VB)
InfoMessage Event (ADO)
EditModeEnum
OpenSchema Method Example (VB)
Type Property Example (Field) (VC++)
Recordset Object Properties, Methods, Events
NamedParameters Property (ADO)
DefaultDatabase Property
Status Property (ADO Recordset)
UpdateBatch and CancelBatch Example (VB)
Source Property (ADO Error)
MarshalOptionsEnum
DefinedSize Property
WillChangeField and FieldChangeComplete Events (ADO)
Refresh Method Example (VC++)
Close Method (ADO)
ConnectionString Property (ADO)
Execute, Requery, and Clear Example (VBScript)
StayInSync Property Example (VC++)
Command (ADO - WFC Syntax)
CursorLocation Property (ADO)
MarshalOptions Property (ADO)
AbsolutePage, PageCount, PageSize Example (VC++)
ConnectModeEnum
Append and CreateParameter Example (JScript)
Collections (Visual C++ Syntax Indeximport)
BOF, EOF Properties (ADO)
Clone Method Example (VBScript)
Sort Property
CacheSize Property Example (JScript)
Count Property Example (VB)
ADCPROP_UPDATECRITERIA_ENUM
IsolationLevel and Mode PExample (VB)
Seek Method and Index Example (VB)
Save and Open Example (VC++)
Dialect Property
ObjectStateEnum
Open Method (ADO Recordset)
MoveFirst, MoveLast, MoveNext Example (VB)
ConvertToString Method Example (VB)
FetchProgress Event (ADO)
DataSource Property (ADO)
CopyRecordOptionsEnum
Type Property Example (Property) (VB)
CreateRecordset Method Example (VB)
Attributes and Name Example (VC++)
AbsolutePage, PageCount, PageSize Example (JScript)
Value Property Example (VB)
CursorType, LockType, EditMode Example (VB)
DataMember Property
DataTypeEnum
Source Property (ADO Record)
HelpContext, HelpFile Properties
Value Property Example (VC++)
Move Method Example (VBScript)
NumericScale Property (ADO)
Supports Method
ADO Events Model Example (VC++)
Errors Collection (ADO)
StringFormatEnum
DeleteRecord Method (ADO)
Delete Method (ADO Fields Collection)
Attributes and Name Properties Example (VB)
CompareBookmarks Method Example (VC++)
Version Property Example (VC++)
UpdateBatch Method
get_OLEDBCommand Method
ActiveCommand Property Example (VB)
ActualSize and DefinedSize Properties Example (JScript)
ADO Code Examples in Microsoft JScript
StreamTypeEnum
Property Object Properties, Methods
SchemaEnum
ConnectPromptEnum
Row Property (ADO)
MaxRecords Property (ADO)
Precision Property (ADO)
Error (Visual C++ Syntax Index with import)
Delete Method (ADO Recordset)
Field Object Properties, Methods Events
Properties Collection (ADO)
Index Property
Error (ADO for Visual C++ Syntax)
State Property Example (VC++)
AffectEnum
WillMove and MoveComplete Events (ADO)
Status Property Example (VC++)
OriginalValue and UnderlyingValue Example (VB)
Delete Method (ADO Parameters Collection)
GetString Method Example (VB)
GetRows Method (ADO)
Move Method (ADO)
Supports Method Example (VB)
Open and Close Methods Example (VB)
Seek Method
Prepared Property (ADO)
ADO Code Examples in Visual Basic
Provider Property (ADO)
Move Method Example (VC++)
ADO Events
ActiveConnection, CommandText Example (VC++)
Delete Method Example (VB)
State Property (ADO)
LineSeparator Property (ADO)
ADO Properties
SkipLine Method
Clear Method (ADO)
GetRows Method Example (VC++)
CursorTypeEnum
Recordset (Visual C++ Syntax Index with import)
Status Property Example (Field) (VB)
Sort Property Example (VB)
GetChunk Method (ADO)
ActiveCommand Property (ADO)
ADO Syntax Indexes
SQLState Property
Refresh Method (ADO)
ADORecordsetConstruction Interface
Collections (ADO - WFC Syntax)
ActualSize and DefinedSize Example (VC++)
Item Property Example (VC++)
Stream Object (ADO)
Field (ADO for Visual C++ Syntax)
LineSeparatorsEnum
Connection (Visual C++ Syntax Index with import)
Properties Collection Properties, Methods, Events
Execute Method (ADO Connection)
Command Object Properties, Methods, Events
Write Method
UnderlyingValue Property
ADO MD Object Model
ADO MD Objects
Catalog Object (ADO MD)
Catalog Object Properties, Methods, and Events (ADO MD)
Member Object (ADO MD)
Member Object Properties, Methods, and Events
Cellset Object (ADO MD)
Cellset Object Properties, Methods, and Events
Axis Object (ADO MD)
Axis Object Properties, Methods, and Events
Dimension Object (ADO MD)
Dimension Object Properties, Methods, and Events
Level Object (ADO MD)
Level Object Properties, Methods, and Events
Cell Object (ADO MD)
Cell Object Properties, Methods, and Events
Position Object (ADO MD)
Position Object Properties, Methods, and Events
CubeDef Object (ADO MD)
CubeDef Object Properties, Methods, and Events
Hierarchy Object (ADO MD)
Hierarchy Object Properties, Methods, and Events
ADO MD Collections
Axes Collection (ADO MD)
Axes Collection Properties, Methods, and Events
CubeDefs Collection (ADO MD)
CubeDefs Collection Properties, Methods, and Events
Dimensions Collection (ADO MD)
Dimensions Collection Properties, Methods, and Events
Hierarchies Collection (ADO MD)
Hierarchies Collection Properties, Methods, and Events
Levels Collection (ADO MD)
Levels Collection Properties, Methods, and Events
Members Collection (ADO MD)
Members Collection Properties, Methods, and Events
Positions Collection (ADO MD)
Positions Collection Properties, Methods, and Events
ADO MD Properties
ActiveConnection Property (ADO MD)
Caption Property (ADO MD)
ChildCount Property (ADO MD)
Children Property (ADO MD)
Depth Property (ADO MD)
Description Property (ADO MD)
DimensionCount Property (ADO MD)
DrilledDown Property (ADO MD)
FilterAxis Property (ADO MD)
FormattedValue Property (ADO MD)
Item Property (ADO MD Cellset)
LevelDepth Property (ADO MD)
LevelName Property (ADO MD)
Name Property (ADO MD)
Ordinal Property (ADO MD Cell)
Ordinal Property (ADO MD Position)
Parent Property (ADO MD)
ParentSameAsPrev Property (ADO MD)
Source Property (ADO MD)
State Property (ADO MD)
Type Property (ADO MD)
UniqueName Property (ADO MD)
Value Property (ADO MD)
ADO MD Methods
Close Method (ADO MD)
GetSchemaObject Method (ADO MD)
Open Method (ADO MD)
ADO MD Enumerated Constants
MemberTypeEnum
SchemaObjectTypeEnum
ADO MD Code Examples
ADO MD Code Examples in Visual Basic
Cellset Example (VB)
Catalog Example (VB)
ADO MD Code Examples in Visual Basic, Scripting Edition
Axis Example (VBScript)
Members Example (VBScript)
CubeDef Example (VBScript)
ADOX Object Model
ADOX Objects
Catalog Object (ADOX)
Catalog Object Properties, Methods, and Events
Column Object (ADOX)
Column Object Properties, Methods, and Events
Group Object (ADOX)
Group Object Properties, Methods, and Events
Index Object (ADOX)
Index Object Properties, Methods, and Events
Key Object (ADOX)
Key Object Properties, Methods, and Events
Procedure Object (ADOX)
Procedure Object Properties, Methods, and Events
Property Object (ADOX)
ADOX Property Object Properties, Methods, and Events
Table Object (ADOX)
Table Object Properties, Methods, and Events
User Object (ADOX)
User Object Properties, Methods, and Events
View Object (ADOX)
View Object Properties, Methods, and Events
ADOX Collections
Columns Collection (ADOX)
Columns Collection Properties, Methods, and Events
Groups Collection (ADOX)
Groups Collection Properties, Methods, and Events
Indexes Collection (ADOX)
Indexes Collection Properties, Methods, and Events
Keys Collection (ADOX)
Keys Collection Properties, Methods, and Events
Procedures Collection (ADOX)
Procedures Collection Properties, Methods, and Events
Tables Collection (ADOX)
Tables Collection Properties, Methods, and Events
Users Collection (ADOX)
Users Collection Properties, Methods, and Events
Views Collection (ADOX)
Views Collection Properties, Methods, and Events
ADOX Properties
ActiveConnection Property (ADOX)
Attributes Property (ADOX)
Clustered Property (ADOX)
Command Property (ADOX)
DateCreated Property (ADOX)
DateModified Property (ADOX)
DefinedSize Property (ADOX)
DeleteRule Property (ADOX)
IndexNulls Property (ADOX)
Name Property (ADOX)
NumericScale Property (ADOX)
ParentCatalog Property (ADOX)
Precision Property (ADOX)
PrimaryKey Property (ADOX)
RelatedColumn Property (ADOX)
RelatedTable Property (ADOX)
SortOrder Property (ADOX)
Type Property (Column) (ADOX)
Type Property (Key) (ADOX)
Type Property (Table) (ADOX)
Unique Property (ADOX)
UpdateRule Property (ADOX)
ADOX Methods
Append Method (ADOX Columns)
Append Method (ADOX Groups)
Append Method (ADOX Indexes)
Append Method (ADOX Keys)
Append Method (ADOX Procedures)
Append Method (ADOX Tables)
Append Method (ADOX Users)
Append Method (ADOX Views)
ChangePassword Method (ADOX)
Create Method (ADOX)
Delete Method (ADOX Collections)
GetObjectOwner Method (ADOX)
GetPermissions Method (ADOX)
SetObjectOwner Method
SetPermissions Method (ADOX)
ADOX Enumerated Constants
AllowNullsEnum
ActionEnum
SortOrderEnum
RightsEnum
RuleEnum
KeyTypeEnum
InheritTypeEnum
ObjectTypeEnum
ColumnAttributesEnum
ADOX Code Examples
ADOX Code Examples in Microsoft Visual Basic
Attributes Property Example (VB)
Catalog ActiveConnection Property Example (VB)
Clustered Property Example (VB)
Columns and Tables Append Methods, Name Property Example (VB)
Command and CommandText Properties Example (VB)
Connection Close Method, Table Type Property Example (VB)
Create Method Example (VB)
DateCreated and DateModified Properties Example (VB)
DefinedSize Property Example (VB)
DeleteRule Property Example (VB)
GetObjectOwner and SetObjectOwner Methods Example (VB)
GetPermissions and SetPermissions Methods Example (VB)
Groups and Users Append, ChangePassword Methods Example (VB)
Indexes Append Method Example (VB)
IndexNulls Property Example (VB)
Keys Append Method, Key Type, RelatedColumn, RelatedTable and UpdateRule
Properties Example (VB)
ADOX Code Example: NumericScale and Precision Properties Example (VB)
Parameters Collection, Command Property Example (VB)
ParentCatalog Property Example (VB)
PrimaryKey and Unique Properties Example (VB)
Procedures Append Method Example (VB)
Procedures Delete Method Example (VB)
Procedures Refresh Method Example (VB)
SortOrder Property Example (VB)
Views and Fields Collections Example (VB)
Views Append Method Example (VB)
Views Collection, CommandText Property Example (VB)
Views Delete Method Example (VB)
Views Refresh Method Example (VB)
ADOX Code Examples in Microsoft Visual C++
Attributes Property Example (VC++)
Catalog ActiveConnection Property Example (VC++)
Clustered Property Example (VC++)
Columns and Tables Append Methods, Name Property Example (VC++)
Command and CommandText Properties Example (VC++)
Connection Close Method, Table Type Property Example (VC++)
Create Method Example (VC++)
DateCreated and DateModified Properties Example (VC++)
DefinedSize Property Example (VC++)
DeleteRule Property Example (VC++)
GetObjectOwner and SetObjectOwner Methods Example (VC++)
GetPermissions and SetPermissions Methods Example (VC++)
Groups and Users Append, ChangePassword Methods Example (VC++)
Indexes Append Method Example (VC++)
IndexNulls Property Example (VC++)
Keys Append Method, Key Type, RelatedColumn, RelatedTable and UpdateRule
Properties Example (VC++)
NumericScale and Precision Properties of the Column Object Example (VC++)
Parameters Collection, Command Property Example (VC++)
ParentCatalog Property Example (VC++)
PrimaryKey and Unique Properties Example (VC++)
Deprecated: RDS API Reference
RDS Objects
DataControl Object (RDS)
DataControl Object (RDS) Properties, Methods, and Events
DataFactory Object (RDSServer)
DataFactory Object (RDSServer) Properties, Methods, and Events
DataSpace Object (RDS)
DataSpace Object (RDS) Properties, Methods, and Events
IRDSService Interface (RDS)
RDS Properties
Connect Property (RDS)
ExecuteOptions Property (RDS)
FetchOptions Property (RDS)
FilterColumn Property (RDS)
FilterCriterion Property (RDS)
FilterValue Property (RDS)
Handler Property (RDS)
InternetTimeout Property (RDS)
ReadyState Property (RDS)
Recordset, SourceRecordset Properties (RDS)
Server Property (RDS)
SortColumn Property (RDS)
SortDirection Property (RDS)
SQL Property
URL Property (RDS)
RDS Methods
Cancel Method (RDS)
CancelUpdate Method (RDS)
ConvertToString Method (RDS)
CreateObject Method (RDS)
CreateRecordset Method (RDS)
Execute Method (RDS)
Execute21 Method (RDS)
InvokeService (RDS)
MoveFirst, MoveLast, MoveNext, and MovePrevious Methods (RDS)
Query Method (RDS)
Refresh Method (RDS)
Reset Method (RDS)
SubmitChanges Method (RDS)
Synchronize Method (RDS)
Synchronize21 Method (RDS)
RDS Events
onError Event (RDS)
onReadyStateChange Event (RDS)
RDS Code Examples
RDS Code Examples in Visual Basic
Handler Property Example (VB)
InternetTimeout Property Example (VB)
RDS Code Examples in VBScript
Cancel Method Example (VBScript)
CancelUpdate Method Example (VBScript)
Connect Property Example (VBScript)
ConvertToString Method Example (VBScript)
CreateRecordset Method Example (VBScript)
DataControl Object Example (VBScript)
DataSpace Object and CreateObject Method Example (VBScript)
DataFactory Object, Query Method, and CreateObject Method Example
(VBScript)
ExecuteOptions and FetchOptions Properties Example (VBScript)
Filter Column, Criterion, Value, SortColumn, and SortDirection Properties and
Reset Method Example (VBScript)
ReadyState Property Example (VBScript)
Recordset and SourceRecordset Properties Example (VBScript)
Refresh Method Example (VBScript)
Server Property Example (VBScript)
SQL Property Example (VBScript)
SubmitChanges Method Example (VBScript)
URL Property Example (VBScript)
RDS Code Examples in Visual C++
Handler Property Example (VC++)
InternetTimeout Property Example (VC++)
ADO Programmer's Reference
ADO Glossary
Homepage for client programming to Microsoft
SQL Server
4/27/2022 • 10 minutes to read • Edit Online

Welcome to our homepage about client programming to interact with Microsoft SQL Server, and with Azure
SQL Database in the cloud. This article provides the following information:
Lists and describes the available language and driver combinations.
Information is given for the operating systems of Linux (Ubuntu and others), macOS, and Windows.
Provides links to the detailed documentation for each combination.
Displays the areas and subareas of the hierarchical documentation for certain languages, where appropriate.
Azure SQL Database
In any given language, the code that connects to SQL Server is almost identical to the code for connecting to
Azure SQL Database.
For details about the connection strings for connecting to Azure SQL Database, see:
Use .NET Core (C#) to query an Azure SQL database.
Other Azure SQL Database articles that are nearby the preceding article in the table of contents, about other
languages. For instance, see Use PHP to query an Azure SQL database.
Build-an-app webpages
Our Build-an-app webpages present code examples, along with configuration information, in an alternative
format. For more information, see later in this article the section labeled Build-an-app website.

Languages and drivers for client programs


In the following table, each language image is a link to detail about using the language with SQL Server. Each
link jumps to a later section in this article.

ODBC for C++


Downloads and installs
The following article is devoted to the download and install various SQL connection drivers, for use by
programming languages:
SQL Server Drivers

C# using ADO.NET
The .NET managed languages, such as C# and Visual Basic, are the most common users of ADO.NET. ADO.NET is
a casual name for a subset of .NET Framework classes.
Code examples

EXA M P L E DESC RIP T IO N

Proof of concept connecting to SQL using ADO.NET A small code example focused on connecting and querying
SQL Server.

Connect resiliently to SQL with ADO.NET Retry logic in a code example, because connections can
occasionally experience moments of connectivity loss.

Retry logic applies well to connections maintained through


the internet into any cloud database, such as to Azure SQL
Database.

Azure SQL Database: Demonstration of how to use .NET Azure SQL Database example.
Core on Windows/Linux/macOS to create a C# program, to
connect and query

Build-an-app: C#, ADO.NET, Windows Configuration information, along with code examples.

Documentation

A REA DESC RIP T IO N

C# using ADO.NET Root of our documentation.

Namespace: System.Data A set of classes used for ADO.NET.


A REA DESC RIP T IO N

Namespace: Microsoft.Data.SqlClient The set of classes used for Microsoft .NET Data Provider for
SQL Server

Entity Framework (EF) with C#


Entity Framework (EF) provides Object-Relational Mapping (ORM). ORM makes it easier for your Object-
Oriented Programming (OOP) source code to manipulate data that was retrieved from a relational SQL
database.
EF has direct or indirect relationships with the following technologies:
.NET Framework
LINQ to SQL, or LINQ to Entities
Language syntax enhancements, such as the => operator in C#.
Handy programs that generate source code for classes, which map to the tables in your SQL database. For
instance, EdmGen.exe.
Original EF, and new EF
The start page for Entity Framework introduces EF with a description similar to this:
Entity Framework is an object-relational mapper (O/RM) that enables .NET developers to work with a
database using .NET objects. It eliminates the need for most of the data-access source code that developers
usually need to write.
Entity Framework is a name shared by two separate source code branches. One EF branch is older, and its source
code can now be maintained by the public. The other EF is new. The two EFs are described next:

VERSIO N DESC RIP T IO N

EF 6.x Microsoft first released EF in August 2008. In March 2015,


Microsoft announced that EF 6.x was the final version that
Microsoft would develop. Microsoft released the source code
into the public domain.

Initially EF was part of .NET Framework. But EF 6.x was


removed from .NET Framework.

EF 6.x source code on GitHub, in repository


aspnet/EntityFramework6

EF Core Microsoft released the newly developed EF Core in June


2016. EF Core is designed for better flexibility and portability.
EF Core can run on operating systems beyond just Microsoft
Windows. And EF Core can interact with databases beyond
just Microsoft SQL Server and other relational databases.

C# code examples:
Getting Started with Entity Framework Core
Getting started with EF Core on .NET Framework with an
Existing Database
VERSIO N DESC RIP T IO N

EF and related technologies are powerful, and are a lot to learn for the developer who wants to master the entire
area.

Java and JDBC


Microsoft provides a Java Database Connectivity (JDBC) driver for use with SQL Server (or with Azure SQL
Database). It is a Type 4 JDBC driver, and it provides database connectivity through the standard JDBC
application program interfaces (APIs).
Code examples

EXA M P L E DESC RIP T IO N

Code examples Code examples that teach about data types, result sets, and
large data.

Connection URL Sample Describes how to use a connection URL to connect to SQL
Server. Then use it to use an SQL statement to retrieve data.

Data Source Sample Describes how to use a data source to connect to SQL
Server. Then use a stored procedure to retrieve data.

Use Java to query an Azure SQL database Azure SQL Database example.

Create Java apps using SQL Server on Ubuntu Configuration information, along with code examples.

Documentation
The JDBC documentation includes the following major areas:

A REA DESC RIP T IO N

Java Database Connectivity (JDBC) Root of our JDBC documentation.

Reference Interfaces, classes, and members.

Programming Guide for JDBC SQL Driver Configuration information, along with code examples.
Node.js
With Node.js you can connect to SQL Server from Windows, Linux, or macOS. The root of our Node.js
documentation is here.
The Node.js connection driver for SQL Server is implemented in JavaScript. The driver uses the TDS protocol,
which is supported by all modern versions of SQL Server. The driver is an open-source project, available on
GitHub.
Code examples

EXA M P L E DESC RIP T IO N

Proof of concept connecting to SQL using Node.js Bare bones source code for connecting to SQL Server, and
executing a query.

Azure SQL database: Use Node.js to query Example for Azure SQL Database in the cloud.

Create Node.js apps to use SQL Server on macOS Configuration information, along with code examples.

ODBC for C++

Open database connectivity (ODBC) was developed in the 1990s, and it predates .NET Framework. ODBC is
designed to be independent of any particular database system, and independent of operating system.
Over the years numerous ODBC drivers have been created and released by groups within and outside of
Microsoft. The range of drivers involve several client programming languages. The list of data targets goes well
beyond SQL Server.
Some other connectivity drivers use ODBC internally.
Code example
C++ code example, using ODBC
Documentation outline
The ODBC content in this section focuses on accessing either SQL Server or Azure SQL Database, from C++. The
following table lists an approximate outline of the major documentation for ODBC.
A REA SUB A REA DESC RIP T IO N

ODBC for C++ Root of our documentation.

Linux-macOS Information about using ODBC on the


Linux or macOS operating systems.

Windows Information about using ODBC on the


Windows operating system.

Administration The administrative tool for managing


ODBC data sources.

Microsoft Various ODBC drivers that are created


and provided by Microsoft.

Conceptual and reference Conceptual information about the


ODBC interface, in addition to
traditional reference.

" Appendixes State transition tables, ODBC cursor


library, and more.

" Develop app Functions, handles, and much more.

" Develop driver How to develop your own ODBC


driver, if you have a specialized data
source.

" Install ODBC installation, subkeys, and more.

" Syntax APIs for setup, installer, translation,


and data access.

PHP
You can use PHP to interact with SQL Server. The root of our PHP documentation is here.
Code examples

EXA M P L E DESC RIP T IO N

Proof of concept connecting to SQL using PHP A small code example focused on connecting and querying
SQL Server.

Connect resiliently to SQL with PHP Retry logic in a code example, because connections through
the Internet and the cloud can occasionally experience
moments of connectivity loss.

Azure SQL database: Use PHP to query Azure SQL Database example.
EXA M P L E DESC RIP T IO N

Create PHP apps to use SQL Server on RHEL Configuration information, along with code examples.

Python
You can use Python to interact with SQL Server.
Code examples

EXA M P L E DESC RIP T IO N

Proof of concept connecting to SQL with Python using A small code example focused on connecting and querying
pyodbc SQL Server.

Azure SQL database: Use Python to query Azure SQL Database example.

Create PHP apps to use SQL Server on SLES Configuration information, along with code examples.

Documentation

A REA DESC RIP T IO N

Python to SQL Server Root of our documentation.

pymssql driver Microsoft does not maintain or test the pymssql driver.

The pymssql connection driver is a simple interface to SQL


databases, for use in Python programs. Pymssql builds on
top of FreeTDS to provide a Python DB-API (PEP-249)
interface to Microsoft SQL Server.

pyodbc driver The pyodbc connection driver is an open-source Python


module that makes accessing ODBC databases simple. It
implements the DB API 2.0 specification, but is packed with
even more Pythonic convenience.

Ruby
You can use Ruby to interact with SQL Server. The root of our Ruby documentation is here.
Code examples
EXA M P L E DESC RIP T IO N

Proof of concept connecting to SQL with Ruby A small code example focused on connecting and querying
SQL Server.

Azure SQL database: Use Ruby to query Azure SQL Database example.

Create Ruby apps to use SQL Server on macOS Configuration information, along with code examples.

Build-an-app website, for SQL client development


On our Build-an-app webpages, you can choose from a long list of programming languages for connecting to
SQL Server. And your client program can run a variety of operating systems.
Build-an-app emphasizes simplicity and completeness for the developer who is just getting started. The steps
explain the following tasks:
1. How to install Microsoft SQL Server
2. How to download and install tools and drivers.
3. How to make any necessary configurations, as appropriate for your chosen operating system.
4. How to compile the provided source code.
5. How to run the program.
Next are a couple approximate outlines of the detail provided on the website:
Java on Ubuntu
1. Set up your environment
Step 1.1 Install SQL Server
Step 1.2 Install Java
Step 1.3 Install the Java Development Kit (JDK)
Step 1.4 Install Maven
2. Create Java application with SQL Server
Step 2.1 Create a Java app that connects to SQL Server and executes queries
Step 2.2 Create a Java app that connects to SQL Server using the popular framework Hibernate
3. Make your Java app up to 100x faster
Step 3.1 Create a Java app to demonstrate Columnstore indexes
Python on Windows
1. Set up your environment
Step 1.1 Install SQL Server
Step 1.2 Install Python
Step 1.3 Install the ODBC Driver and SQL Command Line Utility for SQL Server
2. Create Python application with SQL Server
Step 2.1 Install the Python driver for SQL Server
Step 2.2 Create a database for your application
Step 2.3 Create a Python app that connects to SQL Server and executes queries
3. Make your Python app up to 100x faster
Step 3.1 Create a new table with 5 million using sqlcmd
Step 3.2 Create a Python app that queries this table and measures the time taken
Step 3.3 Measure how long it takes to run the query
Step 3.4 Add a columnstore index to your table
Step 3.5 Measure how long it takes to run the query with a columnstore index
The following screenshots give you an idea of what our SQL development documentation website looks like.
Choose a language

Choose an operating system


Other development
This section provides links about other development options. These include using these same languages for
Azure development in general. The information goes beyond targeting just Azure SQL Database and Microsoft
SQL Server.
Developer hub for Azure
Developer hub for Azure
Azure for .NET developers
Azure for Java developers
Azure for Node.js developers
Azure for Python developers
Create a PHP web app in Azure
Other languages
Create Go apps using SQL Server on Windows
Connection modules for Microsoft SQL Database
4/27/2022 • 2 minutes to read • Edit Online

This article provides download links to connection modules or drivers that your client programs can use for
interacting with Microsoft SQL Server, and with its twin in the cloud Azure SQL Database. Drivers are available
for a variety of programming languages, running on the following operating systems:
Linux
macOS
Windows
OOP-to-relational mismatch:
Relational: Client programs that are written in an object-oriented programming (OOP) language often use SQL
drivers, which return queried data in a format that is more relational than object oriented. C# using ADO.NET is
one example. The OOP-relational format mismatch sometimes makes the OOP code harder to write and
understand.
ORM: Other drivers or frameworks return queried data in the OOP format, avoiding the mismatch. These drivers
work by expecting that classes have been defined to match the data columns of particular SQL tables. The driver
then performs the object-relational mapping (ORM) to return queried data as an instance of a class. Microsoft's
Entity Framework (EF) for C#, and Hibernate for Java, are two examples.
The present article devotes separate sections to these two kinds of connection drivers.

Drivers for relational access


L A N GUA GE DO W N LO A D T H E SQ L DRIVER

C# ADO.NET
Microsoft.Data.SqlClient

.NET Core for: Linux-Ubuntu, macOS, Windows

C++ ODBC

OLE DB

Java JDBC

Node.js Node.js driver, install instructions

PHP PHP

Python pyodbc, install instructions


Download ODBC

Ruby Ruby driver, install instructions


Ruby download page
Drivers for ORM access
The following table lists examples of Object Relational Mapping (ORM) frameworks that client applications use
to connect to Microsoft SQL Database.

L A N GUA GE O RM DRIVER DO W N LO A D

C# Entity Framework Core


Entity Framework (6.x or later)

Java Hibernate ORM

PHP Eloquent ORM, included in Laravel install

Node.js Sequelize ORM


Prisma

Python Django

Ruby Ruby on Rails

Build-an-app webpages
https://aka.ms/sqldev takes you to a set of Build-an-app webpages. The webpages provide information about
numerous combinations of programming language, operating system, and SQL connection driver. Among the
information provided by the Build-an-app webpages are the following items:
Details about how to get started from the very beginning, for each combination of language + operating
system + driver.
Instructions for installing the latest SQL connection drivers.
Code examples for each of the following items:
Object-relational code examples.
ORM code examples.
Columnstore index demonstrations for much faster performance.
First page, of Build-an-app webpages:
Menu for Java - Ubuntu, of Build-an-app webpages
Related links
Code examples for connecting to Azure SQL Database in the cloud, with Java and other languages.
Driver feature support matrix for Microsoft SQL
Server
4/27/2022 • 3 minutes to read • Edit Online

If you're planning to use a feature in Microsoft SQL Server, it might not be available in all drivers. Some reasons
a feature might not be in a particular driver include:
The feature doesn't apply to the driver technology.
The feature is new and hasn't been implemented across all drivers yet.
The feature isn't in demand in a particular driver.
Other features are being implemented first.
We wish all drivers supported every feature and spend effort to ensure feature parity across drivers. However
that isn't always possible. To help you choose the appropriate driver for your needs, here's a list of popular
features and the drivers that implement them.
.NET
ODBC
OLE DB
JDBC
PHP
Node.js / JavaScript
Python

M IC RO SO F T. DATA . M IC RO SO F T. DATA . SY ST EM . DATA . SY ST EM . DATA .


SQ L C L IEN T ( . N ET SQ L C L IEN T ( . N ET SQ L C L IEN T ( . N ET SQ L C L IEN T ( . N ET
F EAT URE C O RE) F RA M EW O RK ) C O RE) F RA M EW O RK )

Always Encrypted Yes Yes Yes (v4.6+)

Always Encrypted Yes (v1.1+) Yes (v1.1+) Yes (v4.7.2+)


with secure enclaves

Azure Active Yes Yes Yes (v4.6+) Yes (v4.6+)


Directory Access
Token authentication

Azure Active Yes Yes Yes (v4.6+)


Directory Password
authentication

Azure Active Yes Yes Yes (v4.6+)


Directory Integrated
authentication

Azure Active Yes Yes (v2.0+)


Directory Interactive
(MFA) authentication
M IC RO SO F T. DATA . M IC RO SO F T. DATA . SY ST EM . DATA . SY ST EM . DATA .
SQ L C L IEN T ( . N ET SQ L C L IEN T ( . N ET SQ L C L IEN T ( . N ET SQ L C L IEN T ( . N ET
F EAT URE C O RE) F RA M EW O RK ) C O RE) F RA M EW O RK )

Azure Active Yes (v2.1+) Yes (v2.1+)


Directory Managed
Identity
authentication

Azure Active Yes (v2.0+) Yes (v2.0+)


Directory Service
Principal
authentication

Windows-Integrated Yes Yes Yes Yes


authentication

Bulk Copy Yes Yes Yes Yes

Data Sensitivity and Yes Yes


Classification
metadata

Multiple Active Result Yes Yes Yes Yes


Sets (MARS)

Spatial Data Types Yes Yes

Table-Valued Yes Yes Yes Yes


Parameters (TVP)

MultiSubnetFailover Yes Yes Yes Yes

Transparent Network Yes Yes


IP Resolution

O DB C DRIVER F O R O DB C DRIVER F O R
SQ L SERVER O N SQ L SERVER O N JDB C DRIVER F O R O L E DB DRIVER F O R
F EAT URE W IN DO W S L IN UX A N D M A C O S SQ L SERVER SQ L SERVER

Always Encrypted Yes (v13.1+) Yes (v13.1+) Yes (v6.0+)

Always Encrypted Yes (v17.4+) Yes (v17.4+) Yes (v8.2+)


with secure enclaves

Azure Active Yes (v13.1+) Yes (v13.1+) Yes (v6.0+) Yes (v18.2+)
Directory Access
Token authentication

Azure Active Yes (v13.1+) Yes (v13.1+) Yes (v6.0+) Yes (v18.2+)
Directory Password
authentication
O DB C DRIVER F O R O DB C DRIVER F O R
SQ L SERVER O N SQ L SERVER O N JDB C DRIVER F O R O L E DB DRIVER F O R
F EAT URE W IN DO W S L IN UX A N D M A C O S SQ L SERVER SQ L SERVER

Azure Active Yes (v13.1+) Yes (v17.6+) Yes (v6.0+) Yes (v18.2+)
Directory Integrated
authentication

Azure Active Yes (v17.1+) Yes (v9.2+) Yes (v18.3+)


Directory Interactive
(MFA) authentication

Azure Active Yes (v17.3+) Yes (v17.3+) Yes (v7.2+) Yes (v18.3+)
Directory Managed
Identity
authentication

Azure Active Yes (v17.7+) Yes (v17.7+) Yes (v9.2+) Yes (v18.5+)
Directory Service
Principal
authentication

Windows-Integrated Yes Yes Yes Yes


authentication

Bulk Copy Yes Yes Yes Yes

Data Discovery and Yes (v17.2+) Yes (v17.2+) Yes (v7.0+) Yes (v18.5+)
Classification
metadata

Multiple Active Result Yes Yes Yes


Sets (MARS)

Spatial Data Types Yes (v7.0+)

Table-Valued Yes Yes Yes (v6.0+) Yes


Parameters (TVP)

MultiSubnetFailover Yes Yes Yes Yes

Transparent Network Yes (v13.0+) Yes (v13.1+) Yes (v6.0+) Yes (v18.4+)
IP Resolution

DRIVERS F O R P H P DRIVERS F O R P H P
F O R SQ L SERVER O N F O R SQ L SERVER O N
F EAT URE W IN DO W S 1 L IN UX A N D M A C O S 1 T EDIO US ( N O DE. JS) P Y O DB C ( P Y T H O N ) 1

Always Encrypted Yes (v5.2+) Yes (v5.2+) Yes

Always Encrypted Yes (v5.8+) Yes (v5.8+) Yes


with secure enclaves
DRIVERS F O R P H P DRIVERS F O R P H P
F O R SQ L SERVER O N F O R SQ L SERVER O N
F EAT URE W IN DO W S L IN UX A N D M A C O S T EDIO US ( N O DE. JS) P Y O DB C ( P Y T H O N )

Azure Active Yes (v4.3+) Yes (v4.3+) Yes Yes


Directory Access
Token authentication

Azure Active Yes (v4.3+) Yes (v4.3+) Yes Yes


Directory Password
authentication

Azure Active Yes (v4.3+) Yes (v4.3+) Yes


Directory Integrated
authentication

Azure Active Yes2


Directory Interactive
(MFA) authentication

Azure Active Yes (v5.6+) Yes (v5.6+) Yes Yes


Directory Managed
Identity
authentication

Azure Active Yes (v5.9+) Yes (v5.9+) Yes Yes


Directory Service
Principal
authentication

Windows-Integrated Yes Yes Yes


authentication

Bulk Copy Yes

Data Discovery and Yes (v5.8+) Yes (v5.8+)


Classification
metadata

Multiple Active Result Yes Yes Yes


Sets (MARS)

Spatial Data Types

Table-Valued Yes (v5.10+) Yes (v5.10+) Yes Yes


Parameters (TVP)

MultiSubnetFailover Yes Yes Yes

Transparent Network Yes Yes Yes


IP Resolution

1 Since these drivers rely on the Microsoft ODBC Driver for SQL Server, a version of that driver that supports the
feature must also be used.

2
2 Only on Windows.

Get help
Ideas for SQL: Have suggestions for improving SQL Server?
Microsoft Q & A (SQL Server)
DBA Stack Exchange (tag sql-server): Ask SQL Server questions
Stack Overflow (tag sql-server): Answers to SQL development questions
Reddit: General discussion about SQL Server
Microsoft SQL Server License Terms and Information
Support options for business users
Contact Microsoft
Additional SQL Server help and feedback

Contribute to SQL documentation


Did you know that you can edit SQL content yourself? If you do so, not only do you help improve our
documentation, but you also get credited as a contributor to the page.
For more information, see How to contribute to SQL Server documentation
Driver history for Microsoft SQL Server
4/27/2022 • 15 minutes to read • Edit Online

This page describes Microsoft's historical data connection technologies for connecting to SQL Server.

ODBC
There are three distinct generations of Microsoft ODBC drivers for SQL Server. The first "SQL Server" ODBC
driver still ships as part of Windows Data Access Components. This driver isn't recommended for new
development. Starting in SQL Server 2005, the SQL Server Native Client includes an ODBC interface and is the
ODBC driver that shipped with SQL Server 2005 through SQL Server 2012. This driver also isn't recommended
for new development. After SQL Server 2012, the Microsoft ODBC Driver for SQL Server is the driver that is
updated with the most recent server features going forward.
SQL Server Native Client
SQL Server Native Client is a stand-alone library that is used for both OLE DB and ODBC. SQL Server Native
Client (often abbreviated SNAC) was included in SQL Server 2005 through 2012. SQL Server Native Client can
be used for applications that need to take advantage of new features introduced in SQL Server 2005 through
SQL Server 2012. (Microsoft/Windows Data Access Components aren't updated for these new features in SQL
Server.) For new features beyond SQL Server 2012, SQL Server Native Client won't be updated. Switch to the
Microsoft ODBC Driver for SQL Server or the Microsoft OLE DB Driver for SQL Server if you want to take
advantage of new SQL Server features going forward.
For complete documentation of the SQL Server Native Client, see the SQL Server Native Client documentation.
Microsoft ODBC Driver for SQL Server
After SQL Server 2012, the primary ODBC driver for SQL Server has been developed and released as the
Microsoft ODBC Driver for SQL Server. For more information, see the Microsoft ODBC Driver for SQL Server
documentation.

OLE DB
There are three distinct generations of Microsoft OLE DB providers for SQL Server. The first "Microsoft OLE DB
Provider for SQL Server" (SQLOLEDB) still ships as part of Windows Data Access Components. This provider
won't be updated with new features and it isn't recommended to use this driver for new development. Starting
in SQL Server 2005, the SQL Server Native Client includes an OLE DB provider interface (SQLNCLI) and is the
OLE DB provider that shipped with SQL Server 2005 through SQL Server 2017. It was announced as deprecated
in 2011 and it isn't recommended to use this driver for new development. In 2017, OLE DB data access
technology was later undeprecated and a new planned release was announced for 2018. The new OLE DB
provider is called the "Microsoft OLE DB Driver for SQL Server" (MSOLEDBSQL) and is currently maintained and
supported.

ADO.NET
ADO.NET is a set of classes that defines an interface for accessing any kind of data source, both relational and
non-relational. ADO.NET was introduced with the Microsoft .NET Framework and continues to be improved and
maintained in .NET. The SqlClient library is an ADO.NET data provider that provides connectivity to SQL Server
and Azure SQL data sources.
System.Data.SqlClient
System.Data.SqlClient is included as part of .NET Framework and .NET Core. Up until 2019, it was receiving
regular feature updates. With the announcements of the future of .NET Core, .NET Framework, and .NET in
general, development of SqlClient needed to shift to a package outside of .NET. System.Data.SqlClient is still
supported but isn't receiving feature updates and isn't recommended for new development.
Microsoft.Data.SqlClient
Introduced in 2019, the Microsoft SqlClient Data Provider for SQL Server is an ADO.NET data provider
supporting applications that target .NET Framework, .NET Core, and .NET Standard. For more information about
the Microsoft.Data.SqlClient namespace, see Microsoft ADO.NET for SQL Server.

JDBC
Microsoft JDBC Driver for SQL Server
Introduced in 2000, the Microsoft JDBC Driver for SQL Server continues to be improved and maintained. It was
open-sourced in 2016. For the latest information, including how to download the driver, see Overview of the
JDBC Driver.

PHP
Microsoft Drivers for PHP for SQL Server
Introduced in 2009 as an open-source project, the Microsoft Drivers for PHP for SQL Server continue to be
improved and maintained. For the latest information, including how to download the PHP driver, see Microsoft
Drivers for PHP for SQL Server.

Node.js
Microsoft Driver for Node.js for SQL Server
The Microsoft Driver for Node.js for SQL Server allows Node.js applications on Microsoft Windows and
Microsoft Azure to access Microsoft SQL Server and Microsoft Azure SQL Database. Development efforts are no
longer being focused on this driver. It isn't recommended to create new applications using the Microsoft Driver
for Node.js for SQL Server.
For more information about the Microsoft Driver for Node.js for SQL Server, see WindowsAzure / node-
sqlserver.
Tedious
Microsoft currently contributes to and supports the open-source tedious module in Node.js for connectivity to
SQL Server using JavaScript. For more information, see Node.js Driver for SQL Server.

Microsoft or Windows Data Access Components


Microsoft/Windows Data Access Components (MDAC/WDAC) are shipped with and supported by Windows for
application backwards compatibility and aren't part of the current SQL Server technology stack. No new
features will be added to components in MDAC/WDAC and it isn't recommended to use them for new
application development.
For the purposes of this document, you can divide the MDAC/WDAC stack into the following components, based
on technology and products:
ADO (including ADOMD and ADOX)
OLE DB (including OLE DB Core Services, SQL Server OLE DB Provider, Oracle OLE DB Provider, OLE DB
Provider for ODBC Drivers, Data Shape Provider, and Remote Data Provider)
ODBC (including ODBC Driver Manager, SQL ODBC Driver, and Oracle ODBC Driver)
MDAC/WDAC components
MDAC/WDAC includes these components:
ODBC: The Microsoft Open Database Connectivity (ODBC) interface is a C programming-language interface
that allows applications to access data from different kinds of Database Management Systems (DBMS).
Applications that use this API are limited to accessing relational data sources only.
OLE DB: OLE DB is a set of COM interfaces for accessing data in different kinds of data stores. OLE DB
providers exist for accessing data in databases, file systems, message stores, directory services, workflow,
and document stores.
ADO: ActiveX Data Objects (ADO) provides a high-level programming model. Although a little less
performant than coding to OLE DB or ODBC directly, ADO is straightforward to learn and use. It can be used
from script languages, such as Microsoft Visual Basic Scripting Edition (VBScript) or Microsoft JScript.
ADOMD: ADO Multi-Dimensional (ADOMD) is to be used with multidimensional data providers such as
Microsoft OLAP Provider, also known as Microsoft Analysis Services Provider. No major feature
enhancements have been made to it since MDAC 2.0.
ADOX: ADO Extensions for DDL and Security (ADOX) enable the creation and modification of definitions of a
database, table, index, or stored procedure. You can use ADOX with any provider. The Microsoft Jet OLE DB
Provider provides full support for ADOX, while the Microsoft SQL Server OLE DB Provider provides limited
support.
Microsoft SQL Ser ver Network Libraries: The SQL Server Network Libraries allow SQLOLEDB and
SQLODBC to communicate with the SQL Server database. The following SQL Server Network Libraries have
been deprecated in MDAC/WDAC releases: Banyan Vines, AppleTalk, ServerNet, IPX/SPX, Giganet, and RPC.
TCP/IP and Named Pipes will continue to be supported and are available on the 64-bit Windows operating
system.
MSDASQL: The Microsoft OLE DB Provider for ODBC (MSDASQL) allows applications that are built on OLE
DB and ADO (which uses OLEDB internally) to access data sources through an ODBC driver. MSDASQL is an
OLEDB provider that connects to ODBC, instead of a database. It is meant as a bridge from OLE DB to an
ODBC driver when no direct OLE DB provider exists for a data source. MSDASQL ships with the Windows
operating system, and Windows Server 2008 and Vista SP1 were the first Windows releases to include a 64-
bit version of the technology.
Deprecated MDAC/WDAC Components
These components are still supported in the current release of MDAC/WDAC, but they might be removed in
future releases. When developing new applications, Microsoft recommends that you avoid using these
components. Additionally, when you upgrade or modify existing applications, remove any dependency on these
components.
SQLOLEDB: The Microsoft OLE DB Provider for SQL Server (SQLOLEDB), which supports access to
Microsoft SQL Server, has been deprecated. Its connectivity to future versions of SQL Server may not be
supported. The ability to connect to versions earlier than SQL Server 7 will be removed from the
operating system after Windows 7. New applications should use the Microsoft OLE DB Driver for SQL
Server (MSOLEDBSQL), which supports new SQL Server features. Existing applications should migrate to
the Microsoft OLE DB Driver for SQL Server as well for better performance, reliability, and supportability.
For more information, see Updating an Application to OLE DB Driver for SQL Server from MDAC.
SQLODBC: The Microsoft SQL Server ODBC Driver (SQLODBC), which supports access to Microsoft SQL
Server, has been deprecated. Its connectivity to future versions of SQL Server may not be supported. The
ability to connect to versions earlier than SQL Server 7 will be removed from the operating system after
Windows 7. New applications should use the Microsoft ODBC Driver for SQL Server on Windows, which
supports new SQL Server features. Existing applications should migrate to the Microsoft ODBC Driver for
SQL Server as well for better performance, reliability, and supportability. For relevant information, see
Updating an Application to SQL Server Native Client from MDAC.
Microsoft Jet Database Engine 4.0: Starting with version 2.6, MDAC no longer contains Jet
components. In other words, MDAC 2.6, 2.7, and 2.8 don't contain Microsoft Jet, the Microsoft Jet OLE DB
Provider, the ODBC Desktop Database Drivers, or Jet Data Access Objects (DAO).
There's no 64-bit version of the Jet Database Engine, the Jet OLEDB Driver, the Jet ODBC Drivers, or Jet
DAO available. For more information, see KB article 957570. On 64-bit versions of Windows, 32-bit Jet
runs under the Windows WOW64 subsystem. For more information on WOW64, see the MSDN WOW64
documentation. Native 64-bit applications cannot communicate with the 32-bit Jet drivers running in
WOW64.
Instead of Microsoft Jet, Microsoft recommends using Microsoft SQL Server Express Edition when
developing new, non-Microsoft Access applications requiring a relational data store. These new or
converted Jet applications can continue to use Jet with the intention of using Microsoft Office 2003 and
earlier files (.mdb and .xls) for non-primary data storage. However, for these applications, you should plan
to migrate from Jet to the Microsoft Access Database Engine. You can download the Microsoft Access
Database Engine, which allows you to read from and write to pre-existing files in either Office 2003 (.mdb
and .xls) or the Office 2007 (*.accdb, *.xlsm, *.xlsx and *.xlsb) file formats.

IMPORTANT
Please read the 2007 Office System End User License Agreement for specific usage limitations.

NOTE
SQL Server applications can also access the 2007 Office System, and earlier, files from SQL Server heterogeneous
data connectivity and Integrations Services capabilities as well, via the 2007 Office System Driver. Additionally, 64-
bit SQL Server applications can access to 32-bit Jet and 2007 Office System files by using 32-bit SQL Server
Integration Services (SSIS) on 64-bit Windows.

Microsoft OLE DB Provider for Data Shaping (MSDADS): With MSDADS, you can create
hierarchical relationships between keys, fields, or rowsets in an application. No major feature
enhancements have been made since MDAC 2.1. This Provider has been deprecated. Microsoft
recommends that you use XML, instead of MSDADS.
Oracle ODBC and Oracle OLE DB: The Microsoft Oracle ODBC Driver (Oracle ODBC) and Microsoft
OLE DB Provider for Oracle (Oracle OLE DB) provide access to Oracle database servers. They're built by
using Oracle Call Interface (OCI) version 7 and provide full support for Oracle 7. Also, it uses Oracle 7
emulation to provide limited support for Oracle 8 databases. Oracle no longer supports applications that
use OCI version 7 calls. These technologies are deprecated. If you're using Oracle data sources, you
should migrate to Oracle-supplied driver and provider.
Remote Data Ser vices (RDS): RDS is a proprietary Microsoft mechanism for accessing remote ADO
Recordset objects across the Internet or an Intranet. RDS is deprecated; no major feature enhancements
have been made to RDS since MDAC 2.1. Microsoft has released the .NET Framework, which has
extensive SOAP capabilities and replaces RDS components. All RDS server components will be removed
from the operating system after Windows 7.
Jet Replication Objects (JRO): JRO is deprecated. JRO is used within ADO with Jet (.mdb) databases to
create and compress Jet Databases (.mdb's) and perform Jet Replication Management. MDAC 2.7 will be
its last release. JRO won't be available on the 64-bit Windows operating system. JRO isn't supported in
the Microsoft Access 2007 file format (.accdb).
16-bit ODBC Suppor t: If you're using 16-bit applications, you should migrate to a 32-bit application.
16-bit functionality is deprecated and is being removed from 64-bit operating systems. For more
information, see Knowledge base article 896458.
OLEDB Simple Provider (MSDAOSP): OLEDB Simple Provider offers a framework for quickly building
OLE DB providers over simple data. MSDAOSP is deprecated.
ODBC Cursor Librar y: ODBC Cursor Library (ODBCCR32.dll) provides limited client-side data cursors.
ODBC Cursor Library has been deprecated; your application can use server-side cursor implementations
as a replacement.
OLE DB Out-of-Process Interface Remoting: OLEDB Interface remoting (msdaps.dll) was an attempt
to allow OLE DB providers to run out of process. OLEDB Out-of-Process Interface remoting is deprecated.
AppleTalk and Banyan Vines SQL Network Libraries: The Banyan Vines, AppleTalk, ServerNet,
IPX/SPX, Giganet, and RPC SQL network libraries are deprecated. If you're using any of these
technologies, you should modify your applications to use one of the other network libraries, such as
TCP/IP and Named Pipe.
MDAC/WDAC Releases
Here's a list of the supportability scenarios of past MDAC/WDAC releases, starting with the earliest.
MDAC 1.5, MDAC 2.0, and MDAC 2.1: These versions of MDAC were independent releases that were
released through the Microsoft Windows NT Option Pack, the Microsoft Windows Platform SDK, or the
MDAC Web site. These versions of MDAC are no longer supported.
MDAC 2.5: This version of MDAC was included with the Windows 2000 operating system. Service packs
of MDAC 2.5 were included with corresponding Windows 2000 service packs.
MDAC 2.6: MDAC 2.6 RTM, SP1, and SP2 were included with Microsoft SQL Server 2000 RTM, SP1, and
SP2, respectively. Additionally, these MDAC service packs were released to the MDAC Web site following
the Microsoft SQL Server 2000 service-pack release schedule. You can install this version of MDAC and
its service packs on Windows 2000, Windows Millennium Edition, Windows NT, Windows 95, and
Windows 98 platforms. This version of MDAC no longer is supported.
MDAC 2.7: This version of MDAC was included with the Microsoft Windows XP RTM and SP1 operating
systems. You can install this version of MDAC and its service packs on Windows 2000, Windows
Millennium, Windows NT, and Windows 98 platforms. You can install this version on the Windows XP
platform only through the operating system or its services packs. This version of MDAC no longer is
supported.
MDAC 2.8: This version of MDAC was included with Windows Server 2003 and Windows XP SP2 and
later. You also can install this version of MDAC and its service packs on Windows 2000.
The 32-bit version of MDAC 2.8 also was released to the MDAC Web site at the same time that
Windows Server 2003 was released to the customer.
The 64-bit version of MDAC 2.8 was released with the 64-bit version of Windows Server 2003 and
Windows XP.
Windows Data Access Components (WDAC): MDAC changed its name to WDAC - "Windows Data
Access Components" starting with Windows Vista and Windows Server 2008. WDAC is included as part
of the operating system and isn't available separately for redistribution. Serviceability for WDAC is
subject to the life cycle of the operating system.
32-bit and 64-bit versions of WDAC are released with the 32-bit and 64-bit versions of the Windows
operating systems, respectively.

Obsolete data access technologies


Obsolete technologies are technologies that have not been enhanced or updated in several product releases and
that will be excluded from future product releases. Don't use these technologies when you write new
applications. When you modify existing applications that are written by using these technologies, consider
migrating those applications to ADO.NET or another current technology.
The following components are considered obsolete:
DB-Librar y: DB-Library is a SQL Server-specific programming model that includes C APIs. There have been
no feature enhancements to the DB-Library since SQL Server 6.5. Its final release was with SQL Server 2000,
and it won't be ported to the 64-bit Windows operating system.
Embedded SQL (E-SQL): E-SQL is a SQL Server-specific programming model that enables Transact-SQL
statements to be embedded in Visual C code. No feature enhancements have been made to the E-SQL since
SQL Server 6.5. Its final release was with SQL Server 2000, and it won't be ported to the 64-bit Windows
operating system.
Data Access Objects (DAO): DAO provides access to JET (Access) databases. This API can be used from
Microsoft Visual Basic, Microsoft Visual C++, and scripting languages. It was included with Microsoft Office
2000 and Office XP. DAO 3.6 is the final version of this technology. It won't be available on the 64-bit
Windows operating system.
Remote Data Objects (RDO): RDO was designed specifically to access remote ODBC relational data
sources, and made it easier to use ODBC without complex application code. It was included with Microsoft
Visual Basic versions 4, 5, and 6. RDO version 2.0 was the final version of this technology.

Get help
Ideas for SQL: Have suggestions for improving SQL Server?
Microsoft Q & A (SQL Server)
DBA Stack Exchange (tag sql-server): Ask SQL Server questions
Stack Overflow (tag sql-server): Answers to SQL development questions
Reddit: General discussion about SQL Server
Microsoft SQL Server License Terms and Information
Support options for business users
Contact Microsoft
Additional SQL Server help and feedback

Contribute to SQL documentation


Did you know that you can edit SQL content yourself? If you do so, not only do you help improve our
documentation, but you also get credited as a contributor to the page.
For more information, see How to contribute to SQL Server documentation
SQL Data Developer
4/27/2022 • 2 minutes to read • Edit Online

Use Microsoft's SQL data platform to create data-centric solutions across mobile devices and desktops for web
servers, enterprise servers, and the cloud.

SQL Data storage


SQL Server Database Engine: Use the SQL Server Database Engine to create relational databases for online
transaction processing or online analytical processing data.
Azure SQL: Use Azure SQL to move your database to the cloud
SQL Compact: Use SQL Server Compact to build standalone and occasionally connected applications for
mobile devices, desktops, and Web clients.
LocalDB: Use LocalDB during development to write and test Transact-SQL code without having to manage a
full server instance of SQL Server.

SQL Data tools


Azure Data Studio: Use Azure Data Studio on Windows, macOS, and Linux to run SQL Server, Azure SQL
Database, PostgreSQL, Jupyter Notebooks and more.
SQL Server Data Tools: Use SSDT inside Visual Studio to build relational databases, Azure SQL databases,
Integration Services packages, Analysis Services data models, and Reporting Services reports.
SQL Server Management Tools: Use SSMS on Windows to configure, monitor, and administer instances of
SQL Server.

SQL Data access


SQL Client Drivers: Use SQL drivers to connect, query, update, insert, or delete data from a SQL database.
Entity Framework: Use the Entity Framework to easily access databases using LINQ, with direct access to SQL
Server and the option to control the mapping between an Entity Data Model (EDM) and raw relational
structures.
Windows Communication Foundation (WCF): Use Data Services for a near-turnkey solution to easily create
and consume OData services on both the web and intranet
Sync Framework: Use the Sync Framework to enable offline access to any data type, any data store, any
transfer protocol, and any network topology.
Reactive Extensions: Use the Reactive Extensions (Rx) to perform event stream programming and simplify
asynchronous programming using observable sequences and LINQ-style query operators. Use the Reactive
Extensions for JavaScript (RxJS) to simplify asynchronous callback-based and event-driven programming on
the web using observable sequences.
CLR Integration: Use CLR Integration to write stored procedures, triggers, user-defined types, user-defined
functions, user-defined aggregates, and streaming table-valued functions, using any .NET Framework
language, including Microsoft Visual Basic .NET and Microsoft Visual C#.
SQLXML 4.0: Use SQLXML 4.0 to export relational data to XML.

Data collection, processing, and visualization


Analysis Services
Integration Services
Master Data Services
Replication Services
Reporting Services
Service Broker
Microsoft ADO.NET for SQL Server
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
ADO.NET is the core data access technology for .NET languages. Use the Microsoft.Data.SqlClient namespace to
access SQL Server, or providers from other suppliers to access their stores. Use System.Data.Odbc or
System.Data.Oledb to access data from .NET languages using other data access technologies. Use
System.Data.Dataset when you need an offline data cache in client applications. It also provides local persistence
and XML capabilities that can be useful in web services.

Getting started
Step 1: Configure development environment for ADO.NET development
Step 2: Create a SQL database for ADO.NET development
Step 3: Proof of concept connecting to SQL using ADO.NET
Step 4: Connect resiliently to SQL with ADO.NET

Documentation
ADO.NET Overview
Getting started with the SqlClient driver
Overview of the SqlClient driver
Data type mappings in ADO.NET
Retrieving and modifying data in ADO.NET
SQL Server and ADO.NET

Community
ADO.NET Managed Providers Forum
ADO.NET DataSet Forum

More samples
ADO.NET Code Examples
Getting Started with .NET Framework on Windows
Getting Started with .NET Core on macOS
Getting Started with .NET Core on Ubuntu
Getting Started with .NET Core on Red Hat Enterprise Linux (RHEL)
Getting started with the SqlClient driver
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Step 1: Configure development environment for ADO.NET development
Step 2: Create a SQL database for ADO.NET development
Step 3: Proof of concept connecting to SQL using ADO.NET
Step 4: Connect resiliently to SQL with ADO.NET
Step 1: Configure development environment for
ADO.NET development
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Next article: Step 2: Create a SQL database for ADO.NET development

Download a .NET SQL driver


Our current code example uses ADO.NET of the .NET Framework, for Windows. The .NET Core is available for
Linux and macOS (in addition to Windows).
ADO.NET, for Windows
To download and install .NET Framework, including ADO.NET
Install Visual Studio Community, or a similar integrated development environment (IDE) for writing and
compiling C# source code. Microsoft now provides Visual Studio Community for free.
Download Visual Studio Community
More options for free Visual Studio
.NET Core, for Linux-Ubuntu and macOS
Links to download .NET Core, for a variety of operating systems, are available at:

To download and install .NET Core


Step 2: Create a SQL database for ADO.NET
development
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
The samples in this section only work with the AdventureWorks schema, on either Microsoft SQL Server or
Azure SQL Database.

Azure SQL Database


Create a SQL database in minutes using the Azure portal

Microsoft SQL Server


Microsoft SQL Server Samples on GitHub

Sequential articles
Previous: Step 1: Configure development environment for ADO.NET development
Next: Step 3: Proof of concept connecting to SQL using ADO.NET
Step 3: Proof of concept connecting to SQL using
ADO.NET
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Previous article: Step 2: Create a SQL database for ADO.NET development
Next article: Step 4: Connect resiliently to SQL with ADO.NET
This C# code example should be considered a proof of concept only. The sample code is simplified for clarity,
and does not necessarily represent best practices recommended by Microsoft.

Step 1: Connect
The method SqlConnection.Open is used to connect to your SQL database.

using System;
using QC = Microsoft.Data.SqlClient;

namespace ProofOfConcept_SQL_CSharp
{
public class Program
{
static public void Main()
{
using (var connection = new QC.SqlConnection(
"Server=tcp:YOUR_SERVER_NAME_HERE.database.windows.net,1433;" +
"Database=AdventureWorksLT;User ID=YOUR_LOGIN_NAME_HERE;" +
"Password=YOUR_PASSWORD_HERE;Encrypt=True;" +
"TrustServerCertificate=False;Connection Timeout=30;"
))
{
connection.Open();
Console.WriteLine("Connected successfully.");

Console.WriteLine("Press any key to finish...");


Console.ReadKey(true);
}
}
}
}
/**** Actual output:
Connected successfully.
Press any key to finish...
****/

Step 2: Execute a query


The method SqlCommand.ExecuteReader:
Issues the SQL SELECT statement to the SQL system.
Returns an instance of SqlDataReader to provide access to the result rows.

using System;
using DT = System.Data;
using QC = Microsoft.Data.SqlClient;

namespace ProofOfConcept_SQL_CSharp
{
public class Program
{
static public void Main()
{
using (var connection = new QC.SqlConnection(
"Server=tcp:YOUR_SERVER_NAME_HERE.database.windows.net,1433;" +
"Database=AdventureWorksLT;User ID=YOUR_LOGIN_NAME_HERE;" +
"Password=YOUR_PASSWORD_HERE;Encrypt=True;" +
"TrustServerCertificate=False;Connection Timeout=30;"
))
{
connection.Open();
Console.WriteLine("Connected successfully.");

Program.SelectRows(connection);

Console.WriteLine("Press any key to finish...");


Console.ReadKey(true);
}
}

static public void SelectRows(QC.SqlConnection connection)


{
using (var command = new QC.SqlCommand())
{
command.Connection = connection;
command.CommandType = DT.CommandType.Text;
command.CommandText = @"
SELECT
TOP 5
COUNT(soh.SalesOrderID) AS [OrderCount],
c.CustomerID,
c.CompanyName
FROM
SalesLT.Customer AS c
LEFT OUTER JOIN SalesLT.SalesOrderHeader AS soh
ON c.CustomerID = soh.CustomerID
GROUP BY
c.CustomerID,
c.CompanyName
ORDER BY
[OrderCount] DESC,
c.CompanyName; ";

QC.SqlDataReader reader = command.ExecuteReader();

while (reader.Read())
{
Console.WriteLine("{0}\t{1}\t{2}",
reader.GetInt32(0),
reader.GetInt32(1),
reader.GetString(2));
}
}
}
}
}
/**** Actual output:
Connected successfully.
1 29736 Action Bicycle Specialists
1 29638 Aerobic Exercise Company
1 29546 Bulk Discount Store
1 29741 Central Bicycle Specialists
1 29612 Channel Outlet
Press any key to finish...
****/

Step 3: Insert a row


This example demonstrates how to:
Execute an SQL INSERT statement safely by passing parameters.
Use of parameters protects against SQL injection attacks.
Retrieve the auto-generated value.

using System;
using DT = System.Data;
using QC = Microsoft.Data.SqlClient;

namespace ProofOfConcept_SQL_CSharp
{
public class Program
{
static public void Main()
{
using (var connection = new QC.SqlConnection(
"Server=tcp:YOUR_SERVER_NAME_HERE.database.windows.net,1433;" +
"Database=AdventureWorksLT;User ID=YOUR_LOGIN_NAME_HERE;" +
"Password=YOUR_PASSWORD_HERE;Encrypt=True;" +
"TrustServerCertificate=False;Connection Timeout=30;"
))
{
connection.Open();
Console.WriteLine("Connected successfully.");

Program.InsertRows(connection);

Console.WriteLine("Press any key to finish...");


Console.ReadKey(true);
}
}

static public void InsertRows(QC.SqlConnection connection)


{
QC.SqlParameter parameter;

using (var command = new QC.SqlCommand())


{
command.Connection = connection;
command.CommandType = DT.CommandType.Text;
command.CommandText = @"
INSERT INTO SalesLT.Product
(Name,
ProductNumber,
StandardCost,
ListPrice,
SellStartDate
)
OUTPUT
INSERTED.ProductID
VALUES
(@Name,
@ProductNumber,
@StandardCost,
@ListPrice,
CURRENT_TIMESTAMP
); ";

parameter = new QC.SqlParameter("@Name", DT.SqlDbType.NVarChar, 50);


parameter.Value = "SQL Server Express 2014";
parameter.Value = "SQL Server Express 2014";
command.Parameters.Add(parameter);

parameter = new QC.SqlParameter("@ProductNumber", DT.SqlDbType.NVarChar, 25);


parameter.Value = "SQLEXPRESS2014";
command.Parameters.Add(parameter);

parameter = new QC.SqlParameter("@StandardCost", DT.SqlDbType.Int);


parameter.Value = 11;
command.Parameters.Add(parameter);

parameter = new QC.SqlParameter("@ListPrice", DT.SqlDbType.Int);


parameter.Value = 12;
command.Parameters.Add(parameter);

int productId = (int)command.ExecuteScalar();


Console.WriteLine("The generated ProductID = {0}.", productId);
}
}
}
}
/**** Actual output:
Connected successfully.
The generated ProductID = 1000.
Press any key to finish...
****/
Step 4: Connect resiliently to SQL with ADO.NET
4/27/2022 • 6 minutes to read • Edit Online

Download ADO.NET
Previous article: Step 3: Proof of concept connecting to SQL using ADO.NET
This topic provides a C# code sample that demonstrates custom retry logic. The retry logic provides reliability.
The retry logic is designed to gracefully process temporary errors or transient faults which tend to go away if
the program waits several seconds and retries.
Sources of transient faults include:
A brief failure of the networking that supports the Internet.
A cloud system might be load balancing its resources at the moment your query was sent.
The ADO.NET classes for connecting to your local Microsoft SQL Server can also connect to Azure SQL Database.
However, by themselves the ADO.NET classes cannot provide all the robustness and reliability necessary in
production use. Your client program can encounter transient faults from which it should silently and gracefully
recover and continue on its own.

Step 1: Identify transient errors


Your program must distinguish between transient errors versus persistent errors. Transient errors are error
conditions that may clear up within a short period of time, such as transient network problems. An example of a
persistent error would be, if your program has a misspelling of the target database name - in this case, the "No
such database found" error would persist, and has no chance of clearing up within a short period of time.
The list of error numbers that are categorized as transient faults is available at Error messages for SQL Database
client applications

Step 2: Create and run sample application


This sample assumes .NET Framework 4.5.1 or later is installed. The C# code sample consists of one file named
Program.cs. Its code is provided in the next section.
Step 2.a: Capture and compile the code sample
You can compile the sample with the following steps:
1. In the free Visual Studio Community edition, create a new project from the C# Console Application template.
File > New > Project > Installed > Templates > Visual C# > Windows > Classic Desktop > Console
Application
Name the project Retr yAdo2 .
2. Open the Solution Explorer pane.
See the name of your project.
See the name of the Program.cs file.
3. Open the Program.cs file.
4. Entirely replace the contents of the Program.cs file with the code in the following code block.
5. Click the menu Build > Build Solution.
Step 2.b: Copy and paste sample code
Paste this code into your Program.cs file.
Then you must edit the strings for server name, password, and so on. You can find these strings in the method
named GetSqlConnectionStringBuilder .
NOTE: The connection string for server name is geared toward Azure SQL Database, because it includes the four
character prefix of tcp:. But you can adjust the server string to connect to your Microsoft SQL Server.

using System; // C#
using CG = System.Collections.Generic;
using QC = Microsoft.Data.SqlClient;
using TD = System.Threading;

namespace RetryAdo2
{
public class Program
{
static public int Main(string[] args)
{
bool succeeded = false;
int totalNumberOfTimesToTry = 4;
int retryIntervalSeconds = 10;

for (int tries = 1;


tries <= totalNumberOfTimesToTry;
tries++)
{
try
{
if (tries > 1)
{
Console.WriteLine
("Transient error encountered. Will begin attempt number {0} of {1} max...",
tries, totalNumberOfTimesToTry
);
TD.Thread.Sleep(1000 * retryIntervalSeconds);
retryIntervalSeconds = Convert.ToInt32
(retryIntervalSeconds * 1.5);
}
AccessDatabase();
succeeded = true;
break;
}

catch (QC.SqlException sqlExc)


{
if (TransientErrorNumbers.Contains
(sqlExc.Number) == true)
{
Console.WriteLine("{0}: transient occurred.", sqlExc.Number);
continue;
}
else
{
Console.WriteLine(sqlExc);
succeeded = false;
break;
}
}

catch (TestSqlException sqlExc)


{
if (TransientErrorNumbers.Contains
(sqlExc.Number) == true)
{
Console.WriteLine("{0}: transient occurred. (TESTING.)", sqlExc.Number);
continue;
}
else
{
Console.WriteLine(sqlExc);
succeeded = false;
break;
}
}

catch (Exception Exc)


{
Console.WriteLine(Exc);
succeeded = false;
break;
}
}

if (succeeded == true)
{
return 0;
}
else
{
Console.WriteLine("ERROR: Unable to access the database!");
return 1;
}
}

/// <summary>
/// Connects to the database, reads,
/// prints results to the console.
/// </summary>
static public void AccessDatabase()
{
//throw new TestSqlException(4060); //(7654321); // Uncomment for testing.

using (var sqlConnection = new QC.SqlConnection


(GetSqlConnectionString()))
{
using (var dbCommand = sqlConnection.CreateCommand())
{
dbCommand.CommandText = @"
SELECT TOP 3
ob.name,
CAST(ob.object_id as nvarchar(32)) as [object_id]
FROM sys.objects as ob
WHERE ob.type='IT'
ORDER BY ob.name;";

sqlConnection.Open();
var dataReader = dbCommand.ExecuteReader();

while (dataReader.Read())
{
Console.WriteLine("{0}\t{1}",
dataReader.GetString(0),
dataReader.GetString(1));
}
}
}
}

/// <summary>
/// You must edit the four 'my' string values.
/// </summary>
/// <returns>An ADO.NET connection string.</returns>
static private string GetSqlConnectionString()
{
// Prepare the connection string to Azure SQL Database.
// Prepare the connection string to Azure SQL Database.
var sqlConnectionSB = new QC.SqlConnectionStringBuilder();

// Change these values to your values.


sqlConnectionSB.DataSource = "tcp:myazuresqldbserver.database.windows.net,1433"; //["Server"]
sqlConnectionSB.InitialCatalog = "MyDatabase"; //["Database"]

sqlConnectionSB.UserID = "MyLogin"; // "@yourservername" as suffix sometimes.


sqlConnectionSB.Password = "MyPassword";
sqlConnectionSB.IntegratedSecurity = false;

// Adjust these values if you like. (ADO.NET 4.5.1 or later.)


sqlConnectionSB.ConnectRetryCount = 3;
sqlConnectionSB.ConnectRetryInterval = 10; // Seconds.

// Leave these values as they are.


sqlConnectionSB.IntegratedSecurity = false;
sqlConnectionSB.Encrypt = true;
sqlConnectionSB.ConnectTimeout = 30;

return sqlConnectionSB.ToString();
}

static public CG.List<int> TransientErrorNumbers =


new CG.List<int> { 4060, 40197, 40501, 40613,
49918, 49919, 49920, 11001 };
}

/// <summary>
/// For testing retry logic, you can have method
/// AccessDatabase start by throwing a new
/// TestSqlException with a Number that does
/// or does not match a transient error number
/// present in TransientErrorNumbers.
/// </summary>
internal class TestSqlException : ApplicationException
{
internal TestSqlException(int testErrorNumber)
{ this.Number = testErrorNumber; }

internal int Number


{ get; set; }
}
}

Step 2.c: Run the program


The Retr yAdo2.exe executable inputs no parameters. To run the .exe:
1. Open a console window to where you have compiled the RetryAdo2.exe binary.
2. Run RetryAdo2.exe, with no input parameters.

database_firewall_rules_table 245575913
filestream_tombstone_2073058421 2073058421
filetable_updates_2105058535 2105058535

Step 3: Ways to test your retry logic


There are a variety of ways you can simulate a transient error to test your retry logic.
Step 3.a: Throw a test exception
The code sample includes:
A small second class named TestSqlException , with a property named Number .
//throw new TestSqlException(4060); , which you can uncomment.

If you uncomment the throw statement, and recompile, the next run of Retr yAdo2.exe outputs something
similar to the following.

[C:\VS15\RetryAdo2\RetryAdo2\bin\Debug\]
>> RetryAdo2.exe
4060: transient occurred. (TESTING.)
Transient error encountered. Will begin attempt number 2 of 4 max...
4060: transient occurred. (TESTING.)
Transient error encountered. Will begin attempt number 3 of 4 max...
4060: transient occurred. (TESTING.)
Transient error encountered. Will begin attempt number 4 of 4 max...
4060: transient occurred. (TESTING.)
ERROR: Unable to access the database!

[C:\VS15\RetryAdo2\RetryAdo2\bin\Debug\]
>>

Step 3.b: Retest with a persistent error


To prove the code handles persistent errors correctly, rerun the preceding test except do not use the number of a
real transient error like 4060. Instead use the nonsense number 7654321. The program should treat this as a
persistent error, and should bypass any retry.
Step 3.c: Disconnect from the network
1. Disconnect your client computer from the network.
For a desktop, unplug the network cable.
For a laptop, press the function combination of keys to turn off the network adapter.
2. Start RetryAdo2.exe, and wait for the console to display the first transient error, probably 11001.
3. Reconnect to the network, while RetryAdo2.exe continues to run.
4. Watch the console report success on a subsequent retry.
Step 2.d: Temporarily misspell the server name
1. Temporarily add 40615 as another error number to TransientErrorNumbers , and recompile.
2. Set a breakpoint on the line: new QC.SqlConnectionStringBuilder() .
3. Use the Edit and Continue feature to purposely misspell the server name, a couple of lines below.
Let the program run and come back to your breakpoint.
The error 40615 occurs.
4. Fix the misspelling.
5. Let the program run and finish successfully.
6. Remove 40615, and recompile.

Next steps
To explore other best practicies and design guidelines, visit Connecting to SQL Database: Links, Best Practices
and Design Guidelines
Overview of the SqlClient driver
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
The Microsoft SqlClient Data Provider for SQL Server is a .NET Framework and .NET Core data provider. It's used
for connecting to a database, executing commands, and retrieving results.
The articles in this section provide a general overview of the SqlClient driver.

In this section
A RT IC L E DESC RIP T IO N

Introduction to Microsoft.Data.SqlClient namespace Introduction page for the Microsoft.Data.SqlClient


namespace.

Download Microsoft SqlClient Data Provider for SQL Server Download page for ADO.NET and Microsoft SqlClient Data
Provider for SQL Server.

Enabling event tracing in SqlClient Describes how to use event tracing to debug and test the
driver.

AppContext switches in SqlClient Describes the AppContext switches supported by the driver.

SqlClient troubleshooting guide Provides resolutions to commonly observed problems.

SqlClient driver support lifecycle Page that contains product support lifecycle information.

Finding additional SqlClient driver information Page that contains useful information about the driver.

Next steps
SqlClient driver GitHub Repository
.NET API browser
Introduction to Microsoft.Data.SqlClient namespace
4/27/2022 • 27 minutes to read • Edit Online

Download ADO.NET
The Microsoft.Data.SqlClient namespace is essentially a new version of the System.Data.SqlClient namespace.
Microsoft.Data.SqlClient generally maintains the same API and backwards compatibility with
System.Data.SqlClient. To migrate from System.Data.SqlClient to Microsoft.Data.SqlClient, for most applications,
it's simple. Add a NuGet dependency on Microsoft.Data.SqlClient and update references and using statements
to Microsoft.Data.SqlClient.
There are a few differences in less-used APIs compared to System.Data.SqlClient that may affect some
applications. For those differences, see this useful porting cheat sheet.

API reference
The Microsoft.Data.SqlClient API details can be found in the .NET API Browser.

Release notes for Microsoft.Data.SqlClient 4.1


Full release notes, including dependencies, are available in the GitHub Repository: 4.1 Release Notes.
New features in 4.1
Introduce Attestation Protocol None
A new attestation protocol called None will be allowed in the connection string. This protocol will allow users to
forgo enclave attestation for VBS enclaves. When this protocol is set, the enclave attestation URL property is
optional.
Connection string example:

//Attestation protocol NONE with no URL


"Data Source = {server}; Initial Catalog = {db}; Column Encryption Setting = Enabled; Attestation Protocol =
None;"

4.1 Target Platform Support


.NET Framework 4.6.1+ (Windows x86, Windows x64)
.NET Core 3.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)
.NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)

Release notes for Microsoft.Data.SqlClient 4.0


Full release notes, including dependencies, are available in the GitHub Repository: 4.0 Release Notes.
Breaking changes in 4.0
Changed Encrypt connection string property to be true by default. #1210 Read more
The driver now throws SqlException replacing AggregateException for active directory authentication
modes. #1213
Dropped obsolete Asynchronous Processing connection property from .NET Framework. #1148
Removed Configurable Retry Logic safety switch. #1254 Read more
Dropped support for .NET Core 2.1 #1272
[.NET Framework] Exception will not be thrown if a User ID is provided in the connection string when using
Active Directory Integrated authentication #1359

New features in 4.0


Encrypt default value set to true
The default value of the Encrypt connection setting has been changed from false to true . With the growing
use of cloud databases and the need to ensure those connections are secure, it's time for this backwards-
compatibility-breaking change.
Ensure connections fail when encryption is required
In scenarios where client encryption libraries were disabled or unavailable, it was possible for unencrypted
connections to be made when Encrypt was set to true or the server required encryption.
App Context Switch for using System default protocols
TLS 1.3 is not supported by the driver; therefore, it has been removed from the supported protocols list by
default. Users can switch back to forcing use of the Operating System's client protocols, by enabling the App
Context switch below:
Switch.Microsoft.Data.SqlClient.UseSystemDefaultSecureProtocols

Enable optimized parameter binding


Microsoft.Data.SqlClient introduces a new SqlCommand API, EnableOptimizedParameterBinding to improve
performance of queries with large number of parameters. This property is disabled by default. When set to
true , parameter names will not be sent to the SQL server when the command is executed.

public class SqlCommand


{
public bool EnableOptimizedParameterBinding { get; set; }
}

Remove configurable retry logic safety switch


The App Context switch "Switch.Microsoft.Data.SqlClient.EnableRetryLogic" will no longer be required to use the
configurable retry logic feature. The feature is now supported in production. The default behavior of the feature
will continue to be a non-retry policy, which will need to be overridden by client applications to enable retries.
SqlLocalDb shared instance support
SqlLocalDb shared instances are now supported when using Managed SNI.
Possible scenarios:
(localdb)\. (connects to default instance of SqlLocalDb)
(localdb)\<named instance>
(localdb)\.\<shared instance name> (*newly added support)
GetFieldValueAsync<T> and GetFieldValue<T> support for XmlReader , TextReader , Stream types
XmlReader , TextReader , Stream types are now supported when using GetFieldValueAsync<T> and
GetFieldValue<T> .
Example usage:
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
using (Stream stream = await reader.GetFieldValueAsync<Stream>(1))
{
// Continue to read from stream
}
}
}
}
}

4.0 Target Platform Support


.NET Framework 4.6.1+ (Windows x86, Windows x64)
.NET Core 3.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)
.NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)

Release notes for Microsoft.Data.SqlClient 3.0


Full release notes, including dependencies, are available in the GitHub Repository: 3.0 Release Notes.
Breaking changes in 3.0
The minimum supported .NET Framework version has been increased to v4.6.1. .NET Framework v4.6.0 is no
longer supported. #899
User Id connection property now requires Client Id instead of Object Id for User-Assigned Managed
Identity #1010 Read more
SqlDataReader now returns a DBNull value instead of an empty byte[] . Legacy behavior can be enabled by
setting AppContext switch Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior #998
Read more
New features in 3.0
Configurable Retry Logic
This new feature introduces configurable support for client applications to retry on "transient" or "retriable"
errors. Configuration can be done through code or app config files and retry operations can be applied to
opening a connection or executing a command. This feature is disabled by default and is currently in preview. To
enable this support, client applications must turn on the following safety switch:
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.EnableRetryLogic", true);

Once the .NET AppContext switch is enabled, a retry logic policy can be defined for SqlConnection and
SqlCommand independently, or together using various customization options.

New public APIs are introduced in SqlConnection and SqlCommand for registering a custom
SqlRetryLogicBaseProvider implementation:
public SqlConnection
{
public SqlRetryLogicBaseProvider RetryLogicProvider;
}

public SqlCommand
{
public SqlRetryLogicBaseProvider RetryLogicProvider;
}

API Usage examples can be found here:

using Microsoft.Data.SqlClient;

/// Detecting retriable exceptions is a vital part of the retry pattern.


/// Before applying retry logic it is important to investigate exceptions and choose a retry provider that
best fits your scenario.
/// First, log your exceptions and find transient faults.
/// The purpose of this sample is to illustrate how to use this feature and the condition might not be
realistic.
class RetryLogicSample
{
private const string DefaultDB = "Northwind";
private const string CnnStringFormat = "Server=localhost; Initial Catalog={0}; Integrated Security=true;
pooling=false;";
private const string DropDatabaseFormat = "DROP DATABASE {0}";

// For general use


private static SqlConnection s_generalConnection = new SqlConnection(string.Format(CnnStringFormat,
DefaultDB));

static void Main(string[] args)


{
// 1. Define the retry logic parameters
var options = new SqlRetryLogicOption()
{
NumberOfTries = 5,
MaxTimeInterval = TimeSpan.FromSeconds(20),
DeltaTime = TimeSpan.FromSeconds(1)
};

// 2. Create a retry provider


var provider = SqlConfigurableRetryFactory.CreateExponentialRetryProvider(options);

// define the retrying event to report the execution attempts


provider.Retrying += (object s, SqlRetryingEventArgs e) =>
{
int attempts = e.RetryCount + 1;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"attempt {attempts} - current delay time:{e.Delay} \n");
Console.ForegroundColor = ConsoleColor.DarkGray;
if (e.Exceptions[e.Exceptions.Count - 1] is SqlException ex)
{
Console.WriteLine($"{ex.Number}-{ex.Message}\n");
}
else
{
Console.WriteLine($"{e.Exceptions[e.Exceptions.Count - 1].Message}\n");
}

// It is not a good practice to do time-consuming tasks inside the retrying event which
blocks the running task.
// Use parallel programming patterns to mitigate it.
if (e.RetryCount == provider.RetryLogic.NumberOfTries - 1)
{
Console.WriteLine("This is the last chance to execute the command before throwing the
exception.");
Console.WriteLine("Press Enter when you're ready:");
Console.ReadLine();
Console.WriteLine("continue ...");
}
};

// Open the general connection.


s_generalConnection.Open();

try
{
// Assume the database is being created and other services are going to connect to it.
RetryConnection(provider);
}
catch
{
// exception is thrown if connecting to the database isn't successful.
throw;
}
}

private static void ExecuteCommand(SqlConnection cn, string command)


{
using var cmd = cn.CreateCommand();
cmd.CommandText = command;
cmd.ExecuteNonQuery();
}

private static void RetryConnection(SqlRetryLogicBaseProvider provider)


{
// Change this if you already have a database with the same name in your database.
string dbName = "Invalid_DB_Open";

// Create a connection to an invalid database.


using var cnn = new SqlConnection(string.Format(CnnStringFormat, dbName));
// 3. Assign the `provider` to the connection
cnn.RetryLogicProvider = provider;
Console.WriteLine($"Connecting to the [{dbName}] ...");
// Manually execute the following command in SSMS to create the invalid database while the
SqlConnection is attempting to connect to it.
// >> CREATE DATABASE Invalid_DB_Open;
Console.WriteLine($"Manually, run the 'CREATE DATABASE {dbName};' in the SQL Server before exceeding
the {provider.RetryLogic.NumberOfTries} attempts.");
// the connection tries to connect to the database 5 times
Console.WriteLine("The first attempt, before getting into the retry logic.");
cnn.Open();
Console.WriteLine($"Connected to the [{dbName}] successfully.");

cnn.Close();

// Drop it after test


ExecuteCommand(s_generalConnection, string.Format(DropDatabaseFormat, dbName));
Console.WriteLine($"The [{dbName}] is removed.");
}
}

/// Detecting retriable exceptions is a vital part of the retry pattern.


/// Before applying retry logic it is important to investigate exceptions and choose a retry provider that
best fits your scenario.
/// First, log your exceptions and find transient faults.
/// The purpose of this sample is to illustrate how to use this feature and the condition might not be
realistic.

private const string DefaultDB = "Northwind";


private const string CnnStringFormat = "Server=localhost; Initial Catalog={0}; Integrated Security=true;
pooling=false;";
private const string DropDatabaseFormat = "DROP DATABASE {0}";
private const string CreateDatabaseFormat = "CREATE DATABASE {0}";

// For general use


private static SqlConnection s_generalConnection = new SqlConnection(string.Format(CnnStringFormat,
DefaultDB));

static void Main(string[] args)


{
// 1. Define the retry logic parameters
var options = new SqlRetryLogicOption()
{
NumberOfTries = 5,
MaxTimeInterval = TimeSpan.FromSeconds(20),
DeltaTime = TimeSpan.FromSeconds(1),
AuthorizedSqlCondition = null,
// error number 3702 : Cannot drop database "xxx" because it is currently in use.
TransientErrors = new int[] {3702}
};

// 2. Create a retry provider


var provider = SqlConfigurableRetryFactory.CreateExponentialRetryProvider(options);

// define the retrying event to report execution attempts


provider.Retrying += (object s, SqlRetryingEventArgs e) =>
{
int attempts = e.RetryCount + 1;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"attempt {attempts} - current delay time:{e.Delay} \n");
Console.ForegroundColor = ConsoleColor.DarkGray;
if (e.Exceptions[e.Exceptions.Count - 1] is SqlException ex)
{
Console.WriteLine($"{ex.Number}-{ex.Message}\n");
}
else
{
Console.WriteLine($"{e.Exceptions[e.Exceptions.Count - 1].Message}\n");
}

// It is not good practice to do time-consuming tasks inside the retrying event which blocks
the running task.
// Use parallel programming patterns to mitigate it.
if (e.RetryCount == provider.RetryLogic.NumberOfTries - 1)
{
Console.WriteLine("This is the last chance to execute the command before throwing the
exception.");
Console.WriteLine("Press Enter when you're ready:");
Console.ReadLine();
Console.WriteLine("continue ...");
}
};

// Open a general connection.


s_generalConnection.Open();

try
{
// Assume the database is creating and other services are going to connect to it.
RetryCommand(provider);
}
catch
{
s_generalConnection.Close();
// exception is thrown if connecting to the database isn't successful.
throw;
}
s_generalConnection.Close();
}
private static void ExecuteCommand(SqlConnection cn, string command)
{
using var cmd = cn.CreateCommand();
cmd.CommandText = command;
cmd.ExecuteNonQuery();
}

private static void FindActiveSessions(SqlConnection cnn, string dbName)


{
using var cmd = cnn.CreateCommand();
cmd.CommandText = "DECLARE @query NVARCHAR(max) = '';" + Environment.NewLine +
$"SELECT @query = @query + 'KILL ' + CAST(spid as varchar(50)) + ';' FROM sys.sysprocesses WHERE
dbid = DB_ID('{dbName}')" + Environment.NewLine +
"SELECT @query AS Active_sessions;";
var reader = cmd.ExecuteReader();
if (reader.Read())
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write($">> Execute the '{reader.GetString(0)}' command in SQL Server to unblock the
running task.");
Console.ResetColor();
}
reader.Close();
}

var RetryLogicOption = new SqlRetryLogicOption()


{
NumberOfTries = 5,
// Declare the error number 102 as a transient error to apply the retry logic when it occurs.
TransientErrors = new int[] { 102 },
// When a SqlCommand executes out of a transaction,
// the retry logic will apply if it contains a 'select' keyword.
AuthorizedSqlCondition = x => string.IsNullOrEmpty(x)
|| Regex.IsMatch(x, @"\b(SELECT)\b", RegexOptions.IgnoreCase),
DeltaTime = TimeSpan.FromSeconds(1),
MaxTimeInterval = TimeSpan.FromSeconds(60),
MinTimeInterval = TimeSpan.FromSeconds(3)
};

New configuration sections have also been introduced to do the same registration from configuration files,
without having to modify existing code:

<section name="SqlConfigurableRetryLogicConnection"
type="Microsoft.Data.SqlClient.SqlConfigurableRetryConnectionSection,
Microsoft.Data.SqlClient"/>

<section name="SqlConfigurableRetryLogicCommand"
type="Microsoft.Data.SqlClient.SqlConfigurableRetryCommandSection, Microsoft.Data.SqlClient"/>

A simple example of using the new configuration sections in configuration files is below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="SqlConfigurableRetryLogicConnection"
type="Microsoft.Data.SqlClient.SqlConfigurableRetryConnectionSection,
Microsoft.Data.SqlClient"/>
<section name="SqlConfigurableRetryLogicCommand"
type="Microsoft.Data.SqlClient.SqlConfigurableRetryCommandSection, Microsoft.Data.SqlClient"/>

<section name="AppContextSwitchOverrides"
type="Microsoft.Data.SqlClient.AppContextSwitchOverridesSection, Microsoft.Data.SqlClient"/>
</configSections>

<!--Enable safety switch in .NET Core-->


<AppContextSwitchOverrides value="Switch.Microsoft.Data.SqlClient.EnableRetryLogic=true"/>

<!--Retry method for SqlConnection-->


<SqlConfigurableRetryLogicConnection retryMethod ="CreateFixedRetryProvider" numberOfTries ="3" deltaTime
="00:00:10" maxTime ="00:00:30"
transientErrors="40615" />

<!--Retry method for SqlCommand containing SELECT queries-->


<SqlConfigurableRetryLogicCommand retryMethod ="CreateIncrementalRetryProvider" numberOfTries ="5"
deltaTime ="00:00:10" maxTime ="00:01:10"
authorizedSqlCondition="\b(SELECT)\b" transientErrors="102, 4060, 0"/>
</configuration>

Alternatively, applications can implement their own provider of the SqlRetryLogicBaseProvider base class, and
register it with SqlConnection / SqlCommand .
Event Counters
The following counters are now available for applications targeting .NET Core 3.1+ and .NET Standard 2.1+:

NAME DISP L AY N A M E DESC RIP T IO N

active-hard-connections Actual active connections currently The number of connections that are
made to servers currently open to database servers.

hard-connects Actual connection rate to servers The number of connections per second
that are being opened to database
servers.

hard-disconnects Actual disconnection rate from servers The number of disconnects per second
that are being made to database
servers.

active-soft-connects Active connections retrieved from the The number of already-open


connection pool connections being consumed from the
connection pool.

soft-connects Rate of connections retrieved from the The number of connections per second
connection pool that are being consumed from the
connection pool.

soft-disconnects Rate of connections returned to the The number of connections per second
connection pool that are being returned to the
connection pool.

number-of-non-pooled- Number of connections not using The number of active connections that
connections connection pooling aren't pooled.
NAME DISP L AY N A M E DESC RIP T IO N

number-of-pooled-connections Number of connections managed by The number of active connections that


the connection pool are being managed by the connection
pooling infrastructure.

number-of-active-connection- Number of active unique connection The number of unique connection pool
pool-groups strings groups that are active. This counter is
controlled by the number of unique
connection strings that are found in
the AppDomain.

number-of-inactive-connection- Number of unique connection strings The number of unique connection pool
pool-groups waiting for pruning groups that are marked for pruning.
This counter is controlled by the
number of unique connection strings
that are found in the AppDomain.

number-of-active-connection- Number of active connection pools The total number of connection pools.
pools

number-of-inactive-connection- Number of inactive connection pools The number of inactive connection


pools pools that haven't had any recent
activity and are waiting to be disposed.

number-of-active-connections Number of active connections The number of active connections that


are currently in use.

number-of-free-connections Number of ready connections in the The number of open connections


connection pool available for use in the connection
pools.

number-of-stasis-connections Number of connections currently The number of connections currently


waiting to be ready awaiting completion of an action and
which are unavailable for use by the
application.

number-of-reclaimed-connections Number of reclaimed connections from The number of connections that have
GC been reclaimed through garbage
collection where Close or Dispose
wasn't called by the application. Note
Not explicitly closing or disposing
connections hurts performance.

These counters can be used with .NET Core global CLI tools: dotnet-counters and dotnet-trace in Windows or
Linux and PerfView in Windows, using Microsoft.Data.SqlClient.EventSource as the provider name. For more
information, see Retrieve event counter values.

dotnet-counters monitor Microsoft.Data.SqlClient.EventSource -p


PerfView /onlyProviders=*Microsoft.Data.SqlClient.EventSource:EventCounterIntervalSec=1 collect

Azure Identity dependency introduction


Microsoft.Data.SqlClient now depends on the Azure.Identity library to acquire tokens for "Active Directory
Managed Identity/MSI" and "Active Directory Service Principal" authentication modes. This change brings the
following changes to the public surface area:
Breaking Change
The "User Id" connection property now requires "Client Id" instead of "Object Id" for "User-Assigned
Managed Identity".
Public API
New read-only public property: SqlAuthenticationParameters.ConnectionTimeout
Dependency
Azure.Identity v1.3.0
Event tracing improvements in SNI.dll
Microsoft.Data.SqlClient.SNI (.NET Framework dependency) and Microsoft.Data.SqlClient.SNI.runtime (.NET
Core/Standard dependency) versions have been updated to v3.0.0-preview1.21104.2 . Event tracing in SNI.dll
will no longer be enabled through a client application. Subscribing a session to the
Microsoft.Data.SqlClient.EventSource provider through tools like xperf or perfview will be sufficient. For
more information, see Event tracing support in Native SNI.
Enabling row version null behavior
SqlDataReader returns a DBNull value instead of an empty byte[] . To enable the legacy behavior, you must
enable the following AppContext switch on application startup:
"Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior"
Active Directory Default authentication support
This PR introduces a new SQL Authentication method, Active Director y Default . This authentication mode
widens the possibilities of user authentication, extending login solutions to the client environment, Visual Studio
Code, Visual Studio, Azure CLI etc.
With this authentication mode, the driver acquires a token by passing "DefaultAzureCredential" from the Azure
Identity library to acquire an access token. This mode attempts to use these credential types to acquire an access
token in the following order:
EnvironmentCredential
Enables authentication to Azure Active Directory using client and secret, or username and password,
details configured in the following environment variables: AZURE_TENANT_ID, AZURE_CLIENT_ID,
AZURE_CLIENT_SECRET, AZURE_CLIENT_CERTIFICATE_PATH, AZURE_USERNAME, AZURE_PASSWORD
(More details)
ManagedIdentityCredential
Attempts authentication to Azure Active Directory using a managed identity that has been assigned to
the deployment environment. "Client Id" of "User Assigned Managed Identity" is read from the
"User Id" connection proper ty .
SharedTokenCacheCredential
Authenticates using tokens in the local cache shared between Microsoft applications.
VisualStudioCredential
Enables authentication to Azure Active Directory using data from Visual Studio
VisualStudioCodeCredential
Enables authentication to Azure Active Directory using data from Visual Studio Code.
AzureCliCredential
Enables authentication to Azure Active Directory using Azure CLI to obtain an access token.

InteractiveBrowserCredential is disabled in the driver implementation of "Active Directory Default", and


"Active Directory Interactive" is the only option available to acquire a token using MFA/Interactive
authentication.*
Further customization options are not available at the moment.

Custom master key store provider registration enhancements


Microsoft.Data.SqlClient now offers more control of where master key store providers are accessible in an
application to better support multi-tenant applications and their use of column encryption/decryption. The
following APIs are introduced to allow registration of custom master key store providers on instances of
SqlConnection and SqlCommand :

public class SqlConnection


{
public void RegisterColumnEncryptionKeyStoreProvidersOnConnection(IDictionary<string,
SqlColumnEncryptionKeyStoreProvider> customProviders)
}
public class SqlCommand
{
public void RegisterColumnEncryptionKeyStoreProvidersOnCommand(IDictionary<string,
SqlColumnEncryptionKeyStoreProvider> customProviders)
}

The static API on SqlConnection , i.e. SqlConnection.RegisterColumnEncryptionKeyStoreProviders to register


custom master key store providers globally continues to be supported. The column encryption key cache
maintained globally only applies to globally registered providers.
Column master key store provider registration precedence
The built-in column master key store providers that are available for the Windows Certificate Store, CNG Store
and CSP are pre-registered. No providers should be registered on the connection or command instances if one
of the built-in column master key store providers is needed.
Custom master key store providers can be registered with the driver at three different layers. The global level is
as it currently is. The new per-connection and per-command level registrations will be empty initially and can be
set more than once.
The precedence of the three registrations are as follows:
The per-command registration will be checked if it is not empty.
If the per-command registration is empty, the per-connection registration will be checked if it is not empty.
If the per-connection registration is empty, the global registration will be checked.
Once any key store provider is found at a registration level, the driver will NOT fall back to the other
registrations to search for a provider. If providers are registered but the proper provider is not found at a level,
an exception will be thrown containing only the registered providers in the registration that was checked.
Column encryption key cache precedence
The column encryption keys (CEKs) for custom key store providers registered using the new instance-level APIs
will not be cached by the driver. The key store providers need to implement their own cache to gain
performance. This local cache of column encryption keys implemented by custom key store providers will be
disabled by the driver if the key store provider instance is registered in the driver at the global level.
A new API has also been introduced on the SqlColumnEncryptionKeyStoreProvider base class to set the cache time
to live:
public abstract class SqlColumnEncryptionKeyStoreProvider
{
// The default value of Column Encryption Key Cache Time to Live is 0.
// Provider's local cache is disabled for globally registered providers.
// Custom key store provider implementation must include column encryption key cache to provide caching
support to locally registered providers.
public virtual TimeSpan? ColumnEncryptionKeyCacheTtl { get; set; } = new TimeSpan(0);
}

IP Address preference
A new connection property IPAddressPreference is introduced to specify the IP address family preference to the
driver when establishing TCP connections. If Transparent Network IP Resolution (in .NET Framework) or
Multi Subnet Failover is set to true , this setting has no effect. Below are the three accepted values for this
property:
IPv4First
This is the default preference value. The driver will use resolved IPv4 addresses first. If none of them
can be connected to successfully, it will try resolved IPv6 addresses.
IPv6First
The driver will use resolved IPv6 addresses first. If none of them can be connected to successfully, it
will try resolved IPv4 addresses.
UsePlatformDefault
The driver will try IP addresses in the order received from the DNS resolution response.
3.0 Target Platform Support
.NET Framework 4.6.1+ (Windows x86, Windows x64)
.NET Core 2.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)
.NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)

Release notes for Microsoft.Data.SqlClient 2.1


Full release notes, including dependencies, are available in the GitHub Repository: 2.1 Release Notes.
New features in 2.1
Cross-Platform support for Always Encrypted
Microsoft.Data.SqlClient v2.1 extends support for Always Encrypted on the following platforms:

SUP P O RT A L WAY S
SUP P O RT A L WAY S EN C RY P T ED W IT H TA RGET M IC RO SO F T. DATA . SQ
EN C RY P T ED SEC URE EN C L AVE F RA M EW O RK L C L IEN T VERSIO N O P ERAT IN G SY ST EM

Yes Yes .NET Framework 4.6+ 1.1.0+ Windows

Yes Yes .NET Core 2.1+ 2.1.0+1 Windows, Linux,


macOS

Yes No2 .NET Standard 2.0 2.1.0+ Windows, Linux,


macOS

Yes Yes .NET Standard 2.1+ 2.1.0+ Windows, Linux,


macOS
NOTE
1 Before Microsoft.Data.SqlClient version v2.1, Always Encrypted is only supported on Windows. 2 Always Encrypted with

secure enclaves is not supported on .NET Standard 2.0.

Azure Active Directory Device Code Flow authentication


Microsoft.Data.SqlClient v2.1 provides support for "Device Code Flow" authentication with MSAL.NET. Reference
documentation: OAuth2.0 Device Authorization Grant flow
Connection string example:
Server=<server>.database.windows.net; Authentication=Active Directory Device Code Flow; Database=Northwind;

The following API enables customization of the Device Code Flow callback mechanism:

public class ActiveDirectoryAuthenticationProvider


{
// For .NET Framework, .NET Core and .NET Standard targeted applications
public void SetDeviceCodeFlowCallback(Func<DeviceCodeResult, Task> deviceCodeFlowCallbackMethod)
}

Azure Active Directory Managed Identity authentication


Microsoft.Data.SqlClient v2.1 introduces support for Azure Active Directory authentication using managed
identities.
The following authentication mode keywords are supported:
Active Directory Managed Identity
Active Directory MSI (for cross MS SQL drivers compatibility)
Connection string examples:

// For System Assigned Managed Identity


"Server={serverURL}; Authentication=Active Directory MSI; Initial Catalog={db};"

// For System Assigned Managed Identity


"Server={serverURL}; Authentication=Active Directory Managed Identity; Initial Catalog={db};"

// For User Assigned Managed Identity


"Server={serverURL}; Authentication=Active Directory MSI; User Id={ObjectIdOfManagedIdentity}; Initial
Catalog={db};"

// For User Assigned Managed Identity


"Server={serverURL}; Authentication=Active Directory Managed Identity; User Id={ObjectIdOfManagedIdentity};
Initial Catalog={db};"

Azure Active Directory Interactive authentication enhancements


Microsoft.Data.SqlClient v2.1 adds the following APIs to customize the "Active Directory Interactive"
authentication experience:
public class ActiveDirectoryAuthenticationProvider
{
// For .NET Framework targeted applications only
public void SetIWin32WindowFunc(Func<IWin32Window> iWin32WindowFunc);

// For .NET Standard targeted applications only


public void SetParentActivityOrWindowFunc(Func<object> parentActivityOrWindowFunc);

// For .NET Framework, .NET Core and .NET Standard targeted applications
public void SetAcquireAuthorizationCodeAsyncCallback(Func<Uri, Uri, CancellationToken, Task<Uri>>
acquireAuthorizationCodeAsyncCallback);

// For .NET Framework, .NET Core and .NET Standard targeted applications
public void ClearUserTokenCache();
}

SqlClientAuthenticationProviders configuration section


Microsoft.Data.SqlClient v2.1 introduces a new configuration section, SqlClientAuthenticationProviders (a clone
of the existing SqlAuthenticationProviders ). The existing configuration section, SqlAuthenticationProviders , is
still supported for backwards compatibility when the appropriate type is defined.
The new section allows application config files to contain both a SqlAuthenticationProviders section for
System.Data.SqlClient and a SqlClientAuthenticationProviders section for Microsoft.Data.SqlClient.
Azure Active Directory authentication using an application client ID
Microsoft.Data.SqlClient v2.1 introduces support for passing a user-defined application client ID to the Microsoft
Authentication Library. Application Client ID is used when authenticating with Azure Active Directory.
The following new APIs are introduced:
1. A new constructor has been introduced in ActiveDirectoryAuthenticationProvider:
[Applies to all .NET Platforms (.NET Framework, .NET Core, and .NET Standard)]

public ActiveDirectoryAuthenticationProvider(string applicationClientId)

Usage:

string APP_CLIENT_ID = "<GUID>";


SqlAuthenticationProvider customAuthProvider = new
ActiveDirectoryAuthenticationProvider(APP_CLIENT_ID);
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive,
customAuthProvider);

using (SqlConnection sqlConnection = new SqlConnection("<connection_string>")


{
sqlConnection.Open();
}

2. A new configuration property has been introduced under SqlAuthenticationProviderConfigurationSection


and SqlClientAuthenticationProviderConfigurationSection :
[Applies to .NET Framework and .NET Core]
internal class SqlAuthenticationProviderConfigurationSection : ConfigurationSection
{
...
[ConfigurationProperty("applicationClientId", IsRequired = false)]
public string ApplicationClientId => this["applicationClientId"] as string;
}

// Inheritance
internal class SqlClientAuthenticationProviderConfigurationSection :
SqlAuthenticationProviderConfigurationSection
{ ... }

Usage:

<configuration>
<configSections>
<section name="SqlClientAuthenticationProviders"

type="Microsoft.Data.SqlClient.SqlClientAuthenticationProviderConfigurationSection,
Microsoft.Data.SqlClient" />
</configSections>
<SqlClientAuthenticationProviders applicationClientId ="<GUID>" />
</configuration>

<!--or-->

<configuration>
<configSections>
<section name="SqlAuthenticationProviders"

type="Microsoft.Data.SqlClient.SqlAuthenticationProviderConfigurationSection,
Microsoft.Data.SqlClient" />
</configSections>
<SqlAuthenticationProviders applicationClientId ="<GUID>" />
</configuration>

Data Classification v2 support


Microsoft.Data.SqlClient v2.1 introduces support for Data Classification's "Sensitivity Rank" information. The
following new APIs are now available:

public class SensitivityClassification


{
public SensitivityRank SensitivityRank;
}

public class SensitivityProperty


{
public SensitivityRank SensitivityRank;
}

public enum SensitivityRank


{
NOT_DEFINED = -1,
NONE = 0,
LOW = 10,
MEDIUM = 20,
HIGH = 30,
CRITICAL = 40
}

Server Process ID for an active SqlConnection


Microsoft.Data.SqlClient v2.1 introduces a new SqlConnection property, ServerProcessId , on an active
connection.

public class SqlConnection


{
// Returns the server process Id (SPID) of the active connection.
public int ServerProcessId;
}

Trace Logging support in Native SNI


Microsoft.Data.SqlClient v2.1 extends the existing SqlClientEventSource implementation to enable event tracing
in SNI.dll. Events must be captured using a tool like Xperf.
Tracing can be enabled by sending a command to SqlClientEventSource as illustrated below:

// Enables trace events:


EventSource.SendCommand(eventSource, (EventCommand)8192, null);

// Enables flow events:


EventSource.SendCommand(eventSource, (EventCommand)16384, null);

// Enables both trace and flow events:


EventSource.SendCommand(eventSource, (EventCommand)(8192 | 16384), null);

"Command Timeout" connection string property


Microsoft.Data.SqlClient v2.1 introduces the "Command Timeout" connection string property to override the
default of 30 seconds. The timeout for individual commands can be overridden using the CommandTimeout
property on the SqlCommand.
Connection string examples:
"Server={serverURL}; Initial Catalog={db}; Integrated Security=true; Command Timeout=60"

Removal of symbols from Native SNI


With Microsoft.Data.SqlClient v2.1, we've removed the symbols introduced in v2.0.0 from
Microsoft.Data.SqlClient.SNI.runtime NuGet starting with v2.1.1. The public symbols are now published to
Microsoft Symbols Server for tools like BinSkim that require access to public symbols.
Source -Linking of Microsoft.Data.SqlClient symbols
Starting with Microsoft.Data.SqlClient v2.1, Microsoft.Data.SqlClient symbols are source-linked and published to
the Microsoft Symbols Server for an enhanced debugging experience without the need to download source
code.
2.1 Target Platform Support
.NET Framework 4.6+ (Windows x86, Windows x64)
.NET Core 2.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)
.NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)

Release notes for Microsoft.Data.SqlClient 2.0


Full release notes, including dependencies, are available in the GitHub Repository: 2.0 Release Notes.
Breaking changes in 2.0
The access modifier for the enclave provider interface SqlColumnEncryptionEnclaveProvider has been changed
from public to internal .
Constants in the SqlClientMetaDataCollectionNames class have been updated to reflect changes in SQL Server.
The driver will now perform Server Certificate validation when the target SQL Server enforces TLS
encryption, which is the default for Azure connections.
SqlDataReader.GetSchemaTable() now returns an empty DataTable instead null .
The driver now performs decimal scale rounding to match SQL Server behavior. For backwards compatibility,
the previous behavior of truncation can be enabled using an AppContext switch.
For .NET Framework applications consuming Microsoft.Data.SqlClient , the SNI.dll files previously
downloaded to the bin\x64 and bin\x86 folders are now named Microsoft.Data.SqlClient.SNI.x64.dll and
Microsoft.Data.SqlClient.SNI.x86.dll and will be downloaded to the bin directory.
New connection string property synonyms will replace old properties when fetching connection string from
SqlConnectionStringBuilder for consistency. Read More

New features in 2.0


The following new features have been introduced in Microsoft.Data.SqlClient 2.0.
DNS failure resiliency
The driver will now cache IP addresses from every successful connection to a SQL Server endpoint that
supports the feature. If a DNS resolution failure occurs during a connection attempt, the driver will try
establishing a connection using a cached IP address for that server, if any exists.
EventSource tracing
This release introduces support for capturing event trace logs for debugging applications. To capture these
events, client applications must listen for events from SqlClient's EventSource implementation:

Microsoft.Data.SqlClient.EventSource

For more information, see how to Enable event tracing in SqlClient.


Enabling managed networking on Windows
A new AppContext switch, "Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows" ,
enables the use of a managed SNI implementation on Windows for testing and debugging purposes. This switch
will toggle the driver's behavior to use a managed SNI in .NET Core 2.1+ and .NET Standard 2.0+ projects on
Windows, eliminating all dependencies on native libraries for the Microsoft.Data.SqlClient library.

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true);

See AppContext Switches in SqlClient for a full list of available switches in the driver.
Enabling decimal truncation behavior
The decimal data scale will be rounded by the driver by default as is done by SQL Server. For backwards
compatibility, you can set the AppContext switch
"Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal" to true .

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal", true);

New connection string property synonyms


New synonyms have been added for the following existing connection string properties to avoid spacing
confusion around properties with more than one word. Old property names will continue to be supported for
backwards compatibility but the new connection string properties will now be included when fetching
connection string from SqlConnectionStringBuilder.
EXIST IN G C O N N EC T IO N ST RIN G P RO P ERT Y N EW SY N O N Y M

ApplicationIntent Application Intent

ConnectRetryCount Connect Retry Count

ConnectRetryInterval Connect Retry Interval

PoolBlockingPeriod Pool Blocking Period

MultipleActiveResultSets Multiple Active Result Sets

MultiSubnetFailover Multiple Subnet Failover

TransparentNetworkIPResolution Transparent Network IP Resolution

TrustServerCertificate Trust Server Certificate

SqlBulkCopy RowsCopied property


The RowsCopied property provides read-only access to the number of rows that have been processed in the
ongoing bulk copy operation. This value may not necessarily be equal to the final number of rows added to the
destination table.
Connection open overrides
The default behavior of SqlConnection.Open() can be overridden to disable the ten-second delay and automatic
connection retries triggered by transient errors.

using SqlConnection sqlConnection = new SqlConnection("Data Source=(local);Integrated Security=true;Initial


Catalog=AdventureWorks;");
sqlConnection.Open(SqlConnectionOverrides.OpenWithoutRetry);

NOTE
Note that this override can only be applied to SqlConnection.Open() and not SqlConnection.OpenAsync().

Username support for Active Directory Interactive mode


A username can be specified in the connection string when using Azure Active Directory Interactive
authentication mode for both .NET Framework and .NET Core
Set a username using the User ID or UID connection string property:

"Server=<server name>; Database=<db name>; Authentication=Active Directory Interactive; User Id=<username>;"

Order hints for SqlBulkCopy


Order hints can be provided to improve performance for bulk copy operations on tables with clustered indexes.
For more information, see the bulk copy operations section.
SNI dependency changes
Microsoft.Data.SqlClient (.NET Core and .NET Standard) on Windows is now dependent on
Microsoft.Data.SqlClient.SNI.runtime , replacing the previous dependency on
runtime.native.System.Data.SqlClient.SNI . The new dependency adds support for the ARM platform along
with the already supported platforms ARM64, x64, and x86 on Windows.
2.0 Target Platform Support
.NET Framework 4.6+ (Windows x86, Windows x64)
.NET Core 2.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)
.NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS)

Release notes for Microsoft.Data.SqlClient 1.1.0


Full release notes, including dependencies, are available in the GitHub Repository: 1.1 Release Notes.
New features in 1.1
Always Encrypted with secure enclaves
Always Encrypted is available starting in Microsoft SQL Server 2016. Secure enclaves are available starting in
Microsoft SQL Server 2019. To use the enclave feature, connection strings should include the required
attestation protocol and attestation URL. For example:

"Attestation Protocol=HGS;Enclave Attestation Url=<attestation_url_for_HGS>"

For more information, see:


SqlClient support for Always Encrypted
Tutorial: Develop a .NET application using Always Encrypted with secure enclaves
1.1 Target Platform Support
.NET Framework 4.6+ (Windows x86, Windows x64)
.NET Core 2.1+ (Windows x86, Windows x64, Linux, macOS)
.NET Standard 2.0+ (Windows x86, Windows x64, Linux, macOS)

Release notes for Microsoft.Data.SqlClient 1.0


The initial release for the Microsoft.Data.SqlClient namespace offers more functionality over the existing
System.Data.SqlClient namespace.
Full release notes, including dependencies, are available in the GitHub Repository: 1.0 Release Notes.
New features in 1.0
New features over .NET Framework 4.7.2 System.Data.SqlClient
Data Classification - Available in Azure SQL Database and Microsoft SQL Server 2019.
UTF-8 suppor t - Available in Microsoft SQL Server 2019.
New features over .NET Core 2.2 System.Data.SqlClient
Data Classification - Available in Azure SQL Database and Microsoft SQL Server 2019.
UTF-8 suppor t - Available in Microsoft SQL Server 2019.
Authentication - Active Directory Password authentication mode.
Data Classification
Data Classification brings a new set of APIs exposing read-only Data Sensitivity and Classification information
about objects retrieved via SqlDataReader when the underlying source supports the feature and contains
metadata about data sensitivity and classification. See the sample application at Data Discovery and
Classification in SqlClient.
public class SqlDataReader
{
public Microsoft.Data.SqlClient.DataClassification.SensitivityClassification SensitivityClassification
}

namespace Microsoft.Data.SqlClient.DataClassification
{
public class ColumnSensitivity
{
public
System.Collections.ObjectModel.ReadOnlyCollection<Microsoft.Data.SqlClient.DataClassification.SensitivityPro
perty> SensitivityProperties
}
public class InformationType
{
public string Id
public string Name
}
public class Label
{
public string Id
public string Name
}
public class SensitivityClassification
{
public
System.Collections.ObjectModel.ReadOnlyCollection<Microsoft.Data.SqlClient.DataClassification.ColumnSensitiv
ity> ColumnSensitivities
public
System.Collections.ObjectModel.ReadOnlyCollection<Microsoft.Data.SqlClient.DataClassification.InformationTyp
e> InformationTypes
public
System.Collections.ObjectModel.ReadOnlyCollection<Microsoft.Data.SqlClient.DataClassification.Label> Labels
}
public class SensitivityProperty
{
public Microsoft.Data.SqlClient.DataClassification.InformationType InformationType
public Microsoft.Data.SqlClient.DataClassification.Label Label
}
}

UTF -8 support
UTF-8 support doesn't require any application code changes. These SqlClient changes optimize client-server
communication when the server supports UTF-8 and the underlying column collation is UTF-8. See the UTF-8
section under What's new in SQL Server 2019.
Always encrypted with secure enclaves
In general, existing documentation that uses System.Data.SqlClient on .NET Framework and built-in column
master key store providers should now work with .NET Core, too.
Develop using Always Encrypted with .NET Framework Data Provider
Always Encrypted: Protect sensitive data and store encryption keys in the Windows certificate store
Authentication
Different authentication modes can be specified by using the Authentication connection string option. For more
information, see the documentation for SqlAuthenticationMethod.
NOTE
Custom key store providers, like the Azure Key Vault provider, will need to be updated to support
Microsoft.Data.SqlClient. Similarly, enclave providers will also need to be updated to support Microsoft.Data.SqlClient.
Always Encrypted is only supported against .NET Framework and .NET Core targets. It is not supported against .NET
Standard since .NET Standard is missing certain encryption dependencies.

1.0 Target Platform Support


.NET Framework 4.6+ (Windows x86, Windows x64)
.NET Core 2.1+ (Windows x86, Windows x64, Linux, macOS)
.NET Standard 2.0+ (Windows x86, Windows x64, Linux, macOS)
Download Microsoft SqlClient Data Provider for
SQL Server
4/27/2022 • 2 minutes to read • Edit Online

The Microsoft.Data.SqlClient library is distributed as a NuGet package. Simply add a NuGet reference to
Microsoft.Data.SqlClient. NuGet packages are easily consumed directly from a .NET project without the need to
manually download anything. If you use Visual Studio for development, see Install and use a package. For other
ways to consume a NuGet package, see the NuGet documentation.

Downloading the driver


If you need to download the Microsoft.Data.SqlClient package for offline use, it's available on NuGet.org. Refer to
the dependencies section from the links below to download the dependencies.

Download stable versions of Microsoft SqlClient Data Provider for SQL


Server
4.1.0
4.0.1
4.0.0
3.0.1
3.0.0
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.1
2.0.0
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.19269.1
1.0.19249.1
1.0.19239.1
SqlClient driver support lifecycle
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Microsoft.Data.SqlClient library follows the latest .NET Core support policy for all releases.
View the .NET Core Support Policy

Microsoft.Data.SqlClient release cadence


New stable (GA) releases are published every six months on a regular cadence beginning with version 1.2, along
with 2 to 3 preview releases in between. Long Term Support (LTS) releases will be chosen by stakeholders and
maintainers based on a few qualifications and customer response.
Actively supported releases
O F F IC IA L L AT EST PATC H PATC H REL EA SE EN D O F
VERSIO N REL EA SE DAT E VERSIO N DAT E SUP P O RT L EVEL SUP P O RT

4.1 January 31, - - Current -


2022

4.0 November 18, 4.0.1 January 17, LTS November 19,


2021 2022 2024

3.1 March 30, 2022 - - Current -

3.0 June 9, 2021 3.0.1 September 24, Current May 18, 2022
2021

2.1 November 19, 2.1.4 September 20, LTS November 20,


2020 2021 2023

1.1 November 20, 1.1.4 March 10, 2021 LTS November 21,
2019 2022

Out of support releases


L A ST PATC H L A ST PATC H REL EA SE
VERSIO N REL EA SE DAT E VERSIO N DAT E SUP P O RT EN DED

2.0 June 16, 2020 2.0.1 August 25, 2020 May 19, 2021

1.0 August 28, 2019 1.0.19269.1 September 26, 2019 May 20, 2020

Azure Key Vault Provider release cadence


New stable (GA) releases for Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider are published on
demand when new features are added. Long Term Support (LTS) releases will be chosen by stakeholders and
maintainers based on a few qualifications and customer response.
Actively supported Azure Key Vault Provider releases
O F F IC IA L L AT EST PATC H PATC H REL EA SE EN D O F
VERSIO N REL EA SE DAT E VERSIO N DAT E SUP P O RT L EVEL SUP P O RT

3.x June 14, 2021 3.0.0 June 14, 2021 LTS June 15, 2024

2.x March 3, 2021 2.0.0 March 3, 2021 LTS March 4, 2024

1.x November 19, 1.2.0 December 01, LTS November 21,


2019 2020 2022

Long Term Support (LTS) releases


LTS releases are supported for three years after the initial release.

Current releases
Current releases are supported for three months after a subsequent Current or LTS release.

SQL version compatibility with Microsoft.Data.SqlClient


DATA B A S A Z URE
E SQ L
VERSIO N A Z URE A Z URE M A N A GE
→ SQ L SY N A P SE D SQ L SQ L SQ L SQ L SQ L
↓ DRIVER DATA B A S A N A LY T I IN STA N C SERVER SERVER SERVER SERVER SERVER
VERSIO N E CS E 2019 2017 2016 2014 2012

4.1 Yes Yes Yes Yes Yes Yes Yes Yes

4.0 Yes Yes Yes Yes Yes Yes Yes Yes

3.0 Yes Yes Yes Yes Yes Yes Yes Yes

2.1 Yes Yes Yes Yes Yes Yes Yes Yes

2.0 Yes Yes Yes Yes Yes Yes Yes Yes

1.1 Yes Yes Yes Yes Yes Yes Yes Yes

1.0 Yes Yes Yes Yes Yes Yes Yes Yes

Supported OS versions
Support for .NET Framework applications
Microsoft.Data.SqlClient supports all operating systems supported by .NET Framework v4.6.1 and above.
.NET Framework system requirements.
Support for .NET Core applications
Microsoft.Data.SqlClient supports all operating systems supported by .NET Core v3.1 and above.
.NET Core supported OS lifecycle policy.
NOTE
Globalization Invariant mode is currently not supported.
Enable event tracing in SqlClient
4/27/2022 • 4 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Event Tracing for Windows (ETW) is an efficient, kernel-level, tracing facility that lets you log driver-defined
events for debugging and testing purposes. SqlClient supports capturing ETW events at different informational
levels. To begin capturing event traces, client applications should listen for events from SqlClient's EventSource
implementation:

Microsoft.Data.SqlClient.EventSource

The current implementation supports the following Event Keywords:

K EY W O RD N A M E VA L UE DESC RIP T IO N

ExecutionTrace 1 Turns on capturing Start/Stop events


before and after command execution.

Trace 2 Turns on capturing basic application


flow trace events.

Scope 4 Turns on capturing enter and exit


events

NotificationTrace 8 Turns on capturing SqlNotification


trace events

NotificationScope 16 Turns on capturing SqlNotification


scope enter and exit events

PoolerTrace 32 Turns on capturing connection pooling


flow trace events.

PoolerScope 64 Turns on capturing connection pooling


scope trace events.

AdvancedTrace 128 Turns on capturing advanced flow trace


events.

AdvancedTraceBin 256 Turns on capturing advanced flow trace


events with additional information.

CorrelationTrace 512 Turns on capturing correlation flow


trace events.

StateDump 1024 Turns on capturing full state dump of


SqlConnection
K EY W O RD N A M E VA L UE DESC RIP T IO N

SNITrace 2048 Turns on capturing flow trace events


from Managed Networking
implementation (only applicable in
.NET Core)

SNIScope 4096 Turns on capturing scope events from


Managed Networking implementation
(only applicable in .NET Core)

Example
The following example enables event tracing for a data operation on the AdventureWorks sample database
and displays the events in the console window.
using System;
using System.Diagnostics.Tracing;
using Microsoft.Data.SqlClient;

// This listener class will listen for events from the SqlClientEventSource class.
// SqlClientEventSource is an implementation of the EventSource class which gives
// it the ability to create events.
public class SqlClientListener : EventListener
{
protected override void OnEventSourceCreated(EventSource eventSource)
{
// Only enable events from SqlClientEventSource.
if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource"))
{
// Use EventKeyWord 2 to capture basic application flow events.
// See the above table for all available keywords.
EnableEvents(eventSource, EventLevel.Informational, (EventKeywords)2);
}
}

// This callback runs whenever an event is written by SqlClientEventSource.


// Event data is accessed through the EventWrittenEventArgs parameter.
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
// Print event data.
Console.WriteLine(eventData.Payload[0]);
}
}

class Program
{
public static void Main()
{
// Create a new event listener.
using (SqlClientListener listener = new SqlClientListener())
{
string connectionString = "Data Source=localhost; " +
"Initial Catalog=AdventureWorks; Integrated Security=true";

// Open a connection to the AdventureWorks database.


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

string sql = "SELECT * FROM Sales.Currency";


SqlCommand command = new SqlCommand(sql, connection);

// Perform a data operation on the server.


SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
// Read the data.
}
reader.Close();
}
}
}
}

Event tracing support in Native SNI


Microsoft.Data.SqlClient provides event tracing support in Microsoft.Data.SqlClient.SNI and
Microsoft.Data.SqlClient.SNI.runtime starting with v2.1. Events can be collected from the native DLLs using
the Xperf and PerfView tools.
Starting with Microsoft.Data.SqlClient v3.0, event tracing can be enabled without any modifications in the
client application using event collection tools.
With Microsoft.Data.SqlClient v2.1, event tracing needs to be enabled by configuring the EventCommand with
an event source listener. The valid EventCommand values applicable to Native SNI are listed as below:

// Enables trace events:


EventSource.SendCommand(eventSource, (EventCommand)8192, null);

// Enables flow events:


EventSource.SendCommand(eventSource, (EventCommand)16384, null);

// Enables both trace and flow events:


EventSource.SendCommand(eventSource, (EventCommand)(8192 | 16384), null);

The following example enables event tracing in native SNI DLLs.

// Native SNI tracing example


using System;
using System.Diagnostics.Tracing;
using Microsoft.Data.SqlClient;

public class SqlClientListener : EventListener


{
protected override void OnEventSourceCreated(EventSource eventSource)
{
if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource"))
{
// Enables both trace and flow events
EventSource.SendCommand(eventSource, (EventCommand)(8192 | 16384), null);
}
}
}

class Program
{
static string connectionString = @"Data Source = localhost; Initial Catalog = AdventureWorks;Integrated
Security=true;";

static void Main(string[] args)


{
// Event source listener configuration is not required in v3.0 onwards.
using (SqlClientListener listener = new SqlClientListener())
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
}
}
}

Use Xperf to collect trace log


1. Start tracing using the following command line.

xperf -start trace -f myTrace.etl -on *Microsoft.Data.SqlClient.EventSource

2. Run the native SNI tracing example to connect to SQL Server.


3. Stop tracing using the following command line.
xperf -stop trace

4. Use PerfView to open the myTrace.etl file specified in Step 1. The SNI tracing log can be found with
Microsoft.Data.SqlClient.EventSource/SNIScope and Microsoft.Data.SqlClient.EventSource/SNITrace
event names.

Use PerfView to collect trace log


1. Start PerfView and run Collect > Collect from menu bar.
2. Configure trace file name, output path, and provider name.

3. Start collection.
4. Run the native SNI tracing example to connect to SQL Server.
5. Stop collection from PerfView. It will take a while to generate PerfViewData.etl file according to
configuration in Step 2.
6. Open the etlfile in PerfView. The SNI tracing log can be found with
Microsoft.Data.SqlClient.EventSource/SNIScope and Microsoft.Data.SqlClient.EventSource/SNITrace
event names.

External resources
For more information, see the following resources.

RESO URC E DESC RIP T IO N

EventSource Class Used to create ETW events.


RESO URC E DESC RIP T IO N

EventListener Class Provides methods for enabling and disabling events from
event sources.
AppContext switches in Sqlclient
4/27/2022 • 3 minutes to read • Edit Online

Download ADO.NET
The AppContext class allows SqlClient to provide new functionality while continuing to support callers who
depend on the previous behavior. Users can opt out of a change in behavior by setting specific AppContext
switches.

Force use of operating system encryption protocols


APPLIES TO: .NET Framework .NET Core .NET Standard
Starting with Microsoft.Data.SqlClient 4.0, TLS 1.3 is not supported by the driver and has been removed from
the supported protocols list by default. Users can switch back to forcing use of the operating system's client
protocols, by setting the AppContext switch
"Switch.Microsoft.Data.SqlClient.UseSystemDefaultSecureProtocols" to true:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseSystemDefaultSecureProtocols", true);

Enabling decimal truncation behavior


APPLIES TO: .NET Framework .NET Core .NET Standard
Starting with Microsoft.Data.SqlClient 2.0, decimal data will be rounded by default, as is done by SQL Server. To
enable the previous behavior of truncation, you can set the AppContext switch
"Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal" to true at application startup:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal", true);

Enabling managed networking on Windows


APPLIES TO: .NET Framework .NET Core .NET Standard
(Available starting with version 2.0)
On Windows, SqlClient uses a native implementation of the SNI network interface by default. To enable the use
of a managed SNI implementation, you can set the AppContext switch
"Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows" to true at application startup:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true);

This switch will toggle the driver's behavior to use a managed networking implementation in .NET Core 2.1+
and .NET Standard 2.0+ projects on Windows, eliminating all dependencies on native libraries for the
Microsoft.Data.SqlClient library. It is intended for testing and debugging purposes only.
NOTE
There are some known differences when compared to the native implementation. For example, the managed
implementation does not support non-domain Windows Authentication.

Disabling Transparent Network IP Resolution


APPLIES TO: .NET Framework .NET Core .NET Standard
Transparent Network IP Resolution (TNIR) is a revision of the existing MultiSubnetFailover feature. TNIR affects
the connection sequence of the driver in the case where the first resolved IP of the hostname does not respond
and there are multiple IPs associated with the hostname. TNIR interacts with MultiSubnetFailover to provide the
following three connection sequences:
0: One IP is attempted, followed by all IPs in parallel
1: All IPs are attempted in parallel
2: All IPs are attempted one after another

T RA N SPA REN T N ET W O RK IP RESO L UT IO


N M ULT ISUB N ET FA ILO VER B EH AVIO R

True True 1

True False 0

False True 1

False False 2

TransparentNetworkIPResolution is enabled by default. MultiSubnetFailover is disabled by default. To disable


TNIR, you can set the AppContext switch
"Switch.Microsoft.Data.SqlClient.DisableTNIRByDefaultInConnectionString" to true at application
startup:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.DisableTNIRByDefaultInConnectionString", true);

For more information about setting these properties, see the documentation for
SqlConnection.ConnectionString Property.

Enable a minimum timeout during login


APPLIES TO: .NET Framework .NET Core .NET Standard
To prevent a login attempt from waiting indefinitely, you can set the AppContext switch
Switch.Microsoft.Data.SqlClient.UseOneSecFloorInTimeoutCalculationDuringLogin to true at
application startup:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseOneSecFloorInTimeoutCalculationDuringLogin",
false);

Disable blocking behavior of ReadAsync


APPLIES TO: .NET Framework .NET Core .NET Standard
By default, ReadAsync runs synchronously and blocks the calling thread on .NET Framework. To disable this
blocking behavior, you can set the AppContext switch
Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking to false at application startup:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking", false);

Enable configurable retry logic


APPLIES TO: .NET Framework .NET Core .NET Standard
(Available starting with version 3.0)
By default, configurable retry logic is disabled. To enable this feature, set the AppContext switch
Switch.Microsoft.Data.SqlClient.EnableRetr yLogic to true at application startup. This switch is required,
even if a retry provider is assigned to a connection or command.

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.EnableRetryLogic", true);

For information on how to enable the switch by using a configuration file see Enable safety switch.

NOTE
Starting from Microsoft.Data.SqlClient v4.0, the App Context switch "Switch.Microsoft.Data.SqlClient.EnableRetryLogic" will
no longer be required to use the configurable retry logic feature. The feature is now supported in production. The default
behavior of the feature will continue to be a non-retry policy, which will need to be overridden by client applications to
enable retries.

Enabling rowversion null behavior


APPLIES TO: .NET Framework .NET Core .NET Standard
Starting in version 3.0, when a rowversion has a value of null, SqlDataReader returns a DBNull value instead of
an empty byte[] . To enable the legacy behavior of returning an empty byte[] , enable the AppContext switch
Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior on application startup.

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior", true);

Suppress insecure TLS warning


APPLIES TO: .NET Framework .NET Core .NET Standard
(Available starting with version 4.0.1)
When using Encrypt=false in the connection string, a security warning is output to the console if the TLS
version is 1.2 or lower. This warning can be suppressed by enabling the following AppContext switch on
application startup:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning", true);
See also
AppContext Class
SqlClient troubleshooting guide
4/27/2022 • 6 minutes to read • Edit Online

Download ADO.NET

Exceptions when connecting to SQL Server


There are various reasons why connection can fail to be established. Below are some troubleshooting tips that
can be used as a guide to analyze and solve many of the problems.
Unable to load native SNI (Server Name Indication) library
Issues in .NET Framework applications
Stacktrace observed:

TypeInitializationException: The type initializer for 'Microsoft.Data.SqlClient.SNILoadHandle' threw an


exception.
DllNotFoundException: Unable to load DLL 'Microsoft.Data.SqlClient.SNI.x64.dll': The specified module could
not be found. (Exception from HRESULT: 0x8007007E)

TypeInitializationException: The type initializer for 'Microsoft.Data.SqlClient.SNILoadHandle' threw an


exception.
DllNotFoundException: Unable to load DLL 'Microsoft.Data.SqlClient.SNI.x86.dll': The specified module could
not be found. (Exception from HRESULT: 0x8007007E)

SNI is the native C++ library that SqlClient depends on for various network operations when running on
Windows. In .NET Framework applications that are built with the MSBuild Project SDK, native DLLs aren't
managed with restore commands. So a ".targets" file is included in the "Microsoft.Data.SqlClient.SNI" NuGet
package that defines the necessary "Copy" operations.
The included ".targets" file is auto-referenced when a direct dependency is made to the
"Microsoft.Data.SqlClient" library. In scenarios where a transitive (indirect) reference is made, this ".targets" file
should be manually referenced to ensure "Copy" operations can execute when necessary.
Recommended Solution: Make sure the ".targets" file is referenced in the application's ".csproj" file to ensure
"Copy" operations are executed.
These targets cover Microsoft's well-known and commonly used targets only. If an external tool or application
defines custom targets to copy binaries, new targets must be defined by tool maintainers to ensure native SNI
DLLs are copied along-side the Microsoft.Data.SqlClient.dll binaries and are available when executing client
applications.
Issues in .NET Core applications
Stacktrace observed:

System.TypeInitializationException: The type initializer for 'Microsoft.Data.SqlClient.TdsParser' threw an


exception.
---> System.TypeInitializationException: The type initializer for 'Microsoft.Data.SqlClient.SNILoadHandle'
threw an exception.
---> System.DllNotFoundException: Unable to load shared library 'Microsoft.Data.SqlClient.SNI.dll' or one of
its dependencies.
NOTE
This error may occur on Windows applications only. If it occurs in a Unix environment, you must ensure your application is
built to appropriately target a Unix runtime and not for Windows.

SNI is the native C++ library that SqlClient depends on for various network operations when running on
Windows. Microsoft.Data.SqlClient doesn't manage loading/unloading of this library in .NET Core.
Recommended Solution: Ensure "Execute" permissions are granted on the filesystem where native runtime
libraries are loaded in the .NET Core process. If that doesn't solve the issue, you can file an issue in the
dotnet/runtime repository for further support.
Native SNI (pdb not found) errors
Stacktrace observed:

An assembly specified in the application dependencies manifest (sql2csv.deps.json) was not found:
package: 'Microsoft.Data.SqlClient.SNI.runtime', version: '2.0.0'
path: 'runtimes/win-x64/native/Microsoft.Data.SqlClient.SNI.pdb'

Recommended Solution: Ensure client application references minimum v2.1.0 version of


Microsoft.Data.SqlClient package. When using EF Core, add a reference to this package version of
Microsoft.Data.SqlClient directly to override dependency.
Hostname resolution errors
Stacktrace observed:

Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred


while establishing a connection to SQL Server. The server was not found or was not accessible.
Verify that the instance name is correct and that SQL Server is configured to allow remote connections.
(provider: TCP Provider, error: 0 - No such host is known.)

Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred


while establishing a connection to SQL Server. The server was not found or was not accessible.
Verify that the instance name is correct and that SQL Server is configured to allow remote connections.
(provider: TCP Provider, error: 35 - An internal exception was caught)

Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred


while establishing a connection to SQL Server. The server was not found or was not accessible.
Verify that the instance name is correct and that SQL Server is configured to allow remote connections.
(provider: TCP Provider, error: 35 - An internal exception was caught)
---> System.Net.Internals.SocketExceptionFactory+ExtendedSocketException (00000005, 0xFFFDFFFF): Name does
not resolve

Possible reasons
TCP/Named Pipes Protocol isn't enabled on SQL Server
Recommended Solution: Enable the TCP/Named Pipes Protocol on the SQL Server instance from the
SQL Server Configuration Manager console.
Hostname not known
Recommended Solution: Ensure the hostname resolves to the Server's IP address from the client
where the connection is being initiated.
Login-phase errors
Stacktraces observed:

Microsoft.Data.SqlClient.SqlException (0x80131904): A connection was successfully established with the


server, but then an error occurred during the pre-login handshake.
(provider: SSL Provider, error: 31 - Encryption(ssl/tls) handshake failed)
System.IO.EndOfStreamException: End of stream reached

A connection was successfully established with the server, but then an error occurred during the login
process.
(provider: SSL Provider, error: 0 - The target principal name is incorrect.)

Microsoft.Data.SqlClient.SqlException (0x80131904): Connection Timeout Expired. The timeout period elapsed


during the post-login phase. The connection could have timed out while waiting for server to complete the
login process and respond; Or it could have timed out while attempting to create multiple active
connections.
The duration spent while attempting to connect to this server was - [Pre-Login] initialization=837;
handshake=394; [Login] initialization=3; authentication=15; [Post-Login] complete=1027;
---> System.ComponentModel.Win32Exception (258): Unknown error 258
at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection,
Action1 wrapCloseInAction)

Possible reasons and solutions


SQL Server doesn't support TLS 1.2
This error typically occurs in client environments like docker image containers, Unix clients, or Windows
clients where TLS 1.2 is the minimum supported TLS protocol.
Recommended Solution: Install the latest updates on supported versions of SQL Server1 and ensure
the TLS 1.2 protocol is enabled on the server.
1 View SqlClient driver support lifecycle for the list of supported SQL Server versions with different
versions of Microsoft.Data.SqlClient.
Insecure solution: Configure TLS/SSL settings in the docker image/client environment to connect with
TLS 1.0.

MinProtocol = TLSv1
CipherString = DEFAULT@SECLEVEL=1

NOTE
When connecting with Microsoft.Data.SqlClient v2.0+ from a Windows/Linux environment with TLS 1.0 or TLS 1.1,
a security warning message will be thrown if the target SQL Server and client cannot negotiate a minimum of TLS
version 1.2 when establishing the connection:
Security Warning: The negotiated <TLS1.0 | TLS1.1> is an insecure protocol and is supported for
backward compatibility only. The recommended protocol version is TLS 1.2 and later.

SQL Server enforced encryption


If the target Server is an Azure SQL instance or an On-Premise SQL Server with the "Force Encryption"
property turned on, an encrypted connection will be made, for which the client must establish trust with
the server.
Recommended Solution: There are two available options to fix this issue:
1. Install the target SQL Server's TLS/SSL certificate in the client environment. It will be validated if
encryption is needed.
2. Set the "Trust Server Certificate = true" property in the connection string.
Insecure solution: Disable the "Force Encryption" setting on SQL Server.
TLS/SSL Certificates not signed with SHA-256 or above.
Recommended Solution: Generate a new TLS/SSL Certificate for the server whose hash is signed with
at-least the SHA-256 hashing algorithm.
Tightly restricted cipher suites on Linux with .NET 5+
.NET 5 introduced a breaking change for Linux clients, where a tightly restricted list of permitted cipher
suites is used by default. You may need to expand the default cipher suite list to accept legacy clients (or
to contact legacy servers) by either specify a CipherSuitePolicy value or changing the OpenSSL
configuration file.
Read more on Default TLS cipher suites for .NET on Linux for recommended action.
Connection Pool exhaustion errors
Stacktrace observed:

System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a


connection from the pool.
This may have occurred because all pooled connections were in use and max pool size was reached.

Possible reasons and solutions


Client application is opening more connections than the connection pool can hold active at a given time.
Recommended Solution: Configure "Max Pool Size" connection property to a higher value and close unused
connections in timely manner.

Contact Support
If this guide doesn't solve your connectivity issues, you may view existing issues in the dotnet/sqlclient
repository and open a new issue if needed.
Finding additional SqlClient driver information
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
For more information about the Microsoft SqlClient Data Provider for SQL Server development in general, see
the following online resources:

Remarks
RESO URC E DESC RIP T IO N

.NET API Browser This site contains .NET API information for
Microsoft.Data.SqlClient.

Microsoft SqlClient Data Provider for SQL Server GitHub This repository contains the source code for
Repository Microsoft.Data.SqlClient.

.NET Runtime GitHub Repository This repository contains the runtime library implementation
for .NET.

Next steps
Overview of the SqlClient driver
Data type mappings in ADO.NET
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The ADO.NET is based on the common type system, which defines how types are declared, used, and managed
in the runtime. It consists of both value types and reference types, which all derive from the Object base type.
When working with a data source, the data type is inferred from the data provider if it is not explicitly specified.
For example, a DataSet object is independent of any specific data source. Data in a DataSet is retrieved from a
data source, and changes are persisted back to the data source by using a DataAdapter . This program flow
means that when a DataAdapter fills a DataTable in a DataSet with values from a data source, the resulting data
types of the columns in the DataTable are .NET Framework types, instead of types specific to the Microsoft
SqlClient Data Provider for SQL Server that is used to connect to the data source.
Likewise, when a DataReader returns a value from a data source, the resulting value is stored in a local variable
that has a .NET Framework type. For both the Fill operations of the DataAdapter and the Get methods of the
DataReader , the .NET Framework type is inferred from the value returned from the Microsoft SqlClient Data
Provider for SQL Server.
Instead of relying on the inferred data type, you can use the typed accessor methods of the DataReader when
you know the specific type of the value being returned. Typed accessor methods give you better performance by
returning a value as a specific .NET Framework type, which eliminates the need for additional type conversion.

NOTE
Null values for Microsoft SqlClient Data Provider for SQL Server data types are represented by DBNull.Value .

In This Section
SQL Server Data Type Mappings Lists inferred data type mappings and data accessor methods for
Microsoft.Data.SqlClient.
Floating-Point Numbers Describes issues that developers frequently encounter when working with floating-
point numbers.

See also
SQL Server data types and ADO.NET
Configuring parameters
Retrieving database schema information
Microsoft ADO.NET for SQL Server
SQL Server data type mappings
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
SQL Server and the .NET Framework are based on different type systems. For example, the .NET Framework
Decimal structure has a maximum scale of 28, whereas the SQL Server decimal and numeric data types have a
maximum scale of 38. To maintain data integrity when reading and writing data, the SqlDataReader exposes SQL
Server–specific typed accessor methods that return objects of System.Data.SqlTypes as well as accessor
methods that return .NET Framework types. Both SQL Server types and .NET Framework types are also
represented by enumerations in the DbType and SqlDbType classes, which you can use when specifying
SqlParameter data types.
The following table shows the inferred .NET Framework type, the DbType and SqlDbType enumerations, and the
accessor methods for the SqlDataReader.

SQ L SERVER . N ET SQ L DATA REA DER SQ L DATA REA DER


DATA B A SE F RA M EW O RK SQ L DBT Y P E SQ LT Y P ES T Y P ED DBT Y P E DBT Y P E T Y P ED
EN GIN E T Y P E TYPE EN UM ERAT IO N A C C ESSO R EN UM ERAT IO N A C C ESSO R

bigint Int64 BigInt GetSqlInt64 Int64 GetInt64

binary Byte[] VarBinary GetSqlBinary Binary GetBytes

bit Boolean Bit GetSqlBoolean Boolean GetBoolean

char String Char GetSqlString AnsiStringFixedLe GetString


ngth,
Char[] GetChars
String

date 1 DateTime Date 1 GetSqlDateTime Date 1 GetDateTime

(SQL Server
2008 and later)

datetime DateTime DateTime GetSqlDateTime DateTime GetDateTime

datetime2 DateTime DateTime2 None DateTime2 GetDateTime

(SQL Server
2008 and later)

datetimeoffset DateTimeOffset DateTimeOffset none DateTimeOffset GetDateTimeOffs


et
(SQL Server
2008 and later)

decimal Decimal Decimal GetSqlDecimal Decimal GetDecimal


SQ L SERVER . N ET SQ L DATA REA DER SQ L DATA REA DER
DATA B A SE F RA M EW O RK SQ L DBT Y P E SQ LT Y P ES T Y P ED DBT Y P E DBT Y P E T Y P ED
EN GIN E T Y P E TYPE EN UM ERAT IO N A C C ESSO R EN UM ERAT IO N A C C ESSO R

FILESTREAM Byte[] VarBinary GetSqlBytes Binary GetBytes


attribute
(varbinary(max))

float Double Float GetSqlDouble Double GetDouble

image Byte[] Binary GetSqlBinary Binary GetBytes

int Int32 Int GetSqlInt32 Int32 GetInt32

money Decimal Money GetSqlMoney Decimal GetDecimal

nchar String NChar GetSqlString StringFixedLengt GetString


h
Char[] GetChars

ntext String NText GetSqlString String GetString

Char[] GetChars

numeric Decimal Decimal GetSqlDecimal Decimal GetDecimal

nvarchar String NVarChar GetSqlString String GetString

Char[] GetChars

real Single Real GetSqlSingle Single GetFloat

rowversion Byte[] Timestamp GetSqlBinary Binary GetBytes

smalldatetime DateTime DateTime GetSqlDateTime DateTime GetDateTime

smallint Int16 SmallInt GetSqlInt16 Int16 GetInt16

smallmoney Decimal SmallMoney GetSqlMoney Decimal GetDecimal

sql_variant Object 2 Variant GetSqlValue 2 Object GetValue 2

text String Text GetSqlString String GetString

Char[] GetChars

time TimeSpan Time none Time GetDateTime

(SQL Server
2008 and later)

timestamp Byte[] Timestamp GetSqlBinary Binary GetBytes

tinyint Byte TinyInt GetSqlByte Byte GetByte


SQ L SERVER . N ET SQ L DATA REA DER SQ L DATA REA DER
DATA B A SE F RA M EW O RK SQ L DBT Y P E SQ LT Y P ES T Y P ED DBT Y P E DBT Y P E T Y P ED
EN GIN E T Y P E TYPE EN UM ERAT IO N A C C ESSO R EN UM ERAT IO N A C C ESSO R

uniqueidentifier Guid UniqueIdentifier GetSqlGuid Guid GetGuid

varbinary Byte[] VarBinary GetSqlBinary Binary GetBytes

varchar String VarChar GetSqlString AnsiString, String GetString

Char[] GetChars

xml Xml Xml GetSqlXml Xml none

1 You cannot set the DbType property of a SqlParameter to SqlDbType.Date .


2 Use a specific typed accessor if you know the underlying type of the sql_variant .

SQL Server documentation


For more information about SQL Server data types, see Data types (Transact-SQL).

See also
SQL Server data types and ADO.NET
SQL Server binary and large-value data
Configuring parameters
Data type mappings in ADO.NET
Floating-point numbers
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
This topic describes some of the issues that developers frequently encounter when they work with floating-point
numbers in the Microsoft SqlClient Data Provider for SQL Server. These issues are caused by the way that
computers store floating-point numbers, and are not specific to a particular provider such as
Microsoft.Data.SqlClient.

Floating-point pitfall
Floating-point numbers generally do not have an exact binary representation. Instead, the computer stores an
approximation of the number. At different times, different numbers of binary digits may be used to represent
the number. When a floating point number is converted from one representation to another representation, the
least significant digits of that number may vary slightly. Conversion typically occurs when the number is cast
from one type to another type. The variation occurs whether the conversion occurs within a database, between
types that represent database values, or between types. Because of these changes, numbers that would logically
be equal may have changes in their least-significant digits that cause them to have different values. The number
of digits of precision in the number may be larger or smaller than expected. When formatted as a string, the
number may not show the expected value.

Suggested workarounds
To minimize these effects, you should use the closest match between numeric types that is available to you. For
example, if you are working with SQL Server, the exact numeric value may change if you convert a Transact-SQL
value of real type to a value of float type. In the .NET, converting a Single to a Double may also produce
unexpected results. In both of these cases, a good strategy is to make all the values in the application use the
same numeric type. You can also use a fixed-precision decimal type, or cast floating-point numbers to a fixed-
precision decimal type before you work with them.
To work around problems with equality comparison, consider coding your application so that variations in the
least significant digits are ignored. For example, instead of comparing to see whether two numbers are equal,
subtract one number from the other number. If the difference is within an acceptable margin of rounding, your
application can treat the numbers as if they are the same.

See also
Microsoft ADO.NET for SQL Server
Retrieving and modifying data in ADO.NET
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
A primary function of any database application is connecting to a data source and retrieving the data that it
contains. The SqlClient data provider serves as a bridge between an application and a data source, allowing you
to execute commands as well as to retrieve data by using a DataReader or a DataAdapter . A key function of
any database application is the ability to update the data that is stored in the database. In the Microsoft SqlClient
Data Provider for SQL Server, updating data involves using the DataAdapter and DataSet, and Command
objects; and it may also involve using transactions.

In this section
Connecting to a data source
Describes how to establish a connection to a data source and how to work with connection events.
Connection strings
Contains topics describing various aspects of using connection strings, including connection string keywords,
security info, and storing and retrieving them.
Connection pooling
Describes connection pooling for the Microsoft SqlClient Data Provider for SQL Server.
Commands and Parameters
Contains topics describing how to create commands and command builders, configure parameters,
and how to execute commands to retrieve and modify data.
DataAdapters and DataReaders
Contains topics describing DataReaders, DataAdapters, parameters, handling DataAdapter events and performin
g batch operations.
Transactions and concurrency
Contains topics describing how to perform local transactions, distributed transactions, and work with optimistic
concurrency.
Retrieving database schema information
Describes how to obtain available databases or catalogs, tables and views in a database, constraints that exist for
tables, and other schema information from a data source.
DbProviderFactories
Describes the provider factory model and demonstrates how to use the base classes in the System.Data.Common
namespace.
Configurable retry logic in SqlClient
Describes how to use the configurable retr y logic feature when establishing a connection or executing a
command.
Retrieve identity or autonumber values
Provides an example of mapping the values generated for an identity column in a SQL Server table to a
column of an inserted row in a table. Discusses merging identity values in a DataTable .
Retrieve Binary Data
Describes how to retrieve binary data or large data structures using CommandBehavior . SequentialAccess to
modify the default behavior of a DataReader .
Modify data with stored procedures
Describes how to use stored procedure input parameters and output parameters to insert a row in a database,
returning a new identity value.
Data tracing in SqlClient
Describes how Microsoft SqlClient Data Provider for SQL Server provides built-in data tracing functionality.
Diagnostic counters in SqlClient
Describes diagnostic counters and available for Microsoft SqlClient Data Provider for SQL Server.
Asynchronous programming
Describes Microsoft SqlClient Data Provider for SQL Server support for asynchronous programming.
SqlClient streaming support
Discusses how to write applications that stream data from SQL Server without having it fully loaded in memory.

See also
Data type mappings in ADO.NET
SQL Server and ADO.NET
Microsoft ADO.NET for SQL Server
Connecting to a data source in ADO.NET
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
In the Microsoft SqlClient data provider, you use a Connection object to connect to a specific data source by
supplying necessary authentication information in a connection string. The Connection object you use depends
on the type of data source.
The Microsoft SqlClient Data Provider for SQL Server includes a SqlConnection type that is derived from a
DbConnection class.

In this section
Establishing the Connection
Describes how to use a Connection object to establish a connection to a data source.
Connection Events
Describes how to use an InfoMessage event to retrieve informational messages from a data source.

See also
Connection strings
Connection pooling
Commands and parameters
DataAdapters and DataReaders
Transactions and concurrency
Microsoft ADO.NET for SQL Server
Establishing connection
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
To connect to Microsoft SQL Server, use the SqlConnection object of the Microsoft SqlClient Data Provider for
SQL Server. For securely storing and retrieving connection strings, see Protecting Connection Information.

Closing connections
We recommend that you always close the connection when you are finished using it, so that the connection can
be returned to the pool. The Using block in Visual Basic or C# automatically disposes of the connection when
the code exits the block, even in the case of an unhandled exception. See using Statement and Using Statement
for more information.
You can also use the Close or Dispose methods of the connection object. Connections that are not explicitly
closed might not be added or returned to the pool. For example, a connection that has gone out of scope but
that has not been explicitly closed will only be returned to the connection pool if the maximum pool size has
been reached and the connection is still valid.

NOTE
Do not call Close or Dispose on a Connection , a DataReader , or any other managed object in the Finalize
method of your class. In a finalizer, only release unmanaged resources that your class owns directly. If your class does not
own any unmanaged resources, do not include a Finalize method in your class definition. For more information, see
Garbage Collection.

NOTE
Login and logout events will not be raised on the server when a connection is fetched from or returned to the connection
pool, because the connection is not actually closed when it is returned to the connection pool. For more information, see
SQL Server Connection Pooling (ADO.NET).

Connecting to SQL Server


For valid string format names and values, see the ConnectionString property of the SqlConnection object. You
can also use the SqlConnectionStringBuilder class to create syntactically valid connection strings at run time. For
more information, see Connection String Builders.
The following code example demonstrates how to create and open a connection to a SQL Server database.
using Microsoft.Data.SqlClient;

class Program1
{
static void Main()
{
string s = GetConnectionString();

OpenSqlConnection(s);
Console.ReadLine();
}

private static void OpenSqlConnection(string connectionString)


{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
Console.WriteLine("ServerVersion: {0}", connection.ServerVersion);
Console.WriteLine("State: {0}", connection.State);
}
}

static private string GetConnectionString()


{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file, using the
// System.Configuration.ConfigurationSettings.AppSettings property
return "Data Source=(local);Initial Catalog=AdventureWorks;"
+ "Integrated Security=SSPI;";
}
}

Integrated security and ASP.NET


SQL Server Integrated Security (also known as trusted connections) helps to provide protection when
connecting to SQL Server as it does not expose a user ID and password in the connection string and is the
recommended method for authenticating a connection. Integrated security uses the current security identity, or
token, of the executing process. For desktop applications, this identity is typically the identity of the currently
logged-on user.
The security identity for ASP.NET applications can be set to one of several different options. To better understand
the security identity that an ASP.NET application uses when connecting to SQL Server, see ASP.NET
Impersonation, ASP.NET Authentication, and How to: Access SQL Server Using Windows Integrated Security.

See also
Connecting to a data source
Connection strings
Microsoft ADO.NET for SQL Server
Connection events
4/27/2022 • 3 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The Microsoft SqlClient Data Provider for SQL Server has Connection objects with two events that you can use
to retrieve informational messages from a data source or to determine if the state of a Connection has
changed. The following table describes the events of the Connection object.

EVEN T DESC RIP T IO N

InfoMessage Occurs when an informational message is returned from a


data source. Informational messages are messages from a
data source that don't result in an exception being thrown.

StateChange Occurs when the state of the Connection changes.

Work with the InfoMessage event


You can retrieve warnings and informational messages from a SQL Server data source using the InfoMessage
event of the SqlConnection object. Errors returned from the data source with a severity level of 11 through 16
cause an exception to be thrown. However, the InfoMessage event can be used to obtain messages from the data
source that aren't associated with an error. With Microsoft SQL Server, any error with a severity of 10 or less is
considered to be an informational message, and can be captured by using the InfoMessage event. For more
information, see the Database Engine Error Severities article.
The InfoMessage event receives an SqlInfoMessageEventArgs object containing, in its Errors property, a
collection of the messages from the data source. You can query the Error objects in this collection for the error
number, message text, and the source of the error. The Microsoft SqlClient Data Provider for SQL Server also
includes detail about the database, stored procedure, and line number that the message came from.
Example
The following code example shows how to add an event handler for the InfoMessage event.

// Assumes that connection represents a SqlConnection object.


connection.InfoMessage +=
(object sender, SqlInfoMessageEventArgs args) =>
{
foreach (SqlError err in args.Errors)
{
Console.WriteLine(
"The {0} has received a severity {1}, state {2} error number {3}\n" +
"on line {4} of procedure {5} on server {6}:\n{7}",
err.Source, err.Class, err.State, err.Number, err.LineNumber,
err.Procedure, err.Server, err.Message);
}
};

Handle errors as InfoMessages


The InfoMessage event will normally fire only for informational and warning messages that are sent from the
server. However, when an actual error occurs, the execution of the ExecuteNonQuer y or ExecuteReader
method that began the server operation is halted and an exception is thrown.
If you want to continue processing the rest of the statements in a command regardless of any errors produced
by the server, set the FireInfoMessageEventOnUserErrors property of the SqlConnection to true . Setting this
property causes the connection to fire the InfoMessage event for errors instead of throwing an exception and
interrupting processing. The client application can then handle this event and respond to error conditions.

NOTE
An error with a severity level of 17 or above that causes the server to stop processing the command must be handled as
an exception. In this case, an exception is thrown regardless of how the error is handled in the InfoMessage event.

Work with the StateChange event


The StateChange event occurs when the state of a Connection changes. The StateChange event receives
StateChangeEventArgs that enable you to determine the change in state of the Connection by using the
OriginalState and CurrentState properties. The OriginalState property is a ConnectionState enumeration
that indicates the state of the Connection before it changed. CurrentState is a ConnectionState enumeration
that indicates the state of the Connection after it changed.
The following code example uses the StateChange event to write a message to the console when the state of
the Connection changes.

// Assumes that connection represents a SqlConnection object.


connection.StateChange +=
(object sender, StateChangeEventArgs args) =>
{
Console.WriteLine(
"The current Connection state has changed from {0} to {1}.",
args.OriginalState, args.CurrentState);
};

See also
Connecting to a data source
Microsoft ADO.NET for SQL Server
Connection strings in ADO.NET
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
A connection string contains initialization information that is passed as a parameter from a data provider to a
data source. The data provider receives the connection string as the value of the DbConnection.ConnectionString
property. The provider parses the connection string and ensures that the syntax is correct and that the keywords
are supported. Then the DbConnection.Open() method passes the parsed connection parameters to the data
source. The data source performs further validation and establishes a connection.

Connection string syntax


A connection string is a semicolon-delimited list of key/value parameter pairs:

keyword1=value; keyword2=value;

Keywords are not case-sensitive. Values, however, may be case-sensitive, depending on the data source. Both
keywords and values may contain whitespace characters. Leading and trailing white space is ignored in
keywords and unquoted values.
If a value contains the semicolon, Unicode control characters, or leading or trailing white space, it must be
enclosed in single or double quotation marks. For example:

Keyword=" whitespace ";


Keyword='special;character';

The enclosing character may not occur within the value it encloses. Therefore, a value containing single
quotation marks can be enclosed only in double quotation marks, and vice versa:

Keyword='double"quotation;mark';
Keyword="single'quotation;mark";

You can also escape the enclosing character by using two of them together:

Keyword="double""quotation";
Keyword='single''quotation';

The quotation marks themselves, as well as the equals sign, do not require escaping, so the following connection
strings are valid:

Keyword=no "escaping" 'required';


Keyword=a=b=c

Since each value is read until the next semicolon or the end of string, the value in the latter example is a=b=c ,
and the final semicolon is optional.
All connection strings share the same basic syntax described above. The set of recognized keywords depends on
the provider. The Microsoft SqlClient data provider for SQL Server supports many keywords from older APIs,
but is generally more flexible and accepts synonyms for many of the common connection string keywords.
Typing mistakes can cause errors. For example, Integrated Security=true is valid, but IntegratedSecurity=true
causes an error.
Connection strings constructed manually at run time from invalidated user input are vulnerable to string-
injection attacks and jeopardize security at the data source. To address these problems, the
SqlConnectionStringBuilder class has been created. This connection string builder class exposes parameters as
strongly typed properties, and makes it possible to validate the connection string before it's sent to the data
source.

In this section
Connection String Builder
Demonstrates how to use the ConnectionStringBuilder class to construct valid connection strings at run time.
Connection Strings and Configuration Files
Demonstrates how to store and retrieve connection strings in configuration files.
Connection String Syntax
Describes how to configure provider-specific connection strings for SqlClient .
Protecting Connection Information
Demonstrates techniques for protecting information used to connect to a data source.

See also
Microsoft ADO.NET for SQL Server
Connection string builders
4/27/2022 • 3 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
In earlier versions of ADO.NET, compile-time checking of connection strings with concatenated string values
didn't occur, so that at run time, an incorrect keyword generated an ArgumentException. The Microsoft SqlClient
Data Provider for SQL Server includes the connection string builder class
Microsoft.Data.SqlClient.SqlConnectionStringBuilder that inherits from DbConnectionStringBuilder.

Connection string injection attacks


A connection string injection attack can occur when dynamic string concatenation is used to build connection
strings that are based on user input. If the string isn't validated and malicious text or characters not escaped, an
attacker can potentially access sensitive data or other resources on the server. For example, an attacker could
mount an attack by supplying a semicolon and appending another value. The connection string is parsed by
using a "last one wins " algorithm, and the hostile input is replaced for a legitimate value.
The connection string builder classes are designed to eliminate guesswork and protect against syntax errors and
security vulnerabilities. They provide methods and properties corresponding to the known key/value pairs
permitted by the data provider. Each class maintains a fixed collection of synonyms and can translate from a
synonym to the corresponding well-known key name. Checks are done for valid key/value pairs and an invalid
pair throws an exception. Also, injected values are handled in a safe manner.
The following example demonstrates how the SqlConnectionStringBuilder handles an inserted extra value for
the Initial Catalog setting.

SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();


builder.DataSource = "(local)";
builder.IntegratedSecurity = true;
builder.InitialCatalog = "AdventureWorks;NewValue=Bad";
Console.WriteLine(builder.ConnectionString);

The output shows that the SqlConnectionStringBuilder handled it correctly by escaping the extra value in double
quotation marks instead of appending it to the connection string as a new key/value pair.

data source=(local);Integrated Security=True;


initial catalog="AdventureWorks;NewValue=Bad"

Build connection strings from configuration files


If certain elements of a connection string are known beforehand, they can be stored in a configuration file and
retrieved at run time to construct a complete connection string. For example, the name of the database might be
known in advance, but not the name of the server. Or you might want a user to supply a name and password at
run time without the ability to inject other values into the connection string.
One of the overloaded constructors for a connection string builder takes a String as an argument, which enables
you to supply a partial connection string that can then be completed from user input. The partial connection
string can be stored in a configuration file and retrieved at run time.
NOTE
The System.Configuration namespace allows programmatic access to configuration files that use the
WebConfigurationManager for Web applications and the ConfigurationManager for Windows applications. For more
information about working with connection strings and configuration files, see Connection Strings and Configuration Files.

Example
This example demonstrates retrieving a partial connection string from a configuration file and completing it by
setting the DataSource, UserID, and Password properties of the SqlConnectionStringBuilder. The configuration
file is defined as follows.

<connectionStrings>
<clear/>
<add name="partialConnectString"
connectionString="Initial Catalog=Northwind;"
providerName="Microsoft.Data.SqlClient" />
</connectionStrings>

NOTE
You must set a reference to the System.Configuration.dll in your project for the code to run.

private static void BuildConnectionString(string dataSource,


string userName, string userPassword)
{
// Retrieve the partial connection string named databaseConnection
// from the application's app.config or web.config file.
ConnectionStringSettings settings =
ConfigurationManager.ConnectionStrings["partialConnectString"];

if (null != settings)
{
// Retrieve the partial connection string.
string connectString = settings.ConnectionString;
Console.WriteLine("Original: {0}", connectString);

// Create a new SqlConnectionStringBuilder based on the


// partial connection string retrieved from the config file.
SqlConnectionStringBuilder builder =
new SqlConnectionStringBuilder(connectString);

// Supply the additional values.


builder.DataSource = dataSource;
builder.UserID = userName;
builder.Password = userPassword;
Console.WriteLine("Modified: {0}", builder.ConnectionString);
}
}

See also
Connection strings
Microsoft ADO.NET for SQL Server
Connection strings and configuration files
4/27/2022 • 10 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Embedding connection strings in your application's code can lead to security vulnerabilities and maintenance
problems. Unencrypted connection strings compiled into an application's source code can be viewed using the
Ildasm.exe (IL Disassembler) tool. Moreover, if the connection string ever changes, your application must be
recompiled. For these reasons, we recommend storing connection strings in an application configuration file.

Work with application configuration files


Application configuration files contain settings that are specific to a particular application. For example, an
ASP.NET application can have one or more web.config files, and a Windows application can have an optional
app.config file. Configuration files share common elements, although the name and location of a configuration
file vary depending on the application's host.
The connectionStrings section
Connection strings can be stored as key/value pairs in the connectionStrings section of the configuration
element of an application configuration file. Child elements include add , clear , and remove .
The following configuration file fragment demonstrates the schema and syntax for storing a connection string.
The name attribute is a name that you provide to uniquely identify a connection string so that it can be
retrieved at run time. The providerName is Microsoft.Data.SqlClient with Microsoft SqlClient Data Provider
for SQL Server.

<?xml version='1.0' encoding='utf-8'?>


<configuration>
<connectionStrings>
<clear />
<add name="Name"
providerName="Microsoft.Data.SqlClient"
connectionString="Valid Connection String;" />
</connectionStrings>
</configuration>

NOTE
You can save part of a connection string in a configuration file and use the DbConnectionStringBuilder class to complete it
at run time. This is useful in scenarios where you do not know elements of the connection string ahead of time, or when
you do not want to save sensitive information in a configuration file. For more information, see Connection String
Builders.

Use external configuration files


External configuration files are separate files that contain a fragment of a configuration file consisting of a single
section. The external configuration file is then referenced by the main configuration file. Storing the
connectionStrings section in a physically separate file is useful in situations where connection strings may be
edited after the application is deployed. For example, the standard ASP.NET behavior is to restart an application
domain when configuration files are modified, which results in state information being lost. However, modifying
an external configuration file does not cause an application restart. External configuration files are not limited to
ASP.NET; they can also be used by Windows applications. In addition, file access security and permissions can be
used to restrict access to external configuration files. Working with external configuration files at run time is
transparent, and requires no special coding.
To store connection strings in an external configuration file, create a separate file that contains only the
connectionStrings section. Do not include any additional elements, sections, or attributes. This example shows
the syntax for an external configuration file.

<connectionStrings>
<add name="Name"
providerName="Microsoft.Data.SqlClient"
connectionString="Valid Connection String;" />
</connectionStrings>

In the main application configuration file, you use the configSource attribute to specify the fully qualified name
and location of the external file. This example refers to an external configuration file named connections.config .

<?xml version='1.0' encoding='utf-8'?>


<configuration>
<connectionStrings configSource="connections.config"/>
</configuration>

Retrieving Connection Strings at Run Time


The .NET Framework 2.0 introduced new classes in the System.Configuration namespace to simplify retrieving
connection strings from configuration files at run time. You can programmatically retrieve a connection string by
name or by provider name.

NOTE
The machine.config file also contains a connectionStrings section, which contains connection strings used by Visual
Studio. When retrieving connection strings by provider name from the app.config file in a Windows application, the
connection strings in machine.config get loaded first, and then the entries from app.config . Adding clear immediately
after the connectionStrings element removes all inherited references from the data structure in memory, so that only
the connection strings defined in the local app.config file are considered.

Work with the configuration files


Starting with the .NET Framework 2.0, ConfigurationManager is used when working with configuration files on
the local computer, replacing the deprecated ConfigurationSettings. WebConfigurationManager is used to work
with ASP.NET configuration files. It is designed to work with configuration files on a Web server, and allows
programmatic access to configuration file sections such as system.web .

NOTE
Accessing configuration files at run time requires granting permissions to the caller; the required permissions depend on
the type of application, configuration file, and location. For more information, see Using the Configuration Classes and
WebConfigurationManager for ASP.NET applications, and ConfigurationManager for Windows applications.

You can use the ConnectionStringSettingsCollection to retrieve connection strings from application
configuration files. It contains a collection of ConnectionStringSettings objects, each of which represents a single
entry in the connectionStrings section. Its properties map to connection string attributes, allowing you to
retrieve a connection string by specifying the name or the provider name.
P RO P ERT Y DESC RIP T IO N

Name The name of the connection string. Maps to the name


attribute.

ProviderName The fully qualified provider name. Maps to the


providerName attribute.

ConnectionString The connection string. Maps to the connectionString


attribute.

Example: Listing all connection strings


This example iterates through the ConnectionStringSettingsCollection and displays the
ConnectionStringSettings.Name, ConnectionStringSettings.ProviderName, and
ConnectionStringSettings.ConnectionString properties in the console window.

NOTE
System.Configuration.dll is not included in all project types, and you may need to set a reference to it in order to use the
configuration classes. The name and location of a particular application configuration file varies by the type of application
and the hosting process.

using System.Configuration;

class Program
{
static void Main()
{
GetConnectionStrings();
Console.ReadLine();
}

static void GetConnectionStrings()


{
ConnectionStringSettingsCollection settings =
ConfigurationManager.ConnectionStrings;

if (settings != null)
{
foreach(ConnectionStringSettings cs in settings)
{
Console.WriteLine(cs.Name);
Console.WriteLine(cs.ProviderName);
Console.WriteLine(cs.ConnectionString);
}
}
}
}

Example: Retrieving a connection string by name


This example demonstrates how to retrieve a connection string from a configuration file by specifying its name.
The code creates a ConnectionStringSettings object, matching the supplied input parameter to the
ConnectionStrings name. If no matching name is found, the function returns null ( Nothing in Visual Basic).
// Retrieves a connection string by name.
// Returns null if the name is not found.
static string GetConnectionStringByName(string name)
{
// Assume failure.
string returnValue = null;

// Look for the name in the connectionStrings section.


ConnectionStringSettings settings =
ConfigurationManager.ConnectionStrings[name];

// If found, return the connection string.


if (settings != null)
returnValue = settings.ConnectionString;

return returnValue;
}

Example: Retrieving a connection string by provider name


This example demonstrates how to retrieve a connection string by specifying the provider name in the format
Microsoft.Data.SqlClient. The code iterates through the ConnectionStringSettingsCollection and returns the
connection string for the first ProviderName found. If the provider name is not found, the function returns null
( Nothing in Visual Basic).

// Retrieve a connection string by specifying the providerName.


// Assumes one connection string per provider in the config file.
static string GetConnectionStringByProvider(string providerName)
{
// Return null on failure.
string returnValue = null;

// Get the collection of connection strings.


ConnectionStringSettingsCollection settings =
ConfigurationManager.ConnectionStrings;

// Walk through the collection and return the first


// connection string matching the providerName.
if (settings != null)
{
foreach (ConnectionStringSettings cs in settings)
{
if (cs.ProviderName == providerName)
returnValue = cs.ConnectionString;
break;
}
}
return returnValue;
}

Encrypt configuration file sections using protected configuration


ASP.NET 2.0 introduced a new feature, called protected configuration, that enables you to encrypt sensitive
information in a configuration file. Although primarily designed for ASP.NET, protected configuration can also be
used to encrypt configuration file sections in Windows applications. For a detailed description of the protected
configuration capabilities, see Encrypting Configuration Information Using Protected Configuration.
The following configuration file fragment shows the connectionStrings section after it has been encrypted.
The configProtectionProvider specifies the protected configuration provider used to encrypt and decrypt the
connection strings. The Encr yptedData section contains the cipher text.
<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData>
<CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAH2... </CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>

When the encrypted connection string is retrieved at run time, the .NET Framework uses the specified provider
to decrypt the CipherValue and make it available to your application. You do not need to write any additional
code to manage the decryption process.
Protected configuration providers
Protected configuration providers are registered in the configProtectedData section of the machine.config
file on the local computer, as shown in the following fragment, which shows the two protected configuration
providers supplied with the .NET Framework. The values shown here have been truncated for readability.

<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">
<providers>
<add name="RsaProtectedConfigurationProvider"
type="System.Configuration.RsaProtectedConfigurationProvider" />
<add name="DataProtectionConfigurationProvider"
type="System.Configuration.DpapiProtectedConfigurationProvider" />
</providers>
</configProtectedData>

You can configure additional protected configuration providers by adding them to the machine.config file. You
can also create your own protected configuration provider by inheriting from the
ProtectedConfigurationProvider abstract base class. The following table describes the two configuration files
included with the .NET Framework.

P RO VIDER DESC RIP T IO N

RsaProtectedConfigurationProvider Uses the RSA encryption algorithm to encrypt and decrypt


data. The RSA algorithm can be used for both public key
encryption and digital signatures. It is also known as "public
key" or asymmetrical encryption because it employs two
different keys. You can use the ASP.NET IIS Registration Tool
(Aspnet_regiis.exe) to encrypt sections in a Web.config file
and manage the encryption keys. ASP.NET decrypts the
configuration file when it processes the file. The identity of
the ASP.NET application must have read access to the
encryption key that is used to encrypt and decrypt the
encrypted sections.

DpapiProtectedConfigurationProvider Uses the Windows Data Protection API (DPAPI) to encrypt


configuration sections. It uses the Windows built-in
cryptographic services and can be configured for either
machine-specific or user-account-specific protection.
Machine-specific protection is useful for multiple applications
on the same server that need to share information. User-
account-specific protection can be used with services that
run with a specific user identity, such as a shared hosting
environment. Each application runs under a separate
identity, which restricts access to resources such as files and
databases.

Both providers offer strong encryption of data. However, if you are planning to use the same encrypted
configuration file on multiple servers, such as a Web farm, only the RsaProtectedConfigurationProvider enables
you to export the encryption keys used to encrypt the data and import them on another server. For more
information, see Importing and Exporting Protected Configuration RSA Key Containers.
Use the configuration classes
The System.Configuration namespace provides classes to work with configuration settings programmatically.
The ConfigurationManager class provides access to machine, application, and user configuration files. If you are
creating an ASP.NET application, you can use the WebConfigurationManager class, which provides the same
functionality while also allowing you to access settings that are unique to ASP.NET applications, such as those
found in <system.web> .

NOTE
The System.Security.Cryptography namespace contains classes that provide additional options for encrypting and
decrypting data. Use these classes if you require cryptographic services that are not available using protected
configuration. Some of these classes are wrappers for the unmanaged Microsoft CryptoAPI, while others are purely
managed implementations. For more information, see Cryptographic Services.

App.config example
This example demonstrates how to toggle encrypting the connectionStrings section in an app.config file for
a Windows application. In this example, the procedure takes the name of the application as an argument, for
example, "MyApplication.exe". The app.config file will then be encrypted and copied to the folder that contains
the executable under the name of "MyApplication.exe.config".

NOTE
The connection string can only be decrypted on the computer on which it was encrypted.

The code uses the OpenExeConfiguration method to open the app.config file for editing, and the GetSection
method returns the connectionStrings section. The code then checks the IsProtected property, calling the
ProtectSection to encrypt the section if it is not encrypted. The UnprotectSection method is invoked to decrypt
the section. The Save method completes the operation and saves the changes.

NOTE
You must set a reference to System.Configuration.dll in your project for the code to run.
static void ToggleConfigEncryption(string exeFile)
{
// Takes the executable file name without the
// .config extension.
try
{
// Open the configuration file and retrieve
// the connectionStrings section.
Configuration config = ConfigurationManager.
OpenExeConfiguration(exeConfigName);

ConnectionStringsSection section =
config.GetSection("connectionStrings")
as ConnectionStringsSection;

if (section.SectionInformation.IsProtected)
{
// Remove encryption.
section.SectionInformation.UnprotectSection();
}
else
{
// Encrypt the section.
section.SectionInformation.ProtectSection(
"DataProtectionConfigurationProvider");
}
// Save the current configuration.
config.Save();

Console.WriteLine("Protected={0}",
section.SectionInformation.IsProtected);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

Web.config example
This example uses the OpenWebConfiguration method of the WebConfigurationManager . Note that in this case
you can supply the relative path to the Web.config file by using a tilde. The code requires a reference to the
System.Web.Configuration class.
static void ToggleWebEncrypt()
{
// Open the Web.config file.
Configuration config = WebConfigurationManager.
OpenWebConfiguration("~");

// Get the connectionStrings section.


ConnectionStringsSection section =
config.GetSection("connectionStrings")
as ConnectionStringsSection;

// Toggle encryption.
if (section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
}
else
{
section.SectionInformation.ProtectSection(
"DataProtectionConfigurationProvider");
}

// Save changes to the Web.config file.


config.Save();
}

For more information about securing ASP.NET applications, see Securing ASP.NET web sites.

See also
Connection string builders
Protecting connection information
Using the configuration classes
Configuring apps
ASP.NET web site administration
Microsoft ADO.NET for SQL Server
Connection string syntax
4/27/2022 • 4 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The Microsoft.Data.SqlClient has a Connection object that inherits from DbConnection as well as a provider-
specific ConnectionString property. The specific connection string syntax for the SqlClient provider is
documented in its ConnectionString property. For more information on connection string syntax, see
ConnectionString.

Connection string builders


Microsoft SqlClient Data Provider for SQL Server introduced the following connection string builder.
SqlConnectionStringBuilder
The connection string builders allow you to construct syntactically valid connection strings at run time, so you
do not have to manually concatenate connection string values in your code. For more information, see
Connection String Builders.

Windows authentication
We recommend using Windows Authentication (sometimes referred to as integrated security) to connect to data
sources that support it. The following table shows the Windows Authentication syntax used with the Microsoft
SqlClient Data Provider for SQL Server.

P RO VIDER SY N TA X

SqlClient Integrated Security=true;

-- or --

Integrated Security=SSPI;

SqlClient connection strings


The syntax for a SqlConnection connection string is documented in the SqlConnection.ConnectionString
property. You can use the ConnectionString property to get or set a connection string for a SQL Server database.
The connection string keywords also map to properties in the SqlConnectionStringBuilder.

IMPORTANT
The default setting for the Persist Security Info keyword is false . Setting it to true or yes allows security-
sensitive information, including the user ID and password, to be obtained from the connection after the connection has
been opened. Keep Persist Security Info set to false to ensure that an untrusted source does not have access to
sensitive connection string information.

Windows authentication with SqlClient


Each of the following forms of syntax uses Windows Authentication to connect to the AdventureWorks
database on a local server.

"Persist Security Info=False;Integrated Security=true;


Initial Catalog=AdventureWorks;Server=MSSQL1"
"Persist Security Info=False;Integrated Security=SSPI;
database=AdventureWorks;server=(local)"
"Persist Security Info=False;Trusted_Connection=True;
database=AdventureWorks;server=(local)"

SQL Server authentication with SqlClient


Windows Authentication is preferred for connecting to SQL Server. However, if SQL Server Authentication is
required, use the following syntax to specify a user name and password. In this example, asterisks are used to
represent a valid user name and password.

"Persist Security Info=False;User ID=*****;Password=*****;Initial Catalog=AdventureWorks;Server=MySqlServer"

When you connect to Azure SQL Database or to Azure Synapse Analytics and provide a login in the format
user@servername , make sure that the servername value in the login matches the value provided for Server= .

NOTE
Windows authentication takes precedence over SQL Server logins. If you specify both Integrated Security=true as well as
a user name and password, the user name and password will be ignored and Windows authentication will be used.

Connect to a named instance of SQL Server


To connect to a named instance of SQL Server, use the server name\instance name syntax.

"Data Source=MySqlServer\MSSQL1;"

You can also set the DataSource property of the SqlConnectionStringBuilder to the instance name when
building a connection string. The DataSource property of a SqlConnection object is read-only.
Type system version changes
The Type System Version keyword in a SqlConnection.ConnectionString specifies the client-side representation
of SQL Server types. See SqlConnection.ConnectionString for more information about the Type System Version
keyword.

Connect and Attach to SQL Server Express user instances


User instances are a feature in SQL Server Express. They allow a user running on a least-privileged local
Windows account to attach and run a SQL Server database without requiring administrative privileges. A user
instance executes with the user's Windows credentials, not as a service.
For more information on working with user instances, see SQL Server Express User Instances.

Use TrustServerCertificate
The TrustServerCertificate keyword is valid only when connecting to a SQL Server instance with a valid
certificate. When TrustServerCertificate is set to true , the transport layer will use TLS/SSL to encrypt the
channel and bypass walking the certificate chain to validate trust.
"TrustServerCertificate=true;"

NOTE
If TrustServerCertificate is set to true and encryption is turned on, the encryption level specified on the server will
be used even if Encrypt is set to false in the connection string. The connection will fail otherwise.

Enable encryption
To enable encryption when a certificate has not been provisioned on the server, the Trust Ser ver Cer tificate
connection property must be set. In this case, encryption will use a self-signed server certificate without
validation since no verifiable certificate has been provisioned on the server.
Application settings cannot reduce the level of security configured in SQL Server, but can optionally strengthen
it. An application can request encryption by setting the TrustServerCertificate and Encrypt keywords to true
, guaranteeing that encryption takes place even when a server certificate has not been provisioned. However, if
TrustServerCertificate is not enabled in the client configuration, a provisioned server certificate is still
required.
The following table describes all cases.

EN C RY P T C O N N EC T IO N T RUST SERVER C ERT IF IC AT E


ST RIN G/ AT T RIB UT E C O N N EC T IO N ST RIN G/ AT T RIB UT E RESULT

No Ignored No encryption occurs.

Yes No Encryption occurs only if there is a


verifiable server certificate, otherwise
the connection attempt fails.

Yes Yes Encryption always occurs, but may use


a self-signed server certificate.

For more information, see Using Encryption Without Validation.

See also
Connection strings
Connecting to a data source
Microsoft ADO.NET for SQL Server
Protecting connection information
4/27/2022 • 3 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Protecting access to your data source is one of the most important goals when securing an application. A
connection string presents a potential vulnerability if it is not secured. Storing connection information in plain
text or persisting it in memory risks compromising your entire system. Connection strings embedded in your
source code can be read using the Ildasm.exe (IL Disassembler) to view Microsoft intermediate language (MSIL)
in a compiled assembly.
Security vulnerabilities involving connection strings can arise based on the type of authentication used, how
connection strings are persisted in memory and on disk, and the techniques used to construct them at run time.

Use Windows authentication


To help limit access to your data source, you must secure connection information such as user ID, password, and
data source name. In order to avoid exposing user information, we recommend using Windows authentication
(sometimes referred to as integrated security) wherever possible. Windows authentication is specified in a
connection string by using the Integrated Security or Trusted_Connection keywords, eliminating the need to
use a user ID and password. When using Windows authentication, users are authenticated by Windows, and
access to server and database resources is determined by granting permissions to Windows users and groups.
For situations where it is not possible to use Windows authentication, you must use extra care because user
credentials are exposed in the connection string. In an ASP.NET application, you can configure a Windows
account as a fixed identity that is used to connect to databases and other network resources. You enable
impersonation in the identity element in the web.config file and specify a user name and password.

<identity impersonate="true"
userName="MyDomain\UserAccount"
password="*****" />

The fixed identity account should be a low-privilege account that has been granted only necessary permissions
in the database. In addition, you should encrypt the configuration file so that the user name and password are
not exposed in clear text.

Avoid injection attacks with connection string builders


A connection string injection attack can occur when dynamic string concatenation is used to build connection
strings based on user input. If the user input is not validated and malicious text or characters not escaped, an
attacker can potentially access sensitive data or other resources on the server. To address this problem,
Microsoft SqlClient Data Provider for SQL Server introduced new connection string builder class to validate
connection string syntax and ensure that additional parameters are not introduced. For more information, see
Connection String Builders.

Use "Persist Security Info=false"


The default value for Persist Security Info is false; we recommend using this default in all connection strings.
Setting Persist Security Info to true or yes allows security-sensitive information, including the user ID and
password, to be obtained from a connection after it has been opened. When Persist Security Info is set to
false or no , security information is discarded after it is used to open the connection, ensuring that an
untrusted source does not have access to security-sensitive information.

Encrypt configuration files


APPLIES TO: .NET Framework .NET Core .NET Standard
You can also store connection strings in configuration files, which eliminates the need to embed them in your
application's code. Configuration files are standard XML files for which the .NET Framework has defined a
common set of elements. Connection strings in configuration files are typically stored inside the
<connectionStrings> element in the app.config for a Windows application, or the web.config file for an
ASP.NET application. For more information on the basics of storing, retrieving, and encrypting connection strings
from configuration files, see Connection Strings and Configuration Files.

See also
Encrypting Configuration Information Using Protected Configuration
Microsoft ADO.NET for SQL Server
Connection pooling
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Connecting to a data source can be time consuming. To minimize the cost of opening connections, ADO.NET
uses an optimization technique called connection pooling, which minimizes the cost of repeatedly opening and
closing connections.

In this section
SQL Server Connection Pooling (ADO.NET)
Provides an overview of connection pooling and describes how connection pooling works in SQL Server.

See also
Retrieving and modifying data in ADO.NET
Microsoft ADO.NET for SQL Server
SQL Server connection pooling (ADO.NET)
4/27/2022 • 10 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Connecting to a database server typically consists of several time-consuming steps. A physical channel such as a
socket or a named pipe must be established, the initial handshake with the server must occur, the connection
string information must be parsed, the connection must be authenticated by the server, checks must be run for
enlisting in the current transaction, and so on.
In practice, most applications use only one or a few different configurations for connections. This means that
during application execution, many identical connections will be repeatedly opened and closed. To minimize the
cost of opening connections, Microsoft SqlClient Data Provider for SQL Server uses an optimization technique
called connection pooling.
Connection pooling reduces the number of times that new connections must be opened. The pooler maintains
ownership of the physical connection. It manages connections by keeping alive a set of active connections for
each given connection configuration. Whenever a user calls Open on a connection, the pooler looks for an
available connection in the pool. If a pooled connection is available, it returns it to the caller instead of opening a
new connection. When the application calls Close on the connection, the pooler returns it to the pooled set of
active connections instead of closing it. Once the connection is returned to the pool, it is ready to be reused on
the next Open call.
Only connections with the same configuration can be pooled. Microsoft SqlClient Data Provider for SQL Server
keeps several pools at the same time, one for each configuration. Connections are separated into pools by
connection string, and by Windows identity when integrated security is used. Connections are also pooled based
on whether they are enlisted in a transaction. When using ChangePassword, the SqlCredential instance affects
the connection pool. Different instances of SqlCredential will use different connection pools, even if the user ID
and password are the same.
Pooling connections can significantly enhance the performance and scalability of your application. By default,
connection pooling is enabled in the Microsoft SqlClient Data Provider for SQL Server. Unless you explicitly
disable it, the pooler optimizes the connections as they are opened and closed in your application. You can also
supply several connection string modifiers to control connection pooling behavior. For more information, see
"Controlling Connection Pooling with Connection String Keywords " later in this topic.

IMPORTANT
When connection pooling is enabled, and if a timeout error or other login error occurs, an exception will be thrown and
subsequent connection attempts will fail for the next 5 seconds, the " blocking period ". If the application attempts to
connect within the blocking period, the first exception will be thrown again. Subsequent failures after a blocking period
ends will result in a new blocking periods that is twice as long as the previous blocking period, up to a maximum of 1
minute.

NOTE
The " blocking period " mechanism doesn't apply to Azure SQL Server by default. This behavior can be changed by
modifying the PoolBlockingPeriod property in ConnectionString except for .NET Standard.
Pool creation and assignment
When a connection is first opened, a connection pool is created based on an exact matching algorithm that
associates the pool with the connection string in the connection. Each connection pool is associated with a
distinct connection string. When a new connection is opened, if the connection string is not an exact match to an
existing pool, a new pool is created.

NOTE
Connections are pooled per process, per application domain, per connection string and when integrated security is used,
per Windows identity. Connection strings must also be an exact match; keywords supplied in a different order for the
same connection will be pooled separately.

NOTE
If MinPoolSize is either not specified in the connection string or is specified as zero, the connections in the pool will be
closed after a period of inactivity. However, if the specified MinPoolSize is greater than zero, the connection pool is not
destroyed until the AppDomain is unloaded and the process ends. Maintenance of inactive or empty pools involves
minimal system overhead.

NOTE
The pool is automatically cleared when a fatal error occurs, such as a failover.

In the following C# example, three new SqlConnection objects are created, but only two connection pools are
required to manage them. Note that the first and second connection strings differ by the value assigned for
Initial Catalog .

using (SqlConnection connection = new SqlConnection(


"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// Pool A is created.
}

using (SqlConnection connection = new SqlConnection(


"Integrated Security=SSPI;Initial Catalog=pubs"))
{
connection.Open();
// Pool B is created because the connection strings differ.
}

using (SqlConnection connection = new SqlConnection(


"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// The connection string matches pool A.
}

Add connections
A connection pool is created for each unique connection string. When a pool is created, multiple connection
objects are created and added to the pool so that the minimum pool size requirement is satisfied. Connections
are added to the pool as needed, up to the maximum pool size specified (100 is the default ). Connections are
released back into the pool when they are closed or disposed.
When a SqlConnection object is requested, it is obtained from the pool if a usable connection is available. To be
usable, a connection must be unused, have a matching transaction context or be unassociated with any
transaction context, and have a valid link to the server.
The connection pooler satisfies requests for connections by reallocating connections as they are released back
into the pool. If the maximum pool size has been reached and no usable connection is available, the request is
queued. The pooler then tries to reclaim any connections until the time-out is reached (the default is 15
seconds ). If the pooler cannot satisfy the request before the connection times out, an exception is thrown.
Cau t i on

We strongly recommend that you always close the connection when you are finished using it so that the
connection will be returned to the pool. You can do this using either the Close or Dispose methods of the
Connection object, or by opening all connections inside a using statement in C#, or a Using statement in
Visual Basic. Connections that are not explicitly closed might not be added or returned to the pool. For more
information, see using Statement or How to: Dispose of a System Resource for Visual Basic.

NOTE
Do not call Close or Dispose on a Connection , a DataReader , or any other managed object in the Finalize
method of your class. In a finalizer, only release unmanaged resources that your class owns directly. If your class does not
own any unmanaged resources, do not include a Finalize method in your class definition. For more information, see
Garbage Collection.

For more info about the events associated with opening and closing connections, see Audit Login Event Class
and Audit Logout Event Class in the SQL Server documentation.

Remove connections
The connection pooler removes a connection from the pool after it has been idle for approximately 4-8 minutes,
or if the pooler detects that the connection with the server has been severed.

NOTE
A severed connection can be detected only after attempting to communicate with the server. If a connection is found that
is no longer connected to the server, it is marked as invalid. Invalid connections are removed from the connection pool
only when they are closed or reclaimed.

If a connection exists to a server that has disappeared, this connection can be drawn from the pool even if the
connection pooler has not detected the severed connection and marked it as invalid. This is the case because the
overhead of checking that the connection is still valid would eliminate the benefits of having a pooler by causing
another round trip to the server to occur. When this occurs, the first attempt to use the connection will detect
that the connection has been severed, and an exception is thrown.

Clear the pool


Microsoft SqlClient Data Provider for SQL Server introduced two new methods to clear the pool: ClearAllPools
and ClearPool. ClearAllPools clears the connection pools for a given provider, and ClearPool clears the
connection pool that is associated with a specific connection.

NOTE
If there are connections being used at the time of the call, they are marked appropriately. When they are closed, they are
discarded instead of being returned to the pool.
Transaction support
Connections are drawn from the pool and assigned based on transaction context. Unless Enlist=false is
specified in the connection string, the connection pool makes sure that the connection is enlisted in the Current
context. When a connection is closed and returned to the pool with an enlisted System.Transactions transaction,
it is set aside in such a way that the next request for that connection pool with the same System.Transactions
transaction will return the same connection if it is available. If such a request is issued, and there are no pooled
connections available, a connection is drawn from the non-transacted part of the pool and enlisted. If no
connections are available in either area of the pool, a new connection is created and enlisted.
When a connection is closed, it is released back into the pool and into the appropriate subdivision based on its
transaction context. Therefore, you can close the connection without generating an error, even though a
distributed transaction is still pending. This allows you to commit or abort the distributed transaction later.

Control connection pooling with connection string keywords


The ConnectionString property of the SqlConnection object supports connection string key/value pairs that can
be used to adjust the behavior of the connection pooling logic. For more information, see ConnectionString.

Pool fragmentation
Pool fragmentation is a common problem in many Web applications where the application can create a large
number of pools that are not freed until the process exits. This leaves a large number of connections open and
consuming memory, which results in poor performance.
Pool fragmentation due to integrated security
Connections are pooled according to the connection string plus the user identity. Therefore, if you use Basic
authentication or Windows Authentication on the Web site and an integrated security login, you get one pool
per user. Although this improves the performance of subsequent database requests for a single user, that user
cannot take advantage of connections made by other users. It also results in at least one connection per user to
the database server. This is a side effect of a particular Web application architecture that developers must weigh
against security and auditing requirements.
Pool fragmentation due to many databases
Many Internet service providers host several Web sites on a single server. They may use a single database to
confirm a Forms authentication login and then open a connection to a specific database for that user or group of
users. The connection to the authentication database is pooled and used by everyone. However, there is a
separate pool of connections to each database, which increase the number of connections to the server.
This is also a side-effect of the application design. There is a relatively simple way to avoid this side effect
without compromising security when you connect to SQL Server. Instead of connecting to a separate database
for each user or group, connect to the same database on the server and then execute the Transact-SQL USE
statement to change to the desired database.
The following code fragment demonstrates creating an initial connection to the master database and then
switching to the desired database specified in the databaseName string variable.
// Assume that connectionString connects to master.
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand())
{
connection.Open();
command.Connection = connection;
command.Text = "USE DatabaseName";
command.ExecuteNonQuery();
}

Application roles and connection pooling


After a SQL Server application role has been activated by calling the sp_setapprole system stored procedure,
the security context of that connection cannot be reset. However, if pooling is enabled, the connection is returned
to the pool, and an error occurs when the pooled connection is reused.
Application role alternatives
We recommend that you take advantage of security mechanisms that you can use instead of application roles.

See also
Connection pooling
SQL Server and ADO.NET - Diagnostic counters in SqlClient
Microsoft ADO.NET for SQL Server
Commands and parameters
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
After establishing a connection to a data source, you can execute commands and return results from the data
source using a DbCommand object. You can create a command using one of the command constructors for the
Microsoft SqlClient Data Provider for SQL Server. Constructors can take optional arguments, such as an SQL
statement to execute at the data source, a DbConnection object, or a DbTransaction object.
You can also configure those objects as properties of the command. You can also create a command for a
particular connection using the CreateCommand method of a DbConnection object. The SQL statement being
executed by the command can be configured using the CommandText property. The Microsoft SqlClient Data
Provider for SQL Server has the SqlCommand object.

In this section
Executing a Command
Describes the ADO.NET Command object and how to use it to execute queries and commands against a data
source.
Configuring parameters
Describes working with Command parameters, including direction, data types, and parameter syntax.
Generating commands with CommandBuilders
Describes how to use command builders to automatically generate INSERT, UPDATE, and DELETE commands for
a DataAdapter that has a single-table SELECT command.
Obtaining a single value from a database
Describes how to use the ExecuteScalar method of a Command object to return a single value from a database
query.
Using commands to modify data
Describes how to use the Microsoft SqlClient data provider for SQL Server to execute stored procedures or data
definition language (DDL) statements.

See also
DataAdapters and DataReaders
Connecting to a data source
Microsoft ADO.NET for SQL Server
Executing a command
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The Microsoft SqlClient Data Provider for SQL Server has SqlCommand object that inherits from DbCommand.
This object exposes methods for executing commands based on the type of command and desired return value,
as described in the following table.

C OMMAND RET URN VA L UE

ExecuteReader Returns a DataReader object.

ExecuteScalar Returns a single scalar value.

ExecuteNonQuery Executes a command that does not return any rows.

ExecuteXMLReader Returns an XmlReader. Available for a SqlCommand object


only.

Each strongly typed command object also supports a CommandType enumeration that specifies how a
command string is interpreted, as described in the following table.

C O M M A N DT Y P E DESC RIP T IO N

Text An SQL command defining the statements to be executed at


the data source.

StoredProcedure The name of the stored procedure. You can use the
Parameters property of a command to access input and
output parameters and return values, regardless of which
Execute method is called.

TableDirect The name of a table.

IMPORTANT
When using ExecuteReader , return values and output parameters will not be accessible until the DataReader is closed.

Example
The following code example demonstrates how to create a SqlCommand object to execute a stored procedure
by setting its properties. A SqlParameter object is used to specify the input parameter to the stored procedure.
The command is executed using the ExecuteReader method, and the output from the SqlDataReader is displayed
in the console window.
static void GetSalesByCategory(string connectionString,
string categoryName)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create the command and set its properties.
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "SalesByCategory";
command.CommandType = CommandType.StoredProcedure;

// Add the input parameter and set its properties.


SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@CategoryName";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = categoryName;

// Add the parameter to the Parameters collection.


command.Parameters.Add(parameter);

// Open the connection and execute the reader.


connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}: {1:C}", reader[0], reader[1]);
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
}
}

Troubleshooting commands
The Microsoft SqlClient Data Provider for SQL Server adds diagnostic counters to enable you to detect
intermittent problems related to failed command executions. For more information, see Diagnostic counters in
SqlClient.

See also
Commands and parameters
DataAdapters and DataReaders
Microsoft ADO.NET for SQL Server
Configuring parameters
4/27/2022 • 6 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Command objects use parameters to pass values to SQL statements or stored procedures, providing type
checking and validation. Unlike command text, parameter input is treated as a literal value, not as executable
code. This behavior helps guard against "SQL injection" attacks, in which an attacker inserts a command that
compromises security on the server into an SQL statement.
Parameterized commands can also improve query execution performance, because they help the database
server accurately match the incoming command with a proper cached query plan. For more information, see
Execution Plan Caching and Reuse and Parameters and Execution Plan Reuse. In addition to the security and
performance benefits, parameterized commands provide a convenient method for organizing values passed to a
data source.
A DbParameter object can be created by using its constructor, or by adding it to the DbParameterCollection by
calling the Add method of the DbParameterCollection collection. The Add method will take as input either
constructor arguments or an existing parameter object, depending on the data provider.

Supply the ParameterDirection property


When adding parameters, you must supply a ParameterDirection property for parameters other than input
parameters. The following table shows the ParameterDirection values that you can use with the
ParameterDirection enumeration.

M EM B ER N A M E DESC RIP T IO N

Input The parameter is an input parameter. This value is the


default.

InputOutput The parameter can perform both input and output.

Output The parameter is an output parameter.

ReturnValue The parameter represents a return value from an operation


such as a stored procedure, built-in function, or user-defined
function.

Work with parameter placeholders


The syntax for parameter placeholders depends on the data source. The Microsoft SqlClient Data Provider for
SQL Server handles naming and specifying parameters and parameter placeholders differently. The SqlClient
data provider uses named parameters in the format @parametername .

Specify parameter data types


The data type of a parameter is specific to the Microsoft SqlClient Data Provider for SQL Server. Specifying the
type converts the value of the Parameter to the Microsoft SqlClient Data Provider for SQL Server type before
passing the value to the data source. You may also specify the type of a Parameter in a generic manner by
setting the DbType property of the Parameter object to a particular DbType.
The Microsoft SqlClient Data Provider for SQL Server type of a Parameter object is inferred from the .NET
Framework type of the Value of the Parameter object, or from the DbType of the Parameter object. The
following table shows the inferred Parameter type based on the object passed as the Parameter value or the
specified DbType .

. N ET T Y P E DBT Y P E SQ L DBT Y P E

Boolean Boolean Bit

Byte Byte TinyInt

byte[] Binary VarBinary . This implicit conversion


will fail if the byte array is larger than
the maximum size of a VarBinary ,
which is 8000 bytes. For byte arrays
larger than 8000 bytes, explicitly set
the SqlDbType.

Char Inferring a SqlDbType from char isn't


supported.

DateTime DateTime DateTime

DateTimeOffset DateTimeOffset DateTimeOffset in SQL Server 2008.


Inferring a SqlDbType from
DateTimeOffset isn't supported in
versions of SQL Server earlier than
SQL Server 2008.

Decimal Decimal Decimal

Double Double Float

Single Single Real

Guid Guid UniqueIdentifier

Int16 Int16 SmallInt

Int32 Int32 Int

Int64 Int64 BigInt

Object Object Variant

String String NVarChar . This implicit conversion will


fail if the string is larger than the
maximum size of an NVarChar , which
is 4000 characters. For strings larger
than 4000 characters, explicitly set the
SqlDbType.
. N ET T Y P E DBT Y P E SQ L DBT Y P E

TimeSpan Time Time in SQL Server 2008. Inferring a


SqlDbType from TimeSpan isn't
supported in versions of SQL Server
earlier than SQL Server 2008.

UInt16 UInt16 Inferring a SqlDbType from UInt16


isn't supported.

UInt32 UInt32 Inferring a SqlDbType from UInt32


isn't supported.

UInt64 UInt64 Inferring a SqlDbType from UInt64


isn't supported.

AnsiString VarChar

AnsiStringFixedLength Char

Currency Money

Date Date in SQL Server 2008. Inferring a


SqlDbType from Date isn't supported
in versions of SQL Server earlier than
SQL Server 2008.

SByte Inferring a SqlDbType from SByte


isn't supported.

StringFixedLength NChar

Time Time in SQL Server 2008. Inferring a


SqlDbType from Time isn't supported
in versions of SQL Server earlier than
SQL Server 2008.

VarNumeric Inferring a SqlDbType from


VarNumeric isn't supported.

user-defined type (an object with SqlClient always returns an Object SqlDbType.Udt if
SqlUserDefinedAggregateAttribute SqlUserDefinedTypeAttribute is
present, otherwise Variant

NOTE
Conversions from decimal to other types are narrowing conversions that round the decimal value to the nearest integer
value toward zero. If the result of the conversion isn't representable in the destination type, an OverflowException is
thrown.
NOTE
When you send a null parameter value to the server, you must specify DBNull, not null ( Nothing in Visual Basic). The
null value in the system is an empty object that has no value. DBNull is used to represent null values.

Derive parameter information


Parameters can also be derived from a stored procedure using the DbCommandBuilder class. The
SqlCommandBuilder class provides a static method, DeriveParameters , which automatically populates the
parameters collection of a command object that uses parameter information from a stored procedure.
DeriveParameters overwrites any existing parameter information for the command.

NOTE
Deriving parameter information incurs a performance penalty because it requires an additional round trip to the data
source to retrieve the information. If parameter information is known at design time, you can improve the performance of
your application by setting the parameters explicitly.

For more information, see Generating Commands with CommandBuilders.

Using parameters with a SqlCommand and a stored procedure


Stored procedures offer many advantages in data-driven applications. By using stored procedures, database
operations can be encapsulated in a single command, optimized for best performance, and enhanced with extra
security. Although a stored procedure can be called by passing the stored procedure name followed by
parameter arguments as an SQL statement, by using the Parameters collection of the ADO.NET DbCommand
object enables you to more explicitly define stored procedure parameters, and to access output parameters and
return values.

NOTE
Parameterized statements are executed on the server by using sp_executesql, which allows for query plan reuse. Local
cursors or variables in the sp_executesql batch are not visible to the batch that calls sp_executesql . Changes in
database context last only to the end of the sp_executesql statement. For more information, see sp_executesql
(Transact-SQL).

When using parameters with a SqlCommand to execute a SQL Server stored procedure, the names of the
parameters added to the Parameters collection must match the names of the parameter markers in the stored
procedure. The Microsoft SqlClient Data Provider for SQL Server doesn't support the question mark (?)
placeholder for passing parameters to an SQL statement or a stored procedure. It treats parameters in the
stored procedure as named parameters and searches for matching parameter markers. For example, the
CustOrderHist stored procedure is defined by using a parameter named @CustomerID . When your code
executes the stored procedure, it must also use a parameter named @CustomerID .

CREATE PROCEDURE dbo.CustOrderHist @CustomerID varchar(5)

Example
This example demonstrates how to call a SQL Server stored procedure in the Northwind sample database. The
name of the stored procedure is dbo.SalesByCategory and it has an input parameter named @CategoryName with
a data type of nvarchar(15) . The code creates a new SqlConnection inside a using block so that the connection
is disposed when the procedure ends. The SqlCommand and SqlParameter objects are created, and their
properties set. A SqlDataReader executes the SqlCommand and returns the result set from the stored procedure,
displaying the output in the console window.

NOTE
Instead of creating SqlCommand and SqlParameter objects and then setting properties in separate statements, you can
instead elect to use one of the overloaded constructors to set multiple properties in a single statement.

static void GetSalesByCategory(string connectionString,


string categoryName)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create the command and set its properties.
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "SalesByCategory";
command.CommandType = CommandType.StoredProcedure;

// Add the input parameter and set its properties.


SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@CategoryName";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = categoryName;

// Add the parameter to the Parameters collection.


command.Parameters.Add(parameter);

// Open the connection and execute the reader.


connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}: {1:C}", reader[0], reader[1]);
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
}
}

See also
Commands and parameters
DataAdapters and DataReaders
Data type mappings in ADO.NET
Microsoft ADO.NET for SQL Server
Generating commands with CommandBuilders
4/27/2022 • 6 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
When the SelectCommand property of the DbDataAdapter object is dynamically specified at run time, such as
through a query tool that takes a textual command from the user, you may not be able to specify the
appropriate InsertCommand , UpdateCommand , or DeleteCommand at design time. If your DataTable maps to or is
generated from a single database table, you can take advantage of the DbCommandBuilder object to
automatically generate the DeleteCommand , InsertCommand , and UpdateCommand of the DbDataAdapter.

NOTE
In Microsoft SqlClient Data Provider for SQL Server, the SqlDataAdapter class is derived from the DbDataAdapter class,
and the SqlCommandBuilder class is derived from the DbCommandBuilder class.

As a minimum requirement, you must set the SelectCommand property in order for automatic command
generation to work. The table schema retrieved by the SelectCommand property determines the syntax of the
automatically generated INSERT, UPDATE, and DELETE statements.
The DbCommandBuilder must execute the SelectCommand in order to return the metadata necessary to
construct the INSERT, UPDATE, and DELETE SQL commands. As a result, an extra trip to the data source is
necessary, and this can hinder performance. To achieve optimal performance, specify your commands explicitly
rather than using the DbCommandBuilder.

NOTE
The SelectCommand must also return at least one primary key or unique column. If none is present, an
InvalidOperation exception is generated, and the commands are not generated.

When associated with a DataAdapter , the DbCommandBuilder automatically generates the InsertCommand ,
UpdateCommand , and DeleteCommand properties of the DataAdapter if they are null references. If a Command
already exists for a property, the existing Command is used.
Database views that are created by joining two or more tables together are not considered a single database
table. In this instance, you cannot use the DbCommandBuilder to automatically generate commands; you must
specify your commands explicitly. For information about explicitly setting commands to resolve updates to a
DataSet back to the data source, see Update data sources with DataAdapters.

You might want to map output parameters back to the updated row of a DataSet . One common task would be
retrieving the value of an automatically generated identity field or time stamp from the data source. The
DbCommandBuilder will not map output parameters to columns in an updated row by default. In this instance,
you must specify your command explicitly.
For an example of mapping an automatically generated identity field back to a column of an inserted row, see Re
trieve identity or autonumber values.

Rules for automatically generated commands


The following table shows the rules for how automatically generated commands are generated.

C OMMAND RUL E

InsertCommand Inserts a row at the data source for all rows in the table with
a RowState of Added. Inserts values for all columns that are
updateable (but not columns such as identities, expressions,
or timestamps).

UpdateCommand Updates rows at the data source for all rows in the table
with a RowState of Modified. Updates the values of all
columns except for columns that are not updateable, such as
identities or expressions. Updates all rows where the column
values at the data source match the primary key column
values of the row, and where the remaining columns at the
data source match the original values of the row. For more
information, see "Optimistic Concurrency Model for Updates
and Deletes," later in this topic.

DeleteCommand Deletes rows at the data source for all rows in the table with
a RowState of Deleted. Deletes all rows where the column
values match the primary key column values of the row, and
where the remaining columns at the data source match the
original values of the row. For more information, see
Optimistic Concurrency Model for Updates and Deletes, later
in this topic.

Optimistic concurrency model for updates and deletes


The logic for generating commands automatically for UPDATE and DELETE statements is based on optimistic
concurrency, that is, records are not locked for editing and can be modified by other users or processes at any
time. Because a record could have been modified after it was returned from the SELECT statement, but before
the UPDATE or DELETE statement is issued, the automatically generated UPDATE or DELETE statement contains a
WHERE clause, specifying that a row is only updated if it contains all original values and has not been deleted
from the data source. This is done to avoid overwriting new data.

NOTE
Where an automatically generated update attempts to update a row that has been deleted or that does not contain the
original values found in the DataSet, the command does not affect any records, and a DBConcurrencyException is thrown.

If you want the UPDATE or DELETE to complete regardless of original values, you must explicitly set the
UpdateCommand for the DataAdapter and not rely on automatic command generation.

Limitations of automatic command generation logic


The following limitations apply to automatic command generation.
Unrelated tables only
The automatic command generation logic generates INSERT, UPDATE, or DELETE statements for stand-alone
tables without taking into account any relationships to other tables at the data source. As a result, you may
encounter a failure when calling Update to submit changes for a column that participates in a foreign key
constraint in the database. To avoid this exception, do not use the DbCommandBuilder for updating columns
involved in a foreign key constraint; instead, explicitly specify the statements used to perform the operation.
Table and column names
Automatic command generation logic may fail if column names or table names contain any special characters,
such as spaces, periods, quotation marks, or other nonalphanumeric characters, even if delimited by brackets.
Depending on the provider, setting the QuotePrefix and QuoteSuffix parameters may allow the generation logic
to process spaces, but it cannot escape special characters. Fully qualified table names in the form of
catalog.schema.table are supported.

Use the CommandBuilder to automatically generate an SQL


statement
To automatically generate SQL statements for a DataAdapter , first set the SelectCommand property of the
DataAdapter , then create a CommandBuilder object, and specify as an argument the DataAdapter for which the
CommandBuilder will automatically generate SQL statements.

// Assumes that connection is a valid SqlConnection object


// inside of a using block.
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(queryString, connection);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
builder.QuotePrefix = "[";
builder.QuoteSuffix = "]";

Modify the SelectCommand


If you modify the CommandText of the SelectCommand after the INSERT, UPDATE, or DELETE commands have been
automatically generated, an exception may occur. If the modified SelectCommand.CommandText contains schema
information that is inconsistent with the SelectCommand.CommandText used when the insert, update, or delete
commands were automatically generated, future calls to the DataAdapter.Update method may attempt to access
columns that no longer exist in the current table referenced by the SelectCommand , and an exception will be
thrown.
You can refresh the schema information used by the CommandBuilder to automatically generate commands by
calling the RefreshSchema method of the CommandBuilder .
If you want to know what command was automatically generated, you can obtain a reference to the
automatically generated commands by using the GetInsertCommand , GetUpdateCommand , and GetDeleteCommand
methods of the CommandBuilder object and checking the CommandText property of the associated command.
The following code example writes to the console the update command that was automatically generated.

// Generate the update command automatically by SqlCommandBuilder


Console.WriteLine(builder.GetUpdateCommand().CommandText);

The following example recreates the table in the dataset. The RefreshSchema method is called to refresh the
automatically generated commands with this new column information.

// Assumes an open SqlConnection and SqlDataAdapter inside of a using block.


adapter.SelectCommand.CommandText = newQueryString;
builder.RefreshSchema();

dataSet.Tables.Remove(dataSet.Tables[tableName]);
adapter.Fill(dataSet, tableName);

See also
Commands and parameters
Executing a command
Microsoft ADO.NET for SQL Server
Obtaining a single value from a database
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
You may need to return database information that is simply a single value rather than in the form of a table or
data stream. For example, you may want to return the result of an aggregate function such as COUNT(*),
SUM(Price), or AVG(Quantity). The Command object provides the capability to return single values using the
ExecuteScalar method. The ExecuteScalar method returns, as a scalar value, the value of the first column of
the first row of the result set.

Example
The following code example inserts a new value in the database using a SqlCommand. The ExecuteScalar
method is used to return the identity column value for the inserted record.

static public int AddProductCategory(string newName, string connString)


{
Int32 newProdID = 0;
string sql =
"INSERT INTO Production.ProductCategory (Name) VALUES (@Name); "
+ "SELECT CAST(scope_identity() AS int)";
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("@Name", SqlDbType.VarChar);
cmd.Parameters["@name"].Value = newName;
try
{
conn.Open();
newProdID = (Int32)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return (int)newProdID;
}

See also
Commands and parameters
Executing a command
Microsoft ADO.NET for SQL Server
Using commands to modify data
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Using the Microsoft SqlClient Data Provider for SQL Server, you can execute stored procedures or data
definition language statements (for example, CREATE TABLE and ALTER COLUMN) to perform schema
manipulation on a database or catalog. These commands do not return rows as a query would, so the
SqlCommand object provides an ExecuteNonQuery to process them.
In addition to using ExecuteNonQuer y to modify schema, you can also use this method to process SQL
statements that modify data but that do not return rows, such as INSERT, UPDATE, and DELETE.
Although rows are not returned by the ExecuteNonQuer y method, input and output parameters and return
values can be passed and returned via the Parameters collection of the Command object.

In this section
Updating data in a data source
Describes how to execute commands or stored procedures that modify data in a database.
Performing catalog operations
Describes how to execute commands that modify database schema.

See also
Retrieving and modifying data in ADO.NET
Commands and parameters
Microsoft ADO.NET for SQL Server
Updating data in a data source
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
SQL statements that modify data (such as INSERT, UPDATE, or DELETE) do not return rows. Similarly, many
stored procedures perform an action but do not return rows. To execute commands that do not return rows,
create a Command object with the appropriate SQL command and a Connection , including any required
Parameters . Execute the command with the ExecuteNonQuery method of the SqlCommand object.

NOTE
The ExecuteNonQuer y method returns an integer that represents the number of rows affected by the statement or
stored procedure that was executed. If multiple statements are executed, the value returned is the sum of the records
affected by all of the statements executed.

Example
The following code example executes an INSERT statement to insert a record into a database using
ExecuteNonQuer y .

// Assumes connection is a valid SqlConnection.


connection.Open();

string queryString = "INSERT INTO Customers " +


"(CustomerID, CompanyName) Values('NWIND', 'Northwind Traders')";

SqlCommand command = new SqlCommand(queryString, connection);


Int32 recordsAffected = command.ExecuteNonQuery();

The following code example executes the stored procedure created by the sample code in Performing Catalog
Operations. No rows are returned by the stored procedure, so the ExecuteNonQuer y method is used, but the
stored procedure does receive an input parameter and returns an output parameter and a return value.

// Assumes command is a valid SqlCommand with an open connection.


command.CommandText = "InsertCategory";
command.CommandType = CommandType.StoredProcedure;

SqlParameter parameter = command.Parameters.Add("@RowCount", SqlDbType.Int);


parameter.Direction = ParameterDirection.ReturnValue;

parameter = command.Parameters.Add("@CategoryName", SqlDbType.NChar, 15);

parameter = command.Parameters.Add("@Identity", SqlDbType.Int);


parameter.Direction = ParameterDirection.Output;

command.Parameters["@CategoryName"].Value = "New Category";


command.ExecuteNonQuery();

Int32 categoryID = (Int32) command.Parameters["@Identity"].Value;


Int32 rowCount = (Int32) command.Parameters["@RowCount"].Value;
See also
Using commands to modify data
Update data sources with DataAdapters
Commands and parameters
Microsoft ADO.NET for SQL Server
Performing catalog operations
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
To execute a command to modify a database or catalog, such as the CREATE TABLE or CREATE PROCEDURE
statement, create a Command object using the appropriate SQL statements and a Connection object. Execute
the command with the ExecuteNonQuery method of the SqlCommand object.

Example
The following code example creates a stored procedure in a Microsoft SQL Server database.

// Assumes connection is a valid SqlConnection.


string queryString = "CREATE PROCEDURE InsertCategory " +
"@CategoryName nchar(15), " +
"@Identity int OUT " +
"AS " +
"INSERT INTO Categories (CategoryName) VALUES(@CategoryName) " +
"SET @Identity = @@Identity " +
"RETURN @@ROWCOUNT";

SqlCommand command = new SqlCommand(queryString, connection);


command.ExecuteNonQuery();

See also
Using commands to modify data
Commands and parameters
Microsoft ADO.NET for SQL Server
DataAdapters and DataReaders
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
You can use the Microsoft SqlClient Data Provider for SQL Server DataReader to retrieve a read-only, forward-
only stream of data from a database. Results are returned as the query executes, and are stored in the network
buffer on the client until you request them using the Read method of the DataReader . Using the DataReader
can increase application performance both by retrieving data as soon as it is available, and (by default) storing
only one row at a time in memory, reducing system overhead.
A DataAdapter is used to retrieve data from a data source and populate tables within a DataSet. The
DataAdapter also resolves changes made to the DataSet back to the data source. The DataAdapter uses the
Connection object of the Microsoft SqlClient Data Provider for SQL Server to connect to a data source, and it
uses Command objects to retrieve data from and resolve changes to the data source.
.NET has a DbDataReader and a DbDataAdapter object: the Microsoft SqlClient Data Provider for SQL Server
includes a SqlDataReader and a SqlDataAdapter object.

In this section
Retrieve data by a DataReader
Describes the ADO.NET DataReader object and how to use it to return a stream of results from a data source.
Populate a DataSet from a DataAdapter
Describes how to fill a DataSet with tables, columns, and rows by using a DataAdapter .
DataAdapter parameters
Describes how to use parameters with the command properties of a DataAdapter including how to map the
contents of a column in a DataSet to a command parameter.
Add existing constraints to a DataSet
Describes how to add existing constraints to a DataSet .
DataAdapter, DataTable, and DataColumn mappings
Describes how to set up DataTableMappings and ColumnMappings for a DataAdapter .
Paging through a query result
Provides an example of viewing the results of a query as pages of data.
Update data sources with DataAdapters
Describes how to use a DataAdapter to resolve changes in a DataSet back to the database.
Handle DataAdapter events
Describes DataAdapter events and how to use them.
Batch operations using DataAdapters
Describes enhancing application performance by reducing the number of round trips to SQL Server when
applying updates from the DataSet .

See also
Connecting to a data source
Commands and parameters
Transactions and concurrency
Microsoft ADO.NET for SQL Server
Retrieve data by a DataReader
4/27/2022 • 3 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
To retrieve data using a DataReader , create an instance of the Command object, and then create a
DataReader by calling Command.ExecuteReader to retrieve rows from a data source. The DataReader
provides an unbuffered stream of data that allows procedural logic to efficiently process results from a data
source sequentially.

NOTE
The DataReader is a good choice when you're retrieving large amounts of data because the data is not cached in
memory.

The following example illustrates using a DataReader , where reader represents a valid DataReader and
command represents a valid Command object.

reader = command.ExecuteReader();

Use the DataReader.Read method to obtain a row from the query results. You can access each column of the
returned row by passing the name or ordinal number of the column to the DataReader . However, for best
performance, the DataReader provides a series of methods that allow you to access column values in their
native data types (GetDateTime , GetDouble , GetGuid , GetInt32 , and so on). For a list of typed accessor
methods for data provider-specific DataReaders , see SqlDataReader. Using the typed accessor methods when
you know the underlying data type reduces the amount of type conversion required when retrieving the column
value.
The following example iterates through a DataReader object and returns two columns from each row.
static void HasRows(SqlConnection connection)
{
using (connection)
{
SqlCommand command = new SqlCommand(
"SELECT CategoryID, CategoryName FROM Categories;",
connection);
connection.Open();

SqlDataReader reader = command.ExecuteReader();

// Check if the DataReader has any row.


if (reader.HasRows)
{
// Obtain a row from the query result.
while (reader.Read())
{
Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));
}
}
else
{
Console.WriteLine("No rows found.");
}
// Always call the Close method when you have finished using the DataReader object.
reader.Close();
}
}

Close the DataReader


Always call the Close() method when you have finished using the DataReader object.

NOTE
If your Command contains output parameters or return values, those values are not available until the DataReader is
closed.

IMPORTANT
While a DataReader is open, the Connection is in use exclusively by that DataReader . You cannot execute any
commands for the Connection , including creating another DataReader , until the original DataReader is closed.

NOTE
Do not call Close or Dispose on a Connection , a DataReader , or any other managed object in the Finalize method of
your class. In a finalizer, only release unmanaged resources that your class owns directly. If your class does not own any
unmanaged resources, do not include a Finalize method in your class definition. For more information, see Garbage
Collection.

Retrieve multiple result-sets using NextResult


If the DataReader returns multiple result sets, call the NextResult method to iterate through the result sets
sequentially. The following example shows the SqlDataReader processing the results of two SELECT statements
using the ExecuteReader method.
static void RetrieveMultipleResults(SqlConnection connection)
{
using (connection)
{
SqlCommand command = new SqlCommand(
"SELECT CategoryID, CategoryName FROM dbo.Categories;" +
"SELECT EmployeeID, LastName FROM dbo.Employees",
connection);
connection.Open();

SqlDataReader reader = command.ExecuteReader();

// Check if the DataReader has any row.


while (reader.HasRows)
{
Console.WriteLine("\t{0}\t{1}", reader.GetName(0),
reader.GetName(1));

// Obtain a row from the query result.


while (reader.Read())
{
Console.WriteLine("\t{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));
}

// Hop to the next result-set.


reader.NextResult();
}
// Always call the Close method when you have finished using the DataReader object.
reader.Close();
}
}

Get schema information from the DataReader


While a DataReader is open, you can retrieve schema information about the current result set using the
GetSchemaTable method. GetSchemaTable returns a DataTable object populated with rows and columns that
contain the schema information for the current result set. The DataTable contains one row for each column of
the result set. Each column of the schema table maps to a property of the columns returned in the rows of the
result set, where the ColumnName is the name of the property and the value of the column is the value of the
property. The following example writes out the schema information for DataReader .
static void GetSchemaInfo(SqlConnection connection)
{
using (connection)
{
SqlCommand command = new SqlCommand(
"SELECT CategoryID, CategoryName FROM Categories;",
connection);
connection.Open();

SqlDataReader reader = command.ExecuteReader();

// Retrieve schema information about the current result-set.


DataTable schemaTable = reader.GetSchemaTable();

foreach (DataRow row in schemaTable.Rows)


{
foreach (DataColumn column in schemaTable.Columns)
{
Console.WriteLine(String.Format("{0} = {1}",
column.ColumnName, row[column]));
}
}

// Always call the Close method when you have finished using the DataReader object.
reader.Close();
}
}

See also
DataAdapters and DataReaders
Commands and parameters
Retrieving database schema information
Microsoft ADO.NET for SQL Server
Populate a DataSet from a DataAdapter
4/27/2022 • 6 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The ADO.NET DataSet is a memory-resident representation of data that provides a consistent relational
programming model independent of the data source. The DataSet represents a complete set of data that
includes tables, constraints, and relationships among the tables. Because the DataSet is independent of the data
source, a DataSet can include data local to the application, and data from multiple data sources. Interaction with
existing data sources is controlled through the DataAdapter .
The SelectCommand property of the DataAdapter is a Command object that retrieves data from the data source.
The InsertCommand , UpdateCommand , and DeleteCommand properties of the DataAdapter are Command objects that
manage updates to the data in the data source according to modifications made to the data in the DataSet .
These properties are covered in more detail in Update Data Sources with DataAdapters.
The Fill method of the DataAdapter is used to populate a DataSet with the results of the SelectCommand of
the DataAdapter . Fill takes as its arguments a DataSet to be populated, and a DataTable object, or the name
of the DataTable to be filled with the rows returned from the SelectCommand .

NOTE
Using the DataAdapter to retrieve all of a table takes time, especially if there are many rows in the table. This is because
accessing the database, locating and processing the data, and then transferring the data to the client is time-consuming.
Pulling all of the table to the client also locks all of the rows on the server. To improve performance, you can use the
WHERE clause to greatly reduce the number of rows returned to the client. You can also reduce the amount of data
returned to the client by only explicitly listing required columns in the SELECT statement. Another good workaround is
to retrieve the rows in batches (such as several hundred rows at a time) and only retrieve the next batch when the client is
finished with the current batch.

The Fill method uses the DataReader object implicitly to return the column names and types that are used to
create the tables in the DataSet , and the data to populate the rows of the tables in the DataSet . Tables and
columns are only created if they do not already exist; otherwise Fill uses the existing DataSet schema.
Column types are created as .NET Framework types according to the tables in Data Type Mappings in ADO.NET.
Primary keys are not created unless they exist in the data source and DataAdapter . MissingSchemaAction is set to
MissingSchemaAction . AddWithKey . If Fill finds that a primary key exists for a table, it will overwrite data in the
DataSet with data from the data source for rows where the primary key column values match those of the row
returned from the data source. If no primary key is found, the data is appended to the tables in the DataSet .
Fill uses any mappings that may exist when you populate the DataSet (see DataAdapter, DataTable, and
DataColumn Mappings).

NOTE
If the SelectCommand returns the results of an OUTER JOIN, the DataAdapter does not set a PrimaryKey value for
the resulting DataTable . You must define the PrimaryKey yourself to make sure that duplicate rows are resolved
correctly.
The following code example creates an instance of a SqlDataAdapter that uses a SqlConnection to the Microsoft
SQL Server Northwind database and populates a DataTable in a DataSet with the list of customers. The SQL
statement and SqlConnection arguments passed to the SqlDataAdapter constructor are used to create the
SelectCommand property of the SqlDataAdapter.

Example
// Assumes that connection is a valid SqlConnection object.
string queryString =
"SELECT CustomerID, CompanyName FROM dbo.Customers";
SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

DataSet customers = new DataSet();


adapter.Fill(customers, "Customers");

NOTE
The code shown in this example does not explicitly open and close the Connection . The Fill method implicitly opens
the Connection that the DataAdapter is using if it finds that the connection is not already open. If Fill opened the
connection, it also closes the connection when Fill is finished. This can simplify your code when you deal with a single
operation such as a Fill or an Update . However, if you are performing multiple operations that require an open
connection, you can improve the performance of your application by explicitly calling the Open method of the
Connection , performing the operations against the data source, and then calling the Close method of the
Connection . You should try to keep connections to the data source open as briefly as possible to free resources for use
by other client applications.

Multiple result sets


If the DataAdapter encounters multiple result sets, it creates multiple tables in the DataSet . The tables are given
an incremental default name of TableN, starting with "Table" for Table0. If a table name is passed as an argument
to the Fill method, the tables are given an incremental default name of TableNameN, starting with
"TableName" for TableName0.

Populate a DataSet from multiple DataAdapters


Any number of DataAdapter objects can be used with a DataSet . Each DataAdapter can be used to fill one or
more DataTable objects and resolve updates back to the relevant data source. DataRelation and Constraint
objects can be added to the DataSet locally, which enables you to relate data from dissimilar data sources. For
example, a DataSet can contain data from a Microsoft SQL Server database, an IBM DB2 database exposed
through OLE DB, and a data source that streams XML. One or more DataAdapter objects can handle
communication to each data source.
Example
The following code example populates a list of customers from the Northwind database on Microsoft SQL
Server, and a list of orders from the Northwind database stored in Microsoft Access. The filled tables are related
with a DataRelation , and the list of customers is then displayed with the orders for that customer.
// Assumes that customerConnection and orderConnection are valid SqlConnection objects.
SqlDataAdapter custAdapter = new SqlDataAdapter(
"SELECT * FROM dbo.Customers", customerConnection);
SqlDataAdapter ordAdapter = new SqlDataAdapter(
"SELECT * FROM Orders", orderConnection);

DataSet customerOrders = new DataSet();

custAdapter.Fill(customerOrders, "Customers");
ordAdapter.Fill(customerOrders, "Orders");

DataRelation relation = customerOrders.Relations.Add("CustOrders",


customerOrders.Tables["Customers"].Columns["CustomerID"],
customerOrders.Tables["Orders"].Columns["CustomerID"]);

foreach (DataRow pRow in customerOrders.Tables["Customers"].Rows)


{
Console.WriteLine(pRow["CustomerID"]);
foreach (DataRow cRow in pRow.GetChildRows(relation))
Console.WriteLine("\t" + cRow["OrderID"]);
}

SQL Server Decimal type


By default, the DataSet stores data by using .NET data types. For most applications, these provide a convenient
representation of data source information. However, this representation may cause a problem when the data
type in the data source is a SQL Server decimal or numeric data type. The .NET decimal data type allows a
maximum of 28 significant digits, whereas the SQL Server decimal data type allows 38 significant digits. If the
SqlDataAdapter determines during a Fill operation that the precision of a SQL Server decimal field is larger
than 28 characters, the current row is not added to the DataTable . Instead the FillError event occurs, which
enables you to determine whether a loss of precision will occur, and respond appropriately. For more
information about the FillError event, see Handle DataAdapter Events. To get the SQL Server decimal value,
you can also use a SqlDataReader object and call the GetSqlDecimal method.
ADO.NET also includes enhanced support for System.Data.SqlTypes in the DataSet . For more information, see
SqlTypes and the DataSet.

See also
DataAdapters and DataReaders
Data type mappings in ADO.NET
Multiple Active Result Sets (MARS)
Microsoft ADO.NET for SQL Server
DataAdapter parameters
4/27/2022 • 4 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The DbDataAdapter has four properties that are used to retrieve data from and update data to the data source:
the SelectCommand property returns data from the data source; and the InsertCommand , UpdateCommand,
and DeleteCommand properties are used to manage changes at the data source.

NOTE
The SelectCommand property must be set before you call the Fill method of the DataAdapter . The InsertCommand
, UpdateCommand , or DeleteCommand properties must be set before the Update method of the DataAdapter is called,
depending on what changes were made to the data in the DataTable. For example, if rows have been added, the
InsertCommand must be set before you call Update . When Update is processing an inserted, updated, or deleted row,
the DataAdapter uses the respective Command property to process the action. Current information about the modified
row is passed to the Command object through the Parameters collection.

When you update a row at the data source, you call the UPDATE statement, which uses a unique identifier to
identify the row in the table to be updated. The unique identifier is typically the value of a primary key field. The
UPDATE statement uses parameters that contain both the unique identifier and the columns and values to be
updated, as shown in the following Transact-SQL statement.

UPDATE Customers SET CompanyName = @CompanyName


WHERE CustomerID = @CustomerID

NOTE
The syntax for parameter placeholders depends on the data source. This example shows placeholders for a SQL Server
data source.

In this example, the CompanyName field is updated with the value of the @CompanyName parameter for the row
where CustomerID equals the value of the @CustomerID parameter. The parameters retrieve information from
the modified row using the SourceColumn property of the SqlParameter object. The following are the
parameters for the previous sample UPDATE statement. The code assumes that the variable adapter represents
a valid SqlDataAdapter object.

// Assumes that connection is a valid SqlAdapter object


adapter.UpdateCommand.Parameters.Add("@CompanyName",
SqlDbType.VarChar, 15, "CompanyName");
SqlParameter parameter = adapter.UpdateCommand.Parameters.Add("@CustomerID",
SqlDbType.Char, 5, "CustomerID");
parameter.SourceVersion = DataRowVersion.Original;

The Add method of the Parameters collection takes the name of the parameter, the data type, the size (if
applicable to the type), and the name of the SourceColumn from the DataTable . Notice that the SourceVersion
of the @CustomerID parameter is set to Original . This guarantees that the existing row in the data source is
updated if the value of the identifying column or columns has been changed in the modified DataRow. In that
case, the Original row value would match the current value at the data source, and the Current row value
would contain the updated value. The SourceVersion for the @CompanyName parameter is not set and uses the
default, Current row value.

NOTE
For both the Fill operations of the DataAdapter and the Get methods of the DataReader , the .NET type is
inferred from the type returned from the Microsoft SqlClient Data Provider for SQL Server. The inferred .NET types and
accessor methods for Microsoft SQL Server data types are described in Data Type Mappings in ADO.NET.

Parameter.SourceColumn, Parameter.SourceVersion
The SourceColumn and SourceVersion may be passed as arguments to the Parameter constructor, or set as
properties of an existing Parameter . The SourceColumn is the name of the DataColumn from the DataRow where
the value of the Parameter will be retrieved. The SourceVersion specifies the DataRow version that the
DataAdapter uses to retrieve the value.

The following table shows the DataRowVersion enumeration values available for use with SourceVersion .

DATA RO W VERSIO N EN UM ERAT IO N DESC RIP T IO N

Current The parameter uses the current value of the column. This is
the default.

Default The parameter uses the DefaultValue of the column.

Original The parameter uses the original value of the column.

Proposed The parameter uses a proposed value.

The SqlClient code example in the next section defines a parameter for an UpdateCommand in which the
CustomerID column is used as a SourceColumn for two parameters: @CustomerID ( SET CustomerID = @CustomerID
), and @OldCustomerID ( WHERE CustomerID = @OldCustomerID ). The @CustomerID parameter is used to update the
CustomerID column to the current value in the DataRow . As a result, the CustomerID SourceColumn with a
SourceVersion of Current is used. The @OldCustomerID parameter is used to identify the current row in the data
source. Because the matching column value is found in the Original version of the row, the same SourceColumn
( CustomerID ) with a SourceVersion of Original is used.

Work with SqlClient parameters


The following example demonstrates how to create a SqlDataAdapter and set the MissingSchemaAction to
AddWithKey in order to retrieve additional schema information from the database. The SelectCommand,
InsertCommand, UpdateCommand, and DeleteCommand properties set and their corresponding SqlParameter
objects added to the Parameters collection. The method returns a SqlDataAdapter object.
public static SqlDataAdapter CreateSqlDataAdapter(SqlConnection connection)
{
// Assumes that connection is a valid SqlConnection object
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;

// Create the commands.


adapter.SelectCommand = new SqlCommand(
"SELECT CustomerID, CompanyName FROM CUSTOMERS", connection);
adapter.InsertCommand = new SqlCommand(
"INSERT INTO Customers (CustomerID, CompanyName) " +
"VALUES (@CustomerID, @CompanyName)", connection);
adapter.UpdateCommand = new SqlCommand(
"UPDATE Customers SET CustomerID = @CustomerID, CompanyName = @CompanyName " +
"WHERE CustomerID = @oldCustomerID", connection);
adapter.DeleteCommand = new SqlCommand(
"DELETE FROM Customers WHERE CustomerID = @CustomerID", connection);

// Create the parameters.


adapter.InsertCommand.Parameters.Add("@CustomerID",
SqlDbType.Char, 5, "CustomerID");
adapter.InsertCommand.Parameters.Add("@CompanyName",
SqlDbType.VarChar, 40, "CompanyName");

adapter.UpdateCommand.Parameters.Add("@CustomerID",
SqlDbType.Char, 5, "CustomerID");
adapter.UpdateCommand.Parameters.Add("@CompanyName",
SqlDbType.VarChar, 40, "CompanyName");
adapter.UpdateCommand.Parameters.Add("@oldCustomerID",
SqlDbType.Char, 5, "CustomerID").SourceVersion =
DataRowVersion.Original;

adapter.DeleteCommand.Parameters.Add("@CustomerID",
SqlDbType.Char, 5, "CustomerID").SourceVersion =
DataRowVersion.Original;

return adapter;
}

See also
DataAdapters and DataReaders
Commands and parameters
Update data sources with DataAdapters
Modify data with stored procedures
Data type mappings in ADO.NET
Microsoft ADO.NET for SQL Server
Add existing constraints to a DataSet
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The Fill method of the SqlDataAdapter fills a DataSet only with table columns and rows from a data source;
though constraints are commonly set by the data source, the Fill method does not add this schema information
to the DataSet by default.
To populate a DataSet with existing primary key constraint information from a data source, you can either call
the FillSchema method of the DataAdapter , or set the MissingSchemaAction property of the DataAdapter to
AddWithKey before calling Fill . This will ensure that primary key constraints in the DataSet reflect those at the
data source.

NOTE
Foreign key constraint information is not included and must be created explicitly.

Adding schema information to a DataSet before filling it with data ensures that primary key constraints are
included with the DataTable objects in the DataSet . As a result, when additional calls to fill the DataSet are
made, the primary key column information is used to match new rows from the data source with current rows
in each DataTable , and current data in the tables is overwritten with data from the data source. Without the
schema information, the new rows from the data source are appended to the DataSet , resulting in duplicate
rows.

NOTE
If a column in a data source is identified as auto-incrementing, the FillSchema method, or the Fill method with a
MissingSchemaAction of AddWithKey , creates a DataColumn with an AutoIncrement property set to true .
However, you will need to set the AutoIncrementStep and AutoIncrementSeed values yourself.

NOTE
Using FillSchema or setting the MissingSchemaAction to AddWithKey requires extra processing at the data source
to determine primary key column information. This additional processing can hinder performance. If you know the
primary key information at design time, we recommend that you explicitly specify the primary key column or columns in
order to achieve optimal performance.

The following code example shows how to add schema information to a DataSet using FillSchema:

// Assumes that connection is a valid SqlConnection object.


string queryString =
"SELECT CustomerID, CompanyName FROM dbo.Customers";
SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

DataSet customers = new DataSet();


adapter.Fill(customers, "Customers");
The following code example shows how to add schema information to a DataSet using the
MissingSchemaAction property and the Fill method:

// Assumes that customerConnection and orderConnection are valid SqlConnection objects.


SqlDataAdapter custAdapter = new SqlDataAdapter(
"SELECT * FROM dbo.Customers", customerConnection);
SqlDataAdapter ordAdapter = new SqlDataAdapter(
"SELECT * FROM Orders", orderConnection);

DataSet customerOrders = new DataSet();

custAdapter.Fill(customerOrders, "Customers");
ordAdapter.Fill(customerOrders, "Orders");

DataRelation relation = customerOrders.Relations.Add("CustOrders",


customerOrders.Tables["Customers"].Columns["CustomerID"],
customerOrders.Tables["Orders"].Columns["CustomerID"]);

foreach (DataRow pRow in customerOrders.Tables["Customers"].Rows)


{
Console.WriteLine(pRow["CustomerID"]);
foreach (DataRow cRow in pRow.GetChildRows(relation))
Console.WriteLine("\t" + cRow["OrderID"]);
}

Handling multiple result sets


If the DataAdapter meets multiple result sets returned from the SelectCommand, it will create multiple tables
in the DataSet . The tables will be given a zero-based incremental default name of Table N, starting with Table
instead of "Table0". The tables will be given a zero-based incremental name of TableName N, starting with
TableName instead of "TableName0" if a table name is passed as an argument to the FillSchema method.

See also
DataAdapters and DataReaders
Retrieving and modifying data in ADO.NET
Microsoft ADO.NET for SQL Server
DataAdapter, DataTable, and DataColumn
mappings
4/27/2022 • 3 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
A SqlDataAdapter contains a collection of zero or more DataTableMapping objects in its TableMappings
property. A DataTableMapping provides a main mapping between the data returned from a query against a
data source, and a DataTable. The DataTableMapping name can be passed in place of the DataTable name to
the Fill method of the DataAdapter . The following example creates a DataTableMapping named
AuthorsMapping for the Authors table.

workAdapter.TableMappings.Add("AuthorsMapping", "Authors");

A DataTableMapping enables you to use column names in a DataTable that are different from those in the
database. The DataAdapter uses the mapping to match the columns when the table is updated.

NOTE
If you do not specify a TableName or a DataTableMapping name when calling the Fill or Update method of the
DataAdapter , the DataAdapter looks for a DataTableMapping named "Table". The TableName of the DataTable is
"Table" if that DataTableMapping does not exist. You can specify a default DataTableMapping by creating a
DataTableMapping with the name of "Table".

The following code example creates a DataTableMapping (from the System.Data.Common namespace) and
makes it the default mapping for the specified DataAdapter by naming it "Table". The example then maps the
columns from the first table in the query result (the Customers table of the Nor thwind database) to a set of
more user-friendly names in the Nor thwind Customers table in the DataSet. For columns that are not
mapped, the name of the column from the data source is used.

// Assumes that connection is a valid SqlConnection object.


DataSet custDataSet = new DataSet();

SqlDataAdapter custAdapter = new SqlDataAdapter(


"SELECT * FROM dbo.Customers", connection);

DataTableMapping mapping =
custAdapter.TableMappings.Add("Table", "NorthwindCustomers");
mapping.ColumnMappings.Add("CompanyName", "Company");
mapping.ColumnMappings.Add("ContactName", "Contact");
mapping.ColumnMappings.Add("PostalCode", "ZIPCode");

custAdapter.Fill(custDataSet);

In more advanced situations, you may decide that you want the same DataAdapter to support loading different
tables with different mappings. To do this, add additional DataTableMapping objects.
When the Fill method is passed an instance of a DataSet and a DataTableMapping name, if a mapping with
that name exists it is used; otherwise, a DataTable with that name is used.
The following examples create a DataTableMapping with a name of Customers and a DataTable name of
BizTalkSchema . The example then maps the rows returned by the SELECT statement to the BizTalkSchema
DataTable .

// Assumes that connection is a valid SqlConnection object.


DataSet custDataSet = new DataSet();

SqlDataAdapter custAdapter = new SqlDataAdapter(


"SELECT * FROM dbo.Customers", connection);

// The DataTableMapping is implemented ITableMapping.


ITableMapping mapping =
custAdapter.TableMappings.Add("Table", "BizTalkSchema");
mapping.ColumnMappings.Add("CustomerID", "ClientID");
mapping.ColumnMappings.Add("CompanyName", "ClientName");
mapping.ColumnMappings.Add("ContactName", "Contact");
mapping.ColumnMappings.Add("PostalCode", "ZIP");

custAdapter.Fill(custDataSet);

NOTE
If a source column name is not supplied for a column mapping, default names will be automatically generated. The
column mapping is given an incremental default name of SourceColumn N, starting with SourceColumn1 if no source
column is supplied for a column mapping.

NOTE
If a source table name is not supplied for a table mapping, default names will be automatically generated. The table
mapping is given an incremental default name of SourceTable N, starting with SourceTable1 if no source table name is
supplied for a table mapping.

NOTE
We recommend that you avoid the naming convention of SourceColumn N for a column mapping, or SourceTable N
for a table mapping, because the name you supply may conflict with an existing default column mapping name in the
ColumnMappingCollection or table mapping name in the DataTableMappingCollection . If the supplied name
already exists, an exception will be thrown.

Handle multiple result sets


If your SelectCommand returns multiple tables, Fill automatically generates table names with incremental
values for the tables in the DataSet , starting with the specified table name and continuing on in the form
TableName N, starting with TableName1 . You can use table mappings to map the automatically generated
table name to a name you want specified for the table in the DataSet . For example, for a SelectCommand that
returns two tables, Customers and Orders , issue the following call to Fill .

adapter.Fill(customersDataSet, "Customers");

Two tables are created in the DataSet : Customers and Customers1 . You can use table mappings to ensure
that the second table is named Orders instead of Customers1 . To do this, map the source table of
Customers1 to the DataSet table Orders , as shown in the following example.
// Assumes that connection is a valid SqlConnection object.
string queryString =
"SELECT * FROM dbo.Customers; SELECT * FROM dbo.Orders;";
SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

DataSet customersDataSet = new DataSet();

adapter.TableMappings.Add("Customers1", "Orders");
adapter.Fill(customersDataSet, "Customers");

See also
DataAdapters and DataReaders
Retrieving and modifying data in ADO.NET
Microsoft ADO.NET for SQL Server
Paging through a query result
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Paging through a query result is the process of returning the results of a query in smaller subsets of data, or
pages. This is a common practice for displaying results to a user in small, easy-to-manage chunks.
The SqlDataAdapter provides a facility for returning only a page of data, through overloads of the Fill method.
However, this might not be the best choice for paging through large query results because, although the
DataAdapter fills the target DataTable or DataSet with only the requested records, the resources to return the
entire query are still used.
To return a page of data from a data source without using the resources to return the entire query, specify
additional criteria for your query that reduce the rows returned to only those required.
To use the Fill method to return a page of data, specify a star tRecord parameter, for the first record in the page
of data, and a maxRecords parameter, for the number of records in the page of data.

Example
The following code example shows how to use the Fill method to return the first page of a query result where
the page size is five records.

int currentIndex = 0;
int pageSize = 5;

string orderSQL = "SELECT * FROM Orders ORDER BY OrderID";


// Assumes that connection is a valid SqlConnection object.
SqlDataAdapter adapter = new SqlDataAdapter(orderSQL, connection);

DataSet dataSet = new DataSet();


adapter.Fill(dataSet, currentIndex, pageSize, "Orders");

In the previous example, the DataSet is only filled with five records, but the entire Orders table is returned. To
fill the DataSet with those same five records, but only return five records, use the TOP and WHERE clauses in
your SQL statement, as in the following code example.

int pageSize = 5;

string orderSQL = "SELECT TOP " + pageSize +


" * FROM Orders ORDER BY OrderID";

// Assumes that connection is a valid SqlConnection object.


SqlDataAdapter adapter = new SqlDataAdapter(orderSQL, connection);

DataSet dataSet = new DataSet();


adapter.Fill(dataSet, "Orders");
NOTE
When paging through the query results in this way, you must preserve the unique identifier that orders the rows, in
order to pass the unique ID to the command to return the next page of records, as shown in the following code example.

string lastRecord =
dataSet.Tables["Orders"].Rows[pageSize - 1]["OrderID"].ToString();

To return the next page of records using the overload of the Fill method that takes the star tRecord and
maxRecords parameters, increment the current record index by the page size and fill the table.

NOTE
Remember that the database server returns the entire query results even though only one page of records is added to
the DataSet .

In the following code example, the table rows are cleared before they are filled with the next page of data. You
might want to preserve a certain number of returned rows in a local cache to reduce trips to the database
server.

currentIndex += pageSize;

// Assumes that dataset and adapter are valid objects.


dataSet.Tables["Orders"].Rows.Clear();
adapter.Fill(dataSet, currentIndex, pageSize, "Orders");

To return the next page of records without having the database server return the entire query, specify restrictive
criteria to the SELECT statement. Because the preceding example preserved the last record returned, you can use
it in the WHERE clause to specify a starting point for the query, as shown in the following code example.

orderSQL = "SELECT TOP " + pageSize +


" * FROM Orders WHERE OrderID > " + lastRecord + " ORDER BY OrderID";
adapter.SelectCommand.CommandText = orderSQL;

dataSet.Tables["Orders"].Rows.Clear();

adapter.Fill(dataSet, "Orders");

See also
DataAdapters and DataReaders
Microsoft ADO.NET for SQL Server
Update data sources with DataAdapters
4/27/2022 • 13 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The Update method of the DataAdapter is called to resolve changes from a DataSet back to the data source. The
Update method, like the Fill method, takes as arguments an instance of a DataSet , and an optional DataTable
object or DataTable name. The DataSet instance is the DataSet that contains the changes that have been
made, and the DataTable identifies the table from which to retrieve the changes. If no DataTable is specified,
the first DataTable in the DataSet is used.
When you call the Update method, the DataAdapter analyzes the changes that have been made and executes
the appropriate command (INSERT, UPDATE, or DELETE). When the DataAdapter encounters a change to a
DataRow, it uses the InsertCommand, UpdateCommand, or DeleteCommand to process the change.
These properties allow you to maximize the performance of your ADO.NET application by specifying command
syntax at design time and, where possible, through the use of stored procedures. You must explicitly set the
commands before calling Update . If Update is called and the appropriate command does not exist for a
particular update (for example, no DeleteCommand for deleted rows), an exception is thrown.

IMPORTANT
If you are using SQL Server stored procedures to edit or delete data using a DataAdapter , make sure that you do not
use SET NOCOUNT ON in the stored procedure definition. This causes the rows affected count returned to be zero, which
the DataAdapter interprets as a concurrency conflict. In this event, a DBConcurrencyException will be thrown.

Command parameters can be used to specify input and output values for an SQL statement or stored procedure
for each modified row in a DataSet . For more information, see DataAdapter parameters.

NOTE
It is important to understand the difference between deleting a row in a DataTable and removing the row. When you call
the Remove or RemoveAt method, the row is removed immediately. Any corresponding rows in the back end data
source will not be affected if you then pass the DataTable or DataSet to a DataAdapter and call Update . When
you use the Delete method, the row remains in the DataTable and is marked for deletion. If you then pass the
DataTable or DataSet to a DataAdapter and call Update , the corresponding row in the back end data source is
deleted .

If your DataTable maps to or is generated from a single database table, you can take advantage of the
DbCommandBuilder object to automatically generate the DeleteCommand , InsertCommand , and UpdateCommand
objects for the DataAdapter . For more information, see Generating commands with CommandBuilders.

Use UpdatedRowSource to map values to a DataSet


You can control how the values returned from the data source are mapped back to the DataTable following a
call to the Update method of a DataAdapter , by using the UpdatedRowSource property of a SqlCommand
object. By setting the UpdatedRowSource property to one of the UpdateRowSource enumeration values, you can
control whether output parameters returned by the DataAdapter commands are ignored or applied to the
changed row in the DataSet . You can also specify whether the first returned row (if it exists) is applied to the
changed row in the DataTable .
The following table describes the different values of the UpdateRowSource enumeration and how they affect the
behavior of a command used with a DataAdapter .

UP DAT EDRO W SO URC E EN UM ERAT IO N DESC RIP T IO N

Both Both the output parameters and the first row of a returned
result set may be mapped to the changed row in the
DataSet .

FirstReturnedRecord Only the data in the first row of a returned result set may be
mapped to the changed row in the DataSet .

None Any output parameters or rows of a returned result set are


ignored.

OutputParameters Only output parameters may be mapped to the changed


row in the DataSet .

The Update method resolves your changes back to the data source; however other clients may have modified
data at the data source since the last time you filled the DataSet . To refresh your DataSet with current data, use
the DataAdapter and Fill method. New rows will be added to the table, and updated information will be
incorporated into existing rows.
The Fill method determines whether a new row will be added or an existing row will be updated by
examining the primary key values of the rows in the DataSet and the rows returned by the SelectCommand . If
the Fill method encounters a primary key value for a row in the DataSet that matches a primary key value
from a row in the results returned by the SelectCommand , it updates the existing row with the information from
the row returned by the SelectCommand and sets the RowState of the existing row to Unchanged . If a row
returned by the SelectCommand has a primary key value that does not match any of the primary key values of
the rows in the DataSet , the Fill method adds a new row with a RowState of Unchanged .

NOTE
If the SelectCommand returns the results of an OUTER JOIN, the DataAdapter will not set a PrimaryKey value for
the resulting DataTable . You must define the PrimaryKey yourself to ensure that duplicate rows are resolved correctly.

To handle exceptions that may occur when calling the Update method, you can use the RowUpdated event to
respond to row update errors as they occur (see Handle DataAdapter events), or you can set
ContinueUpdateOnError to true before calling Update , and respond to the error information stored in the
RowError property of a particular row when the update is complete.
NOTE
Calling AcceptChanges on the DataSet , DataTable , or DataRow will cause all Original values for a DataRow to
be overwritten with the Current values for the DataRow . If the field values that identify the row as unique have been
modified, after calling AcceptChanges the Original values will no longer match the values in the data source.
AcceptChanges is called automatically for each row during a call to the Update method of a DataAdapter . You can
preserve the original values during a call to the Update method by first setting the AcceptChangesDuringUpdate
property of the DataAdapter to false, or by creating an event handler for the RowUpdated event and setting the Status
to SkipCurrentRow. For more information, see Handle DataAdapter Events.

The following examples demonstrate how to perform updates to modified rows by explicitly setting the
UpdateCommand of a DataAdapter and calling its Update method.

NOTE
The parameter specified in the WHERE clause of the UPDATE statement is set to use the Original value of the
SourceColumn . This is important, because the Current value may have been modified and may not match the value in
the data source. The Original value is the value that was used to populate the DataTable from the data source.

private static void AdapterUpdate(string connectionString)


{
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlDataAdapter dataAdpater = new SqlDataAdapter(
"SELECT CategoryID, CategoryName FROM Categories",
connection);

dataAdpater.UpdateCommand = new SqlCommand(


"UPDATE Categories SET CategoryName = @CategoryName " +
"WHERE CategoryID = @CategoryID", connection);

dataAdpater.UpdateCommand.Parameters.Add(
"@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(


"@CategoryID", SqlDbType.Int);
parameter.SourceColumn = "CategoryID";
parameter.SourceVersion = DataRowVersion.Original;

DataTable categoryTable = new DataTable();


dataAdpater.Fill(categoryTable);

DataRow categoryRow = categoryTable.Rows[0];


categoryRow["CategoryName"] = "New Beverages";

dataAdpater.Update(categoryTable);

Console.WriteLine("Rows after update.");


foreach (DataRow row in categoryTable.Rows)
{
{
Console.WriteLine("{0}: {1}", row[0], row[1]);
}
}
}
}
AutoIncrement columns
If the tables from your data source have auto-incrementing columns, you can fill the columns in your DataSet
either by returning the auto-increment value as an output parameter of a stored procedure and mapping that to
a column in a table, by returning the auto-increment value in the first row of a result set returned by a stored
procedure or SQL statement, or by using the RowUpdated event of the DataAdapter to execute an additional
SELECT statement. For more information and an example, see Retrieve identity or autonumber values.

Ordering of inserts, updates, and deletes


In many circumstances, the order in which changes made through the DataSet are sent to the data source is
important. For example, if a primary key value for an existing row is updated, and a new row has been added
with the new primary key value as a foreign key, it is important to process the update before the insert.
You can use the Select method of the DataTable to return a DataRow array that only references rows with a
particular RowState . You can then pass the returned DataRow array to the Update method of the DataAdapter
to process the modified rows. By specifying a subset of rows to be updated, you can control the order in which
inserts, updates, and deletes are processed.

Example
For example, the following code ensures that the deleted rows of the table are processed first, then the updated
rows, and then the inserted rows.

// Assumes that dataSet and adapter are valid objects.


DataTable table = dataSet.Tables["Customers"];

// First process deletes.


adapter.Update(table.Select(null, null, DataViewRowState.Deleted));

// Next process updates.


adapter.Update(table.Select(null, null,
DataViewRowState.ModifiedCurrent));

// Finally, process inserts.


adapter.Update(table.Select(null, null, DataViewRowState.Added));

Use a DataAdapter to retrieve and update data


You can use a DataAdapter to retrieve and update the data.
The sample uses DataAdapter.AcceptChangesDuringFill to clone the data in the database. If the property is
set as false , AcceptChanges is not called when filling the table, and the newly added rows are treated as
inserted rows. So, the sample uses these rows to insert the new rows into the database.
The samples uses DataAdapter.TableMappings to define the mapping between the source table and
DataTable.
The sample uses DataAdapter.FillLoadOption to determine how the adapter fills the DataTable from the
DbDataReader . When you create a DataTable, you can only write the data from database to the current
version or the original version by setting the property as the LoadOption.Upser t or the
LoadOption.Preser veChanges .
The sample will also update the table by using DbDataAdapter.UpdateBatchSize to perform batch
operations.
Before you compile and run the sample, you need to create the sample database:
USE [master]
GO

CREATE DATABASE [MySchool]

GO

USE [MySchool]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Course]([CourseID] [nvarchar](10) NOT NULL,
[Year] [smallint] NOT NULL,
[Title] [nvarchar](100) NOT NULL,
[Credits] [int] NOT NULL,
[DepartmentID] [int] NOT NULL,
CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED
(
[CourseID] ASC,
[Year] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Department]([DepartmentID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Budget] [money] NOT NULL,
[StartDate] [datetime] NOT NULL,
[Administrator] [int] NULL,
CONSTRAINT [PK_Department] PRIMARY KEY CLUSTERED
(
[DepartmentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]

GO

INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1045', 2012,
N'Calculus', 4, 7)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1061', 2012,
N'Physics', 4, 1)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2021', 2012,
N'Composition', 3, 2)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2042', 2012,
N'Literature', 4, 2)

SET IDENTITY_INSERT [dbo].[Department] ON

INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (1,


N'Engineering', 350000.0000, CAST(0x0000999C00000000 AS DateTime), 2)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (2,
N'English', 120000.0000, CAST(0x0000999C00000000 AS DateTime), 6)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (4,
N'Economics', 200000.0000, CAST(0x0000999C00000000 AS DateTime), 4)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (7,
N'Mathematics', 250024.0000, CAST(0x0000999C00000000 AS DateTime), 3)
SET IDENTITY_INSERT [dbo].[Department] OFF

ALTER TABLE [dbo].[Course] WITH CHECK ADD CONSTRAINT [FK_Course_Department] FOREIGN KEY([DepartmentID])
REFERENCES [dbo].[Department] ([DepartmentID])
REFERENCES [dbo].[Department] ([DepartmentID])
GO
ALTER TABLE [dbo].[Course] CHECK CONSTRAINT [FK_Course_Department]
GO

using System;
using System.Data;
using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Linq;
using CSDataAdapterOperations.Properties;

class Program
{
static void Main(string[] args)
{
Settings settings = new Settings();

// Copy the data from the database. Get the table Department and Course from the database.
String selectString = @"SELECT [DepartmentID],[Name],[Budget],[StartDate],[Administrator]
FROM [MySchool].[dbo].[Department];

SELECT [CourseID],@Year as [Year],Max([Title]) as [Title],


Max([Credits]) as [Credits],Max([DepartmentID]) as [DepartmentID]
FROM [MySchool].[dbo].[Course]
Group by [CourseID]";

DataSet mySchool = new DataSet();

SqlCommand selectCommand = new SqlCommand(selectString);


SqlParameter parameter = selectCommand.Parameters.Add("@Year", SqlDbType.SmallInt, 2);
parameter.Value = new Random(DateTime.Now.Millisecond).Next(9999);

// Use DataTableMapping to map the source tables and the destination tables.
DataTableMapping[] tableMappings = { new DataTableMapping("Table", "Department"), new
DataTableMapping("Table1", "Course") };
CopyData(mySchool, settings.MySchoolConnectionString, selectCommand, tableMappings);

Console.WriteLine("The following tables are from the database.");


foreach (DataTable table in mySchool.Tables)
{
Console.WriteLine(table.TableName);
ShowDataTable(table);
}

// Roll back the changes


DataTable department = mySchool.Tables["Department"];
DataTable course = mySchool.Tables["Course"];

department.Rows[0]["Name"] = "New" + department.Rows[0][1];


course.Rows[0]["Title"] = "New" + course.Rows[0]["Title"];
course.Rows[0]["Credits"] = 10;

Console.WriteLine("After we changed the tables:");


foreach (DataTable table in mySchool.Tables)
{
Console.WriteLine(table.TableName);
ShowDataTable(table);
}

department.RejectChanges();
Console.WriteLine("After use the RejectChanges method in Department table to roll back the
changes:");
ShowDataTable(department);

DataColumn[] primaryColumns = { course.Columns["CourseID"] };


DataColumn[] resetColumns = { course.Columns["Title"] };
ResetCourse(course, settings.MySchoolConnectionString, primaryColumns, resetColumns);
Console.WriteLine("After use the ResetCourse method in Course table to roll back the changes:");
ShowDataTable(course);

// Batch update the table.


String insertString = @"Insert into [MySchool].[dbo].[Course]([CourseID],[Year],[Title],
[Credits],[DepartmentID])
values (@CourseID,@Year,@Title,@Credits,@DepartmentID)";
SqlCommand insertCommand = new SqlCommand(insertString);
insertCommand.Parameters.Add("@CourseID", SqlDbType.NVarChar, 10, "CourseID");
insertCommand.Parameters.Add("@Year", SqlDbType.SmallInt, 2, "Year");
insertCommand.Parameters.Add("@Title", SqlDbType.NVarChar, 100, "Title");
insertCommand.Parameters.Add("@Credits", SqlDbType.Int, 4, "Credits");
insertCommand.Parameters.Add("@DepartmentID", SqlDbType.Int, 4, "DepartmentID");

const Int32 batchSize = 10;


BatchInsertUpdate(course, settings.MySchoolConnectionString, insertCommand, batchSize);
}

private static void CopyData(DataSet dataSet, String connectionString, SqlCommand selectCommand,


DataTableMapping[] tableMappings)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
selectCommand.Connection = connection;

connection.Open();

using (SqlDataAdapter adapter = new SqlDataAdapter(selectCommand))


{
adapter.TableMappings.AddRange(tableMappings);
// If set the AcceptChangesDuringFill as the false, AcceptChanges will not be called on a
// DataRow after it is added to the DataTable during any of the Fill operations.
adapter.AcceptChangesDuringFill = false;

adapter.Fill(dataSet);
}
}
}

// Roll back only one column or several columns data of the Course table by call ResetDataTable method.
private static void ResetCourse(DataTable table, String connectionString,
DataColumn[] primaryColumns, DataColumn[] resetColumns)
{
table.PrimaryKey = primaryColumns;

// Build the query string


String primaryCols = String.Join(",", primaryColumns.Select(col => col.ColumnName));
String resetCols = String.Join(",", resetColumns.Select(col => $"Max({col.ColumnName}) as
{col.ColumnName}"));

String selectString = $"Select {primaryCols},{resetCols} from Course Group by {primaryCols}";

SqlCommand selectCommand = new SqlCommand(selectString);

ResetDataTable(table, connectionString, selectCommand);


}

// RejectChanges will roll back all changes made to the table since it was loaded, or the last time
AcceptChanges
// was called. When you copy from the database, you can lose all the data after calling RejectChanges
// The ResetDataTable method rolls back one or more columns of data.
private static void ResetDataTable(DataTable table, String connectionString,
SqlCommand selectCommand)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
selectCommand.Connection = connection;

connection.Open();
connection.Open();

using (SqlDataAdapter adapter = new SqlDataAdapter(selectCommand))


{
// The incoming values for this row will be written to the current version of each
// column. The original version of each column's data will not be changed.
adapter.FillLoadOption = LoadOption.Upsert;

adapter.Fill(table);
}
}
}

private static void BatchInsertUpdate(DataTable table, String connectionString,


SqlCommand insertCommand, Int32 batchSize)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
insertCommand.Connection = connection;
// When setting UpdateBatchSize to a value other than 1, all the commands
// associated with the SqlDataAdapter have to have their UpdatedRowSource
// property set to None or OutputParameters. An exception is thrown otherwise.
insertCommand.UpdatedRowSource = UpdateRowSource.None;

connection.Open();

using (SqlDataAdapter adapter = new SqlDataAdapter())


{
adapter.InsertCommand = insertCommand;
// Gets or sets the number of rows that are processed in each round-trip to the server.
// Setting it to 1 disables batch updates, as rows are sent one at a time.
adapter.UpdateBatchSize = batchSize;

adapter.Update(table);

Console.WriteLine("Successfully to update the table.");


}
}
}

private static void ShowDataTable(DataTable table)


{
foreach (DataColumn col in table.Columns)
{
Console.Write("{0,-14}", col.ColumnName);
}
Console.WriteLine("{0,-14}", "RowState");

foreach (DataRow row in table.Rows)


{
foreach (DataColumn col in table.Columns)
{
if (col.DataType.Equals(typeof(DateTime)))
Console.Write("{0,-14:d}", row[col]);
else if (col.DataType.Equals(typeof(Decimal)))
Console.Write("{0,-14:C}", row[col]);
else
Console.Write("{0,-14}", row[col]);
}
Console.WriteLine("{0,-14}", row.RowState);
}
}
}

namespace CSDataAdapterOperations.Properties
{
internal sealed partial class Settings : System.Configuration.ApplicationSettingsBase
{
private static readonly Settings defaultInstance =
((Settings)(System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
((Settings)(System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

public static Settings Default => defaultInstance;

[System.Configuration.ApplicationScopedSetting()]
[System.Configuration.DefaultSettingValue("Data Source=(local);Initial Catalog=MySchool;Integrated
Security=True")]
public string MySchoolConnectionString => ((string)(this["MySchoolConnectionString"]));
}
}

See also
DataAdapters and DataReaders
Retrieve identity or autonumber values
Microsoft ADO.NET for SQL Server
Handle DataAdapter events
4/27/2022 • 5 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The Microsoft SqlClient data provider for SQL Server SqlDataAdapter exposes three events that you can use to
respond to changes made to data at the data source. The following table shows the DataAdapter events.

EVEN T DESC RIP T IO N

RowUpdating An UPDATE, INSERT, or DELETE operation on a row (by a call


to one of the Update methods) is about to begin.

RowUpdated An UPDATE, INSERT, or DELETE operation on a row (by a call


to one of the Update methods) is complete.

FillError An error has occurred during a Fill operation.

RowUpdating and RowUpdated events


RowUpdating is raised before any update to a row from the DataSet has been processed at the data source.
RowUpdated is raised after any update to a row from the DataSet has been processed at the data source. As a
result, you can use RowUpdating to modify update behavior before it happens, to provide additional handling
when an update will occur, to retain a reference to an updated row, to cancel the current update and schedule it
for a batch process to be processed later, and so on. RowUpdated is useful for responding to errors and
exceptions that occur during the update. You can add error information to the DataSet , as well as retr y
logic , and so on.
The RowUpdatingEventArgs and RowUpdatedEventArgs arguments passed to the RowUpdating and RowUpdated
events include the following: a Command property that references the Command object being used to perform the
update; a Row property that references the DataRow object containing the updated information; a
StatementType property for what type of update is being performed; the TableMapping , if applicable; and the
Status of the operation.

You can use the Status property to determine if an error has occurred during the operation and, if desired, to
control the actions against the current and resulting rows. When the event occurs, the Status property equals
either Continue or ErrorsOccurred . The following table shows the values to which you can set the Status
property in order to control later actions during the update.

STAT US DESC RIP T IO N

Continue Continue the update operation.

ErrorsOccurred Abort the update operation and throw an exception.

SkipCurrentRow Ignore the current row and continue the update operation.
STAT US DESC RIP T IO N

SkipAllRemainingRows Abort the update operation but do not throw an exception.

Setting the Status property to ErrorsOccurred causes an exception to be thrown. You can control which
exception is thrown by setting the Errors property to the desired exception. Using one of the other values for
Status prevents an exception from being thrown.

You can also use the ContinueUpdateOnError property to handle errors for updated rows. If
DataAdapter.ContinueUpdateOnError is true , when an update to a row results in an exception being thrown, the
text of the exception is placed into the RowError information of the particular row, and processing continues
without throwing an exception. This enables you to respond to errors when the Update is complete, in contrast
to the RowUpdated event, which enables you to respond to errors when the error is encountered.
The following code sample shows how to both add and remove event handlers. The RowUpdating event handler
writes a log of all deleted records with a time stamp. The RowUpdated event handler adds error information to
the RowError property of the row in the DataSet , suppresses the exception, and continues processing
(mirroring the behavior of ContinueUpdateOnError = true ).
static DataSet DataAdapterEventsDemo(SqlConnection connection, DataSet custDS)
{
// Assumes that connection is a valid SqlConnection object
// and custDS includes the Customers table.
SqlDataAdapter custAdapter = new SqlDataAdapter(
"SELECT CustomerID, CompanyName FROM Customers", connection);

// Add handlers.
custAdapter.RowUpdating += new SqlRowUpdatingEventHandler(OnRowUpdating);
custAdapter.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated);

// Set DataAdapter command properties, fill DataSet, modify DataSet.


custAdapter.Update(custDS, "Customers");

// Remove handlers.
custAdapter.RowUpdating -= new SqlRowUpdatingEventHandler(OnRowUpdating);
custAdapter.RowUpdated -= new SqlRowUpdatedEventHandler(OnRowUpdated);

return custDS;
}

protected static void OnRowUpdating(object sender, SqlRowUpdatingEventArgs args)


{
if (args.StatementType == StatementType.Delete)
{
// Saves the removing rows with additional information in a file.
System.IO.TextWriter tw = System.IO.File.AppendText("Deletes.log");
tw.WriteLine(
"{0}: Customer {1} Deleted.", DateTime.Now,
args.Row["CustomerID", DataRowVersion.Original]);
tw.Close();
}
}

protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs args)


{
if (args.Status == UpdateStatus.ErrorsOccurred)
{
// Adds the error message to the row and skips from it.
args.Row.RowError = args.Errors.Message;
args.Status = UpdateStatus.SkipCurrentRow;
}
}

FillError event
The DataAdapter issues the FillError event when an error occurs during a Fill operation. This type of error
commonly occurs when the data in the row being added could not be converted to a .NET type without some
loss of precision.
If an error occurs during a Fill operation, the current row is not added to the DataTable . The FillError event
enables you to resolve the error and add the row, or to ignore the excluded row and continue the Fill
operation.
The FillErrorEventArgs passed to the FillError event can contain several properties that enable you to respond
to and resolve errors. The following table shows the properties of the FillErrorEventArgs object.

P RO P ERT Y DESC RIP T IO N

Errors The Exception that occurred.


P RO P ERT Y DESC RIP T IO N

DataTable The DataTable object being filled when the error occurred.

Values An array of objects that contains the values of the row being
added when the error occurred. The ordinal references of the
Values array correspond to the ordinal references of the
columns of the row being added. For example, Values[0]
is the value that was being added as the first column of the
row.

Continue Allows you to choose whether or not to throw an exception.


Setting the Continue property to false will halt the
current Fill operation, and an exception will be thrown.
Setting Continue to true continues the Fill operation
despite the error.

The following code example adds an event handler for the FillError event of the DataAdapter . In the
FillError event code, the example determines if there is the potential for precision loss, providing the
opportunity to respond to the exception.

static DataSet DataAdapterFillAndError(SqlDataAdapter adapter)


{
// Assuemes adapter is a valid SqlDataAdapter object.
adapter.FillError += new FillErrorEventHandler(FillError);

DataSet dataSet = new DataSet();


adapter.Fill(dataSet);
return dataSet;
}

protected static void FillError(object sender, FillErrorEventArgs args)


{
if (args.Errors.GetType() == typeof(System.OverflowException))
{
// Code to handle precision loss.
// Add a row to table using the values from the first two columns.
DataRow myRow = args.DataTable.Rows.Add(new object[]
{args.Values[0], args.Values[1], DBNull.Value});
//Set the RowError containing the value for the third column.
myRow.RowError =
"OverflowException Encountered. Value from data source: " +
args.Values[2];
args.Continue = true;
}
}

See also
DataAdapters and DataReaders
Events
Microsoft ADO.NET for SQL Server
Batch operations using DataAdapters
4/27/2022 • 4 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Batch support in ADO.NET allows a DataAdapter to group INSERT, UPDATE, and DELETE operations from a
DataSet or DataTable to the server, instead of sending one operation at a time. The reduction in the number of
round trips to the server typically results in significant performance gains. Batch update is supported for the
Microsoft SqlClient data provider for SQL Server (Microsoft.Data.SqlClient).
When updating a database with changes from a DataSet in previous versions of ADO.NET, the Update method
of a DataAdapter performed updates to the database one row at a time. As it iterated through the rows in the
specified DataTable, it examined each DataRow to see if it had been modified. If the row had been modified, it
called the appropriate UpdateCommand , InsertCommand , or DeleteCommand , depending on the value of the
RowState property for that row. Every row update involved a network round-trip to the database.
At the Microsoft SqlClient Data Provider for SQL Server, the SqlDataAdapter exposes an UpdateBatchSize
property. Setting the UpdateBatchSize to a positive integer value causes updates to the database to be sent as
batches of the specified size. For example, setting the UpdateBatchSize to 10 will group 10 separate statements
and submit them as single batch. Setting the UpdateBatchSize to 0 will cause the SqlDataAdapter to use the
largest batch size that the server can handle. Setting it to 1 disables batch updates, as rows are sent one at a
time.

NOTE
Executing an extremely large batch could decrease performance. Therefore, you should test for the optimum batch size
setting before implementing your application.

Use the UpdateBatchSize property


When batch updates are enabled, the UpdatedRowSource property value of the DataAdapter's UpdateCommand ,
InsertCommand , and DeleteCommand should be set to None or OutputParameters. When performing a batch
update, the command's UpdatedRowSource property value of FirstReturnedRecord or Both is invalid.
The following procedure demonstrates the use of the UpdateBatchSize property. The procedure takes two
arguments, a DataSet object that has columns representing the ProductCategor yID and Name fields in the
Production.ProductCategor y table, and an integer representing the batch size (the number of rows in the
batch). The code creates a new SqlDataAdapter object, setting its UpdateCommand, InsertCommand, and
DeleteCommand properties. The code assumes that the DataSet object has modified rows. It sets the
UpdateBatchSize property and executes the update.
public static void BatchUpdate(DataTable dataTable, Int32 batchSize)
{
// Assumes GetConnectionString() returns a valid connection string.
string connectionString = GetConnectionString();

// Connect to the AdventureWorks database.


using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create a SqlDataAdapter.
SqlDataAdapter adapter = new SqlDataAdapter();

// Set the UPDATE command and parameters.


adapter.UpdateCommand = new SqlCommand(
"UPDATE Production.ProductCategory SET "
+ "Name=@Name WHERE ProductCategoryID=@ProdCatID;",
connection);
adapter.UpdateCommand.Parameters.Add("@Name",
SqlDbType.NVarChar, 50, "Name");
adapter.UpdateCommand.Parameters.Add("@ProdCatID",
SqlDbType.Int, 4, "ProductCategoryID");
adapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;

// Set the INSERT command and parameter.


adapter.InsertCommand = new SqlCommand(
"INSERT INTO Production.ProductCategory (Name) VALUES (@Name);",
connection);
adapter.InsertCommand.Parameters.Add("@Name",
SqlDbType.NVarChar, 50, "Name");
adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.None;

// Set the DELETE command and parameter.


adapter.DeleteCommand = new SqlCommand(
"DELETE FROM Production.ProductCategory "
+ "WHERE ProductCategoryID=@ProdCatID;", connection);
adapter.DeleteCommand.Parameters.Add("@ProdCatID",
SqlDbType.Int, 4, "ProductCategoryID");
adapter.DeleteCommand.UpdatedRowSource = UpdateRowSource.None;

// Set the batch size.


adapter.UpdateBatchSize = batchSize;

// Execute the update.


adapter.Update(dataTable);
}
}

Handle batch update-related events and errors


The DataAdapter has two update-related events: RowUpdating and RowUpdated . For more information, see
Handle DataAdapter events.
Event behavior changes with batch updates
When batch processing is enabled, multiple rows are updated in a single database operation. Therefore, only
one RowUpdated event occurs for each batch, whereas the RowUpdating event occurs for each row processed.
When batch processing is disabled, the two events are fired with one-to-one interleaving, where one
RowUpdating event and one RowUpdated event fire for a row, and then one RowUpdating and one RowUpdated
event fire for the next row, until all of the rows are processed.
Access updated rows
When batch processing is disabled, the row being updated can be accessed using the Row property of the
RowUpdatedEventArgs class.
When batch processing is enabled, a single RowUpdated event is generated for multiple rows. Therefore, the
value of the Row property for each row is null. RowUpdating events are still generated for each row. The
CopyToRows method of the RowUpdatedEventArgs class allows you to access the processed rows by copying
references to the rows into an array. If no rows are being processed, CopyToRows throws an
ArgumentNullException. Use the RowCount property to return the number of rows processed before calling the
CopyToRows method.
Handle data errors
Batch execution has the same effect as the execution of each individual statement. Statements are executed in
the order that the statements were added to the batch. Errors are handled the same way in batch mode as they
are when batch mode is disabled. Each row is processed separately. Only rows that have been successfully
processed in the database will be updated in the corresponding DataRow within the DataTable.

NOTE
The Microsoft SqlClient Data Provider for SQL Server and the back-end database server determine which SQL constructs
are supported for batch execution. An exception may be thrown if a non-supported statement is submitted for execution.

See also
DataAdapters and DataReaders
Update data sources with DataAdapters
Handle DataAdapter events
Microsoft ADO.NET for SQL Server
Transactions and concurrency
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
A transaction consists of a single command or a group of commands that execute as a package. Transactions
allow you to combine multiple operations into a single unit of work. If a failure occurs at one point in the
transaction, all of the updates can be rolled back to their pre-transaction state.
A transaction must conform to the ACID properties—atomicity, consistency, isolation, and durability—in order to
guarantee data consistency. Most relational database systems, such as Microsoft SQL Server, support
transactions by providing locking, logging, and transaction management facilities whenever a client application
performs an update, insert, or delete operation.

NOTE
Transactions that involve multiple resources can lower concurrency if locks are held too long. Therefore, keep transactions
as short as possible.

If a transaction involves multiple tables in the same database or server, then explicit transactions in stored
procedures often perform better. You can create transactions in SQL Server stored procedures by using the
Transact-SQL BEGIN TRANSACTION , COMMIT TRANSACTION , and ROLLBACK TRANSACTION statements. For more
information, see SQL Server Books Online.
Transactions involving different resource managers, such as a transaction between SQL Server and Oracle,
require a distributed transaction.

In this section
Local transactions
Demonstrates how to perform transactions against a database.
Distributed transactions
Describes how to perform distributed transactions in ADO.NET.
System.Transactions integration with SQL Server
Describes System.Transactions integration with SQL Server for working with distributed transactions.
Optimistic concurrency Describes optimistic and pessimistic concurrency, and how you can test for concurrency
violations.

See also
Transaction fundamentals
Connecting to data source
Commands and parameters
DataAdapters and DataReaders
DbProviderFactories
Microsoft ADO.NET for SQL Server
Local transactions
4/27/2022 • 3 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Transactions in ADO.NET are used when you want to bind multiple tasks together so that they execute as a single
unit of work. For example, imagine that an application performs two tasks. First, it updates a table with order
information. Second, it updates a table that contains inventory information, debiting the items ordered. If either
task fails, then both updates are rolled back.

Determining the transaction type


A transaction is considered to be a local transaction when it is a single-phase transaction and is handled by the
database directly. A transaction is considered to be a distributed transaction when it is coordinated by a
transaction monitor and uses fail-safe mechanisms (such as two-phase commit) for transaction resolution.
The Microsoft SqlClient Data Provider for SQL Server has its own SqlTransaction object for performing local
transactions in SQL Server databases. Other .NET data providers also provide their own Transaction objects. In
addition, there is a DbTransaction class that is available for writing provider-independent code that requires
transactions.

NOTE
Transactions are most efficient when they are performed on the server. If you are working with a SQL Server database that
makes extensive use of explicit transactions, consider writing them as stored procedures using the Transact-SQL BEGIN
TRANSACTION statement.

Performing a transaction using a single connection


In ADO.NET, you control transactions with the Connection object. You can initiate a local transaction with the
BeginTransaction method. Once you have begun a transaction, you can enlist a command in that transaction
with the Transaction property of a Command object. You can then commit or roll back modifications made at the
data source based on the success or failure of the components of the transaction.

NOTE
The EnlistDistributedTransaction method should not be used for a local transaction.

The scope of the transaction is limited to the connection. The following example performs an explicit transaction
that consists of two separate commands in the try block. The commands execute INSERT statements against
the Production.ScrapReason table in the AdventureWorks SQL Server sample database, which are committed if
no exceptions are thrown. The code in the catch block rolls back the transaction if an exception is thrown. If the
transaction is aborted or the connection is closed before the transaction has completed, it is automatically rolled
back.

Example
Follow these steps to perform a transaction.
1. Call the BeginTransaction method of the SqlConnection object to mark the start of the transaction. The
BeginTransaction method returns a reference to the transaction. This reference is assigned to the
SqlCommand objects that are enlisted in the transaction.
2. Assign the Transaction object to the Transaction property of the SqlCommand to be executed. If a
command is executed on a connection with an active transaction, and the Transaction object has not
been assigned to the Transaction property of the Command object, an exception is thrown.
3. Execute the required commands.
4. Call the Commit method of the SqlTransaction object to complete the transaction, or call the Rollback
method to end the transaction. If the connection is closed or disposed before either the Commit or
Rollback methods have been executed, the transaction is rolled back.
The following code example demonstrates transactional logic using the Microsoft SqlClient Data Provider for
SQL Server.
using System;
using Microsoft.Data.SqlClient;

class Program
{
static void Main(string[] args)
{
string connectionString = "Data Source = localhost; Integrated Security = true; Initial Catalog =
AdventureWorks";

using (SqlConnection connection = new SqlConnection(connectionString))


{
connection.Open();

// Start a local transaction.


SqlTransaction sqlTran = connection.BeginTransaction();

// Enlist a command in the current transaction.


SqlCommand command = connection.CreateCommand();
command.Transaction = sqlTran;

try
{
// Execute two separate commands.
command.CommandText =
"INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')";
command.ExecuteNonQuery();
command.CommandText =
"INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')";
command.ExecuteNonQuery();

// Commit the transaction.


sqlTran.Commit();
Console.WriteLine("Both records were written to database.");
}
catch (Exception ex)
{
// Handle the exception if the transaction fails to commit.
Console.WriteLine(ex.Message);

try
{
// Attempt to roll back the transaction.
sqlTran.Rollback();
}
catch (Exception exRollback)
{
// Throws an InvalidOperationException if the connection
// is closed or the transaction has already been rolled
// back on the server.
Console.WriteLine(exRollback.Message);
}
}
}
}
}

See also
Transactions and concurrency
Distributed transactions
System.Transactions integration with SQL Server
Microsoft ADO.NET for SQL Server
Distributed transactions
4/27/2022 • 4 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
A transaction is a set of related tasks that either succeeds (commit) or fails (abort) as a unit, among other things.
A distributed transaction is a transaction that affects several resources. For a distributed transaction to commit,
all participants must guarantee that any change to data will be permanent. Changes must persist despite system
crashes or other unforeseen events. If even a single participant fails to make this guarantee, the entire
transaction fails, and any changes to data within the scope of the transaction are rolled back.

NOTE
An exception will be thrown if you attempt to commit or roll back a transaction if a DataReader is started while the
transaction is active.

Working with System.Transactions


In .NET, distributed transactions are managed through the API in the System.Transactions namespace. The
System.Transactions API will delegate distributed transaction handling to a transaction monitor such as the
Microsoft Distributed Transaction Coordinator (MS DTC) when multiple persistent resource managers are
involved. For more information, see Transaction Fundamentals.
ADO.NET 2.0 introduced support for enlisting in a distributed transaction using the EnlistTransaction method,
which enlists a connection in a Transaction instance. In previous versions of ADO.NET, explicit enlistment in
distributed transactions was performed using the EnlistDistributedTransaction method of a connection to
enlist a connection in a ITransaction instance, which is supported for backwards compatibility. For more
information on Enterprise Services transactions, see Interoperability with Enterprise Services and COM+
Transactions.
When using a System.Transactions transaction with the Microsoft SqlClient Data Provider for SQL Server against
a SQL Server database, a lightweight Transaction will automatically be used. The transaction can then be
promoted to a full distributed transaction on an as-needed basis. For more information, see System.Transactions
integration with SQL Server.

Automatically enlisting in a distributed transaction


Automatic enlistment is the default (and preferred) way of integrating ADO.NET connections with
System.Transactions . A connection object will automatically enlist in an existing distributed transaction if it
determines that a transaction is active, which, in System.Transaction terms, means that Transaction.Current is
not null. Automatic transaction enlistment occurs when the connection is opened. It will not happen after that
even if a command is executed inside of a transaction scope. You can disable auto-enlistment in existing
transactions by specifying Enlist=false as a connection string parameter for a
SqlConnection.ConnectionString.

Manually enlisting in a distributed transaction


If auto-enlistment is disabled or you need to enlist a transaction that was started after the connection was
opened, you can enlist in an existing distributed transaction using the EnlistTransaction method of the
SqlConnection object for the Microsoft SqlClient Data Provider for SQL Server. Enlisting in an existing
distributed transaction ensures that, if the transaction is committed or rolled back, modifications made by the
code at the data source will be committed or rolled back as well.
Enlisting in distributed transactions is particularly applicable when pooling business objects. If a business object
is pooled with an open connection, automatic transaction enlistment only occurs when that connection is
opened. If multiple transactions are performed using the pooled business object, the open connection for that
object will not automatically enlist in newly initiated transactions. In this case, you can disable automatic
transaction enlistment for the connection and enlist the connection in transactions using EnlistTransaction .
EnlistTransaction takes a single argument of type Transaction that is a reference to the existing transaction.
After calling the connection's EnlistTransaction method, all modifications made at the data source using the
connection are included in the transaction. Passing a null value unenlists the connection from its current
distributed transaction enlistment. Note that the connection must be opened before calling EnlistTransaction .

NOTE
Once a connection is explicitly enlisted on a transaction, it cannot be un-enlisted or enlisted in another transaction until
the first transaction finishes.

Cau t i on

EnlistTransaction throws an exception if the connection has already begun a transaction using the connection's
BeginTransaction method. However, if the transaction is a local transaction started at the data source (for
example, executing the BEGIN TRANSACTION statement explicitly using a SqlCommand), EnlistTransaction will
roll back the local transaction and enlist in the existing distributed transaction as requested. You will not receive
notice that the local transaction was rolled back, and must manage any local transactions not started using
BeginTransaction. If you are using the Microsoft SqlClient Data Provider for SQL Server with SQL Server, an
attempt to enlist will throw an exception. All other cases will go undetected.

Promotable transactions in SQL Server


SQL Server supports promotable transactions in which a local lightweight transaction can be automatically
promoted to a distributed transaction only if it is required. A promotable transaction does not invoke the added
overhead of a distributed transaction unless the added overhead is required. For more information and a code
sample, see System.Transactions integration with SQL Server.

Configuring Distributed Transactions


You may need to enable the MS DTC over the network in order to use distributed transactions. If have the
Windows Firewall enabled, you must allow the MS DTC service to use the network or open the MS DTC port.

See also
Transactions and concurrency
System.Transactions integration with SQL Server
Microsoft ADO.NET for SQL Server
System.Transactions integration with SQL Server
4/27/2022 • 6 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
.NET includes a transaction framework that can be accessed through the System.Transactions namespace. This
framework exposes transactions in a way that is fully integrated in .NET, including ADO.NET.
In addition to the programmability enhancements, System.Transactions and ADO.NET can work together to
coordinate optimizations when you work with transactions. A promotable transaction is a lightweight (local)
transaction that can be automatically promoted to a fully distributed transaction on an as-needed basis.
The Microsoft SqlClient Data Provider for SQL Server supports promotable transactions when you work with
SQL Server. A promotable transaction does not invoke the added overhead of a distributed transaction unless
the added overhead is required. Promotable transactions are automatic and require no intervention from the
developer.

Creating promotable transactions


The Microsoft SqlClient Data Provider for SQL Server provides support for promotable transactions, which are
handled through the classes in the System.Transactions namespace. Promotable transactions optimize
distributed transactions by deferring creating a distributed transaction until it is needed. If only one resource
manager is required, no distributed transaction occurs.

NOTE
In a partially trusted scenario, the DistributedTransactionPermission is required when a transaction is promoted to a
distributed transaction.

Promotable transaction scenarios


Distributed transactions typically consume significant system resources, being managed by Microsoft
Distributed Transaction Coordinator (MS DTC), which integrates all the resource managers accessed in the
transaction. A promotable transaction is a special form of a System.Transactions transaction that effectively
delegates the work to a simple SQL Server transaction. System.Transactions, Microsoft.Data.SqlClient, and SQL
Server coordinate the work involved in handling the transaction, promoting it to a full distributed transaction as
needed.
The benefit of using promotable transactions is that when a connection is opened by using an active
TransactionScope transaction, and no other connections are opened, the transaction commits as a lightweight
transaction, instead of incurring the additional overhead of a full distributed transaction.
Connection string keywords
The ConnectionString property supports a keyword, Enlist , which indicates whether Microsoft.Data.SqlClient
will detect transactional contexts and automatically enlist the connection in a distributed transaction. If
Enlist=true , the connection is automatically enlisted in the opening thread's current transaction context. If
Enlist=false , the SqlClient connection does not interact with a distributed transaction. The default value for
Enlist is true. If Enlist is not specified in the connection string, the connection is automatically enlisted in a
distributed transaction if one is detected when the connection is opened.
The Transaction Binding keywords in a SqlConnection connection string control the connection's association
with an enlisted System.Transactions transaction. It is also available through the TransactionBinding property of
a SqlConnectionStringBuilder.
The following table describes the possible values.

K EY W O RD DESC RIP T IO N

Implicit Unbind The default. The connection detaches from the transaction
when it ends, switching back to autocommit mode.

Explicit Unbind The connection remains attached to the transaction until the
transaction is closed. The connection will fail if the associated
transaction is not active or does not match Current.

Using TransactionScope
The TransactionScope class makes a code block transactional by implicitly enlisting connections in a distributed
transaction. You must call the Complete method at the end of the TransactionScope block before leaving it.
Leaving the block invokes the Dispose method. If an exception has been thrown that causes the code to leave
scope, the transaction is considered aborted.
We recommend that you use a using block to make sure that Dispose is called on the TransactionScope object
when the using block is exited. Failure to commit or roll back pending transactions can significantly damage
performance because the default time-out for the TransactionScope is one minute. If you do not use a using
statement, you must perform all work in a Try block and explicitly call the Dispose method in the Finally
block.
If an exception occurs in the TransactionScope, the transaction is marked as inconsistent and is abandoned. It will
be rolled back when the TransactionScope is disposed. If no exception occurs, participating transactions commit.

NOTE
The TransactionScope class creates a transaction with a IsolationLevel of Serializable by default. Depending on
your application, you might want to consider lowering the isolation level to avoid high contention in your application.

NOTE
We recommend that you perform only updates, inserts, and deletes within distributed transactions because they
consume significant database resources. Select statements may lock database resources unnecessarily, and in some
scenarios, you may have to use transactions for selects. Any non-database work should be done outside the scope of the
transaction, unless it involves other transacted resource managers. Although an exception in the scope of the transaction
prevents the transaction from committing, the TransactionScope class has no provision for rolling back any changes your
code has made outside the scope of the transaction itself. If you have to take some action when the transaction is rolled
back, you must write your own implementation of the IEnlistmentNotification interface and explicitly enlist in the
transaction.

Example
Working with System.Transactions requires that you have a reference to System.Transactions.dll.
The following function demonstrates how to create a promotable transaction against two different SQL Server
instances, represented by two different SqlConnection objects, which are wrapped in a TransactionScope block.
The code below creates the TransactionScope block with a using statement and opens the first connection,
which automatically enlists it in the TransactionScope.
The transaction is initially enlisted as a lightweight transaction, not a full distributed transaction. The second
connection is enlisted in the TransactionScope only if the command in the first connection does not throw an
exception. When the second connection is opened, the transaction is automatically promoted to a full distributed
transaction.
Later, the Complete method is invoked, which commits the transaction only if no exceptions have been thrown. If
an exception has been thrown at any point in the TransactionScope block, Complete will not be called, and the
distributed transaction will roll back when the TransactionScope is disposed at the end of its using block.

using System;
using System.Transactions;
using Microsoft.Data.SqlClient;

class Program
{
static void Main(string[] args)
{
string connectionString = "Data Source = localhost; Integrated Security = true; Initial Catalog =
AdventureWorks";

string commandText1 = "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')";


string commandText2 = "INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')";

int result = CreateTransactionScope(connectionString, connectionString, commandText1, commandText2);

Console.WriteLine("result = " + result);


}

static public int CreateTransactionScope(string connectString1, string connectString2,


string commandText1, string commandText2)
{
// Initialize the return value to zero and create a StringWriter to display results.
int returnValue = 0;
System.IO.StringWriter writer = new System.IO.StringWriter();

// Create the TransactionScope in which to execute the commands, guaranteeing


// that both commands will commit or roll back as a single unit of work.
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection connection1 = new SqlConnection(connectString1))
{
try
{
// Opening the connection automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();

// Create the SqlCommand object and execute the first command.


SqlCommand command1 = new SqlCommand(commandText1, connection1);
returnValue = command1.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command1: {0}", returnValue);

// if you get here, this means that command1 succeeded. By nesting


// the using block for connection2 inside that of connection1, you
// conserve server and network resources by opening connection2
// only when there is a chance that the transaction can commit.
using (SqlConnection connection2 = new SqlConnection(connectString2))
try
{
// The transaction is promoted to a full distributed
// transaction when connection2 is opened.
// transaction when connection2 is opened.
connection2.Open();

// Execute the second command in the second database.


returnValue = 0;
SqlCommand command2 = new SqlCommand(commandText2, connection2);
returnValue = command2.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
}
catch (Exception ex)
{
// Display information that command2 failed.
writer.WriteLine("returnValue for command2: {0}", returnValue);
writer.WriteLine("Exception Message2: {0}", ex.Message);
}
}
catch (Exception ex)
{
// Display information that command1 failed.
writer.WriteLine("returnValue for command1: {0}", returnValue);
writer.WriteLine("Exception Message1: {0}", ex.Message);
}
}

// If an exception has been thrown, Complete will not


// be called and the transaction is rolled back.
scope.Complete();
}

// The returnValue is greater than 0 if the transaction committed.


if (returnValue > 0)
{
writer.WriteLine("Transaction was committed.");
}
else
{
// You could write additional business logic here, notify the caller by
// throwing a TransactionAbortedException, or log the failure.
writer.WriteLine("Transaction rolled back.");
}

// Display messages.
Console.WriteLine(writer.ToString());

return returnValue;
}
}

See also
Transactions and concurrency
Microsoft ADO.NET for SQL Server
Optimistic concurrency
4/27/2022 • 8 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
In a multiuser environment, there are two models for updating data in a database: optimistic concurrency and
pessimistic concurrency. The DataSet object is designed to encourage the use of optimistic concurrency for long-
running activities, such as remoting data and interacting with data.
Pessimistic concurrency involves locking rows at the data source to prevent other users from modifying data in
a way that affects the current user. In a pessimistic model, when a user performs an action that causes a lock to
be applied, other users cannot perform actions that would conflict with the lock until the lock owner releases it.
This model is primarily used in environments where there is heavy contention for data, so that the cost of
protecting data with locks is less than the cost of rolling back transactions if concurrency conflicts occur.
Therefore, in a pessimistic concurrency model, a user who updates a row establishes a lock. Until the user has
finished the update and released the lock, no one else can change that row. For this reason, pessimistic
concurrency is best implemented when lock times will be short, as in programmatic processing of records.
Pessimistic concurrency is not a scalable option when users are interacting with data and causing records to be
locked for relatively large periods of time.

NOTE
If you need to update multiple rows in the same operation, then creating a transaction is a more scalable option than
using pessimistic locking.

By contrast, users who use optimistic concurrency do not lock a row when reading it. When a user wants to
update a row, the application must determine whether another user has changed the row since it was read.
Optimistic concurrency is generally used in environments with a low contention for data. Optimistic concurrency
improves performance because no locking of records is required, and locking of records requires additional
server resources. Also, in order to maintain record locks, a persistent connection to the database server is
required. Because this is not the case in an optimistic concurrency model, connections to the server are free to
serve a larger number of clients in less time.
In an optimistic concurrency model, a violation is considered to have occurred if, after a user receives a value
from the database, another user modifies the value before the first user has attempted to modify it. How the
server resolves a concurrency violation is best shown by first describing the following example.
The following tables follow an example of optimistic concurrency.
At 1:00 p.m., User1 reads a row from the database with the following values:
CustID LastName FirstName
101 Smith Bob

C O L UM N N A M E O RIGIN A L VA L UE C URREN T VA L UE VA L UE IN DATA B A SE

CustID 101 101 101


C O L UM N N A M E O RIGIN A L VA L UE C URREN T VA L UE VA L UE IN DATA B A SE

LastName Smith Smith Smith

FirstName Bob Bob Bob

At 1:01 p.m., User2 reads the same row.


At 1:03 p.m., User2 changes FirstName from "Bob" to "Robert" and updates the database.

C O L UM N N A M E O RIGIN A L VA L UE C URREN T VA L UE VA L UE IN DATA B A SE

CustID 101 101 101

LastName Smith Smith Smith

FirstName Bob Robert Bob

The update succeeds because the values in the database at the time of update match the original values that
User2 has.
At 1:05 p.m., User1 changes "Bob"'s first name to "James" and tries to update the row.

C O L UM N N A M E O RIGIN A L VA L UE C URREN T VA L UE VA L UE IN DATA B A SE

CustID 101 101 101

LastName Smith Smith Smith

FirstName Bob James Robert

At this point, User1 encounters an optimistic concurrency violation because the value in the database ("Robert")
no longer matches the original value that User1 was expecting ("Bob"). The concurrency violation simply lets
you know that the update failed. The decision now needs to be made whether to overwrite the changes supplied
by User2 with the changes supplied by User1, or to cancel the changes by User1.

Testing for optimistic concurrency violations


There are several techniques for testing for an optimistic concurrency violation. One involves including a
timestamp column in the table.
Databases commonly provide timestamp functionality that can be used to identify the date and time when the
record was last updated. Using this technique, a timestamp column is included in the table definition. Whenever
the record is updated, the timestamp is updated to reflect the current date and time.
In a test for optimistic concurrency violations, the timestamp column is returned with any query of the contents
of the table. When an update is attempted, the timestamp value in the database is compared to the original
timestamp value contained in the modified row. If they match, the update is performed and the timestamp
column is updated with the current time to reflect the update. If they do not match, an optimistic concurrency
violation has occurred.
Another technique for testing for an optimistic concurrency violation is to verify that all the original column
values in a row still match those found in the database. For example, consider the following query:
SELECT Col1, Col2, Col3 FROM Table1

To test for an optimistic concurrency violation when updating a row in Table1 , you would issue the following
UPDATE statement:

UPDATE Table1 Set Col1 = @NewCol1Value,


Set Col2 = @NewCol2Value,
Set Col3 = @NewCol3Value
WHERE Col1 = @OldCol1Value AND
Col2 = @OldCol2Value AND
Col3 = @OldCol3Value

As long as the original values match the values in the database, the update is performed. If a value has been
modified, the update will not modify the row because the WHERE clause will not find a match.
Note that it is recommended to always return a unique primary key value in your query. Otherwise, the
preceding UPDATE statement may update more than one row, which might not be your intent.
If a column at your data source allows nulls, you may need to extend your WHERE clause to check for a
matching null reference in your local table and at the data source. For example, the following UPDATE statement
verifies that a null reference in the local row still matches a null reference at the data source, or that the value in
the local row still matches the value at the data source.

UPDATE Table1 Set Col1 = @NewVal1


WHERE (@OldVal1 IS NULL AND Col1 IS NULL) OR Col1 = @OldVal1

You may also choose to apply less restrictive criteria when using an optimistic concurrency model. For example,
using only the primary key columns in the WHERE clause causes the data to be overwritten regardless of
whether the other columns have been updated since the last query. You can also apply a WHERE clause only to
specific columns, resulting in data being overwritten unless particular fields have been updated since they were
last queried.
The DataAdapter.RowUpdated event
The RowUpdated event of the DataAdapter object can be used in conjunction with the techniques described
earlier, to provide notification to your application of optimistic concurrency violations. RowUpdated occurs
after each attempt to update a Modified row from a DataSet . This enables you to add special handling code,
including processing when an exception occurs, adding custom error information, adding retry logic, and so on.
The RowUpdatedEventArgs object returns a RecordsAffected property containing the number of rows affected
by a particular update command for a modified row in a table. By setting the update command to test for
optimistic concurrency, the RecordsAffected property will, as a result, return a value of 0 when an optimistic
concurrency violation has occurred, because no records were updated. If this is the case, an exception is thrown.
The RowUpdated event enables you to handle this occurrence and avoid the exception by setting an
appropriate RowUpdatedEventArgs.Status value, such as UpdateStatus.SkipCurrentRow . For more
information about the RowUpdated event, see Handling DataAdapter Events.
Optionally, you can set DataAdapter.ContinueUpdateOnError to true , before calling Update , and respond
to the error information stored in the RowError property of a particular row when the Update is completed.
For more information, see Row Error Information.

Optimistic concurrency example


The following is a simple example that sets the UpdateCommand of a DataAdapter to test for optimistic
concurrency, and then uses the RowUpdated event to test for optimistic concurrency violations. When an
optimistic concurrency violation is encountered, the application sets the RowError of the row that the update
was issued for to reflect an optimistic concurrency violation.
Note that the parameter values passed to the WHERE clause of the UPDATE command are mapped to the
Original values of their respective columns.
using System;
using System.Data;
using Microsoft.Data.SqlClient;

class Program
{
static void Main(string[] args)
{
string connectionString = "Data Source = localhost; Integrated Security = true; Initial Catalog =
Northwind";

using (SqlConnection connection = new SqlConnection(connectionString))


{
// Assumes connection is a valid SqlConnection.
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT CustomerID, CompanyName FROM Customers ORDER BY CustomerID",
connection);

// The Update command checks for optimistic concurrency violations


// in the WHERE clause.
adapter.UpdateCommand = new SqlCommand("UPDATE Customers Set CustomerID = @CustomerID,
CompanyName = @CompanyName " +
"WHERE CustomerID = @oldCustomerID AND CompanyName = @oldCompanyName", connection);
adapter.UpdateCommand.Parameters.Add(
"@CustomerID", SqlDbType.NChar, 5, "CustomerID");
adapter.UpdateCommand.Parameters.Add(
"@CompanyName", SqlDbType.NVarChar, 30, "CompanyName");

// Pass the original values to the WHERE clause parameters.


SqlParameter parameter = adapter.UpdateCommand.Parameters.Add(
"@oldCustomerID", SqlDbType.NChar, 5, "CustomerID");
parameter.SourceVersion = DataRowVersion.Original;
parameter = adapter.UpdateCommand.Parameters.Add(
"@oldCompanyName", SqlDbType.NVarChar, 30, "CompanyName");
parameter.SourceVersion = DataRowVersion.Original;

// Add the RowUpdated event handler.


adapter.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated);

DataSet dataSet = new DataSet();


adapter.Fill(dataSet, "Customers");

// Modify the DataSet contents.


adapter.Update(dataSet, "Customers");

foreach (DataRow dataRow in dataSet.Tables["Customers"].Rows)


{
if (dataRow.HasErrors)
Console.WriteLine(dataRow[0] + "\n" + dataRow.RowError);
}
}
}

protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs args)


{
if (args.RecordsAffected == 0)
{
args.Row.RowError = "Optimistic Concurrency Violation Encountered";
args.Status = UpdateStatus.SkipCurrentRow;
}
}
}

See also
Retrieving and modifying data in ADO.NET
Updating Data Sources with DataAdapters
Transactions and concurrency
Microsoft ADO.NET for SQL Server
Retrieving database schema information
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Obtaining schema information from a database is accomplished with the process of schema discovery. Schema
discovery allows applications to request that managed providers find and return information about the
database schema, also known as metadata, of a given database. Different database schema elements such as
tables, columns, and stored-procedures are exposed through schema collections. Each schema collection
contains a variety of schema information specific to the provider being used.
The Microsoft SqlClient Data Provider for SQL Server implements the GetSchema method in the
SqlConnection class, and the schema information that is returned from the GetSchema method comes in the
form of a DataTable. The GetSchema method is an overloaded method that provides optional parameters for
specifying the schema collection to return, and restricting the amount of information returned. The SqlClient
data provider also provides a GetSchemaTable method that returns a DataTable describing the column
metadata of the SqlDataReader .

In this section
GetSchema and schema collections
Describes the GetSchema method and how it can be used to retrieve and restrict schema information from a
database.
Schema restrictions
Describes schema restrictions that can be used with GetSchema .
Common schema collections
Describes all of the common schema collections supported by all of the .NET managed providers.
SQL Server schema collections
Describes the additional schema collections supported by the Microsoft SqlClient Data Provider for SQL Server.

Reference
GetSchema
Describes the GetSchema method of the DbConnection class.
GetSchema
Describes the GetSchema method of the SqlConnection class.
GetSchemaTable
Describes the GetSchemaTable method of the DbDataReader class.
GetSchemaTable
Describes the GetSchemaTable method of the SqlDataReader class.

See also
Retrieving and modifying data in ADO.NET
Microsoft ADO.NET for SQL Server
Get schema and schema collections
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The SqlConnection classes in the Microsoft SqlClient Data Provider for SQL Server implements a GetSchema
method which is used to retrieve schema information about the database that is currently connected, and the
schema information returned from the GetSchema method comes in the form of a DataTable. The GetSchema
method is an overloaded method that provides optional parameters for specifying the schema collection to
return, and restricting the amount of information returned.

Specifying the schema collections


The first optional parameter of the GetSchema method is the collection name which is specified as a string.
There are two types of schema collections: common schema collections that are common to all providers, and
specific schema collections which are specific to each provider.
You can query the Microsoft SqlClient Data Provider for SQL Server to determine the list of supported schema
collections by calling the GetSchema method with no arguments, or with the schema collection name
"MetaDataCollections". This will return a DataTable with a list of the supported schema collections, the number
of restrictions that they each support, and the number of identifier parts that they use.
Retrieving schema collections example
The following examples demonstrate how to use the GetSchema method of the Microsoft SqlClient Data
Provider for SQL Server SqlConnection class to retrieve schema information about all of the tables contained in
the AdventureWorks sample database:
using System;
using System.Data;
using Microsoft.Data.SqlClient;

class Program
{
static void Main(string[] args)
{
string connectionString = "Data Source = localhost; Integrated Security = true; Initial Catalog =
AdventureWorks";

using (SqlConnection connection = new SqlConnection(connectionString))


{
connection.Open();
DataTable table = connection.GetSchema("Tables");

// Display the contents of the table.


DisplayData(table);
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
}
}

private static void DisplayData(System.Data.DataTable table)


{
foreach (System.Data.DataRow row in table.Rows)
{
foreach (System.Data.DataColumn col in table.Columns)
{
Console.WriteLine("{0} = {1}", col.ColumnName, row[col]);
}
Console.WriteLine("============================");
}
}
}

See also
Retrieving database schema information
Microsoft ADO.NET for SQL Server
Schema restrictions
4/27/2022 • 4 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The second optional parameter of the GetSchema method is the restrictions that are used to limit the amount
of schema information returned, and it is passed to the GetSchema method as an array of strings. The position
in the array determines the values that you can pass, and this is equivalent to the restriction number.
For example, the following table describes the restrictions supported by the "Tables" schema collection using the
Microsoft SqlClient Data Provider for SQL Server. Additional restrictions for SQL Server schema collections are
listed at the end of this topic.

REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog TABLE_CATALOG 1

Owner @Owner TABLE_SCHEMA 2

Table @Name TABLE_NAME 3

TableType @TableType TABLE_TYPE 4

Specifying restriction values


To use one of the restrictions of the "Tables" schema collection, simply create an array of strings with four
elements, then place a value in the element that matches the restriction number. For example, to restrict the
tables returned by the GetSchema method to only those tables in the "Sales" schema, set the second element
of the array to "Sales" before passing it to the GetSchema method.

NOTE
The restrictions collections for SqlClient have an additional ParameterName column. The restriction default column
is still there for backwards compatibility, but is currently ignored. Parameterized queries rather than string replacement
should be used to minimize the risk of an SQL injection attack when specifying restriction values.
The number of elements in the array must be less than or equal to the number of restrictions supported for the
specified schema collection else an ArgumentException will be thrown. There can be fewer than the maximum number
of restrictions. The missing restrictions are assumed to be null (unrestricted).

You can query the Microsoft SqlClient Data Provider for SQL Server to determine the list of supported
restrictions by calling the GetSchema method with the name of the restrictions schema collection, which is
"Restrictions". This will return a DataTable with a list of the collection names, the restriction names, the default
restriction values, and the restriction numbers.
Example
The following examples demonstrate how to use the GetSchema method of the Microsoft SqlClient Data
Provider for SQL Server SqlConnection class to retrieve schema information about all of the tables contained in
the AdventureWorks sample database, and to restrict the information returned to only those tables in the
"Sales" schema:

using System;
using System.Data;
using Microsoft.Data.SqlClient;

class Program
{
static void Main(string[] args)
{
string connectionString = "Data Source = localhost; Integrated Security = true; Initial Catalog =
AdventureWorks";

using (SqlConnection connection = new SqlConnection(connectionString))


{
connection.Open();

// Specify the restrictions.


string[] restrictions = new string[4];
restrictions[1] = "Sales";
System.Data.DataTable table = connection.GetSchema("Tables", restrictions);

// Display the contents of the table.


DisplayData(table);
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
}
}

private static void DisplayData(System.Data.DataTable table)


{
foreach (System.Data.DataRow row in table.Rows)
{
foreach (System.Data.DataColumn col in table.Columns)
{
Console.WriteLine("{0} = {1}", col.ColumnName, row[col]);
}
Console.WriteLine("============================");
}
}
}

SQL Server schema restrictions


The following tables list the restrictions for SQL Server schema collections.
Users
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

User_Name @Name name 1

Databases
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Name @Name Name 1

Tables
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog TABLE_CATALOG 1

Owner @Owner TABLE_SCHEMA 2

Table @Name TABLE_NAME 3

TableType @TableType TABLE_TYPE 4

Columns
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog TABLE_CATALOG 1

Owner @Owner TABLE_SCHEMA 2

Table @Table TABLE_NAME 3

Column @Column COLUMN_NAME 4

StructuredTypeMembers
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog TABLE_CATALOG 1

Owner @Owner TABLE_SCHEMA 2

Table @Table TABLE_NAME 3

Column @Column COLUMN_NAME 4

Views
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog TABLE_CATALOG 1

Owner @Owner TABLE_SCHEMA 2

Table @Table TABLE_NAME 3

ViewColumns
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog VIEW_CATALOG 1

Owner @Owner VIEW_SCHEMA 2

Table @Table VIEW_NAME 3


REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Column @Column COLUMN_NAME 4

ProcedureParameters
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog SPECIFIC_CATALOG 1

Owner @Owner SPECIFIC_SCHEMA 2

Name @Name SPECIFIC_NAME 3

Parameter @Parameter PARAMETER_NAME 4

Procedures
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog SPECIFIC_CATALOG 1

Owner @Owner SPECIFIC_SCHEMA 2

Name @Name SPECIFIC_NAME 3

Type @Type ROUTINE_TYPE 4

IndexColumns
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog db_name() 1

Owner @Owner user_name() 2

Table @Table o.name 3

ConstraintName @ConstraintName x.name 4

Column @Column c.name 5

Indexes
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog db_name() 1

Owner @Owner user_name() 2

Table @Table o.name 3

UserDefinedTypes
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

assembly_name @AssemblyName assemblies.name 1

udt_name @UDTName types.assembly_class 2

ForeignKeys
REST RIC T IO N N A M E PA RA M ET ER N A M E REST RIC T IO N DEFA ULT REST RIC T IO N N UM B ER

Catalog @Catalog CONSTRAINT_CATALOG 1

Owner @Owner CONSTRAINT_SCHEMA 2

Table @Table TABLE_NAME 3

Name @Name CONSTRAINT_NAME 4

See also
Microsoft ADO.NET for SQL Server
Common schema collections
4/27/2022 • 9 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The common schema collections are the schema collections that are implemented by each of the .NET managed
providers. You can query a .NET managed provider to determine the list of supported schema collections by
calling the GetSchema method with no arguments, or with the schema collection name "MetaDataCollections".
This method will return a DataTable with a list of the supported schema collections, the number of restrictions
that they each support, and the number of identifier parts that they use. These collections describe all of the
required columns. Providers are free to add more columns if they wish. For example, the Microsoft SqlClient
Data Provider for SQL Server adds ParameterName to the restrictions collection.
If a provider is unable to determine the value of a required column, it will return null.
For more information about using the GetSchema methods, see GetSchema and Schema Collections.

MetaDataCollections
This collection exposes information about all of the schema collections supported by the provider that is
currently used to connect to the database.

C O L UM N N A M E DATAT Y P E DESC RIP T IO N

CollectionName string The name of the collection to pass to


the GetSchema method to return the
collection.

NumberOfRestrictions int The number of restrictions that may be


specified for the collection.

NumberOfIdentifierParts int The number of parts in the composite


identifier/database object name. For
example, in SQL Server, the value
would be 3 for tables and 4 for
columns.

DataSourceInformation
This schema collection exposes information about data source that the Microsoft SqlClient Data Provider for
SQL Server is currently connected to.

C O L UM N N A M E DATAT Y P E DESC RIP T IO N


C O L UM N N A M E DATAT Y P E DESC RIP T IO N

CompositeIdentifierSeparatorPattern string The regular expression to match the


composite separators in a composite
identifier. For example, \. (for SQL
Server).

A composite identifier is typically what


is used for a database object name, for
example: pubs.dbo.authors or
[email protected] .

For SQL Server, use the regular


expression \. .

DataSourceProductName string The name of the product accessed by


the provider, such as "SQLServer".

DataSourceProductVersion string Indicates the version of the product


accessed by the provider, in the data
sources native format and not in
Microsoft format.

In some cases,
DataSourceProductVersion and
DataSourceProductVersionNormalized
will be the same value.

DataSourceProductVersionNormalized string A normalized version for the data


source, such that it can be compared
with String.Compare() . This format
is consistent for all versions of the
provider to prevent version 10 from
sorting between version 1 and version
2.

For example, SQL Server uses the


typical Microsoft nn.nn.nnnn format.

In some cases,
DataSourceProductVersion and
DataSourceProductVersionNormalized
will be the same value.

GroupByBehavior GroupByBehavior Specifies the relationship between the


columns in a GROUP BY clause and the
non-aggregated columns in the select
list.

IdentifierPattern string A regular expression that matches an


identifier and has a match value of the
identifier. For example,
[A-Za-z0-9_#$] .

IdentifierCase IdentifierCase Indicates whether non-quoted


identifiers are treated as case sensitive
or not.
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

OrderByColumnsInSelect bool Specifies whether columns in an


ORDER BY clause must be in the select
list. A value of true indicates that
they're required to be in the select list.
A value of false indicates that
they're not required to be in the select
list.

ParameterMarkerFormat string A format string that represents how to


format a parameter.

If named parameters are supported by


the data source, the first placeholder in
this string should be where the
parameter name should be formatted.

For example, if the data source expects


parameters to be named and prefixed
with a : this string would be :{0} .
When formatting this parameter with a
name of p1 the resulting string is
:p1 .

If the data source expects parameters


to be prefixed with the @ , but the
names already include them, this string
would be {0} , and the result of
formatting a parameter named @p1
would be @p1 .

For data sources that don't expect


named parameters and expect the use
of the ? character, the format string
can be specified as ? , which would
ignore the parameter name.

ParameterMarkerPattern string A regular expression that matches a


parameter marker. It will have a match
value of the parameter name, if any.

For example, if named parameters are


supported with an @ lead-in
character that will be included in the
parameter name, this pattern would
be: (\@[A-Za-z0-9_$#]*) .

However, if named parameters are


supported with a : as the lead-in
character and it isn't part of the
parameter name, this pattern would
be: :([A-Za-z0-9_$#]\*) .

If the data source doesn't support


named parameters, this pattern would
be ? .
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

ParameterNameMaxLength int The maximum length of a parameter


name in characters. Visual Studio
expects that if parameter names are
supported, the minimum value for the
maximum length is 30 characters.

If the data source doesn't support


named parameters, this property
returns zero.

ParameterNamePattern string A regular expression that matches the


valid parameter names. Different data
sources have different rules about the
characters that may be used for
parameter names.

Visual Studio expects that if parameter


names are supported, the characters
\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}\p{Nd}
are the minimum supported set of
characters that are valid for parameter
names.

QuotedIdentifierPattern string A regular expression that matches a


quoted identifier and has a match
value of the identifier itself without the
quotes. For example, if the data source
used double-quotes to identify quoted
identifiers, this pattern would be:
(([^\\"]\|\\"\\")*) .

QuotedIdentifierCase IdentifierCase Indicates whether quoted identifiers


are treated as case sensitive or not.

StatementSeparatorPattern string A regular expression that matches the


statement separator.

StringLiteralPattern string A regular expression that matches a


string literal and has a match value of
the literal itself. For example, if the data
source used single-quotes to identify
strings, this pattern would be:
('([^']\|'')*') '

SupportedJoinOperators SupportedJoinOperators Specifies what types of SQL join


statements are supported by the data
source.

DataTypes
This schema collection exposes information about the data types that are supported by the database that the
provider is currently connected to.

C O L UM N N A M E DATAT Y P E DESC RIP T IO N

TypeName string The provider-specific data type name.


C O L UM N N A M E DATAT Y P E DESC RIP T IO N

ProviderDbType int The provider-specific type value that


should be used when specifying a
parameter's type. For example,
SqlDbType.Money .

ColumnSize long The length of a non-numeric column


or parameter. This value refers to either
the maximum or the length defined for
this type by the provider.

For character data, this value is the


maximum or defined length in units,
defined by the data source.

For date-time data types, this value is


the length of the string representation
(assuming the maximum allowed
precision of the fractional seconds
component).

If the data type is numeric, this value is


the upper bound on the maximum
precision of the data type.

CreateFormat string Format string that represents how to


add this column to a data definition
statement, such as CREATE TABLE.
Each element in the
CreateParameter array should be
represented by a "parameter marker"
in the format string.

For example, the SQL data type


DECIMAL needs a precision and a
scale. In this case, the format string
would be DECIMAL({0},{1}) .

CreateParameters string The creation parameters that must be


specified when creating a column of
this data type. Each creation parameter
is listed in the string, separated by a
comma in the order they're to be
supplied.

For example, the SQL data type


DECIMAL needs a precision and a
scale. In this case, the creation
parameters should contain the string
"precision, scale".

In a text command to create a


DECIMAL column with a precision of
10 and a scale of 2, the value of the
CreateFormat column might be
DECIMAL({0},{1}) and the complete
type specification would be
DECIMAL(10,2) .
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

DataType string The name of the .NET type of the data


type.

IsAutoincrementable bool true - Values of this data type may


be auto-incrementing.

false - Values of this data type may


not be auto-incrementing.

This property merely indicates whether


a column of this data type may be
auto-incrementing, not that all
columns of this type are auto-
incrementing.

IsBestMatch bool true - The data type is the best


match between all data types in the
data store and the .NET data type
indicated by the value in the
DataType column.

false - The data type isn't the best


match.

For each set of rows in which the value


of the DataType column is the same,
the IsBestMatch column is set to
true in only one row.

IsCaseSensitive bool true - The data type is a character


type and is case-sensitive.

false - The data type isn't a


character type or isn't case-sensitive.

IsFixedLength bool true - Columns of this data type


created by the data definition
language (DDL) will be of fixed length.

false - Columns of this data type


created by the DDL will be of variable
length.

DBNull.Value - It isn't known


whether the provider will map this field
with a fixed-length or variable-length
column.

IsFixedPrecisionScale bool true - The data type has a fixed


precision and scale.

false - The data type doesn't have a


fixed precision and scale.
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

IsLong bool true - The data type contains very


long data; the definition of very long
data is provider-specific.

false - The data type doesn't


contain very long data.

IsNullable bool true - The data type is nullable.

false - The data type isn't nullable.

DBNull.Value - It isn't known


whether the data type is nullable.

IsSearchable bool true - The data type can be used in


a WHERE clause with any operator
except the LIKE predicate.

false - The data type cannot be


used in a WHERE clause with any
operator except the LIKE predicate.

IsSearchableWithLike bool true - The data type can be used


with the LIKE predicate.

false - The data type cannot be


used with the LIKE predicate.

IsUnsigned bool true - The data type is unsigned.

false - The data type is signed.

DBNull.Value - Not applicable to


data type.

MaximumScale short If the type indicator is a numeric type,


this value is the maximum number of
digits allowed to the right of the
decimal point. Otherwise, this value is
DBNull.Value .

MinimumScale short If the type indicator is a numeric type,


this value is the minimum number of
digits allowed to the right of the
decimal point. Otherwise, this value is
DBNull.Value .
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

IsConcurrencyType bool true – The data type is updated by


the database every time the row is
changed and the value of the column
is different from all previous values.

false – The data type is note


updated by the database every time
the row is changed.

DBNull.Value – The database


doesn't support this data type.

IsLiteralSupported bool true – The data type can be


expressed as a literal.

false – The data type can't be


expressed as a literal.

LiteralPrefix string The prefix applied to a given literal.

LiteralSuffix string The suffix applied to a given literal.

Restrictions
This schema collection exposed information about the restrictions that are supported by the provider that is
currently used to connect to the database.

C O L UM N N A M E DATAT Y P E DESC RIP T IO N

CollectionName string The name of the collection that these


restrictions apply to.

RestrictionName string The name of the restriction in the


collection.

RestrictionDefault string Ignored.

RestrictionNumber int The actual location in the collections


restrictions that this particular
restriction falls in.

ReservedWords
This schema collection exposes information about the words that are reserved by the database that the provider
that is currently connected to.

C O L UM N N A M E DATAT Y P E DESC RIP T IO N

ReservedWord string Provider specific reserved word.

See also
Retrieving database schema information
GetSchema and schema collections
Microsoft ADO.NET for SQL Server
SQL Server schema collections
4/27/2022 • 10 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The Microsoft SqlClient Data Provider for SQL Server supports additional schema collections in addition to the
common schema collections. The schema collections vary slightly by the version of SQL Server you are using. To
determine the list of supported schema collections, call the GetSchema method with no arguments, or with the
schema collection name "MetaDataCollections". This will return a DataTable with a list of the supported schema
collections, the number of restrictions that they each support, and the number of identifier parts that they use.

Databases
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

database_name String Name of the database.

dbid Int16 Database ID.

create_date DateTime Creation Date of the database.

Foreign Keys
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

CONSTRAINT_CATALOG String Catalog the constraint belongs to.

CONSTRAINT_SCHEMA String Schema that contains the constraint.

CONSTRAINT_NAME String Name.

TABLE_CATALOG String Table Name constraint is part of.

TABLE_SCHEMA String Schema that contains the table.

TABLE_NAME String Table Name

CONSTRAINT_TYPE String Type of constraint. Only "FOREIGN


KEY" is allowed.

IS_DEFERRABLE String Specifies whether the constraint is


deferrable. Returns NO.

INITIALLY_DEFERRED String Specifies whether the constraint is


initially deferrable. Returns NO.

Indexes
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

constraint_catalog String Catalog that index belongs to.

constraint_schema String Schema that contains the index.

constraint_name String Name of the index.

table_catalog String Table name the index is associated


with.

table_schema String Schema that contains the table the


index is associated with.

table_name String Table Name.

index_name String Index Name.

type_desc String The type of the index will be one of the


following:

- HEAP
- CLUSTERED
- NONCLUSTERED
- XML
- SPATIAL

IndexColumns
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

constraint_catalog String Catalog that index belongs to.

constraint_schema String Schema that contains the index.

constraint_name String Name of the index.

table_catalog String Table name the index is associated


with.

table_schema String Schema that contains the table the


index is associated with.

table_name String Table Name.

column_name String Column name the index is associated


with.

ordinal_position Int32 Column ordinal position.

KeyType Byte The type of object.

index_name String Index Name.


Procedures
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

SPECIFIC_CATALOG String Specific name for the catalog.

SPECIFIC_SCHEMA String Specific name of the schema.

SPECIFIC_NAME String Specific name of the catalog.

ROUTINE_CATALOG String Catalog the stored procedure belongs


to.

ROUTINE_SCHEMA String Schema that contains the stored


procedure.

ROUTINE_NAME String Name of the stored procedure.

ROUTINE_TYPE String Returns PROCEDURE for stored


procedures and FUNCTION for
functions.

CREATED DateTime Time the procedure was created.

LAST_ALTERED DateTime The last time the procedure was


modified.

Procedure Parameters
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

SPECIFIC_CATALOG String Catalog name of the procedure for


which this is a parameter.

SPECIFIC_SCHEMA String Schema that contains the procedure


for which this parameter is part of.

SPECIFIC_NAME String Name of the procedure for which this


parameter is a part of.

ORDINAL_POSITION Int32 Ordinal position of the parameter


starting at 1. For the return value of a
procedure, this is a 0.

PARAMETER_MODE String Returns IN if an input parameter, OUT


if an output parameter, and INOUT if
an input/output parameter.

IS_RESULT String Returns YES if indicates result of the


procedure that is a function.
Otherwise, returns NO.

AS_LOCATOR String Returns YES if declared as locator.


Otherwise, returns NO.
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

PARAMETER_NAME String Name of the parameter. NULL if this


corresponds to the return value of a
function.

DATA_TYPE String System-supplied data type.

CHARACTER_MAXIMUM_LENGTH Int32 Maximum length in characters for


binary or character data types.
Otherwise, returns NULL.

CHARACTER_OCTET_LENGTH Int32 Maximum length, in bytes, for binary


or character data types. Otherwise,
returns NULL.

COLLATION_CATALOG String Catalog name of the collation of the


parameter. If not one of the character
types, returns NULL.

COLLATION_SCHEMA String Always returns NULL.

COLLATION_NAME String Name of the collation of the parameter.


If not one of the character types,
returns NULL.

CHARACTER_SET_CATALOG String Catalog name of the character set of


the parameter. If not one of the
character types, returns NULL.

CHARACTER_SET_SCHEMA String Always returns NULL.

CHARACTER_SET_NAME String Name of the character set of the


parameter. If not one of the character
types, returns NULL.

NUMERIC_PRECISION Byte Precision of approximate numeric data,


exact numeric data, integer data, or
monetary data. Otherwise, returns
NULL.

NUMERIC_PRECISION_RADIX Int16 Precision radix of approximate numeric


data, exact numeric data, integer data,
or monetary data. Otherwise, returns
NULL.

NUMERIC_SCALE Int32 Scale of approximate numeric data,


exact numeric data, integer data, or
monetary data. Otherwise, returns
NULL.

DATETIME_PRECISION Int16 Precision in fractional seconds if the


parameter type is datetime or
smalldatetime. Otherwise, returns
NULL.
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

INTERVAL_TYPE String NULL. Reserved for future use by SQL


Server.

INTERVAL_PRECISION Int16 NULL. Reserved for future use by SQL


Server.

Tables
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

TABLE_CATALOG String Catalog of the table.

TABLE_SCHEMA String Schema that contains the table.

TABLE_NAME String Table name.

TABLE_TYPE String Type of table. Can be VIEW or BASE


TABLE.

Columns
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

TABLE_CATALOG String Catalog of the table.

TABLE_SCHEMA String Schema that contains the table.

TABLE_NAME String Table name.

COLUMN_NAME String Column name.

ORDINAL_POSITION Int32 Column identification number.

COLUMN_DEFAULT String Default value of the column

IS_NULLABLE String Nullability of the column. If this column


allows NULL, this column returns YES.
Otherwise, No is returned.

DATA_TYPE String System-supplied data type.

CHARACTER_MAXIMUM_LENGTH Int32 – Sql8, Int16 – Sql7 Maximum length, in characters, for


binary data, character data, or text and
image data. Otherwise, NULL is
returned.

CHARACTER_OCTET_LENGTH Int32 – SQL8, Int16 – Sql7 Maximum length, in bytes, for binary
data, character data, or text and image
data. Otherwise, NULL is returned.
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

NUMERIC_PRECISION Unsigned Byte Precision of approximate numeric data,


exact numeric data, integer data, or
monetary data. Otherwise, NULL is
returned.

NUMERIC_PRECISION_RADIX Int16 Precision radix of approximate numeric


data, exact numeric data, integer data,
or monetary data. Otherwise, NULL is
returned.

NUMERIC_SCALE Int32 Scale of approximate numeric data,


exact numeric data, integer data, or
monetary data. Otherwise, NULL is
returned.

DATETIME_PRECISION Int16 Subtype code for datetime and SQL-


92 interval data types. For other data
types, NULL is returned.

CHARACTER_SET_CATALOG String Returns master, indicating the


database in which the character set is
located, if the column is character data
or text data type. Otherwise, NULL is
returned.

CHARACTER_SET_SCHEMA String Always returns NULL.

CHARACTER_SET_NAME String Returns the unique name for the


character set if this column is character
data or text data type. Otherwise,
NULL is returned.

COLLATION_CATALOG String Returns master, indicating the


database in which the collation is
defined, if the column is character data
or text data type. Otherwise, this
column is NULL.

IS_FILESTREAM String YES if the column has FILESTREAM


attribute.

NO if the column does not have


FILESTREAM attribute.

IS_SPARSE String YES if the column is a sparse column.

NO if the column is not a sparse


column.

IS_COLUMN_SET String YES if the column is a column set


column.

NO if the column is not a column set


column.

AllColumns
The AllColumns schema collection is used to support sparse columns. AllColumns has the same restrictions and
resulting DataTable schema as the Columns schema collection. The only difference is that AllColumns includes
column set columns that are not included in the Columns schema collection. The following table describes these
columns.

C O L UM N N A M E DATAT Y P E DESC RIP T IO N

TABLE_CATALOG String Catalog of the table.

TABLE_SCHEMA String Schema that contains the table.

TABLE_NAME String Table name.

COLUMN_NAME String Column name.

ORDINAL_POSITION Int32 Column identification number.

COLUMN_DEFAULT String Default value of the column

IS_NULLABLE String Nullability of the column. If this column


allows NULL, this column returns YES.
Otherwise, NO is returned.

DATA_TYPE String System-supplied data type.

CHARACTER_MAXIMUM_LENGTH Int32 Maximum length, in characters, for


binary data, character data, or text and
image data. Otherwise, NULL is
returned.

CHARACTER_OCTET_LENGTH Int32 Maximum length, in bytes, for binary


data, character data, or text and image
data. Otherwise, NULL is returned.

NUMERIC_PRECISION Unsigned Byte Precision of approximate numeric data,


exact numeric data, integer data, or
monetary data. Otherwise, NULL is
returned.

NUMERIC_PRECISION_RADIX Int16 Precision radix of approximate numeric


data, exact numeric data, integer data,
or monetary data. Otherwise, NULL is
returned.

NUMERIC_SCALE Int32 Scale of approximate numeric data,


exact numeric data, integer data, or
monetary data. Otherwise, NULL is
returned.

DATETIME_PRECISION Int16 Subtype code for datetime and SQL-


92 interval data types. For other data
types, NULL is returned.
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

CHARACTER_SET_CATALOG String Returns master, indicating the


database in which the character set is
located, if the column is character data
or text data type. Otherwise, NULL is
returned.

CHARACTER_SET_SCHEMA String Always returns NULL.

CHARACTER_SET_NAME String Returns the unique name for the


character set if this column is character
data or text data type. Otherwise,
NULL is returned.

COLLATION_CATALOG String Returns master, indicating the


database in which the collation is
defined, if the column is character data
or text data type. Otherwise, this
column is NULL.

IS_FILESTREAM String YES if the column has FILESTREAM


attribute.

NO if the column does not have


FILESTREAM attribute.

IS_SPARSE String YES if the column is a sparse column.

NO if the column is not a sparse


column.

IS_COLUMN_SET String YES if the column is a column set


column.

NO if the column is not a column set


column.

ColumnSetColumns
The ColumnSetColumns schema collection is used to support sparse columns. The ColumnSetColumns schema
collection returns the schema for all of the columns in a column set. The following table describes these
columns.

C O L UM N N A M E DATAT Y P E DESC RIP T IO N

TABLE_CATALOG String Catalog of the table.

TABLE_SCHEMA String Schema that contains the table.

TABLE_NAME String Table name.

COLUMN_NAME String Column name.

ORDINAL_POSITION Int32 Column identification number.


C O L UM N N A M E DATAT Y P E DESC RIP T IO N

COLUMN_DEFAULT String Default value of the column

IS_NULLABLE String Nullability of the column. If this column


allows NULL, this column returns YES.
Otherwise, NO is returned.

DATA_TYPE String System-supplied data type.

CHARACTER_MAXIMUM_LENGTH Int32 Maximum length, in characters, for


binary data, character data, or text and
image data. Otherwise, NULL is
returned.

CHARACTER_OCTET_LENGTH Int32 Maximum length, in bytes, for binary


data, character data, or text and image
data. Otherwise, NULL is returned.

NUMERIC_PRECISION Unsigned Byte Precision of approximate numeric data,


exact numeric data, integer data, or
monetary data. Otherwise, NULL is
returned.

NUMERIC_PRECISION_RADIX Int16 Precision radix of approximate numeric


data, exact numeric data, integer data,
or monetary data. Otherwise, NULL is
returned.

NUMERIC_SCALE Int32 Scale of approximate numeric data,


exact numeric data, integer data, or
monetary data. Otherwise, NULL is
returned.

DATETIME_PRECISION Int16 Subtype code for datetime and SQL-


92 interval data types. For other data
types, NULL is returned.

CHARACTER_SET_CATALOG String Returns master, indicating the


database in which the character set is
located, if the column is character data
or text data type. Otherwise, NULL is
returned.

CHARACTER_SET_SCHEMA String Always returns NULL.

CHARACTER_SET_NAME String Returns the unique name for the


character set if this column is character
data or text data type. Otherwise,
NULL is returned.

COLLATION_CATALOG String Returns master, indicating the


database in which the collation is
defined, if the column is character data
or text data type. Otherwise, this
column is NULL.
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

IS_FILESTREAM String YES if the column has FILESTREAM


attribute.

NO if the column does not have


FILESTREAM attribute.

IS_SPARSE String YES if the column is a sparse column.

NO if the column is not a sparse


column.

IS_COLUMN_SET String YES if the column is a column set


column.

NO if the column is not a column set


column.

Users
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

uid Int16 User ID, unique in this database. 1 is


the database owner.

user_name String Username or group name, unique in


this database.

createdate DateTime Date the account was added.

updatedate DateTime Date the account was last changed.

Views
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

TABLE_CATALOG String Catalog of the view.

TABLE_SCHEMA String Schema that contains the view.

TABLE_NAME String View name.

CHECK_OPTION String Type of WITH CHECK OPTION. Is


CASCADE if the original view was
created using the WITH CHECK
OPTION. Otherwise, NONE is returned.

IS_UPDATABLE String Specifies whether the view is


updatable. Always returns NO.

ViewColumns
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

VIEW_CATALOG String Catalog of the view.

VIEW_SCHEMA String Schema that contains the view.

VIEW_NAME String View name.

TABLE_CATALOG String Catalog of the table that is associated


with this view.

TABLE_SCHEMA String Schema that contains the table that is


associated with this view.

TABLE_NAME String Name of the table that is associated


with the view. Base Table.

COLUMN_NAME String Column name.

UserDefinedTypes
C O L UM N N A M E DATAT Y P E DESC RIP T IO N

assembly_name String The name of the file for the assembly.

udt_name String The class name for the assembly.

version_major Object Major Version Number.

version_minor Object Minor Version Number.

version_build Object Build Number.

version_revision Object Revision Number.

culture_info Object The culture information associated


with this UDT.

public_key Object The public key used by this Assembly.

is_fixed_length Boolean Specifies whether length of type is


always same as max_length.

max_length Int16 Maximum length of type in bytes.

Create_Date DateTime The date the assembly was


created/registered.

Permission_set_desc String The friendly name for the permission-


set/security-level for the assembly.

See also
Retrieving database schema information
Microsoft ADO.NET for SQL Server
Configurable retry logic in SqlClient
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
An application that communicates with elements running in the cloud has to be sensitive to the transient faults
that can occur in this environment. These faults are typically self-correcting. If the action that triggered a fault is
repeated after a suitable delay, it's likely to be successful.

NOTE
This feature is available starting with Microsoft.Data.SqlClient version 3.0.0 preview 1.

Retry pattern
Attempting to complete an operation despite transient errors, instead of throwing an exception and letting a
user decide the next action, is an intelligent decision called a retry pattern. For more information, see Retry
pattern.

Transient faults
You can have a robust infrastructure and use well-known applications implemented with the latest technologies
to reduce service downtime. However, it's impossible to reduce failures to zero. Transient errors are those faults
that sometimes happen for known reasons and will disappear after a short time. For example, when a load-
balancing change is in progress on the server-side, it may briefly cause requested services to fail or time out. For
more information, see Transient faults.

Do and don't
Even though using a retry pattern greatly improves an application's resiliency, it could negatively impact an
application if used in the wrong circumstances. Before adding an exception to the list of transient faults, pause
for a moment and ask yourself, "Will it resolve itself soon?". Don't rush. Study the reasons if you don't have a
good answer for the question. For more information, see Troubleshooting connectivity issues and other errors
with Azure SQL Database and Azure SQL Managed Instance.

In this section
Configurable retry logic in SqlClient introduction
Introduces different section of configurable retry logic.
Internal retry logic providers in SqlClient
Demonstrates how to use pre-defined retry providers to apply the retry logic against database.
Configurable retry logic core APIs in SqlClient
Demonstrates how to use core APIs to implement custom retry logic.
Configurable retry logic configuration file with SqlClient
Demonstrates how to specify default retry logic providers through a configuration file.
See also
Retry Pattern
Transient faults
Troubleshooting connectivity issues and other errors with Azure SQL Database and Azure SQL Managed
Instance
Microsoft ADO.NET for SQL Server
Configurable retry logic in SqlClient introduction
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Configurable retry logic lets developers and administrators manage application behavior when transient faults
happen. The feature adds controls during connection or execution of a command. The controls can be defined
through code or an application configuration file. Transient error numbers and retry properties can be defined
to control retry behavior. Also, regular expressions can be used to filter specific SQL statements.

Feature components
This feature consists of three main components:
1. Core APIs : Developers can use these interfaces to implement their own retry logic on SqlConnection and
SqlCommand objects. For more information, see Configurable retry logic core APIs in SqlClient.
2. Pre-defined configurable retr y logic : Built-in retry logic methods using the core APIs are accessible from
the SqlConfigurableRetryFactory class. For more information, see Internal retry logic providers in SqlClient.
3. Configuration file schema : To specify the default retry logic for SqlConnection and SqlCommand in an
application. For more information, see Configurable retry logic configuration file with SqlClient.

Quick start
To use this feature, follow these four steps:
1. Enable the safety switch in the preview version. For information on how to enable the AppContext safety
switch, see Enable configurable retry logic.
2. Define the retry logic options using SqlRetryLogicOption.
In this sample, some of the retry parameters are set and the rest of them will use the default values.

// Define the retry logic parameters


var options = new SqlRetryLogicOption()
{
// Tries 5 times before throwing an exception
NumberOfTries = 5,
// Preferred gap time to delay before retry
DeltaTime = TimeSpan.FromSeconds(1),
// Maximum gap time for each delay time before retry
MaxTimeInterval = TimeSpan.FromSeconds(20)
};

3. Create a retry logic provider using your SqlRetryLogicOption object.

// Create a retry logic provider


SqlRetryLogicBaseProvider provider =
SqlConfigurableRetryFactory.CreateExponentialRetryProvider(options);

4. Assign the SqlRetryLogicBaseProvider instance to the SqlConnection.RetryLogicProvider or


SqlCommand.RetryLogicProvider.
In this sample, the connection open command will retry if it hits one of the transient errors in the
SqlConfigurableRetryFactory internal list for a maximum of five times.

// Assumes that connection is a valid SqlConnection object


// Set the retry logic provider on the connection instance
connection.RetryLogicProvider = provider;
// Establishing the connection will retry if a transient failure occurs.
connection.Open();

NOTE
These steps are the same for a command execution, except you would instead assign the retry provider to the
SqlCommand.RetryLogicProvider property before executing the command.

See also
Configurable retry logic core APIs in SqlClient
Internal retry logic providers in SqlClient
Configurable retry logic configuration file with SqlClient
Enable configurable retry logic
Configurable retry logic in SqlClient
Microsoft ADO.NET for SQL Server
Internal retry logic providers in SqlClient
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Built-in, internal retry providers have been implemented for the most common retry patterns. You can use the
retry providers by using the following Microsoft.Data.SqlClient.SqlConfigurableRetryFactory static methods:
SqlConfigurableRetryFactory.CreateFixedRetryProvider
SqlConfigurableRetryFactory.CreateIncrementalRetryProvider
SqlConfigurableRetryFactory.CreateExponentialRetryProvider
SqlConfigurableRetryFactory.CreateNoneRetryProvider

NOTE
All of the internal retry providers slightly randomize interval gap times before each retry. This randomization avoids
hitting the database at the same time when multiple clients are trying to connect or execute a command with the same
configuration.

WARNING
Internal retry providers don't support retrying on a command that executes in an open transaction. That operation will
execute without retry logic. You can override this behavior by using custom retry logic. For more information, see
Configurable retry logic core APIs in SqlClient.

Example
You can find samples for connection and command retry logic at the following links:
SqlConnection.RetryLogicProvider
SqlCommand.RetryLogicProvider

See also
Configurable retry logic core APIs in SqlClient
Configurable retry logic in SqlClient
Microsoft ADO.NET for SQL Server
Configurable retry logic core APIs in SqlClient
4/27/2022 • 5 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
If the built-in retry logic providers don't cover your needs, you can create your own custom providers. You can
then assign those providers to a SqlConnection or SqlCommand object to apply your custom logic.
The built-in providers are designed around three interfaces that can be used to implement custom providers.
Custom retry providers can then be used in the same way as internal retry providers on a SqlConnection or
SqlCommand:
1. SqlRetryIntervalBaseEnumerator: Generates a sequence of time intervals.
2. SqlRetryLogicBase: Retrieves the next time interval for a given enumerator, if the number of retries has not
been exceeded and a transient condition is met.
3. SqlRetryLogicBaseProvider: Applies retry logic to connection and command operations.
Cau t i on

By implementing a custom retry logic provider, you're in charge of all aspects, including concurrency,
performance, and exception management.

Example
The implementation in this sample is as simple as possible to demonstrate step-by-step customization. It doesn't
include advanced practices like thread safety, async, and concurrency. For a deep-dive into a real
implementation, you can study the pre-defined retry logic in the Microsoft.Data.SqlClient GitHub repository.
1. Define custom configurable retry logic classes:
Enumerator : Define a fixed sequence of time intervals and extend the acceptable range of times from
two minutes to four minutes.
public class CustomEnumerator : SqlRetryIntervalBaseEnumerator
{
// Set the maximum acceptable time to 4 minutes
private readonly TimeSpan _maxValue = TimeSpan.FromMinutes(4);

public CustomEnumerator(TimeSpan timeInterval, TimeSpan maxTime, TimeSpan minTime)


: base(timeInterval, maxTime, minTime) {}

// Return fixed time on each request


protected override TimeSpan GetNextInterval()
{
return GapTimeInterval;
}

// Override the validate method with the new time range validation
protected override void Validate(TimeSpan timeInterval, TimeSpan maxTimeInterval, TimeSpan
minTimeInterval)
{
if (minTimeInterval < TimeSpan.Zero || minTimeInterval > _maxValue)
{
throw new ArgumentOutOfRangeException(nameof(minTimeInterval));
}

if (maxTimeInterval < TimeSpan.Zero || maxTimeInterval > _maxValue)


{
throw new ArgumentOutOfRangeException(nameof(maxTimeInterval));
}

if (timeInterval < TimeSpan.Zero || timeInterval > _maxValue)


{
throw new ArgumentOutOfRangeException(nameof(timeInterval));
}

if (maxTimeInterval < minTimeInterval)


{
throw new ArgumentOutOfRangeException(nameof(minTimeInterval));
}
}
}

Retr y logic : Implement retry logic on any command that isn't part of an active transaction. Lower the
number of retries from 60 to 20.
public class CustomRetryLogic : SqlRetryLogicBase
{
// Maximum number of attempts
private const int maxAttempts = 20;

public CustomRetryLogic(int numberOfTries,


SqlRetryIntervalBaseEnumerator enumerator,
Predicate<Exception> transientPredicate)
{
if (!(numberOfTries > 0 && numberOfTries <= maxAttempts))
{
// 'numberOfTries' should be between 1 and 20.
throw new ArgumentOutOfRangeException(nameof(numberOfTries));
}

// Assign parameters to the relevant properties


NumberOfTries = numberOfTries;
RetryIntervalEnumerator = enumerator;
TransientPredicate = transientPredicate;
Current = 0;
}

// Prepare this object for the next round


public override void Reset()
{
Current = 0;
RetryIntervalEnumerator.Reset();
}

public override bool TryNextInterval(out TimeSpan intervalTime)


{
intervalTime = TimeSpan.Zero;
// First try has occurred before starting the retry process.
// Check if retry is still allowed
bool result = Current < NumberOfTries - 1;

if (result)
{
// Increase the number of attempts
Current++;
// It's okay if the RetryIntervalEnumerator gets to the last value before we've reached
our maximum number of attempts.
// MoveNext() will simply leave the enumerator on the final interval value and we will
repeat that for the final attempts.
RetryIntervalEnumerator.MoveNext();
// Receive the current time from enumerator
intervalTime = RetryIntervalEnumerator.Current;
}
return result;
}
}

Provider : Implements a retry provider that retries on synchronous operations without a Retrying
event. Adds TimeoutException to the existing SqlException transient exception error numbers.
public class CustomProvider : SqlRetryLogicBaseProvider
{
// Preserve the given retryLogic on creation
public CustomProvider(SqlRetryLogicBase retryLogic)
{
RetryLogic = retryLogic;
}

public override TResult Execute<TResult>(object sender, Func<TResult> function)


{
// Create a list to save transient exceptions to report later if necessary
IList<Exception> exceptions = new List<Exception>();
// Prepare it before reusing
RetryLogic.Reset();
// Create an infinite loop to attempt the defined maximum number of tries
do
{
try
{
// Try to invoke the function
return function.Invoke();
}
// Catch any type of exception for further investigation
catch (Exception e)
{
// Ask the RetryLogic object if this exception is a transient error
if (RetryLogic.TransientPredicate(e))
{
// Add the exception to the list of exceptions we've retried on
exceptions.Add(e);
// Ask the RetryLogic for the next delay time before the next attempt to run the
function
if (RetryLogic.TryNextInterval(out TimeSpan gapTime))
{
Console.WriteLine($"Wait for {gapTime} before next try");
// Wait before next attempt
Thread.Sleep(gapTime);
}
else
{
// Number of attempts has exceeded the maximum number of tries
throw new AggregateException("The number of retries has exceeded the maximum
number of attempts.", exceptions);
}
}
else
{
// If the exception wasn't a transient failure throw the original exception
throw;
}
}
} while (true);
}

public override Task<TResult> ExecuteAsync<TResult>(object sender, Func<Task<TResult>> function,


CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public override Task ExecuteAsync(object sender, Func<Task> function, CancellationToken


cancellationToken = default)
{
throw new NotImplementedException();
}
}
2. Create a retry provider instance consisting of the defined custom types:

public static SqlRetryLogicBaseProvider CreateCustomProvider(SqlRetryLogicOption options)


{
// 1. create an enumerator instance
CustomEnumerator customEnumerator = new CustomEnumerator(options.DeltaTime,
options.MaxTimeInterval, options.MinTimeInterval);
// 2. Use the enumerator object to create a new RetryLogic instance
CustomRetryLogic customRetryLogic = new CustomRetryLogic(5, customEnumerator, (e) =>
TransientErrorsCondition(e, options.TransientErrors));
// 3. Create a provider using the RetryLogic object
CustomProvider customProvider = new CustomProvider(customRetryLogic);
return customProvider;
}

The following function will evaluate an exception by using the given list of retryable exceptions and
the special TimeoutException exception to determine if it's retryable:

// Return true if the exception is a transient fault.


private static bool TransientErrorsCondition(Exception e, IEnumerable<int> retriableConditions)
{
bool result = false;

// Assess only SqlExceptions


if (retriableConditions != null && e is SqlException ex)
{
foreach (SqlError item in ex.Errors)
{
// Check each error number to see if it is a retriable error number
if (retriableConditions.Contains(item.Number))
{
result = true;
break;
}
}
}
// Other types of exceptions can also be assessed
else if (e is TimeoutException)
{
result = true;
}
return result;
}

3. Use the customized retry logic:


Define the retry logic parameters:

// Define the retry logic parameters


var options = new SqlRetryLogicOption()
{
// Tries 5 times before throwing an exception
NumberOfTries = 5,
// Preferred gap time to delay before retry
DeltaTime = TimeSpan.FromSeconds(1),
// Maximum gap time for each delay time before retry
MaxTimeInterval = TimeSpan.FromSeconds(20),
// SqlException retriable error numbers
TransientErrors = new int[] { 4060, 1024, 1025}
};

Create a custom retry provider:


// Create a custom retry logic provider
SqlRetryLogicBaseProvider provider = CustomRetry.CreateCustomProvider(options);

Assign the retry provider to the SqlConnection.RetryLogicProvider or


SqlCommand.RetryLogicProvider:

// Assumes that connection is a valid SqlConnection object


// Set the retry logic provider on the connection instance
connection.RetryLogicProvider = provider;
// Establishing the connection will trigger retry if one of the given transient failure occurs.
connection.Open();

NOTE
Don't forget to enable the configurable retry logic switch before using it. For more information, see Enable configurable
retry logic.

See also
Microsoft.Data.SqlClient GitHub repository
Configurable retry logic in SqlClient
Microsoft ADO.NET for SQL Server
Configurable retry logic configuration file with
SqlClient
4/27/2022 • 4 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The default retry method when the safety switch is enabled is the
SqlConfigurableRetryFactory.CreateNoneRetryProvider for both SqlConnection and SqlCommand. You can
specify a different retry method by using a configuration file.

Configuration sections
Default retry logic options for an application can be changed by adding the following sections inside the
configSections section of the configuration file:

SqlConfigurableRetryLogicConnection : to specify the default retry logic for SqlConnection.

<section name="SqlConfigurableRetryLogicConnection"
type="Microsoft.Data.SqlClient.SqlConfigurableRetryConnectionSection, Microsoft.Data.SqlClient"/>

SqlConfigurableRetryLogicCommand : to specify the default retry logic for SqlCommand.

<section name="SqlConfigurableRetryLogicCommand"
type="Microsoft.Data.SqlClient.SqlConfigurableRetryCommandSection, Microsoft.Data.SqlClient"/>

AppContextSwitchOverrides : .NET Framework supports AppContext switches via an


AppContextSwitchOverrides section, which doesn't need to be defined explicitly. To turn on a switch in .NET
Core , you must specify this section.

<section name="AppContextSwitchOverrides"
type="Microsoft.Data.SqlClient.AppContextSwitchOverridesSection, Microsoft.Data.SqlClient"/>

NOTE
The following configurations should be specified inside the configuration section. Declare these new sections to
configure the default retry logic through an application configuration file.

Enable safety switch

NOTE
Starting from Microsoft.Data.SqlClient v4.0, the App Context switch "Switch.Microsoft.Data.SqlClient.EnableRetryLogic" will
no longer be required to use the configurable retry logic feature. The feature is now supported in production. The default
behavior of the feature will continue to be a non-retry policy, which will need to be overridden by client applications to
enable retries.
You can enable the safety switch through a configuration file. To learn how to enable it through application code,
see Enable configurable retry logic.
.NET Framework : For more information, see AppContextSwitchOverrides element.

<runtime>
<AppContextSwitchOverrides value="Switch.Microsoft.Data.SqlClient.EnableRetryLogic=true"/>
</runtime>

.NET Core : supports multiple, semi-colon (;) delimited switches like .NET Framework.

<AppContextSwitchOverrides value="Switch.Microsoft.Data.SqlClient.EnableRetryLogic=true"/>

Connection section
The following attributes can be used to specify the default retry logic for all SqlConnection instances in an
application:
numberOfTries : sets the number of times to try.
deltaTime : sets the gap time interval as a TimeSpan object.
minTime : sets the allowed minimum gap time interval as a TimeSpan object.
maxTime : sets the allowed maximum gap time interval as a TimeSpan object.
transientErrors : sets the list of transient error numbers on which to retry.
retr yMethod : specifies a retry method creator that receives the retry configuration via a
SqlRetryLogicOption parameter and returns a SqlRetryLogicBaseProvider object.
retr yLogicType : sets a custom retry logic provider, which contains the retry method creators that
provide the retryMethod . These methods should meet the criteria for retryMethod . The fully qualified
type name of the provider should be used. For more information, see Specifying fully qualified type
names.

NOTE
It's not required to specify the retryLogicType if you use the built-in retry providers. To find the built-in retry providers,
see Internal retry logic providers in SqlClient.

Command section
The following attribute can also be set for all SqlCommand instances in an application:
authorizedSqlCondition : Sets a pre-retry regular expression for SqlCommand.CommandText to filter
specific SQL statements.

NOTE
The regular expression is case sensitive.

Examples
Attempts to establish a connection up to three times with an approximate 1-second delay between tries
by using the SqlConfigurableRetryFactory.CreateFixedRetryProvider method and the default transient
error list:
<SqlConfigurableRetryLogicConnection retryMethod ="CreateFixedRetryProvider"
numberOfTries ="3" deltaTime ="00:00:01"/>

Attempts to establish a connection up to five times with up to a 45-second delay between tries by using
the SqlConfigurableRetryFactory.CreateExponentialRetryProvider method and the default transient error
list:

<SqlConfigurableRetryLogicConnection retryMethod ="CreateExponentialRetryProvider"


numberOfTries ="5" deltaTime ="00:00:03" maxTime ="00:00:45"/>

Attempts to execute a command up to four times with a delay between 2 and 30 seconds by using the
SqlConfigurableRetryFactory.CreateIncrementalRetryProvider method and the default transient error list:

<SqlConfigurableRetryLogicCommand retryMethod ="CreateIncrementalRetryProvider"


numberOfTries ="4" deltaTime ="00:00:02" maxTime ="00:00:30"/>

Attempts to execute a command up to eight times with a delay from one second to one minute. It's
limited to commands with CommandText containing the word SELECT and exception numbers 102 or 997.
It uses the built-in SqlConfigurableRetryFactory.CreateIncrementalRetryProvider method:

<SqlConfigurableRetryLogicCommand retryMethod ="CreateIncrementalRetryProvider"


numberOfTries ="8" deltaTime ="00:00:01" maxTime ="00:01:00"
transientErrors="102, 997"
authorizedSqlCondition="\b(SELECT)\b"/>

NOTE
In the next two samples, you can find the custom retry logic source code from Configurable retry logic core APIs in
SqlClient. It's assumed the CreateCustomProvider method is defined in the CustomCRL_Doc.CustomRetry class in the
CustomCRL_Doc.dll assembly that is in the application's executing directory.

Attempts to establish a connection up to five times, with a delay between 3 and 45 seconds, error
numbers 4060, 997, and 233 in the list, and using the specified custom retry provider:

<SqlConfigurableRetryLogicConnection retryLogicType ="CustomCRL_Doc.CustomRetry, CustomCRL_Doc,


Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
retryMethod ="CreateCustomProvider"
numberOfTries ="5" deltaTime ="00:00:03" maxTime ="00:00:45"
transientErrors ="4060, 997, 233"/>

This sample behaves like the previous one:

<SqlConfigurableRetryLogicConnection retryLogicType ="CustomCRL_Doc.CustomRetry, CustomCRL_Doc"


retryMethod ="CreateCustomProvider"
numberOfTries ="5" deltaTime ="00:00:03" maxTime ="00:00:45"
transientErrors ="4060, 997, 233"/>
NOTE
Retry logic providers will be cached at the first use on a connection or command for future use during an application's
lifetime.

NOTE
Any errors when reading an application configuration file for retry logic settings won't cause errors in the application. The
default SqlConfigurableRetryFactory.CreateNoneRetryProvider will be used instead.
You can use event source tracing to verify or troubleshoot issues with configuring retry logic. For more information, see
Enable event tracing in SqlClient.

See also
Enable configurable retry logic
Internal retry logic providers in SqlClient
Enable event tracing in SqlClient
Specifying fully qualified type names
Configurable retry logic in SqlClient
Microsoft ADO.NET for SQL Server
DbProviderFactories
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The System.Data.Common namespace provides classes for creating DbProviderFactory instances to work with
specific data sources. When you create a DbProviderFactory instance and pass it information about the data
provider, the DbProviderFactory can determine the correct, strongly typed connection object to return based on
the information it has been provided.
The data provider Microsoft.Data.SqlClient is no longer listed in machine.config file, but custom providers will
continue to be listed there.

In this section
Obtain a SqlClientFactory
Demonstrates how to obtain a SqlClientFactory from the DbProviderFactories class to work with specific data
sources in .NET.

See also
Retrieving and modifying data in ADO.NET
Microsoft ADO.NET for SQL Server
Obtain a SqlClientFactory
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
The process of obtaining a DbProviderFactory involves passing information about a data provider to the
DbProviderFactories class. Based on this information, the GetFactory method creates a strongly typed provider
factory. For example, to create a SqlClientFactory, you can pass GetFactory a string with the provider name
specified as "Microsoft.Data.SqlClient ".
The other overload of GetFactory takes a DataRow. Once you create the provider factory, you can then use its
methods to create additional objects. Some of the methods of a SqlClientFactory include CreateConnection,
CreateCommand, and CreateDataAdapter.

Register SqlClientFactory
To retrieve the SqlClientFactory object by the DbProviderFactories class in .NET Framework, it's necessary to
register it in a App.config or web.config file. The following configuration file fragment shows the syntax and
format for Microsoft.Data.SqlClient.

<system.data>
<DbProviderFactories>
<add name="Microsoft SqlClient Data Provider"
invariant="Microsoft.Data.SqlClient"
description="Microsoft SqlClient Data Provider for SQL Server"
type="Microsoft.Data.SqlClient.SqlClientFactory, Microsoft.Data.SqlClient, Version=2.0.20168.4,
Culture=neutral, PublicKeyToken=23ec7fc2d6eaa4a5"/>
</DbProviderFactories>
</system.data>

The invariant attribute identifies the underlying data provider. This three-part naming syntax is also used when
creating a new factory and for identifying the provider in an application configuration file so that the provider
name, along with its associated connection string, can be retrieved at run time.

NOTE
In .NET core, since there is no GAC or global configuration support, the SqlClientFactory object should be registered by
calling RegisterFactory method in the project.

The following sample shows how to use the SqlClientFactory in a .NET core application.

private static DbProviderFactory GetFactory()


{
// register SqlClientFactory in provider factories
DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", SqlClientFactory.Instance);

return DbProviderFactories.GetFactory("Microsoft.Data.SqlClient");
}
See also
DbProviderFactories
Connection strings
Using the configuration classes
Microsoft ADO.NET for SQL Server
Diagnostic counters in SqlClient
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
You can use Microsoft.Data.SqlClient diagnostic counters in multiple target frameworks to monitor the status of
your application and the connection resources that it uses. Use performance counters in .NET Framework, and
event counters in .NET Core and .NET Standard.

NOTE
When using Windows Authentication (integrated security), you must monitor either the pair
number-of-active-connection-pool-groups and number-of-active-connection-pools event counters or the
NumberOfActiveConnectionPoolGroups and NumberOfActiveConnectionPools performance counters. The reason is
that connection pool groups map to unique connection strings. When integrated security is used, connection pools map
to connection strings and additionally create separate pools for individual Windows identities. For example, if Fred and
Julie, each within the same AppDomain, both use the connection string
"Data Source=MySqlServer;Integrated Security=true" , a connection pool group is created for the connection string,
and two additional pools are created, one for Fred and one for Julie. If John and Martha use a connection string with an
identical SQL Server login, "Data Source=MySqlServer;User Id=<myUserID>;Password=<myPassword>" , then only a
single pool is created for the <myUserID> identity.

In this section
Performance counters in SqlClient
Use Microsoft SqlClient Data Provider for SQL Server performance counters to monitor your application status
and its connection resources by using Windows Performance Monitor or programmatically in .NET Framework .
Event counters in SqlClient
Use Microsoft SqlClient Data Provider for SQL Server event counters to monitor your application status and its
connection resources in .NET Core and .NET Standard .

See also
Retrieving and modifying data in ADO.NET
Microsoft ADO.NET for SQL Server
Event counters in SqlClient
4/27/2022 • 5 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET

IMPORTANT
Event counters are available when targeting .NET Core 3.1 and higher or .NET Standard 2.1 and higher. This feature is
available starting with Microsoft.Data.SqlClient version 3.0.0 .

You can use Microsoft.Data.SqlClient event counters to monitor the status of your application and the
connection resources that it uses. Event counters can be monitored by .NET CLI global tools and perfView or
can be accessed programmatically using the EventListener class in the System.Diagnostics.Tracing namespace.

Available event counters


Currently there are 16 different event counters available for Microsoft.Data.SqlClient as described in the
following table:

NAME DISP L AY N A M E DESC RIP T IO N

active-hard-connections Actual active connections currently The number of connections that are
made to servers currently open to database servers.

hard-connects Actual connection rate to servers The number of connections per second
that are being opened to database
servers.

hard-disconnects Actual disconnection rate from servers The number of disconnects per second
that are being made to database
servers.

active-soft-connects Active connections retrieved from the The number of already-open


connection pool connections being consumed from the
connection pool.

soft-connects Rate of connections retrieved from the The number of connections per second
connection pool that are being consumed from the
connection pool.

soft-disconnects Rate of connections returned to the The number of connections per second
connection pool that are being returned to the
connection pool.

number-of-non-pooled- Number of connections not using The number of active connections that
connections connection pooling aren't pooled.
NAME DISP L AY N A M E DESC RIP T IO N

number-of-pooled-connections Number of connections managed by The number of active connections that


the connection pool are being managed by the connection
pooling infrastructure.

number-of-active-connection- Number of active unique connection The number of unique connection pool
pool-groups strings groups that are active. This counter is
controlled by the number of unique
connection strings that are found in
the AppDomain.

number-of-inactive-connection- Number of unique connection strings The number of unique connection pool
pool-groups waiting for pruning groups that are marked for pruning.
This counter is controlled by the
number of unique connection strings
that are found in the AppDomain.

number-of-active-connection- Number of active connection pools The total number of connection pools.
pools

number-of-inactive-connection- Number of inactive connection pools The number of inactive connection


pools pools that haven't had any recent
activity and are waiting to be disposed.

number-of-active-connections Number of active connections The number of active connections that


are currently in use.

number-of-free-connections Number of ready connections in the The number of open connections


connection pool available for use in the connection
pools.

number-of-stasis-connections Number of connections currently The number of connections currently


waiting to be ready awaiting completion of an action and
which are unavailable for use by the
application.

number-of-reclaimed-connections Number of reclaimed connections from The number of connections that have
GC been reclaimed through garbage
collection where Close or Dispose
wasn't called by the application. Note
Not explicitly closing or disposing
connections hurts performance.

Retrieve event counter values


There are two primary ways of consuming EventCounters, either in-proc, or out-of-proc. For more information,
see Consume EventCounters.
Consume out-of-proc
In Windows, you can use PerfView and Xperf to collect event counters data. For more information, see Enable
event tracing in SqlClient. You can use dotnet-counters and dotnet-trace, which are cross platform .NET tools to
monitor and collect event counters data.
Out-of-proc example
The following command runs and collects SqlClient event counters values once every second. Replacing
EventCounterIntervalSec=1 with a higher value allows collection of a smaller trace with less granularity in the
counter data.

PerfView /onlyProviders=*Microsoft.Data.SqlClient.EventSource:EventCounterIntervalSec=1 run "<application-


Path>"

The following command collects SqlClient event counters values once every second.

dotnet-trace collect --process-id <pid> --providers


Microsoft.Data.SqlClient.EventSource:0:1:EventCounterIntervalSec=1

The following command monitors SqlClient event counters values once every three seconds.

dotnet-counters monitor Microsoft.Data.SqlClient.EventSource -p <process-id> --refresh-interval 3

The following command monitors selected SqlClient event counters values once every second.

dotnet-counters monitor Microsoft.Data.SqlClient.EventSource[hard-connects,hard-disconnects] -p <process-id>

Consume in-proc
You can consume the counter values via the EventListener API. An EventListener is an in-proc way of
consuming any event written by instances of an EventSource in your application. For more information, see
EventListener.
In-proc example
The following sample code captures Microsoft.Data.SqlClient.EventSource events using
EventCounterIntervalSec=1 . It writes the counter name and its Mean value on each event counter update.

NOTE
It's required to specify the EventCounterIntervalSec property value when enabling this event.
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Linq;

// This listener class will listen for events from the SqlClientEventSource class.
// SqlClientEventSource is an implementation of the EventSource class which gives
// it the ability to create events.
public class EventCounterListener : EventListener
{
protected override void OnEventSourceCreated(EventSource eventSource)
{
// Only enable events from SqlClientEventSource.
if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource"))
{
var options = new Dictionary<string, string>();
// define time interval 1 second
// without defining this parameter event counters will not enabled
options.Add("EventCounterIntervalSec", "1");
// enable for the None keyword
EnableEvents(eventSource, EventLevel.Informational, EventKeywords.None, options);
}
}

// This callback runs whenever an event is written by SqlClientEventSource.


// Event data is accessed through the EventWrittenEventArgs parameter.
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
if (eventData.Payload.FirstOrDefault(p => p is IDictionary<string, object> x &&
x.ContainsKey("Name")) is IDictionary<string, object> counters)
{
if (counters.TryGetValue("DisplayName", out object name) && name is string cntName
&& counters.TryGetValue("Mean", out object value) && value is double cntValue)
{
// print event counter's name and mean value
Console.WriteLine($"{cntName}\t\t{cntValue}");
}
}
}
}

class Program
{
static void Main(string[] args)
{
// Create a new event listener
using (var listener = new EventCounterListener())
{
string connectionString = "Data Source=localhost; Integrated Security=true";

for (int i = 0; i < 50; i++)


{
// Open a connection
SqlConnection cnn = new SqlConnection(connectionString);
cnn.Open();
// wait for sampling interval happens
System.Threading.Thread.Sleep(500);
}
}
}
}
Actual active connections currently made to servers 0
Active connections retrieved from the connection pool 26
Number of connections not using connection pooling 0
Number of connections managed by the connection pool 26
Number of active unique connection strings 1
Number of unique connection strings waiting for pruning 0
Number of active connection pools 1
Number of inactive connection pools 0
Number of active connections 26
Number of ready connections in the connection pool 0
Number of connections currently waiting to be ready 0
...

See also
Performance counters in SqlClient
dotnet-counters
dotnet-trace
Enable event tracing in SqlClient
Microsoft ADO.NET for SQL Server
Performance counters in SqlClient
4/27/2022 • 5 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
You can use Microsoft.Data.SqlClient performance counters to monitor the status of your application and the
connection resources that it uses. Performance counters can be monitored by using Windows Performance
Monitor or can be accessed programmatically using the PerformanceCounter class in the System.Diagnostics
namespace.

Available performance counters


Currently there are 14 different performance counters available for Microsoft.Data.SqlClient as described in the
following table.

P ERF O RM A N C E C O UN T ER DESC RIP T IO N

HardConnectsPerSecond The number of connections per second that are being made
to a database server.

HardDisconnectsPerSecond The number of disconnects per second that are being made
to a database server.

NumberOfActiveConnectionPoolGroups The number of unique connection pool groups that are


active. This counter is controlled by the number of unique
connection strings that are found in the AppDomain.

NumberOfActiveConnectionPools The total number of connection pools.

NumberOfActiveConnections The number of active connections that are currently in use.


Note: This performance counter is not enabled by default.
To enable this performance counter, see Activate off-by-
default counters.

NumberOfFreeConnections The number of connections available for use in the


connection pools. Note: This performance counter is not
enabled by default. To enable this performance counter, see
Activate off-by-default counters.

NumberOfInactiveConnectionPoolGroups The number of unique connection pool groups that are


marked for pruning. This counter is controlled by the
number of unique connection strings that are found in the
AppDomain.

NumberOfInactiveConnectionPools The number of inactive connection pools that have not had
any recent activity and are waiting to be disposed.

NumberOfNonPooledConnections The number of active connections that are not pooled.


P ERF O RM A N C E C O UN T ER DESC RIP T IO N

NumberOfPooledConnections The number of active connections that are being managed


by the connection pooling infrastructure.

NumberOfReclaimedConnections The number of connections that have been reclaimed


through garbage collection where Close or Dispose was
not called by the application. Note Not explicitly closing or
disposing connections hurts performance.

NumberOfStasisConnections The number of connections currently awaiting completion of


an action and which are therefore unavailable for use by
your application.

SoftConnectsPerSecond The number of active connections being pulled from the


connection pool. Note: This performance counter is not
enabled by default. To enable this performance counter, see
Activate off-by-default counters.

SoftDisconnectsPerSecond The number of active connections that are being returned to


the connection pool. Note: This performance counter is not
enabled by default. To enable this performance counter, see
Activate off-by-default counters.

Activate off-by-default counters


The performance counters NumberOfFreeConnections , NumberOfActiveConnections , SoftDisconnectsPerSecond , and
SoftConnectsPerSecond are off by default. Add the following information to the application's configuration file to
enable them:

<system.diagnostics>
<switches>
<add name="ConnectionPoolPerformanceCounterDetail" value="4"/>
<!-- A value of 4 corresponds to System.Diagnostics.TraceLevel.Verbose -->
</switches>
</system.diagnostics>

Retrieve performance counter values


The following console application shows how to retrieve performance counter values in your application.
Connections must be open and active for information to be returned for all of the Microsoft SqlClient Data
Provider for SQL Server performance counters.

NOTE
This example uses the sample AdventureWorks database. The connection strings provided in the sample code assume
that the database is installed and available on the local computer, and that you have created logins that match those
supplied in the connection strings. You may need to enable SQL Server logins if your server is configured using the
default security settings which allow only Windows Authentication. Modify the connection strings as necessary to suit
your environment.

Example

using System;
using Microsoft.Data.SqlClient;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace PerformanceCounterTest
{
class Program
{
PerformanceCounter[] PerfCounters = new PerformanceCounter[10];
SqlConnection connection = new SqlConnection();

static void Main()


{
Program prog = new Program();
// Open a connection and create the performance counters.
prog.connection.ConnectionString =
GetIntegratedSecurityConnectionString();
prog.SetUpPerformanceCounters();
Console.WriteLine("Available Performance Counters:");

// Create the connections and display the results.


prog.CreateConnections();
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}

private void CreateConnections()


{
// List the Performance counters.
WritePerformanceCounters();

// Create 4 connections and display counter information.


SqlConnection connection1 = new SqlConnection(
GetIntegratedSecurityConnectionString());
connection1.Open();
Console.WriteLine("Opened the 1st Connection:");
WritePerformanceCounters();

SqlConnection connection2 = new SqlConnection(


GetSqlConnectionStringDifferent());
connection2.Open();
Console.WriteLine("Opened the 2nd Connection:");
WritePerformanceCounters();

SqlConnection connection3 = new SqlConnection(


GetSqlConnectionString());
connection3.Open();
Console.WriteLine("Opened the 3rd Connection:");
WritePerformanceCounters();

SqlConnection connection4 = new SqlConnection(


GetSqlConnectionString());
connection4.Open();
Console.WriteLine("Opened the 4th Connection:");
WritePerformanceCounters();

connection1.Close();
Console.WriteLine("Closed the 1st Connection:");
WritePerformanceCounters();

connection2.Close();
Console.WriteLine("Closed the 2nd Connection:");
WritePerformanceCounters();

connection3.Close();
Console.WriteLine("Closed the 3rd Connection:");
WritePerformanceCounters();

connection4.Close();
Console.WriteLine("Closed the 4th Connection:");
WritePerformanceCounters();
}

private enum ADO_Net_Performance_Counters


{
NumberOfActiveConnectionPools,
NumberOfReclaimedConnections,
HardConnectsPerSecond,
HardDisconnectsPerSecond,
NumberOfActiveConnectionPoolGroups,
NumberOfInactiveConnectionPoolGroups,
NumberOfInactiveConnectionPools,
NumberOfNonPooledConnections,
NumberOfPooledConnections,
NumberOfStasisConnections
// The following performance counters are more expensive to track.
// Enable ConnectionPoolPerformanceCounterDetail in your config file.
// SoftConnectsPerSecond
// SoftDisconnectsPerSecond
// NumberOfActiveConnections
// NumberOfFreeConnections
}

private void SetUpPerformanceCounters()


{
connection.Close();
this.PerfCounters = new PerformanceCounter[10];
string instanceName = GetInstanceName();
Type apc = typeof(ADO_Net_Performance_Counters);
int i = 0;
foreach (string s in Enum.GetNames(apc))
{
this.PerfCounters[i] = new PerformanceCounter();
this.PerfCounters[i].CategoryName = ".NET Data Provider for SqlServer";
this.PerfCounters[i].CounterName = s;
this.PerfCounters[i].InstanceName = instanceName;
i++;
}
}

[DllImport("kernel32.dll", SetLastError = true)]


static extern int GetCurrentProcessId();

private string GetInstanceName()


{
//This works for Winforms apps.
string instanceName =
System.Reflection.Assembly.GetEntryAssembly().GetName().Name;

// Must replace special characters like (, ), #, /, \\


string instanceName2 =
AppDomain.CurrentDomain.FriendlyName.ToString().Replace('(', '[')
.Replace(')', ']').Replace('#', '_').Replace('/', '_').Replace('\\', '_');

// For ASP.NET applications your instanceName will be your CurrentDomain's


// FriendlyName. Replace the line above that sets the instanceName with this:
// instanceName = AppDomain.CurrentDomain.FriendlyName.ToString().Replace('(','[')
// .Replace(')',']').Replace('#','_').Replace('/','_').Replace('\\','_');

string pid = GetCurrentProcessId().ToString();


instanceName = instanceName + "[" + pid + "]";
Console.WriteLine("Instance Name: {0}", instanceName);
Console.WriteLine("---------------------------");
return instanceName;
}

private void WritePerformanceCounters()


{
Console.WriteLine("---------------------------");
foreach (PerformanceCounter p in this.PerfCounters)
foreach (PerformanceCounter p in this.PerfCounters)
{
Console.WriteLine("{0} = {1}", p.CounterName, p.NextValue());
}
Console.WriteLine("---------------------------");
}

private static string GetIntegratedSecurityConnectionString()


{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return @"Data Source=.;Integrated Security=True;" +
"Initial Catalog=AdventureWorks";
}
private static string GetSqlConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return @"Data Source=.;User Id=<myUserID>;Password=<myPassword>;" +
"Initial Catalog=AdventureWorks";
}

private static string GetSqlConnectionStringDifferent()


{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return @"Initial Catalog=AdventureWorks;Data Source=.;" +
"User Id=<myUserID>;Password=<myPassword>;";
}
}
}

See also
Event counters in SqlClient
Connecting to a data source
Runtime profiling
Introduction to monitoring performance thresholds
Microsoft ADO.NET for SQL Server
Retrieve identity or autonumber values
4/27/2022 • 15 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
A primary key in a relational database is a column or combination of columns that always contain unique
values. Knowing the primary key value allows you to locate the row that contains it. Relational database engines,
such as SQL Server, Oracle, and Microsoft Access/Jet support the creation of automatically incrementing
columns that can be designated as primary keys. These values are generated by the server as rows are added to
a table. In SQL Server, you set the identity property of a column, in Oracle you create a Sequence, and in
Microsoft Access you create an AutoNumber column.
A DataColumn can also be used to generate automatically incrementing values by setting the AutoIncrement
property to true. However, you might end up with duplicate values in separate instances of a DataTable, if
multiple client applications are independently generating automatically incrementing values. Having the server
generate automatically incrementing values eliminates potential conflicts by allowing each user to retrieve the
generated value for each inserted row.
During a call to the Update method of a DataAdapter , the database can send data back to your ADO.NET
application as output parameters or as the first returned record of the result set of a SELECT statement executed
in the same batch as the INSERT statement. The Microsoft SqlClient Data Provider for SQL Server can retrieve
these values and update the corresponding columns in the DataRow being updated.

NOTE
An alternative to using an auto incrementing value is to use the NewGuid method of a Guid object to generate a GUID, or
globally unique identifier, on the client computer that can be copied to the server as each new row is inserted. The
NewGuid method generates a 16-byte binary value that is created using an algorithm that provides a high probability
that no value will be duplicated. In a SQL Server database, a GUID is stored in a uniqueidentifier column which SQL
Server can automatically generate using the Transact-SQL NEWID() function. Using a GUID as a primary key can
adversely affect performance. SQL Server provides support for the NEWSEQUENTIALID() function, which generates a
sequential GUID that is not guaranteed to be globally unique but that can be indexed more efficiently.

Retrieve SQL Server identity column values


When working with Microsoft SQL Server, you can create a stored procedure with an output parameter to return
the identity value for an inserted row. The following table describes the three Transact-SQL functions in SQL
Server that can be used to retrieve identity column values.

F UN C T IO N DESC RIP T IO N

SCOPE_IDENTITY Returns the last identity value within the current execution
scope. SCOPE_IDENTITY is recommended for most scenarios.

@@IDENTITY Contains the last identity value generated in any table in the
current session. @@IDENTITY can be affected by triggers
and may not return the identity value that you expect.
F UN C T IO N DESC RIP T IO N

IDENT_CURRENT Returns the last identity value generated for a specific table
in any session and any scope.

The following stored procedure demonstrates how to insert a row into the Categories table and use an output
parameter to return the new identity value generated by the Transact-SQL SCOPE_IDENTITY() function.

CREATE PROCEDURE dbo.InsertCategory


@CategoryName nvarchar(15),
@Identity int OUT
AS
INSERT INTO Categories (CategoryName) VALUES(@CategoryName)
SET @Identity = SCOPE_IDENTITY()

The stored procedure can then be specified as the source of the InsertCommand of a SqlDataAdapter object. The
CommandType property of the InsertCommand must be set to StoredProcedure. The identity output is retrieved
by creating a SqlParameter that has a ParameterDirection of Output. When the InsertCommand is processed, the
auto-incremented identity value is returned and placed in the Categor yID column of the current row if you set
the UpdatedRowSource property of the insert command to UpdateRowSource.OutputParameters or to
UpdateRowSource.Both .

If your insert command executes a batch that includes both an INSERT statement and a SELECT statement that
returns the new identity value, then you can retrieve the new value by setting the UpdatedRowSource property of
the insert command to UpdateRowSource.FirstReturnedRecord .
private static void RetrieveIdentity(string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create a SqlDataAdapter based on a SELECT query.
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT CategoryID, CategoryName FROM dbo.Categories",
connection);

//Create the SqlCommand to execute the stored procedure.


adapter.InsertCommand = new SqlCommand("dbo.InsertCategory",
connection);
adapter.InsertCommand.CommandType = CommandType.StoredProcedure;

// Add the parameter for the CategoryName. Specifying the


// ParameterDirection for an input parameter is not required.
adapter.InsertCommand.Parameters.Add(
new SqlParameter("@CategoryName", SqlDbType.NVarChar, 15,
"CategoryName"));

// Add the SqlParameter to retrieve the new identity value.


// Specify the ParameterDirection as Output.
SqlParameter parameter =
adapter.InsertCommand.Parameters.Add(
"@Identity", SqlDbType.Int, 0, "CategoryID");
parameter.Direction = ParameterDirection.Output;

// Create a DataTable and fill it.


DataTable categories = new DataTable();
adapter.Fill(categories);

// Add a new row.


DataRow newRow = categories.NewRow();
newRow["CategoryName"] = "New Category";
categories.Rows.Add(newRow);

adapter.Update(categories);

Console.WriteLine("List All Rows:");


foreach (DataRow row in categories.Rows)
{
{
Console.WriteLine("{0}: {1}", row[0], row[1]);
}
}
}
}

Merge new identity values


A common scenario is to call the GetChanges method of a DataTable to create a copy that contains only
changed rows, and to use the new copy when calling the Update method of a DataAdapter . This is especially
useful when you need to marshal the changed rows to a separate component that performs the update.
Following the update, the copy can contain new identity values that must then be merged back into the original
DataTable . The new identity values are likely to be different from the original values in the DataTable . To
accomplish the merge, the original values of the AutoIncrement columns in the copy must be preserved, in
order to be able to locate and update existing rows in the original DataTable , rather than appending new rows
containing the new identity values. However, by default those original values are lost after a call to the Update
method of a DataAdapter , because AcceptChanges is implicitly called for each updated DataRow .
There are two ways to preserve the original values of a DataColumn in a DataRow during a DataAdapter update:
The first method of preserving the original values is to set the AcceptChangesDuringUpdate property of the
DataAdapter to false . This configuration affects every DataRow in the DataTable being updated. For
more information and a code example, see AcceptChangesDuringUpdate.
The second method is to write code in the RowUpdated event handler of the DataAdapter to set the Status
to SkipCurrentRow. The DataRow is updated but the original value of each DataColumn is preserved. This
method enables you to preserve the original values for some rows and not for others. For example, your
code can preserve the original values for added rows and not for edited or deleted rows by first checking
the StatementType and then setting Status to SkipCurrentRow only for rows with a StatementType of
Insert .

When either of these methods is used to preserve original values in a DataRow during a DataAdapter update,
the Microsoft SqlClient Data Adapter for SQL Server performs a series of actions to set the current values of the
DataRow to new values returned by output parameters or by the first returned row of a result set, while still
preserving the original value in each DataColumn . First, the AcceptChanges method of the DataRow is called to
preserve the current values as original values, and then the new values are assigned. Following these actions,
DataRows that had their RowState property set to Added will have their RowState property set to Modified,
which may be unexpected.
How the command results are applied to each DataRow being updated is determined by the UpdatedRowSource
property of each DbCommand. This property is set to a value from the UpdateRowSource enumeration.
The following table describes how the UpdateRowSource enumeration values affect the RowState property of
updated rows.

M EM B ER N A M E DESC RIP T IO N

Both AcceptChanges is called and both output parameter values


and/or the values in the first row of any returned result set
are placed in the DataRow being updated. If there are no
values to apply, the RowState will be Unchanged.

FirstReturnedRecord If a row was returned, AcceptChanges is called and the row


is mapped to the changed row in the DataTable , setting
the RowState to Modified . If no row is returned, then
AcceptChanges is not called and the RowState remains
Added .

None Any returned parameters or rows are ignored. There is no


call to AcceptChanges and the RowState remains Added .

OutputParameters AcceptChanges is called and any output parameters are


mapped to the changed row in the DataTable , setting the
RowState to Modified . If there are no output
parameters, the RowState will be Unchanged .

Example
This example demonstrates extracting changed rows from a DataTable and using a SqlDataAdapter to update
the data source and retrieve a new identity column value. The InsertCommand executes two Transact-SQL
statements; the first one is the INSERT statement, and the second one is a SELECT statement that uses the
SCOPE_IDENTITY function to retrieve the identity value.
INSERT INTO dbo.Shippers (CompanyName)
VALUES (@CompanyName);
SELECT ShipperID, CompanyName FROM dbo.Shippers
WHERE ShipperID = SCOPE_IDENTITY();

The UpdatedRowSource property of the insert command is set to UpdateRowSource.FirstReturnedRow and the
MissingSchemaAction property of the DataAdapter is set to MissingSchemaAction.AddWithKey . The DataTable is
filled and the code adds a new row to the DataTable . The changed rows are then extracted into a new
DataTable , which is passed to the DataAdapter , which then updates the server.
private static void MergeIdentityColumns(string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create the DataAdapter
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT ShipperID, CompanyName FROM dbo.Shippers",
connection);

//Add the InsertCommand to retrieve new identity value.


adapter.InsertCommand = new SqlCommand(
"INSERT INTO dbo.Shippers (CompanyName) " +
"VALUES (@CompanyName); " +
"SELECT ShipperID, CompanyName FROM dbo.Shippers " +
"WHERE ShipperID = SCOPE_IDENTITY();", connection);

// Add the parameter for the inserted value.


adapter.InsertCommand.Parameters.Add(
new SqlParameter("@CompanyName", SqlDbType.NVarChar, 40,
"CompanyName"));
adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both;

// MissingSchemaAction adds any missing schema to


// the DataTable, including identity columns
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;

// Fill the DataTable.


DataTable shipper = new DataTable();
adapter.Fill(shipper);

// Add a new shipper.


DataRow newRow = shipper.NewRow();
newRow["CompanyName"] = "New Shipper";
shipper.Rows.Add(newRow);

// Add changed rows to a new DataTable. This


// DataTable will be used by the DataAdapter.
DataTable dataChanges = shipper.GetChanges();

// Add the event handler.


adapter.RowUpdated +=
new SqlRowUpdatedEventHandler(OnRowUpdated);

adapter.Update(dataChanges);
connection.Close();

// Merge the updates.


shipper.Merge(dataChanges);

// Commit the changes.


shipper.AcceptChanges();

Console.WriteLine("Rows after merge.");


foreach (DataRow row in shipper.Rows)
{
{
Console.WriteLine("{0}: {1}", row[0], row[1]);
}
}
}
}

The OnRowUpdated event handler checks the StatementType of the SqlRowUpdatedEventArgs to determine if the
row is an insert. If it is, then the Status property is set to SkipCurrentRow. The row is updated, but the original
values in the row are preserved. In the main body of the procedure, the Merge method is called to merge the
new identity value into the original DataTable , and finally AcceptChanges is called.

protected static void OnRowUpdated(


object sender, SqlRowUpdatedEventArgs e)
{
// If this is an insert, then skip this row.
if (e.StatementType == StatementType.Insert)
{
e.Status = UpdateStatus.SkipCurrentRow;
}
}

Retrieve identity values


We often set the column as identity when the values in the column must be unique. And sometimes we need the
identity value of new data. This sample demonstrates how to retrieve identity values:
Creates a stored procedure to insert data and return an identity value.
Executes a command to insert the new data and display the result.
Uses SqlDataAdapter to insert new data and display the result.
Before you compile and run the sample, you must create the sample database, using the following script:

USE [master]
GO

CREATE DATABASE [MySchool]


GO

USE [MySchool]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE procedure [dbo].[CourseExtInfo] @CourseId int
as
select c.CourseID,c.Title,c.Credits,d.Name as DepartmentName
from Course as c left outer join Department as d on c.DepartmentID=d.DepartmentID
where c.CourseID=@CourseId

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create procedure [dbo].[DepartmentInfo] @DepartmentId int,@CourseCount int output
as
select @CourseCount=Count(c.CourseID)
from course as c
where c.DepartmentID=@DepartmentId

select d.DepartmentID,d.Name,d.Budget,d.StartDate,d.Administrator
from Department as d
where d.DepartmentID=@DepartmentId

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
GO
Create PROCEDURE [dbo].[GetDepartmentsOfSpecifiedYear]
@Year int,@BudgetSum money output
AS
BEGIN
SELECT @BudgetSum=SUM([Budget])
FROM [MySchool].[dbo].[Department]
Where YEAR([StartDate])=@Year

SELECT [DepartmentID]
,[Name]
,[Budget]
,[StartDate]
,[Administrator]
FROM [MySchool].[dbo].[Department]
Where YEAR([StartDate])=@Year

END
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GradeOfStudent]
-- Add the parameters for the stored procedure here
@CourseTitle nvarchar(100),@FirstName nvarchar(50),
@LastName nvarchar(50),@Grade decimal(3,2) output
AS
BEGIN
select @Grade=Max(Grade)
from [dbo].[StudentGrade] as s join [dbo].[Course] as c on
s.CourseID=c.CourseID join [dbo].[Person] as p on s.StudentID=p.PersonID
where c.Title=@CourseTitle and p.FirstName=@FirstName
and p.LastName= @LastName
END
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[InsertPerson]
-- Add the parameters for the stored procedure here
@FirstName nvarchar(50),@LastName nvarchar(50),
@PersonID int output
AS
BEGIN
insert [dbo].[Person](LastName,FirstName) Values(@LastName,@FirstName)

set @PersonID=SCOPE_IDENTITY()
END
Go

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Course]([CourseID] [nvarchar](10) NOT NULL,
[Year] [smallint] NOT NULL,
[Title] [nvarchar](100) NOT NULL,
[Credits] [int] NOT NULL,
[DepartmentID] [int] NOT NULL,
CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED
(
[CourseID] ASC,
[Year] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Department]([DepartmentID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Budget] [money] NOT NULL,
[StartDate] [datetime] NOT NULL,
[Administrator] [int] NULL,
CONSTRAINT [PK_Department] PRIMARY KEY CLUSTERED
(
[DepartmentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Person]([PersonID] [int] IDENTITY(1,1) NOT NULL,
[LastName] [nvarchar](50) NOT NULL,
[FirstName] [nvarchar](50) NOT NULL,
[HireDate] [datetime] NULL,
[EnrollmentDate] [datetime] NULL,
[Picture] [varbinary](max) NULL,
CONSTRAINT [PK_School.Student] PRIMARY KEY CLUSTERED
(
[PersonID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[StudentGrade]([EnrollmentID] [int] IDENTITY(1,1) NOT NULL,
[CourseID] [nvarchar](10) NOT NULL,
[StudentID] [int] NOT NULL,
[Grade] [decimal](3, 2) NOT NULL,
CONSTRAINT [PK_StudentGrade] PRIMARY KEY CLUSTERED
(
[EnrollmentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create view [dbo].[EnglishCourse]
as
select c.CourseID,c.Title,c.Credits,c.DepartmentID
from Course as c join Department as d on c.DepartmentID=d.DepartmentID
where d.Name=N'English'

GO
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1045', 2012,
N'Calculus', 4, 7)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1061', 2012,
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1061', 2012,
N'Physics', 4, 1)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2021', 2012,
N'Composition', 3, 2)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2042', 2012,
N'Literature', 4, 2)
SET IDENTITY_INSERT [dbo].[Department] ON

INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (1,


N'Engineering', 350000.0000, CAST(0x0000999C00000000 AS DateTime), 2)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (2,
N'English', 120000.0000, CAST(0x0000999C00000000 AS DateTime), 6)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (4,
N'Economics', 200000.0000, CAST(0x0000999C00000000 AS DateTime), 4)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (7,
N'Mathematics', 250024.0000, CAST(0x0000999C00000000 AS DateTime), 3)
SET IDENTITY_INSERT [dbo].[Department] OFF
SET IDENTITY_INSERT [dbo].[Person] ON

INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (1, N'Hu',
N'Nan', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (2,
N'Norman', N'Laura', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (3,
N'Olivotto', N'Nino', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (4,
N'Anand', N'Arturo', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (5, N'Jai',
N'Damien', NULL, CAST(0x0000A0BF00000000 AS DateTime))
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (6,
N'Holt', N'Roger', CAST(0x000097F100000000 AS DateTime), NULL)
INSERT [dbo].[Person] ([PersonID], [LastName], [FirstName], [HireDate], [EnrollmentDate]) VALUES (7,
N'Martin', N'Randall', CAST(0x00008B1A00000000 AS DateTime), NULL)
SET IDENTITY_INSERT [dbo].[Person] OFF
SET IDENTITY_INSERT [dbo].[StudentGrade] ON

INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (1, N'C1045', 1,


CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (2, N'C1045', 2,
CAST(3.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (3, N'C1045', 3,
CAST(2.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (4, N'C1045', 4,
CAST(4.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (5, N'C1045', 5,
CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (6, N'C1061', 1,
CAST(4.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (7, N'C1061', 3,
CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (8, N'C1061', 4,
CAST(2.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (9, N'C1061', 5,
CAST(1.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (10, N'C2021', 1,
CAST(2.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (11, N'C2021', 2,
CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (12, N'C2021', 4,
CAST(3.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (13, N'C2021', 5,
CAST(3.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (14, N'C2042', 1,
CAST(2.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (15, N'C2042', 2,
CAST(3.50 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (16, N'C2042', 3,
CAST(4.00 AS Decimal(3, 2)))
INSERT [dbo].[StudentGrade] ([EnrollmentID], [CourseID], [StudentID], [Grade]) VALUES (17, N'C2042', 5,
CAST(3.00 AS Decimal(3, 2)))
CAST(3.00 AS Decimal(3, 2)))
SET IDENTITY_INSERT [dbo].[StudentGrade] OFF
ALTER TABLE [dbo].[Course] WITH CHECK ADD CONSTRAINT [FK_Course_Department] FOREIGN KEY([DepartmentID])
REFERENCES [dbo].[Department] ([DepartmentID])
GO
ALTER TABLE [dbo].[Course] CHECK CONSTRAINT [FK_Course_Department]
GO
ALTER TABLE [dbo].[StudentGrade] WITH CHECK ADD CONSTRAINT [FK_StudentGrade_Student] FOREIGN
KEY([StudentID])
REFERENCES [dbo].[Person] ([PersonID])
GO
ALTER TABLE [dbo].[StudentGrade] CHECK CONSTRAINT [FK_StudentGrade_Student]
GO

The code listing follows:

static void Main(string[] args)


{
String SqlDbConnectionString = "Data Source=(local);Initial Catalog=MySchool;Integrated Security=True;";

InsertPersonInCommand(SqlDbConnectionString, "Janice", "Galvin");


Console.WriteLine();

InsertPersonInAdapter(SqlDbConnectionString, "Peter", "Krebs");


Console.WriteLine();

Console.WriteLine("Please press any key to exit.....");


Console.ReadKey();
}

// Using stored procedure to insert a new row and retrieve the identity value
static void InsertPersonInCommand(String connectionString, String firstName, String lastName)
{
String commandText = "dbo.InsertPerson";

using (SqlConnection conn = new SqlConnection(connectionString))


{
using (SqlCommand cmd = new SqlCommand(commandText, conn))
{
cmd.CommandType = CommandType.StoredProcedure;

cmd.Parameters.Add(new SqlParameter("@FirstName", firstName));


cmd.Parameters.Add(new SqlParameter("@LastName", lastName));
SqlParameter personId = new SqlParameter("@PersonID", SqlDbType.Int);
personId.Direction = ParameterDirection.Output;
cmd.Parameters.Add(personId);

conn.Open();
cmd.ExecuteNonQuery();

Console.WriteLine("Person Id of new person:{0}", personId.Value);


}
}
}

// Using stored procedure in adapter to insert new rows and update the identity value.
static void InsertPersonInAdapter(String connectionString, String firstName, String lastName)
{
String commandText = "dbo.InsertPerson";
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlDataAdapter mySchool = new SqlDataAdapter("Select PersonID,FirstName,LastName from [dbo].
[Person]", conn);

mySchool.InsertCommand = new SqlCommand(commandText, conn);


mySchool.InsertCommand.CommandType = CommandType.StoredProcedure;

mySchool.InsertCommand.Parameters.Add(
mySchool.InsertCommand.Parameters.Add(
new SqlParameter("@FirstName", SqlDbType.NVarChar, 50, "FirstName"));
mySchool.InsertCommand.Parameters.Add(
new SqlParameter("@LastName", SqlDbType.NVarChar, 50, "LastName"));

SqlParameter personId = mySchool.InsertCommand.Parameters.Add(new SqlParameter("@PersonID",


SqlDbType.Int, 0, "PersonID"));
personId.Direction = ParameterDirection.Output;

DataTable persons = new DataTable();


mySchool.Fill(persons);

DataRow newPerson = persons.NewRow();


newPerson["FirstName"] = firstName;
newPerson["LastName"] = lastName;
persons.Rows.Add(newPerson);

mySchool.Update(persons);
Console.WriteLine("Show all persons:");
ShowDataTable(persons, 14);
}
}

private static void ShowDataTable(DataTable table, Int32 length)


{
foreach (DataColumn col in table.Columns)
{
Console.Write("{0,-" + length + "}", col.ColumnName);
}
Console.WriteLine();

foreach (DataRow row in table.Rows)


{
foreach (DataColumn col in table.Columns)
{
if (col.DataType.Equals(typeof(DateTime)))
Console.Write("{0,-" + length + ":d}", row[col]);
else if (col.DataType.Equals(typeof(Decimal)))
Console.Write("{0,-" + length + ":C}", row[col]);
else
Console.Write("{0,-" + length + "}", row[col]);
}

Console.WriteLine();
}
}

See also
Retrieving and modifying data in ADO.NET
DataAdapters and DataReaders
Update data sources with DataAdapters
Microsoft ADO.NET for SQL Server
Retrieve binary data
4/27/2022 • 3 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
By default, the DataReader loads incoming data as a row as soon as an entire row of data is available. Binary
large objects (BLOBs) need different treatment, however, because they can contain gigabytes of data that cannot
be contained in a single row. The Command.ExecuteReader method has an overload that will take a
CommandBehavior argument to modify the default behavior of the DataReader . You can pass
SequentialAccess to the ExecuteReader method to modify the default behavior of the DataReader so that
instead of loading rows of data, it will load data sequentially as it is received. This is ideal for loading BLOBs or
other large data structures.

NOTE
When setting the DataReader to use SequentialAccess , it is important to note the sequence in which you access the
fields returned. The default behavior of the DataReader , which loads an entire row as soon as it is available, allows you to
access the fields returned in any order until the next row is read. When using SequentialAccess however, you must
access the fields returned by the DataReader in order. For example, if your query returns three columns, the third of
which is a BLOB, you must return the values of the first and second fields before accessing the BLOB data in the third field.
If you access the third field before the first or second fields, the first and second field values are no longer available. This is
because SequentialAccess has modified the DataReader to return data in sequence and the data is not available after
the DataReader has read past it.

When accessing the data in the BLOB field, use the GetBytes or GetChars typed accessors of the DataReader ,
which fill an array with data. You can also use GetString for character data; however, to conserve system
resources you might not want to load an entire BLOB value into a single string variable. You can instead specify a
specific buffer size of data to be returned, and a starting location for the first byte or character to be read from
the returned data. GetBytes and GetChars will return a long value, which represents the number of bytes or
characters returned. If you pass a null array to GetBytes or GetChars , the long value returned will be the total
number of bytes or characters in the BLOB. You can optionally specify an index in the array as a starting position
for the data being read.

Example
The following example returns the publisher ID and logo from the pubs sample database. The publisher ID (
pub_id ) is a character field, and the logo is an image, which is a BLOB. Because the logo field is a bitmap, the
example returns binary data using GetBytes . Notice that the publisher ID is accessed for the current row of data
before the logo, because the fields must be accessed sequentially.
// Assumes that connection is a valid SqlConnection object.
SqlCommand command = new SqlCommand(
"SELECT pub_id, logo FROM pub_info", connection);

// Writes the BLOB to a file (*.bmp).


System.IO.FileStream stream;
// Streams the BLOB to the FileStream object.
System.IO.BinaryWriter writer;

// Size of the BLOB buffer.


int bufferSize = 100;
// The BLOB byte[] buffer to be filled by GetBytes.
byte[] outByte = new byte[bufferSize];
// The bytes returned from GetBytes.
long retval;
// The starting position in the BLOB output.
long startIndex = 0;

// The publisher id to use in the file name.


string pubID = "";

// Open the connection and read data into the DataReader.


connection.Open();
SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess);

while (reader.Read())
{
// Get the publisher id, which must occur before getting the logo.
pubID = reader.GetString(0);

// Create a file to hold the output.


stream = new System.IO.FileStream(
"logo" + pubID + ".bmp", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
writer = new System.IO.BinaryWriter(stream);

// Reset the starting byte for the new BLOB.


startIndex = 0;

// Read bytes into outByte[] and retain the number of bytes returned.
retval = reader.GetBytes(1, startIndex, outByte, 0, bufferSize);

// Continue while there are bytes beyond the size of the buffer.
while (retval == bufferSize)
{
writer.Write(outByte);
writer.Flush();

// Reposition start index to end of last buffer and fill buffer.


startIndex += bufferSize;
retval = reader.GetBytes(1, startIndex, outByte, 0, bufferSize);
}

// Write the remaining buffer.


writer.Write(outByte, 0, (int)retval);
writer.Flush();

// Close the output file.


writer.Close();
stream.Close();
}

// Close the reader and the connection.


reader.Close();
connection.Close();
See also
SQL Server binary and large-value data
Microsoft ADO.NET for SQL Server
Modify data with stored procedures
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Stored procedures can accept data as input parameters and can return data as output parameters, result sets, or
return values. The sample below illustrates how Microsoft SqlClient Data Provider for SQL Server sends and
receives input parameters, output parameters, and return values. The example inserts a new record into a table
where the primary key column is an identity column.

NOTE
If you are using stored procedures to edit or delete data using a SqlDataAdapter, make sure that you do not use SET
NOCOUNT ON in the stored procedure definition. This causes the rows affected count returned to be zero, which the
DataAdapter interprets as a concurrency conflict. In this event, a DBConcurrencyException will be thrown.

Example
The sample uses the following stored procedure to insert a new category into the Nor thwind Categories
table. The stored procedure takes the value in the Categor yName column as an input parameter and uses the
SCOPE_IDENTITY() function to retrieve the new value of the identity field, Categor yID , and return it in an
output parameter. The RETURN statement uses the @@ROWCOUNT function to return the number of rows
inserted.

CREATE PROCEDURE dbo.InsertCategory


@CategoryName nvarchar(15),
@Identity int OUT
AS
INSERT INTO Categories (CategoryName) VALUES(@CategoryName)
SET @Identity = SCOPE_IDENTITY()
RETURN @@ROWCOUNT

The following code example uses the InsertCategory stored procedure shown above as the source for the
InsertCommand of the SqlDataAdapter. The @Identity output parameter will be reflected in the DataSet after
the record has been inserted into the database when the Update method of the SqlDataAdapter is called. The
code also retrieves the return value.

using System;
using System.Data;
using Microsoft.Data.SqlClient;

class Program
{
static void Main()
{
string connectionString = GetConnectionString();
ReturnIdentity(connectionString);
// Console.ReadLine();
}

private static void ReturnIdentity(string connectionString)


{
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create a SqlDataAdapter based on a SELECT query.
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT CategoryID, CategoryName FROM dbo.Categories", connection);

// Create a SqlCommand to execute the stored procedure.


adapter.InsertCommand = new SqlCommand("InsertCategory", connection);
adapter.InsertCommand.CommandType = CommandType.StoredProcedure;

// Create a parameter for the ReturnValue.


SqlParameter parameter = adapter.InsertCommand.Parameters.Add("@RowCount", SqlDbType.Int);
parameter.Direction = ParameterDirection.ReturnValue;

// Create an input parameter for the CategoryName.


// You do not need to specify direction for input parameters.
adapter.InsertCommand.Parameters.Add("@CategoryName", SqlDbType.NChar, 15, "CategoryName");

// Create an output parameter for the new identity value.


parameter = adapter.InsertCommand.Parameters.Add("@Identity", SqlDbType.Int, 0, "CategoryID");
parameter.Direction = ParameterDirection.Output;

// Create a DataTable and fill it.


DataTable categories = new DataTable();
adapter.Fill(categories);

// Add a new row.


DataRow categoryRow = categories.NewRow();
categoryRow["CategoryName"] = "New Beverages";
categories.Rows.Add(categoryRow);

// Update the database.


adapter.Update(categories);

// Retrieve the ReturnValue.


Int rowCount = (Int)adapter.InsertCommand.Parameters["@RowCount"].Value;

Console.WriteLine("ReturnValue: {0}", rowCount.ToString());


Console.WriteLine("All Rows:");
foreach (DataRow row in categories.Rows)
{
Console.WriteLine(" {0}: {1}", row[0], row[1]);
}
}
}

static private string GetConnectionString()


{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=(local);Initial Catalog=Northwind;Integrated Security=true";
}
}

See also
Retrieving and modifying data in ADO.NET
DataAdapters and DataReaders
Executing a command
Microsoft ADO.NET for SQL Server
Data tracing in SqlClient
4/27/2022 • 3 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
.NET features built-in data tracing functionality that is supported by the Microsoft SqlClient Data Provider for
SQL Server and SQL Server network protocols.
Tracing data access API calls can help diagnose the following problems:
Schema mismatch between client program and the database.
Database unavailability or network library problems.
Incorrect SQL whether hard coded or generated by an application.
Incorrect programming logic.
Issues resulting from the interaction between Microsoft SqlClient Data Provider for SQL Server and your
own components.
To support different trace technologies, tracing is extensible, so a developer can trace a problem at any level of
the application stack. The Microsoft SqlClient Data Provider for SQL Server takes advantage of generalized
tracing and instrumentation APIs.
For more information about setting and configuring managed tracing in .NET, see Tracing Data Access.

Access diagnostic information in the extended events log


In the Microsoft SqlClient Data Provider for SQL Server, Data Access Tracing makes it easier to correlate client
events with diagnostic information, such as connection failures, from the server's connectivity ring buffer and
application performance information in the extended events log. For information about reading the extended
events log, see View Event Session Data.
For connection operations, the Microsoft SqlClient Data Provider for SQL Server will send a client connection ID.
If the connection fails, you can access the connectivity ring buffer (Connectivity troubleshooting in SQL Server
2008 with the Connectivity Ring Buffer) and find the ClientConnectionID field and get diagnostic information
about the connection failure. Client connection IDs are logged in the ring buffer only if an error occurs. If a
connection fails before sending the prelogin packet, a client connection ID will not be generated. The client
connection ID is a 16-byte GUID. You can also find the client connection ID in the extended events target output,
if the client_connection_id action is added to events in an extended events session. You can enable data access
tracing and rerun the connection command and observe the ClientConnectionID field in the data access trace, if
you need further client driver diagnostic assistance.
You can get the client connection ID programmatically by using the SqlConnection.ClientConnectionID property.

NOTE
The Microsoft SqlClient Data Provider for SQL Server supports the server process ID since version 2.1.0. You can get it
programmatically by using the SqlConnection.ServerProcessId property.
The ClientConnectionID and ServerProcessId are available for a SqlConnection object that successfully
establishes a connection. If a connection attempt fails, ClientConnectionID may be available via
SqlException.ToString .

The Microsoft SqlClient Data Provider for SQL Server also sends a thread-specific activity ID. The activity ID is
captured in the extended events sessions if the sessions are started with the TRACK_CAUSALITY option enabled.
For performance issues with an active connection, you can get the activity ID from the client's data access trace (
ActivityID field) and then locate the activity ID in the extended events output. The activity ID in extended events
is a 16-byte GUID (not the same as the GUID for the client connection ID) appended with a 4-bytes sequence
number. The sequence number represents the order of a request within a thread and indicates the relative
ordering of batch and RPC statements for the thread. The ActivityID is currently optionally sent for SQL batch
statements and RPC requests when data access tracing is enabled on and the 18th bit in the data access tracing
configuration word is turned ON.
The following SQL statement is a sample that uses Transact-SQL to start an extended events session that will be
stored in a ring buffer and will record the activity ID sent from a client on RPC and batch operations.

create event session MySession on server


add event connectivity_ring_buffer_recorded,
add event sql_statement_starting (action (client_connection_id)),
add event sql_statement_completed (action (client_connection_id)),
add event rpc_starting (action (client_connection_id)),
add event rpc_completed (action (client_connection_id))
add target ring_buffer with (track_causality=on)

See also
Microsoft ADO.NET for SQL Server
Asynchronous programming
4/27/2022 • 15 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
This article discusses support for asynchronous programming in the Microsoft SqlClient Data Provider for SQL
Server (SqlClient).

Legacy asynchronous programming


The Microsoft SqlClient Data Provider for SQL Server includes methods from System.Data.SqlClient to
maintain backwards compatibility for applications migrating to Microsoft.Data.SqlClient. It isn't recommended to
use the following legacy asynchronous programming methods for new development:
SqlCommand.BeginExecuteNonQuery
SqlCommand.BeginExecuteReader
SqlCommand.BeginExecuteXmlReader

TIP
In the Microsoft SqlClient Data Provider for SQL Server, these legacy methods no longer require
Asynchronous Processing=true in the connection string.

Asynchronous programming features


These asynchronous programming features provide a simple technique to make code asynchronous.
For more information about asynchronous programming in .NET, see:
Asynchronous programming in C#
Asynchronous Programming with Async and Await (Visual Basic)
When your user interface is unresponsive or your server doesn't scale, it's likely you need your code to be more
asynchronous. Writing asynchronous code has traditionally involved installing a callback (also called
continuation) to express the logic that occurs after the asynchronous operation finishes. This style complicates
the structure of asynchronous code as compared with synchronous code.
You can call into asynchronous methods without using callbacks, and without splitting your code across multiple
methods or lambda expressions.
The async modifier specifies that a method is asynchronous. When calling an async method, a task is returned.
When the await operator is applied to a task, the current method exits immediately. When the task finishes,
execution resumes in the same method.
TIP
In the Microsoft SqlClient Data Provider for SQL Server, asynchronous calls are not required to set the
Context Connection connection string keyword.

Calling an async method doesn't create extra threads. It may use the existing I/O completion thread briefly at
the end.
The following methods in the Microsoft SqlClient Data Provider for SQL Server support asynchronous
programming:
DbConnection.OpenAsync
DbCommand.ExecuteDbDataReaderAsync
DbCommand.ExecuteNonQueryAsync
DbCommand.ExecuteReaderAsync
DbCommand.ExecuteScalarAsync
GetFieldValueAsync
IsDBNullAsync
DbDataReader.NextResultAsync
DbDataReader.ReadAsync
SqlConnection.OpenAsync
SqlCommand.ExecuteNonQueryAsync
SqlCommand.ExecuteReaderAsync
SqlCommand.ExecuteScalarAsync
SqlCommand.ExecuteXmlReaderAsync
SqlDataReader.NextResultAsync
SqlDataReader.ReadAsync
SqlBulkCopy.WriteToServerAsync
Other asynchronous members support SqlClient streaming support.

TIP
The asynchronous methods don't require Asynchronous Processing=true in the connection string. And this property is
obsolete in the Microsoft SqlClient Data Provider for SQL Server.

Synchronous to asynchronous connection open


You can upgrade an existing application to use the asynchronous feature. For example, assume an application
has a synchronous connection algorithm and blocks the UI thread every time it connects to the database. Once
connected, the application calls a stored procedure that signals other users of the one who just signed in.
using System;
using System.Data;
using Microsoft.Data.SqlClient;

namespace SqlCommandCS
{
class Program
{
static void Main()
{
string str = "Data Source=(local);Initial Catalog=Northwind;"
+ "Integrated Security=SSPI";
string qs = "SELECT OrderID, CustomerID FROM dbo.Orders;";
CreateCommand(qs, str);
}
private static void CreateCommand(string queryString,
string connectionString)
{
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
}
}
}

When converted to use the asynchronous functionality, the program would look like:

using Microsoft.Data.SqlClient;
using System.Threading.Tasks;

class A {
public static void Main()
{
using (SqlConnection conn = new SqlConnection("Data Source=(local); Initial Catalog=NorthWind;
Integrated Security=SSPI"))
{
SqlCommand command = new SqlCommand("SELECT TOP 2 * FROM dbo.Orders", conn);

int result = A.Method(conn, command).Result;

SqlDataReader reader = command.ExecuteReader();


while (reader.Read())
Console.WriteLine(reader[0]);
}
}

static async Task<int> Method(SqlConnection conn, SqlCommand cmd) {


await conn.OpenAsync();
await cmd.ExecuteNonQueryAsync();
return 1;
}
}

Add the asynchronous feature in an existing application (mixing old and new patterns)
It's also possible to add asynchronous capability (SqlConnection::OpenAsync) without changing the existing
asynchronous logic. For example, if an application currently uses:
AsyncCallback productList = new AsyncCallback(ProductList);
SqlConnection conn = new SqlConnection("Data Source=(local); Initial Catalog=NorthWind; Integrated
Security=SSPI");
conn.Open();
SqlCommand cmd = new SqlCommand("select top 2 * from orders", conn);
IAsyncResult ia = cmd.BeginExecuteReader(productList, cmd);

You can begin to use the asynchronous pattern without substantially changing the existing algorithm.

using Microsoft.Data.SqlClient;
using System.Threading.Tasks;

class A
{
static void ProductList(IAsyncResult result) { }

public static void Main()


{
// AsyncCallback productList = new AsyncCallback(ProductList);
// SqlConnection conn = new SqlConnection("Data Source=(local); Initial Catalog=NorthWind; Integrated
Security=SSPI");
// conn.Open();
// SqlCommand cmd = new SqlCommand("select top 2 * from orders", conn);
// IAsyncResult ia = cmd.BeginExecuteReader(productList, cmd);

AsyncCallback productList = new AsyncCallback(ProductList);


SqlConnection conn = new SqlConnection("Data Source=(local); Initial Catalog=NorthWind; Integrated
Security=SSPI");
conn.OpenAsync().ContinueWith((task) => {
SqlCommand cmd = new SqlCommand("select top 2 * from orders", conn);
IAsyncResult ia = cmd.BeginExecuteReader(productList, cmd);
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
}

Use the base provider model and the asynchronous feature


You may need to create a tool that can connect to different databases and execute queries. You can use the base
provider model and the asynchronous feature.
The Microsoft Distributed Transaction Controller (MSDTC) must be enabled on the server to use distributed
transactions. For information on how to enable MSDTC, see How to Enable MSDTC on a Web Server.
using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;

class program
{
static async Task PerformDBOperationsUsingProviderModel(string connectionString)
{
using (DbConnection connection = SqlClientFactory.Instance.CreateConnection())
{
connection.ConnectionString = connectionString;
await connection.OpenAsync();

DbCommand command = connection.CreateCommand();


command.CommandText = "SELECT * FROM AUTHORS";

using (DbDataReader reader = await command.ExecuteReaderAsync())


{
while (await reader.ReadAsync())
{
for (int i = 0; i < reader.FieldCount; i++)
{
// Process each column as appropriate
object obj = await reader.GetFieldValueAsync<object>(i);
Console.WriteLine(obj);
}
}
}
}
}

public static void Main()


{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
// replace these with your own values
builder.DataSource = "localhost";
builder.InitialCatalog = "pubs";
builder.IntegratedSecurity = true;

Task task = PerformDBOperationsUsingProviderModel(builder.ConnectionString);


task.Wait();
}
}

Use SQL transactions and the new asynchronous feature

using Microsoft.Data.SqlClient;
using System.Threading.Tasks;

class Program
{
static void Main()
{
string connectionString =
"Persist Security Info=False;Integrated Security=SSPI;database=Northwind;server=(local)";
Task task = ExecuteSqlTransaction(connectionString);
task.Wait();
}

static async Task ExecuteSqlTransaction(string connectionString)


{
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();

SqlCommand command = connection.CreateCommand();


SqlTransaction transaction = null;
SqlTransaction transaction = null;

// Start a local transaction.


transaction = await Task.Run<SqlTransaction>(
() => connection.BeginTransaction("SampleTransaction")
);

// Must assign both transaction object and connection


// to Command object for a pending local transaction
command.Connection = connection;
command.Transaction = transaction;

try {
command.CommandText =
"Insert into Region (RegionID, RegionDescription) VALUES (555, 'Description')";
await command.ExecuteNonQueryAsync();

command.CommandText =
"Insert into Region (RegionID, RegionDescription) VALUES (556, 'Description')";
await command.ExecuteNonQueryAsync();

// Attempt to commit the transaction.


await Task.Run(() => transaction.Commit());
Console.WriteLine("Both records are written to database.");
}
catch (Exception ex)
{
Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
Console.WriteLine(" Message: {0}", ex.Message);

// Attempt to roll back the transaction.


try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
}
}
}
}

Use distributed transactions and the new asynchronous feature


In an enterprise application, you may need to add distributed transactions in some scenarios, to enable
transactions between multiple database servers. You can use the System.Transactions namespace and enlist a
distributed transaction, as follows:

using Microsoft.Data.SqlClient;
using System.Threading.Tasks;
using System.Transactions;

class Program
{
public static void Main()
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
// replace these with your own values
// create two tables RegionTable1 and RegionTable2
// and add a constraint in one of these tables
// to avoid duplicate RegionID
builder.DataSource = "localhost";
builder.InitialCatalog = "Northwind";
builder.IntegratedSecurity = true;

Task task = ExecuteDistributedTransaction(builder.ConnectionString, builder.ConnectionString);


task.Wait();
}

static async Task ExecuteDistributedTransaction(string connectionString1, string connectionString2)


{
using (SqlConnection connection1 = new SqlConnection(connectionString1))
using (SqlConnection connection2 = new SqlConnection(connectionString2))
{
using (CommittableTransaction transaction = new CommittableTransaction())
{
await connection1.OpenAsync();
connection1.EnlistTransaction(transaction);

await connection2.OpenAsync();
connection2.EnlistTransaction(transaction);

try
{
SqlCommand command1 = connection1.CreateCommand();
command1.CommandText = "Insert into RegionTable1 (RegionID, RegionDescription) VALUES
(100, 'Description')";
await command1.ExecuteNonQueryAsync();

SqlCommand command2 = connection2.CreateCommand();


command2.CommandText = "Insert into RegionTable2 (RegionID, RegionDescription) VALUES
(100, 'Description')";
await command2.ExecuteNonQueryAsync();

transaction.Commit();
}
catch (Exception ex)
{
Console.WriteLine("Exception Type: {0}", ex.GetType());
Console.WriteLine(" Message: {0}", ex.Message);

try
{
transaction.Rollback();
}
catch (Exception ex2)
{
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
Console.WriteLine(" Message: {0}", ex2.Message);
}
}
}
}
}
}

Cancel an asynchronous operation


You can cancel an asynchronous request by using the CancellationToken.
using Microsoft.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;

namespace Samples
{
class CancellationSample
{
public static void Main(string[] args)
{
CancellationTokenSource source = new CancellationTokenSource();
source.CancelAfter(2000); // give up after 2 seconds
try
{
Task result = CancellingAsynchronousOperations(source.Token);
result.Wait();
}
catch (AggregateException exception)
{
if (exception.InnerException is SqlException)
{
Console.WriteLine("Operation canceled");
}
else
{
throw;
}
}
}

static async Task CancellingAsynchronousOperations(CancellationToken cancellationToken)


{
using (SqlConnection connection = new SqlConnection("Server=(local);Integrated Security=true"))
{
await connection.OpenAsync(cancellationToken);

SqlCommand command = new SqlCommand("WAITFOR DELAY '00:10:00'", connection);


await command.ExecuteNonQueryAsync(cancellationToken);
}
}
}
}

Asynchronous operations with SqlBulkCopy


Asynchronous capabilities are also in Microsoft.Data.SqlClient.SqlBulkCopy with
SqlBulkCopy.WriteToServerAsync.

using System.Data;
using Microsoft.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;

namespace SqlBulkCopyAsyncCodeSample
{
class Program
{
static string selectStatement = "SELECT * FROM [pubs].[dbo].[titles]";
static string createDestTableStatement =
@"CREATE TABLE {0} (
[title_id] [varchar](6) NOT NULL,
[title] [varchar](80) NOT NULL,
[type] [char](12) NOT NULL,
[pub_id] [char](4) NULL,
[price] [money] NULL,
[advance] [money] NULL,
[royalty] [int] NULL,
[ytd_sales] [int] NULL,
[notes] [varchar](200) NULL,
[pubdate] [datetime] NOT NULL)";

// Replace the connection string if needed, for instance to connect to SQL Express: @"Server=
(local)\SQLEXPRESS;Database=Demo;Integrated Security=true"
// static string connectionString = @"Server=(localdb)\V11.0;Database=Demo";
static string connectionString = @"Server=(local);Database=Demo;Integrated Security=true";

// static string marsConnectionString = @"Server=


(localdb)\V11.0;Database=Demo;MultipleActiveResultSets=true;";
static string marsConnectionString = @"Server=
(local);Database=Demo;MultipleActiveResultSets=true;Integrated Security=true";

// Replace the Server name with your actual sql azure server name and User ID/Password
static string azureConnectionString = @"Server=SqlAzure;User ID=<myUserID>;Password=
<myPassword>;Database=Demo";

static void Main(string[] args)


{
SynchronousSqlBulkCopy();
AsyncSqlBulkCopy().Wait();
MixSyncAsyncSqlBulkCopy().Wait();
AsyncSqlBulkCopyNotifyAfter().Wait();
AsyncSqlBulkCopyDataRows().Wait();
AsyncSqlBulkCopySqlServerToSqlAzure().Wait();
AsyncSqlBulkCopyCancel().Wait();
AsyncSqlBulkCopyMARS().Wait();
}

// 3.1.1 Synchronous bulk copy in .NET 4.5


private static void SynchronousSqlBulkCopy()
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
DataTable dt = new DataTable();
using (SqlCommand cmd = new SqlCommand(selectStatement, conn))
{
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(dt);

string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";


cmd.CommandText = string.Format(createDestTableStatement, temptable);
cmd.ExecuteNonQuery();

using (SqlBulkCopy bcp = new SqlBulkCopy(conn))


{
bcp.DestinationTableName = temptable;
bcp.WriteToServer(dt);
}
}
}

// 3.1.2 Asynchronous bulk copy in .NET 4.5


private static async Task AsyncSqlBulkCopy()
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
await conn.OpenAsync();
DataTable dt = new DataTable();
using (SqlCommand cmd = new SqlCommand(selectStatement, conn))
{
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(dt);
string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
cmd.CommandText = string.Format(createDestTableStatement, temptable);
await cmd.ExecuteNonQueryAsync();

using (SqlBulkCopy bcp = new SqlBulkCopy(conn))


{
bcp.DestinationTableName = temptable;
await bcp.WriteToServerAsync(dt);
}
}
}
}

// 3.2 Add new Async.NET capabilities in an existing application (Mixing synchronous and
asynchronous calls)
private static async Task MixSyncAsyncSqlBulkCopy()
{
using (SqlConnection conn1 = new SqlConnection(connectionString))
{
conn1.Open();
using (SqlCommand cmd = new SqlCommand(selectStatement, conn1))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
using (SqlConnection conn2 = new SqlConnection(connectionString))
{
await conn2.OpenAsync();
string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
SqlCommand createCmd = new SqlCommand(string.Format(createDestTableStatement,
temptable), conn2);
await createCmd.ExecuteNonQueryAsync();
using (SqlBulkCopy bcp = new SqlBulkCopy(conn2))
{
bcp.DestinationTableName = temptable;
await bcp.WriteToServerAsync(reader);
}
}
}
}
}
}

// 3.3 Using the NotifyAfter property


private static async Task AsyncSqlBulkCopyNotifyAfter()
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
await conn.OpenAsync();
DataTable dt = new DataTable();
using (SqlCommand cmd = new SqlCommand(selectStatement, conn))
{
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(dt);

string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";


cmd.CommandText = string.Format(createDestTableStatement, temptable);
await cmd.ExecuteNonQueryAsync();

using (SqlBulkCopy bcp = new SqlBulkCopy(conn))


{
bcp.DestinationTableName = temptable;
bcp.NotifyAfter = 5;
bcp.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnSqlRowsCopied);
await bcp.WriteToServerAsync(dt);
}
}
}
}
private static void OnSqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
{
Console.WriteLine("Copied {0} so far...", e.RowsCopied);
}

// 3.4 Using the new SqlBulkCopy Async.NET capabilities with DataRow[]


private static async Task AsyncSqlBulkCopyDataRows()
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
await conn.OpenAsync();
DataTable dt = new DataTable();
using (SqlCommand cmd = new SqlCommand(selectStatement, conn))
{
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(dt);
DataRow[] rows = dt.Select();

string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";


cmd.CommandText = string.Format(createDestTableStatement, temptable);
await cmd.ExecuteNonQueryAsync();

using (SqlBulkCopy bcp = new SqlBulkCopy(conn))


{
bcp.DestinationTableName = temptable;
await bcp.WriteToServerAsync(rows);
}
}
}
}

// 3.5 Copying data from SQL Server to SQL Azure in .NET 4.5
private static async Task AsyncSqlBulkCopySqlServerToSqlAzure()
{
using (SqlConnection srcConn = new SqlConnection(connectionString))
using (SqlConnection destConn = new SqlConnection(azureConnectionString))
{
await srcConn.OpenAsync();
await destConn.OpenAsync();
using (SqlCommand srcCmd = new SqlCommand(selectStatement, srcConn))
{
using (SqlDataReader reader = await srcCmd.ExecuteReaderAsync())
{
string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
using (SqlCommand destCmd = new SqlCommand(string.Format(createDestTableStatement,
temptable), destConn))
{
await destCmd.ExecuteNonQueryAsync();
using (SqlBulkCopy bcp = new SqlBulkCopy(destConn))
{
bcp.DestinationTableName = temptable;
await bcp.WriteToServerAsync(reader);
}
}
}
}
}
}

// 3.6 Cancelling an Asynchronous Operation to SQL Azure


private static async Task AsyncSqlBulkCopyCancel()
{
CancellationTokenSource cts = new CancellationTokenSource();
using (SqlConnection srcConn = new SqlConnection(connectionString))
using (SqlConnection destConn = new SqlConnection(azureConnectionString))
{
await srcConn.OpenAsync(cts.Token);
await destConn.OpenAsync(cts.Token);
using (SqlCommand srcCmd = new SqlCommand(selectStatement, srcConn))
using (SqlCommand srcCmd = new SqlCommand(selectStatement, srcConn))
{
using (SqlDataReader reader = await srcCmd.ExecuteReaderAsync(cts.Token))
{
string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
using (SqlCommand destCmd = new SqlCommand(string.Format(createDestTableStatement,
temptable), destConn))
{
await destCmd.ExecuteNonQueryAsync(cts.Token);
using (SqlBulkCopy bcp = new SqlBulkCopy(destConn))
{
bcp.DestinationTableName = temptable;
await bcp.WriteToServerAsync(reader, cts.Token);
//Cancel Async SqlBulCopy Operation after 200 ms
cts.CancelAfter(200);
}
}
}
}
}
}

// 3.7 Using Async.Net and MARS


private static async Task AsyncSqlBulkCopyMARS()
{
using (SqlConnection marsConn = new SqlConnection(marsConnectionString))
{
await marsConn.OpenAsync();

SqlCommand titlesCmd = new SqlCommand("SELECT * FROM [pubs].[dbo].[titles]", marsConn);


SqlCommand authorsCmd = new SqlCommand("SELECT * FROM [pubs].[dbo].[authors]", marsConn);
//With MARS we can have multiple active results sets on the same connection
using (SqlDataReader titlesReader = await titlesCmd.ExecuteReaderAsync())
using (SqlDataReader authorsReader = await authorsCmd.ExecuteReaderAsync())
{
await authorsReader.ReadAsync();

string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";


using (SqlConnection destConn = new SqlConnection(connectionString))
{
await destConn.OpenAsync();
using (SqlCommand destCmd = new SqlCommand(string.Format(createDestTableStatement,
temptable), destConn))
{
await destCmd.ExecuteNonQueryAsync();
using (SqlBulkCopy bcp = new SqlBulkCopy(destConn))
{
bcp.DestinationTableName = temptable;
await bcp.WriteToServerAsync(titlesReader);
}
}
}
}
}
}
}
}

Asynchronously use multiple commands with MARS


The example opens a single connection to the AdventureWorks database. Using a SqlCommand object, a
SqlDataReader is created. As the reader is used, a second SqlDataReader is opened, using data from the first
SqlDataReader as input to the WHERE clause for the second reader.
NOTE
The following example uses the sample AdventureWorks database. The connection string provided in the sample code
assumes that the database is installed and available on the local computer. Modify the connection string as necessary for
your environment.

using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;

class Class1
{
static void Main()
{
Task task = MultipleCommands();
task.Wait();
}

static async Task MultipleCommands()


{
// By default, MARS is disabled when connecting to a MARS-enabled.
// It must be enabled in the connection string.
string connectionString = GetConnectionString();

int vendorID;
SqlDataReader productReader = null;
string vendorSQL =
"SELECT BusinessEntityID, Name FROM Purchasing.Vendor";
string productSQL =
"SELECT Production.Product.Name FROM Production.Product " +
"INNER JOIN Purchasing.ProductVendor " +
"ON Production.Product.ProductID = " +
"Purchasing.ProductVendor.ProductID " +
"WHERE Purchasing.ProductVendor.BusinessEntityID = @VendorId";

using (SqlConnection awConnection =


new SqlConnection(connectionString))
{
SqlCommand vendorCmd = new SqlCommand(vendorSQL, awConnection);
SqlCommand productCmd =
new SqlCommand(productSQL, awConnection);

productCmd.Parameters.Add("@VendorId", SqlDbType.Int);

await awConnection.OpenAsync();
using (SqlDataReader vendorReader = await vendorCmd.ExecuteReaderAsync())
{
while (await vendorReader.ReadAsync())
{
Console.WriteLine(vendorReader["Name"]);

vendorID = (int)vendorReader["BusinessEntityID"];

productCmd.Parameters["@VendorId"].Value = vendorID;
// The following line of code requires a MARS-enabled connection.
productReader = await productCmd.ExecuteReaderAsync();
using (productReader)
{
while (await productReader.ReadAsync())
{
Console.WriteLine(" " +
productReader["Name"].ToString());
}
}
}
}
}
}
}

private static string GetConnectionString()


{
// To avoid storing the connection string in your code, you can retrieve it from a configuration
file.
return "Data Source=(local);Integrated Security=SSPI;Initial
Catalog=AdventureWorks;MultipleActiveResultSets=True";
}
}

Asynchronously read and update data with MARS


MARS allows a connection to be used for both read operations and data manipulation language (DML)
operations with more than one pending operation. This feature eliminates the need for an application to deal
with connection-busy errors. Also, MARS can replace the use of server-side cursors, which generally consume
more resources. Finally, because multiple operations can operate on a single connection, they can share the
same transaction context, eliminating the need to use sp_getbindtoken and sp_bindsession system stored
procedures.
The following Console application demonstrates how to use two SqlDataReader objects with three SqlCommand
objects and a single SqlConnection object with MARS enabled. The first command object retrieves a list of
vendors whose credit rating is 5. The second command object uses the vendor ID provided from a
SqlDataReader to load the second SqlDataReader with all of the products for the particular vendor. Each product
record is visited by the second SqlDataReader. A calculation is performed to determine what the new
OnOrderQty should be. The third command object is then used to update the ProductVendor table with the
new value. This entire process takes place within a single transaction, which is rolled back at the end.

NOTE
The following example uses the sample AdventureWorks database. The connection string provided in the sample code
assumes that the database is installed and available on the local computer. Modify the connection string as necessary for
your environment.

using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;

class Program
{
static void Main()
{
Task task = ReadingAndUpdatingData();
task.Wait();
}

static async Task ReadingAndUpdatingData()


{
// By default, MARS is disabled when connecting to a MARS-enabled host.
// It must be enabled in the connection string.
string connectionString = GetConnectionString();

SqlTransaction updateTx = null;


SqlCommand vendorCmd = null;
SqlCommand prodVendCmd = null;
SqlCommand updateCmd = null;

SqlDataReader prodVendReader = null;


int vendorID = 0;
int productID = 0;
int minOrderQty = 0;
int maxOrderQty = 0;
int onOrderQty = 0;
int recordsUpdated = 0;
int totalRecordsUpdated = 0;

string vendorSQL =
"SELECT BusinessEntityID, Name FROM Purchasing.Vendor " +
"WHERE CreditRating = 5";
string prodVendSQL =
"SELECT ProductID, MaxOrderQty, MinOrderQty, OnOrderQty " +
"FROM Purchasing.ProductVendor " +
"WHERE BusinessEntityID = @VendorID";
string updateSQL =
"UPDATE Purchasing.ProductVendor " +
"SET OnOrderQty = @OrderQty " +
"WHERE ProductID = @ProductID AND BusinessEntityID = @VendorID";

using (SqlConnection awConnection =


new SqlConnection(connectionString))
{
await awConnection.OpenAsync();
updateTx = await Task.Run(() => awConnection.BeginTransaction());

vendorCmd = new SqlCommand(vendorSQL, awConnection);


vendorCmd.Transaction = updateTx;

prodVendCmd = new SqlCommand(prodVendSQL, awConnection);


prodVendCmd.Transaction = updateTx;
prodVendCmd.Parameters.Add("@VendorId", SqlDbType.Int);

updateCmd = new SqlCommand(updateSQL, awConnection);


updateCmd.Transaction = updateTx;
updateCmd.Parameters.Add("@OrderQty", SqlDbType.Int);
updateCmd.Parameters.Add("@ProductID", SqlDbType.Int);
updateCmd.Parameters.Add("@VendorID", SqlDbType.Int);

using (SqlDataReader vendorReader = await vendorCmd.ExecuteReaderAsync())


{
while (await vendorReader.ReadAsync())
{
Console.WriteLine(vendorReader["Name"]);

vendorID = (int)vendorReader["BusinessEntityID"];
prodVendCmd.Parameters["@VendorID"].Value = vendorID;
prodVendReader = await prodVendCmd.ExecuteReaderAsync();

using (prodVendReader)
{
while (await prodVendReader.ReadAsync())
{
productID = (int)prodVendReader["ProductID"];

if (prodVendReader["OnOrderQty"] == DBNull.Value)
{
minOrderQty = (int)prodVendReader["MinOrderQty"];
onOrderQty = minOrderQty;
}
else
{
maxOrderQty = (int)prodVendReader["MaxOrderQty"];
onOrderQty = (int)(maxOrderQty / 2);
}

updateCmd.Parameters["@OrderQty"].Value = onOrderQty;
updateCmd.Parameters["@ProductID"].Value = productID;
updateCmd.Parameters["@VendorID"].Value = vendorID;
updateCmd.Parameters["@VendorID"].Value = vendorID;

recordsUpdated = await updateCmd.ExecuteNonQueryAsync();


totalRecordsUpdated += recordsUpdated;
}
}
}
}
Console.WriteLine("Total Records Updated: ", totalRecordsUpdated.ToString());
await Task.Run(() => updateTx.Rollback());
Console.WriteLine("Transaction Rolled Back");
}
}

private static string GetConnectionString()


{
// To avoid storing the connection string in your code, you can retrieve it from a configuration
file.
return "Data Source=(local);Integrated Security=SSPI;Initial
Catalog=AdventureWorks;MultipleActiveResultSets=True";
}
}

See also
Retrieving and modifying data in ADO.NET
Microsoft ADO.NET for SQL Server
SqlClient streaming support
4/27/2022 • 11 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Streaming support between SQL Server and an application supports unstructured data on the server
(documents, images, and media files). A SQL Server database can store binary large objects (BLOBs), but
retrieving BLOBS can use a lot of memory.
Streaming support to and from SQL Server simplifies writing applications that stream data, without having to
fully load the data into memory, resulting in fewer memory overflow exceptions.
Streaming support will also enable middle-tier applications to scale better, especially in scenarios where
business objects connect to Azure SQL in order to send, retrieve, and manipulate large BLOBs.

WARNING
The members that support streaming are used to retrieve data from queries and to pass parameters to queries and
stored procedures. The streaming feature addresses basic OLTP and data migration scenarios and is applicable to on-
premises and off-premises data migrations environments.

Streaming support from SQL Server


Streaming support from SQL Server introduces new functionality in the DbDataReader and in the
SqlDataReader classes in order to get Stream, XmlReader, and TextReader objects and react to them. These
classes are used to retrieve data from queries. As a result, Streaming support from SQL Server addresses OLTP
scenarios and applies to on-premises and off-premises environments.
The following members were added to SqlDataReader to enable streaming support from SQL Server:
IsDBNullAsync
SqlDataReader.GetFieldValue
GetFieldValueAsync
GetStream
GetTextReader
GetXmlReader
The following members were added to DbDataReader to enable streaming support from SQL Server:
GetFieldValue
GetStream
GetTextReader

Streaming support to SQL Server


Streaming support to SQL Server is in the SqlParameter class so it can accept and react to XmlReader, Stream,
and TextReader objects. SqlParameter is used to pass parameters to queries and stored procedures.

NOTE
Disposing a SqlCommand object or calling Cancel must cancel any streaming operation. If an application sends
CancellationToken, cancellation is not guaranteed.

The following SqlDbType types will accept a Value of Stream:


Binar y
VarBinar y
The following SqlDbType types will accept a Value of TextReader:
Char
NChar
NVarChar
Xml
The Xml SqlDbType type will accept a Value of XmlReader.
SqlValue can accept values of type XmlReader, TextReader, and Stream.
The XmlReader, TextReader, and Stream object will be transferred up to the value defined by the Size.

Sample -- streaming from SQL Server


Use the following Transact-SQL to create the sample database:

CREATE DATABASE [Demo]


GO
USE [Demo]
GO
CREATE TABLE [Streams] (
[id] INT PRIMARY KEY IDENTITY(1, 1),
[textdata] NVARCHAR(MAX),
[bindata] VARBINARY(MAX),
[xmldata] XML)
GO
INSERT INTO [Streams] (textdata, bindata, xmldata) VALUES (N'This is a test', 0x48656C6C6F,
N'<test>value</test>')
INSERT INTO [Streams] (textdata, bindata, xmldata) VALUES (N'Hello, World!', 0x54657374696E67,
N'<test>value2</test>')
INSERT INTO [Streams] (textdata, bindata, xmldata) VALUES (N'Another row', 0x666F6F626172, N'<fff>bbb</fff>
<fff>bbc</fff>')
GO

The sample shows how to do the following:


Avoid blocking a user-interface thread by providing an asynchronous way to retrieve large files.
Transfer a large text file from SQL Server in .NET.
Transfer a large XML file from SQL Server in .NET.
Retrieve data from SQL Server.
Transfer large files (BLOBs) from one SQL Server database to another without running out of memory.
using System;
using System.Data;
using Microsoft.Data.SqlClient;
using System.IO;
using System.Threading.Tasks;
using System.Xml;

namespace StreamingFromServer
{
class Program
{
private const string connectionString = @"Server=localhost;Database=Demo;Integrated Security=true";

static void Main(string[] args)


{
CopyBinaryValueToFile().Wait();
PrintTextValues().Wait();
PrintXmlValues().Wait();
PrintXmlValuesViaNVarChar().Wait();

Console.WriteLine("Done");
}

// Application retrieving a large BLOB from SQL Server in .NET 4.5 using the new asynchronous
capability
private static async Task CopyBinaryValueToFile()
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
using (SqlCommand command = new SqlCommand("SELECT [bindata] FROM [Streams] WHERE [id]=@id",
connection))
{
command.Parameters.AddWithValue("id", 1);

// The reader needs to be executed with the SequentialAccess behavior to enable network
streaming
// Otherwise ReadAsync will buffer the entire BLOB into memory which can cause
scalability issues or even OutOfMemoryExceptions
using (SqlDataReader reader = await
command.ExecuteReaderAsync(CommandBehavior.SequentialAccess))
{
if (await reader.ReadAsync())
{
if (!(await reader.IsDBNullAsync(0)))
{
using (FileStream file = new FileStream("binarydata.bin", FileMode.Create,
FileAccess.Write))
{
using (Stream data = reader.GetStream(0))
{

// Asynchronously copy the stream from the server to the file we


just created
await data.CopyToAsync(file);
}
}
}
}
}
}
}
}

// Application transferring a large Text File from SQL Server


private static async Task PrintTextValues()
{
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
using (SqlCommand command = new SqlCommand("SELECT [id], [textdata] FROM [Streams]",
connection))
{

// The reader needs to be executed with the SequentialAccess behavior to enable network
streaming
// Otherwise ReadAsync will buffer the entire text document into memory which can cause
scalability issues or even OutOfMemoryExceptions
using (SqlDataReader reader = await
command.ExecuteReaderAsync(CommandBehavior.SequentialAccess))
{
while (await reader.ReadAsync())
{
Console.Write("{0}: ", reader.GetInt32(0));

if (await reader.IsDBNullAsync(1))
{
Console.Write("(NULL)");
}
else
{
char[] buffer = new char[4096];
int charsRead = 0;
using (TextReader data = reader.GetTextReader(1))
{
do
{
// Grab each chunk of text and write it to the console
// If you are writing to a TextWriter you should use WriteAsync or
WriteLineAsync
charsRead = await data.ReadAsync(buffer, 0, buffer.Length);
Console.Write(buffer, 0, charsRead);
} while (charsRead > 0);
}
}

Console.WriteLine();
}
}
}
}
}

// Application transferring a large Xml Document from SQL Server


private static async Task PrintXmlValues()
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
using (SqlCommand command = new SqlCommand("SELECT [id], [xmldata] FROM [Streams]",
connection))
{

// The reader needs to be executed with the SequentialAccess behavior to enable network
streaming
// Otherwise ReadAsync will buffer the entire Xml Document into memory which can cause
scalability issues or even OutOfMemoryExceptions
using (SqlDataReader reader = await
command.ExecuteReaderAsync(CommandBehavior.SequentialAccess))
{
while (await reader.ReadAsync())
{
Console.WriteLine("{0}: ", reader.GetInt32(0));

if (await reader.IsDBNullAsync(1))
{
Console.WriteLine("\t(NULL)");
Console.WriteLine("\t(NULL)");
}
else
{
using (XmlReader xmlReader = reader.GetXmlReader(1))
{
int depth = 1;
// NOTE: The XmlReader returned by GetXmlReader does NOT support async
operations
// See the example below (PrintXmlValuesViaNVarChar) for how to get an
XmlReader with asynchronous capabilities
while (xmlReader.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.Element:
Console.WriteLine("{0}<{1}>", new string('\t', depth),
xmlReader.Name);
depth++;
break;
case XmlNodeType.Text:
Console.WriteLine("{0}{1}", new string('\t', depth),
xmlReader.Value);
break;
case XmlNodeType.EndElement:
depth--;
Console.WriteLine("{0}</{1}>", new string('\t', depth),
xmlReader.Name);
break;
}
}
}
}
}
}
}
}
}

// Application transferring a large Xml Document from SQL Server


// This goes via NVarChar and TextReader to enable asynchronous reading
private static async Task PrintXmlValuesViaNVarChar()
{
XmlReaderSettings xmlSettings = new XmlReaderSettings()
{
// Async must be explicitly enabled in the XmlReaderSettings otherwise the XmlReader will
throw exceptions when async methods are called
Async = true,
// Since we will immediately wrap the TextReader we are creating in an XmlReader, we will
permit the XmlReader to take care of closing\disposing it
CloseInput = true,
// If the Xml you are reading is not a valid document (as per
<https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/6bts1x50(v=vs.100)>) you will need to
set the conformance level to Fragment
ConformanceLevel = ConformanceLevel.Fragment
};

using (SqlConnection connection = new SqlConnection(connectionString))


{
await connection.OpenAsync();

// Cast the XML into NVarChar to enable GetTextReader - trying to use GetTextReader on an
XML type will throw an exception
using (SqlCommand command = new SqlCommand("SELECT [id], CAST([xmldata] AS NVARCHAR(MAX))
FROM [Streams]", connection))
{

// The reader needs to be executed with the SequentialAccess behavior to enable network
streaming
// Otherwise ReadAsync will buffer the entire Xml Document into memory which can cause
// Otherwise ReadAsync will buffer the entire Xml Document into memory which can cause
scalability issues or even OutOfMemoryExceptions
using (SqlDataReader reader = await
command.ExecuteReaderAsync(CommandBehavior.SequentialAccess))
{
while (await reader.ReadAsync())
{
Console.WriteLine("{0}:", reader.GetInt32(0));

if (await reader.IsDBNullAsync(1))
{
Console.WriteLine("\t(NULL)");
}
else
{
// Grab the row as a TextReader, then create an XmlReader on top of it
// We are not keeping a reference to the TextReader since the XmlReader is
created with the "CloseInput" setting (so it will close the TextReader when needed)
using (XmlReader xmlReader = XmlReader.Create(reader.GetTextReader(1),
xmlSettings))
{
int depth = 1;
// The XmlReader above now supports asynchronous operations, so we can
use ReadAsync here
while (await xmlReader.ReadAsync())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.Element:
Console.WriteLine("{0}<{1}>", new string('\t', depth),
xmlReader.Name);
depth++;
break;
case XmlNodeType.Text:
// Depending on what your data looks like, you should either
use Value or GetValueAsync
// Value has less overhead (since it doesn't create a Task),
but it may also block if additional data is required
Console.WriteLine("{0}{1}", new string('\t', depth), await
xmlReader.GetValueAsync());
break;
case XmlNodeType.EndElement:
depth--;
Console.WriteLine("{0}</{1}>", new string('\t', depth),
xmlReader.Name);
break;
}
}
}
}
}
}
}
}
}
}
}

Sample -- streaming to SQL Server


Use the following Transact-SQL to create the sample database:
CREATE DATABASE [Demo2]
GO
USE [Demo2]
GO
CREATE TABLE [BinaryStreams] (
[id] INT PRIMARY KEY IDENTITY(1, 1),
[bindata] VARBINARY(MAX))
GO
CREATE TABLE [TextStreams] (
[id] INT PRIMARY KEY IDENTITY(1, 1),
[textdata] NVARCHAR(MAX))
GO
CREATE TABLE [BinaryStreamsCopy] (
[id] INT PRIMARY KEY IDENTITY(1, 1),
[bindata] VARBINARY(MAX))
GO

The sample shows how to do the following:


Transferring a large BLOB to SQL Server in .NET.
Transferring a large text file to SQL Server in .NET.
Using the new asynchronous feature to transfer a large BLOB.
Using the new asynchronous feature and the await keyword to transfer a large BLOB.
Cancelling the transfer of a large BLOB.
Streaming from one SQL Server to another using the asynchronous feature.

using System;
using System.Data;
using Microsoft.Data.SqlClient;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace StreamingToServer
{
class Program
{
private const string connectionString = @"Server=localhost;Database=Demo2;Integrated Security=true";

static void Main(string[] args)


{
CreateDemoFiles();

StreamBLOBToServer().Wait();
StreamTextToServer().Wait();

// Create a CancellationTokenSource that will be cancelled after 100ms


// Typically this token source will be cancelled by a user request (e.g. a Cancel button)
CancellationTokenSource tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(100);
try
{
CancelBLOBStream(tokenSource.Token).Wait();
}
catch (AggregateException ex)
{
// Cancelling an async operation will throw an exception
// Since we are using the Task's Wait method, this exception will be wrapped in an
AggregateException
// If you were using the 'await' keyword, the compiler would take care of unwrapping the
AggregateException
AggregateException
// Depending on when the cancellation occurs, you can either get an error from SQL Server or
from .Net
if ((ex.InnerException is SqlException) || (ex.InnerException is TaskCanceledException))
{
// This is an expected exception
Console.WriteLine("Got expected exception: {0}", ex.InnerException.Message);
}
else
{
// Did not expect this exception - re-throw it
throw;
}
}

Console.WriteLine("Done");
}

// This is used to generate the files which are used by the other sample methods
private static void CreateDemoFiles()
{
Random rand = new Random();
byte[] data = new byte[1024];
rand.NextBytes(data);

using (FileStream file = File.Open("binarydata.bin", FileMode.Create))


{
file.Write(data, 0, data.Length);
}

using (StreamWriter writer = new StreamWriter(File.Open("textdata.txt", FileMode.Create)))


{
writer.Write(Convert.ToBase64String(data));
}
}

// Application transferring a large BLOB to SQL Server


private static async Task StreamBLOBToServer()
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
await conn.OpenAsync();
using (SqlCommand cmd = new SqlCommand("INSERT INTO [BinaryStreams] (bindata) VALUES
(@bindata)", conn))
{
using (FileStream file = File.Open("binarydata.bin", FileMode.Open))
{

// Add a parameter which uses the FileStream we just opened


// Size is set to -1 to indicate "MAX"
cmd.Parameters.Add("@bindata", SqlDbType.Binary, -1).Value = file;

// Send the data to the server asynchronously


await cmd.ExecuteNonQueryAsync();
}
}
}
}

// Application transferring a large Text File to SQL Server


private static async Task StreamTextToServer()
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
await conn.OpenAsync();
using (SqlCommand cmd = new SqlCommand("INSERT INTO [TextStreams] (textdata) VALUES
(@textdata)", conn))
{
using (StreamReader file = File.OpenText("textdata.txt"))
{
{

// Add a parameter which uses the StreamReader we just opened


// Size is set to -1 to indicate "MAX"
cmd.Parameters.Add("@textdata", SqlDbType.NVarChar, -1).Value = file;

// Send the data to the server asynchronously


await cmd.ExecuteNonQueryAsync();
}
}
}
}

// Cancelling the transfer of a large BLOB


private static async Task CancelBLOBStream(CancellationToken cancellationToken)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
// We can cancel not only sending the data to the server, but also opening the connection
await conn.OpenAsync(cancellationToken);

// Artificially delay the command by 100ms


using (SqlCommand cmd = new SqlCommand("WAITFOR DELAY '00:00:00:100';INSERT INTO
[BinaryStreams] (bindata) VALUES (@bindata)", conn))
{
using (FileStream file = File.Open("binarydata.bin", FileMode.Open))
{

// Add a parameter which uses the FileStream we just opened


// Size is set to -1 to indicate "MAX"
cmd.Parameters.Add("@bindata", SqlDbType.Binary, -1).Value = file;

// Send the data to the server asynchronously


// Pass the cancellation token such that the command will be cancelled if needed
await cmd.ExecuteNonQueryAsync(cancellationToken);
}
}
}
}
}
}

Sample -- Streaming from one SQL Server to another SQL Server


This sample demonstrates how to asynchronously stream a large BLOB from one SQL Server to another, with
support for cancellation.

NOTE
Before running the following sample, be sure the Demo and Demo2 databases are created.

using System;
using System.Data;
using Microsoft.Data.SqlClient;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace StreamingFromServerToAnother
{
class Program
{
private const string connectionString = @"Server=localhost;Database=Demo2;Integrated Security=true";
static void Main(string[] args)
{
// For this example, we don't want to cancel
// So we can pass in a "blank" cancellation token
E2EStream(CancellationToken.None).Wait();

Console.WriteLine("Done");
}

// Streaming from one SQL Server to Another One


private static async Task E2EStream(CancellationToken cancellationToken)
{
using (SqlConnection readConn = new SqlConnection(connectionString))
{
using (SqlConnection writeConn = new SqlConnection(connectionString))
{

// Note that we are using the same cancellation token for calls to both
connections\commands
// Also we can start both the connection opening asynchronously, and then wait for both
to complete
Task openReadConn = readConn.OpenAsync(cancellationToken);
Task openWriteConn = writeConn.OpenAsync(cancellationToken);
await Task.WhenAll(openReadConn, openWriteConn);

using (SqlCommand readCmd = new SqlCommand("SELECT [bindata] FROM [BinaryStreams]",


readConn))
{
using (SqlCommand writeCmd = new SqlCommand("INSERT INTO [BinaryStreamsCopy]
(bindata) VALUES (@bindata)", writeConn))
{

// Add an empty parameter to the write command which will be used for the
streams we are copying
// Size is set to -1 to indicate "MAX"
SqlParameter streamParameter = writeCmd.Parameters.Add("@bindata",
SqlDbType.Binary, -1);

// The reader needs to be executed with the SequentialAccess behavior to enable


network streaming
// Otherwise ReadAsync will buffer the entire BLOB into memory which can cause
scalability issues or even OutOfMemoryExceptions
using (SqlDataReader reader = await
readCmd.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken))
{
while (await reader.ReadAsync(cancellationToken))
{
// Grab a stream to the binary data in the source database
using (Stream dataStream = reader.GetStream(0))
{

// Set the parameter value to the stream source that was opened
streamParameter.Value = dataStream;

// Asynchronously send data from one database to another


await writeCmd.ExecuteNonQueryAsync(cancellationToken);
}
}
}
}
}
}
}
}
}
}
See also
Retrieving and modifying data in ADO.NET
Microsoft ADO.NET for SQL Server
SQL Server and ADO.NET
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET

Microsoft.Data.SqlClient
Microsoft.Data.SqlClient provides access to versions of SQL Server, which encapsulates database-specific
protocols. Microsoft.Data.SqlClient includes a tabular data stream (TDS) parser to communicate directly with
SQL Server.

NOTE
To use the Microsoft SqlClient Data Provider for SQL Server, an application must reference the Microsoft.Data.SqlClient
namespace.

In this section
SQL Server security
Provides an overview of SQL Server security features, and application scenarios for creating secure ADO.NET
applications that target SQL Server.
SQL Server data types and ADO.NET
Describes how to work with SQL Server data types and how they interact with .NET data types.
SQL Server binary and large-value data
Describes how to work with large value data in SQL Server.
SQL Server data operations in ADO.NET
Describes how to work with data in SQL Server. Contains sections about bulk copy operations, MARS,
asynchronous operations, and table-valued parameters.
SQL Server features and ADO.NET
Describes SQL Server features that are useful for ADO.NET application developers.
For complete documentation of the SQL Server Database Engine, see SQL Server Books Online for the version
of SQL Server you are using.
SQL Server Books Online
SQL Server security
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
SQL Server has many features that support creating secure database applications.
Common security considerations, such as data theft or vandalism, apply regardless of the version of SQL Server
you are using. Data integrity should also be considered as a security issue. If data is not protected, it is possible
that it could become worthless if ad hoc data manipulation is permitted and the data is inadvertently or
maliciously modified with incorrect values or deleted entirely. In addition, there are often legal requirements that
must be adhered to, such as the correct storage of confidential information. Storing some kinds of personal data
is proscribed entirely, depending on the laws that apply in a particular jurisdiction.
Each version of SQL Server has different security features, as does each version of Windows, with later versions
having enhanced functionality over earlier ones. It is important to understand that security features alone
cannot guarantee a secure database application. Each database application is unique in its requirements,
execution environment, deployment model, physical location, and user population. Some applications that are
local in scope may need only minimal security whereas other local applications or applications deployed over
the Internet may require stringent security measures and ongoing monitoring and evaluation.
The security requirements of a SQL Server database application should be considered at design time, not as an
afterthought. Evaluating threats early in the development cycle gives you the opportunity to mitigate potential
damage wherever a vulnerability is detected.
Even if the initial design of an application is sound, new threats may emerge as the system evolves. By creating
multiple lines of defense around your database, you can minimize the damage inflicted by a security breach.
Your first line of defense is to reduce the attack surface area by never to granting more permissions than are
absolutely necessary.
The topics in this section briefly describe the security features in SQL Server that are relevant for developers,
with links to relevant topics in SQL Server Books Online and other resources that provide more detailed
coverage.

In this section
Authentication in SQL Server
Describes logins and authentication in SQL Server and provides links to additional resources.
Azure Active Directory authentication
Describes how to use supported Azure Active Directory authentication modes to connect to Azure SQL data
sources with SqlClient.
Application security scenarios in SQL Server
Contains topics discussing various application security scenarios for ADO.NET and SQL Server applications.
SQL Server Express security
Describes security considerations for SQL Server Express.

Related sections
Security Center for SQL Server Database Engine and Azure SQL Database
Describes security considerations for SQL Server and Azure SQL Database.
Security Considerations for a SQL Server Installation
Describes security concerns to consider before installing SQL Server.

Next steps
SQL Server and ADO.NET
Authentication in SQL Server
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
SQL Server supports two authentication modes, Windows authentication mode and mixed mode.
Windows authentication is the default, and is often referred to as integrated security because this SQL
Server security model is tightly integrated with Windows. Specific Windows user and group accounts are
trusted to log in to SQL Server. Windows users who have already been authenticated do not have to
present additional credentials.
Mixed mode supports authentication both by Windows and by SQL Server. User name and password
pairs are maintained within SQL Server.

IMPORTANT
We recommend using Windows authentication wherever possible. Windows authentication uses a series of encrypted
messages to authenticate users in SQL Server. When SQL Server logins are used, SQL Server login names and encrypted
passwords are passed across the network, which makes them less secure.

With Windows authentication, users are already logged onto Windows and do not have to log on separately to
SQL Server. The following SqlConnection.ConnectionString specifies Windows authentication without requiring
users to provide a user name or password.

"Server=MSSQL1;Database=AdventureWorks;Integrated Security=true;"

NOTE
Logins are distinct from database users. You must map logins or Windows groups to database users or roles in a separate
operation. You then grant permissions to users or roles to access database objects.

Authentication scenarios
Windows authentication is usually the best choice in the following situations:
There is a domain controller.
The application and the database are on the same computer.
You are using an instance of SQL Server Express or LocalDB.
SQL Server logins are often used in the following situations:
If you have a workgroup.
Users connect from different, non-trusted domains.
Internet applications, such as ASP.NET.
NOTE
Specifying Windows authentication does not disable SQL Server logins. Use the ALTER LOGIN DISABLE Transact-SQL
statement to disable highly-privileged SQL Server logins.

Login types
SQL Server supports three types of logins:
A local Windows user account or trusted domain account. SQL Server relies on Windows to authenticate
the Windows user accounts.
Windows group. Granting access to a Windows group grants access to all Windows user logins that are
members of the group.
SQL Server login. SQL Server stores both the username and a hash of the password in the master
database, by using internal authentication methods to verify login attempts.

NOTE
SQL Server provides logins created from certificates or asymmetric keys that are used only for code signing. They cannot
be used to connect to SQL Server.

Mixed mode authentication


If you must use mixed mode authentication, you must create SQL Server logins, which are stored in SQL Server.
You then have to supply the SQL Server user name and password at run time.

IMPORTANT
SQL Server installs with a SQL Server login named sa (an abbreviation of "system administrator"). Assign a strong
password to the sa login and do not use the sa login in your application. The sa login maps to the sysadmin fixed
server role, which has irrevocable administrative credentials on the whole server. There are no limits to the potential
damage if an attacker gains access as a system administrator. All members of the Windows BUILTIN\Administrators
group (the local administrator's group) are members of the sysadmin role by default, but can be removed from that role.

IMPORTANT
Concatenating connection strings from user input can leave you vulnerable to a connection string injection attack. Use
the SqlConnectionStringBuilder to create syntactically valid connection strings at run time.

External resources
For more information, see the following resources.

RESO URC E DESC RIP T IO N

Principals Describes logins and other security principals in SQL Server.

Next steps
Application security scenarios in SQL Server
Using Azure Active Directory authentication with
SqlClient
4/27/2022 • 13 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
This article describes how to connect to Azure SQL data sources by using Azure Active Directory (Azure AD)
authentication from a .NET application with SqlClient.
Azure AD authentication uses identities in Azure AD to access Azure SQL data sources such as Azure SQL
Database, Azure SQL Managed Instance, and Azure Synapse Analytics. The Microsoft.Data.SqlClient
namespace allows client applications to specify Azure AD credentials in different authentication modes when
they're connecting to Azure SQL Database. To use Azure AD authentication, you must configure your Azure SQL
data source. For more information, see Configure and manage Azure AD authentication with Azure SQL.
When you set the Authentication connection property in the connection string, the client can choose a
preferred Azure AD authentication mode according to the value provided:
The earliest Microsoft.Data.SqlClient version supports Active Directory Password for .NET
Framework, .NET Core, and .NET Standard. It also supports Active Directory Integrated authentication
and Active Directory Interactive authentication for .NET Framework.
Starting with Microsoft.Data.SqlClient 2.0.0, support for Active Directory Integrated authentication
and Active Directory Interactive authentication has been extended across .NET Framework, .NET Core,
and .NET Standard.
A new Active Directory Service Principal authentication mode is also added in SqlClient 2.0.0. It makes
use of the client ID and secret of a service principal identity to accomplish authentication.
More authentication modes are added in Microsoft.Data.SqlClient 2.1.0, including
Active Directory Device Code Flow and Active Directory Managed Identity (also known as
Active Directory MSI ). These new modes enable the application to acquire an access token to connect to
the server.
For information about Azure AD authentication beyond what the following sections describe, see Connecting to
SQL Database by using Azure Active Directory authentication.

Setting Azure Active Directory authentication


When the application is connecting to Azure SQL data sources by using Azure AD authentication, it needs to
provide a valid authentication mode. The following table lists the supported authentication modes. The
application specifies a mode by using the Authentication connection property in the connection string.

M IC RO SO F T. DATA . SQ L C L IEN T
VA L UE DESC RIP T IO N VERSIO N

Active Directory Password Authenticate with an Azure AD identity 1.0+


by using a username and password
M IC RO SO F T. DATA . SQ L C L IEN T
VA L UE DESC RIP T IO N VERSIO N

Active Directory Integrated Authenticate with an Azure AD identity 2.0.0+1


by using integrated authentication

Active Directory Interactive Authenticate with an Azure AD identity 2.0.0+1


by using interactive authentication

Active Directory Service Principal Authenticate with an Azure AD identity 2.0.0+


by using the client ID and secret of a
service principal identity

Active Directory Device Code Flow Authenticate with an Azure AD identity 2.1.0+
by using Device Code Flow mode

Active Directory Managed Identity, Authenticate with an Azure AD identity 2.1.0+


Active Directory MSI by using system-assigned or user-
assigned managed identity

Active Directory Default Authenticate with an Azure AD identity 3.0.0+


by using password-less and non-
interactive mechanisms including
Managed Identities, Visual Studio
Code, Visual Studio, Azure CLI, etc.

1 Before Microsoft.Data.SqlClient 2.0.0, Active Directory Integrated , and Active Directory Interactive
authentication modes are supported only on .NET Framework.

Using Active Directory Password authentication


Active Directory Password authentication mode supports authentication to Azure data sources with Azure AD
for native or federated Azure AD users. When you're using this mode, user credentials must be provided in the
connection string. The following example shows how to use Active Directory Password authentication.

// Use your own server, database, user ID, and password.


string ConnectionString = @"Server=demo.database.windows.net; Authentication=Active Directory Password;
Database=testdb; User [email protected]; Password=***";

using (SqlConnection conn = new SqlConnection(ConnectionString)) {


conn.Open();
}

Using Active Directory Integrated authentication


To use Active Directory Integrated authentication mode, you need to federate the on-premises Active
Directory instance with Azure AD in the cloud. You can do federation by using Active Directory Federation
Services (AD FS), for example.
When you're signed in to a domain-joined machine, you can access Azure SQL data sources without being
prompted for credentials with this mode. You can't specify username and password in the connection string for
.NET Framework applications. Username is optional in the connection string for .NET Core and .NET Standard
applications. You can't set the Credential property of SqlConnection in this mode.
The following code snippet is an example of when Active Directory Integrated authentication is in use.
// Use your own server and database.
string ConnectionString1 = @"Server=demo.database.windows.net; Authentication=Active Directory Integrated;
Database=testdb";

using (SqlConnection conn = new SqlConnection(ConnectionString1)) {


conn.Open();
}

// User ID is optional for .NET Core and .NET Standard.


string ConnectionString2 = @"Server=demo.database.windows.net; Authentication=Active Directory Integrated;
Database=testdb; User [email protected]";

using (SqlConnection conn = new SqlConnection(ConnectionString2)) {


conn.Open();
}

Using Active Directory Interactive authentication


Active Directory Interactive authentication supports multi-factor authentication technology to connect to
Azure SQL data sources. If you provide this authentication mode in the connection string, an Azure
authentication screen will appear and ask the user to enter valid credentials. You can't specify the password in
the connection string.
You can't set the Credential property of SqlConnection in this mode. With Microsoft.Data.SqlClient 2.0.0
and later, username is allowed in the connection string when you're in interactive mode.
The following example shows how to use Active Directory Interactive authentication.

// Use your own server, database, and user ID.


// User ID is optional.
string ConnectionString1 = @"Server=demo.database.windows.net; Authentication=Active Directory Interactive;
Database=testdb; User [email protected]";

using (SqlConnection conn = new SqlConnection(ConnectionString1)) {


conn.Open();
}

// User ID is not provided.


string ConnectionString2 = @"Server=demo.database.windows.net; Authentication=Active Directory Interactive;
Database=testdb";

using (SqlConnection conn = new SqlConnection(ConnectionString2)) {


conn.Open();
}

Using Active Directory Service Principal authentication


In Active Directory Service Principal authentication mode, the client application can connect to Azure SQL
data sources by providing the client ID and secret of a service principal identity. Service principal authentication
involves:
1. Setting up an app registration with a secret.
2. Granting permissions to the app in the Azure SQL Database instance.
3. Connecting with the correct credential.
The following example shows how to use Active Directory Service Principal authentication.
// Use your own server, database, app ID, and secret.
string ConnectionString = @"Server=demo.database.windows.net; Authentication=Active Directory Service
Principal; Database=testdb; User Id=AppId; Password=secret";

using (SqlConnection conn = new SqlConnection(ConnectionString)) {


conn.Open();
}

Using Active Directory Device Code Flow authentication


With Microsoft Authentication Library for .NET (MSAL.NET), Active Directory Device Code Flow authentication
enables the client application to connect to Azure SQL data sources from devices and operating systems that
don't have an interactive web browser. Interactive authentication will be performed on another device. For more
information about device code flow authentication, see OAuth 2.0 Device Code Flow.
When this mode is in use, you can't set the Credential property of SqlConnection . Also, the username and
password must not be specified in the connection string.
The following code snippet is an example of using Active Directory Device Code Flow authentication.

// Use your own server and database.


string ConnectionString = @"Server=demo.database.windows.net; Authentication=Active Directory Device Code
Flow; Database=testdb";

using (SqlConnection conn = new SqlConnection(ConnectionString)) {


conn.Open();
}

Using Active Directory Managed Identity authentication


Managed Identities for Azure resources is the new name for the service formerly known as Managed Service
Identity (MSI). When a client application uses an Azure resource to access an Azure service that supports Azure
AD authentication, you can use managed identities to authenticate by providing an identity for the Azure
resource in Azure AD. You can then use that identity to obtain access tokens. This authentication method can
eliminate the need to manage credentials and secrets.
There are two types of managed identities:
System-assigned managed identity is created on a service instance in Azure AD. It's tied to the lifecycle of
that service instance.
User-assigned managed identity is created as a standalone Azure resource. It can be assigned to one or more
instances of an Azure service.
For more information about managed identities, see About managed identities for Azure resources.
Since Microsoft.Data.SqlClient 2.1.0, the driver supports authentication to Azure SQL Database, Azure
Synapse Analytics, and Azure SQL Managed Instance by acquiring access tokens via managed identity. To use
this authentication, specify either Active Directory Managed Identity or Active Directory MSI in the connection
string, and no password is required. You can't set the Credential property of SqlConnection in this mode either.
For a user-assigned managed identity, the client id of the managed identity must be provided when using
Microsoft.Data.SqlClient v3.0 or newer. If using Microsoft.Data.SqlClient v2.1, the object id of the managed
identity must be provided.
The following example shows how to use Active Directory Managed Identity authentication with a system-
assigned managed identity.
// For system-assigned managed identity
// Use your own server and database.
string ConnectionString1 = @"Server=demo.database.windows.net; Authentication=Active Directory Managed
Identity; Database=testdb";

using (SqlConnection conn = new SqlConnection(ConnectionString1)) {


conn.Open();
}

string ConnectionString2 = @"Server=demo.database.windows.net; Authentication=Active Directory MSI;


Database=testdb";

using (SqlConnection conn = new SqlConnection(ConnectionString2)) {


conn.Open();
}

The following example demonstrates Active Directory Managed Identity authentication with a user-assigned
managed identity with Microsoft.Data.SqlClient v3.0 onwards .

// For user-assigned managed identity


// Use your own values for Server, Database, and User Id.

// With Microsoft.Data.SqlClient v3.0+


string ConnectionString1 = @"Server=demo.database.windows.net; Authentication=Active Directory Managed
Identity; User Id=ClientIdOfManagedIdentity; Database=testdb";

using (SqlConnection conn = new SqlConnection(ConnectionString1)) {


conn.Open();
}

// With Microsoft.Data.SqlClient v3.0+


string ConnectionString2 = @"Server=demo.database.windows.net; Authentication=Active Directory MSI; User
Id=ClientIdOfManagedIdentity; Database=testdb";

using (SqlConnection conn = new SqlConnection(ConnectionString2)) {


conn.Open();
}

The following example demonstrates Active Directory Managed Identity authentication with a user-assigned
managed identity with Microsoft.Data.SqlClient v2.1 .

// With Microsoft.Data.SqlClient v2.1


string ConnectionString1 = @"Server=demo.database.windows.net; Authentication=Active Directory Managed
Identity; User Id=ObjectIdOfManagedIdentity; Database=testdb";

using (SqlConnection conn = new SqlConnection(ConnectionString1)) {


conn.Open();
}

// With Microsoft.Data.SqlClient v2.1


string ConnectionString2 = @"Server=demo.database.windows.net; Authentication=Active Directory MSI; User
Id=ObjectIdOfManagedIdentity; Database=testdb";

using (SqlConnection conn = new SqlConnection(ConnectionString2)) {


conn.Open();
}

Using Active Directory Default authentication


This authentication mode widens the possibilities of user authentication, extending login solutions to the client
environment, Visual Studio Code, Visual Studio, Azure CLI etc.
With this authentication mode, the driver acquires a token by passing "DefaultAzureCredential" from the Azure
Identity library to acquire an access token. This mode attempts to use these credential types to acquire an access
token in the following order:
EnvironmentCredential
Enables authentication to Azure Active Directory using client and secret, or username and password,
details configured in the following environment variables: AZURE_TENANT_ID, AZURE_CLIENT_ID,
AZURE_CLIENT_SECRET, AZURE_CLIENT_CERTIFICATE_PATH, AZURE_USERNAME, AZURE_PASSWORD
(More details)
ManagedIdentityCredential
Attempts authentication to Azure Active Directory using a managed identity that has been assigned to
the deployment environment. "Client Id" of "User Assigned Managed Identity" is read from the
"User Id" connection proper ty .
SharedTokenCacheCredential
Authenticates using tokens in the local cache shared between Microsoft applications.
VisualStudioCredential
Enables authentication to Azure Active Directory using data from Visual Studio
VisualStudioCodeCredential
Enables authentication to Azure Active Directory using data from Visual Studio Code.
AzureCliCredential
Enables authentication to Azure Active Directory using Azure CLI to obtain an access token.

NOTE
InteractiveBrowserCredential is disabled in the driver implementation of "Active Directory Default", and "Active Directory
Interactive" is the only option available to acquire a token using MFA/Interactive authentication.
Further customization options are not available at the moment.

The following example shows how to use Active Director y Default authentication.

// Use your own server, database


string ConnectionString = @"Server=demo.database.windows.net; Authentication=Active Directory Default;
Database=testdb;";

using (SqlConnection conn = new SqlConnection(ConnectionString)) {


conn.Open();
}

Customizing Active Directory authentication


Besides using the Active Directory authentication built into the driver, Microsoft.Data.SqlClient 2.1.0 and later
provide applications the option to customize Active Directory authentication. The customization is based on the
ActiveDirectoryAuthenticationProvider class, which is derived from the SqlAuthenticationProvider abstract
class.
During Active Directory authentication, the client application can define its own
ActiveDirectoryAuthencationProvider class by either:

Using a customized callback method.


Passing an application client ID to the MSAL library via SqlClient driver for fetching access tokens.
The following example displays how to use a custom callback when Active Directory Device Code Flow
authentication is in use.

using System;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using Microsoft.Data.SqlClient;

namespace CustomAuthenticationProviderExamples
{
public class Program
{
public static void Main()
{
SqlAuthenticationProvider authProvider = new
ActiveDirectoryAuthenticationProvider(CustomDeviceFlowCallback);
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow,
authProvider);
using (SqlConnection sqlConnection = new SqlConnection("Server=
<myserver>.database.windows.net;Authentication=Active Directory Device Code Flow;Database=<db>;"))
{
sqlConnection.Open();
Console.WriteLine("Connected successfully!");
}
}

private static Task CustomDeviceFlowCallback(DeviceCodeResult result)


{
// Provide custom logic to process result information and read device code.
Console.WriteLine(result.Message);
return Task.FromResult(0);
}
}
}

With a customized ActiveDirectoryAuthenticationProvider class, a user-defined application client ID can be


passed to SqlClient when a supported Active Directory authentication mode is in use. Supported Active
Directory authentication modes include Active Directory Password , Active Directory Integrated ,
Active Directory Interactive , Active Directory Service Principal , and Active Directory Device Code Flow .

The application client ID is also configurable via SqlAuthenticationProviderConfigurationSection or


SqlClientAuthenticationProviderConfigurationSection . The configuration property applicationClientId applies
to .NET Framework 4.6+ and .NET Core 2.1+.
The following code snippet is an example of using a customized ActiveDirectoryAuthenticationProvider class
with a user-defined application client ID when Active Directory Interactive authentication is in use.
using System;
using Microsoft.Data.SqlClient;

namespace CustomAuthenticationProviderExamples
{
public class Program
{
public static void Main()
{
// Supported for all authentication modes supported by ActiveDirectoryAuthenticationProvider
ActiveDirectoryAuthenticationProvider provider = new ActiveDirectoryAuthenticationProvider("
<application_client_id>");
if (provider.IsSupported(SqlAuthenticationMethod.ActiveDirectoryInteractive))
{
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive,
provider);
}

using (SqlConnection sqlConnection = new SqlConnection("Server=


<myserver>.database.windows.net;Authentication=Active Directory Interactive;Database=<db>;"))
{
sqlConnection.Open();
Console.WriteLine("Connected successfully!");
}
}
}
}

The following example shows how to set an application client ID through a configuration section.

<configuration>
<configSections>
<section name="SqlClientAuthenticationProviders"
type="Microsoft.Data.SqlClient.SqlClientAuthenticationProviderConfigurationSection,
Microsoft.Data.SqlClient" />
</configSections>
<SqlClientAuthenticationProviders applicationClientId ="<GUID>" />
</configuration>

<!--or-->

<configuration>
<configSections>
<section name="SqlAuthenticationProviders"
type="Microsoft.Data.SqlClient.SqlAuthenticationProviderConfigurationSection,
Microsoft.Data.SqlClient" />
</configSections>
<SqlAuthenticationProviders applicationClientId ="<GUID>" />
</configuration>

Support for a custom SQL authentication provider


Given more flexibility, the client application can also use its own provider for Active Directory authentication
instead of using the ActiveDirectoryAuthenticationProvider class. The custom authentication provider needs to
be a subclass of SqlAuthenticationProvider with overridden methods. It then must register the custom provider,
overriding one or more of the existing Active Directory* authentication methods.
The following example shows how to use a new authentication provider for Active Directory Device Code Flow
authentication.
using System;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using Microsoft.Data.SqlClient;

namespace CustomAuthenticationProviderExamples
{
/// <summary>
/// Example demonstrating creating a custom device code flow authentication provider and attaching it to
the driver.
/// This is helpful for applications that wish to override the Callback for the Device Code Result
implemented by the SqlClient driver.
/// </summary>
public class CustomDeviceCodeFlowAzureAuthenticationProvider : SqlAuthenticationProvider
{
public override async Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters
parameters)
{
string clientId = "my-client-id";
string clientName = "My Application Name";
string s_defaultScopeSuffix = "/.default";

string[] scopes = new string[] { parameters.Resource.EndsWith(s_defaultScopeSuffix) ?


parameters.Resource : parameters.Resource + s_defaultScopeSuffix };

IPublicClientApplication app = PublicClientApplicationBuilder.Create(clientId)


.WithAuthority(parameters.Authority)
.WithClientName(clientName)
.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
.Build();

AuthenticationResult result = await app.AcquireTokenWithDeviceCode(scopes,


deviceCodeResult => CustomDeviceFlowCallback(deviceCodeResult)).ExecuteAsync();
return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn);
}

public override bool IsSupported(SqlAuthenticationMethod authenticationMethod) =>


authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow);

private Task CustomDeviceFlowCallback(DeviceCodeResult result)


{
Console.WriteLine(result.Message);
return Task.FromResult(0);
}
}

public class Program


{
public static void Main()
{
// Register our custom authentication provider class to override Active Directory Device Code
Flow
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow, new
CustomDeviceCodeFlowAzureAuthenticationProvider());
using (SqlConnection sqlConnection = new SqlConnection("Server=
<myserver>.database.windows.net;Authentication=Active Directory Device Code Flow;Database=<db>;"))
{
sqlConnection.Open();
Console.WriteLine("Connected successfully!");
}
}
}
}

In addition to improving the Active Directory Interactive authentication experience,


Microsoft.Data.SqlClient 2.1.0 and later provide the following APIs for client applications to customize
interactive authentication and device code flow authentication.

public class ActiveDirectoryAuthenticationProvider


{
// For .NET Framework targeted applications only
// Sets a reference to the current System.Windows.Forms.IWin32Window that triggers the browser to be
shown.
// Used to center the browser pop-up onto this window.
public void SetIWin32WindowFunc(Func<IWin32Window> iWin32WindowFunc);

// For .NET Standard targeted applications only


// Sets a reference to the ViewController (if using Xamarin.iOS), Activity (if using Xamarin.Android)
IWin32Window, or IntPtr (if using .NET Framework).
// Used for invoking the browser for Active Directory Interactive authentication.
public void SetParentActivityOrWindowFunc(Func<object> parentActivityOrWindowFunc);

// For .NET Framework, .NET Core, and .NET Standard targeted applications
// Sets a callback method that's invoked with a custom web UI instance that will let the user sign in
with Azure AD, present consent if needed, and get back the authorization code.
// Applicable when working with Active Directory Interactive authentication.
public void SetAcquireAuthorizationCodeAsyncCallback(Func<Uri, Uri, CancellationToken, Task<Uri>>
acquireAuthorizationCodeAsyncCallback);

// For .NET Framework, .NET Core, and .NET Standard targeted applications
// Clears cached user tokens from the token provider.
public static void ClearUserTokenCache();
}

See also
Application and service principal objects in Azure Active Directory
Authentication flows
Application security scenarios in SQL Server
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
There is no single correct way to create a secure SQL Server client application. Every application is unique in its
requirements, deployment environment, and user population. An application that is reasonably secure when it is
initially deployed can become less secure over time. It is impossible to predict with any accuracy what threats
may emerge in the future.
SQL Server, as a product, has evolved over many versions to incorporate the latest security features that enable
developers to create secure database applications. However, security doesn't come in the box; it requires
continual monitoring and updating.

Common threats
Developers need to understand security threats, the tools provided to counter them, and how to avoid self-
inflicted security holes. Security can best be thought of as a chain, where a break in any one link compromises
the strength of the whole. The following list includes some common security threats that are discussed in more
detail in the topics in this section.
SQL injection
SQL Injection is the process by which a malicious user enters Transact-SQL statements instead of valid input. If
the input is passed directly to the server without being validated and if the application inadvertently executes
the injected code, then the attack has the potential to damage or destroy data. You can thwart SQL Server
injection attacks by using stored procedures and parameterized commands, avoiding dynamic SQL, and
restricting permissions on all users.
Elevation of privilege
Elevation of privilege attacks occur when a user is able to assume the privileges of a trusted account, such as an
owner or administrator. Always run under least-privileged user accounts and assign only needed permissions.
Avoid using administrative or owner accounts for executing code. This limits the amount of damage that can
occur if an attack succeeds. When performing tasks that require additional permissions, use procedure signing
or impersonation only for the duration of the task. You can sign stored procedures with certificates or use
impersonation to temporarily assign permissions.
Probing and intelligent observation
A probing attack can use error messages generated by an application to search for security vulnerabilities.
Implement error handling in all procedural code to prevent SQL Server error information from being returned
to the end user.
Authentication
A connection string injection attack can occur when using SQL Server logins if a connection string based on user
input is constructed at run time. If the connection string is not checked for valid keyword pairs, an attacker can
insert extra characters, potentially accessing sensitive data or other resources on the server. Use Windows
authentication wherever possible. If you must use SQL Server logins, use the SqlConnectionStringBuilder to
create and validate connection strings at run time.
Passwords
Many attacks succeed because an intruder was able to obtain or guess a password for a privileged user.
Passwords are your first line of defense against intruders, so setting strong passwords is essential to the security
of your system. Create and enforce password policies for mixed mode authentication.
Always assign a strong password to the sa account, even when using Windows Authentication.

In this section
Writing secure dynamic SQL in SQL Server
Describes techniques for writing secure dynamic SQL using stored procedures.

Next steps
SQL Server security
Writing secure dynamic SQL in SQL Server
4/27/2022 • 3 minutes to read • Edit Online

Download ADO.NET
SQL Injection is the process by which a malicious user enters Transact-SQL statements instead of valid input. If
the input is passed directly to the server without being validated and if the application inadvertently executes
the injected code, the attack has the potential to damage or destroy data.
Any procedure that constructs SQL statements should be reviewed for injection vulnerabilities because SQL
Server will execute all syntactically valid queries that it receives. Even parameterized data can be manipulated by
a skilled and determined attacker. If you use dynamic SQL, be sure to parameterize your commands, and never
include parameter values directly into the query string.

Anatomy of a SQL injection attack


The injection process works by prematurely terminating a text string and appending a new command. Because
the inserted command may have additional strings appended to it before it is executed, the malefactor
terminates the injected string with a comment mark "--". Subsequent text is ignored at execution time. Multiple
commands can be inserted using a semicolon (;) delimiter.
As long as injected SQL code is syntactically correct, tampering cannot be detected programmatically. Therefore,
you must validate all user input and carefully review code that executes constructed SQL commands in the
server that you are using. Never concatenate user input that is not validated. String concatenation is the primary
point of entry for script injection.
Here are some helpful guidelines:
Never build Transact-SQL statements directly from user input; use stored procedures to validate user
input.
Validate user input by testing type, length, format, and range. Use the Transact-SQL QUOTENAME()
function to escape system names or the REPLACE() function to escape any character in a string.
Implement multiple layers of validation in each tier of your application.
Test the size and data type of input and enforce appropriate limits. This can help prevent deliberate buffer
overruns.
Test the content of string variables and accept only expected values. Reject entries that contain binary
data, escape sequences, and comment characters.
When you are working with XML documents, validate all data against its schema as it is entered.
In multi-tiered environments, all data should be validated before admission to the trusted zone.
Do not accept the following strings in fields from which file names can be constructed: AUX, CLOCK$,
COM1 through COM8, CON, CONFIG$, LPT1 through LPT8, NUL, and PRN.
Use SqlParameter objects with stored procedures and commands to provide type checking and length
validation.
Use Regex expressions in client code to filter invalid characters.
Dynamic SQL strategies
Executing dynamically created SQL statements in your procedural code breaks the ownership chain, causing
SQL Server to check the permissions of the caller against the objects being accessed by the dynamic SQL.
SQL Server has methods for granting users access to data using stored procedures and user-defined functions
that execute dynamic SQL.
Using impersonation with the Transact-SQL EXECUTE AS clause.
Signing stored procedures with certificates.
EXECUTE AS
The EXECUTE AS clause replaces the permissions of the caller with that of the user specified in the EXECUTE AS
clause. Nested stored procedures or triggers execute under the security context of the proxy user. This can break
applications that rely on row-level security or require auditing. Some functions that return the identity of the
user return the user specified in the EXECUTE AS clause, not the original caller. Execution context is reverted to
the original caller only after execution of the procedure or when a REVERT statement is issued.
Certificate signing
When a stored procedure that has been signed with a certificate executes, the permissions granted to the
certificate user are merged with those of the caller. The execution context remains the same; the certificate user
does not impersonate the caller. Signing stored procedures requires several steps to implement. Each time the
procedure is modified, it must be re-signed.
Cross database access
Cross-database ownership chaining does not work in cases where dynamically created SQL statements are
executed. You can work around this in SQL Server by creating a stored procedure that accesses data in another
database and signing the procedure with a certificate that exists in both databases. This gives users access to the
database resources used by the procedure without granting them database access or permissions.

External resources
For more information, see the following resources.

RESO URC E DESC RIP T IO N

Stored Procedures and SQL Injection in SQL Server Books Topics describe how to create stored procedures and how
Online SQL Injection works.

Next steps
Application security scenarios in SQL Server
SQL Server Express security
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Microsoft SQL Server Express Edition (SQL Server Express) is based on Microsoft SQL Server, and supports
most of the features of the database engine. It is designed so that nonessential features and network
connectivity are off by default. This reduces the surface area available for attack by a malicious user.
SQL Server Express is usually installed as a named instance. The default name of the instance is SQLExpress . A
named instance is identified by the network name of the computer plus the instance name that you specify
during installation.

Network access
For security reasons, networking protocols are disabled by default in SQL Server Express. This prevents attacks
from outside users that might compromise the computer that hosts the instance of SQL Server Express. You
must explicitly enable network connectivity and start the SQL Server Browser service to connect to a SQL Server
Express instance from another computer.
Once network connectivity is enabled, a SQL Server Express instance has the same security requirements as the
other editions of SQL Server.

User instances
A user instance is a separate instance of the SQL Server Express database engine that is generated by a parent
instance of SQL Server Express. The primary goal of a user instance is to allow users who are running Windows
under a least-privilege user account to have system administrator ( sysadmin ) privileges on the SQL Server
Express instance on their local computer. User instances are not intended for users who are system
administrators on their own computers.
A user instance is generated from a primary instance of SQL Server or SQL Server Express on behalf of a user. It
runs as a user process under the Windows security context of the user, not as a service. SQL Server logins are
disallowed; only Windows logins are supported. This prevents software executing on a user instance from
making system-wide changes that the user would not have permissions to make. A user instance is also known
as a child or client instance, and is sometimes referred to by using the RANU acronym ("run as normal user").
Each user instance is isolated from its parent instance and from other user instances running on the same
computer. Databases installed on user instances are opened in single-user mode only; multiple users cannot
connect to them. Replication, distributed queries and remote connections are disabled for user instances. When
connected to a user instance, users do not have any special privileges on the parent SQL Server Express
instance.

External resources
For more information about SQL Server Express, see the following resources.

RESO URC E DESC RIP T IO N

Microsoft SQL Server 2005 Express Edition Books Online Complete documentation for SQL Server 2005 Express
Edition.
RESO URC E DESC RIP T IO N

User Instances for Non-Administrators in SQL Server Books Describes how to create and deploy user instances.
Online

SQL Server Express user instances Describes user instance capabilities in an ADO.NET
application. Provides information about how to enable a user
instance, connect to a user instance using a SqlConnection,
user instance lifetime, and user instance scenarios.

Next steps
SQL Server security
SQL Server Express user instances
SQL Server data types and ADO.NET
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
SQL Server and the .NET are based on different type systems, which can result in potential data loss. To preserve
data integrity, the Microsoft SqlClient Data Provider for SQL Server (Microsoft.Data.SqlClient) provides typed
accessor methods for working with SQL Server data. You can use the enumerations in the SqlDbType classes to
specify SqlParameter data types.
SQL Server 2008 introduces new data types that are designed to meet business needs to work with date and
time, structured, semi-structured, and unstructured data. These are documented in SQL Server 2008 Books
Online.
The SQL Server data types that are available for use in your application depends on the version of SQL Server
that you are using. For more information, see Data Types (Database Engine) from SQL Server Books Online.

In this section
SqlTypes and the DataSet
Describes type support for SqlTypes in the DataSet .
Handling null values
Demonstrates how to work with null values and three-valued logic.
Comparing GUID and uniqueidentifier values
Demonstrates how to work with GUID and uniqueidentifier values in SQL Server and .NET.
Date and time data
Describes how to use the new date and time data types introduced in SQL Server 2008.
Large UDTs
Demonstrates how to retrieve data from large value UDTs introduced in SQL Server 2008.
XML data in SQL Server
Describes how to work with XML data retrieved from SQL Server.

Reference
DataSet
Describes the DataSet class and all of its members.
System.Data.SqlTypes
Describes the SqlTypes namespace and all of its members.
SqlDbType
Describes the SqlDbType enumeration and all of its members.
DbType
Describes the DbType enumeration and all of its members.

Next steps
Table-valued parameters
SQL Server binary and large-value data
SqlTypes and the DataSet
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
ADO.NET 2.0 introduced enhanced type support for the DataSet through the System.Data.SqlTypes namespace.
The types in System.Data.SqlTypes are designed to provide data types with the same semantics and precision as
the data types in a SQL Server database. Each data type in System.Data.SqlTypes has an equivalent data type in
SQL Server, with the same underlying data representation.
Using System.Data.SqlTypes directly in a DataSet confers several benefits when working with SQL Server data
types. System.Data.SqlTypes supports the same semantics as SQL Server native data types. Specifying one of
the System.Data.SqlTypes in the definition of a DataColumn eliminates the loss of precision that can occur when
converting decimal or numeric data types to one of the common language runtime (CLR) data types.
The following example creates a DataTable object, explicitly defining the DataColumn data types by using
System.Data.SqlTypes instead of CLR types. The code fills the DataTable with data from the
Sales.SalesOrderDetail table in the AdventureWorks database in SQL Server. The output displayed in the console
window shows the data type of each column, and the values retrieved from SQL Server.

using Microsoft.Data.SqlClient;
using System.Data.SqlTypes;

class Program
{
static void Main()
{
string connectionString = GetConnectionString();
GetSqlTypesAW(connectionString);
Console.ReadLine();
}
static private void GetSqlTypesAW(string connectionString)
{
// Create a DataTable and specify a SqlType
// for each column.
DataTable table = new DataTable();
DataColumn icolumnolumn =
table.Columns.Add("SalesOrderID", typeof(SqlInt32));
DataColumn priceColumn =
table.Columns.Add("UnitPrice", typeof(SqlMoney));
DataColumn totalColumn =
table.Columns.Add("LineTotal", typeof(SqlDecimal));
DataColumn columnModifiedDate =
table.Columns.Add("ModifiedDate", typeof(SqlDateTime));

// Open a connection to SQL Server and fill the DataTable


// with data from the Sales.SalesOrderDetail table
// in the AdventureWorks sample database.
using (SqlConnection connection = new SqlConnection(connectionString))
{
string queryString =
"SELECT TOP 5 SalesOrderID, UnitPrice, LineTotal, ModifiedDate "
+ "FROM Sales.SalesOrderDetail WHERE LineTotal < @LineTotal";

// Create the SqlCommand.


SqlCommand command = new SqlCommand(queryString, connection);

// Create the SqlParameter and assign a value.


SqlParameter parameter =
SqlParameter parameter =
new SqlParameter("@LineTotal", SqlDbType.Decimal);
parameter.Value = 1.5;
command.Parameters.Add(parameter);

// Open the connection and load the data.


connection.Open();
SqlDataReader reader =
command.ExecuteReader(CommandBehavior.CloseConnection);
table.Load(reader);

// Close the SqlDataReader.


reader.Close();
}

// Display the SqlType of each column.


Console.WriteLine("Data Types:");
foreach (DataColumn column in table.Columns)
{
Console.WriteLine(" {0} -- {1}",
column.ColumnName, column.DataType.UnderlyingSystemType);
}

// Display the value for each row.


Console.WriteLine("Values:");
foreach (DataRow row in table.Rows)
{
Console.Write(" {0}, ", row["SalesOrderID"]);
Console.Write(" {0}, ", row["UnitPrice"]);
Console.Write(" {0}, ", row["LineTotal"]);
Console.Write(" {0} ", row["ModifiedDate"]);
Console.WriteLine();
}
}

static private string GetConnectionString()


{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file, using the
// System.Configuration.ConfigurationSettings.AppSettings property
return "Data Source=(local);Initial Catalog=AdventureWorks;"
+ "Integrated Security=SSPI;";
}
}
Handling null values
4/27/2022 • 8 minutes to read • Edit Online

Download ADO.NET
A null value in a relational database is used when the value in a column is unknown or missing. A null is neither
an empty string (for character or datetime data types) nor a zero value (for numeric data types). The ANSI SQL-
92 specification states that a null must be the same for all data types, so that all nulls are handled consistently.
The System.Data.SqlTypes namespace provides null semantics by implementing the INullable interface. Each of
the data types in System.Data.SqlTypes has its own IsNull property and a Null value that can be assigned to
an instance of that data type.

NOTE
The .NET Framework version 2.0 and .NET Core version 1.0 introduced support for nullable types, which allow
programmers to extend a value type to represent all values of the underlying type. These CLR nullable types represent an
instance of the Nullable structure. This capability is especially useful when value types are boxed and unboxed, providing
enhanced compatibility with object types. CLR nullable types are not intended for storage of database nulls because an
ANSI SQL null does not behave the same way as a null reference (or Nothing in Visual Basic). For working with
database ANSI SQL null values, use System.Data.SqlTypes nulls rather than Nullable. For more information on working
with CLR nullable types in C# see Nullable Types, and for C# see Using Nullable Types.

Nulls and three-valued logic


Allowing null values in column definitions introduces three-valued logic into your application. A comparison can
evaluate to one of three conditions:
True
False
Unknown
Because null is considered to be unknown, two null values compared to each other are not considered to be
equal. In expressions using arithmetic operators, if any of the operands is null, the result is null as well.

Nulls and SqlBoolean


Comparison between any System.Data.SqlTypes will return a SqlBoolean. The IsNull function for each
SqlType returns a SqlBoolean and can be used to check for null values. The following truth tables show how the
AND, OR, and NOT operators function in the presence of a null value. (T=true, F=false, and U=unknown, or null.)
Understanding the ANSI_NULLS option
System.Data.SqlTypes provides the same semantics as when the ANSI_NULLS option is set on in SQL Server. All
arithmetic operators (+, -, *, /, %), bitwise operators (~, &, |), and most functions return null if any of the
operands or arguments is null, except for the property IsNull .
The ANSI SQL-92 standard does not support columnName = NULL in a WHERE clause. In SQL Server, the
ANSI_NULLS option controls both default nullability in the database and evaluation of comparisons against null
values. If ANSI_NULLS is turned on (the default), the IS NULL operator must be used in expressions when testing
for null values. For example, the following comparison always yields unknown when ANSI_NULLS is on:

colname > NULL

Comparison to a variable containing a null value also yields unknown:

colname > @MyVariable

Use the IS NULL or IS NOT NULL predicate to test for a null value. This can add complexity to the WHERE clause.
For example, the TerritoryID column in the AdventureWorks Customer table allows null values. If a SELECT
statement is to test for null values in addition to others, it must include an IS NULL predicate:

SELECT CustomerID, AccountNumber, TerritoryID


FROM AdventureWorks.Sales.Customer
WHERE TerritoryID IN (1, 2, 3)
OR TerritoryID IS NULL

If you set ANSI_NULLS off in SQL Server, you can create expressions that use the equality operator to compare
to null. However, you can't prevent different connections from setting null options for that connection. Using IS
NULL to test for null values always works, regardless of the ANSI_NULLS settings for a connection.
Setting ANSI_NULLS off is not supported in a DataSet , which always follows the ANSI SQL-92 standard for
handling null values in System.Data.SqlTypes.

Assigning null values


Null values are special, and their storage and assignment semantics differ across different type systems and
storage systems. A Dataset is designed to be used with different type and storage systems.
This section describes the null semantics for assigning null values to a DataColumn in a DataRow across the
different type systems.
DBNull.Value
This assignment is valid for a DataColumn of any type. If the type implements INullable , DBNull.Value is
coerced into the appropriate strongly typed Null value.
SqlType.Null
All System.Data.SqlTypes data types implement INullable . If the strongly typed null value can be converted
into the column's data type using implicit cast operators, the assignment should go through. Otherwise an
invalid cast exception is thrown.
null
If 'null' is a legal value for the given DataColumn data type, it is coerced into the appropriate DbNull.Value or
Null associated with the INullable type ( SqlType.Null )

derivedUdt.Null
For UDT columns, nulls are always stored based on the type associated with the DataColumn . Consider the case
of a UDT associated with a DataColumn that does not implement INullable while its sub-class does. In this case,
if a strongly typed null value associated with the derived class is assigned, it is stored as an untyped
DbNull.Value , because null storage is always consistent with the DataColumn's data type.

NOTE
The Nullable<T> or Nullable structure is not currently supported in the DataSet .

Multiple column (row) assignment


DataTable.Add , DataTable.LoadDataRow , or other APIs that accept an ItemArray that gets mapped to a row, map
'null' to the DataColumn's default value. If an object in the array contains DbNull.Value or its strongly typed
counterpart, the same rules as described above are applied.
In addition, the following rules apply for an instance of DataRow.["columnName"] null assignments:
The default default value is DbNull.Value for all except the strongly typed null columns where it is the
appropriate strongly typed null value.
Null values are never written out during serialization to XML files (as in "xsi:nil").
All non-null values, including defaults, are always written out while serializing to XML. This is unlike
XSD/XML semantics where a null value (xsi:nil) is explicit and the default value is implicit (if not present in
XML, a validating parser can get it from an associated XSD schema). The opposite is true for a DataTable :
a null value is implicit and the default value is explicit.
All missing column values for rows read from XML input are assigned NULL. Rows created using
NewRow or similar methods are assigned the DataColumn's default value.
The IsNull method returns true for both DbNull.Value and INullable.Null .

Assigning null values to SqlTypes


The default value for any System.Data.SqlTypes instance is null.
Nulls in System.Data.SqlTypes are type-specific and cannot be represented by a single value, such as DbNull .
Use the IsNull property to check for nulls.
Null values can be assigned to a DataColumn as shown in the following code example. You can directly assign
null values to SqlTypes variables without triggering an exception.
Example
The following code example creates a DataTable with two columns defined as SqlInt32 and SqlString. The code
adds one row of known values, one row of null values and then iterates through the DataTable, assigning the
values to variables and displaying the output in the console window.

using Microsoft.Data.SqlClient;
using System.Data.SqlTypes;

class Program
{
static void Main()
{
WorkWithSqlNulls();
Console.ReadLine();
}
static private void WorkWithSqlNulls()
{
DataTable table = new DataTable();

// Specify the SqlType for each column.


DataColumn idColumn =
table.Columns.Add("ID", typeof(SqlInt32));
DataColumn descColumn =
table.Columns.Add("Description", typeof(SqlString));

// Add some data.


DataRow nRow = table.NewRow();
nRow["ID"] = 123;
nRow["Description"] = "Side Mirror";
table.Rows.Add(nRow);

// Add null values.


nRow = table.NewRow();
nRow["ID"] = SqlInt32.Null;
nRow["Description"] = SqlString.Null;
table.Rows.Add(nRow);

// Initialize variables to use when


// extracting the data.
SqlBoolean isColumnNull = false;
SqlInt32 idValue = SqlInt32.Zero;
SqlString descriptionValue = SqlString.Null;

// Iterate through the DataTable and display the values.


foreach (DataRow row in table.Rows)
{
// Assign values to variables. Note that you
// do not have to test for null values.
idValue = (SqlInt32)row["ID"];
descriptionValue = (SqlString)row["Description"];

// Test for null value in ID column.


isColumnNull = idValue.IsNull;

// Display variable values in console window.


Console.Write("isColumnNull={0}, ID={1}, Description={2}",
isColumnNull, idValue, descriptionValue);
Console.WriteLine();
}
}
}

This example displays the following results:


isColumnNull=False, ID=123, Description=Side Mirror
isColumnNull=True, ID=Null, Description=Null

Comparing null values with SqlTypes and CLR types


When comparing null values, it is important to understand the difference between the way the Equals method
evaluates null values in System.Data.SqlTypes as compared with the way it works with CLR types. All of the
System.Data.SqlTypes Equals methods use database semantics for evaluating null values: if either or both of the
values is null, the comparison yields null. On the other hand, using the CLR Equals method on two
System.Data.SqlTypes will yield true if both are null. This reflects the difference between using an instance
method such as the CLR String.Equals method, and using the static/shared method, SqlString.Equals .
The following example demonstrates the difference in results between the SqlString.Equals method and the
String.Equals method when each is passed a pair of null values and then a pair of empty strings.
using System.Data.SqlTypes;

namespace SqlNullsCS
{
class Program
{
static void Main()
{
CompareNulls();
Console.ReadLine();
}
private static void CompareNulls()
{
// Create two new null strings.
SqlString a = new SqlString();
SqlString b = new SqlString();

// Compare nulls using static/shared SqlString.Equals.


Console.WriteLine("SqlString.Equals shared/static method:");
Console.WriteLine(" Two nulls={0}", SqlStringEquals(a, b));

// Compare nulls using instance method String.Equals.


Console.WriteLine();
Console.WriteLine("String.Equals instance method:");
Console.WriteLine(" Two nulls={0}", StringEquals(a, b));

// Make them empty strings.


a = "";
b = "";

// When comparing two empty strings (""), both the shared/static and
// the instance Equals methods evaluate to true.
Console.WriteLine();
Console.WriteLine("SqlString.Equals shared/static method:");
Console.WriteLine(" Two empty strings={0}", SqlStringEquals(a, b));

Console.WriteLine();
Console.WriteLine("String.Equals instance method:");
Console.WriteLine(" Two empty strings={0}", StringEquals(a, b));
}

private static string SqlStringEquals(SqlString string1, SqlString string2)


{
// SqlString.Equals uses database semantics for evaluating nulls.
string returnValue = SqlString.Equals(string1, string2).ToString();
return returnValue;
}

private static string StringEquals(SqlString string1, SqlString string2)


{
// String.Equals uses CLR type semantics for evaluating nulls.
string returnValue = string1.Equals(string2).ToString();
return returnValue;
}
}
}

The code produces the following output:


SqlString.Equals shared/static method:
Two nulls=Null

String.Equals instance method:


Two nulls=True

SqlString.Equals shared/static method:


Two empty strings=True

String.Equals instance method:


Two empty strings=True

Next steps
SQL Server data types and ADO.NET
Comparing GUID and uniqueidentifier values
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
The globally unique identifier (GUID) data type in SQL Server is represented by the uniqueidentifier data type,
which stores a 16-byte binary value. A GUID is a binary number, and its main use is as an identifier that must be
unique in a network that has many computers at many sites. GUIDs can be generated by calling the Transact-
SQL NEWID function, and is guaranteed to be unique throughout the world. For more information, see
uniqueidentifier (Transact-SQL).

Working with SqlGuid values


Because GUIDs values are long and obscure, they are not meaningful for users. If randomly generated GUIDs are
used for key values and you insert a lot of rows, you get random I/O into your indexes, which can negatively
impact performance. GUIDs are also relatively large when compared to other data types. In general we
recommend using GUIDs only for very narrow scenarios for which no other data type is suitable.
Comparing GUID values
Comparison operators can be used with uniqueidentifier values. However, ordering is not implemented by
comparing the bit patterns of the two values. The only operations that are allowed against a uniqueidentifier
value are comparisons (=, <>, <, >, <=, >=) and checking for NULL (IS NULL and IS NOT NULL). No other
arithmetic operators are allowed.
Both Guid and SqlGuid have a CompareTo method for comparing different GUID values. However,
System.Guid.CompareTo and SqlTypes.SqlGuid.CompareTo are implemented differently. SqlGuid implements
CompareTo using SQL Server behavior, in the last six bytes of a value are most significant. Guid evaluates all 16
bytes. The following example demonstrates this behavioral difference. The first section of code displays
unsorted Guid values, and the second section of code shows the sorted Guid values. The third section shows the
sorted SqlGuid values. The output is displayed beneath the code listing.
using System.Data.SqlTypes;
using System.Collections;

class Program
{
static void Main()
{
WorkWithGuids();
Console.ReadLine();
}
private static void WorkWithGuids()
{
// Create an ArrayList and fill it with Guid values.
ArrayList guidList = new ArrayList();
guidList.Add(new Guid("3AAAAAAA-BBBB-CCCC-DDDD-2EEEEEEEEEEE"));
guidList.Add(new Guid("2AAAAAAA-BBBB-CCCC-DDDD-1EEEEEEEEEEE"));
guidList.Add(new Guid("1AAAAAAA-BBBB-CCCC-DDDD-3EEEEEEEEEEE"));

// Display the unsorted Guid values.


Console.WriteLine("Unsorted Guids:");
foreach (Guid guidValue in guidList)
{
Console.WriteLine(" {0}", guidValue);
}
Console.WriteLine("");

// Sort the Guids.


guidList.Sort();

// Display the sorted Guid values.


Console.WriteLine("Sorted Guids:");
foreach (Guid guidSorted in guidList)
{
Console.WriteLine(" {0}", guidSorted);
}
Console.WriteLine("");

// Create an ArrayList of SqlGuids.


ArrayList sqlGuidList = new ArrayList();
sqlGuidList.Add(new SqlGuid("3AAAAAAA-BBBB-CCCC-DDDD-2EEEEEEEEEEE"));
sqlGuidList.Add(new SqlGuid("2AAAAAAA-BBBB-CCCC-DDDD-1EEEEEEEEEEE"));
sqlGuidList.Add(new SqlGuid("1AAAAAAA-BBBB-CCCC-DDDD-3EEEEEEEEEEE"));

// Sort the SqlGuids. The unsorted SqlGuids are in the same order
// as the unsorted Guid values.
sqlGuidList.Sort();

// Display the sorted SqlGuids. The sorted SqlGuid values are ordered
// differently than the Guid values.
Console.WriteLine("Sorted SqlGuids:");
foreach (SqlGuid sqlGuidValue in sqlGuidList)
{
Console.WriteLine(" {0}", sqlGuidValue);
}
}
}

This example produces the following results.


Unsorted Guids:
3aaaaaaa-bbbb-cccc-dddd-2eeeeeeeeeee
2aaaaaaa-bbbb-cccc-dddd-1eeeeeeeeeee
1aaaaaaa-bbbb-cccc-dddd-3eeeeeeeeeee

Sorted Guids:
1aaaaaaa-bbbb-cccc-dddd-3eeeeeeeeeee
2aaaaaaa-bbbb-cccc-dddd-1eeeeeeeeeee
3aaaaaaa-bbbb-cccc-dddd-2eeeeeeeeeee

Sorted SqlGuids:
2aaaaaaa-bbbb-cccc-dddd-1eeeeeeeeeee
3aaaaaaa-bbbb-cccc-dddd-2eeeeeeeeeee
1aaaaaaa-bbbb-cccc-dddd-3eeeeeeeeeee

Next steps
SQL Server data types and ADO.NET
Date and time data
4/27/2022 • 9 minutes to read • Edit Online

Download ADO.NET
SQL Server 2008 introduces new data types for handling date and time information. The new data types include
separate types for date and time, and expanded data types with greater range, precision, and time-zone
awareness. The Microsoft SqlClient Data Provider for SQL Server (Microsoft.Data.SqlClient) provides full
support for all the new features of the SQL Server 2008 Database Engine. You must install the .NET Framework
3.5 SP1 (or later) or .NET Core 1.0 (or later) to use these new features with SqlClient.
Versions of SQL Server earlier than SQL Server 2008 only had two data types for working with date and time
values: datetime and smalldatetime . Both of these data types contain both the date value and a time value,
which makes it difficult to work with only date or only time values. Also, these data types only support dates that
occur after the introduction of the Gregorian calendar in England in 1753. Another limitation is that these older
data types are not time-zone aware, which makes it difficult to work with data that originates from multiple time
zones.
Complete documentation for SQL Server data types is available in SQL Server Books Online. See Using Date
and Time Data for entry-level topics on date and time data.

Date/Time data types introduced in SQL Server 2008


The following table describes the new date and time data types.

SQ L SERVER DATA T Y P E DESC RIP T IO N

date The date data type has a range of January 1, 01 through


December 31, 9999 with an accuracy of 1 day. The default
value is January 1, 1900. The storage size is 3 bytes.

time The time data type stores time values only, based on a 24-
hour clock. The time data type has a range of
00:00:00.0000000 through 23:59:59.9999999 with an
accuracy of 100 nanoseconds. The default value is
00:00:00.0000000 (midnight). The time data type
supports user-defined fractional second precision, and the
storage size varies from 3 to 6 bytes, based on the precision
specified.

datetime2 The datetime2 data type combines the range and


precision of the date and time data types into a single
data type.

The default values and string literal formats are the same as
those defined in the date and time data types.
SQ L SERVER DATA T Y P E DESC RIP T IO N

datetimeoffset The datetimeoffset data type has all the features of


datetime2 with an additional time zone offset. The time
zone offset is represented as [+|-] HH:MM. HH is 2 digits
ranging from 00 to 14 that represent the number of hours
in the time zone offset. MM is 2 digits ranging from 00 to
59 that represent the number of additional minutes in the
time zone offset. Time formats are supported to 100
nanoseconds. The mandatory + or - sign indicates whether
the time zone offset is added or subtracted from UTC
(Universal Time Coordinate or Greenwich Mean Time) to
obtain the local time.

NOTE
For more information about using the Type System Version keyword, see ConnectionString.

Date format and date order


How SQL Server parses date and time values depends not only on the type system version and server version,
but also on the server's default language and format settings. A date string that works for the date formats of
one language might be unrecognizable if the query is executed by a connection that uses a different language
and date format setting.
The Transact-SQL SET LANGUAGE statement implicitly sets the DATEFORMAT that determines the order of the
date parts. You can use the SET DATEFORMAT Transact-SQL statement on a connection to disambiguate date
values by ordering the date parts in MDY, DMY, YMD, YDM, MYD, or DYM order.
If you do not specify any DATEFORMAT for the connection, SQL Server uses the default language associated
with the connection. For example, a date string of '01/02/03' would be interpreted as MDY (January 2, 2003) on
a server with a language setting of United States English, and as DMY (February 1, 2003) on a server with a
language setting of British English. The year is determined by using SQL Server's cutoff year rule, which defines
the cutoff date for assigning the century value. For more information, see two digit year cutoff Option in SQL
Server Books Online.

NOTE
The YDM date format is not supported when converting from a string format to date , time , datetime2 , or
datetimeoffset .

For more information about how SQL Server interprets date and time data, see Using Date and Time Data in
SQL Server 2008 Books Online.

Date/Time data types and parameters


The following enumerations have been added to SqlDbType to support the new date and time data types.
SqlDbType.Date

SqlDbType.Time

SqlDbType.DateTime2

SqlDbType.DateTimeOffSet
You can specify the data type of a SqlParameter by using one of the preceding SqlDbType enumerations.

NOTE
You cannot set the DbType property of a SqlParameter to SqlDbType.Date .

You can also specify the type of a SqlParameter generically by setting the DbType property of a SqlParameter
object to a particular DbType enumeration value. The following enumeration values have been added to DbType
to support the datetime2 and datetimeoffset data types:
DbType.DateTime2
DbType.DateTimeOffset
These new enumerations supplement the Date , Time , and DateTime enumerations.
The Microsoft SqlClient Data Provider type of a parameter object is inferred from the .NET type of the value of
the parameter object, or from the DbType of the parameter object. No new System.Data.SqlTypes data types
have been introduced to support the new date and time data types. The following table describes the mappings
between the SQL Server 2008 date and time data types and the CLR data types.

SQ L SERVER DATA T Y P E . N ET T Y P E SY ST EM . DATA . SQ L DBT Y P E SY ST EM . DATA . DBT Y P E

date System.DateTime Date Date

time System.TimeSpan Time Time

datetime2 System.DateTime DateTime2 DateTime2

datetimeoffset System.DateTimeOffset DateTimeOffset DateTimeOffset

datetime System.DateTime DateTime DateTime

smalldatetime System.DateTime DateTime DateTime

SqlParameter properties
The following table describes SqlParameter properties that are relevant to date and time data types.

P RO P ERT Y DESC RIP T IO N

IsNullable Gets or sets whether a value is nullable. When you send a


null parameter value to the server, you must specify DBNull,
rather than null ( Nothing in Visual Basic). For more
information about database nulls, see Handling null values.

Precision Gets or sets the maximum number of digits used to


represent the value. This setting is ignored for date and time
data types.

Scale Gets or sets the number of decimal places to which the time
portion of the value is resolved for Time , DateTime2 ,and
DateTimeOffset . The default value is 0, which means that
the actual scale is inferred from the value and sent to the
server.
P RO P ERT Y DESC RIP T IO N

Size Ignored for date and time data types.

Value Gets or sets the parameter value.

SqlValue Gets or sets the parameter value.

NOTE
Time values that are less than zero or greater than or equal to 24 hours will throw an ArgumentException.

Creating parameters
You can create a SqlParameter object by using its constructor, or by adding it to a SqlCommand.Parameters
collection by calling the Add method of the SqlParameterCollection. The Add method will take as input either
constructor arguments or an existing parameter object.
The next sections in this topic provide examples of how to specify date and time parameters.
Date example
The following code fragment demonstrates how to specify a date parameter.

SqlParameter parameter = new SqlParameter();


parameter.ParameterName = "@Date";
parameter.SqlDbType = SqlDbType.Date;
parameter.Value = "2007/12/1";

Time example
The following code fragment demonstrates how to specify a time parameter.

SqlParameter parameter = new SqlParameter();


parameter.ParameterName = "@time";
parameter.SqlDbType = SqlDbType.Time;
parameter.Value = DateTime.Parse("23:59:59").TimeOfDay;

Datetime2 example
The following code fragment demonstrates how to specify a datetime2 parameter with both the date and time
parts.

SqlParameter parameter = new SqlParameter();


parameter.ParameterName = "@Datetime2";
parameter.SqlDbType = SqlDbType.DateTime2;
parameter.Value = DateTime.Parse("1666-09-02 1:00:00");

DateTimeOffSet example
The following code fragment demonstrates how to specify a DateTimeOffSet parameter with a date, a time, and
a time zone offset of 0.
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@DateTimeOffSet";
parameter.SqlDbType = SqlDbType.DateTimeOffSet;
parameter.Value = DateTimeOffset.Parse("1666-09-02 1:00:00+0");

AddWithValue
You can also supply parameters by using the AddWithValue method of a SqlCommand, as shown in the
following code fragment. However, the AddWithValue method does not allow you to specify the DbType or
SqlDbType for the parameter.

command.Parameters.AddWithValue(
"@date", DateTimeOffset.Parse("16660902"));

The @date parameter could map to a date , datetime , or datetime2 data type on the server. When working
with the new datetime data types, you must explicitly set the parameter's SqlDbType property to the data type
of the instance. Using Variant or implicitly supplying parameter values can cause problems with backward
compatibility with the datetime and smalldatetime data types.
The following table shows which SqlDbTypes are inferred from which CLR types:

CLR TYPE IN F ERRED SQ L DBT Y P E

DateTime SqlDbType.DateTime

TimeSpan SqlDbType.Time

DateTimeOffset SqlDbType.DateTimeOffset

Retrieving date and time data


The following table describes methods that are used to retrieve SQL Server 2008 date and time values.

SQ L C L IEN T M ET H O D DESC RIP T IO N

GetDateTime Retrieves the specified column value as a DateTime structure.

GetDateTimeOffset Retrieves the specified column value as a DateTimeOffset


structure.

GetProviderSpecificFieldType Returns the type that is the underlying provider-specific type


for the field. Returns the same types as GetFieldType for
new date and time types.

GetProviderSpecificValue Retrieves the value of the specified column. Returns the same
types as GetValue for the new date and time types.

GetProviderSpecificValues Retrieves the values in the specified array.

GetSqlString Retrieves the column value as a SqlString. An


InvalidCastException occurs if the data cannot be expressed
as a SqlString .
SQ L C L IEN T M ET H O D DESC RIP T IO N

GetSqlValue Retrieves column data as its default SqlDbType . Returns the


same types as GetValue for the new date and time types.

GetSqlValues Retrieves the values in the specified array.

GetString Retrieves the column value as a string if the Type System


Version is set to SQL Server 2005. An InvalidCastException
occurs if the data cannot be expressed as a string.

GetTimeSpan Retrieves the specified column value as a TimeSpan structure.

GetValue Retrieves the specified column value as its underlying CLR


type.

GetValues Retrieves column values in an array.

GetSchemaTable Returns a DataTable that describes the metadata of the


result set.

NOTE
The new date and time SqlDbTypes are not supported for code that is executing in-process in SQL Server. An exception
will be raised if one of these types is passed to the server.

Specifying date and time values as literals


You can specify date and time data types by using a variety of different literal string formats, which SQL Server
then evaluates at run time, converting them to internal date/time structures. SQL Server recognizes date and
time data that is enclosed in single quotation marks ('). The following examples demonstrate some formats:
Alphabetic date formats, such as 'October 15, 2006' .
Numeric date formats, such as '10/15/2006' .
Unseparated string formats, such as '20061015' , which would be interpreted as October 15, 2006 if you
are using the ISO standard date format.

NOTE
You can find complete documentation for all of the literal string formats and other features of the date and time data
types in SQL Server Books Online.

Time values that are less than zero or greater than or equal to 24 hours will throw an ArgumentException.

Resources in SQL Server 2008 Books Online


For more information about working with date and time values in SQL Server 2008, see the following resources
in SQL Server 2008 Books Online.
TO P IC DESC RIP T IO N

Date and Time Data Types and Functions (Transact-SQL) Provides an overview of all Transact-SQL date and time data
types and functions.

Using Date and Time Data Provides information about the date and time data types
and functions, and examples of using them.

Data Types (Transact-SQL) Describes system data types in SQL Server 2008.

Next steps
SQL Server data types and ADO.NET
Large UDTs
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
User-defined types (UDTs) allow a developer to extend the server's scalar type system by storing common
language runtime (CLR) objects in a SQL Server database. UDTs can contain multiple elements and can have
behaviors, unlike the traditional alias data types, which consist of a single SQL Server system data type.
Previously, UDTs were restricted to a maximum size of 8 kilobytes. In SQL Server 2008, this restriction has been
removed for UDTs that have a format of UserDefined.
For the complete documentation for user-defined types, see CLR User-Defined Types from SQL Server Books
Online.

Retrieving UDT schemas using GetSchema


The GetSchema method of SqlConnection returns database schema information in a DataTable.
GetSchemaTable column values for UDTs
The GetSchemaTable method of a SqlDataReader returns a DataTable that describes column metadata. The
following table describes the differences in the column metadata for large UDTs between SQL Server 2005 and
SQL Server 2008.

SQ L DATA REA DER C O L UM N SQ L SERVER 2005 SQ L SERVER 2008 A N D L AT ER

ColumnSize Varies Varies

NumericPrecision 255 255

NumericScale 255 255

DataType Byte[] UDT instance

ProviderSpecificDataType SqlTypes.SqlBinary UDT instance

ProviderType 21 ( SqlDbType.VarBinary ) 29 ( SqlDbType.Udt )

NonVersionedProviderType 29 ( SqlDbType.Udt ) 29 ( SqlDbType.Udt )

DataTypeName SqlDbType.VarBinary The three part name specified as


Database.SchemaName.TypeName.

IsLong Varies Varies

SqlDataReader considerations
The SqlDataReader has been extended beginning in SQL Server 2008 to support retrieving large UDT values.
How large UDT values are processed by a SqlDataReader depends on the version of SQL Server you are using,
as well as on the Type System Version specified in the connection string. For more information, see
ConnectionString.
The following methods of SqlDataReader will return a SqlBinary instead of a UDT when the Type System Version
is set to SQL Server 2005:
GetProviderSpecificFieldType
GetProviderSpecificValue
GetProviderSpecificValues
GetSqlValue
GetSqlValues
The following methods will return an array of Byte[] instead of a UDT when the Type System Version is set to
SQL Server 2005:
GetValue
GetValues
Note that no conversions are made for the current version of ADO.NET.

Specifying SqlParameters
The following SqlParameter properties have been extended to work with large UDTs.

SQ L PA RA M ET ER P RO P ERT Y DESC RIP T IO N

Value Gets or sets an object that represents the value of the


parameter. The default is null. The property can be
SqlBinary , Byte[] , or a managed object.

SqlValue Gets or sets an object that represents the value of the


parameter. The default is null. The property can be
SqlBinary , Byte[] , or a managed object.

Size Gets or sets the size of the parameter value to resolve. The
default value is 0. The property can be an integer that
represents the size of the parameter value. For large UDTs, it
can be the actual size of the UDT, or -1 for unknown.

Retrieving data example


The following code fragment demonstrates how to retrieve large UDT data. The connectionString variable
assumes a valid connection to a SQL Server database and the commandString variable assumes a valid SELECT
statement with the primary key column listed first.
using (SqlConnection connection = new SqlConnection(
connectionString, commandString))
{
connection.Open();
SqlCommand command = new SqlCommand(commandString);
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
// Retrieve the value of the Primary Key column.
int id = reader.GetInt32(0);

// Retrieve the value of the UDT.


LargeUDT udt = (LargeUDT)reader[1];

// You can also use GetSqlValue and GetValue.


// LargeUDT udt = (LargeUDT)reader.GetSqlValue(1);
// LargeUDT udt = (LargeUDT)reader.GetValue(1);

Console.WriteLine(
"ID={0} LargeUDT={1}", id, udt);
}
reader.close
}

Next steps
SQL Server binary and large-value data
XML data in SQL Server
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
SQL Server exposes the functionality of SQLXML inside the .NET. Developers can write applications that access
XML data from an instance of SQL Server, bring the data into the .NET environment, process the data, and send
the updates back to SQL Server. XML data can be used in several ways in SQL Server, including data storage, and
as parameter values for retrieving data. The SqlXml class in the .NET provides the client-side support for
working with data stored in an XML column within SQL Server. For more information, see "SQLXML Managed
Classes" in SQL Server Books Online.

In this section
SQL XML column values
Demonstrates how to retrieve and work with XML data retrieved from SQL Server.
Specifying XML values as parameters
Demonstrates how to pass XML data as a parameter to a command.

Next steps
SQL Server and ADO.NET
SQL XML column values
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
SQL Server supports the xml data type, and developers can retrieve result sets including this type using
standard behavior of the SqlCommand class. An xml column can be retrieved just as any column is retrieved
(into a SqlDataReader, for example) but if you want to work with the content of the column as XML, you must
use an XmlReader.

Example
The following console application selects two rows, each containing an xml column, from the Sales.Store table
in the AdventureWorks database to a SqlDataReader instance. For each row, the value of the xml column is
read using the GetSqlXml method of SqlDataReader. The value is stored in an XmlReader. Note that you must
use GetSqlXml rather than the GetValue method if you want to set the contents to a SqlXml variable; GetValue
returns the value of the xml column as a string.

NOTE
The AdventureWorks sample database is not installed by default when you install SQL Server. You can install it by
running SQL Server Setup.

using Microsoft.Data.SqlClient;
using System.Xml;
using System.Data.SqlTypes;

class Class1
{
static void Main()
{
string c = "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks; ";
GetXmlData(c);
Console.ReadLine();
}

static void GetXmlData(string connectionString)


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

// The query includes two specific customers for simplicity's


// sake. A more realistic approach would use a parameter
// for the CustomerID criteria. The example selects two rows
// in order to demonstrate reading first from one row to
// another, then from one node to another within the xml column.
string commandText =
"SELECT Demographics from Sales.Store WHERE " +
"CustomerID = 3 OR CustomerID = 4";

SqlCommand commandSales = new SqlCommand(commandText, connection);

SqlDataReader salesReaderData = commandSales.ExecuteReader();


// Multiple rows are returned by the SELECT, so each row
// is read and an XmlReader (an xml data type) is set to the
// value of its first (and only) column.
int countRow = 1;
while (salesReaderData.Read())
// Must use GetSqlXml here to get a SqlXml type.
// GetValue returns a string instead of SqlXml.
{
SqlXml salesXML =
salesReaderData.GetSqlXml(0);
XmlReader salesReaderXml = salesXML.CreateReader();
Console.WriteLine("-----Row " + countRow + "-----");

// Move to the root.


salesReaderXml.MoveToContent();

// We know each node type is either Element or Text.


// All elements within the root are string values.
// For this simple example, no elements are empty.
while (salesReaderXml.Read())
{
if (salesReaderXml.NodeType == XmlNodeType.Element)
{
string elementLocalName =
salesReaderXml.LocalName;
salesReaderXml.Read();
Console.WriteLine(elementLocalName + ": " +
salesReaderXml.Value);
}
}
countRow = countRow + 1;
}
}
}
}

Next steps
SqlXml
XML data in SQL Server
Specifying XML values as parameters
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
If a query requires a parameter whose value is an XML string, developers can supply that value using an
instance of the SqlXml data type. There really are no tricks; XML columns in SQL Server accept parameter
values in exactly the same way as other data types.

Example
The following console application creates a new table in the AdventureWorks database. The new table includes
a column named SalesID and an XML column named SalesInfo .

NOTE
The AdventureWorks sample database is not installed by default when you install SQL Server. You can install it by
running SQL Server Setup.

The example prepares a SqlCommand object to insert a row in the new table. A saved file provides the XML data
needed for the SalesInfo column.
To create the file needed for the example to run, create a new text file in the same folder as your project. Name
the file MyTestStoreData.xml. Open the file in Notepad and copy and paste the following text:

<StoreSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/StoreSurvey">
<AnnualSales>300000</AnnualSales>
<AnnualRevenue>30000</AnnualRevenue>
<BankName>International Bank</BankName>
<BusinessType>BM</BusinessType>
<YearOpened>1970</YearOpened>
<Specialty>Road</Specialty>
<SquareFeet>7000</SquareFeet>
<Brands>3</Brands>
<Internet>T1</Internet>
<NumberEmployees>2</NumberEmployees>
</StoreSurvey>
using System;
using System.Data;
using Microsoft.Data.SqlClient;
using System.Xml;
using System.Data.SqlTypes;

class Class1
{
static void Main()
{
using (SqlConnection connection = new SqlConnection(GetConnectionString()))
{
connection.Open();
// Create a sample table (dropping first if it already
// exists.)

string commandNewTable =
"IF EXISTS (SELECT * FROM dbo.sysobjects " +
"WHERE id = " +
"object_id(N'[dbo].[XmlDataTypeSample]') " +
"AND OBJECTPROPERTY(id, N'IsUserTable') = 1) " +
"DROP TABLE [dbo].[XmlDataTypeSample];" +
"CREATE TABLE [dbo].[XmlDataTypeSample](" +
"[SalesID] [int] IDENTITY(1,1) NOT NULL, " +
"[SalesInfo] [xml])";
SqlCommand commandAdd =
new SqlCommand(commandNewTable, connection);
commandAdd.ExecuteNonQuery();
string commandText =
"INSERT INTO [dbo].[XmlDataTypeSample] " +
"([SalesInfo] ) " +
"VALUES(@xmlParameter )";
SqlCommand command =
new SqlCommand(commandText, connection);

// Read the saved XML document as a


// SqlXml-data typed variable.
SqlXml newXml =
new SqlXml(new XmlTextReader("MyTestStoreData.xml"));

// Supply the SqlXml value for the value of the parameter.


command.Parameters.AddWithValue("@xmlParameter", newXml);

int result = command.ExecuteNonQuery();


Console.WriteLine(result + " row was added.");
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}
}

private static string GetConnectionString()


{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks; ";
}
}

Next steps
SqlXml
XML data in SQL Server
SQL Server binary and large-value data
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
SQL Server provides the max specifier, which expands the storage capacity of the varchar , nvarchar , and
varbinary data types. varchar(max) , nvarchar(max) , and varbinary(max) are collectively called large-value
data types. You can use the large-value data types to store up to 2^31-1 bytes of data.
SQL Server 2008 introduces the FILESTREAM attribute, which is not a data type, but rather an attribute that can
be defined on a column, allowing large-value data to be stored on the file system instead of in the database.

In this section
Modifying large-value (max) data in ADO.NET
Describes how to work with the large-value data types.
FILESTREAM data
Describes how to work with large-value data stored in SQL Server 2008 with the FILESTREAM attribute.

Next steps
SQL Server data types and ADO.NET
SQL Server data operations in ADO.NET
Modifying large-value (max) data in ADO.NET
4/27/2022 • 9 minutes to read • Edit Online

Download ADO.NET
Large object (LOB) data types are those that exceed the maximum row size of 8 kilobytes (KB). SQL Server
provides a max specifier for varchar , nvarchar , and varbinary data types to allow storage of values as large
as 2^32 bytes. Table columns and Transact-SQL variables may specify varchar(max) , nvarchar(max) , or
varbinary(max) data types. In .NET, the max data types can be fetched by a DataReader , and can also be
specified as both input and output parameter values without any special handling. For large varchar data types,
data can be retrieved and updated incrementally.
The max data types can be used for comparisons, as Transact-SQL variables, and for concatenation. They can
also be used in the DISTINCT, ORDER BY, GROUP BY clauses of a SELECT statement as well as in aggregates,
joins, and subqueries.
See Using Large-Value Data Types from SQL Server Books Online more details on large-value data types.

Large-value type restrictions


The following restrictions apply to the max data types, which do not exist for smaller data types:
A sql_variant cannot contain a large varchar data type.
Large varchar columns cannot be specified as a key column in an index. They are allowed in an included
column in a non-clustered index.
Large varchar columns cannot be used as partitioning key columns.

Working with large-value types in transact-SQL


The Transact-SQL OPENROWSET function is a one-time method of connecting and accessing remote data.
OPENROWSET can be referenced in the FROM clause of a query as though it were a table name. It can also be
referenced as the target table of an INSERT, UPDATE, or DELETE statement.
The OPENROWSET function includes the BULK rowset provider, which allows you to read data directly from a file
without loading the data into a target table. This enables you to use OPENROWSET in a simple INSERT SELECT
statement.
The OPENROWSET BULK option arguments provide significant control over where to begin and end reading data,
how to deal with errors, and how data is interpreted. For example, you can specify that the data file be read as a
single-row, single-column rowset of type varbinary , varchar , or nvarchar . For the complete syntax and
options, see SQL Server Books Online.
The following example inserts a photo into the ProductPhoto table in the AdventureWorks sample database.
When using the BULK OPENROWSET provider, you must supply the named list of columns even if you aren't
inserting values into every column. The primary key in this case is defined as an identity column, and may be
omitted from the column list. Note that you must also supply a correlation name at the end of the OPENROWSET
statement, which in this case is ThumbnailPhoto. This correlates with the column in the ProductPhoto table into
which the file is being loaded.
INSERT Production.ProductPhoto (
ThumbnailPhoto,
ThumbnailPhotoFilePath,
LargePhoto,
LargePhotoFilePath)
SELECT ThumbnailPhoto.*, null, null, N'tricycle_pink.gif'
FROM OPENROWSET
(BULK 'c:\images\tricycle.jpg', SINGLE_BLOB) ThumbnailPhoto

Updating data using UPDATE .WRITE


The Transact-SQL UPDATE statement has new WRITE syntax for modifying the contents of varchar(max) ,
nvarchar(max) , or varbinary(max) columns. This allows you to perform partial updates of the data. The UPDATE
.WRITE syntax is shown here in abbreviated form:
UPDATE
{ <object> }
SET
{ column_name = { .WRITE ( expression , @Offset , @Length ) }
The WRITE method specifies that a section of the value of the column_name will be modified. The expression is
the value that will be copied to the column_name, the @Offset is the beginning point at which the expression
will be written, and the @Length argument is the length of the section in the column.

IF T H EN

The expression is set to NULL @Length is ignored and the value in column_name is
truncated at the specified @Offset .

@Offset is NULL The update operation appends the expression at the end of
the existing column_name value and @Length is ignored.

@Offset is greater than the length of the column_name SQL Server returns an error.
value

@Length is NULL The update operation removes all data from @Offset to
the end of the column_name value.

NOTE
Neither @Offset nor @Length can be a negative number.

Example
This Transact-SQL example updates a partial value in DocumentSummary, an nvarchar(max) column in the
Document table in the AdventureWorks database. The word 'components' is replaced by the word 'features' by
specifying the replacement word, the beginning location (offset) of the word to be replaced in the existing data,
and the number of characters to be replaced (length). The example includes SELECT statements before and after
the UPDATE statement to compare results.
USE AdventureWorks;
GO
--View the existing value.
SELECT DocumentSummary
FROM Production.Document
WHERE DocumentID = 3;
GO
-- The first sentence of the results will be:
-- Reflectors are vital safety components of your bicycle.

--Modify a single word in the DocumentSummary column


UPDATE Production.Document
SET DocumentSummary .WRITE (N'features',28,10)
WHERE DocumentID = 3 ;
GO
--View the modified value.
SELECT DocumentSummary
FROM Production.Document
WHERE DocumentID = 3;
GO
-- The first sentence of the results will be:
-- Reflectors are vital safety features of your bicycle.

Working with large-value types in ADO.NET


You can work with large value types in ADO.NET by specifying large value types as SqlParameter objects in a
SqlDataReader to return a result set, or by using a SqlDataAdapter to fill a DataSet / DataTable . There is no
difference between the way you work with a large value type and its related, smaller value data type.
Using GetSqlBytes to Retrieve Data
The GetSqlBytes method of the SqlDataReader can be used to retrieve the contents of a varbinary(max)
column. The following code fragment assumes a SqlCommand object named cmd that selects varbinary(max)
data from a table and a SqlDataReader object named reader that retrieves the data as SqlBytes.

reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
SqlBytes bytes = reader.GetSqlBytes(0);
}

Using GetSqlChars to retrieve data


The GetSqlChars method of the SqlDataReader can be used to retrieve the contents of a varchar(max) or
nvarchar(max) column. The following code fragment assumes a SqlCommand object named cmd that selects
nvarchar(max) data from a table and a SqlDataReader object named reader that retrieves the data.

reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
SqlChars buffer = reader.GetSqlChars(0);
}

Using GetSqlBinary to retrieve data


The GetSqlBinary method of a SqlDataReader can be used to retrieve the contents of a varbinary(max) column.
The following code fragment assumes a SqlCommand object named cmd that selects varbinary(max) data
from a table and a SqlDataReader object named reader that retrieves the data as a SqlBinary stream.
reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
SqlBinary binaryStream = reader.GetSqlBinary(0);
}

Using GetBytes to retrieve data


The GetBytes method of a SqlDataReader reads a stream of bytes from the specified column offset into a byte
array starting at the specified array offset. The following code fragment assumes a SqlDataReader object named
reader that retrieves bytes into a byte array. Note that, unlike GetSqlBytes , GetBytes requires a size for the
array buffer.

while (reader.Read())
{
byte[] buffer = new byte[4000];
long byteCount = reader.GetBytes(1, 0, buffer, 0, 4000);
}

Using GetValue to retrieve data


The GetValue method of a SqlDataReader reads the value from the specified column offset into an array. The
following code fragment assumes a SqlDataReader object named reader that retrieves binary data from the
first column offset, and then string data from the second column offset.

while (reader.Read())
{
// Read the data from varbinary(max) column
byte[] binaryData = (byte[])reader.GetValue(0);

// Read the data from varchar(max) or nvarchar(max) column


String stringData = (String)reader.GetValue(1);
}

Converting from large value types to CLR types


You can convert the contents of a varchar(max) or nvarchar(max) column using any of the string conversion
methods, such as ToString . The following code fragment assumes a SqlDataReader object named reader that
retrieves the data.

while (reader.Read())
{
string str = reader[0].ToString();
Console.WriteLine(str);
}

Example
The following code retrieves the name and the LargePhoto object from the ProductPhoto table in the
AdventureWorks database and saves it to a file. The assembly needs to be compiled with a reference to the
System.Drawing namespace. The GetSqlBytes method of the SqlDataReader returns a SqlBytes object that
exposes a Stream property. The code uses this to create a new Bitmap object, and then saves it in the Gif
ImageFormat .

using Microsoft.Data.SqlClient;
using System.Data.SqlTypes;
using System.Drawing;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

class Program
{
static void Main()
{
// Supply any valid DocumentID value and file path.
// The value 3 is supplied for DocumentID, and a literal
// string for the file path where the image will be saved. 1, 60
TestGetSqlBytes(7, @"c:\temp\");
Console.ReadLine();
}
static private void TestGetSqlBytes(int documentID, string filePath)
{
// Assumes GetConnectionString returns a valid connection string.
using (SqlConnection connection =
new SqlConnection(GetConnectionString()))
{
SqlCommand command = connection.CreateCommand();
SqlDataReader reader = null;
try
{
// Setup the command
command.CommandText =
"SELECT LargePhotoFileName, LargePhoto "
+ "FROM Production.ProductPhoto "
+ "WHERE ProductPhotoID=@ProductPhotoID";
command.CommandType = CommandType.Text;

// Declare the parameter


SqlParameter paramID =
new SqlParameter("@ProductPhotoID", SqlDbType.Int);
paramID.Value = documentID;
command.Parameters.Add(paramID);
connection.Open();

string photoName = null;

reader = command.ExecuteReader(CommandBehavior.CloseConnection);

if (reader.HasRows)
{
while (reader.Read())
{
// Get the name of the file.
photoName = reader.GetString(0);

// Ensure that the column isn't null


if (reader.IsDBNull(1))
{
Console.WriteLine("{0} is unavailable.", photoName);
}
else
{
SqlBytes bytes = reader.GetSqlBytes(1);
using (Bitmap productImage = new Bitmap(bytes.Stream))
{
String fileName = filePath + photoName;

// Save in gif format.


productImage.Save(fileName, ImageFormat.Gif);
Console.WriteLine("Successfully created {0}.", fileName);
}
}
}
}
else
{
{
Console.WriteLine("No records returned.");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (reader != null)
reader.Dispose();
}
}
}

static private string GetConnectionString()


{
// To avoid storing the connectionection string in your code,
// you can retrieve it from a configuration file, using the
// System.Configuration.ConfigurationSettings.AppSettings property
return "Data Source=(local);Initial Catalog=AdventureWorks;" +
"Integrated Security=SSPI";
}
}

Using large value type parameters


Large value types can be used in SqlParameter objects the same way you use smaller value types in
SqlParameter objects. You can retrieve large value types as SqlParameter values, as shown in the following
example. The code assumes that the following GetDocumentSummary stored procedure exists in the
AdventureWorks sample database. The stored procedure takes an input parameter named @DocumentID and
returns the contents of the DocumentSummary column in the @DocumentSummary output parameter.

CREATE PROCEDURE GetDocumentSummary


(
@DocumentID int,
@DocumentSummary nvarchar(MAX) OUTPUT
)
AS
SET NOCOUNT ON
SELECT @DocumentSummary=Convert(nvarchar(MAX), DocumentSummary)
FROM Production.Document
WHERE DocumentID=@DocumentID

Example
The ADO.NET code creates SqlConnection and SqlCommand objects to execute the GetDocumentSummary
stored procedure and retrieve the document summary, which is stored as a large value type. The code passes a
value for the @DocumentID input parameter, and displays the results passed back in the @DocumentSummary
output parameter in the Console window.
using Microsoft.Data.SqlClient;
class Program
{
static void Main()
{
// Supply any valid Document ID value.
// The value 7 is supplied for demonstration purposes.
string summaryString = GetDocumentSummary(7);
Console.ReadLine();
}
static private string GetDocumentSummary(int documentID)
{
//Assumes GetConnectionString returns a valid connection string.
using (SqlConnection connection =
new SqlConnection(GetConnectionString()))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
try
{
// Setup the command to execute the stored procedure.
command.CommandText = "GetDocumentSummary";
command.CommandType = CommandType.StoredProcedure;

// Set up the input parameter for the DocumentID.


SqlParameter paramID =
new SqlParameter("@DocumentID", SqlDbType.Int);
paramID.Value = documentID;
command.Parameters.Add(paramID);

// Set up the output parameter to retrieve the summary.


SqlParameter paramSummary =
new SqlParameter("@DocumentSummary",
SqlDbType.NVarChar, -1);
paramSummary.Direction = ParameterDirection.Output;
command.Parameters.Add(paramSummary);

// Execute the stored procedure.


command.ExecuteNonQuery();
Console.WriteLine((String)(paramSummary.Value));
return (String)(paramSummary.Value);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
}
static private string GetConnectionString()
{
// To avoid storing the connectionection string in your code,
// you can retrieve it from a configuration file, using the
// System.Configuration.ConfigurationSettings.AppSettings property
return "Data Source=(local);Initial Catalog=AdventureWorks;" +
"Integrated Security=SSPI";
}
}

Next steps
SQL Server binary and large-value data
SQL Server data operations in ADO.NET
FILESTREAM data
4/27/2022 • 4 minutes to read • Edit Online

Download ADO.NET
The FILESTREAM storage attribute is for binary (BLOB) data stored in a varbinary(max) column. Before
FILESTREAM, storing binary data required special handling. Unstructured data, such as text documents, images
and video, is often stored outside of the database, making it difficult to manage.

NOTE
You must install the .NET Framework 3.5 SP1 (or later) or .NET Core to work with FILESTREAM data using SqlClient.

Specifying the FILESTREAM attribute on a varbinary(max) column causes SQL Server to store the data on the
local NTFS file system instead of in the database file. Although it's stored separately, you can use the same
Transact-SQL statements that are supported for working with varbinary(max) data that is stored in the database.

SqlClient support for FILESTREAM


The Microsoft SqlClient Data Provider for SQL Server, Microsoft.Data.SqlClient, supports reading and writing to
FILESTREAM data using the SqlFileStream class defined in the System.Data.SqlTypes namespace. SqlFileStream
inherits from the Stream class, which provides methods for reading and writing to streams of data. Reading
from a stream transfers data from the stream into a data structure, such as an array of bytes. Writing transfers
the data from the data structure into a stream.
Creating the SQL Server table
The following Transact-SQL statements create a table named employees and inserts a row of data. Once you
have enabled FILESTREAM storage, you can use this table with the code examples that follow. The links to
resources in SQL Server Books Online are located at the end of this article.

CREATE TABLE employees


(
EmployeeId INT NOT NULL PRIMARY KEY,
Photo VARBINARY(MAX) FILESTREAM NULL,
RowGuid UNIQUEIDENTIFIER NOT NULL ROWGUIDCOL
UNIQUE DEFAULT NEWID()
)
GO
Insert into employees
Values(1, 0x00, default)
GO

Example: Reading, overwriting, and inserting FILESTREAM data


The following sample demonstrates how to read data from a FILESTREAM. The code gets the logical path to the
file, setting the FileAccess to Read and the FileOptions to SequentialScan . The code then reads the bytes
from the SqlFileStream into the buffer. The bytes are then written to the console window.
The sample also demonstrates how to write data to a FILESTREAM in which all existing data is overwritten. The
code gets the logical path to the file and creates the SqlFileStream , setting the FileAccess to Write and the
FileOptions to SequentialScan . A single byte is written to the SqlFileStream , replacing any data in the file.
The sample also demonstrates how to write data to a FILESTREAM by using the Seek method to append data to
the end of the file. The code gets the logical path to the file and creates the SqlFileStream , setting the
FileAccess to ReadWrite and the FileOptions to SequentialScan . The code uses the Seek method to seek to
the end of the file, appending a single byte to the existing file.

using System;
using Microsoft.Data.SqlClient;
using System.Data.SqlTypes;
using System.Data;
using System.IO;

namespace FileStreamTest
{
class Program
{
static void Main(string[] args)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder("server=(local);integrated
security=true;database=myDB");
ReadFileStream(builder);
OverwriteFileStream(builder);
InsertFileStream(builder);

Console.WriteLine("Done");
}

private static void ReadFileStream(SqlConnectionStringBuilder connStringBuilder)


{
using (SqlConnection connection = new SqlConnection(connStringBuilder.ToString()))
{
connection.Open();
SqlCommand command = new SqlCommand("SELECT TOP(1) Photo.PathName(),
GET_FILESTREAM_TRANSACTION_CONTEXT() FROM employees", connection);

SqlTransaction tran = connection.BeginTransaction(IsolationLevel.ReadCommitted);


command.Transaction = tran;

using (SqlDataReader reader = command.ExecuteReader())


{
while (reader.Read())
{
// Get the pointer for the file
string path = reader.GetString(0);
byte[] transactionContext = reader.GetSqlBytes(1).Buffer;

// Create the SqlFileStream


using (Stream fileStream = new SqlFileStream(path, transactionContext,
FileAccess.Read, FileOptions.SequentialScan, allocationSize: 0))
{
// Read the contents as bytes and write them to the console
for (long index = 0; index < fileStream.Length; index++)
{
Console.WriteLine(fileStream.ReadByte());
}
}
}
}
tran.Commit();
}
}

private static void OverwriteFileStream(SqlConnectionStringBuilder connStringBuilder)


{
using (SqlConnection connection = new SqlConnection(connStringBuilder.ToString()))
{
connection.Open();
SqlCommand command = new SqlCommand("SELECT TOP(1) Photo.PathName(),
GET_FILESTREAM_TRANSACTION_CONTEXT() FROM employees", connection);

SqlTransaction tran = connection.BeginTransaction(IsolationLevel.ReadCommitted);


command.Transaction = tran;

using (SqlDataReader reader = command.ExecuteReader())


{
while (reader.Read())
{
// Get the pointer for file
string path = reader.GetString(0);
byte[] transactionContext = reader.GetSqlBytes(1).Buffer;

// Create the SqlFileStream


using (Stream fileStream = new SqlFileStream(path, transactionContext,
FileAccess.Write, FileOptions.SequentialScan, allocationSize: 0))
{
// Write a single byte to the file. This will
// replace any data in the file.
fileStream.WriteByte(0x01);
}
}
}
tran.Commit();
}
}

private static void InsertFileStream(SqlConnectionStringBuilder connStringBuilder)


{
using (SqlConnection connection = new SqlConnection(connStringBuilder.ToString()))
{
connection.Open();

SqlCommand command = new SqlCommand("SELECT TOP(1) Photo.PathName(),


GET_FILESTREAM_TRANSACTION_CONTEXT() FROM employees", connection);

SqlTransaction tran = connection.BeginTransaction(IsolationLevel.ReadCommitted);


command.Transaction = tran;

using (SqlDataReader reader = command.ExecuteReader())


{
while (reader.Read())
{
// Get the pointer for file
string path = reader.GetString(0);
byte[] transactionContext = reader.GetSqlBytes(1).Buffer;

using (Stream fileStream = new SqlFileStream(path, transactionContext,


FileAccess.ReadWrite, FileOptions.SequentialScan, allocationSize: 0))
{
// Seek to the end of the file
fileStream.Seek(0, SeekOrigin.End);

// Append a single byte


fileStream.WriteByte(0x01);
}
}
}
tran.Commit();
}

}
}
}

For another sample, see How to store and fetch binary data into a file stream column.
Resources in SQL Server Books Online
The complete documentation for FILESTREAM is located in the following sections in SQL Server Books Online.

A RT IC L E DESC RIP T IO N

FILESTREAM (SQL Server) Describes when to use FILESTREAM storage and how it
integrates the SQL Server Database Engine with an NTFS file
system.

Create Client Applications for FILESTREAM Data Describes the Windows API functions for working with
FILESTREAM data.

FILESTREAM and Other SQL Server Features Provides considerations, guidelines, and limitations for using
FILESTREAM data with other features of SQL Server.

Next steps
SQL Server data types and ADO.NET
SQL Server binary and large-value data
Inserting an image from a file
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
You can write a binary large object (BLOB) to a database as either binary or character data, depending on the
type of field at your data source. BLOB is a generic term that refers to the text , ntext , and image data types,
which typically contain documents and pictures.
To write a BLOB value to your database, issue the appropriate INSERT or UPDATE statement and pass the BLOB
value as an input parameter. If your BLOB is stored as text, such as a SQL Server text field, you can pass the
BLOB as a string parameter. If the BLOB is stored in binary format, such as a SQL Server image field, you can
pass an array of type byte as a binary parameter.

Example
The following code example adds employee information to the Employees table in the Northwind database. A
photo of the employee is read from a file and added to the Photo field in the table, which is an image field.
public static void AddEmployee(
string lastName,
string firstName,
string title,
DateTime hireDate,
int reportsTo,
string photoFilePath,
string connectionString)
{
byte[] photo = GetPhoto(photoFilePath);

using (SqlConnection connection = new SqlConnection(


connectionString))

SqlCommand command = new SqlCommand(


"INSERT INTO Employees (LastName, FirstName, " +
"Title, HireDate, ReportsTo, Photo) " +
"Values(@LastName, @FirstName, @Title, " +
"@HireDate, @ReportsTo, @Photo)", connection);

command.Parameters.Add("@LastName",
SqlDbType.NVarChar, 20).Value = lastName;
command.Parameters.Add("@FirstName",
SqlDbType.NVarChar, 10).Value = firstName;
command.Parameters.Add("@Title",
SqlDbType.NVarChar, 30).Value = title;
command.Parameters.Add("@HireDate",
SqlDbType.DateTime).Value = hireDate;
command.Parameters.Add("@ReportsTo",
SqlDbType.Int).Value = reportsTo;

command.Parameters.Add("@Photo",
SqlDbType.Image, photo.Length).Value = photo;

connection.Open();
command.ExecuteNonQuery();
}
}

public static byte[] GetPhoto(string filePath)


{
FileStream stream = new FileStream(
filePath, FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(stream);

byte[] photo = reader.ReadBytes((int)stream.Length);

reader.Close();
stream.Close();

return photo;
}

Next steps
SQL Server binary and large-value data
SQL Server data operations in ADO.NET
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
This section describes SQL Server features and functionality that are specific to the Microsoft SqlClient Data
Provider for SQL Server (Microsoft.Data.SqlClient).

In this section
Bulk copy operations in SQL Server
Describes the bulk copy functionality for the .NET Data Provider for SQL Server.
Multiple Active Result Sets (MARS)
Describes how to have more than one SqlDataReader open on a connection when each instance of
SqlDataReader is started from a separate command.
Asynchronous operations
Describes how to perform asynchronous database operations by using an API that is modeled after the
asynchronous model used by the .NET Framework.
Table-valued parameters
Describes how to work with table-valued parameters, which were introduced in SQL Server 2008.

Next steps
SQL Server and ADO.NET
Bulk copy operations in SQL Server
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Microsoft SQL Server includes a popular command-line utility named bcp . Bcp is used to quickly bulk copy
large files into tables or views in SQL Server databases. The SqlBulkCopy class allows you to write managed
code solutions that provide similar functionality. There are other ways to load data into a table (INSERT
statements, for example) but SqlBulkCopy offers a significant performance advantage over them.
Using the SqlBulkCopy class, you can perform:
A single bulk copy operation
Multiple bulk copy operations
A bulk copy operation within a transaction

NOTE
When using .NET Framework version 1.1 or earlier (which does not support the SqlBulkCopy class), you can execute the
SQL Server Transact-SQL BULK INSERT statement using the SqlCommand object.

In this section
Bulk copy example setup:
Describes the tables used in the bulk copy examples and provides SQL scripts for creating the tables in the
AdventureWorks database.
Single bulk copy operations:
Describes how to do a single bulk copy of data into a database instance using the SqlBulkCopy class. It includes
how to do the bulk copy operation using Transact-SQL statements and the SqlCommand class.
Multiple bulk copy operations:
Describes how to do multiple bulk copy operations of data into a database instance using the SqlBulkCopy class.
Transaction and bulk copy operations:
Describes how to do a bulk copy operation within a transaction, including how to commit or roll back the
transaction.
Order hints for bulk copy operations:
Describes how to use order hints to improve bulk copy performance.

Next steps
SQL Server and ADO.NET
Bulk copy example setup
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
The SqlBulkCopy class can be used to write data only to SQL Server tables. The code samples shown in this topic
use the SQL Server sample database, AdventureWorks . To avoid altering the existing tables code samples
write data to tables that you must create first.
The BulkCopyDemoMatchingColumns and BulkCopyDemoDifferentColumns tables are both based on
the AdventureWorks Production.Products table. In code samples that use these tables, data is added from
the Production.Products table to one of these sample tables. The BulkCopyDemoDifferentColumns table
is used when the sample illustrates how to map columns from the source data to the destination table;
BulkCopyDemoMatchingColumns is used for most other samples.
A few of the code samples demonstrate how to use one SqlBulkCopy class to write to multiple tables. For these
samples, the BulkCopyDemoOrderHeader and BulkCopyDemoOrderDetail tables are used as the
destination tables. These tables are based on the Sales.SalesOrderHeader and Sales.SalesOrderDetail
tables in AdventureWorks .

NOTE
The SqlBulkCopy code samples are provided to demonstrate the syntax for using SqlBulkCopy only. If the source and
destination tables are located in the same SQL Server instance, it is easier and faster to use a Transact-SQL
INSERT … SELECT statement to copy the data.

Table setup
To create the tables necessary for the code samples to run correctly, you must run the following Transact-SQL
statements in a SQL Server database.
USE AdventureWorks

IF EXISTS (SELECT * FROM dbo.sysobjects


WHERE id = object_id(N'[dbo].[BulkCopyDemoMatchingColumns]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE [dbo].[BulkCopyDemoMatchingColumns]

CREATE TABLE [dbo].[BulkCopyDemoMatchingColumns]([ProductID] [int] IDENTITY(1,1) NOT NULL,


[Name] [nvarchar](50) NOT NULL,
[ProductNumber] [nvarchar](25) NOT NULL,
CONSTRAINT [PK_ProductID] PRIMARY KEY CLUSTERED
(
[ProductID] ASC
) ON [PRIMARY]) ON [PRIMARY]

IF EXISTS (SELECT * FROM dbo.sysobjects


WHERE id = object_id(N'[dbo].[BulkCopyDemoDifferentColumns]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE [dbo].[BulkCopyDemoDifferentColumns]

CREATE TABLE [dbo].[BulkCopyDemoDifferentColumns]([ProdID] [int] IDENTITY(1,1) NOT NULL,


[ProdNum] [nvarchar](25) NOT NULL,
[ProdName] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_ProdID] PRIMARY KEY CLUSTERED
(
[ProdID] ASC
) ON [PRIMARY]) ON [PRIMARY]

IF EXISTS (SELECT * FROM dbo.sysobjects


WHERE id = object_id(N'[dbo].[BulkCopyDemoOrderHeader]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE [dbo].[BulkCopyDemoOrderHeader]

CREATE TABLE [dbo].[BulkCopyDemoOrderHeader]([SalesOrderID] [int] IDENTITY(1,1) NOT NULL,


[OrderDate] [datetime] NOT NULL,
[AccountNumber] [nvarchar](15) NULL,
CONSTRAINT [PK_SalesOrderID] PRIMARY KEY CLUSTERED
(
[SalesOrderID] ASC
) ON [PRIMARY]) ON [PRIMARY]

IF EXISTS (SELECT * FROM dbo.sysobjects


WHERE id = object_id(N'[dbo].[BulkCopyDemoOrderDetail]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE [dbo].[BulkCopyDemoOrderDetail]

CREATE TABLE [dbo].[BulkCopyDemoOrderDetail]([SalesOrderID] [int] NOT NULL,


[SalesOrderDetailID] [int] NOT NULL,
[OrderQty] [smallint] NOT NULL,
[ProductID] [int] NOT NULL,
[UnitPrice] [money] NOT NULL,
CONSTRAINT [PK_LineNumber] PRIMARY KEY CLUSTERED
(
[SalesOrderID] ASC,
[SalesOrderDetailID] ASC
) ON [PRIMARY]) ON [PRIMARY]

Next steps
Bulk copy operations in SQL Server
Single bulk copy operations
4/27/2022 • 4 minutes to read • Edit Online

Download ADO.NET
The simplest approach to performing a SQL Server bulk copy operation is to perform a single operation against
a database. By default, a bulk copy operation is performed as an isolated operation: the copy operation occurs in
a non-transacted way, with no opportunity for rolling it back.

NOTE
If you need to roll back all or part of the bulk copy when an error occurs, you can either use a SqlBulkCopy-managed
transaction, or perform the bulk copy operation within an existing transaction. SqlBulkCopy will also work with
System.Transactions if the connection is enlisted (implicitly or explicitly) into a System.Transactions transaction.
For more information, see Transaction and bulk copy operations.

The general steps for performing a bulk copy operation are as follows:
1. Connect to the source server and obtain the data to be copied. Data can also come from other sources, if
it can be retrieved from an IDataReader or DataTable object.
2. Connect to the destination server (unless you want SqlBulkCopy to establish a connection for you).
3. Create a SqlBulkCopy object, setting any necessary properties.
4. Set the DestinationTableName property to indicate the target table for the bulk insert operation.
5. Call one of the WriteToSer ver methods.
6. Optionally, update properties and call WriteToSer ver again as necessary.
7. Call Close, or wrap the bulk copy operations within a Using statement.
Cau t i on

We recommend that the source and target column data types match. If the data types do not match,
SqlBulkCopy attempts to convert each source value to the target data type, using the rules employed by Value.
Conversions can affect performance, and also can result in unexpected errors. For example, a Double data type
can be converted to a Decimal data type most of the time, but not always.

Example
The following console application demonstrates how to load data using the SqlBulkCopy class. In this example, a
SqlDataReader is used to copy data from the Production.Product table in the SQL Server AdventureWorks
database to a similar table in the same database.

IMPORTANT
This sample will not run unless you have created the work tables as described in Bulk copy example setup. This code is
provided to demonstrate the syntax for using SqlBulkCopy only. If the source and destination tables are located in the
same SQL Server instance, it is easier and faster to use a Transact-SQL INSERT … SELECT statement to copy the data.

using Microsoft.Data.SqlClient;
class Program
{
static void Main()
{
string connectionString = GetConnectionString();
// Open a sourceConnection to the AdventureWorks database.
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
{
sourceConnection.Open();

// Perform an initial count on the destination table.


SqlCommand commandRowCount = new SqlCommand(
"SELECT COUNT(*) FROM " +
"dbo.BulkCopyDemoMatchingColumns;",
sourceConnection);
long countStart = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count = {0}", countStart);

// Get data from the source table as a SqlDataReader.


SqlCommand commandSourceData = new SqlCommand(
"SELECT ProductID, Name, " +
"ProductNumber " +
"FROM Production.Product;", sourceConnection);
SqlDataReader reader =
commandSourceData.ExecuteReader();

// Open the destination connection. In the real world you would


// not use SqlBulkCopy to move data from one table to the other
// in the same database. This is for demonstration purposes only.
using (SqlConnection destinationConnection =
new SqlConnection(connectionString))
{
destinationConnection.Open();

// Set up the bulk copy object.


// Note that the column positions in the source
// data reader match the column positions in
// the destination table so there is no need to
// map columns.
using (SqlBulkCopy bulkCopy =
new SqlBulkCopy(destinationConnection))
{
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoMatchingColumns";

try
{
// Write from the source to the destination.
bulkCopy.WriteToServer(reader);
// Print the number of rows processed using the
// RowsCopied property.
Console.WriteLine("{0} rows were processed.",
bulkCopy.RowsCopied);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// Close the SqlDataReader. The SqlBulkCopy
// object is automatically closed at the end
// of the using block.
reader.Close();
}
}
}

// Perform a final count on the destination


// table to see how many rows were added.
long countEnd = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Ending row count = {0}", countEnd);
Console.WriteLine("{0} rows were added.", countEnd - countStart);
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}
}
}

private static string GetConnectionString()


// To avoid storing the sourceConnection string in your code,
// you can retrieve it from a configuration file.
{
return "Data Source=(local); " +
" Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
}

Performing a bulk copy operation using transact-SQL and the


command class
The following example illustrates how to use the ExecuteNonQuery method to execute the BULK INSERT
statement.

NOTE
The file path for the data source is relative to the server. The server process must have access to that path in order for the
bulk copy operation to succeed.

using (SqlConnection connection = New SqlConnection(connectionString))


{
string queryString = "BULK INSERT Northwind.dbo.[Order Details] " +
"FROM 'f:\mydata\data.tbl' " +
"WITH ( FORMATFILE='f:\mydata\data.fmt' )";
connection.Open();
SqlCommand command = new SqlCommand(queryString, connection);

command.ExecuteNonQuery();
}

Next steps
Bulk copy operations in SQL Server
Multiple bulk copy operations
4/27/2022 • 3 minutes to read • Edit Online

Download ADO.NET
You can perform multiple bulk copy operations using a single instance of a SqlBulkCopy class. If the operation
parameters change between copies (for example, the name of the destination table), you must update them
prior to any subsequent calls to any of the WriteToSer ver methods, as demonstrated in the following example.
Unless explicitly changed, all property values remain the same as they were on the previous bulk copy operation
for a given instance.

NOTE
Performing multiple bulk copy operations using the same instance of SqlBulkCopy is usually more efficient than using a
separate instance for each operation.

If you perform several bulk copy operations using the same SqlBulkCopy object, there are no restrictions on
whether source or target information is equal or different in each operation. However, you must ensure that
column association information is properly set each time you write to the server.

Example
IMPORTANT
This sample will not run unless you have created the work tables as described in Bulk copy example setup. This code is
provided to demonstrate the syntax for using SqlBulkCopy only. If the source and destination tables are located in the
same SQL Server instance, it is easier and faster to use a Transact-SQL INSERT … SELECT statement to copy the data.

using Microsoft.Data.SqlClient;

class Program
{
static void Main()
{
string connectionString = GetConnectionString();
// Open a connection to the AdventureWorks database.
using (SqlConnection connection =
new SqlConnection(connectionString))
{
connection.Open();

// Empty the destination tables.


SqlCommand deleteHeader = new SqlCommand(
"DELETE FROM dbo.BulkCopyDemoOrderHeader;",
connection);
deleteHeader.ExecuteNonQuery();
SqlCommand deleteDetail = new SqlCommand(
"DELETE FROM dbo.BulkCopyDemoOrderDetail;",
connection);
deleteDetail.ExecuteNonQuery();

// Perform an initial count on the destination


// table with matching columns.
SqlCommand countRowHeader = new SqlCommand(
"SELECT COUNT(*) FROM dbo.BulkCopyDemoOrderHeader;",
"SELECT COUNT(*) FROM dbo.BulkCopyDemoOrderHeader;",
connection);
long countStartHeader = System.Convert.ToInt32(
countRowHeader.ExecuteScalar());
Console.WriteLine(
"Starting row count for Header table = {0}",
countStartHeader);

// Perform an initial count on the destination


// table with different column positions.
SqlCommand countRowDetail = new SqlCommand(
"SELECT COUNT(*) FROM dbo.BulkCopyDemoOrderDetail;",
connection);
long countStartDetail = System.Convert.ToInt32(
countRowDetail.ExecuteScalar());
Console.WriteLine(
"Starting row count for Detail table = {0}",
countStartDetail);

// Get data from the source table as a SqlDataReader.


// The Sales.SalesOrderHeader and Sales.SalesOrderDetail
// tables are quite large and could easily cause a timeout
// if all data from the tables is added to the destination.
// To keep the example simple and quick, a parameter is
// used to select only orders for a particular account
// as the source for the bulk insert.
SqlCommand headerData = new SqlCommand(
"SELECT [SalesOrderID], [OrderDate], " +
"[AccountNumber] FROM [Sales].[SalesOrderHeader] " +
"WHERE [AccountNumber] = @accountNumber;",
connection);
SqlParameter parameterAccount = new SqlParameter();
parameterAccount.ParameterName = "@accountNumber";
parameterAccount.SqlDbType = SqlDbType.NVarChar;
parameterAccount.Direction = ParameterDirection.Input;
parameterAccount.Value = "10-4020-000034";
headerData.Parameters.Add(parameterAccount);
SqlDataReader readerHeader = headerData.ExecuteReader();

// Get the Detail data in a separate connection.


using (SqlConnection connection2 = new SqlConnection(connectionString))
{
connection2.Open();
SqlCommand sourceDetailData = new SqlCommand(
"SELECT [Sales].[SalesOrderDetail].[SalesOrderID], [SalesOrderDetailID], " +
"[OrderQty], [ProductID], [UnitPrice] FROM [Sales].[SalesOrderDetail] " +
"INNER JOIN [Sales].[SalesOrderHeader] ON [Sales].[SalesOrderDetail]." +
"[SalesOrderID] = [Sales].[SalesOrderHeader].[SalesOrderID] " +
"WHERE [AccountNumber] = @accountNumber;", connection2);

SqlParameter accountDetail = new SqlParameter();


accountDetail.ParameterName = "@accountNumber";
accountDetail.SqlDbType = SqlDbType.NVarChar;
accountDetail.Direction = ParameterDirection.Input;
accountDetail.Value = "10-4020-000034";
sourceDetailData.Parameters.Add(accountDetail);
SqlDataReader readerDetail = sourceDetailData.ExecuteReader();

// Create the SqlBulkCopy object.


using (SqlBulkCopy bulkCopy =
new SqlBulkCopy(connectionString))
{
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoOrderHeader";

// Guarantee that columns are mapped correctly by


// defining the column mappings for the order.
bulkCopy.ColumnMappings.Add("SalesOrderID", "SalesOrderID");
bulkCopy.ColumnMappings.Add("OrderDate", "OrderDate");
bulkCopy.ColumnMappings.Add("AccountNumber", "AccountNumber");

// Write readerHeader to the destination.


try
{
bulkCopy.WriteToServer(readerHeader);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
readerHeader.Close();
}

// Set up the order details destination.


bulkCopy.DestinationTableName = "dbo.BulkCopyDemoOrderDetail";

// Clear the ColumnMappingCollection.


bulkCopy.ColumnMappings.Clear();

// Add order detail column mappings.


bulkCopy.ColumnMappings.Add("SalesOrderID", "SalesOrderID");
bulkCopy.ColumnMappings.Add("SalesOrderDetailID", "SalesOrderDetailID");
bulkCopy.ColumnMappings.Add("OrderQty", "OrderQty");
bulkCopy.ColumnMappings.Add("ProductID", "ProductID");
bulkCopy.ColumnMappings.Add("UnitPrice", "UnitPrice");

// Write readerDetail to the destination.


try
{
bulkCopy.WriteToServer(readerDetail);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
readerDetail.Close();
}
}

// Perform a final count on the destination


// tables to see how many rows were added.
long countEndHeader = System.Convert.ToInt32(
countRowHeader.ExecuteScalar());
Console.WriteLine("{0} rows were added to the Header table.",
countEndHeader - countStartHeader);
long countEndDetail = System.Convert.ToInt32(
countRowDetail.ExecuteScalar());
Console.WriteLine("{0} rows were added to the Detail table.",
countEndDetail - countStartDetail);
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}
}
}

private static string GetConnectionString()


// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
{
return "Data Source=(local); " +
" Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
}
}

Next steps
Bulk copy operations in SQL Server
Transaction and bulk copy operations
4/27/2022 • 11 minutes to read • Edit Online

Download ADO.NET
Bulk copy operations can be performed as isolated operations or as part of a multiple step transaction. This
latter option enables you to perform more than one bulk copy operation within the same transaction, as well as
perform other database operations such as inserts, updates, and deletes, while still being able to commit or roll
back the entire transaction.
By default, a bulk copy operation is done as an isolated operation. The bulk copy operation occurs in a non-
transacted way, with no opportunity for rolling it back. If you need to roll back all or part of the bulk copy when
an error occurs, you can:
Use a SqlBulkCopy-managed transaction
Do the bulk copy operation within an existing transaction
Enlist in a System.Transactions Transaction.

Performing a non-transacted bulk copy operation


The following Console application shows what happens when a non-transacted bulk copy operation encounters
an error partway through the operation.
In the example, the source table and destination table each include an Identity column named ProductID . The
code first prepares the destination table by deleting all rows and then inserting a single row whose ProductID
is known to exist in the source table. By default, a new value for the Identity column is generated in the
destination table for each row added. In this example, an option is set when the connection is opened that forces
the bulk load process to use the Identity values from the source table instead.
The bulk copy operation is executed with the BatchSize property set to 10. When the operation comes across the
invalid row, an exception is thrown. In this first example, the bulk copy operation is non-transacted. All batches
that are copied up to the point of the error are committed. The batch containing the duplicate key is rolled back,
and the bulk copy operation is halted before it processes any remaining batches.

NOTE
This sample will not run unless you have created the work tables as described in Bulk copy example setup. This code is
provided to demonstrate the syntax for using SqlBulkCopy only. If the source and destination tables are located in the
same SQL Server instance, it is easier and faster to use a Transact-SQL INSERT … SELECT statement to copy the data.

using Microsoft.Data.SqlClient;

class Program
{
static void Main()
{
string connectionString = GetConnectionString();
// Open a sourceConnection to the AdventureWorks database.
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
{
sourceConnection.Open();
sourceConnection.Open();

// Delete all from the destination table.


SqlCommand commandDelete = new SqlCommand();
commandDelete.Connection = sourceConnection;
commandDelete.CommandText =
"DELETE FROM dbo.BulkCopyDemoMatchingColumns";
commandDelete.ExecuteNonQuery();

// Add a single row that will result in duplicate key


// when all rows from source are bulk copied.
// Note that this technique will only be successful in
// illustrating the point if a row with ProductID = 446
// exists in the AdventureWorks Production.Products table.
// If you have made changes to the data in this table, change
// the SQL statement in the code to add a ProductID that
// does exist in your version of the Production.Products
// table. Choose any ProductID in the middle of the table
// (not first or last row) to best illustrate the result.
SqlCommand commandInsert = new SqlCommand();
commandInsert.Connection = sourceConnection;
commandInsert.CommandText =
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns ON;" +
"INSERT INTO " + "dbo.BulkCopyDemoMatchingColumns " +
"([ProductID], [Name] ,[ProductNumber]) " +
"VALUES(446, 'Lock Nut 23','LN-3416');" +
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns OFF";
commandInsert.ExecuteNonQuery();

// Perform an initial count on the destination table.


SqlCommand commandRowCount = new SqlCommand(
"SELECT COUNT(*) FROM dbo.BulkCopyDemoMatchingColumns;",
sourceConnection);
long countStart = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count = {0}", countStart);

// Get data from the source table as a SqlDataReader.


SqlCommand commandSourceData = new SqlCommand(
"SELECT ProductID, Name, ProductNumber " +
"FROM Production.Product;", sourceConnection);
SqlDataReader reader = commandSourceData.ExecuteReader();

// Set up the bulk copy object using the KeepIdentity option.


using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
connectionString, SqlBulkCopyOptions.KeepIdentity))
{
bulkCopy.BatchSize = 10;
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoMatchingColumns";

// Write from the source to the destination.


// This should fail with a duplicate key error
// after some of the batches have been copied.
try
{
bulkCopy.WriteToServer(reader);
}
catch (Exception ex)
{
// Print the number of rows processed using the
// RowsCopied property.
Console.WriteLine("{0} rows were processed.",
bulkCopy.RowsCopied);
Console.WriteLine(ex.Message);
}
finally
{
reader.Close();
}
}
}

// Perform a final count on the destination


// table to see how many rows were added.
// Note that for this scenario, the value will
// not be equal to the RowsCopied property.
long countEnd = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Ending row count = {0}", countEnd);
Console.WriteLine("{0} rows were added.", countEnd - countStart);
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}
}

private static string GetConnectionString()


// To avoid storing the sourceConnection string in your code,
// you can retrieve it from a configuration file.
{
return "Data Source=(local); " +
" Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
}

Performing a dedicated bulk copy operation in a transaction


By default, a bulk copy operation is its own transaction. When you want to perform a dedicated bulk copy
operation, create an instance of SqlBulkCopy with a connection string, or use an existing SqlConnection object
without an active transaction. The bulk copy operation creates a transaction in each scenario and then commits
or rolls back the transaction.
You can explicitly specify the UseInternalTransaction option in the SqlBulkCopy class constructor to execute a
bulk copy operation in its own transaction. Each batch of the operation will execute within a separate
transaction.

NOTE
Since different batches are executed in different transactions, if an error occurs during the bulk copy operation, all the
rows in the current batch will be rolled back, but rows from previous batches will remain in the database.

The following console application is similar to the previous example, with one exception: In this example, the
bulk copy operation manages its own transactions. All batches that are copied up to the point of the error are
committed. The batch containing the duplicate key is rolled back, and the bulk copy operation is halted before it
processes any remaining batches.

IMPORTANT
This sample will not run unless you have created the work tables as described in Bulk copy example setup. This code is
provided to demonstrate the syntax for using SqlBulkCopy only. If the source and destination tables are located in the
same SQL Server instance, it is easier and faster to use a Transact-SQL INSERT … SELECT statement to copy the data.

using Microsoft.Data.SqlClient;

class Program
{
static void Main()
{
string connectionString = GetConnectionString();
string connectionString = GetConnectionString();
// Open a sourceConnection to the AdventureWorks database.
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
{
sourceConnection.Open();

// Delete all from the destination table.


SqlCommand commandDelete = new SqlCommand();
commandDelete.Connection = sourceConnection;
commandDelete.CommandText =
"DELETE FROM dbo.BulkCopyDemoMatchingColumns";
commandDelete.ExecuteNonQuery();

// Add a single row that will result in duplicate key


// when all rows from source are bulk copied.
// Note that this technique will only be successful in
// illustrating the point if a row with ProductID = 446
// exists in the AdventureWorks Production.Products table.
// If you have made changes to the data in this table, change
// the SQL statement in the code to add a ProductID that
// does exist in your version of the Production.Products
// table. Choose any ProductID in the middle of the table
// (not first or last row) to best illustrate the result.
SqlCommand commandInsert = new SqlCommand();
commandInsert.Connection = sourceConnection;
commandInsert.CommandText =
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns ON;" +
"INSERT INTO " + "dbo.BulkCopyDemoMatchingColumns " +
"([ProductID], [Name] ,[ProductNumber]) " +
"VALUES(446, 'Lock Nut 23','LN-3416');" +
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns OFF";
commandInsert.ExecuteNonQuery();

// Perform an initial count on the destination table.


SqlCommand commandRowCount = new SqlCommand(
"SELECT COUNT(*) FROM dbo.BulkCopyDemoMatchingColumns;",
sourceConnection);
long countStart = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count = {0}", countStart);

// Get data from the source table as a SqlDataReader.


SqlCommand commandSourceData = new SqlCommand(
"SELECT ProductID, Name, ProductNumber " +
"FROM Production.Product;", sourceConnection);
SqlDataReader reader = commandSourceData.ExecuteReader();

// Set up the bulk copy object.


// Note that when specifying the UseInternalTransaction
// option, you cannot also specify an external transaction.
// Therefore, you must use the SqlBulkCopy construct that
// requires a string for the connection, rather than an
// existing SqlConnection object.
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
connectionString, SqlBulkCopyOptions.KeepIdentity |
SqlBulkCopyOptions.UseInternalTransaction))
{
bulkCopy.BatchSize = 10;
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoMatchingColumns";

// Write from the source to the destination.


// This should fail with a duplicate key error
// after some of the batches have been copied.
try
{
bulkCopy.WriteToServer(reader);
}
catch (Exception ex)
{
// Print the number of rows processed using the
// RowsCopied property.
Console.WriteLine("{0} rows were processed.",
bulkCopy.RowsCopied);
Console.WriteLine(ex.Message);
}
finally
{
reader.Close();
}
}

// Perform a final count on the destination


// table to see how many rows were added.
// Note that for this scenario, the value will
// not be equal to the RowsCopied property.
long countEnd = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Ending row count = {0}", countEnd);
Console.WriteLine("{0} rows were added.", countEnd - countStart);
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}
}

private static string GetConnectionString()


// To avoid storing the sourceConnection string in your code,
// you can retrieve it from a configuration file.
{
return "Data Source=(local); " +
" Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
}

Using existing transactions


You can specify an existing SqlTransaction object as a parameter in a SqlBulkCopy constructor. In this situation,
the bulk copy operation is done in the existing transaction, and no change is made to the transaction state - it is
not committed or aborted. This method allows an application to include the bulk copy operation in a transaction
with other database operations. However, if you do not specify a SqlTransaction object and pass a null reference,
and the connection has an active transaction, an exception is thrown.
If you need to roll back the entire bulk copy operation because an error occurs, or if the bulk copy should
execute as part of a larger process that can be rolled back, you can provide a SqlTransaction object to the
SqlBulkCopy constructor.
The following console application is similar to the first (non-transacted) example, with one exception: in this
example, the bulk copy operation is included in a larger, external transaction. When the primary key violation
error occurs, the entire transaction is rolled back and no rows are added to the destination table.

IMPORTANT
This sample will not run unless you have created the work tables as described in Bulk copy example setup. This code is
provided to demonstrate the syntax for using SqlBulkCopy only. If the source and destination tables are located in the
same SQL Server instance, it is easier and faster to use a Transact-SQL INSERT … SELECT statement to copy the data.

using Microsoft.Data.SqlClient;
class Program
{
static void Main()
{
string connectionString = GetConnectionString();
// Open a sourceConnection to the AdventureWorks database.
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
{
sourceConnection.Open();

// Delete all from the destination table.


SqlCommand commandDelete = new SqlCommand();
commandDelete.Connection = sourceConnection;
commandDelete.CommandText =
"DELETE FROM dbo.BulkCopyDemoMatchingColumns";
commandDelete.ExecuteNonQuery();

// Add a single row that will result in duplicate key


// when all rows from source are bulk copied.
// Note that this technique will only be successful in
// illustrating the point if a row with ProductID = 446
// exists in the AdventureWorks Production.Products table.
// If you have made changes to the data in this table, change
// the SQL statement in the code to add a ProductID that
// does exist in your version of the Production.Products
// table. Choose any ProductID in the middle of the table
// (not first or last row) to best illustrate the result.
SqlCommand commandInsert = new SqlCommand();
commandInsert.Connection = sourceConnection;
commandInsert.CommandText =
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns ON;" +
"INSERT INTO " + "dbo.BulkCopyDemoMatchingColumns " +
"([ProductID], [Name] ,[ProductNumber]) " +
"VALUES(446, 'Lock Nut 23','LN-3416');" +
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns OFF";
commandInsert.ExecuteNonQuery();

// Perform an initial count on the destination table.


SqlCommand commandRowCount = new SqlCommand(
"SELECT COUNT(*) FROM dbo.BulkCopyDemoMatchingColumns;",
sourceConnection);
long countStart = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count = {0}", countStart);

// Get data from the source table as a SqlDataReader.


SqlCommand commandSourceData = new SqlCommand(
"SELECT ProductID, Name, ProductNumber " +
"FROM Production.Product;", sourceConnection);
SqlDataReader reader = commandSourceData.ExecuteReader();

//Set up the bulk copy object inside the transaction.


using (SqlConnection destinationConnection =
new SqlConnection(connectionString))
{
destinationConnection.Open();

using (SqlTransaction transaction =


destinationConnection.BeginTransaction())
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
destinationConnection, SqlBulkCopyOptions.KeepIdentity,
transaction))
{
bulkCopy.BatchSize = 10;
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoMatchingColumns";
// Write from the source to the destination.
// This should fail with a duplicate key error.
try
{
bulkCopy.WriteToServer(reader);
transaction.Commit();
}
catch (Exception ex)
{
// Print the number of rows processed using the
// RowsCopied property.
Console.WriteLine("{0} rows were processed.",
bulkCopy.RowsCopied);
Console.WriteLine(ex.Message);
transaction.Rollback();
}
finally
{
reader.Close();
}
}
}
}

// Perform a final count on the destination


// table to see how many rows were added.
long countEnd = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Ending row count = {0}", countEnd);
Console.WriteLine("{0} rows were added.", countEnd - countStart);
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}
}

private static string GetConnectionString()


// To avoid storing the sourceConnection string in your code,
// you can retrieve it from a configuration file.
{
return "Data Source=(local); " +
" Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
}

Next steps
Bulk copy operations in SQL Server
Order hints for bulk copy operations
4/27/2022 • 2 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Bulk copy operations offer significant performance advantages over other methods for loading data into a SQL
Server table. Performance can be further enhanced by using order hints. Specifying order hints for your bulk
copy operations can lower the insertion time of sorted data into tables with clustered indexes.
By default, the bulk insert operation assumes the incoming data is unordered. SQL Server forces an
intermediate sort of this data before bulk loading it. If you know your incoming data is already sorted, you can
use order hints to tell the bulk copy operation about the sort order of any destination columns that are part of a
clustered index.

Adding order hints to a bulk copy operation


The following example bulk copies data from a source table in the AdventureWorks sample database to a
destination table in the same database. A SqlBulkCopyColumnOrderHint object is created to define the sort
order for the ProductNumber column in the destination table. The order hint is then added to the SqlBulkCopy
instance, which will append the appropriate order hint argument to the resulting INSERT BULK query.

using System;
using System.Data;
using Microsoft.Data.SqlClient;

class Program
{
static void Main()
{
string connectionString = GetConnectionString();
// Open a sourceConnection to the AdventureWorks database.
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
{
sourceConnection.Open();

// Perform an initial count on the destination table.


SqlCommand commandRowCount = new SqlCommand(
"SELECT COUNT(*) FROM " +
"dbo.BulkCopyDemoMatchingColumns;",
sourceConnection);
long countStart = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count = {0}", countStart);

// Get data from the source table as a SqlDataReader.


SqlCommand commandSourceData = new SqlCommand(
"SELECT ProductID, Name, " +
"ProductNumber " +
"FROM Production.Product;", sourceConnection);
SqlDataReader reader =
commandSourceData.ExecuteReader();

// Set up the bulk copy object.


using (SqlBulkCopy bulkCopy =
new SqlBulkCopy(connectionString))
{
{
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoMatchingColumns";

// Setup an order hint for the ProductNumber column.


SqlBulkCopyColumnOrderHint hintNumber =
new SqlBulkCopyColumnOrderHint("ProductNumber", SortOrder.Ascending);
bulkCopy.ColumnOrderHints.Add(hintNumber);

// Write from the source to the destination.


try
{
bulkCopy.WriteToServer(reader);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// Close the SqlDataReader. The SqlBulkCopy
// object is automatically closed at the end
// of the using block.
reader.Close();
}
}

// Perform a final count on the destination


// table to see how many rows were added.
long countEnd = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Ending row count = {0}", countEnd);
Console.WriteLine("{0} rows were added.", countEnd - countStart);
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}
}

private static string GetConnectionString()


// To avoid storing the sourceConnection string in your code,
// you can retrieve it from a configuration file.
{
return "Data Source=(local); " +
" Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
}

Next steps
Bulk copy operations in SQL Server
Multiple Active Result Sets (MARS)
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Multiple Active Result Sets (MARS) is a feature that allows the execution of multiple batches on a single
connection. In previous versions, only one batch could be executed at a time against a single connection.
Executing multiple batches with MARS does not imply simultaneous execution of operations.

In this section
Enabling Multiple Active Result Sets
Discusses how to use MARS with SQL Server.
Manipulating data
Provides examples of coding MARS applications.

Related sections
Asynchronous operations
Provides details on using the new asynchronous features in .NET.

Next steps
SQL Server and ADO.NET
Enabling Multiple Active Result Sets
4/27/2022 • 4 minutes to read • Edit Online

Download ADO.NET
Multiple Active Result Sets (MARS) is a feature that works with SQL Server to allow the execution of multiple
batches on a single connection. When MARS is enabled for use with SQL Server, each command object used
adds a session to the connection.

NOTE
A single MARS session opens one logical connection for MARS to use and then one logical connection for each active
command.

Enabling and disabling MARS in the connection string


NOTE
The following connection strings use the sample AdventureWorks database included with SQL Server. The connection
strings provided assume that the database is installed on a server named MSSQL1. Modify the connection string as
necessary for your environment.

The MARS feature is disabled by default. It can be enabled by adding the "MultipleActiveResultSets=True"
keyword pair to your connection string. "True" is the only valid value for enabling MARS. The following example
demonstrates how to connect to an instance of SQL Server and how to specify that MARS should be enabled.

string connectionString = "Data Source=MSSQL1;" +


"Initial Catalog=AdventureWorks;Integrated Security=SSPI;" +
"MultipleActiveResultSets=True";

You can disable MARS by adding the "MultipleActiveResultSets=False" keyword pair to your connection string.
"False" is the only valid value for disabling MARS. The following connection string demonstrates how to disable
MARS.

string connectionString = "Data Source=MSSQL1;" +


"Initial Catalog=AdventureWorks;Integrated Security=SSPI;" +
"MultipleActiveResultSets=False";

Special considerations when using MARS


In general, existing applications should not need modification to use a MARS-enabled connection. However, if
you wish to use MARS features in your applications, you should understand the following special
considerations.
Statement interleaving
MARS operations execute synchronously on the server. Statement interleaving of SELECT and BULK INSERT
statements is allowed. However, data manipulation language (DML) and data definition language (DDL)
statements execute atomically. Any statements attempting to execute while an atomic batch is executing are
blocked. Parallel execution at the server is not a MARS feature.
If two batches are submitted under a MARS connection, one of them containing a SELECT statement, the other
containing a DML statement, the DML can begin execution within execution of the SELECT statement. However,
the DML statement must run to completion before the SELECT statement can make progress. If both statements
are running under the same transaction, any changes made by a DML statement after the SELECT statement has
started execution are not visible to the read operation.
A WAITFOR statement inside a SELECT statement does not yield the transaction while it is waiting, that is, until
the first row is produced. This implies that no other batches can execute within the same connection while a
WAITFOR statement is waiting.
MARS session cache
When a connection is opened with MARS enabled, a logical session is created, which adds additional overhead.
To minimize overhead and enhance performance, SqlClient caches the MARS session within a connection. The
cache contains at most 10 MARS sessions. This value is not user adjustable. If the session limit is reached, a new
session is created—an error is not generated. The cache and sessions contained in it are per-connection; they are
not shared across connections. When a session is released, it is returned to the pool unless the pool's upper limit
has been reached. If the cache pool is full, the session is closed. MARS sessions do not expire. They are only
cleaned up when the connection object is disposed. The MARS session cache is not preloaded. It is loaded as the
application requires more sessions.
Thread safety
MARS operations are not thread-safe.
Connection pooling
MARS-enabled connections are pooled like any other connection. If an application opens two connections, one
with MARS enabled and one with MARS disabled, the two connections are in separate pools.
SQL Server batch execution environment
When a connection is opened, a default environment is defined. This environment is then copied into a logical
MARS session.
The batch execution environment includes the following components:
Set options (for example, ANSI_NULLS, DATE_FORMAT, LANGUAGE, TEXTSIZE)
Security context (user/application role)
Database context (current database)
Execution state variables (for example, @@ERROR, @@ROWCOUNT, @@FETCH_STATUS @@IDENTITY)
Top-level temporary tables
With MARS, a default execution environment is associated to a connection. Every new batch that starts
executing under a given connection receives a copy of the default environment. Whenever code is executed
under a given batch, all changes made to the environment are scoped to the specific batch. Once execution
finishes, the execution settings are copied into the default environment. In the case of a single batch issuing
several commands to be executed sequentially under the same transaction, semantics are the same as those
exposed by connections involving earlier clients or servers.
Parallel execution
MARS is not designed to remove all requirements for multiple connections in an application. If an application
needs true parallel execution of commands against a server, multiple connections should be used.
For example, consider the following scenario. Two command objects are created, one for processing a result set
and another for updating data; they share a common connection via MARS. In this scenario, the Transaction .
Commit fails on the update until all the results have been read on the first command object, yielding the
following exception:
Message: Transaction context in use by another session.
Source: Microsoft SqlClient Data Provider
Expected: (null)
Received: Microsoft.Data.SqlClient.SqlException
There are three options for handling this scenario:
Start the transaction after the reader is created, so that it is not part of the transaction. Every update then
becomes its own transaction.
Commit all work after the reader is closed. This has the potential for a substantial batch of updates.
Don't use MARS; instead use a separate connection for each command object as you would have before
MARS.
Detecting MARS support
An application can check for MARS support by reading the SqlConnection.ServerVersion value. The major
number should be 9 for SQL Server 2005 and 10 for SQL Server 2008.

Next steps
Multiple Active Result Sets (MARS)
Manipulating data
4/27/2022 • 4 minutes to read • Edit Online

Download ADO.NET
Before the introduction of Multiple Active Result Sets (MARS), developers had to use either multiple connections
or server-side cursors to solve certain scenarios. In addition, when multiple connections were used in a
transactional situation, bound connections (with sp_getbindtoken and sp_bindsession ) were required. The
following scenarios show how to use a MARS-enabled connection instead of multiple connections.

Using multiple commands with MARS


The following Console application demonstrates how to use two SqlDataReader objects with two SqlCommand
objects and a single SqlConnection object with MARS enabled.
Example
The example opens a single connection to the AdventureWorks database. Using a SqlCommand object, a
SqlDataReader is created. As the reader is used, a second SqlDataReader is opened, using data from the first
SqlDataReader as input to the WHERE clause for the second reader.

NOTE
The following example uses the sample AdventureWorks database included with SQL Server. The connection string
provided in the sample code assumes that the database is installed and available on the local computer. Modify the
connection string as necessary for your environment.

using System;
using System.Data;
using Microsoft.Data.SqlClient;

class Class1
{
static void Main()
{
// By default, MARS is disabled when connecting
// to a MARS-enabled host.
// It must be enabled in the connection string.
string connectionString = GetConnectionString();

int vendorID;
SqlDataReader productReader = null;
string vendorSQL =
"SELECT VendorId, Name FROM Purchasing.Vendor";
string productSQL =
"SELECT Production.Product.Name FROM Production.Product " +
"INNER JOIN Purchasing.ProductVendor " +
"ON Production.Product.ProductID = " +
"Purchasing.ProductVendor.ProductID " +
"WHERE Purchasing.ProductVendor.VendorID = @VendorId";

using (SqlConnection awConnection =


new SqlConnection(connectionString))
{
SqlCommand vendorCmd = new SqlCommand(vendorSQL, awConnection);
SqlCommand productCmd =
new SqlCommand(productSQL, awConnection);
new SqlCommand(productSQL, awConnection);

productCmd.Parameters.Add("@VendorId", SqlDbType.Int);

awConnection.Open();
using (SqlDataReader vendorReader = vendorCmd.ExecuteReader())
{
while (vendorReader.Read())
{
Console.WriteLine(vendorReader["Name"]);

vendorID = (int)vendorReader["VendorId"];

productCmd.Parameters["@VendorId"].Value = vendorID;
// The following line of code requires
// a MARS-enabled connection.
productReader = productCmd.ExecuteReader();
using (productReader)
{
while (productReader.Read())
{
Console.WriteLine(" " +
productReader["Name"].ToString());
}
}
}
}
Console.WriteLine("Press any key to continue");
Console.ReadLine();
}
}
private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=(local);Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks;MultipleActiveResultSets=True";
}
}

Reading and updating data with MARS


MARS allows a connection to be used for both read operations and data manipulation language (DML)
operations with more than one pending operation. This feature eliminates the need for an application to deal
with connection-busy errors. In addition, MARS can replace the user of server-side cursors, which generally
consume more resources. Finally, because multiple operations can operate on a single connection, they can
share the same transaction context, eliminating the need to use sp_getbindtoken and sp_bindsession system
stored procedures.
Example
The following Console application demonstrates how to use two SqlDataReader objects with three SqlCommand
objects and a single SqlConnection object with MARS enabled. The first command object retrieves a list of
vendors whose credit rating is 5. The second command object uses the vendor ID provided from a
SqlDataReader to load the second SqlDataReader with all of the products for the particular vendor. Each product
record is visited by the second SqlDataReader. A calculation is performed to determine what the new
OnOrderQty should be. The third command object is then used to update the ProductVendor table with the
new value. This entire process takes place within a single transaction, which is rolled back at the end.
NOTE
The following example uses the sample AdventureWorks database included with SQL Server. The connection string
provided in the sample code assumes that the database is installed and available on the local computer. Modify the
connection string as necessary for your environment.

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Microsoft.Data.SqlClient;

class Program
{
static void Main()
{
// By default, MARS is disabled when connecting
// to a MARS-enabled host.
// It must be enabled in the connection string.
string connectionString = GetConnectionString();

SqlTransaction updateTx = null;


SqlCommand vendorCmd = null;
SqlCommand prodVendCmd = null;
SqlCommand updateCmd = null;

SqlDataReader prodVendReader = null;

int vendorID = 0;
int productID = 0;
int minOrderQty = 0;
int maxOrderQty = 0;
int onOrderQty = 0;
int recordsUpdated = 0;
int totalRecordsUpdated = 0;

string vendorSQL =
"SELECT VendorID, Name FROM Purchasing.Vendor " +
"WHERE CreditRating = 5";
string prodVendSQL =
"SELECT ProductID, MaxOrderQty, MinOrderQty, OnOrderQty " +
"FROM Purchasing.ProductVendor " +
"WHERE VendorID = @VendorID";
string updateSQL =
"UPDATE Purchasing.ProductVendor " +
"SET OnOrderQty = @OrderQty " +
"WHERE ProductID = @ProductID AND VendorID = @VendorID";

using (SqlConnection awConnection =


new SqlConnection(connectionString))
{
awConnection.Open();
updateTx = awConnection.BeginTransaction();

vendorCmd = new SqlCommand(vendorSQL, awConnection);


vendorCmd.Transaction = updateTx;

prodVendCmd = new SqlCommand(prodVendSQL, awConnection);


prodVendCmd.Transaction = updateTx;
prodVendCmd.Parameters.Add("@VendorId", SqlDbType.Int);

updateCmd = new SqlCommand(updateSQL, awConnection);


updateCmd.Transaction = updateTx;
updateCmd.Parameters.Add("@OrderQty", SqlDbType.Int);
updateCmd.Parameters.Add("@ProductID", SqlDbType.Int);
updateCmd.Parameters.Add("@VendorID", SqlDbType.Int);
updateCmd.Parameters.Add("@VendorID", SqlDbType.Int);

using (SqlDataReader vendorReader = vendorCmd.ExecuteReader())


{
while (vendorReader.Read())
{
Console.WriteLine(vendorReader["Name"]);

vendorID = (int) vendorReader["VendorID"];


prodVendCmd.Parameters["@VendorID"].Value = vendorID;
prodVendReader = prodVendCmd.ExecuteReader();

using (prodVendReader)
{
while (prodVendReader.Read())
{
productID = (int) prodVendReader["ProductID"];

if (prodVendReader["OnOrderQty"] == DBNull.Value)
{
minOrderQty = (int) prodVendReader["MinOrderQty"];
onOrderQty = minOrderQty;
}
else
{
maxOrderQty = (int) prodVendReader["MaxOrderQty"];
onOrderQty = (int)(maxOrderQty / 2);
}

updateCmd.Parameters["@OrderQty"].Value = onOrderQty;
updateCmd.Parameters["@ProductID"].Value = productID;
updateCmd.Parameters["@VendorID"].Value = vendorID;

recordsUpdated = updateCmd.ExecuteNonQuery();
totalRecordsUpdated += recordsUpdated;
}
}
}
}
Console.WriteLine("Total Records Updated: " +
totalRecordsUpdated.ToString());
updateTx.Rollback();
Console.WriteLine("Transaction Rolled Back");
}

Console.WriteLine("Press any key to continue");


Console.ReadLine();
}
private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=(local);Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks;" +
"MultipleActiveResultSets=True";
}
}

Next steps
Multiple Active Result Sets (MARS)
Asynchronous operations
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Some database operations, such as command executions, can take significant time to complete. In such a case,
single-threaded applications must block other operations and wait for the command to finish before they can
continue their own operations. In contrast, being able to assign the long-running operation to a background
thread allows the foreground thread to remain active throughout the operation. In a Windows application, for
example, delegating the long-running operation to a background thread allows the user interface thread to
remain responsive while the operation is executing.
The .NET provides several standard asynchronous design patterns that developers can use to take advantage of
background threads and free the user interface or high-priority threads to complete other operations in its
SqlCommand class. Specifically, the BeginExecuteNonQuery, BeginExecuteReader, and BeginExecuteXmlReader
methods, paired with the EndExecuteNonQuery, EndExecuteReader, and EndExecuteXmlReader methods,
provide the asynchronous support.

NOTE
Asynchronous programming is a core feature of the .NET. For more information about the different asynchronous
techniques available to developers, see Calling Synchronous Methods Asynchronously.

Although using asynchronous techniques with ADO.NET features does not add any special considerations, it is
important to be aware of the benefits and pitfalls of creating multithreaded applications. The examples that
follow in this section point out several important issues that developers will need to take into account when
building applications that incorporate multithreaded functionality.

In this section
Windows applications using callbacks
Provides an example demonstrating how to execute an asynchronous command safely, correctly handling
interaction with a form and its contents from a separate thread.
ASP.NET applications using wait handles
Provides an example demonstrating how to execute multiple concurrent commands from an ASP.NET page,
using Wait handles to manage the operation at completion of all the commands.
Polling in console applications
Provides an example demonstrating the use of polling to wait for the completion of an asynchronous command
execution from a console application. This technique is also valid in a class library or other application without a
user interface.

Next steps
SQL Server and ADO.NET
Calling Synchronous Methods Asynchronously
Windows applications using callbacks
4/27/2022 • 5 minutes to read • Edit Online

Download ADO.NET
In most asynchronous processing scenarios, you want to start a database operation and continue running other
processes without waiting for the database operation to complete. However, many scenarios require doing
something once the database operation has ended. In a Windows application, for example, you may want to
delegate the long-running operation to a background thread while allowing the user interface thread to remain
responsive. However, when the database operation is complete, you want to use the results to populate the
form. This type of scenario is best implemented with a callback.
You define a callback by specifying an AsyncCallback delegate in the BeginExecuteNonQuery,
BeginExecuteReader, or BeginExecuteXmlReader method. The delegate is called when the operation is complete.
You can pass the delegate a reference to the SqlCommand itself, making it easy to access the SqlCommand
object and call the appropriate End method without having to use a global variable.

Example
The following Windows application demonstrates the use of the BeginExecuteNonQuery method, executing a
Transact-SQL statement that includes a delay of a few seconds (emulating a long-running command).
This example demonstrates a number of important techniques, including calling a method that interacts with the
form from a separate thread. In addition, this example demonstrates how you must block users from
concurrently executing a command multiple times, and how you must ensure that the form does not close
before the callback procedure is called.
To set up this example, create a new Windows application. Place a Button control and two Label controls on the
form (accepting the default name for each control). Add the following code to the form's class, modifying the
connection string as necessary for your environment.

// Add these to the top of the class, if they're not already there:
using System;
using System.Data;
using Microsoft.Data.SqlClient;

// Hook up the form's Load event handler (you can double-click on


// the form's design surface in Visual Studio), and then add
// this code to the form's class:

// You'll need this delegate in order to display text from a thread


// other than the form's thread. See the HandleCallback
// procedure for more information.
// This same delegate matches both the DisplayStatus
// and DisplayResults methods.
private delegate void DisplayInfoDelegate(string Text);

// This flag ensures that the user doesn't attempt


// to restart the command or close the form while the
// asynchronous command is executing.
private bool isExecuting;

// This example maintains the connection object


// externally, so that it's available for closing.
private SqlConnection connection;

private static string GetConnectionString()


private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.

// If you have not included "Asynchronous Processing=true" in the


// connection string, the command will not be able
// to execute asynchronously.
return "Data Source=(local);Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks; Asynchronous Processing=true";
}

private void DisplayStatus(string Text)


{
this.label1.Text = Text;
}

private void DisplayResults(string Text)


{
this.label1.Text = Text;
DisplayStatus("Ready");
}

private void Form1_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)


{
if (isExecuting)
{
MessageBox.Show(this, "Can't close the form until " +
"the pending asynchronous command has completed. Please " +
"wait...");
e.Cancel = true;
}
}

private void button1_Click(object sender, System.EventArgs e)


{
if (isExecuting)
{
MessageBox.Show(this, "Already executing. Please wait until " +
"the current query has completed.");
}
else
{
SqlCommand command = null;
try
{
DisplayResults("");
DisplayStatus("Connecting...");
connection = new SqlConnection(GetConnectionString());
// To emulate a long-running query, wait for
// a few seconds before working with the data.
// This command doesn't do much, but that's the point--
// it doesn't change your data, in the long run.
string commandText =
"WAITFOR DELAY '0:0:05';" +
"UPDATE Production.Product " +
"SET ReorderPoint = ReorderPoint + 1 " +
"WHERE ReorderPoint Is Not Null;" +
"UPDATE Production.Product " +
"SET ReorderPoint = ReorderPoint - 1 " +
"WHERE ReorderPoint Is Not Null";

command = new SqlCommand(commandText, connection);


connection.Open();

DisplayStatus("Executing...");
isExecuting = true;
// Although it's not required that you pass the
// SqlCommand object as the second parameter in the
// BeginExecuteNonQuery call, doing so makes it easier
// to call EndExecuteNonQuery in the callback procedure.
AsyncCallback callback = new AsyncCallback(HandleCallback);

// Once the BeginExecuteNonQuery method is called,


// the code continues--and the user can interact with
// the form--while the server executes the query.
command.BeginExecuteNonQuery(callback, command);

}
catch (Exception ex)
{
isExecuting = false;
DisplayStatus($"Ready (last error: {ex.Message})");
if (connection != null)
{
connection.Close();
}
}
}
}

private void HandleCallback(IAsyncResult result)


{
try
{
// Retrieve the original command object, passed
// to this procedure in the AsyncState property
// of the IAsyncResult parameter.
SqlCommand command = (SqlCommand)result.AsyncState;
int rowCount = command.EndExecuteNonQuery(result);
string rowText = " rows affected.";
if (rowCount == 1)
{
rowText = " row affected.";
}
rowText = rowCount + rowText;

// You may not interact with the form and its contents
// from a different thread, and this callback procedure
// is all but guaranteed to be running from a different thread
// than the form. Therefore you cannot simply call code that
// displays the results, like this:
// DisplayResults(rowText)

// Instead, you must call the procedure from the form's thread.
// One simple way to accomplish this is to call the Invoke
// method of the form, which calls the delegate you supply
// from the form's thread.
DisplayInfoDelegate del =
new DisplayInfoDelegate(DisplayResults);
this.Invoke(del, rowText);
}
catch (Exception ex)
{
// Because you're now running code in a separate thread,
// if you don't handle the exception here, none of your other
// code will catch the exception. Because none of your
// code is on the call stack in this thread, there's nothing
// higher up the stack to catch the exception if you don't
// handle it here. You can either log the exception or
// invoke a delegate (as in the non-error case in this
// example) to display the error on the form. In no case
// can you simply display the error without executing a
// delegate as in the try block here.

// You can create the delegate instance as you


// invoke it, like this:
this.Invoke(new DisplayInfoDelegate(DisplayStatus),
$"Ready (last error: {ex.Message}");
}
finally
{
isExecuting = false;
if (connection != null)
{
connection.Close();
}
}
}

private void Form1_Load(object sender, System.EventArgs e)


{
this.button1.Click += new System.EventHandler(this.button1_Click);
this.FormClosing += new System.Windows.Forms.
FormClosingEventHandler(this.Form1_FormClosing);
}

Next steps
Asynchronous operations
ASP.NET applications using wait handles
4/27/2022 • 7 minutes to read • Edit Online

Download ADO.NET
The callback and polling models for handling asynchronous operations are useful when your application is
processing only one asynchronous operation at a time. The Wait models provide a more flexible way of
processing multiple asynchronous operations. There are two Wait models, named for the WaitHandle methods
used to implement them: the Wait (Any) model and the Wait (All) model.
To use either Wait model, you need to use the AsyncWaitHandle property of the IAsyncResult object returned by
the BeginExecuteNonQuery, BeginExecuteReader, or BeginExecuteXmlReader methods. The WaitAny and WaitAll
methods both require you to send the WaitHandle objects as an argument, grouped together in an array.
Both Wait methods monitor the asynchronous operations, waiting for completion. The WaitAny method waits
for any of the operations to complete or time out. Once you know a particular operation is complete, you can
process its results and then continue waiting for the next operation to complete or time out. The WaitAll method
waits for all of the processes in the array of WaitHandle instances to complete or time out before continuing.
The Wait models' benefit is most striking when you need to run multiple operations of some length on different
servers, or when your server is powerful enough to process all the queries at the same time. In the examples
presented here, three queries emulate long processes by adding WAITFOR commands of varying lengths to
inconsequential SELECT queries.

Example: Wait (Any) model


The following example illustrates the Wait (Any) model. Once three asynchronous processes are started, the
WaitAny method is called to wait for the completion of any one of them. As each process completes, the
EndExecuteReader method is called and the resulting SqlDataReader object is read. At this point, a real-world
application would likely use the SqlDataReader to populate a portion of the page. In this simple example, the
time the process completed is added to a text box corresponding to the process. Taken together, the times in the
text boxes illustrate the point: Code is executed each time a process completes.
To set up this example, create a new ASP.NET Web Site project. Place a Button control and four TextBox controls
on the page (accepting the default name for each control).
Add the following code to the form's class, modifying the connection string as necessary for your environment.

// Add the following using statements, if they are not already there.
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Threading;
using Microsoft.Data.SqlClient;

// Add this code to the page's class


string GetConnectionString()
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
// If you have not included "Asynchronous Processing=true"
// If you have not included "Asynchronous Processing=true"
// in the connection string, the command will not be able
// to execute asynchronously.
{
return "Data Source=(local);Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks;" +
"Asynchronous Processing=true";
}
void Button1_Click(object sender, System.EventArgs e)
{
// In a real-world application, you might be connecting to
// three different servers or databases. For the example,
// we connect to only one.

SqlConnection connection1 =
new SqlConnection(GetConnectionString());
SqlConnection connection2 =
new SqlConnection(GetConnectionString());
SqlConnection connection3 =
new SqlConnection(GetConnectionString());
// To keep the example simple, all three asynchronous
// processes select a row from the same table. WAITFOR
// commands are used to emulate long-running processes
// that complete after different periods of time.

string commandText1 = "WAITFOR DELAY '0:0:01';" +


"SELECT * FROM Production.Product " +
"WHERE ProductNumber = 'BL-2036'";
string commandText2 = "WAITFOR DELAY '0:0:05';" +
"SELECT * FROM Production.Product " +
"WHERE ProductNumber = 'BL-2036'";
string commandText3 = "WAITFOR DELAY '0:0:10';" +
"SELECT * FROM Production.Product " +
"WHERE ProductNumber = 'BL-2036'";
try
// For each process, open a connection and begin
// execution. Use the IAsyncResult object returned by
// BeginExecuteReader to add a WaitHandle for the
// process to the array.
{
connection1.Open();
SqlCommand command1 =
new SqlCommand(commandText1, connection1);
IAsyncResult result1 = command1.BeginExecuteReader();
WaitHandle waitHandle1 = result1.AsyncWaitHandle;

connection2.Open();
SqlCommand command2 =
new SqlCommand(commandText2, connection2);
IAsyncResult result2 = command2.BeginExecuteReader();
WaitHandle waitHandle2 = result2.AsyncWaitHandle;

connection3.Open();
SqlCommand command3 =
new SqlCommand(commandText3, connection3);
IAsyncResult result3 = command3.BeginExecuteReader();
WaitHandle waitHandle3 = result3.AsyncWaitHandle;

WaitHandle[] waitHandles = {
waitHandle1, waitHandle2, waitHandle3
};

int index;
for (int countWaits = 0; countWaits <= 2; countWaits++)
{
// WaitAny waits for any of the processes to
// complete. The return value is either the index
// of the array element whose process just
// completed, or the WaitTimeout value.
index = WaitHandle.WaitAny(waitHandles,
60000, false);
// This example doesn't actually do anything with
// the data returned by the processes, but the
// code opens readers for each just to demonstrate
// the concept.
// Instead of using the returned data to fill the
// controls on the page, the example adds the time
// the process was completed to the corresponding
// text box.

switch (index)
{
case 0:
SqlDataReader reader1;
reader1 =
command1.EndExecuteReader(result1);
if (reader1.Read())
{
TextBox1.Text =
"Completed " +
System.DateTime.Now.ToLongTimeString();
}
reader1.Close();
break;
case 1:
SqlDataReader reader2;
reader2 =
command2.EndExecuteReader(result2);
if (reader2.Read())
{
TextBox2.Text =
"Completed " +
System.DateTime.Now.ToLongTimeString();
}
reader2.Close();
break;
case 2:
SqlDataReader reader3;
reader3 =
command3.EndExecuteReader(result3);
if (reader3.Read())
{
TextBox3.Text =
"Completed " +
System.DateTime.Now.ToLongTimeString();
}
reader3.Close();
break;
case WaitHandle.WaitTimeout:
throw new Exception("Timeout");
break;
}
}
}
catch (Exception ex)
{
TextBox4.Text = ex.ToString();
}
connection1.Close();
connection2.Close();
connection3.Close();
}

Example: Wait (All) model


The following example illustrates the Wait (All) model. Once three asynchronous processes are started, the
WaitAll method is called to wait for the processes to complete or time out.
Like the example of the Wait (Any) model, the time the process completed is added to a text box corresponding
to the process. Again, the times in the text boxes illustrate the point: Code following the WaitAny method is
executed only after all processes are complete.
To set up this example, create a new ASP.NET Web Site project. Place a Button control and four TextBox controls
on the page (accepting the default name for each control).
Add the following code to the form's class, modifying the connection string as necessary for your environment.

// Add the following using statements, if they are not already there.
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Threading;
using Microsoft.Data.SqlClient;

// Add this code to the page's class


string GetConnectionString()
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
// If you have not included "Asynchronous Processing=true"
// in the connection string, the command will not be able
// to execute asynchronously.
{
return "Data Source=(local);Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks;" +
"Asynchronous Processing=true";
}
void Button1_Click(object sender, System.EventArgs e)
{
// In a real-world application, you might be connecting to
// three different servers or databases. For the example,
// we connect to only one.

SqlConnection connection1 =
new SqlConnection(GetConnectionString());
SqlConnection connection2 =
new SqlConnection(GetConnectionString());
SqlConnection connection3 =
new SqlConnection(GetConnectionString());
// To keep the example simple, all three asynchronous
// processes execute UPDATE queries that result in
// no change to the data. WAITFOR
// commands are used to emulate long-running processes
// that complete after different periods of time.

string commandText1 =
"UPDATE Production.Product " +
"SET ReorderPoint = ReorderPoint + 1 " +
"WHERE ReorderPoint Is Not Null;" +
"WAITFOR DELAY '0:0:01';" +
"UPDATE Production.Product " +
"SET ReorderPoint = ReorderPoint - 1 " +
"WHERE ReorderPoint Is Not Null";

string commandText2 =
"UPDATE Production.Product " +
"SET ReorderPoint = ReorderPoint + 1 " +
"SET ReorderPoint = ReorderPoint + 1 " +
"WHERE ReorderPoint Is Not Null;" +
"WAITFOR DELAY '0:0:05';" +
"UPDATE Production.Product " +
"SET ReorderPoint = ReorderPoint - 1 " +
"WHERE ReorderPoint Is Not Null";

string commandText3 =
"UPDATE Production.Product " +
"SET ReorderPoint = ReorderPoint + 1 " +
"WHERE ReorderPoint Is Not Null;" +
"WAITFOR DELAY '0:0:10';" +
"UPDATE Production.Product " +
"SET ReorderPoint = ReorderPoint - 1 " +
"WHERE ReorderPoint Is Not Null";
try
// For each process, open a connection and begin
// execution. Use the IAsyncResult object returned by
// BeginExecuteReader to add a WaitHandle for the
// process to the array.
{
connection1.Open();
SqlCommand command1 =
new SqlCommand(commandText1, connection1);
IAsyncResult result1 = command1.BeginExecuteNonQuery();
WaitHandle waitHandle1 = result1.AsyncWaitHandle;
connection2.Open();

SqlCommand command2 =
new SqlCommand(commandText2, connection2);
IAsyncResult result2 = command2.BeginExecuteNonQuery();
WaitHandle waitHandle2 = result2.AsyncWaitHandle;
connection3.Open();

SqlCommand command3 =
new SqlCommand(commandText3, connection3);
IAsyncResult result3 = command3.BeginExecuteNonQuery();
WaitHandle waitHandle3 = result3.AsyncWaitHandle;

WaitHandle[] waitHandles = {
waitHandle1, waitHandle2, waitHandle3
};

bool result;
// WaitAll waits for all of the processes to
// complete. The return value is True if the processes
// all completed successfully, False if any process
// timed out.

result = WaitHandle.WaitAll(waitHandles, 60000, false);


if(result)
{
long rowCount1 =
command1.EndExecuteNonQuery(result1);
TextBox1.Text = "Completed " +
System.DateTime.Now.ToLongTimeString();
long rowCount2 =
command2.EndExecuteNonQuery(result2);
TextBox2.Text = "Completed " +
System.DateTime.Now.ToLongTimeString();

long rowCount3 =
command3.EndExecuteNonQuery(result3);
TextBox3.Text = "Completed " +
System.DateTime.Now.ToLongTimeString();
}
else
{
throw new Exception("Timeout");
}
}
}

catch (Exception ex)


{
TextBox4.Text = ex.ToString();
}
connection1.Close();
connection2.Close();
connection3.Close();
}

Next steps
Asynchronous operations
Polling in console applications
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Asynchronous operations in ADO.NET allow you to initiate time-consuming database operations on one thread
while performing other tasks on another thread. In most scenarios, however, you will eventually reach a point
where your application should not continue until the database operation is complete. For such cases, it is useful
to poll the asynchronous operation to determine whether the operation has completed or not.
You can use the IsCompleted property to find out whether or not the operation has completed.

Example
The following console application updates data within the AdventureWorks sample database, doing its work
asynchronously. In order to emulate a long-running process, this example inserts a WAITFOR statement in the
command text. Normally, you would not try to make your commands run slower, but doing so in this case
makes it easier to demonstrate asynchronous behavior.

using System;
using System.Data;
using Microsoft.Data.SqlClient;

class Class1
{
[STAThread]
static void Main()
{
// The WAITFOR statement simply adds enough time to
// prove the asynchronous nature of the command.

string commandText =
"UPDATE Production.Product SET ReorderPoint = " +
"ReorderPoint + 1 " +
"WHERE ReorderPoint Is Not Null;" +
"WAITFOR DELAY '0:0:3';" +
"UPDATE Production.Product SET ReorderPoint = " +
"ReorderPoint - 1 " +
"WHERE ReorderPoint Is Not Null";

RunCommandAsynchronously(
commandText, GetConnectionString());

Console.WriteLine("Press Enter to continue.");


Console.ReadLine();
}

private static void RunCommandAsynchronously(


string commandText, string connectionString)
{
// Given command text and connection string, asynchronously
// execute the specified command against the connection.
// For this example, the code displays an indicator as it's
// working, verifying the asynchronous behavior.
using (SqlConnection connection =
new SqlConnection(connectionString))
{
try
{
int count = 0;
SqlCommand command =
new SqlCommand(commandText, connection);
connection.Open();

IAsyncResult result =
command.BeginExecuteNonQuery();
while (!result.IsCompleted)
{
Console.WriteLine(
"Waiting ({0})", count++);
// Wait for 1/10 second, so the counter
// doesn't consume all available
// resources on the main thread.
System.Threading.Thread.Sleep(100);
}
Console.WriteLine(
"Command complete. Affected {0} rows.",
command.EndExecuteNonQuery(result));
}
catch (SqlException ex)
{
Console.WriteLine("Error ({0}): {1}",
ex.Number, ex.Message);
}
catch (InvalidOperationException ex)
{
Console.WriteLine("Error: {0}", ex.Message);
}
catch (Exception ex)
{
// You might want to pass these errors
// back out to the caller.
Console.WriteLine("Error: {0}", ex.Message);
}
}
}

private static string GetConnectionString()


{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.

// If you have not included "Asynchronous Processing=true"


// in the connection string, the command will not be able
// to execute asynchronously.
return "Data Source=(local);Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks; " +
"Asynchronous Processing=true";
}
}

Next steps
Asynchronous operations
Table-valued parameters
4/27/2022 • 7 minutes to read • Edit Online

Download ADO.NET
Table-valued parameters provide an easy way to marshal multiple rows of data from a client application to SQL
Server. They don't require multiple round trips or special server-side logic for processing the data. You can use
table-valued parameters to encapsulate rows of data in a client application and send the data to the server in a
single parameterized command. The incoming data rows are stored in a table variable that can then be operated
on by using Transact-SQL.
Column values in table-valued parameters can be accessed using standard Transact-SQL SELECT statements.
Table-valued parameters are strongly typed and their structure is automatically validated. The size of table-
valued parameters is limited only by server memory.

NOTE
You cannot return data in a table-valued parameter. Table-valued parameters are input-only; the OUTPUT keyword is not
supported.

For more information about table-valued parameters, see the following resources.

RESO URC E DESC RIP T IO N

Use Table-Valued Parameters (Database Engine) Describes how to create and use table-valued parameters.

Creating a user-defined table type Describes user-defined table types that are used to declare
table-valued parameters.

User-Defined Table Types Describes user-defined table types that are used to declare
table-valued parameters.

Passing multiple rows in previous versions of SQL Server


Before table-valued parameters were introduced, the options for passing multiple rows of data to a stored
procedure or a parameterized SQL command were limited. A developer could choose from the following
options for passing multiple rows to the server:
Use a series of individual parameters to represent the values in multiple columns and rows of data. The
amount of data that can be passed by using this method is limited by the number of parameters allowed.
SQL Server procedures can have, at most, 2100 parameters. Server-side logic is required to assemble
these individual values into a table variable or a temporary table for processing.
Bundle multiple data values into delimited strings or XML documents and then pass those text values to a
procedure or statement. This method requires the procedure or statement to include logic for validating
the data structures and unbundling the values.
Create a series of individual SQL statements for data modifications that affect multiple rows, such as
those created by calling the Update method of a SqlDataAdapter. Changes can be submitted to the
server individually or batched into groups. However, even when submitted in batches that contain
multiple statements, each statement is executed separately on the server.
Use the bcp utility program or the SqlBulkCopy object to load many rows of data into a table. Although
this technique is efficient, it doesn't support server-side processing unless the data is loaded into a
temporary table or table variable.

Creating table-valued parameter types


Table-valued parameters are based on strongly typed table structures that are defined by using Transact-SQL
CREATE TYPE statements. You must create a table type and define the structure in SQL Server before you can
use table-valued parameters in your client applications. For more information about creating table types, see
Use Table-Valued Parameters (Database Engine).
The following statement creates a table type named CategoryTableType that consists of CategoryID and
CategoryName columns:

CREATE TYPE dbo.CategoryTableType AS TABLE


( CategoryID int, CategoryName nvarchar(50) )

After you create a table type, you can declare table-valued parameters based on that type. The following
Transact-SQL fragment demonstrates how to declare a table-valued parameter in a stored procedure definition.
The READONLY keyword is required for declaring a table-valued parameter.

CREATE PROCEDURE usp_UpdateCategories


(@tvpNewCategories dbo.CategoryTableType READONLY)

Modifying data with table-valued parameters (transact-SQL)


Table-valued parameters can be used in set-based data modifications that affect multiple rows by executing a
single statement. For example, you can select all the rows in a table-valued parameter and insert them into a
database table, or you can create an update statement by joining a table-valued parameter to the table you want
to update.
The following Transact-SQL UPDATE statement demonstrates how to use a table-valued parameter by joining it
to the Categories table. When you use a table-valued parameter with a JOIN in a FROM clause, you must also
alias it, as shown here, where the table-valued parameter is aliased as "ec":

UPDATE dbo.Categories
SET Categories.CategoryName = ec.CategoryName
FROM dbo.Categories INNER JOIN @tvpEditedCategories AS ec
ON dbo.Categories.CategoryID = ec.CategoryID;

This Transact-SQL example demonstrates how to select rows from a table-valued parameter to perform an
INSERT in a single set-based operation.

INSERT INTO dbo.Categories (CategoryID, CategoryName)


SELECT nc.CategoryID, nc.CategoryName FROM @tvpNewCategories AS nc;

Limitations of table-valued parameters


There are several limitations to table-valued parameters:
You can't pass table-valued parameters to CLR user-defined functions.
Table-valued parameters can only be indexed to support UNIQUE or PRIMARY KEY constraints. SQL
Server doesn't maintain statistics on table-valued parameters.
Table-valued parameters are read-only in Transact-SQL code. You can't update the column values in the
rows of a table-valued parameter and you can't insert or delete rows. To modify data passed to a stored
procedure or parameterized statement in a table-valued parameter, you must insert the data into a
temporary table or into a table variable.
You can't use ALTER TABLE statements to modify the design of table-valued parameters.

Configuring a SqlParameter example


Microsoft.Data.SqlClient supports populating table-valued parameters from DataTable, DbDataReader, or
IEnumerable<T> \ SqlDataRecord objects. Specify a type name for the table-valued parameter by using the
TypeName property of a SqlParameter. The TypeName must match the name of a compatible type previously
created on the server. The following code fragment demonstrates how to configure SqlParameter to insert data.
In the following example, the addedCategories variable contains a DataTable. To see how the variable is
populated, see the examples in the next section, Passing a Table-Valued Parameter to a Stored Procedure.

// Configure the command and parameter.


SqlCommand insertCommand = new SqlCommand(sqlInsert, connection);
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("@tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.CategoryTableType";

You can also use any object derived from DbDataReader to stream rows of data to a table-valued parameter, as
shown in this fragment:

// Configure the SqlCommand and table-valued parameter.


SqlCommand insertCommand = new SqlCommand("usp_InsertCategories", connection);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("@tvpNewCategories", dataReader);
tvpParam.SqlDbType = SqlDbType.Structured;

Passing a table-valued parameter to a stored procedure


This example demonstrates how to pass table-valued parameter data to a stored procedure. The code extracts
added rows into a new DataTable by using the GetChanges method. The code then defines a SqlCommand,
setting the CommandType property to StoredProcedure. The SqlParameter is populated by using the
AddWithValue method and the SqlDbType is set to Structured . The SqlCommand is then executed by using the
ExecuteNonQuery method.

// Assumes connection is an open SqlConnection object.


using (connection)
{
// Create a DataTable with the modified rows.
DataTable addedCategories = CategoriesDataTable.GetChanges(DataRowState.Added);

// Configure the SqlCommand and SqlParameter.


SqlCommand insertCommand = new SqlCommand("usp_InsertCategories", connection);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("@tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;

// Execute the command.


insertCommand.ExecuteNonQuery();
}
Passing a table -valued parameter to a parameterized SQL statement
The following example demonstrates how to insert data into the dbo.Categories table by using an INSERT
statement with a SELECT subquery that has a table-valued parameter as the data source. When passing a table-
valued parameter to a parameterized SQL statement, you must specify a type name for the table-valued
parameter by using the new TypeName property of a SqlParameter. This TypeName must match the name of a
compatible type previously created on the server. The code in this example uses the TypeName property to
reference the type structure defined in dbo.CategoryTableType.

NOTE
If you supply a value for an identity column in a table-valued parameter, you must issue the SET IDENTITY_INSERT
statement for the session.

// Assumes connection is an open SqlConnection.


using (connection)
{
// Create a DataTable with the modified rows.
DataTable addedCategories = CategoriesDataTable.GetChanges(DataRowState.Added);

// Define the INSERT-SELECT statement.


string sqlInsert =
"INSERT INTO dbo.Categories (CategoryID, CategoryName)"
+ " SELECT nc.CategoryID, nc.CategoryName"
+ " FROM @tvpNewCategories AS nc;"

// Configure the command and parameter.


SqlCommand insertCommand = new SqlCommand(sqlInsert, connection);
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("@tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.CategoryTableType";

// Execute the command.


insertCommand.ExecuteNonQuery();
}

Streaming rows with a DataReader


You can also use any object derived from DbDataReader to stream rows of data to a table-valued parameter. The
following code fragment demonstrates retrieving data from an Oracle database by using an OracleCommand
and an OracleDataReader. The code then configures a SqlCommand to invoke a stored procedure with a single
input parameter. The SqlDbType property of the SqlParameter is set to Structured . The AddWithValue passes
the OracleDataReader result set to the stored procedure as a table-valued parameter.
// Assumes connection is an open SqlConnection.
// Retrieve data from Oracle.
OracleCommand selectCommand = new OracleCommand(
"Select CategoryID, CategoryName FROM Categories;",
oracleConnection);
OracleDataReader oracleReader = selectCommand.ExecuteReader(
CommandBehavior.CloseConnection);

// Configure the SqlCommand and table-valued parameter.


SqlCommand insertCommand = new SqlCommand(
"usp_InsertCategories", connection);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam =
insertCommand.Parameters.AddWithValue(
"@tvpNewCategories", oracleReader);
tvpParam.SqlDbType = SqlDbType.Structured;

// Execute the command.


insertCommand.ExecuteNonQuery();

Next steps
SQL Server data operations in ADO.NET
SQL Server features and ADO.NET
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
The topics in this section discuss features in SQL Server that are targeted at developing database applications
using ADO.NET.
For more information, see Development (Database Engine) from SQL Server Books Online.

In this section
Enumerating instances of SQL Server (ADO.NET)
Describes how to enumerate active instances of SQL Server.
Provider statistics for SQL Server
Describes support for obtaining SQL Server run-time statistics.
SQL Server Express user instances
Describes support for SQL Server Express user instances.
Database mirroring in SQL Server
Describes database mirroring functionality.
The context connection
Describes the context connection.
Query notifications in SQL Server
Describes how .NET applications can request notification from SQL Server when data has changed.
Snapshot isolation in SQL Server
Describes support for snapshot isolation, a row versioning mechanism designed to reduce blocking in
transactional applications.
SqlClient support for high availability, disaster recovery
Describes SqlClient support for high-availability, disaster recovery (AlwaysOn) availability groups.
SqlClient support for LocalDB
Describes SqlClient support for LocalDB databases.
SqlClient support for Always Encrypted
Describes SqlClient support for the Always Encrypted feature.
SqlClient support for Data Discovery and Classification
Describes how to access Data Discovery and Classification information through SqlClient.

Next steps
SQL Server data operations in ADO.NET
SQL Server and ADO.NET
Enumerating instances of SQL Server (ADO.NET)
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
SQL Server permits applications to find SQL Server instances within the current network. The
SqlDataSourceEnumerator class exposes this information to the application developer, providing a DataTable
containing information about all the visible servers. This returned table contains a list of server instances
available on the network that matches the list provided when a user attempts to create a new connection, and
expands the drop-down list containing all the available servers on the Connection Proper ties dialog box. The
results displayed are not always complete.

NOTE
As with most Windows services, it is best to run the SQL Browser service with the least possible privileges. See SQL Server
Books Online for more information on the SQL Browser service, and how to manage its behavior.

Retrieving an enumerator instance


In order to retrieve the table containing information about the available SQL Server instances, you must first
retrieve an enumerator, using the shared/static Instance property:

System.Data.Sql.SqlDataSourceEnumerator instance =
System.Data.Sql.SqlDataSourceEnumerator.Instance

Once you have retrieved the static instance, you can call the GetDataSources method, which returns a DataTable
containing information about the available servers:

System.Data.DataTable dataTable = instance.GetDataSources();

The table returned from the method call contains the following columns, all of which contain string values:

C O L UM N DESC RIP T IO N

Ser verName Name of the server.

InstanceName Name of the server instance. Blank if the server is running as


the default instance.

IsClustered Indicates whether the server is part of a cluster.

Version Version of the server. For example:

- 9.00.x (SQL Server 2005)


- 10.0.xx (SQL Server 2008)
- 10.50.x (SQL Server 2008 R2)
- 11.0.xx (SQL Server 2012)
Enumeration limitations
All of the available servers may or may not be listed. The list can vary depending on factors such as timeouts
and network traffic. This can cause the list to be different on two consecutive calls. Only servers on the same
network will be listed. Broadcast packets typically won't traverse routers, which is why you may not see a server
listed, but it will be stable across calls.
Listed servers may or may not have additional information such as IsClustered and version. This is dependent
on how the list was obtained. Servers listed through the SQL Server browser service will have more details than
those found through the Windows infrastructure, which will list only the name.

NOTE
Server enumeration is only available when running in full-trust. Assemblies running in a partially-trusted environment will
not be able to use it, even if they have the SqlClientPermission Code Access Security (CAS) permission.

SQL Server provides information for the SqlDataSourceEnumerator through the use of an external Windows
service named SQL Browser. This service is enabled by default, but administrators may turn it off or disable it,
making the server instance invisible to this class.

Example
The following console application retrieves information about all of the visible SQL Server instances and
displays the information in the console window.

using System.Data.Sql;

class Program
{
static void Main()
{
// Retrieve the enumerator instance and then the data.
SqlDataSourceEnumerator instance =
SqlDataSourceEnumerator.Instance;
System.Data.DataTable table = instance.GetDataSources();

// Display the contents of the table.


DisplayData(table);

Console.WriteLine("Press any key to continue.");


Console.ReadKey();
}

private static void DisplayData(System.Data.DataTable table)


{
foreach (System.Data.DataRow row in table.Rows)
{
foreach (System.Data.DataColumn col in table.Columns)
{
Console.WriteLine("{0} = {1}", col.ColumnName, row[col]);
}
Console.WriteLine("============================");
}
}
}

Next steps
SQL Server and ADO.NET
Provider statistics for SQL Server
4/27/2022 • 8 minutes to read • Edit Online

Download ADO.NET
Starting with the .NET Framework version 2.0 and .NET Core version 1.0, the Microsoft SqlClient Data Provider
for SQL Server supports run-time statistics. You must enable statistics by setting the StatisticsEnabled property
of the SqlConnection object to True after you have a valid connection object created. After statistics are
enabled, you can review them as a "snapshot in time" by retrieving an IDictionary reference via the
RetrieveStatistics method of the SqlConnection object. You enumerate through the list as a set of name/value
pair dictionary entries. These name/value pairs are unordered. At any time, you can call the ResetStatistics
method of the SqlConnection object to reset the counters. If statistic gathering has not been enabled, an
exception is not generated. In addition, if RetrieveStatistics is called without StatisticsEnabled having been called
first, the values retrieved are the initial values for each entry. If you enable statistics, run your application for a
while, and then disable statistics, the values retrieved will reflect the values collected up to the point where
statistics were disabled. All statistical values gathered are on a per-connection basis.

Statistical values available


Currently there are 18 different items available from the Microsoft SQL Server provider. The number of items
available can be accessed via the Count property of the IDictionary interface reference returned by
RetrieveStatistics. All of the counters for provider statistics use the common language runtime Int64 type (long
in C# and Visual Basic), which is 64 bits wide. The maximum value of the int64 data type, as defined by the
int64.MaxValue field, is ((2^63)-1)). When the values for the counters reach this maximum value, they should
no longer be considered accurate. This means that int64.MaxValue -1((2^63)-2) is effectively the greatest valid
value for any statistic.

NOTE
A dictionary is used for returning provider statistics because the number, names and order of the returned statistics may
change in the future. Applications should not rely on a specific value being found in the dictionary, but should instead
check whether the value is there and branch accordingly.

The following table describes the current statistical values available. Note that the key names for the individual
values are not localized across regional versions of the Microsoft .NET Framework and .NET Core.

K EY N A M E DESC RIP T IO N

BuffersReceived Returns the number of tabular data stream (TDS) packets


received by the provider from SQL Server after the
application has started using the provider and has enabled
statistics.

BuffersSent Returns the number of TDS packets sent to SQL Server by


the provider after statistics have been enabled. Large
commands can require multiple buffers. For example, if a
large command is sent to the server and it requires six
packets, ServerRoundtrips is incremented by one and
BuffersSent is incremented by six.
K EY N A M E DESC RIP T IO N

BytesReceived Returns the number of bytes of data in the TDS packets


received by the provider from SQL Server once the
application has started using the provider and has enabled
statistics.

BytesSent Returns the number of bytes of data sent to SQL Server in


TDS packets after the application has started using the
provider and has enabled statistics.

ConnectionTime The amount of time (in milliseconds) that the connection has
been opened after statistics have been enabled (total
connection time if statistics were enabled before opening the
connection).

CursorOpens Returns the number of times a cursor was open through the
connection once the application has started using the
provider and has enabled statistics.

Note that read-only/forward-only results returned by


SELECT statements are not considered cursors and thus do
not affect this counter.

ExecutionTime Returns the cumulative amount of time (in milliseconds) that


the provider has spent processing once statistics have been
enabled, including the time spent waiting for replies from the
server as well as the time spent executing code in the
provider itself.

The classes that include timing code are:

SqlConnection

SqlCommand

SqlDataReader

SqlDataAdapter

SqlTransaction

SqlCommandBuilder

To keep performance-critical members as small as possible,


the following members are not timed:

SqlDataReader

this[] operator (all overloads)

GetBoolean

GetChar

GetDateTime

GetDecimal

GetDouble

GetFloat
K EY N A M E DESC RIP T IO N
GetGuid

GetInt16

GetInt32

GetInt64

GetName

GetOrdinal

GetSqlBinary

GetSqlBoolean

GetSqlByte

GetSqlDateTime

GetSqlDecimal

GetSqlDouble

GetSqlGuid

GetSqlInt16

GetSqlInt32

GetSqlInt64

GetSqlMoney

GetSqlSingle

GetSqlString

GetString

IsDBNull
IduCount Returns the total number of INSERT, DELETE, and UPDATE
statements executed through the connection once the
application has started using the provider and has enabled
statistics.

IduRows Returns the total number of rows affected by INSERT,


DELETE, and UPDATE statements executed through the
connection once the application has started using the
provider and has enabled statistics.

NetworkServerTime Returns the cumulative amount of time (in milliseconds) that


the provider spent waiting for replies from the server once
the application has started using the provider and has
enabled statistics.

PreparedExecs Returns the number of prepared commands executed


through the connection once the application has started
using the provider and has enabled statistics.
K EY N A M E DESC RIP T IO N

Prepares Returns the number of statements prepared through the


connection once the application has started using the
provider and has enabled statistics.

SelectCount Returns the number of SELECT statements executed through


the connection once the application has started using the
provider and has enabled statistics. This includes FETCH
statements to retrieve rows from cursors, and the count for
SELECT statements is updated when the end of a
SqlDataReader is reached.

SelectRows Returns the number of rows selected once the application


has started using the provider and has enabled statistics.
This counter reflects all the rows generated by SQL
statements, even those that were not actually consumed by
the caller. For example, closing a data reader before reading
the entire result set would not affect the count. This includes
the rows retrieved from cursors through FETCH statements.

ServerRoundtrips Returns the number of times the connection sent commands


to the server and got a reply back once the application has
started using the provider and has enabled statistics.

SumResultSets Returns the number of result sets that have been used once
the application has started using the provider and has
enabled statistics. For example this would include any result
set returned to the client. For cursors, each fetch or block-
fetch operation is considered an independent result set.

Transactions Returns the number of user transactions started once the


application has started using the provider and has enabled
statistics, including rollbacks. If a connection is running with
auto commit on, each command is considered a transaction.

This counter increments the transaction count as soon as a


BEGIN TRAN statement is executed, regardless of whether
the transaction is committed or rolled back later.

UnpreparedExecs Returns the number of unprepared statements executed


through the connection once the application has started
using the provider and has enabled statistics.

Retrieving a value
The following console application shows how to enable statistics on a connection, retrieve four individual
statistic values, and write them out to the console window.

NOTE
The following example uses the sample AdventureWorks database included with SQL Server. The connection string
provided in the sample code assumes the database is installed and available on the local computer. Modify the connection
string as necessary for your environment.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data;
using Microsoft.Data.SqlClient;

namespace CS_Stats_Console_GetValue
{
class Program
{
static void Main(string[] args)
{
string connectionString = GetConnectionString();

using (SqlConnection awConnection =


new SqlConnection(connectionString))
{
// StatisticsEnabled is False by default.
// It must be set to True to start the
// statistic collection process.
awConnection.StatisticsEnabled = true;

string productSQL = "SELECT * FROM Production.Product";


SqlDataAdapter productAdapter =
new SqlDataAdapter(productSQL, awConnection);

DataSet awDataSet = new DataSet();

awConnection.Open();

productAdapter.Fill(awDataSet, "ProductTable");
// Retrieve the current statistics as
// a collection of values at this point
// and time.
IDictionary currentStatistics =
awConnection.RetrieveStatistics();

Console.WriteLine("Total Counters: " +


currentStatistics.Count.ToString());
Console.WriteLine();

// Retrieve a few individual values


// related to the previous command.
long bytesReceived =
(long) currentStatistics["BytesReceived"];
long bytesSent =
(long) currentStatistics["BytesSent"];
long selectCount =
(long) currentStatistics["SelectCount"];
long selectRows =
(long) currentStatistics["SelectRows"];

Console.WriteLine("BytesReceived: " +
bytesReceived.ToString());
Console.WriteLine("BytesSent: " +
bytesSent.ToString());
Console.WriteLine("SelectCount: " +
selectCount.ToString());
Console.WriteLine("SelectRows: " +
selectRows.ToString());

Console.WriteLine();
Console.WriteLine("Press any key to continue");
Console.ReadLine();
}

}
private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=localhost;Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks";
"Initial Catalog=AdventureWorks";
}
}
}

Retrieving all values


The following console application shows how to enable statistics on a connection, retrieve all available statistic
values using the enumerator, and write them to the console window.

NOTE
The following example uses the sample AdventureWorks database included with SQL Server. The connection string
provided in the sample code assumes the database is installed and available on the local computer. Modify the connection
string as necessary for your environment.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Microsoft.Data.SqlClient;

namespace CS_Stats_Console_GetAll
{
class Program
{
static void Main(string[] args)
{
string connectionString = GetConnectionString();

using (SqlConnection awConnection =


new SqlConnection(connectionString))
{
// StatisticsEnabled is False by default.
// It must be set to True to start the
// statistic collection process.
awConnection.StatisticsEnabled = true;

string productSQL = "SELECT * FROM Production.Product";


SqlDataAdapter productAdapter =
new SqlDataAdapter(productSQL, awConnection);

DataSet awDataSet = new DataSet();

awConnection.Open();

productAdapter.Fill(awDataSet, "ProductTable");

// Retrieve the current statistics as


// a collection of values at this point
// and time.
IDictionary currentStatistics =
awConnection.RetrieveStatistics();

Console.WriteLine("Total Counters: " +


currentStatistics.Count.ToString());
Console.WriteLine();

Console.WriteLine("Key Name and Value");

// Note the entries are unsorted.


foreach (DictionaryEntry entry in currentStatistics)
{
Console.WriteLine(entry.Key.ToString() +
": " + entry.Value.ToString());
": " + entry.Value.ToString());
}

Console.WriteLine();
Console.WriteLine("Press any key to continue");
Console.ReadLine();
}

}
private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=localhost;Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks";
}
}
}

Next steps
SQL Server and ADO.NET
SQL Server Express user instances
4/27/2022 • 8 minutes to read • Edit Online

Download ADO.NET
Microsoft SQL Server Express Edition (SQL Server Express) supports the user instance feature, which is only
available when using the Microsoft SqlClient Data Provider for SQL Server. A user instance is a separate instance
of the SQL Server Express Database Engine that is generated by a parent instance. User instances allow users
who are not administrators on their local computers to attach and connect to SQL Server Express databases.
Each instance runs under the security context of the individual user, on a one-instance-per-user basis.

User instance capabilities


User instances are useful for users who are running Windows under a least-privilege user account (LUA)
because each user has SQL Server system administrator ( sysadmin ) privileges over the instance running on her
computer without needing to run as a Windows administrator as well. Software executing on a user instance
with limited permissions cannot make system-wide changes because the instance of SQL Server Express is
running under the non-administrator Windows account of the user, not as a service. Each user instance is
isolated from its parent instance and from any other user instances running on the same computer. Databases
running on a user instance are opened in single-user mode only, and it is not possible for multiple users to
connect to databases running on a user instance. Replication and distributed queries are also disabled for user
instances.
For more information, see "User Instances" in SQL Server Books Online.

NOTE
User instances are not needed for users who are already administrators on their own computers, or for scenarios
involving multiple database users.

Enabling user instances


To generate user instances, a parent instance of SQL Server Express must be running. User instances are enabled
by default when SQL Server Express is installed, and they can be explicitly enabled or disabled by a system
administrator executing the sp_configure system stored procedure on the parent instance.

-- Enable user instances.


sp_configure 'user instances enabled','1'

-- Disable user instances.


sp_configure 'user instances enabled','0'

The network protocol for user instances must be local Named Pipes. A user instance cannot be started on a
remote instance of SQL Server, and SQL Server logins are not allowed.

Connecting to a user instance


The User Instance and AttachDBFilename ConnectionString keywords allow a SqlConnection to connect to a
user instance. User instances are also supported by the SqlConnectionStringBuilder UserInstance and
AttachDBFilename properties.
Note the following about the sample connection string shown below:
The Data Source keyword refers to the parent instance of SQL Server Express that is generating the user
instance. The default instance is .\sqlexpress.
Integrated Security is set to true . To connect to a user instance, Windows Authentication is required;
SQL Server logins are not supported.
The User Instance is set to true , which invokes a user instance. (The default is false .)
The AttachDbFileName connection string keyword is used to attach the primary database file (.mdf), which
must include the full path name. AttachDbFileName also corresponds to the "extended properties" and
"initial file name" keys within a SqlConnection connection string.
The |DataDirectory| substitution string enclosed in the pipe symbols refers to the data directory of the
application opening the connection and provides a relative path indicating the location of the .mdf and
.ldf database and log files. If you want to locate these files elsewhere, you must provide the full path to
the files.

Data Source=.\\SQLExpress;Integrated Security=true;


User Instance=true;AttachDBFilename=|DataDirectory|\InstanceDB.mdf;
Initial Catalog=InstanceDB;

NOTE
You can also use the SqlConnectionStringBuilderUserInstance and AttachDBFilename properties to build a connection
string at run time.

Using the |DataDirectory| substitution string


DataDirectory is used in conjunction with AttachDbFileName to indicate a relative path to a data file, allowing
developers to create connection strings that are based on a relative path to the data source instead of being
required to specify a full path.
The physical location that DataDirectory points to depends on the type of application. In this example, the
Northwind.mdf file to be attached is located in the application's \app_data folder.

Data Source=.\\SQLExpress;Integrated Security=true;


User Instance=true;
AttachDBFilename=|DataDirectory|\app_data\Northwind.mdf;
Initial Catalog=Northwind;

When DataDirectory is used, the resulting file path cannot be higher in the directory structure than the
directory pointed to by the substitution string. For example, if the fully expanded DataDirectory is
C:\AppDirectory\app_data, then the sample connection string shown above works because it is below
c:\AppDirectory. However, attempting to specify DataDirectory as |DataDirectory|\..\data will result in an
error because \data is not a subdirectory of \AppDirectory.
If the connection string has an improperly formatted substitution string, an ArgumentException will be thrown.

NOTE
Microsoft.Data.SqlClient resolves the substitution strings into full paths against the local computer file system. Therefore,
remote server, HTTP, and UNC path names are not supported. An exception is thrown when the connection is opened if
the server is not located on the local computer.
When the SqlConnection is opened, it is redirected from the default SQL Server Express instance to a run-time
initiated instance running under the caller's account.

NOTE
It may be necessary to increase the ConnectionTimeout value since user instances may take longer to load than regular
instances.

The following code fragment opens a new SqlConnection , displays the connection string in the console window,
and then closes the connection when exiting the using code block.

private static void OpenSqlConnection()


{
// Retrieve the connection string.
string connectionString = GetConnectionString();

using (SqlConnection connection =


new SqlConnection(connectionString))
{
connection.Open();
Console.WriteLine("ConnectionString: {0}",
connection.ConnectionString);
}
}

NOTE
User instances are not supported in common language runtime (CLR) code that is running inside of SQL Server. An
InvalidOperationException is thrown if Open is called on a SqlConnection that has User Instance=true in the
connection string.

Lifetime of a user instance connection


Unlike versions of SQL Server that run as a service, SQL Server Express instances do not need to be manually
started and stopped. Each time a user logs in and connects to a user instance, the user instance is started if it is
not already running. User instance databases have the AutoClose option set so that the database is
automatically shut down after a period of inactivity. The sqlservr.exe process that is started is kept running for a
limited time-out period after the last connection to the instance is closed, so it does not need to be restarted if
another connection is opened before the time-out has expired. The user instance automatically shuts down if no
new connection opens before that time-out period has expired. A system administrator on the parent instance
can set the duration of the time-out period for a user instance by using sp_configure to change the user
instance timeout option. The default is 60 minutes.

NOTE
If Min Pool Size is used in the connection string with a value greater than zero, the connection pooler will always
maintain a few opened connections, and the user instance will not automatically shut down.

How user instances work


The first time a user instance is generated for each user, the master and msdb system databases are copied
from the Template Data folder to a path under the user's local application data repository directory for exclusive
use by the user instance. This path is typically
C:\Documents and Settings\<UserName>\Local Settings\Application Data\Microsoft\Microsoft SQL Server
Data\SQLEXPRESS
. When a user instance starts up, the tempdb , log, and trace files are also written to this directory. A name is
generated for the instance, which is guaranteed to be unique for each user.
By default all members of the Windows Builtin\Users group are granted permissions to connect on the local
instance as well as read and execute permissions on the SQL Server binaries. Once the credentials of the calling
user hosting the user instance have been verified, that user becomes the sysadmin on that instance. Only shared
memory is enabled for user instances, which means that only operations on the local machine are possible.
Users must be granted both read and write permissions on the .mdf and .ldf files specified in the connection
string.

NOTE
The .mdf and .ldf files represent the database and log files, respectively. These two files are a matched set, so care must be
taken during backup and restore operations. The database file contains information about the exact version of the log file,
and the database will not open if it is coupled with the wrong log file.

To avoid data corruption, a database in the user instance is opened with exclusive access. If two different user
instances share the same database on the same computer, the user on the first instance must close the database
before it can be opened in a second instance.

User instance scenarios


User instances provide developers of database applications with a SQL Server data store that does not depend
on developers having administrative accounts on their development computers. User instances are based on the
Access/Jet model, where the database application simply connects to a file, and the user automatically has full
permissions on all of the database objects without needing the intervention of a system administrator to grant
permissions. It is intended to work in situations where the user is running under a least-privilege user account
(LUA) and does not have administrative privileges on the server or local machine, yet needs to create database
objects and applications. User instances allow users to create instances at run time that run under the user's own
security context, and not in the security context of a more privileged system service.

IMPORTANT
User instances should only be used in scenarios where all the applications using it are fully trusted.

User instance scenarios include:


Any single-user application where sharing data is not required.
ClickOnce deployment. If the .NET Framework 2.0 (or later) or .NET Core 1.0 (or later) and SQL Server
Express are already installed on the target computer, the installation package downloaded as a result of a
ClickOnce action can be installed and used by non-administrator users. Note that an administrator must
install SQL Server Express if that is part of the setup. For more information, see ClickOnce Deployment
for Windows Forms.
Dedicated ASP.NET hosting using Windows Authentication. A single SQL Server Express instance can be
hosted on an intranet. The application connects using the ASPNET Windows account, not by using
impersonation. User instances should not be used for third-party or shared hosting scenarios where all
applications would share the same user instance and would no longer remain isolated from each other.

Next steps
SQL Server and ADO.NET
Database mirroring in SQL Server
4/27/2022 • 3 minutes to read • Edit Online

Download ADO.NET
Database mirroring in SQL Server allows you to keep a copy, or mirror, of a SQL Server database on a standby
server. Mirroring ensures two separate copies of the data always exist, providing high availability and complete
data redundancy. The Microsoft SqlClient Provider for SQL Server provides implicit support for database
mirroring. The developer doesn't need to do anything once the client has been configured for a SQL Server
database. Also, the SqlConnection object supports an explicit connection mode that allows supplying the name
of a failover partner server in the ConnectionString.
The following simplified sequence of events occurs for a SqlConnection object that targets a database
configured for mirroring:
1. The client application successfully connects to the principal database, and the server sends back the name of
the partner server, which the client caches.
2. If the server containing the principal database fails or connectivity is interrupted, connection and transaction
state is lost. The client application attempts to re-establish a connection to the principal database and fails.
3. The client application then transparently attempts to establish a connection to the mirror database on the
partner server. If it succeeds, the connection is redirected to the mirror database, which then becomes the
new principal database.

Specifying the failover partner in the connection string


If you supply the name of a failover partner server in the connection string and the principal database is
unavailable when the client application connects, the client will transparently attempt a connection with the
failover partner.

";Failover Partner=PartnerServerName"

If you omit the name of the failover partner server and the principal database is unavailable when the client
application first connects, then a SqlException occurs.
When a SqlConnection is successfully opened, the server returns the failover partner name, which supersedes
any values that are supplied in the connection string.

NOTE
You must explicitly specify the initial catalog or database name in the connection string for database mirroring scenarios. If
the client receives failover information on a connection that doesn't have an explicitly specified initial catalog or database,
the failover information is not cached and the application does not attempt to fail over if the principal server fails. If a
connection string has a value for the failover partner, but no value for the initial catalog or database, an
InvalidArgumentException is raised.

Retrieving the current server name


When a failover happens, you can retrieve the name of the server to which the current connection is connected
by using the DataSource property of a SqlConnection object. The following code fragment retrieves the name of
the active server, assuming that the connection variable references an open SqlConnection.
When a failover event occurs and the connection switches to the mirror server, the DataSource property
updates to reflect the mirror name.

string activeServer = connection.DataSource;

SqlClient mirroring behavior


The client always tries to connect to the principal server. If it fails, it tries the failover partner. If the mirror
database has already been switched to the principal role on the partner server, the connection succeeds and the
new principal-mirror mapping is sent to the client and cached for the lifetime of the calling AppDomain. It isn't
stored in persistent storage and isn't available for future connections in a different AppDomain or process.
However, it's available for later connections within the same AppDomain . Another AppDomain or process
running on the same or a different computer always has its pool of connections, and those connections aren't
reset. In that case, if the primary database goes down, each process or AppDomain fails once, and the pool is
automatically cleared.

NOTE
Mirroring support on the server is configured on a per-database basis. If data manipulation operations are executed
against other databases not included in the principal/mirror set, either by using multipart names or by changing the
current database, the changes to these other databases do not propagate in the event of failure. No error is generated
when data is modified in a database that is not mirrored. The developer must evaluate the possible impact of such
operations.

Next steps
Database mirroring resources
For conceptual documentation and information on configuring, deploying, and administering mirroring, see the
following resources in SQL Server documentation.

RESO URC E DESC RIP T IO N

Database Mirroring Describes how to set up and configure mirroring in SQL


Server.
The context connection
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
The problem of internal data access is a fairly common scenario. That is, you wish to access the same server on
which your common language runtime (CLR) stored procedure or function is executing. One option is to create
a connection using SqlConnection, specify a connection string that points to the local server, and open the
connection. This requires specifying credentials for logging in. The connection is in a different database session
than the stored procedure or function, it may have different SET options, it is in a separate transaction, it does
not see your temporary tables, and so on. If your managed stored procedure or function code is executing in the
SQL Server process, it is because someone connected to that server and executed a SQL statement to invoke it.
You probably want the stored procedure or function to execute in the context of that connection, along with its
transaction, SET options, and so on. This is called the context connection.
The context connection lets you execute Transact-SQL statements in the same context that your code was
invoked in the first place. For more detailed information, see The context connection from SQL Server Books
Online.
Query notifications in SQL Server
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Built upon the Service Broker infrastructure, query notifications allow applications to be notified when data has
changed. This feature is particularly useful for applications that provide a cache of information from a database,
such as a Web application, and need to be notified when the source data is changed.
There are three ways you can implement query notifications using ADO.NET:
The low-level implementation is provided by the SqlNotificationRequest class that exposes server-side
functionality, enabling you to execute a command with a notification request.
The high-level implementation is provided by the SqlDependency class, which is a class that provides a
high-level abstraction of notification functionality between the source application and SQL Server,
enabling you to use a dependency to detect changes in the server. In most cases, this is the simplest and
most effective way to leverage SQL Server notifications capability by managed client applications using
the Microsoft SqlClient Data Provider for SQL Server.
In addition, Web applications built using ASP.NET 2.0 or later can use the SqlCacheDependency helper
classes.
Query notifications are used for applications that need to refresh displays or caches in response to changes in
underlying data. Microsoft SQL Server allows .NET applications to send a command to SQL Server and request
notification if executing the same command would produce result sets different from those initially retrieved.
Notifications generated at the server are sent through queues to be processed later.
You can set up notifications for SELECT and EXECUTE statements. When using an EXECUTE statement, SQL
Server registers a notification for the command executed rather than the EXECUTE statement itself. The
command must meet the requirements and limitations for a SELECT statement. When a command that registers
a notification contains more than one statement, the Database Engine creates a notification for each statement
in the batch.
If you are developing an application where you need reliable sub-second notifications when data changes,
review the sections Planning an Efficient Quer y Notifications Strategy and Alternatives to Quer y
Notifications in the Planning for Notifications topic in SQL Server Books Online. For more information about
Query Notifications and SQL Server Service Broker, see the following links to topics in SQL Server Books Online.
SQL Ser ver documentation
Using Query Notifications
Creating a Query for Notification
Development (Service Broker)
Service Broker Developer InfoCenter
Developer's Guide (Service Broker)

In this section
Enabling query notifications
Discusses how to use query notifications, including the requirements for enabling and using them.
SqlDependency in an ASP.NET application
Demonstrates how to use query notifications from an ASP.NET application.
Detecting changes with SqlDependency
Demonstrates how to detect when query results will be different from those originally received.
SqlCommand execution with a SqlNotificationRequest
Demonstrates configuring a SqlCommand object to work with a query notification.

Reference
SqlNotificationRequest
Describes the SqlNotificationRequest class and all of its members.
SqlDependency
Describes the SqlDependency class and all of its members.
SqlCacheDependency
Describes the SqlCacheDependency class and all of its members.

Next steps
SQL Server and ADO.NET
Enabling query notifications
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Applications that consume query notifications have a common set of requirements. Your data source must be
correctly configured to support SQL query notifications and the user must have the correct client-side and
server-side permissions.
To use query notifications, you must:
Enable query notifications for your database.
Ensure that the user ID used to connect to the database has the necessary permissions.
Use a SqlCommand object to execute a valid SELECT statement with an associated notification object—either
SqlDependency or SqlNotificationRequest.
Provide code to process the notification if the data being monitored changes.

Query notifications requirements


Query notifications are supported only for SELECT statements that meet a list of specific requirements. The
following table provides links to the Service Broker and Query Notifications documentation in SQL Server
Books Online.
SQL Server documentation
Creating a Query for Notification
Security Considerations for Service Broker
Security and Protection (Service Broker)
Security Considerations for Notifications Services
Query Notification Permissions
International Considerations for Service Broker
Solution Design Considerations (Service Broker)
Service Broker Developer InfoCenter
Developer's Guide (Service Broker)

Enabling query notifications to run sample code


To enable Service Broker on the AdventureWorks database by using SQL Server Management Studio, execute
the following Transact-SQL statement:
ALTER DATABASE AdventureWorks SET ENABLE_BROKER;

For the query notification samples to run correctly, the following Transact-SQL statements must be executed on
the database server.

CREATE QUEUE ContactChangeMessages;

CREATE SERVICE ContactChangeNotifications


ON QUEUE ContactChangeMessages
([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]);
Query notifications permissions
Users who execute commands requesting notification must have SUBSCRIBE QUERY NOTIFICATIONS database
permission on the server.
Client-side code that runs in a partial trust situation requires the SqlClientPermission.
The following code creates a SqlClientPermission object, setting the PermissionState to Unrestricted. The
Demand will force a SecurityException at run time if all callers higher in the call stack haven't been granted the
permission.

using Microsoft.Data.SqlClient;
using System.Security.Permissions;

class Program
{
static void Main()
{
}

// Code requires directives to


// System.Security.Permissions and
// Microsoft.Data.SqlClient

private bool CanRequestNotifications()


{
SqlClientPermission permission =
new SqlClientPermission(
PermissionState.Unrestricted);
try
{
permission.Demand();
return true;
}
catch (System.Exception)
{
return false;
}
}
}

Choosing a notification object


The query notifications API provides two objects to process notifications: SqlDependency and
SqlNotificationRequest.
Using SqlDependency
To use SqlDependency, Service Broker must be enabled for the SQL Server database being used, and users must
have permissions to receive notifications. Service Broker objects, such as the notification queue, are predefined.
Also, SqlDependency automatically launches a worker thread to process notifications as they're posted to the
queue. It also parses the Service Broker message, exposing the information as event argument data.
SqlDependency must be initialized by calling the Start method to establish a dependency to the database.
Start is a static method that needs to be called only once during application initialization for each database
connection required. The Stop method should be called at application termination for each dependency
connection that was made.
Using SqlNotificationRequest
In contrast, SqlNotificationRequest requires you to implement the entire listening infrastructure yourself. Also,
all the supporting Service Broker objects such as the queue, service, and message types that are supported by
the queue must be defined. This manual approach is useful if your application requires special notification
messages or notification behaviors, or if your application is part of a larger Service Broker application.

Next steps
Query notifications in SQL Server
SqlDependency in an ASP.NET application
4/27/2022 • 3 minutes to read • Edit Online

Download ADO.NET
The example in this section shows how to use SqlDependency indirectly by using the ASP.NET
SqlCacheDependency object. The SqlCacheDependency object uses a SqlDependency to listen for notifications
and correctly update the cache.

NOTE
The sample code assumes that you have enabled query notifications by executing the scripts in Enabling query
notifications.

About the sample application


The sample application uses a single ASP.NET Web page to display product information from the
AdventureWorks SQL Server database in a GridView control. When the page loads, the code writes the current
time to a Label control. It then defines a SqlCacheDependency object and sets properties on the Cache object to
store the cache data for up to three minutes. The code then connects to the database and retrieves the data.
When the page is loaded and the application is running ASP.NET will retrieve data from the cache, which you can
verify by noting that the time on the page doesn't change. If the data being monitored changes, ASP.NET
invalidates the cache and repopulates the GridView control with fresh data, updating the time displayed in the
Label control.

Creating the sample application


Follow these steps to create and run the sample application:
1. Create a new ASP.NET Web site.
2. Add a Label and a GridView control to the Default.aspx page.
3. Open the page's class module and add the following directives:

using Microsoft.Data.SqlClient;
using System.Web.Caching;

4. Add the following code in the page's Page_Load event:


// using Microsoft.Data.SqlClient;
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = "Cache Refresh: " +
DateTime.Now.ToLongTimeString();

// Create a dependency connection to the database.


SqlDependency.Start(GetConnectionString());

using (SqlConnection connection =


new SqlConnection(GetConnectionString()))
{
using (SqlCommand command =
new SqlCommand(GetSQL(), connection))
{
SqlCacheDependency dependency =
new SqlCacheDependency(command);
// Refresh the cache after the number of minutes
// listed below if a change does not occur.
// This value could be stored in a configuration file.
int numberOfMinutes = 3;
DateTime expires =
DateTime.Now.AddMinutes(numberOfMinutes);

Response.Cache.SetExpires(expires);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetValidUntilExpires(true);

Response.AddCacheDependency(dependency);

connection.Open();

GridView1.DataSource = command.ExecuteReader();
GridView1.DataBind();
}
}
}

5. Add two helper methods, GetConnectionString and GetSQL . The connection string defined uses
integrated security. Verify that the account you're using has the necessary database permissions and that
the sample database, AdventureWorks , has notifications enabled.
// using Microsoft.Data.SqlClient;
private string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
private string GetSQL()
{
return "SELECT Production.Product.ProductID, " +
"Production.Product.Name, " +
"Production.Location.Name AS Location, " +
"Production.ProductInventory.Quantity " +
"FROM Production.Product INNER JOIN " +
"Production.ProductInventory " +
"ON Production.Product.ProductID = " +
"Production.ProductInventory.ProductID " +
"INNER JOIN Production.Location " +
"ON Production.ProductInventory.LocationID = " +
"Production.Location.LocationID " +
"WHERE ( Production.ProductInventory.Quantity <= 100 ) " +
"ORDER BY Production.ProductInventory.Quantity, " +
"Production.Product.Name;";
}

Testing the application


The application caches the data displayed on the Web form and refreshes it every three minutes if there's no
activity. If a change occurs to the database, the cache is refreshed immediately. Run the application from Visual
Studio, which loads the page into the browser. The cache refresh time displayed indicates when the cache was
last refreshed. Wait three minutes, and then refresh the page, causing a postback event to occur. The time
displayed on the page has changed. If you refresh the page in less than three minutes, the time displayed on the
page will remain the same.
Now update the data in the database using a Transact-SQL UPDATE command and refresh the page. The time
displayed now indicates the cache was refreshed with the new data from the database. Although the cache is
updated, the time displayed on the page doesn't change until a postback event occurs.

Next steps
Query notifications in SQL Server
Detecting changes with SqlDependency
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
A SqlDependency object can be associated with a SqlCommand to detect when query results differ from the
results originally retrieved. You can also assign a delegate to the OnChange event, which will fire when the results
change for an associated command. Associate the SqlDependency with the command before you execute the
command. The HasChanges property of the SqlDependency can also be used to determine if the query results
have changed since the data was first retrieved.

Security considerations
The dependency infrastructure relies on a SqlConnection that is opened when Start is called to receive
notifications that the underlying data has changed for a given command. The ability for a client to begin the call
to SqlDependency.Start is controlled by using SqlClientPermission and code access security attributes. For more
information, see Enabling query notifications.
Example
The following steps illustrate how to declare a dependency, execute a command, and receive a notification when
the result set changes:
1. Initiate a SqlDependency connection to the server.
2. Create SqlConnection and SqlCommand objects to connect to the server and define a Transact-SQL
statement.
3. Create a new SqlDependency object, or use an existing one, and bind it to the SqlCommand object.
Internally, this association creates a SqlNotificationRequest object and binds it to the command object as
needed. This notification request contains an internal identifier that uniquely identifies this SqlDependency
object. It also starts the client listener if it isn't already active.
4. Subscribe an event handler to the OnChange event of the SqlDependency object.
5. Execute the command using any of the Execute methods of the SqlCommand object. Because the
command is bound to the notification object, the server recognizes that it must generate a notification,
and the queue information will point to the dependencies queue.
6. Stop the SqlDependency connection to the server.
If any user then changes the underlying data, Microsoft SQL Server detects that there's a notification pending for
such a change, and posts a notification that is processed and forwarded to the client through the underlying
SqlConnection that was created by calling SqlDependency.Start . The client listener receives the invalidation
message. The client listener then locates the associated SqlDependency object and fires the OnChange event.
The following code fragment shows the design pattern you would use to create a sample application.
void Initialization()
{
// Create a dependency connection.
SqlDependency.Start(connectionString, queueName);
}

void SomeMethod()
{
// Assume connection is an open SqlConnection.

// Create a new SqlCommand object.


using (SqlCommand command=new SqlCommand(
"SELECT ShipperID, CompanyName, Phone FROM dbo.Shippers",
connection))
{

// Create a dependency and associate it with the SqlCommand.


SqlDependency dependency=new SqlDependency(command);
// Maintain the reference in a class member.

// Subscribe to the SqlDependency event.


dependency.OnChange+=new
OnChangeEventHandler(OnDependencyChange);

// Execute the command.


using (SqlDataReader reader = command.ExecuteReader())
{
// Process the DataReader.
}
}
}

// Handler method
void OnDependencyChange(object sender,
SqlNotificationEventArgs e )
{
// Handle the event (for example, invalidate this cache entry).
}

void Termination()
{
// Release the dependency.
SqlDependency.Stop(connectionString, queueName);
}

Next steps
Query notifications in SQL Server
SqlCommand execution with a
SqlNotificationRequest
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
A SqlCommand can be configured to generate a notification when data changes after it has been fetched from
the server and the result set would be different if the query were executed again. This is useful for scenarios
where you want to use custom notification queues on the server or when you do not want to maintain live
objects.

Creating the notification request


You can use a SqlNotificationRequest object to create the notification request by binding it to a SqlCommand
object. Once the request is created, you no longer need the SqlNotificationRequest object. You can query the
queue for any notifications and respond appropriately. Notifications can occur even if the application is shut
down and subsequently restarted.
When the command with the associated notification is executed, any changes to the original result set trigger
sending a message to the SQL Server queue that was configured in the notification request.
How you poll the SQL Server queue and interpret the message is specific to your application. The application is
responsible for polling the queue and reacting based on the contents of the message.

NOTE
When using SQL Server notification requests with SqlDependency, create your own queue name instead of using the
default service name.

There are no new client-side security elements for SqlNotificationRequest. This is primarily a server feature, and
the server has created special privileges that users must have to request a notification.
Example
The following code fragment demonstrates how to create a SqlNotificationRequest and associate it with a
SqlCommand.
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
SqlCommand command=new SqlCommand(
"SELECT ShipperID, CompanyName, Phone FROM dbo.Shippers", connection);

// Create a SqlNotificationRequest object.


SqlNotificationRequest notificationRequest=new SqlNotificationRequest();
notificationRequest.id="NotificationID";
notificationRequest.Service="mySSBQueue";

// Associate the notification request with the command.


command.Notification=notificationRequest;
// Execute the command.
command.ExecuteReader();
// Process the DataReader.
// You can use Transact-SQL syntax to periodically poll the
// SQL Server queue to see if you have a new message.

Next steps
Query notifications in SQL Server
Snapshot isolation in SQL Server
4/27/2022 • 15 minutes to read • Edit Online

Download ADO.NET
Snapshot isolation enhances concurrency for OLTP applications.

Understanding snapshot isolation and row versioning


Once snapshot isolation is enabled, updated row versions for each transaction are maintained in tempdb . A
unique transaction sequence number identifies each transaction, and these unique numbers are recorded for
each row version. The transaction works with the most recent row versions having a sequence number before
the sequence number of the transaction. Newer row versions created after the transaction has begun are
ignored by the transaction.
The term "snapshot" reflects the fact that all queries in the transaction see the same version, or snapshot, of the
database, based on the state of the database at the moment in time when the transaction begins. No locks are
acquired on the underlying data rows or data pages in a snapshot transaction, which permits other transactions
to execute without being blocked by a prior incompleted transaction. Transactions that modify data do not block
transactions that read data, and transactions that read data do not block transactions that write data, as they
normally would under the default READ COMMITTED isolation level in SQL Server. This non-blocking behavior
also significantly reduces the likelihood of deadlocks for complex transactions.
Snapshot isolation uses an optimistic concurrency model. If a snapshot transaction attempts to commit
modifications to data that has changed since the transaction began, the transaction will roll back and an error
will be raised. You can avoid this by using UPDLOCK hints for SELECT statements that access data to be
modified. See "Locking Hints" in SQL Server Books Online for more information.
Snapshot isolation must be enabled by setting the ALLOW_SNAPSHOT_ISOLATION ON database option before
it is used in transactions. This activates the mechanism for storing row versions in the temporary database
(tempdb ). You must enable snapshot isolation in each database that uses it with the Transact-SQL ALTER
DATABASE statement. In this respect, snapshot isolation differs from the traditional isolation levels of READ
COMMITTED, REPEATABLE READ, SERIALIZABLE, and READ UNCOMMITTED, which require no configuration. The
following statements activate snapshot isolation and replace the default READ COMMITTED behavior with
SNAPSHOT:

ALTER DATABASE MyDatabase


SET ALLOW_SNAPSHOT_ISOLATION ON

ALTER DATABASE MyDatabase


SET READ_COMMITTED_SNAPSHOT ON

Setting the READ_COMMITTED_SNAPSHOT ON option allows access to versioned rows under the default READ
COMMITTED isolation level. If the READ_COMMITTED_SNAPSHOT option is set to OFF, you must explicitly set
the Snapshot isolation level for each session in order to access versioned rows.

Managing concurrency with isolation levels


The isolation level under which a Transact-SQL statement executes determines its locking and row versioning
behavior. An isolation level has connection-wide scope, and once set for a connection with the SET
TRANSACTION ISOLATION LEVEL statement, it remains in effect until the connection is closed or another
isolation level is set. When a connection is closed and returned to the pool, the isolation level from the last SET
TRANSACTION ISOLATION LEVEL statement is retained. Subsequent connections reusing a pooled connection
use the isolation level that was in effect at the time the connection is pooled.
Individual queries issued within a connection can contain lock hints that modify the isolation for a single
statement or transaction but do not affect the isolation level of the connection. Isolation levels or lock hints set in
stored procedures or functions do not change the isolation level of the connection that calls them and are in
effect only for the duration of the stored procedure or function call.
Four isolation levels defined in the SQL-92 standard were supported in early versions of SQL Server:
READ UNCOMMITTED is the least restrictive isolation level because it ignores locks placed by other
transactions. Transactions executing under READ UNCOMMITTED can read modified data values that
have not yet been committed by other transactions; these are called "dirty" reads.
READ COMMITTED is the default isolation level for SQL Server. It prevents dirty reads by specifying that
statements cannot read data values that have been modified but not yet committed by other transactions.
Other transactions can still modify, insert, or delete data between executions of individual statements
within the current transaction, resulting in non-repeatable reads, or "phantom" data.
REPEATABLE READ is a more restrictive isolation level than READ COMMITTED. It encompasses READ
COMMITTED and additionally specifies that no other transactions can modify or delete data that has been
read by the current transaction until the current transaction commits. Concurrency is lower than for READ
COMMITTED because shared locks on read data are held for the duration of the transaction instead of
being released at the end of each statement.
SERIALIZABLE is the most restrictive isolation level, because it locks entire ranges of keys and holds the
locks until the transaction is complete. It encompasses REPEATABLE READ and adds the restriction that
other transactions cannot insert new rows into ranges that have been read by the transaction until the
transaction is complete.
For more information, refer to the Transaction Locking and Row Versioning Guide.
Snapshot isolation level extensions
SQL Server introduced extensions to the SQL-92 isolation levels with the introduction of the SNAPSHOT
isolation level and an additional implementation of READ COMMITTED. The READ_COMMITTED_SNAPSHOT
isolation level can transparently replace READ COMMITTED for all transactions.
SNAPSHOT isolation specifies that data read within a transaction will never reflect changes made by
other simultaneous transactions. The transaction uses the data row versions that exist when the
transaction begins. No locks are placed on the data when it is read, so SNAPSHOT transactions do not
block other transactions from writing data. Transactions that write data do not block snapshot
transactions from reading data. You need to enable snapshot isolation by setting the
ALLOW_SNAPSHOT_ISOLATION database option in order to use it.
The READ_COMMITTED_SNAPSHOT database option determines the behavior of the default READ
COMMITTED isolation level when snapshot isolation is enabled in a database. If you do not explicitly
specify READ_COMMITTED_SNAPSHOT ON, READ COMMITTED is applied to all implicit transactions. This
produces the same behavior as setting READ_COMMITTED_SNAPSHOT OFF (the default). When
READ_COMMITTED_SNAPSHOT OFF is in effect, the Database Engine uses shared locks to enforce the
default isolation level. If you set the READ_COMMITTED_SNAPSHOT database option to ON, the database
engine uses row versioning and snapshot isolation as the default, instead of using locks to protect the
data.

How snapshot isolation and row versioning work


When the SNAPSHOT isolation level is enabled, each time a row is updated, the SQL Server Database Engine
stores a copy of the original row in tempdb , and adds a transaction sequence number to the row. The following
is the sequence of events that occurs:
1. A new transaction is initiated, and it is assigned a transaction sequence number.
2. The Database Engine reads a row within the transaction and retrieves the row version from tempdb
whose sequence number is closest to, and lower than, the transaction sequence number.
3. The Database Engine checks to see if the transaction sequence number is not in the list of transaction
sequence numbers of the uncommitted transactions active when the snapshot transaction started.
4. The transaction reads the version of the row from tempdb that was current as of the start of the
transaction. It will not see new rows inserted after the transaction was started because those sequence
number values will be higher than the value of the transaction sequence number.
5. The current transaction will see rows that were deleted after the transaction began, because there will be
a row version in tempdb with a lower sequence number value.
The net effect of snapshot isolation is that the transaction sees all of the data as it existed at the start of the
transaction, without honoring or placing any locks on the underlying tables. This can result in performance
improvements in situations where there is contention.
A snapshot transaction always uses optimistic concurrency control, withholding any locks that would prevent
other transactions from updating rows. If a snapshot transaction attempts to commit an update to a row that
was changed after the transaction began, the transaction is rolled back, and an error is raised.

Working with snapshot isolation in ADO.NET


Snapshot isolation is supported in ADO.NET by the SqlTransaction class. If a database has been enabled for
snapshot isolation but is not configured for READ_COMMITTED_SNAPSHOT ON, you must initiate a
SqlTransaction using the IsolationLevel.Snapshot enumeration value when calling the BeginTransaction
method. This code fragment assumes that connection is an open SqlConnection object.

SqlTransaction sqlTran =
connection.BeginTransaction(IsolationLevel.Snapshot);

Example
The following example demonstrates how the different isolation levels behave by attempting to access locked
data, and it is not intended to be used in production code.
The code connects to the AdventureWorks sample database in SQL Server and creates a table named
TestSnapshot and inserts one row of data. The code uses the ALTER DATABASE Transact-SQL statement to turn
on snapshot isolation for the database, but it does not set the READ_COMMITTED_SNAPSHOT option, leaving
the default READ COMMITTED isolation-level behavior in effect. The code then performs the following actions:
1. It begins, but does not complete, sqlTransaction1, which uses the SERIALIZABLE isolation level to start an
update transaction. This has the effect of locking the table.
2. It opens a second connection and initiates a second transaction using the SNAPSHOT isolation level to
read the data in the TestSnapshot table. Because snapshot isolation is enabled, this transaction can read
the data that existed before sqlTransaction1 started.
3. It opens a third connection and initiates a transaction using the READ COMMITTED isolation level to
attempt to read the data in the table. In this case, the code cannot read the data because it cannot read
past the locks placed on the table in the first transaction and times out. The same result would occur if the
REPEATABLE READ and SERIALIZABLE isolation levels were used because these isolation levels also
cannot read past the locks placed in the first transaction.
4. It opens a fourth connection and initiates a transaction using the READ UNCOMMITTED isolation level,
which performs a dirty read of the uncommitted value in sqlTransaction1. This value may never actually
exist in the database if the first transaction is not committed.
5. It rolls back the first transaction and cleans up by deleting the TestSnapshot table and turning off
snapshot isolation for the AdventureWorks database.

NOTE
The following examples use the same connection string with connection pooling turned off. If a connection is pooled,
resetting its isolation level does not reset the isolation level at the server. As a result, subsequent connections that use the
same pooled inner connection start with their isolation levels set to that of the pooled connection. An alternative to
turning off connection pooling is to set the isolation level explicitly for each connection.

using Microsoft.Data.SqlClient;

class Program
{
static void Main()
{
// Assumes GetConnectionString returns a valid connection string
// where pooling is turned off by setting Pooling=False;.
string connectionString = GetConnectionString();
using (SqlConnection connection1 = new SqlConnection(connectionString))
{
// Drop the TestSnapshot table if it exists
connection1.Open();
SqlCommand command1 = connection1.CreateCommand();
command1.CommandText = "IF EXISTS "
+ "(SELECT * FROM sys.tables WHERE name=N'TestSnapshot') "
+ "DROP TABLE TestSnapshot";
try
{
command1.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// Enable Snapshot isolation
command1.CommandText =
"ALTER DATABASE AdventureWorks SET ALLOW_SNAPSHOT_ISOLATION ON";
command1.ExecuteNonQuery();

// Create a table named TestSnapshot and insert one row of data


command1.CommandText =
"CREATE TABLE TestSnapshot (ID int primary key, valueCol int)";
command1.ExecuteNonQuery();
command1.CommandText =
"INSERT INTO TestSnapshot VALUES (1,1)";
command1.ExecuteNonQuery();

// Begin, but do not complete, a transaction to update the data


// with the Serializable isolation level, which locks the table
// pending the commit or rollback of the update. The original
// value in valueCol was 1, the proposed new value is 22.
SqlTransaction transaction1 =
connection1.BeginTransaction(IsolationLevel.Serializable);
command1.Transaction = transaction1;
command1.CommandText =
"UPDATE TestSnapshot SET valueCol=22 WHERE ID=1";
"UPDATE TestSnapshot SET valueCol=22 WHERE ID=1";
command1.ExecuteNonQuery();

// Open a second connection to AdventureWorks


using (SqlConnection connection2 = new SqlConnection(connectionString))
{
connection2.Open();
// Initiate a second transaction to read from TestSnapshot
// using Snapshot isolation. This will read the original
// value of 1 since transaction1 has not yet committed.
SqlCommand command2 = connection2.CreateCommand();
SqlTransaction transaction2 =
connection2.BeginTransaction(IsolationLevel.Snapshot);
command2.Transaction = transaction2;
command2.CommandText =
"SELECT ID, valueCol FROM TestSnapshot";
SqlDataReader reader2 = command2.ExecuteReader();
while (reader2.Read())
{
Console.WriteLine("Expected 1,1 Actual "
+ reader2.GetValue(0).ToString()
+ "," + reader2.GetValue(1).ToString());
}
transaction2.Commit();
}

// Open a third connection to AdventureWorks and


// initiate a third transaction to read from TestSnapshot
// using ReadCommitted isolation level. This transaction
// will not be able to view the data because of
// the locks placed on the table in transaction1
// and will time out after 4 seconds.
// You would see the same behavior with the
// RepeatableRead or Serializable isolation levels.
using (SqlConnection connection3 = new SqlConnection(connectionString))
{
connection3.Open();
SqlCommand command3 = connection3.CreateCommand();
SqlTransaction transaction3 =
connection3.BeginTransaction(IsolationLevel.ReadCommitted);
command3.Transaction = transaction3;
command3.CommandText =
"SELECT ID, valueCol FROM TestSnapshot";
command3.CommandTimeout = 4;
try
{
SqlDataReader sqldatareader3 = command3.ExecuteReader();
while (sqldatareader3.Read())
{
Console.WriteLine("You should never hit this.");
}
transaction3.Commit();
}
catch (Exception ex)
{
Console.WriteLine("Expected timeout expired exception: "
+ ex.Message);
transaction3.Rollback();
}
}

// Open a fourth connection to AdventureWorks and


// initiate a fourth transaction to read from TestSnapshot
// using the ReadUncommitted isolation level. ReadUncommitted
// will not hit the table lock, and will allow a dirty read
// of the proposed new value 22 for valueCol. If the first
// transaction rolls back, this value will never actually have
// existed in the database.
using (SqlConnection connection4 = new SqlConnection(connectionString))
{
{
connection4.Open();
SqlCommand command4 = connection4.CreateCommand();
SqlTransaction transaction4 =
connection4.BeginTransaction(IsolationLevel.ReadUncommitted);
command4.Transaction = transaction4;
command4.CommandText =
"SELECT ID, valueCol FROM TestSnapshot";
SqlDataReader reader4 = command4.ExecuteReader();
while (reader4.Read())
{
Console.WriteLine("Expected 1,22 Actual "
+ reader4.GetValue(0).ToString()
+ "," + reader4.GetValue(1).ToString());
}

transaction4.Commit();
}

// Roll back the first transaction


transaction1.Rollback();
}

// CLEANUP
// Delete the TestSnapshot table and set
// ALLOW_SNAPSHOT_ISOLATION OFF
using (SqlConnection connection5 = new SqlConnection(connectionString))
{
connection5.Open();
SqlCommand command5 = connection5.CreateCommand();
command5.CommandText = "DROP TABLE TestSnapshot";
SqlCommand command6 = connection5.CreateCommand();
command6.CommandText =
"ALTER DATABASE AdventureWorks SET ALLOW_SNAPSHOT_ISOLATION OFF";
try
{
command5.ExecuteNonQuery();
command6.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Console.WriteLine("Done!");
}

static private string GetConnectionString()


{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file, using the
// System.Configuration.ConfigurationSettings.AppSettings property
return "Data Source=localhost;Initial Catalog=AdventureWorks;"
+ "Integrated Security=SSPI";
}
}

Example
The following example demonstrates the behavior of snapshot isolation when data is being modified. The code
performs the following actions:
1. Connects to the AdventureWorks sample database and enables SNAPSHOT isolation.
2. Creates a table named TestSnapshotUpdate and inserts three rows of sample data.
3. Begins, but does not complete, sqlTransaction1 using SNAPSHOT isolation. Three rows of data are
selected in the transaction.
4. Creates a second SqlConnection to AdventureWorks and creates a second transaction using the READ
COMMITTED isolation level that updates a value in one of the rows selected in sqlTransaction1.
5. Commits sqlTransaction2.
6. Returns to sqlTransaction1 and attempts to update the same row that sqlTransaction1 already committed.
Error 3960 is raised, and sqlTransaction1 is rolled back automatically. The SqlException.Number and
SqlException.Message are displayed in the Console window.
7. Executes clean-up code to turn off snapshot isolation in AdventureWorks and delete the
TestSnapshotUpdate table.

using Microsoft.Data.SqlClient;
using System.Data.Common;

class Program
{
static void Main()
{
// Assumes GetConnectionString returns a valid connection string
// where pooling is turned off by setting Pooling=False;.
string connectionString = GetConnectionString();
using (SqlConnection connection1 = new SqlConnection(connectionString))
{
connection1.Open();
SqlCommand command1 = connection1.CreateCommand();

// Enable Snapshot isolation in AdventureWorks


command1.CommandText =
"ALTER DATABASE AdventureWorks SET ALLOW_SNAPSHOT_ISOLATION ON";
try
{
command1.ExecuteNonQuery();
Console.WriteLine(
"Snapshot Isolation turned on in AdventureWorks.");
}
catch (Exception ex)
{
Console.WriteLine("ALLOW_SNAPSHOT_ISOLATION ON failed: {0}", ex.Message);
}
// Create a table
command1.CommandText =
"IF EXISTS "
+ "(SELECT * FROM sys.tables "
+ "WHERE name=N'TestSnapshotUpdate')"
+ " DROP TABLE TestSnapshotUpdate";
command1.ExecuteNonQuery();
command1.CommandText =
"CREATE TABLE TestSnapshotUpdate "
+ "(ID int primary key, CharCol nvarchar(100));";
try
{
command1.ExecuteNonQuery();
Console.WriteLine("TestSnapshotUpdate table created.");
}
catch (Exception ex)
{
Console.WriteLine("CREATE TABLE failed: {0}", ex.Message);
}
// Insert some data
command1.CommandText =
"INSERT INTO TestSnapshotUpdate VALUES (1,N'abcdefg');"
+ "INSERT INTO TestSnapshotUpdate VALUES (2,N'hijklmn');"
+ "INSERT INTO TestSnapshotUpdate VALUES (3,N'opqrstuv');";
try
{
{
command1.ExecuteNonQuery();
Console.WriteLine("Data inserted TestSnapshotUpdate table.");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

// Begin, but do not complete, a transaction


// using the Snapshot isolation level.
SqlTransaction transaction1 = null;
try
{
transaction1 = connection1.BeginTransaction(IsolationLevel.Snapshot);
command1.CommandText =
"SELECT * FROM TestSnapshotUpdate WHERE ID BETWEEN 1 AND 3";
command1.Transaction = transaction1;
command1.ExecuteNonQuery();
Console.WriteLine("Snapshot transaction1 started.");

// Open a second Connection/Transaction to update data


// using ReadCommitted. This transaction should succeed.
using (SqlConnection connection2 = new SqlConnection(connectionString))
{
connection2.Open();
SqlCommand command2 = connection2.CreateCommand();
command2.CommandText = "UPDATE TestSnapshotUpdate SET CharCol="
+ "N'New value from Connection2' WHERE ID=1";
SqlTransaction transaction2 =
connection2.BeginTransaction(IsolationLevel.ReadCommitted);
command2.Transaction = transaction2;
try
{
command2.ExecuteNonQuery();
transaction2.Commit();
Console.WriteLine(
"transaction2 has modified data and committed.");
}
catch (SqlException ex)
{
Console.WriteLine(ex.Message);
transaction2.Rollback();
}
finally
{
transaction2.Dispose();
}
}

// Now try to update a row in Connection1/Transaction1.


// This transaction should fail because Transaction2
// succeeded in modifying the data.
command1.CommandText =
"UPDATE TestSnapshotUpdate SET CharCol="
+ "N'New value from Connection1' WHERE ID=1";
command1.Transaction = transaction1;
command1.ExecuteNonQuery();
transaction1.Commit();
Console.WriteLine("You should never see this.");
}
catch (SqlException ex)
{
Console.WriteLine("Expected failure for transaction1:");
Console.WriteLine(" {0}: {1}", ex.Number, ex.Message);
}
finally
{
transaction1.Dispose();
}
}
}

// CLEANUP:
// Turn off Snapshot isolation and delete the table
using (SqlConnection connection3 = new SqlConnection(connectionString))
{
connection3.Open();
SqlCommand command3 = connection3.CreateCommand();
command3.CommandText =
"ALTER DATABASE AdventureWorks SET ALLOW_SNAPSHOT_ISOLATION OFF";
try
{
command3.ExecuteNonQuery();
Console.WriteLine(
"CLEANUP: Snapshot isolation turned off in AdventureWorks.");
}
catch (Exception ex)
{
Console.WriteLine("CLEANUP FAILED: {0}", ex.Message);
}
command3.CommandText = "DROP TABLE TestSnapshotUpdate";
try
{
command3.ExecuteNonQuery();
Console.WriteLine("CLEANUP: TestSnapshotUpdate table deleted.");
}
catch (Exception ex)
{
Console.WriteLine("CLEANUP FAILED: {0}", ex.Message);
}
}
Console.WriteLine("Done");
Console.ReadLine();
}

static private string GetConnectionString()


{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file, using the
// System.Configuration.ConfigurationSettings.AppSettings property
return "Data Source=(local);Initial Catalog=AdventureWorks;"
+ "Integrated Security=SSPI;Pooling=false";
}

Using lock hints with snapshot isolation


In the previous example, the first transaction selects data, and a second transaction updates the data before the
first transaction is able to complete, causing an update conflict when the first transaction tries to update the
same row. You can reduce the chance of update conflicts in long-running snapshot transactions by supplying
lock hints at the beginning of the transaction. The following SELECT statement uses the UPDLOCK hint to lock
the selected rows:

SELECT * FROM TestSnapshotUpdate WITH (UPDLOCK)


WHERE PriKey BETWEEN 1 AND 3

Using the UPDLOCK lock hint blocks any rows attempting to update the rows before the first transaction
completes. This guarantees that the selected rows have no conflicts when they are updated later in the
transaction. See "Locking Hints" in SQL Server Books Online.
If your application has many conflicts, snapshot isolation may not be the best choice. Hints should only be used
when really needed. Your application should not be designed so that it constantly relies on lock hints for its
operation.

Next steps
SQL Server and ADO.NET
Transaction Locking and Row Versioning Guide
SqlClient support for high availability, disaster
recovery
4/27/2022 • 5 minutes to read • Edit Online

Download ADO.NET
This topic discusses Microsoft SqlClient Data Provider for SQL Server support for high-availability, disaster
recovery -- AlwaysOn Availability Groups. AlwaysOn Availability Groups feature was added to SQL Server 2012.
For more information about AlwaysOn Availability Groups, see SQL Server Books Online.
You can now specify the availability group listener of a (high-availability, disaster-recovery) availability group
(AG) or SQL Server 2012 Failover Cluster Instance in the connection property. If a SqlClient application is
connected to an AlwaysOn database that fails over, the original connection is broken and the application must
open a new connection to continue work after the failover.
If you are not connecting to an availability group listener or SQL Server 2012 Failover Cluster Instance, and if
multiple IP addresses are associated with a hostname, SqlClient will iterate sequentially through all IP addresses
associated with DNS entry. This can be time consuming if the first IP address returned by DNS server is not
bound to any network interface card (NIC). When connecting to an availability group listener or SQL Server
2012 Failover Cluster Instance, SqlClient attempts to establish connections to all IP addresses in parallel and if a
connection attempt succeeds, the driver will discard any pending connection attempts.

NOTE
Increasing connection timeout and implementing connection retry logic will increase the probability that an application
will connect to an availability group. Also, because a connection can fail because of a failover, you should implement
connection retry logic, retrying a failed connection until it reconnects.

The following connection properties are supported in the Microsoft SqlClient Data Provider for SQL Server:
ApplicationIntent

MultiSubnetFailover

You can programmatically modify these connection string keywords with:


ApplicationIntent
MultiSubnetFailover

Connecting With MultiSubnetFailover


Always specify MultiSubnetFailover=True when connecting to a SQL Server 2012 availability group listener or
SQL Server 2012 Failover Cluster Instance. MultiSubnetFailover enables faster failover for all Availability
Groups and or Failover Cluster Instance in SQL Server 2012 and will significantly reduce failover time for single
and multi-subnet AlwaysOn topologies. During a multi-subnet failover, the client will attempt connections in
parallel. During a subnet failover, will aggressively retry the TCP connection.
The MultiSubnetFailover connection property indicates that the application is being deployed in an availability
group or SQL Server 2012 Failover Cluster Instance and that SqlClient will try to connect to the database on the
primary SQL Server instance by trying to connect to all the IP addresses. When MultiSubnetFailover=True is
specified for a connection, the client retries TCP connection attempts faster than the operating system’s default
TCP retransmit intervals. This enables faster reconnection after failover of either an AlwaysOn Availability Group
or an AlwaysOn Failover Cluster Instance, and is applicable to both single- and multi-subnet Availability Groups
and Failover Cluster Instances.
For more information about connection string keywords in SqlClient, see ConnectionString.
Specifying MultiSubnetFailover=True when connecting to something other than a availability group listener or
SQL Server 2012 Failover Cluster Instance may result in a negative performance impact, and is not supported.
Use the following guidelines to connect to a server in an availability group or SQL Server 2012 Failover Cluster
Instance:
Use the MultiSubnetFailover connection property when connecting to a single subnet or multi-subnet; it
will improve performance for both.
To connect to an availability group, specify the availability group listener of the availability group as the
server in your connection string.
Connecting to a SQL Server instance configured with more than 64 IP addresses will cause a connection
failure.
Behavior of an application that uses the MultiSubnetFailover connection property is not affected based
on the type of authentication: SQL Server Authentication, Kerberos Authentication, or Windows
Authentication.
Increase the value of Connect Timeout to accommodate for failover time and reduce application
connection retry attempts.
Distributed transactions are not supported.
If read-only routing is not in effect, connecting to a secondary replica location will fail in the following situations:
If the secondary replica location is not configured to accept connections.
If an application uses ApplicationIntent=ReadWrite (discussed below) and the secondary replica location
is configured for read-only access.
SqlDependency is not supported on read-only secondary replicas.
A connection will fail if a primary replica is configured to reject read-only workloads and the connection string
contains ApplicationIntent=ReadOnly .

Upgrading to use multi-subnet clusters from database mirroring


A connection error (ArgumentException) will occur if the MultiSubnetFailover and Failover Partner connection
keywords are present in the connection string, or if MultiSubnetFailover=True and a protocol other than TCP is
used. An error (SqlException) will also occur if MultiSubnetFailover is used and the SQL Server returns a
failover partner response indicating it is part of a database mirroring pair.
If you upgrade a SqlClient application that currently uses database mirroring to a multi-subnet scenario, you
should remove the Failover Partner connection property and replace it with MultiSubnetFailover set to True
and replace the server name in the connection string with an availability group listener. If a connection string
uses Failover Partner and MultiSubnetFailover=True , the driver will generate an error. However, if a connection
string uses Failover Partner and MultiSubnetFailover=False (or ApplicationIntent=ReadWrite ), the application
will use database mirroring.
The driver will return an error if database mirroring is used on the primary database in the AG, and if
MultiSubnetFailover=True is used in the connection string that connects to a primary database instead of to an
availability group listener.

Specifying application intent


When ApplicationIntent=ReadOnly , the client requests a read workload when connecting to an AlwaysOn
enabled database. The server will enforce the intent at connection time and during a USE database statement
but only to an Always On enabled database.
The ApplicationIntent keyword does not work with legacy, read-only databases.
A database can allow or disallow read workloads on the targeted AlwaysOn database. (This is done with the
ALLOW_CONNECTIONS clause of the PRIMARY_ROLE and SECONDARY_ROLE Transact-SQL statements.)

The ApplicationIntent keyword is used to enable read-only routing.

Read-only routing
Read-only routing is a feature that can ensure the availability of a read only replica of a database. To enable
read-only routing:
You must connect to an Always On Availability Group availability group listener.
The ApplicationIntent connection string keyword must be set to ReadOnly .
The Availability Group must be configured by the database administrator to enable read-only routing.
It is possible that multiple connections using read-only routing will not all connect to the same read-only replica.
Changes in database synchronization or changes in the server's routing configuration can result in client
connections to different read-only replicas. To ensure that all read-only requests connect to the same read-only
replica, do not pass an availability group listener to the Data Source connection string keyword. Instead, specify
the name of the read-only instance.
Read-only routing may take longer than connecting to the primary because read only routing first connects to
the primary and then looks for the best available readable secondary. Because of this, you should increase your
login timeout.

Next steps
SQL Server features and ADO.NET
SqlClient support for LocalDB
4/27/2022 • 2 minutes to read • Edit Online

Download ADO.NET
Beginning in SQL Server code name Denali, a lightweight version of SQL Server, called LocalDB, will be
available. This topic discusses how to connect to a LocalDB database.

Remarks
For more information about LocalDB, including how to install LocalDB and configure your LocalDB instance, see
SQL Server Books Online.
To summarize what you can do with LocalDB:
Create and start LocalDB instances with sqllocaldb.exe or your app.config file.
Use sqlcmd.exe to add and modify databases in a LocalDB instance. For example,
sqlcmd -S (localdb)\myinst .

Use the AttachDBFilename connection string keyword to add a database to your LocalDB instance. When
using AttachDBFilename , if you do not specify the name of the database with the Database connection
string keyword, the database will be removed from the LocalDB instance when the application closes.
Specify a LocalDB instance in your connection string. For example, your instance name is myInstance , the
connection string would include:

server=(localdb)\\myInstance

User Instance=True is not allowed when connecting to a LocalDB database.


You can download LocalDB from Microsoft SQL Server 2012 Feature Pack. If you will use sqlcmd.exe to modify
data in your LocalDB instance, you will need sqlcmd from SQL Server 2012, which you can also get from the
SQL Server 2012 Feature Pack.

Programmatically create a named instance


An application can create a named instance and specify a database as follows:
Specify the LocalDB instances to create in the app.config file, as follows. The version number of the
instance should be the same as the version number of your LocalDB installation.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="system.data.localdb"

type="System.Data.LocalDBConfigurationSection,System.Data,Version=4.0.0.0,Culture=neutral,PublicKeyTo
ken=b77a5c561934e089"/>
</configSections>
<system.data.localdb>
<localdbinstances>
<add name="myInstance" version="11.0" />
</localdbinstances>
</system.data.localdb>
</configuration>

Specify the name of the instance using the server connection string keyword. The instance name
specified in the server connection string keyword must match the name specified in the app.config file.
Use the AttachDBFilename connection string keyword to specify the .MDF file.

Next steps
SQL Server features and ADO.NET
Using Always Encrypted with the Microsoft .NET
Data Provider for SQL Server
4/27/2022 • 37 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard


This article provides information on how to develop .NET applications using Always Encrypted or Always
Encrypted with secure enclaves and the Microsoft .NET Data Provider for SQL Ser ver .
Always Encrypted allows client applications to encrypt sensitive data and never reveal the data or the encryption
keys to SQL Server or Azure SQL Database. An Always Encrypted enabled driver, such as the Microsoft .NET
Data Provider for SQL Ser ver , achieves this security by transparently encrypting and decrypting sensitive
data in the client application. The driver automatically determines which query parameters correspond to
sensitive database columns (protected using Always Encrypted), and encrypts the values of those parameters
before passing the data to the server. Similarly, the driver transparently decrypts data retrieved from encrypted
database columns in query results. For more information, see Develop applications using Always Encrypted and
Develop applications using Always Encrypted with secure enclaves.

Prerequisites
Configure Always Encrypted in your database. This process involves provisioning Always Encrypted keys and
setting up encryption for selected database columns. If you don't already have a database with Always
Encrypted configured, follow the directions in Getting Started with Always Encrypted.
If you're using Always Encrypted with secure enclaves, see Develop applications using Always Encrypted with
secure enclaves for more prerequisites.
Ensure the required .NET platform is installed on your development machine. With Microsoft.Data.SqlClient,
the Always Encrypted feature is supported for both .NET Framework and .NET Core. Make sure .NET
Framework 4.6 or higher, or .NET Core 2.1 or higher is configured as the target .NET platform version in your
development environment. With Microsoft.Data.SqlClient version 2.1.0 and higher, the Always Encrypted
feature is also supported for .NET Standard 2.0. To use Always Encrypted with secure enclaves, .NET Standard
2.1 is required. If you're using Visual Studio, refer to Framework targeting overview.
The following table summarizes the required .NET platforms to use Always Encrypted with
Microsoft.Data.SqlClient .

SUP P O RT A L WAY S
SUP P O RT A L WAY S EN C RY P T ED W IT H TA RGET M IC RO SO F T. DATA . SQ
EN C RY P T ED SEC URE EN C L AVE F RA M EW O RK L C L IEN T VERSIO N O P ERAT IN G SY ST EM

Yes Yes .NET Framework 4.6+ 1.1.0+ Windows

Yes Yes .NET Core 2.1+ 2.1.0+1 Windows, Linux,


macOS

Yes No .NET Standard 2.0 2.1.0+ Windows, Linux,


macOS

Yes Yes .NET Standard 2.1+ 2.1.0+ Windows, Linux,


macOS
NOTE
1 Before Microsoft.Data.SqlClient version 2.1.0, Always Encrypted is only supported on Windows.

Enabling Always Encrypted for application queries


The easiest way to enable the encryption of parameters and the decryption of query results targeting encrypted
columns, is by setting the value of the Column Encryption Setting connection string keyword to enabled .
The following example uses a connection string that enables Always Encrypted:

string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column


Encryption Setting=enabled";
SqlConnection connection = new SqlConnection(connectionString);

The following code snippet is an equivalent example using the


SqlConnectionStringBuilder.ColumnEncryptionSetting Property.

SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();


builder.DataSource = "server63";
builder.InitialCatalog = "Clinic";
builder.IntegratedSecurity = true;
builder.ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled;
SqlConnection connection = new SqlConnection(builder.ConnectionString);
connection.Open();

Always Encrypted can also be enabled for individual queries. See the Controlling the performance impact
of Always Encr ypted section below. Enabling Always Encrypted isn't sufficient for encryption or decryption to
succeed. You also need to make sure:
The application has the VIEW ANY COLUMN MASTER KEY DEFINITION and VIEW ANY COLUMN
ENCRYPTION KEY DEFINITION database permissions, required to access the metadata about Always
Encrypted keys in the database. For details, see the Database Permissions section in Always Encrypted
(Database Engine).
The application can access the column master key that protects the column encryption keys, which encrypt
the queried database columns.

Enabling Always Encrypted with secure enclaves


Beginning with Microsoft.Data.SqlClient version 1.1.0, the driver supports Always Encrypted with secure
enclaves.
For general information on developing applications using enclaves, see Develop applications using Always
Encrypted with secure enclaves.
To enable enclave computations for a database connection, you must set the following connection string
keywords, in addition to enabling Always Encrypted (as explained in the previous section):
Attestation Protocol - specifies an attestation protocol.
If this keyword isn't specified, secure enclaves are disabled on the connection.
If you're using SQL Server and Host Guardian Service (HGS), the value of this keyword should be HGS
.
If you're using Azure SQL Database and Microsoft Azure Attestation, the value of this keyword should
be AAS .
If you're using Virtualization-based security (VBS) enclaves and want to forgo attestation, the value of
this keyword should be None . This option is less secure than the others and should only be used
when attestation isn't possible in your environment and you trust the server. Skipping attestation
opens the application up to the possibility of a malicious server making claims that results in exposure
of column encryption keys to the server.
Enclave Attestation URL - specifies an attestation URL (an attestation service endpoint). You need to
obtain an attestation URL for your environment from your attestation service administrator.
If you're using SQL Server and Host Guardian Service (HGS), see Determine and share the HGS
attestation URL.
If you're using Azure SQL Database and Microsoft Azure Attestation, see Determine the attestation
URL for your attestation policy.
If you're using the None Attestation Protocol, an attestation URL is not required.
For a step-by-step tutorial, see Tutorial: Develop a .NET application using Always Encrypted with secure enclaves.

Retrieving and modifying data in encrypted columns


Once you enable Always Encrypted for application queries, you can use standard SqlClient APIs (see Retrieving
and Modifying Data in ADO.NET) or the Microsoft .NET Data Provider for SQL Ser ver APIs, defined in the
Microsoft.Data.SqlClient Namespace, to retrieve or modify data in encrypted database columns. If your
application has the required database permissions and can access the column master key, the Microsoft .NET
Data Provider for SQL Ser ver will encrypt any query parameters that target encrypted columns, and will
decrypt data retrieved from encrypted columns, returning plaintext values of .NET types corresponding to the
SQL Server data types set for the columns in the database schema. If Always Encrypted isn't enabled, queries
with parameters that target encrypted columns will fail. Queries can still retrieve data from encrypted columns
as long as the query has no parameters targeting encrypted columns. However, the Microsoft .NET Data
Provider for SQL Ser ver won't attempt to decrypt any values retrieved from encrypted columns and the
application will receive binary encrypted data (as byte arrays).
The following table summarizes the behavior of queries, depending on whether Always Encrypted is enabled or
not:

A L WAY S EN C RY P T ED IS A L WAY S EN C RY P T ED IS
EN A B L ED A N D T H E EN A B L ED A N D T H E
A P P L IC AT IO N C A N A C C ESS A P P L IC AT IO N C A N 'T
T H E K EY S A N D K EY A C C ESS T H E K EY S O R K EY A L WAY S EN C RY P T ED IS
Q UERY C H A RA C T ERIST IC M ETA DATA M ETA DATA DISA B L ED

Queries with parameters Parameter values are Error Error


targeting encrypted transparently encrypted.
columns.

Queries retrieving data Results from encrypted Error Results from encrypted
from encrypted columns columns are transparently columns aren't decrypted.
without parameters decrypted. The application The application receives
targeting encrypted receives plaintext values of encrypted values as byte
columns. the .NET data types arrays (byte[]).
corresponding to the SQL
Server types configured for
the encrypted columns.

The following examples illustrate retrieving and modifying data in encrypted columns. The examples assume the
target table with the below schema. The SSN and BirthDate columns are encrypted.
CREATE TABLE [dbo].[Patients]([PatientId] [int] IDENTITY(1,1),
[SSN] [char](11) COLLATE Latin1_General_BIN2
ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC,
ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256',
COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[BirthDate] [date]
ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED,
ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256',
COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL
PRIMARY KEY CLUSTERED ([PatientId] ASC) ON [PRIMARY])
GO

Inserting data example


This example inserts a row into the Patients table. Note the following details:
There isn't anything specific to encryption in the sample code. The Microsoft .NET Data Provider for SQL
Ser ver automatically detects and encrypts the paramSSN and paramBirthdate parameters that target
encrypted columns. This behavior makes encryption transparent to the application.
The values inserted into database columns, including the encrypted columns, are passed as SqlParameter
objects. While using SqlParameter is optional when sending values to non-encrypted columns (although,
it's highly recommended because it helps prevent SQL injection), it's required for values targeting encrypted
columns. If the values inserted in the SSN or BirthDate columns were passed as literals embedded in the
query statement, the query would fail because the Microsoft .NET Data Provider for SQL Ser ver
wouldn't be able to determine the values in the target encrypted columns, so it wouldn't encrypt the values.
As a result, the server would reject them as incompatible with the encrypted columns.
The data type of the parameter targeting the SSN column is set to an ANSI (non-Unicode) string, which
maps to the char/varchar SQL Server data type. If the type of the parameter was set to a Unicode string
(String), which maps to nchar/nvarchar, the query would fail, as Always Encrypted doesn't support
conversions from encrypted nchar/nvarchar values to encrypted char/varchar values. See SQL Server Data
Type Mappings for information about the data type mappings.
The data type of the parameter inserted into the BirthDate column is explicitly set to the target SQL Server
data type using the SqlParameter.SqlDbType Property, instead of relying on the implicit mapping of .NET
types to SQL Server data types applied when using the SqlParameter.DbType Property. By default, the
DateTime Structure maps to the datetime SQL Server data type. As the data type of the BirthDate column is
date and Always Encrypted doesn't support a conversion of encrypted datetime values to encrypted date
values, using the default mapping would result in an error.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column
Encryption Setting=enabled";

using (SqlConnection connection = new SqlConnection(builder.ConnectionString))


using (SqlCommand cmd = connection.CreateCommand())
{
connection.Open();
cmd.CommandText = @"INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES
(@SSN, @FirstName, @LastName, @BirthDate);";

SqlParameter paramSSN = cmd.CreateParameter();


paramSSN.ParameterName = @"@SSN";
paramSSN.DbType = DbType.AnsiStringFixedLength;
paramSSN.Direction = ParameterDirection.Input;
paramSSN.Value = "795-73-9838";
paramSSN.Size = 11;
cmd.Parameters.Add(paramSSN);

SqlParameter paramFirstName = cmd.CreateParameter();


paramFirstName.ParameterName = @"@FirstName";
paramFirstName.DbType = DbType.String;
paramFirstName.Direction = ParameterDirection.Input;
paramFirstName.Value = "Catherine";
paramFirstName.Size = 50;
cmd.Parameters.Add(paramFirstName);

SqlParameter paramLastName = cmd.CreateParameter();


paramLastName.ParameterName = @"@LastName";
paramLastName.DbType = DbType.String;
paramLastName.Direction = ParameterDirection.Input;
paramLastName.Value = "Abel";
paramLastName.Size = 50;
cmd.Parameters.Add(paramLastName);

SqlParameter paramBirthdate = cmd.CreateParameter();


paramBirthdate.ParameterName = @"@BirthDate";
paramBirthdate.SqlDbType = SqlDbType.Date;
paramBirthdate.Direction = ParameterDirection.Input;
paramBirthdate.Value = new DateTime(1996, 09, 10);
cmd.Parameters.Add(paramBirthdate);

cmd.ExecuteNonQuery();
}

Retrieving plaintext data example


The following example demonstrates filtering data based on encrypted values and retrieving plaintext data from
encrypted columns.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true; Column
Encryption Setting=enabled";
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
using (SqlCommand cmd = connection.CreateCommand())
{
connection.Open();
cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE
SSN=@SSN";

SqlParameter paramSSN = cmd.CreateParameter();


paramSSN.ParameterName = @"@SSN";
paramSSN.DbType = DbType.AnsiStringFixedLength;
paramSSN.Direction = ParameterDirection.Input;
paramSSN.Value = "795-73-9838";
paramSSN.Size = 11;
cmd.Parameters.Add(paramSSN);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine(@"{0}, {1}, {2}, {3}", reader[0], reader[1], reader[2],
((DateTime)reader[3]).ToShortDateString());
}
}
}
}

NOTE
The value used in the WHERE clause to filter on the SSN column needs to be passed using SqlParameter, so that
the Microsoft .NET Data Provider for SQL Ser ver can transparently encrypt it before sending it to the
database.
All values printed by the program will be in plaintext, as the Microsoft .NET Data Provider for SQL Ser ver
will transparently decrypt the data retrieved from the SSN and BirthDate columns.
Queries can perform equality comparisons on columns if they are encrypted using deterministic encryption. For
more information, see Selecting Deterministic or Randomized Encryption.

Retrieving encrypted data example


If Always Encrypted isn't enabled, a query can still retrieve data from encrypted columns, as long as the query
has no parameters targeting encrypted columns.
The following example demonstrates how to retrieve binary encrypted data from encrypted columns.
string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";

using (SqlConnection connection = new SqlConnection(connectionString))


using (SqlCommand cmd = connection.CreateCommand())
{
connection.Open();
cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE
[LastName]=@LastName";

SqlParameter paramLastName = cmd.CreateParameter();


paramLastName.ParameterName = @"@LastName";
paramLastName.DbType = DbType.String;
paramLastName.Direction = ParameterDirection.Input;
paramLastName.Value = "Abel";
paramLastName.Size = 50;
cmd.Parameters.Add(paramLastName);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine(@"{0}, {1}, {2}, {3}", BitConverter.ToString((byte[])reader[0]),
reader[1], reader[2], BitConverter.ToString((byte[])reader[3]));
}
}
}
}

NOTE
As Always Encrypted is not enabled in the connection string, the query will return encrypted values of SSN and
BirthDate as byte arrays (the program converts the values to strings).

A query retrieving data from encrypted columns with Always Encrypted disabled can have parameters, as long as
none of the parameters target an encrypted column. The above query filters by LastName, which isn't encrypted
in the database. If the query filtered by SSN or BirthDate , the query would fail.

Avoiding common problems when querying encrypted columns


This section describes common categories of errors when querying encrypted columns from .NET applications
and a few guidelines on how to avoid them.
Unsupported data type conversion errors
Always Encrypted supports few conversions for encrypted data types. See Always Encrypted for a detailed list of
supported type conversions. Do the following to avoid data type conversion errors:
Set the types of parameters targeting encrypted columns so the SQL Server data type of the parameter is
either exactly the same as the type of the target column, or a conversion of the SQL Server data type of the
parameter to the target type of the column is supported. You can enforce the desired mapping of .NET data
types to specific SQL Server data types by using the SqlParameter.SqlDbType Property.
Verify the precision and scale of parameters targeting columns of the decimal and numeric SQL Server data
types is the same as the precision and scale configured for the target column.
Verify the precision of parameters targeting columns of datetime2, datetimeoffset, or time SQL Server data
types isn't greater than the precision for the target column (in queries that modify values in the target
column).
Errors due to passing plaintext instead of encrypted values
Any value that targets an encrypted column needs to be encrypted inside the application. An attempt to
insert/modify or to filter by a plaintext value on an encrypted column will result in an error like this one:

Microsoft.Data.SqlClient.SqlException (0x80131904): Operand type clash: varchar is incompatible with


varchar(8000) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name =
'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1',
column_encryption_key_database_name = 'Clinic') collation_name = 'SQL_Latin1_General_CP1_CI_AS'

To prevent such errors, make sure:


Always Encrypted is enabled for application queries targeting encrypted columns (for the connection string
or in the SqlCommand object for a specific query).
You use SqlParameter to send data targeting encrypted columns. The following example shows a query that
incorrectly filters by a literal/constant on an encrypted column (SSN) instead of passing the literal inside a
SqlParameter object.

using (SqlCommand cmd = connection.CreateCommand())


{
cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN =
'795-73-9838'";
cmd.ExecuteNonQuery();
}

Working with column master key stores


To encrypt a parameter value or to decrypt data in query results, the Microsoft .NET Data Provider for SQL
Ser ver needs to obtain a column encryption key that is configured for the target column. Column encryption
keys are stored in encrypted form in the database metadata. Each column encryption key has a corresponding
column master key that was used to encrypt the column encryption key. The database metadata doesn't store
the column master keys - it only contains the information about a key store containing a particular column
master key and the location of the key in the key store.
To obtain a plaintext value of a column encryption key, the Microsoft .NET Data Provider for SQL Ser ver
first obtains the metadata about both the column encryption key and its corresponding column master key.
Then it uses the information in the metadata to contact the key store containing the column master key, and to
decrypt the encrypted column encryption key. The Microsoft .NET Data Provider for SQL Ser ver
communicates with a key store using a column master key store provider - which is an instance of a class
derived from the SqlColumnEncryptionKeyStoreProvider class.
The process to obtain a column encryption key:
1. If Always Encrypted is enabled for a query, the Microsoft .NET Data Provider for SQL Ser ver
transparently calls sys.sp_describe_parameter_encr yption to retrieve encryption metadata for
parameters targeting encrypted columns, if the query has parameters. For encrypted data contained in
the results of a query, SQL Server automatically attaches encryption metadata. The information about the
column master key includes:
The name of a key store provider that encapsulates a key store containing the column master key.
The key path that specifies the location of the column master key in the key store.
The information about the column encryption key includes:
The encrypted value of a column encryption key.
The name of the algorithm that was used to encrypt the column encryption key.
2. The Microsoft .NET Data Provider for SQL Ser ver uses the name of the column master key store
provider to look up the provider object, which is an instance of a class derived from the
SqlColumnEncryptionKeyStoreProvider class, in an internal data structure.
3. To decrypt the column encryption key, the Microsoft .NET Data Provider for SQL Ser ver calls the
SqlColumnEncryptionKeyStoreProvider.DecryptColumnEncryptionKey() method, passing the column master
key path, the encrypted value of the column encryption key, and the name of the encryption algorithm
used to produce the encrypted column encryption key.
Using built-in column master key store providers
The Microsoft .NET Data Provider for SQL Ser ver comes with the following built-in column master key
store providers, which are pre-registered with the specific provider names (used to look up the provider). These
built-in key store providers are supported only on Windows.

C L A SS DESC RIP T IO N P RO VIDER ( LO O K UP ) N A M E P L AT F O RM

SqlColumnEncryptionCertifi A provider for the Windows MSSQL_CERTIFICATE_STOR Windows


cateStoreProvider Class Certificate Store. E

SqlColumnEncryptionCngPr A provider for a key store MSSQL_CNG_STORE Windows


ovider Class that supports Microsoft
Cryptography API: Next
Generation (CNG) API.
Typically, a store of this type
is a hardware security
module - a physical device
that safeguards and
manages digital keys and
provides crypto-processing.

SqlColumnEncryptionCspPr A provider for a key store MSSQL_CSP_PROVIDER Windows


ovider Class that supports Microsoft
Cryptography API (CAPI).
Typically, a store of this type
is a hardware security
module - a physical device
that safeguards and
manages digital keys and
provides crypto-processing.

You don't need to make any application code changes to use these providers, but note the following details:
You (or your DBA) need to make sure the provider name, configured in the column master key metadata, is
correct and the column master key path complies with the key path format that is valid for a given provider.
It's recommended that you configure the keys using tools such as SQL Server Management Studio, which
automatically generates the valid provider names and key paths when issuing the CREATE COLUMN MASTER
KEY (Transact-SQL) statement. For more information, see Configuring Always Encrypted using SQL Server
Management Studio and Configure Always Encrypted using PowerShell.
Ensure your application can access the key in the key store. This process may involve granting your
application access to the key and/or the key store, depending on the key store, or performing other key
store-specific configuration steps. For example, to access a key store implementing CNG or CAPI (like a
hardware security module), you need to make sure a library implementing CNG or CAPI for your store is
installed on your application machine. For details, see Create and store column master keys for Always
Encrypted.
Using the Azure Key Vault provider
Azure Key Vault is a convenient option to store and manage column master keys for Always Encrypted
(especially if your applications are hosted in Azure). The Microsoft .NET Data Provider for SQL Ser ver
doesn't include a built-in column master key store provider for Azure Key Vault, but it's available as a NuGet
package (Microsoft.Data.SqLClient.AlwaysEncrypted.AzureKeyVaultProvider) that you can easily integrate with
your application. For details, see Always Encrypted - Protect sensitive data in SQL Database with data encryption
and store your encryption keys in the Azure Key Vault.

C L A SS DESC RIP T IO N P RO VIDER ( LO O K UP ) N A M E P L AT F O RM

SqlColumnEncryptionAzure Provider for Azure Key AZURE_KEY_VAULT Windows, Linux, macOS


KeyVaultProvider Class Vault.

.NET Supportability

M IC RO SO F T. DATA . SQ L C L IEN T
VERSIO N VERSIO N . N ET P L AT F O RM S

3.0.0 3.0.0+ .NET Framework 4.6.1+, .NET Core


2.1+, .NET Standard 2.0+

2.0.0 1.1.3+ .NET Framework 4.6.1+, .NET Core


2.1.0+ 2.1+
.NET Standard 2.0+

1.2.0 1.0.19269.1+ .NET Framework 4.6+, .NET Core 2.1+


2.1.0+ .NET Standard 2.0+

1.1.0 1.0.19269.1+ .NET Framework 4.6+, .NET Core 2.1+

1.0.0 1.0.19269.1+ .NET Framework 4.6+, .NET Core 2.1+

Starting with v3.0.0 , the Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider supports column


encryption key caching capabilities when registering the provider using
SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection or
SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand APIs.
Starting with v2.0.0 , the Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider supports the new
Azure.Core and Azure.Identity APIs to perform authentication with Azure Key Vault. An instance of
TokenCredential implementation can now be passed to SqlColumnEncryptionAzureKeyVaultProvider constructors
to initialize Azure Key Vault provider object.

NOTE
The Microsoft.Data.SqLClient.AlwaysEncrypted.AzureKeyVaultProvider supports both Vaults and Managed HSMs
in Azure Key Vault.

For examples that demonstrate encryption/decryption with Azure Key Vault, see Azure Key Vault working with
Always Encrypted and Azure Key Vault working with Always Encrypted with secure enclaves.
Implementing a custom column master key store provider
If you want to store column master keys in a key store that isn't supported by an existing provider, you can
implement a custom provider by extending the SqlColumnEncryptionKeyStoreProvider class and registering the
provider using one of the following methods:
SqlConnection.RegisterColumnEncryptionKeyStoreProviders
SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection (Added in version 3.0.0)
SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand (Added in version 3.0.0)
public class MyCustomKeyStoreProvider : SqlColumnEncryptionKeyStoreProvider
{
public const string ProviderName = "MY_CUSTOM_STORE";

public override byte[] EncryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm,


byte[] columnEncryptionKey)
{
// Logic for encrypting a column encrypted key.
}
public override byte[] DecryptColumnEncryptionKey(string masterKeyPath, string encryptionAlgorithm,
byte[] EncryptedColumnEncryptionKey)
{
// Logic for decrypting a column encrypted key.
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> providers =
new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
providers.Add(MyCustomKeyStoreProvider.ProviderName, new MyCustomKeyStoreProvider());
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);
// ...
}
}

Column encryption key cache precedence


This section applies to version 3.0 and higher of the Microsoft .NET Data Provider for SQL Ser ver .
The column encryption keys (CEK) decrypted by custom key store providers registered on a connection or
command instance won't be cached by the Microsoft .NET Data Provider for SQL Ser ver . Custom key store
providers should implement their own CEK caching mechanism.
Starting with v3.0.0 of the , each instance of
Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider
Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider has its own CEK caching implementation.
When registered on a connection or command instance, CEKs decrypted by an instance of
Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider will be cleared when that instance goes out of
scope:

class Program
{
static void Main()
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = connection.CreateCommand())
{
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customKeyStoreProviders = new
Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = new
SqlColumnEncryptionAzureKeyVaultProvider();
customKeyStoreProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName,
azureKeyVaultProvider);
command.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customKeyStoreProviders);
// Perform database operation using Azure Key Vault Provider
// Any decrypted column encryption keys will be cached
} // Column encryption key cache of "azureKeyVaultProvider" is cleared when
"azureKeyVaultProvider" goes out of scope
}
}
}
NOTE
CEK caching implemented by custom key store providers will be disabled by the driver if the key store provider instance is
registered in the driver globally using the SqlConnection.RegisterColumnEncryptionKeyStoreProviders method. Any CEK
caching implementation should reference the value of
SqlColumnEncryptionKeyStoreProvider.ColumnEncryptionKeyCacheTtl before caching a CEK and not cache it if the value is
zero. This will avoid duplicate caching and possible user confusion when they are trying to configure key caching.

Registering a custom column master key store provider


This section applies to version 3.0 and higher of the provider.
Custom master key store providers can be registered with the driver at three different layers. The precedence of
the three registrations is as follows:
The per-command registration will be checked if it isn't empty.
If the per-command registration is empty, the per-connection registration will be checked if it isn't empty.
If the per-connection registration is empty, the global registration will be checked.
Once any key store provider is found at a registration level, the driver will NOT fall back to the other
registrations to search for a provider. If providers are registered but the proper provider isn't found at a level, an
exception will be thrown containing only the registered providers in the registration that was checked.
The built-in column master key store providers that are available for the Windows Certificate Store, CNG Store
and CSP are pre-registered.
The three registration levels support different scenarios when querying encrypted data. The appropriate method
can be used to ensure that a user of an application can access the plaintext data if they can provide the required
column master key, by authenticating against the key store containing the column master key.
Applications that share a SqlConnection instance between multiple users may want to use
SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand. Each user must register a key store
provider on a SqlCommand instance before executing a query to access an encrypted column. If the key store
provider is able to access the required column master key in the key store using the user's given credentials, the
query will succeed.
Applications that create a SqlConnection instance for each user may want to use
SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection. Key store providers registered with
this method can be used by the connection for any query accessing encrypted data.
Key store providers registered using SqlConnection.RegisterColumnEncryptionKeyStoreProviders will use the
identity given by the application when authenticating against the key store.
The following example shows the precedence of custom column master key store providers registered on a
connection instance:
class Program
{
static void Main()
{
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customKeyStoreProviders = new
Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
MyCustomKeyStoreProvider myProvider = new MyCustomKeyStoreProvider();
customKeyStoreProviders.Add("MY_CUSTOM_STORE", myProvider);
// Registers the provider globally
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customKeyStoreProviders);

using (SqlConnection connection = new SqlConnection(connectionString))


{
customKeyStoreProviders.Clear();
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = new
SqlColumnEncryptionAzureKeyVaultProvider();
customKeyStoreProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName,
azureKeyVaultProvider);
// Registers the provider on the connection
// These providers will take precedence over globally registered providers
connection.RegisterColumnEncryptionKeyStoreProvidersOnConnection(customKeyStoreProviders);
}
}
}

The following example shows the precedence of custom column master key store providers registered on a
command instance:

class Program
{
static void Main()
{
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customKeyStoreProviders = new
Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
MyCustomKeyStoreProvider firstProvider = new MyCustomKeyStoreProvider();
customKeyStoreProviders.Add("FIRST_CUSTOM_STORE", firstProvider);
// Registers the provider globally
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customKeyStoreProviders);

using (SqlConnection connection = new SqlConnection(connectionString))


{
customKeyStoreProviders.Clear();
MyCustomKeyStoreProvider secondProvider = new MyCustomKeyStoreProvider();
customKeyStoreProviders.Add("SECOND_CUSTOM_STORE", secondProvider);
// Registers the provider on the connection
connection.RegisterColumnEncryptionKeyStoreProvidersOnConnection(customKeyStoreProviders);

using (SqlCommand command = connection.CreateCommand())


{
customKeyStoreProviders.Clear();
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = new
SqlColumnEncryptionAzureKeyVaultProvider();
customKeyStoreProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName,
azureKeyVaultProvider);
// Registers the provider on the command
// These providers will take precedence over connection-level providers and globally
registered providers
command.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customKeyStoreProviders);
}
}
}
}

Using column master key store providers for programmatic key provisioning
When the Microsoft .NET Data Provider for SQL Ser ver accesses encrypted columns, it transparently finds
and calls the right column master key store provider to decrypt column encryption keys. Typically, your normal
application code doesn't directly call column master key store providers. You may, however, instantiate and call a
provider explicitly to programmatically create and manage Always Encrypted keys: to generate an encrypted
column encryption key and decrypt a column encryption key (for example, as part column master key rotation).
For more information, see Overview of key management for Always Encrypted. Implementing your own key
management tools may be required only if you use a custom key store provider. When using keys stored in keys
stores, for which built-in providers exist, and or in Azure Key Vault, you can use existing tools, such as SQL
Server Management Studio or PowerShell, to manage and provision keys. The below example, illustrates
generating a column encryption key and using the SqlColumnEncryptionCertificateStoreProvider class to
encrypt the key with a certificate.

using System.Security.Cryptography;
static void Main(string[] args)
{
byte[] EncryptedColumnEncryptionKey = GetEncryptedColumnEncryptonKey();
Console.WriteLine("0x" + BitConverter.ToString(EncryptedColumnEncryptionKey).Replace("-", ""));
Console.ReadKey();
}

static byte[] GetEncryptedColumnEncryptonKey()


{
int cekLength = 32;
String certificateStoreLocation = "CurrentUser";
String certificateThumbprint = "698C7F8E21B2158E9AED4978ADB147CF66574180";
// Generate the plaintext column encryption key.
byte[] columnEncryptionKey = new byte[cekLength];
RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
rngCsp.GetBytes(columnEncryptionKey);

// Encrypt the column encryption key with a certificate.


string keyPath = String.Format(@"{0}/My/{1}", certificateStoreLocation, certificateThumbprint);
SqlColumnEncryptionCertificateStoreProvider provider = new
SqlColumnEncryptionCertificateStoreProvider();
return provider.EncryptColumnEncryptionKey(keyPath, @"RSA_OAEP", columnEncryptionKey);
}

Controlling the performance impact of Always Encrypted


Because Always Encrypted is a client-side encryption technology, most performance overhead is observed on
the client side, not in the database. Apart from the cost of encryption and decryption operations, other sources
of performance overhead on the client side are:
Extra round trips to the database to retrieve metadata for query parameters.
Calls to a column master key store to access a column master key.
This section describes the built-in performance optimizations in Microsoft .NET Data Provider for SQL
Ser ver and how you can control the impact of the above two factors on performance.
Controlling round trips to retrieve metadata for query parameters
If Always Encrypted is enabled for a connection, by default, the Microsoft .NET Data Provider for SQL
Ser ver will call sys.sp_describe_parameter_encryption for each parameterized query, passing the query
statement (without any parameter values) to SQL Server. sys.sp_describe_parameter_encr yption analyzes
the query statement to find out if any parameters need to be encrypted, and if so, for each one, it returns the
encryption-related information that will allow the Microsoft .NET Data Provider for SQL Ser ver to encrypt
parameter values. The above behavior ensures a high level of transparency to the client application. The
application (and the application developer) doesn't need to be aware of which queries access encrypted
columns, as long as the values targeting encrypted columns are passed to the Microsoft .NET Data Provider
for SQL Ser ver in SqlParameter objects.
Query metadata caching
The Microsoft .NET Data Provider for SQL Ser ver caches the results of
sys.sp_describe_parameter_encr yption for each query statement. So, if the same query statement is
executed multiple times, the driver calls sys.sp_describe_parameter_encr yption only once. Encryption
metadata caching for query statements substantially reduces the performance cost of fetching metadata from
the database. Caching is enabled by default. You can disable parameter metadata caching by setting the
SqlConnection.ColumnEncryptionQueryMetadataCacheEnabled property to false, but doing so isn't
recommended except in rare cases like the one described below:
Consider a database that has two different schemas: s1 and s2 . Each schema contains a table with the same
name: t . The definitions of the s1.t and s2.t tables are identical, except encryption-related properties: A
column, named c , in s1.t isn't encrypted, and it's encrypted in s2.t . The database has two users: u1 and
u2 . The default schema for the u1 users is s1 . The default schema for u2 is s2 . A .NET application opens
two connections to the database, impersonating the u1 user on one connection, and the u2 user on another
connection. The application sends a query with a parameter targeting the c column over the connection for
user u1 (the query doesn't specify the schema, so the default user schema is assumed). Next, the application
sends the same query over the connection for the u2 user. If query metadata caching is enabled, after the first
query, the cache will be populated with metadata indicating the c column, which the query parameter targets,
isn't encrypted. As the second query has the identical query statement, the information stored in the cache will
be used. As a result, the driver will send the query without encrypting the parameter (which is incorrect, as the
target column, s2.t.c , is encrypted), leaking the plaintext value of the parameter to the server. The server will
detect that incompatibility and it will force the driver to refresh the cache, so the application will transparently
resend the query with the correctly encrypted parameter value. In such a case, caching should be disabled to
prevent leaking sensitive values to the server.
Setting Always Encrypted at the query level
To control the performance impact of retrieving encryption metadata for parameterized queries, you can enable
Always Encrypted for individual queries, instead of setting it up for the connection. This way, you can ensure that
sys.sp_describe_parameter_encr yption is invoked only for queries that you know have parameters
targeting encrypted columns. Note, however, that by doing so, you reduce the transparency of encryption: if you
change encryption properties of your database columns, you may need to change the code of your application
to align it with the schema changes.

NOTE
Setting Always Encrypted at the query level limits the performance benefit of parameter encryption metadata caching.

To control the Always Encrypted behavior of individual queries, you need to use this constructor of
SqlCommand and SqlCommandColumnEncryptionSetting. Here are some useful guidelines:
If most queries a client application executes access encrypted columns:
Set the Column Encr yption Setting connection string keyword to Enabled .
Set SqlCommandColumnEncr yptionSetting to Disabled for individual queries that don't access
any encrypted columns. This setting will disable both calling
sys.sp_describe_parameter_encr yption and an attempt to decrypt any values in the result set.
Set SqlCommandColumnEncr yptionSetting to ResultSetOnly for individual queries that don't
have any parameters requiring encryption, but retrieve data from encrypted columns. This setting will
disable calling sys.sp_describe_parameter_encr yption and parameter encryption. The query will
be able to decrypt the results from encryption columns.
If most queries a client application executes don't access encrypted columns:
Set the Column Encr yption Setting connection string keyword to Disabled .
Set SqlCommandColumnEncr yptionSetting to Enabled for individual queries that have any
parameters that need to be encrypted. This setting will enable both calling
sys.sp_describe_parameter_encr yption and the decryption of any query results retrieved from
encrypted columns.
Set SqlCommandColumnEncr yptionSetting to ResultSetOnly for queries that don't have any
parameters requiring encryption, but retrieve data from encrypted columns. This setting will disable
calling sys.sp_describe_parameter_encr yption and parameter encryption. The query will be able
to decrypt the results from encryption columns.
In the below example, Always Encrypted is disabled for the database connection. The query the application
issues has a parameter that targets the LastName column that isn't encrypted. The query retrieves data from the
SSN and BirthDate columns that are both encrypted. In such a case, calling
sys.sp_describe_parameter_encr yption to retrieve encryption metadata isn't required. However, the
decryption of the query results needs to be enabled, so that the application can receive plaintext values from the
two encrypted columns. The SqlCommandColumnEncr yptionSetting ResultSetOnly setting is used to
ensure that.

string connectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated Security=true";


using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(@"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].
[Patients] WHERE [LastName]=@LastName",
connection, null, SqlCommandColumnEncryptionSetting.ResultSetOnly))
{
connection.Open();
SqlParameter paramLastName = cmd.CreateParameter();
paramLastName.ParameterName = @"@LastName";
paramLastName.DbType = DbType.String;
paramLastName.Direction = ParameterDirection.Input;
paramLastName.Value = "Abel";
paramLastName.Size = 50;
cmd.Parameters.Add(paramLastName);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine(@"{0}, {1}, {2}, {3}", reader[0], reader[1], reader[2],
((DateTime)reader[3]).ToShortDateString());
}
}
}
}

Column encryption key caching


To reduce the number of calls to a column master key store to decrypt column encryption keys, the Microsoft
.NET Data Provider for SQL Ser ver caches the plaintext column encryption keys in memory. After the
provider receives the encrypted column encryption key value from the database metadata, the driver first tries
to find the plaintext column encryption key corresponding to the encrypted key value. The driver calls the key
store containing the column master key only if it can't find the encrypted column encryption key value in the
cache.
The cache entries are evicted after a configurable time-to-live interval for security reasons. The default time-to-
live value is 2 hours. If you have stricter security requirements about how long column encryption keys can be
cached in plaintext in the application, you can change it using the SqlConnection.ColumnEncryptionKeyCacheTtl
property.
Custom key store providers registered using
SqlConnection.RegisterColumnEncryptionKeyStoreProvidersOnConnection and
SqlCommand.RegisterColumnEncryptionKeyStoreProvidersOnCommand won't have their decrypted column
encryption keys cached by the Microsoft .NET Data Provider for SQL Ser ver . Instead, custom key store
providers must implement their own caching mechanism.
Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider v3.0.0 and higher comes with its own caching
implementation.
To support scenarios where different users of the same application may execute multiple queries, custom key
store providers can be mapped to a user and registered on a connection or command instance specific to that
user. The following example shows how an instance of
Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider can be reused across different SqlCommand
objects for the same user. Its column encryption key cache will persist across multiple queries, reducing the
number of round trips to the key store:
using Microsoft.Data.SqlClient;
using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider;
using System.Collections.Generic;

class Program
{
// Maps a SqlColumnEncryptionAzureKeyVaultProvider to some object that represents a user
static Dictionary<object, SqlColumnEncryptionAzureKeyVaultProvider> providerByUser = new();

void ExecuteSelectQuery(object user, SqlConnection connection)


{
// Check if the user already has a SqlColumnEncryptionAzureKeyVaultProvider
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = providerByUser[user];
if (azureKeyVaultProvider is null)
{
// Create a new SqlColumnEncryptionAzureKeyVaultProvider with the user's credentials and save it
for future use
azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider();
providerByUser[user] = azureKeyVaultProvider;
}

Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders = new();


customProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);

using SqlCommand command = new("SELECT * FROM Customers", connection);


command.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customProviders);
// Perform database operations
// Any decrypted column encryption keys will be cached by azureKeyVaultProvider
}

void ExecuteUpdateQuery(object user, SqlConnection connection)


{
// Check if the user already has a SqlColumnEncryptionAzureKeyVaultProvider
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = providerByUser[user];
if (azureKeyVaultProvider is null)
{
// Create a new SqlColumnEncryptionAzureKeyVaultProvider with the user's credentials and save it
for future use
azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider();
providerByUser[user] = azureKeyVaultProvider;
}

Dictionary<string, SqlColumnEncryptionKeyStoreProvider> customProviders = new();


customProviders.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);

using SqlCommand command = new("UPDATE Customers SET Name = 'NewName' WHERE CustomerId = 1",
connection);
command.RegisterColumnEncryptionKeyStoreProvidersOnCommand(customProviders);
// Perform database operations
// Any decrypted column encryption keys will be cached by azureKeyVaultProvider
}
}

Enabling extra protection for a compromised SQL Server


By default, the Microsoft .NET Data Provider for SQL Ser ver relies on the database system (SQL Server or
Azure SQL Database) to provide metadata about which columns in the database are encrypted and how. The
encryption metadata enables the Microsoft .NET Data Provider for SQL Ser ver to encrypt query
parameters and decrypt query results without any input from the application, which greatly reduces the number
of changes required in the application. However, if the SQL Server process gets compromised and an attacker
tampers with the metadata SQL Server sends to the Microsoft .NET Data Provider for SQL Ser ver , the
attacker might be able to steal sensitive information. This section describes APIs that help provide an extra level
of protection against this type of attack, at the price of reduced transparency.
Forcing Parameter Encryption
Before the Microsoft .NET Data Provider for SQL Ser ver sends a parameterized query to SQL Server, it
asks SQL Server (by calling sys.sp_describe_parameter_encryption) to analyze the query statement and provide
information about which parameters in the query should be encrypted. A compromised SQL Server instance
could mislead the Microsoft .NET Data Provider for SQL Ser ver by sending metadata indicating the
parameter doesn't target an encrypted column, even though the column is encrypted in the database. As a
result, the Microsoft .NET Data Provider for SQL Ser ver wouldn't encrypt the parameter value and it
would send it as plaintext to the compromised SQL Server instance.
To prevent such an attack, an application can set the SqlParameter.ForceColumnEncryption Property for the
parameter to true. This setting will cause the Microsoft .NET Data Provider for SQL Ser ver to throw an
exception, if the metadata it has received from the server indicates the parameter doesn't need to be encrypted.
Although using the SqlParameter.ForceColumnEncr yption proper ty helps improve security, it also reduces
the transparency of encryption to the client application. If you update the database schema to change the set of
encrypted columns, you might need to make application changes as well.
The following code sample illustrates using the SqlParameter.ForceColumnEncr yption proper ty to prevent
social security numbers from being sent in plaintext to the database.

using (SqlCommand cmd = _sqlconn.CreateCommand())


{
// Use parameterized queries to access Always Encrypted data.

cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [SSN]
= @SSN;";

SqlParameter paramSSN = cmd.CreateParameter();


paramSSN.ParameterName = @"@SSN";
paramSSN.DbType = DbType.AnsiStringFixedLength;
paramSSN.Direction = ParameterDirection.Input;
paramSSN.Value = ssn;
paramSSN.Size = 11;
paramSSN.ForceColumnEncryption = true;
cmd.Parameters.Add(paramSSN);

using (SqlDataReader reader = cmd.ExecuteReader())


{
// Do something.
}
}

Configuring trusted column master key paths


The encryption metadata SQL Server returns for query parameters targeting encrypted columns and for the
results retrieved from encryption columns includes the key path of the column master key that identifies the key
store and the location of the key in the key store. If the SQL Server instance is compromised, it could send the
key path directing the Microsoft .NET Data Provider for SQL Ser ver to the location controlled by an
attacker. This process may lead to leaking key store credentials, if the key store requires the application to
authenticate.
To prevent such attacks, the application can specify the list of trusted key paths for a given server using the
SqlConnection.ColumnEncryptionTrustedMasterKeyPaths property. If the Microsoft .NET Data Provider for
SQL Ser ver receives a key path outside of the trusted key path list, it will throw an exception.
Although setting trusted key paths improves security of your application, you'll need to change the code or/and
the configuration of the application whenever you rotate your column master key (whenever the column master
key path changes).
The following example shows how to configure trusted column master key paths:
// Configure trusted key paths to protect against fake key paths sent by a compromised SQL Server instance
// First, create a list of trusted key paths for your server
List<string> trustedKeyPathList = new List<string>();
trustedKeyPathList.Add("CurrentUser/my/425CFBB9DDDD081BB0061534CE6AB06CB5283F5Ea");

// Register the trusted key path list for your server


SqlConnection.ColumnEncryptionTrustedMasterKeyPaths.Add(serverName, trustedKeyPathList);

Copying encrypted data using SqlBulkCopy


With SqlBulkCopy, you can copy data, which is already encrypted and stored in one table, to another table,
without decrypting the data. To do that:
Make sure the encryption configuration of the target table is identical to the configuration of the source
table. In particular, both tables must have the same columns encrypted, and the columns must be encrypted
using the same encryption types and the same encryption keys. If any of the target columns is encrypted
differently than its corresponding source column, you won't be able to decrypt the data in the target table
after the copy operation. The data will be corrupted.
Configure both database connections to the source table and to the target table without Always Encrypted
enabled.
Set the AllowEncryptedValueModifications option (see SqlBulkCopyOptions).

NOTE
Use caution when specifying AllowEncryptedValueModifications . This setting may lead to corrupting the database
because the Microsoft .NET Data Provider for SQL Ser ver does not check if the data is indeed encrypted, or if it is
correctly encrypted using the same encryption type, algorithm, and key as the target column.

Here's an example that copies data from one table to another. The SSN and BirthDate columns are assumed to
be encrypted.

static public void CopyTablesUsingBulk(string sourceTable, string targetTable)


{
string sourceConnectionString = "Data Source=server63; Initial Catalog=Clinic; Integrated
Security=true";
string targetConnectionString = "Data Source=server64; Initial Catalog=Clinic; Integrated
Security=true";
using (SqlConnection connSource = new SqlConnection(sourceConnectionString))
{
connSource.Open();
using (SqlCommand cmd = new SqlCommand(string.Format("SELECT [PatientID], [SSN], [FirstName],
[LastName], [BirthDate] FROM {0}", sourceTable), connSource))
{
using (SqlDataReader reader = cmd.ExecuteReader())
using (SqlBulkCopy copy = new SqlBulkCopy(targetConnectionString,
SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.AllowEncryptedValueModifications))
{
copy.EnableStreaming = true;
copy.DestinationTableName = targetTable;
copy.WriteToServer(reader);
}
}
}
}
Always Encrypted API reference
Namespace: Microsoft.Data.SqlClient
Assembly: Microsoft.Data.SqlClient.dll

NAME DESC RIP T IO N

SqlColumnEncryptionCertificateStoreProvider Class A key store provider for the Windows Certificate Store.

SqlColumnEncryptionCngProvider Class A key store provider for the Microsoft Cryptography API:
Next Generation (CNG).

SqlColumnEncryptionCspProvider Class A key store provider for the Microsoft CAPI based
Cryptographic Service Providers (CSP).

SqlColumnEncryptionKeyStoreProvider Class Base class of the key store providers.

SqlCommandColumnEncryptionSetting Enumeration Settings to control the behavior of Always Encrypted for


individual queries.

SqlConnectionAttestationProtocol Enumeration Specifies a value for Attestation Protocol when using Always
Encrypted with secure enclaves

SqlConnectionColumnEncryptionSetting Enumeration Settings to enable encryption and decryption for a database


connection.

SqlConnectionStringBuilder.ColumnEncryptionSetting Gets and sets Always Encrypted in the connection string.


Property

SqlConnection.ColumnEncryptionQueryMetadataCacheEnabl Enables and disables encryption query metadata caching.


ed Property

SqlConnection.ColumnEncryptionKeyCacheTtl Property Gets and sets time-to-live for entries in the column
encryption key cache.

SqlConnection.ColumnEncryptionTrustedMasterKeyPaths Allows you to set a list of trusted key paths for a database
Property server. If while processing an application query the driver
receives a key path that isn't on the list, the query will fail.
This property provides extra protection against security
attacks that involve a compromised SQL Server providing
fake key paths, which may lead to leaking key store
credentials.

SqlConnection.RegisterColumnEncryptionKeyStoreProviders Allows you to register custom key store providers. It's a


Method dictionary that maps key store provider names to key store
provider implementations.

SqlCommand Constructor (String, SqlConnection, Enables you to control the behavior of Always Encrypted for
SqlTransaction, SqlCommandColumnEncryptionSetting) individual queries.
NAME DESC RIP T IO N

SqlParameter.ForceColumnEncryption Property Enforces encryption of a parameter. If SQL Server informs


the driver that the parameter doesn't need to be encrypted,
the query using the parameter will fail. This property
provides extra protection against security attacks that
involve a compromised SQL Server providing incorrect
encryption metadata to the client, which may lead to data
disclosure.

connection string keyword: Enables or disables Always Encrypted functionality for the
Column Encryption Setting=enabled connection.

See also
Always Encrypted
Always Encrypted with secure enclaves
SQL Database tutorial: Protect sensitive data with Always Encrypted
Tutorial: Develop a .NET application using Always Encrypted with secure enclaves
Example: Azure Key Vault working with Always Encrypted
Example: Azure Key Vault working with Always Encrypted with secure enclaves
Tutorial: Develop a .NET application using Always
Encrypted with secure enclaves
4/27/2022 • 3 minutes to read • Edit Online

Applies to: SQL Server 2019 (15.x) - Windows only Azure SQL Database
APPLIES TO: .NET Framework .NET Core .NET Standard
This tutorial teaches you how to develop an application that issues database queries that use a server-side
secure enclave for Always Encrypted with secure enclaves.

NOTE
Always Encrypted with secure enclaves is only supported on Windows.

Prerequisites
Make sure you've completed one of the below tutorials before following the below steps in this tutorial:
Tutorial: Getting started with Always Encrypted with secure enclaves in SQL Server
Tutorial: Getting started with Always Encrypted with secure enclaves in Azure SQL Database
In addition, you need Visual Studio (version 2019 is recommended) - you can download it from
https://visualstudio.microsoft.com/. Your application development environment must use .NET Framework 4.6
or later or .NET Core 2.1 or later.

Step 1: Set up your Visual Studio Project


To use Always Encrypted with secure enclaves in a .NET Framework application, you need to make sure your
application targets .NET Framework 4.6 or higher. To use Always Encrypted with secure enclaves in a .NET Core
application, you need to make sure your application targets .NET Core 2.1 or higher.
In addition, if you store your column master key in Azure Key Vault, you also need to integrate your application
with the Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider NuGet.
1. Open Visual Studio.
2. Create a new C# Console App (.NET Framework / Core) project.
3. Make sure your project targets at least .NET Framework 4.6 or .NET Core 2.1. Right-click on the project in
Solution Explorer, select Proper ties and set the Target framework.
4. Install the following NuGet package by going to Tools (main menu) > NuGet Package Manager >
Package Manager Console . Run the following code in the Package Manager Console.

Install-Package Microsoft.Data.SqlClient -Version 1.1.0

5. If you use Azure Key Vault for storing your column master keys, install the following NuGet packages by
going to Tools (main menu) > NuGet Package Manager > Package Manager Console . Run the
following code in the Package Manager Console.
Install-Package Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider -Version 1.0.0
Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory

Step 2: Implement your application logic


Your application will connect to the ContosoHR database from Tutorial: Getting started with Always Encrypted
with secure enclaves using SSMS or - Tutorial: Getting started with Always Encrypted with secure enclaves in
Azure SQL Database and it will run a query that contains the LIKE predicate on the SSN column and a range
comparison on the Salar y column.
1. Replace the content of the Program.cs file (generated by Visual Studio) with the following code.
using System;
using Microsoft.Data.SqlClient;
using System.Data;

namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{

// Connection string for SQL Server


string connectionString = "Data Source = myserver; Initial Catalog = ContosoHR; Column
Encryption Setting = Enabled;Attestation Protocol = HGS; Enclave Attestation Url =
http://hgs.bastion.local/Attestation; Integrated Security = true";

// Connection string for Azure SQL Database


//string connectionString = "Data Source = myserver.database.windows.net; Initial Catalog
= ContosoHR; Column Encryption Setting = Enabled;Attestation Protocol = AAS; Enclave Attestation Url
= https://myattestationprovider.uks.attest.azure.net/attest/SgxEnclave; User ID=user;
Password=password";

using (SqlConnection connection = new SqlConnection(connectionString))


{
connection.Open();

SqlCommand cmd = connection.CreateCommand();


cmd.CommandText = @"SELECT [SSN], [FirstName], [LastName], [Salary] FROM [HR].
[Employees] WHERE [SSN] LIKE @SSNPattern AND [Salary] > @MinSalary;";

SqlParameter paramSSNPattern = cmd.CreateParameter();

paramSSNPattern.ParameterName = @"@SSNPattern";
paramSSNPattern.DbType = DbType.AnsiStringFixedLength;
paramSSNPattern.Direction = ParameterDirection.Input;
paramSSNPattern.Value = "%9838";
paramSSNPattern.Size = 11;

cmd.Parameters.Add(paramSSNPattern);

SqlParameter MinSalary = cmd.CreateParameter();

MinSalary.ParameterName = @"@MinSalary";
MinSalary.DbType = DbType.Currency;
MinSalary.Direction = ParameterDirection.Input;
MinSalary.Value = 20000;

cmd.Parameters.Add(MinSalary);
cmd.ExecuteNonQuery();

SqlDataReader reader = cmd.ExecuteReader();


while (reader.Read())

{
Console.WriteLine(reader[0] + ", " + reader[1] + ", " + reader[2] + ", " +
reader[3]);
}
Console.ReadKey();
}
}
}
}

2. Update the database connection string.


a. Set the valid server name and your database authentication settings.
b. Set the value of the Attestation Protocol keyword to:
HGS - if you're using SQL Server and Host Guardian Service (HGS).
AAS - if you're using Azure SQL Database and Microsoft Azure Attestation.
c. Set Enclave Attestation URL to an attestation URL for your environment.
3. Build and run the application.

See also
Using Always Encrypted with the Microsoft .NET Data Provider for SQL Server
Example demonstrating use of Azure Key Vault provider with Always Encrypted
Example demonstrating use of Azure Key Vault provider with Always Encrypted enabled with secure enclaves
Example demonstrating use of Azure Key Vault
provider with Always Encrypted
4/27/2022 • 14 minutes to read • Edit Online

Applies to: SQL Server 2019 (15.x) - Windows only


APPLIES TO: .NET Framework .NET Core .NET Standard
This example demonstrates use of Azure Key Vault Provider when accessing encrypted columns.

AzureKeyVaultProvider v2.0+
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using Azure.Identity;
using Microsoft.Data.SqlClient;
using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider;

namespace Microsoft.Data.SqlClient.Samples
{
public class AzureKeyVaultProviderExample_2_0
{
static readonly string s_algorithm = "RSA_OAEP";

// ********* Provide details here ***********


static readonly string s_akvUrl =
"https://{KeyVaultName}.vault.azure.net/keys/{Key}/{KeyIdentifier}";
static readonly string s_connectionString = "Server={Server}; Database={database}; Integrated
Security=true; Column Encryption Setting=Enabled;";
// ******************************************

public static void Main(string[] args)


{
// Initialize Token Credential instance using InteractiveBrowserCredential. For other
authentication options,
// see classes derived from TokenCredential:
https://docs.microsoft.com/dotnet/api/azure.core.tokencredential
InteractiveBrowserCredential interactiveBrowserCredential = new InteractiveBrowserCredential();

// Initialize AKV provider


SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new
SqlColumnEncryptionAzureKeyVaultProvider(interactiveBrowserCredential);

// Register AKV provider


SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders: new Dictionary<string,
SqlColumnEncryptionKeyStoreProvider>(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase)
{
{ SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, akvProvider}
});
Console.WriteLine("AKV provider Registered");

// Create connection to database


using (SqlConnection sqlConnection = new SqlConnection(s_connectionString))
{
string cmkName = "CMK_WITH_AKV";
string cekName = "CEK_WITH_AKV";
string tblName = "AKV_TEST_TABLE";

CustomerRecord customer = new CustomerRecord(1, @"Microsoft", @"Corporation");


CustomerRecord customer = new CustomerRecord(1, @"Microsoft", @"Corporation");

try
{
sqlConnection.Open();

// Drop Objects if exists


dropObjects(sqlConnection, cmkName, cekName, tblName);

// Create Column Master Key with AKV Url


createCMK(sqlConnection, cmkName);
Console.WriteLine("Column Master Key created.");

// Create Column Encryption Key


createCEK(sqlConnection, cmkName, cekName, akvProvider);
Console.WriteLine("Column Encryption Key created.");

// Create Table with Encrypted Columns


createTbl(sqlConnection, cekName, tblName);
Console.WriteLine("Table created with Encrypted columns.");

// Insert Customer Record in table


insertData(sqlConnection, tblName, customer);
Console.WriteLine("Encryted data inserted.");

// Read data from table


verifyData(sqlConnection, tblName, customer);
Console.WriteLine("Data validated successfully.");
}
finally
{
// Drop table and keys
dropObjects(sqlConnection, cmkName, cekName, tblName);
Console.WriteLine("Dropped Table, CEK and CMK");
}

Console.WriteLine("Completed AKV provider Sample.");


}
}

private static void createCMK(SqlConnection sqlConnection, string cmkName)


{
string KeyStoreProviderName = SqlColumnEncryptionAzureKeyVaultProvider.ProviderName;

string sql =
$@"CREATE COLUMN MASTER KEY [{cmkName}]
WITH (
KEY_STORE_PROVIDER_NAME = N'{KeyStoreProviderName}',
KEY_PATH = N'{s_akvUrl}'
);";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void createCEK(SqlConnection sqlConnection, string cmkName, string cekName,


SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider)
{
string sql =
$@"CREATE COLUMN ENCRYPTION KEY [{cekName}]
WITH VALUES (
COLUMN_MASTER_KEY = [{cmkName}],
ALGORITHM = '{s_algorithm}',
ENCRYPTED_VALUE = {GetEncryptedValue(sqlColumnEncryptionAzureKeyVaultProvider)}
)";

using (SqlCommand command = sqlConnection.CreateCommand())


using (SqlCommand command = sqlConnection.CreateCommand())
{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static string GetEncryptedValue(SqlColumnEncryptionAzureKeyVaultProvider


sqlColumnEncryptionAzureKeyVaultProvider)
{
byte[] plainTextColumnEncryptionKey = new byte[32];
RandomNumberGenerator rng = RandomNumberGenerator.Create();
rng.GetBytes(plainTextColumnEncryptionKey);

byte[] encryptedColumnEncryptionKey =
sqlColumnEncryptionAzureKeyVaultProvider.EncryptColumnEncryptionKey(s_akvUrl, s_algorithm,
plainTextColumnEncryptionKey);
string EncryptedValue = string.Concat("0x",
BitConverter.ToString(encryptedColumnEncryptionKey).Replace("-", string.Empty));
return EncryptedValue;
}

private static void createTbl(SqlConnection sqlConnection, string cekName, string tblName)


{
string ColumnEncryptionAlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA_256";

string sql =
$@"CREATE TABLE [dbo].[{tblName}]
(
[CustomerId] [int] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE
= DETERMINISTIC, ALGORITHM = '{ColumnEncryptionAlgorithmName}'),
[FirstName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM =
'{ColumnEncryptionAlgorithmName}'),
[LastName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM =
'{ColumnEncryptionAlgorithmName}')
)";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void insertData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
string insertSql = $"INSERT INTO [{tblName}] (CustomerId, FirstName, LastName) VALUES
(@CustomerId, @FirstName, @LastName);";

using (SqlTransaction sqlTransaction = sqlConnection.BeginTransaction())


using (SqlCommand sqlCommand = new SqlCommand(insertSql,
connection: sqlConnection, transaction: sqlTransaction,
columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled))
{
sqlCommand.Parameters.AddWithValue(@"CustomerId", customer.Id);
sqlCommand.Parameters.AddWithValue(@"FirstName", customer.FirstName);
sqlCommand.Parameters.AddWithValue(@"LastName", customer.LastName);

sqlCommand.ExecuteNonQuery();
sqlTransaction.Commit();
}
}

private static void verifyData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
// Test INPUT parameter on an encrypted parameter
using (SqlCommand sqlCommand = new SqlCommand($"SELECT CustomerId, FirstName, LastName FROM
[{tblName}] WHERE FirstName = @firstName",
[{tblName}] WHERE FirstName = @firstName",
sqlConnection))
{
SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName",
@"Microsoft");
customerFirstParam.Direction = System.Data.ParameterDirection.Input;
customerFirstParam.ForceColumnEncryption = true;

using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())


{
ValidateResultSet(sqlDataReader);
}
}
}

private static void ValidateResultSet(SqlDataReader sqlDataReader)


{
Console.WriteLine(" * Row available: " + sqlDataReader.HasRows);

while (sqlDataReader.Read())
{
if (sqlDataReader.GetInt32(0) == 1)
{
Console.WriteLine(" * Employee Id received as sent: " + sqlDataReader.GetInt32(0));
}
else
{
Console.WriteLine("Employee Id didn't match");
}

if (sqlDataReader.GetString(1) == @"Microsoft")
{
Console.WriteLine(" * Employee Firstname received as sent: " +
sqlDataReader.GetString(1));
}
else
{
Console.WriteLine("Employee FirstName didn't match.");
}

if (sqlDataReader.GetString(2) == @"Corporation")
{
Console.WriteLine(" * Employee LastName received as sent: " +
sqlDataReader.GetString(2));
}
else
{
Console.WriteLine("Employee LastName didn't match.");
}
}
}

private static void dropObjects(SqlConnection sqlConnection, string cmkName, string cekName, string
tblName)
{
using (SqlCommand cmd = sqlConnection.CreateCommand())
{
cmd.CommandText = $@"IF EXISTS (select * from sys.objects where name = '{tblName}') BEGIN
DROP TABLE [{tblName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_encryption_keys where name =
'{cekName}') BEGIN DROP COLUMN ENCRYPTION KEY [{cekName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_master_keys where name =
'{cmkName}') BEGIN DROP COLUMN MASTER KEY [{cmkName}] END";
cmd.ExecuteNonQuery();
}
}

private class CustomerRecord


private class CustomerRecord
{
internal int Id { get; set; }
internal string FirstName { get; set; }
internal string LastName { get; set; }

public CustomerRecord(int id, string fName, string lName)


{
Id = id;
FirstName = fName;
LastName = lName;
}
}
}
}

Legacy callback implementation design example with v2.0+

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using Azure.Identity;
using Microsoft.Data.SqlClient;
using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider;

namespace Microsoft.Data.SqlClient.Samples
{
public class AzureKeyVaultProviderLegacyExample_2_0
{
const string s_algorithm = "RSA_OAEP";

// ********* Provide details here ***********


static readonly string s_akvUrl =
"https://{KeyVaultName}.vault.azure.net/keys/{Key}/{KeyIdentifier}";
static readonly string s_clientId = "{Application_Client_ID}";
static readonly string s_clientSecret = "{Application_Client_Secret}";
static readonly string s_connectionString = "Server={Server}; Database={database}; Integrated
Security=true; Column Encryption Setting=Enabled;";
// ******************************************

public static void Main()


{
// Initialize AKV provider
SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new
SqlColumnEncryptionAzureKeyVaultProvider(new LegacyAuthCallbackTokenCredential());

// Register AKV provider


SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders: new Dictionary<string,
SqlColumnEncryptionKeyStoreProvider>(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase)
{
{ SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, akvProvider}
});
Console.WriteLine("AKV provider Registered");

// Create connection to database


using (SqlConnection sqlConnection = new SqlConnection(s_connectionString))
{
string cmkName = "CMK_WITH_AKV";
string cekName = "CEK_WITH_AKV";
string tblName = "AKV_TEST_TABLE";

CustomerRecord customer = new CustomerRecord(1, @"Microsoft", @"Corporation");

try
{
sqlConnection.Open();

// Drop Objects if exists


// Drop Objects if exists
dropObjects(sqlConnection, cmkName, cekName, tblName);

// Create Column Master Key with AKV Url


createCMK(sqlConnection, cmkName);
Console.WriteLine("Column Master Key created.");

// Create Column Encryption Key


createCEK(sqlConnection, cmkName, cekName, akvProvider);
Console.WriteLine("Column Encryption Key created.");

// Create Table with Encrypted Columns


createTbl(sqlConnection, cekName, tblName);
Console.WriteLine("Table created with Encrypted columns.");

// Insert Customer Record in table


insertData(sqlConnection, tblName, customer);
Console.WriteLine("Encryted data inserted.");

// Read data from table


verifyData(sqlConnection, tblName, customer);
Console.WriteLine("Data validated successfully.");
}
finally
{
// Drop table and keys
dropObjects(sqlConnection, cmkName, cekName, tblName);
Console.WriteLine("Dropped Table, CEK and CMK");
}

Console.WriteLine("Completed AKV provider Sample.");


}
}

private static void createCMK(SqlConnection sqlConnection, string cmkName)


{
string KeyStoreProviderName = SqlColumnEncryptionAzureKeyVaultProvider.ProviderName;

string sql =
$@"CREATE COLUMN MASTER KEY [{cmkName}]
WITH (
KEY_STORE_PROVIDER_NAME = N'{KeyStoreProviderName}',
KEY_PATH = N'{s_akvUrl}'
);";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void createCEK(SqlConnection sqlConnection, string cmkName, string cekName,


SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider)
{
string sql =
$@"CREATE COLUMN ENCRYPTION KEY [{cekName}]
WITH VALUES (
COLUMN_MASTER_KEY = [{cmkName}],
ALGORITHM = '{s_algorithm}',
ENCRYPTED_VALUE = {GetEncryptedValue(sqlColumnEncryptionAzureKeyVaultProvider)}
)";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}
private static string GetEncryptedValue(SqlColumnEncryptionAzureKeyVaultProvider
sqlColumnEncryptionAzureKeyVaultProvider)
{
byte[] plainTextColumnEncryptionKey = new byte[32];
RandomNumberGenerator rng = RandomNumberGenerator.Create();
rng.GetBytes(plainTextColumnEncryptionKey);

byte[] encryptedColumnEncryptionKey =
sqlColumnEncryptionAzureKeyVaultProvider.EncryptColumnEncryptionKey(s_akvUrl, s_algorithm,
plainTextColumnEncryptionKey);
string EncryptedValue = string.Concat("0x",
BitConverter.ToString(encryptedColumnEncryptionKey).Replace("-", string.Empty));
return EncryptedValue;
}

private static void createTbl(SqlConnection sqlConnection, string cekName, string tblName)


{
string ColumnEncryptionAlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA_256";

string sql =
$@"CREATE TABLE [dbo].[{tblName}]
(
[CustomerId] [int] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE
= DETERMINISTIC, ALGORITHM = '{ColumnEncryptionAlgorithmName}'),
[FirstName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM =
'{ColumnEncryptionAlgorithmName}'),
[LastName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM =
'{ColumnEncryptionAlgorithmName}')
)";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void insertData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
string insertSql = $"INSERT INTO [{tblName}] (CustomerId, FirstName, LastName) VALUES
(@CustomerId, @FirstName, @LastName);";

using (SqlTransaction sqlTransaction = sqlConnection.BeginTransaction())


using (SqlCommand sqlCommand = new SqlCommand(insertSql,
connection: sqlConnection, transaction: sqlTransaction,
columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled))
{
sqlCommand.Parameters.AddWithValue(@"CustomerId", customer.Id);
sqlCommand.Parameters.AddWithValue(@"FirstName", customer.FirstName);
sqlCommand.Parameters.AddWithValue(@"LastName", customer.LastName);

sqlCommand.ExecuteNonQuery();
sqlTransaction.Commit();
}
}

private static void verifyData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
// Test INPUT parameter on an encrypted parameter
using (SqlCommand sqlCommand = new SqlCommand($"SELECT CustomerId, FirstName, LastName FROM
[{tblName}] WHERE FirstName = @firstName",
sqlConnection))
{
SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName",
@"Microsoft");
customerFirstParam.Direction = System.Data.ParameterDirection.Input;
customerFirstParam.ForceColumnEncryption = true;
customerFirstParam.ForceColumnEncryption = true;

using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())


{
ValidateResultSet(sqlDataReader);
}
}
}

private static void ValidateResultSet(SqlDataReader sqlDataReader)


{
Console.WriteLine(" * Row available: " + sqlDataReader.HasRows);

while (sqlDataReader.Read())
{
if (sqlDataReader.GetInt32(0) == 1)
{
Console.WriteLine(" * Employee Id received as sent: " + sqlDataReader.GetInt32(0));
}
else
{
Console.WriteLine("Employee Id didn't match");
}

if (sqlDataReader.GetString(1) == @"Microsoft")
{
Console.WriteLine(" * Employee Firstname received as sent: " +
sqlDataReader.GetString(1));
}
else
{
Console.WriteLine("Employee FirstName didn't match.");
}

if (sqlDataReader.GetString(2) == @"Corporation")
{
Console.WriteLine(" * Employee LastName received as sent: " +
sqlDataReader.GetString(2));
}
else
{
Console.WriteLine("Employee LastName didn't match.");
}
}
}

private static void dropObjects(SqlConnection sqlConnection, string cmkName, string cekName, string
tblName)
{
using (SqlCommand cmd = sqlConnection.CreateCommand())
{
cmd.CommandText = $@"IF EXISTS (select * from sys.objects where name = '{tblName}') BEGIN
DROP TABLE [{tblName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_encryption_keys where name =
'{cekName}') BEGIN DROP COLUMN ENCRYPTION KEY [{cekName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_master_keys where name =
'{cmkName}') BEGIN DROP COLUMN MASTER KEY [{cmkName}] END";
cmd.ExecuteNonQuery();
}
}

private class CustomerRecord


{
internal int Id { get; set; }
internal string FirstName { get; set; }
internal string LastName { get; set; }
public CustomerRecord(int id, string fName, string lName)
{
Id = id;
FirstName = fName;
LastName = lName;
}
}

private class LegacyAuthCallbackTokenCredential : TokenCredential


{
string _authority = "";
string _resource = "";
string _akvUrl = "";

public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken


cancellationToken) =>
AcquireTokenAsync().GetAwaiter().GetResult();

public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext,


CancellationToken cancellationToken) =>
await AcquireTokenAsync();

private async Task<AccessToken> AcquireTokenAsync()


{
// Added to reduce HttpClient calls.
// For multi-user support, a better design can be implemented as needed.
if (_akvUrl != s_akvUrl)
{
using (HttpClient httpClient = new HttpClient())
{
HttpResponseMessage response = await httpClient.GetAsync(s_akvUrl);
string challenge = response?.Headers.WwwAuthenticate.FirstOrDefault()?.ToString();
string trimmedChallenge = ValidateChallenge(challenge);
string[] pairs = trimmedChallenge.Split(new string[] { "," },
StringSplitOptions.RemoveEmptyEntries);

if (pairs != null && pairs.Length > 0)


{
for (int i = 0; i < pairs.Length; i++)
{
string[] pair = pairs[i]?.Split('=');

if (pair.Length == 2)
{
string key = pair[0]?.Trim().Trim(new char[] { '\"' });
string value = pair[1]?.Trim().Trim(new char[] { '\"' });

if (!string.IsNullOrEmpty(key))
{
if (key.Equals("authorization",
StringComparison.InvariantCultureIgnoreCase))
{
_authority = value;
}
else if (key.Equals("resource",
StringComparison.InvariantCultureIgnoreCase))
{
_resource = value;
}
}
}
}
}
}
_akvUrl = s_akvUrl;
}

string strAccessToken = await AzureActiveDirectoryAuthenticationCallback(_authority,


_resource);
_resource);
DateTime expiryTime = InterceptAccessTokenForExpiry(strAccessToken);
return new AccessToken(strAccessToken, new DateTimeOffset(expiryTime));
}

private DateTime InterceptAccessTokenForExpiry(string accessToken)


{
if (null == accessToken)
{
throw new ArgumentNullException(accessToken);
}

var jwtHandler = new JwtSecurityTokenHandler();


var jwtOutput = string.Empty;

// Check Token Format


if (!jwtHandler.CanReadToken(accessToken))
throw new FormatException(accessToken);

JwtSecurityToken token = jwtHandler.ReadJwtToken(accessToken);

// Re-serialize the Token Headers to just Key and Values


var jwtHeader = JsonConvert.SerializeObject(token.Header.Select(h => new { h.Key, h.Value
}));
jwtOutput = $"{{\r\n\"Header\":\r\n{JToken.Parse(jwtHeader)},";

// Re-serialize the Token Claims to just Type and Values


var jwtPayload = JsonConvert.SerializeObject(token.Claims.Select(c => new { c.Type, c.Value
}));
jwtOutput += $"\r\n\"Payload\":\r\n{JToken.Parse(jwtPayload)}\r\n}}";

// Output the whole thing to pretty JSON object formatted.


string jToken = JToken.Parse(jwtOutput).ToString(Formatting.Indented);
JToken payload = JObject.Parse(jToken).GetValue("Payload");

return new DateTime(1970, 1, 1).AddSeconds((long)payload[4]["Value"]);


}

private static string ValidateChallenge(string challenge)


{
string Bearer = "Bearer ";
if (string.IsNullOrEmpty(challenge))
throw new ArgumentNullException(nameof(challenge));

string trimmedChallenge = challenge.Trim();

if (!trimmedChallenge.StartsWith(Bearer))
throw new ArgumentException("Challenge is not Bearer", nameof(challenge));

return trimmedChallenge.Substring(Bearer.Length);
}

/// <summary>
/// Legacy implementation of Authentication Callback, used by Azure Key Vault provider 1.0.
/// This can be leveraged to support multi-user authentication support in the same Azure Key
Vault Provider.
/// </summary>
/// <param name="authority">Authorization URL</param>
/// <param name="resource">Resource</param>
/// <returns></returns>
public static async Task<string> AzureActiveDirectoryAuthenticationCallback(string authority,
string resource)
{
var authContext = new AuthenticationContext(authority);
ClientCredential clientCred = new ClientCredential(s_clientId, s_clientSecret);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
{
throw new InvalidOperationException($"Failed to retrieve an access token for
{resource}");
{resource}");
}
return result.AccessToken;
}
}
}
}

AzureKeyVaultProvider v1.x
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider;
using Microsoft.IdentityModel.Clients.ActiveDirectory;

namespace Microsoft.Data.SqlClient.Samples
{
public class AzureKeyVaultProviderExample
{
static readonly string s_algorithm = "RSA_OAEP";

// ********* Provide details here ***********


static readonly string s_akvUrl =
"https://{KeyVaultName}.vault.azure.net/keys/{Key}/{KeyIdentifier}";
static readonly string s_clientId = "{Application_Client_ID}";
static readonly string s_clientSecret = "{Application_Client_Secret}";
static readonly string s_connectionString = "Server={Server}; Database={database}; Integrated
Security=true; Column Encryption Setting=Enabled;";
// ******************************************

public static void Main(string[] args)


{
// Initialize AKV provider
SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider = new
SqlColumnEncryptionAzureKeyVaultProvider(AzureActiveDirectoryAuthenticationCallback);

// Register AKV provider


SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders: new Dictionary<string,
SqlColumnEncryptionKeyStoreProvider>(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase)
{
{ SqlColumnEncryptionAzureKeyVaultProvider.ProviderName,
sqlColumnEncryptionAzureKeyVaultProvider}
});
Console.WriteLine("AKV provider Registered");

// Create connection to database


using (SqlConnection sqlConnection = new SqlConnection(s_connectionString))
{
string cmkName = "CMK_WITH_AKV";
string cekName = "CEK_WITH_AKV";
string tblName = "AKV_TEST_TABLE";

CustomerRecord customer = new CustomerRecord(1, @"Microsoft", @"Corporation");

try
{
sqlConnection.Open();

// Drop Objects if exists


dropObjects(sqlConnection, cmkName, cekName, tblName);

// Create Column Master Key with AKV Url


createCMK(sqlConnection, cmkName);
Console.WriteLine("Column Master Key created.");
// Create Column Encryption Key
createCEK(sqlConnection, cmkName, cekName, sqlColumnEncryptionAzureKeyVaultProvider);
Console.WriteLine("Column Encryption Key created.");

// Create Table with Encrypted Columns


createTbl(sqlConnection, cekName, tblName);
Console.WriteLine("Table created with Encrypted columns.");

// Insert Customer Record in table


insertData(sqlConnection, tblName, customer);
Console.WriteLine("Encryted data inserted.");

// Read data from table


verifyData(sqlConnection, tblName, customer);
Console.WriteLine("Data validated successfully.");
}
finally
{
// Drop table and keys
dropObjects(sqlConnection, cmkName, cekName, tblName);
Console.WriteLine("Dropped Table, CEK and CMK");
}

Console.WriteLine("Completed AKV provider Sample.");


}
}

public static async Task<string> AzureActiveDirectoryAuthenticationCallback(string authority, string


resource, string scope)
{
var authContext = new AuthenticationContext(authority);
ClientCredential clientCred = new ClientCredential(s_clientId, s_clientSecret);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
{
throw new InvalidOperationException($"Failed to retrieve an access token for {resource}");
}

return result.AccessToken;
}

private static void createCMK(SqlConnection sqlConnection, string cmkName)


{
string KeyStoreProviderName = SqlColumnEncryptionAzureKeyVaultProvider.ProviderName;

string sql =
$@"CREATE COLUMN MASTER KEY [{cmkName}]
WITH (
KEY_STORE_PROVIDER_NAME = N'{KeyStoreProviderName}',
KEY_PATH = N'{s_akvUrl}'
);";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void createCEK(SqlConnection sqlConnection, string cmkName, string cekName,


SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider)
{
string sql =
$@"CREATE COLUMN ENCRYPTION KEY [{cekName}]
WITH VALUES (
COLUMN_MASTER_KEY = [{cmkName}],
ALGORITHM = '{s_algorithm}',
ENCRYPTED_VALUE = {GetEncryptedValue(sqlColumnEncryptionAzureKeyVaultProvider)}
)";
)";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static string GetEncryptedValue(SqlColumnEncryptionAzureKeyVaultProvider


sqlColumnEncryptionAzureKeyVaultProvider)
{
byte[] plainTextColumnEncryptionKey = new byte[32];
RandomNumberGenerator rng = RandomNumberGenerator.Create();
rng.GetBytes(plainTextColumnEncryptionKey);

byte[] encryptedColumnEncryptionKey =
sqlColumnEncryptionAzureKeyVaultProvider.EncryptColumnEncryptionKey(s_akvUrl, s_algorithm,
plainTextColumnEncryptionKey);
string EncryptedValue = string.Concat("0x",
BitConverter.ToString(encryptedColumnEncryptionKey).Replace("-", string.Empty));
return EncryptedValue;
}

private static void createTbl(SqlConnection sqlConnection, string cekName, string tblName)


{
string ColumnEncryptionAlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA_256";

string sql =
$@"CREATE TABLE [dbo].[{tblName}]
(
[CustomerId] [int] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE
= DETERMINISTIC, ALGORITHM = '{ColumnEncryptionAlgorithmName}'),
[FirstName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM =
'{ColumnEncryptionAlgorithmName}'),
[LastName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM =
'{ColumnEncryptionAlgorithmName}')
)";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void insertData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
string insertSql = $"INSERT INTO [{tblName}] (CustomerId, FirstName, LastName) VALUES
(@CustomerId, @FirstName, @LastName);";

using (SqlTransaction sqlTransaction = sqlConnection.BeginTransaction())


using (SqlCommand sqlCommand = new SqlCommand(insertSql,
connection: sqlConnection, transaction: sqlTransaction,
columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled))
{
sqlCommand.Parameters.AddWithValue(@"CustomerId", customer.Id);
sqlCommand.Parameters.AddWithValue(@"FirstName", customer.FirstName);
sqlCommand.Parameters.AddWithValue(@"LastName", customer.LastName);

sqlCommand.ExecuteNonQuery();
sqlTransaction.Commit();
}
}

private static void verifyData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
// Test INPUT parameter on an encrypted parameter
// Test INPUT parameter on an encrypted parameter
using (SqlCommand sqlCommand = new SqlCommand($"SELECT CustomerId, FirstName, LastName FROM
[{tblName}] WHERE FirstName = @firstName",
sqlConnection))
{
SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName",
@"Microsoft");
customerFirstParam.Direction = System.Data.ParameterDirection.Input;
customerFirstParam.ForceColumnEncryption = true;

using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())


{
ValidateResultSet(sqlDataReader);
}
}
}

private static void ValidateResultSet(SqlDataReader sqlDataReader)


{
Console.WriteLine(" * Row available: " + sqlDataReader.HasRows);

while (sqlDataReader.Read())
{
if (sqlDataReader.GetInt32(0) == 1)
{
Console.WriteLine(" * Employee Id received as sent: " + sqlDataReader.GetInt32(0));
}
else
{
Console.WriteLine("Employee Id didn't match");
}

if (sqlDataReader.GetString(1) == @"Microsoft")
{
Console.WriteLine(" * Employee Firstname received as sent: " +
sqlDataReader.GetString(1));
}
else
{
Console.WriteLine("Employee FirstName didn't match.");
}

if (sqlDataReader.GetString(2) == @"Corporation")
{
Console.WriteLine(" * Employee LastName received as sent: " +
sqlDataReader.GetString(2));
}
else
{
Console.WriteLine("Employee LastName didn't match.");
}
}
}

private static void dropObjects(SqlConnection sqlConnection, string cmkName, string cekName, string
tblName)
{
using (SqlCommand cmd = sqlConnection.CreateCommand())
{
cmd.CommandText = $@"IF EXISTS (select * from sys.objects where name = '{tblName}') BEGIN
DROP TABLE [{tblName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_encryption_keys where name =
'{cekName}') BEGIN DROP COLUMN ENCRYPTION KEY [{cekName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_master_keys where name =
'{cmkName}') BEGIN DROP COLUMN MASTER KEY [{cmkName}] END";
cmd.ExecuteNonQuery();
}
}
}

private class CustomerRecord


{
internal int Id { get; set; }
internal string FirstName { get; set; }
internal string LastName { get; set; }

public CustomerRecord(int id, string fName, string lName)


{
Id = id;
FirstName = fName;
LastName = lName;
}
}
}
}

NOTE
To use Always Encrypted feature without secure enclaves for .NET Standard application,
Microsoft.Data.SqlClient version 2.1.0 or higher is required. The supported .NET Standard version is 2.0 or
higher.
To use Always Encrypted feature on Linux and macOS, Microsoft.Data.SqlClient version 2.1.0 or higher is
required.

See also
Example demonstrating use of Azure Key Vault provider with Always Encrypted enabled with secure enclaves
Tutorial: Develop a .NET application using Always Encrypted with secure enclaves
Using Always Encrypted with the Microsoft .NET Data Provider for SQL Server
Example demonstrating use of Azure Key Vault
provider with Always Encrypted enabled with secure
enclaves
4/27/2022 • 8 minutes to read • Edit Online

Applies to: SQL Server 2019 (15.x) - Windows only Azure SQL Database
APPLIES TO: .NET Framework .NET Core .NET Standard

AzureKeyVaultProvider v2.0+
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Data.SqlClient;
using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider;

namespace AKVEnclaveExample
{
class Program
{
static readonly string s_algorithm = "RSA_OAEP";

// ********* Provide details here ***********


static readonly string s_akvUrl =
"https://{KeyVaultName}.vault.azure.net/keys/{Key}/{KeyIdentifier}";
static readonly string s_connectionString = "Server={Server}; Database={database}; Integrated
Security=true; Column Encryption Setting=Enabled; Attestation Protocol=HGS; Enclave Attestation Url =
{attestation_url_for_HGS};";
// ******************************************

static void Main(string[] args)


{
// Initialize Token Credential instance using InteractiveBrowserCredential. For other
authentication options,
// see classes derived from TokenCredential:
https://docs.microsoft.com/dotnet/api/azure.core.tokencredential
InteractiveBrowserCredential interactiveBrowserCredential = new InteractiveBrowserCredential();

// Initialize AKV provider


SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new
SqlColumnEncryptionAzureKeyVaultProvider(interactiveBrowserCredential);

// Register AKV provider


SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders: new Dictionary<string,
SqlColumnEncryptionKeyStoreProvider>(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase)
{
{ SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, akvProvider}
});
Console.WriteLine("AKV provider Registered");

// Create connection to database


using (SqlConnection sqlConnection = new SqlConnection(s_connectionString))
{
string cmkName = "CMK_WITH_AKV";
string cekName = "CEK_WITH_AKV";
string tblName = "AKV_TEST_TABLE";
CustomerRecord customer = new CustomerRecord(1, @"Microsoft", @"Corporation");

try
{
sqlConnection.Open();

// Drop Objects if exists


dropObjects(sqlConnection, cmkName, cekName, tblName);

// Create Column Master Key with AKV Url


createCMK(sqlConnection, cmkName, akvProvider);
Console.WriteLine("Column Master Key created.");

// Create Column Encryption Key


createCEK(sqlConnection, cmkName, cekName, akvProvider);
Console.WriteLine("Column Encryption Key created.");

// Create Table with Encrypted Columns


createTbl(sqlConnection, cekName, tblName);
Console.WriteLine("Table created with Encrypted columns.");

// Insert Customer Record in table


insertData(sqlConnection, tblName, customer);
Console.WriteLine("Encryted data inserted.");

// Read data from table


verifyData(sqlConnection, tblName, customer);
Console.WriteLine("Data validated successfully.");
}
finally
{
// Drop table and keys
dropObjects(sqlConnection, cmkName, cekName, tblName);
Console.WriteLine("Dropped Table, CEK and CMK");
}

Console.WriteLine("Completed AKV provider Sample.");


}
}

private static void createCMK(SqlConnection sqlConnection, string cmkName,


SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider)
{
string KeyStoreProviderName = SqlColumnEncryptionAzureKeyVaultProvider.ProviderName;

byte[] cmkSign = sqlColumnEncryptionAzureKeyVaultProvider.SignColumnMasterKeyMetadata(s_akvUrl,


true);
string cmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-",
string.Empty));

string sql =
$@"CREATE COLUMN MASTER KEY [{cmkName}]
WITH (
KEY_STORE_PROVIDER_NAME = N'{KeyStoreProviderName}',
KEY_PATH = N'{s_akvUrl}',
ENCLAVE_COMPUTATIONS (SIGNATURE = {cmkSignStr})
);";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void createCEK(SqlConnection sqlConnection, string cmkName, string cekName,


SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider)
{
string sql =
string sql =
$@"CREATE COLUMN ENCRYPTION KEY [{cekName}]
WITH VALUES (
COLUMN_MASTER_KEY = [{cmkName}],
ALGORITHM = '{s_algorithm}',
ENCRYPTED_VALUE = {GetEncryptedValue(sqlColumnEncryptionAzureKeyVaultProvider)}
)";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static string GetEncryptedValue(SqlColumnEncryptionAzureKeyVaultProvider


sqlColumnEncryptionAzureKeyVaultProvider)
{
byte[] plainTextColumnEncryptionKey = new byte[32];
RandomNumberGenerator rng = RandomNumberGenerator.Create();
rng.GetBytes(plainTextColumnEncryptionKey);

byte[] encryptedColumnEncryptionKey =
sqlColumnEncryptionAzureKeyVaultProvider.EncryptColumnEncryptionKey(s_akvUrl, s_algorithm,
plainTextColumnEncryptionKey);
string EncryptedValue = string.Concat("0x",
BitConverter.ToString(encryptedColumnEncryptionKey).Replace("-", string.Empty));
return EncryptedValue;
}

private static void createTbl(SqlConnection sqlConnection, string cekName, string tblName)


{
string ColumnEncryptionAlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA_256";

string sql =
$@"CREATE TABLE [dbo].[{tblName}]
(
[CustomerId] [int] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE
= RANDOMIZED, ALGORITHM = '{ColumnEncryptionAlgorithmName}'),
[FirstName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM =
'{ColumnEncryptionAlgorithmName}'),
[LastName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM =
'{ColumnEncryptionAlgorithmName}')
)";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void insertData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
string insertSql = $"INSERT INTO [{tblName}] (CustomerId, FirstName, LastName) VALUES
(@CustomerId, @FirstName, @LastName);";

using (SqlTransaction sqlTransaction = sqlConnection.BeginTransaction())


using (SqlCommand sqlCommand = new SqlCommand(insertSql,
connection: sqlConnection, transaction: sqlTransaction,
columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled))
{
sqlCommand.Parameters.AddWithValue(@"CustomerId", customer.Id);
sqlCommand.Parameters.AddWithValue(@"FirstName", customer.FirstName);
sqlCommand.Parameters.AddWithValue(@"LastName", customer.LastName);

sqlCommand.ExecuteNonQuery();
sqlTransaction.Commit();
}
}

private static void verifyData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
// Test INPUT parameter on an encrypted parameter
using (SqlCommand sqlCommand = new SqlCommand($"SELECT CustomerId, FirstName, LastName FROM
[{tblName}] WHERE FirstName = @firstName", sqlConnection))
{
SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName",
@"Microsoft");
customerFirstParam.Direction = System.Data.ParameterDirection.Input;
customerFirstParam.ForceColumnEncryption = true;

using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())


{
ValidateResultSet(sqlDataReader);
}
}
}

private static void ValidateResultSet(SqlDataReader sqlDataReader)


{
Console.WriteLine(" * Row available: " + sqlDataReader.HasRows);

while (sqlDataReader.Read())
{
if (sqlDataReader.GetInt32(0) == 1)
{
Console.WriteLine(" * Employee Id received as sent: " + sqlDataReader.GetInt32(0));
}
else
{
Console.WriteLine("Employee Id didn't match");
}

if (sqlDataReader.GetString(1) == @"Microsoft")
{
Console.WriteLine(" * Employee Firstname received as sent: " +
sqlDataReader.GetString(1));
}
else
{
Console.WriteLine("Employee FirstName didn't match.");
}

if (sqlDataReader.GetString(2) == @"Corporation")
{
Console.WriteLine(" * Employee LastName received as sent: " +
sqlDataReader.GetString(2));
}
else
{
Console.WriteLine("Employee LastName didn't match.");
}
}
}

private static void dropObjects(SqlConnection sqlConnection, string cmkName, string cekName, string
tblName)
{
using (SqlCommand cmd = sqlConnection.CreateCommand())
{
cmd.CommandText = $@"IF EXISTS (select * from sys.objects where name = '{tblName}') BEGIN
DROP TABLE [{tblName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_encryption_keys where name =
'{cekName}') BEGIN DROP COLUMN ENCRYPTION KEY [{cekName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_master_keys where name =
'{cmkName}') BEGIN DROP COLUMN MASTER KEY [{cmkName}] END";
cmd.ExecuteNonQuery();
}
}

private class CustomerRecord


{
internal int Id { get; set; }
internal string FirstName { get; set; }
internal string LastName { get; set; }

public CustomerRecord(int id, string fName, string lName)


{
Id = id;
FirstName = fName;
LastName = lName;
}
}
}
}

AzureKeyVaultProvider v1.x
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider;
using Microsoft.IdentityModel.Clients.ActiveDirectory;

namespace AKVEnclaveExample
{
class Program
{
static readonly string s_algorithm = "RSA_OAEP";

// ********* Provide details here ***********


static readonly string s_akvUrl =
"https://{KeyVaultName}.vault.azure.net/keys/{Key}/{KeyIdentifier}";
static readonly string s_clientId = "{Application_Client_ID}";
static readonly string s_clientSecret = "{Application_Client_Secret}";
static readonly string s_connectionString = "Server={Server}; Database={database}; Integrated
Security=true; Column Encryption Setting=Enabled; Attestation Protocol=HGS; Enclave Attestation Url =
{attestation_url_for_HGS};";
// ******************************************

static void Main(string[] args)


{
// Initialize AKV provider
SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider = new
SqlColumnEncryptionAzureKeyVaultProvider(AzureActiveDirectoryAuthenticationCallback);

// Register AKV provider


SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders: new Dictionary<string,
SqlColumnEncryptionKeyStoreProvider>(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase)
{
{ SqlColumnEncryptionAzureKeyVaultProvider.ProviderName,
sqlColumnEncryptionAzureKeyVaultProvider}
});
Console.WriteLine("AKV provider Registered");

// Create connection to database


using (SqlConnection sqlConnection = new SqlConnection(s_connectionString))
{
string cmkName = "CMK_WITH_AKV";
string cekName = "CEK_WITH_AKV";
string tblName = "AKV_TEST_TABLE";

CustomerRecord customer = new CustomerRecord(1, @"Microsoft", @"Corporation");

try
{
sqlConnection.Open();

// Drop Objects if exists


dropObjects(sqlConnection, cmkName, cekName, tblName);

// Create Column Master Key with AKV Url


createCMK(sqlConnection, cmkName, sqlColumnEncryptionAzureKeyVaultProvider);
Console.WriteLine("Column Master Key created.");

// Create Column Encryption Key


createCEK(sqlConnection, cmkName, cekName, sqlColumnEncryptionAzureKeyVaultProvider);
Console.WriteLine("Column Encryption Key created.");

// Create Table with Encrypted Columns


createTbl(sqlConnection, cekName, tblName);
Console.WriteLine("Table created with Encrypted columns.");

// Insert Customer Record in table


insertData(sqlConnection, tblName, customer);
Console.WriteLine("Encryted data inserted.");

// Read data from table


verifyData(sqlConnection, tblName, customer);
Console.WriteLine("Data validated successfully.");
}
finally
{
// Drop table and keys
dropObjects(sqlConnection, cmkName, cekName, tblName);
Console.WriteLine("Dropped Table, CEK and CMK");
}

Console.WriteLine("Completed AKV provider Sample.");

Console.ReadKey();
}
}

public static async Task<string> AzureActiveDirectoryAuthenticationCallback(string authority, string


resource, string scope)
{
var authContext = new AuthenticationContext(authority);
ClientCredential clientCred = new ClientCredential(s_clientId, s_clientSecret);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
{
throw new InvalidOperationException($"Failed to retrieve an access token for {resource}");
}

return result.AccessToken;
}

private static void createCMK(SqlConnection sqlConnection, string cmkName,


SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider)
{
string KeyStoreProviderName = SqlColumnEncryptionAzureKeyVaultProvider.ProviderName;

byte[] cmkSign = sqlColumnEncryptionAzureKeyVaultProvider.SignColumnMasterKeyMetadata(s_akvUrl,


true);
string cmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-",
string.Empty));
string.Empty));

string sql =
$@"CREATE COLUMN MASTER KEY [{cmkName}]
WITH (
KEY_STORE_PROVIDER_NAME = N'{KeyStoreProviderName}',
KEY_PATH = N'{s_akvUrl}',
ENCLAVE_COMPUTATIONS (SIGNATURE = {cmkSignStr})
);";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void createCEK(SqlConnection sqlConnection, string cmkName, string cekName,


SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider)
{
string sql =
$@"CREATE COLUMN ENCRYPTION KEY [{cekName}]
WITH VALUES (
COLUMN_MASTER_KEY = [{cmkName}],
ALGORITHM = '{s_algorithm}',
ENCRYPTED_VALUE = {GetEncryptedValue(sqlColumnEncryptionAzureKeyVaultProvider)}
)";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static string GetEncryptedValue(SqlColumnEncryptionAzureKeyVaultProvider


sqlColumnEncryptionAzureKeyVaultProvider)
{
byte[] plainTextColumnEncryptionKey = new byte[32];
RandomNumberGenerator rng = RandomNumberGenerator.Create();
rng.GetBytes(plainTextColumnEncryptionKey);

byte[] encryptedColumnEncryptionKey =
sqlColumnEncryptionAzureKeyVaultProvider.EncryptColumnEncryptionKey(s_akvUrl, s_algorithm,
plainTextColumnEncryptionKey);
string EncryptedValue = string.Concat("0x",
BitConverter.ToString(encryptedColumnEncryptionKey).Replace("-", string.Empty));
return EncryptedValue;
}

private static void createTbl(SqlConnection sqlConnection, string cekName, string tblName)


{
string ColumnEncryptionAlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA_256";

string sql =
$@"CREATE TABLE [dbo].[{tblName}]
(
[CustomerId] [int] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE
= RANDOMIZED, ALGORITHM = '{ColumnEncryptionAlgorithmName}'),
[FirstName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM =
'{ColumnEncryptionAlgorithmName}'),
[LastName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM =
'{ColumnEncryptionAlgorithmName}')
)";

using (SqlCommand command = sqlConnection.CreateCommand())


{
command.CommandText = sql;
command.CommandText = sql;
command.ExecuteNonQuery();
}
}

private static void insertData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
string insertSql = $"INSERT INTO [{tblName}] (CustomerId, FirstName, LastName) VALUES
(@CustomerId, @FirstName, @LastName);";

using (SqlTransaction sqlTransaction = sqlConnection.BeginTransaction())


using (SqlCommand sqlCommand = new SqlCommand(insertSql,
connection: sqlConnection, transaction: sqlTransaction,
columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled))
{
sqlCommand.Parameters.AddWithValue(@"CustomerId", customer.Id);
sqlCommand.Parameters.AddWithValue(@"FirstName", customer.FirstName);
sqlCommand.Parameters.AddWithValue(@"LastName", customer.LastName);

sqlCommand.ExecuteNonQuery();
sqlTransaction.Commit();
}
}

private static void verifyData(SqlConnection sqlConnection, string tblName, CustomerRecord customer)


{
// Test INPUT parameter on an encrypted parameter
using (SqlCommand sqlCommand = new SqlCommand($"SELECT CustomerId, FirstName, LastName FROM
[{tblName}] WHERE FirstName = @firstName",
sqlConnection))
{
SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName",
@"Microsoft");
customerFirstParam.Direction = System.Data.ParameterDirection.Input;
customerFirstParam.ForceColumnEncryption = true;

using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader())


{
ValidateResultSet(sqlDataReader);
}
}
}

private static void ValidateResultSet(SqlDataReader sqlDataReader)


{
Console.WriteLine(" * Row available: " + sqlDataReader.HasRows);

while (sqlDataReader.Read())
{
if (sqlDataReader.GetInt32(0) == 1)
{
Console.WriteLine(" * Employee Id received as sent: " + sqlDataReader.GetInt32(0));
}
else
{
Console.WriteLine("Employee Id didn't match");
}

if (sqlDataReader.GetString(1) == @"Microsoft")
{
Console.WriteLine(" * Employee Firstname received as sent: " +
sqlDataReader.GetString(1));
}
else
{
Console.WriteLine("Employee FirstName didn't match.");
}

if (sqlDataReader.GetString(2) == @"Corporation")
{
{
Console.WriteLine(" * Employee LastName received as sent: " +
sqlDataReader.GetString(2));
}
else
{
Console.WriteLine("Employee LastName didn't match.");
}
}
}

private static void dropObjects(SqlConnection sqlConnection, string cmkName, string cekName, string
tblName)
{
using (SqlCommand cmd = sqlConnection.CreateCommand())
{
cmd.CommandText = $@"IF EXISTS (select * from sys.objects where name = '{tblName}') BEGIN
DROP TABLE [{tblName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_encryption_keys where name =
'{cekName}') BEGIN DROP COLUMN ENCRYPTION KEY [{cekName}] END";
cmd.ExecuteNonQuery();
cmd.CommandText = $@"IF EXISTS (select * from sys.column_master_keys where name =
'{cmkName}') BEGIN DROP COLUMN MASTER KEY [{cmkName}] END";
cmd.ExecuteNonQuery();
}
}

private class CustomerRecord


{
internal int Id { get; set; }
internal string FirstName { get; set; }
internal string LastName { get; set; }

public CustomerRecord(int id, string fName, string lName)


{
Id = id;
FirstName = fName;
LastName = lName;
}
}
}
}

NOTE
To use Always Encrypted with secure enclaves for .NET Standard application, Microsoft.Data.SqlClient version
2.1.0 or higher is required. The supported .NET Standard version is 2.1 or higher.
To use Always Encrypted with secure enclaves on Linux and macOS, Microsoft.Data.SqlClient version 2.1.0 or
higher is required.

See also
Example demonstrating use of Azure Key Vault provider with Always Encrypted
Tutorial: Develop a .NET application using Always Encrypted with secure enclaves
Using Always Encrypted with the Microsoft .NET Data Provider for SQL Server
Data discovery and classification in SqlClient
4/27/2022 • 5 minutes to read • Edit Online

APPLIES TO: .NET Framework .NET Core .NET Standard

Download ADO.NET
Data Discovery & Classification is a set of advanced services for discovering, classifying, labeling & reporting
the sensitive data in your databases. SqlClient provides an API exposing read-only Data Discovery and
Classification information when the underlying source supports the feature. This information is accessed
through SqlDataReader.
Microsoft.Data.SqlClient v2.1.0 introduces support for Data Classification's Sensitivity Rank information.
Sensitivity Rank is an identifier based on a predefined set of values, which define sensitivity rank. It can be
used by other services like Advanced Threat Protection to detect anomalies based on their rank. The following
Data Classification APIs are now available in Microsoft.Data.SqlClient.DataClassification namespace:
// New in Microsoft.Data.SqlClient v2.1.0
public enum SensitivityRank
{
NOT_DEFINED = -1,
NONE = 0,
LOW = 10,
MEDIUM = 20,
HIGH = 30,
CRITICAL = 40
}

public sealed class SensitivityClassification


{
// Returns the sensitivity rank for the query associated with the active 'SqlDataReader'.
// New in Microsoft.Data.SqlClient v2.1.0
public SensitivityRank SensitivityRank;

// Returns the labels collection for this 'SensitivityClassification' Object


public ReadOnlyCollection<Label> Labels;

// Returns the information types collection for this 'SensitivityClassification' Object


public ReadOnlyCollection<InformationType> InformationTypes;

// Returns the column sensitivity for this 'SensitivityClassification' Object


public ReadOnlyCollection<ColumnSensitivity> ColumnSensitivities;
}

public sealed class SensitivityProperty


{
// Returns the sensitivity rank for this 'SensitivityProperty' Object
// New in Microsoft.Data.SqlClient v2.1.0
public SensitivityRank SensitivityRank;

// Returns the label for this 'SensitivityProperty' Object


public Label Label;

// Returns the information type for this 'SensitivityProperty' Object


public InformationType InformationType;
}

public sealed class Label


{
// Gets the name for this 'Label' object
public string Name;

// Gets the ID for this 'Label' object


public string Id;
}

public sealed class InformationType


{
// Gets the name for this 'InformationType' object
public string Name;

// Gets the ID for this 'InformationType' object


public string Id;
}

public sealed class ColumnSensitivity


{
// Returns the list of sensitivity properties as received from Server for this 'ColumnSensitivity'
information
public ReadOnlyCollection<SensitivityProperty> SensitivityProperties;
}
NOTE
Microsoft.Data.SqlClient reads Sensitivity Rank information only if SQL Server supports Data Classification with rank.
For servers use old version of Data Classification without rank, the rank value for queries is "NOT DEFINED".

This sample application demonstrates how to access the Data Classification properties of SqlDataReader.

using System;
using Microsoft.Data.SqlClient;
using Microsoft.Data.SqlClient.DataClassification;

class Program
{
// Name of the temporary table created for this sample program.
static string tableName = "SQLCLIENT_DATA_DISCOVERY_CLASSIFICATION";

public static void Main()


{
// To avoid storing the connection string in your code, you can retrieve it from a configuration
file.
string connectionString = "Data Source=localhost; Integrated Security=true; Initial
Catalog=AdventureWorks;";

// Open a connection to the AdventureWorks database.


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

try
{
// Check if the target SQL Server supports Data Discovery and Classification.
if (DataClassificationSupported(connection))
{
// Create the temporary table and retrieve its Data Discovery and Classification
information.
// Set rankEnabled to be true if testing with rank information.
CreateTable(connection, rankEnabled : true);
RunTests(connection, rankEnabled : true);
}
}
finally
{
// Drop the temporary table.
DropTable(connection);
}
}
}

/// <summary>
/// Verifies if SQL Data Discovery and Classification feature is available on the target server.
/// </summary>
/// <param name="connection">The SqlConnection to work with.</param>
/// <returns>True if the target SQL Server supports the feature and false otherwise.</returns>
public static bool DataClassificationSupported(SqlConnection connection)
{
try
{
SqlCommand command = new SqlCommand(null, connection);
command.CommandText = "SELECT * FROM SYS.SENSITIVITY_CLASSIFICATIONS";
command.ExecuteNonQuery();
}
catch (SqlException e)
{
// Error 208: Object Not Found
if (e.Errors != null && e.Errors[0].Number == 208)
{
{
Console.WriteLine("This feature is not supported on the target SQL Server.");
return false;
}
}
return true;
}

/// <summary>
/// Creates a temporary table for this sample program and sets tags for Sensitivity Classification.
/// </summary>
/// <param name="connection">The SqlConnection to work with.</param>
/// <param name="rankEnabled">True if rank information is enabled and false otherwise</param>
private static void CreateTable(SqlConnection connection, bool rankEnabled = false)
{
SqlCommand command = new SqlCommand(null, connection);

// Creates table for storing Supplier data.


command.CommandText = $"CREATE TABLE {tableName} ("
+ "[Id] [int] IDENTITY(1,1) NOT NULL,"
+ "[CompanyName] [nvarchar](40) NOT NULL,"
+ "[ContactName] [nvarchar](50) NULL,"
+ "[ContactTitle] [nvarchar](40) NULL,"
+ "[City] [nvarchar](40) NULL,"
+ "[CountryName] [nvarchar](40) NULL,"
+ "[Phone] [nvarchar](30) MASKED WITH (FUNCTION = 'default()') NULL,"
+ "[Fax] [nvarchar](30) MASKED WITH (FUNCTION = 'default()') NULL)";
command.ExecuteNonQuery();

if (rankEnabled)
{
// Set Sensitivity Classification tags for table columns with rank information
command.CommandText = $"ADD SENSITIVITY CLASSIFICATION TO {tableName}"
+ ".CompanyName WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Company Name',
INFORMATION_TYPE_ID='COMPANY', RANK=LOW)";
command.ExecuteNonQuery();

command.CommandText = $"ADD SENSITIVITY CLASSIFICATION TO {tableName}"


+ ".ContactName WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Person Name',
INFORMATION_TYPE_ID='NAME', RANK=LOW)";
command.ExecuteNonQuery();

command.CommandText = $"ADD SENSITIVITY CLASSIFICATION TO {tableName}"


+ ".Phone WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Contact Information',
INFORMATION_TYPE_ID='CONTACT', RANK=MEDIUM)";
command.ExecuteNonQuery();

command.CommandText = $"ADD SENSITIVITY CLASSIFICATION TO {tableName}"


+ ".Fax WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Contact Information',
INFORMATION_TYPE_ID='CONTACT', RANK=MEDIUM)";
command.ExecuteNonQuery();
}
else
{
// Set Sensitivity Classification tags for table columns without rank information
command.CommandText = $"ADD SENSITIVITY CLASSIFICATION TO {tableName}"
+ ".CompanyName WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Company Name',
INFORMATION_TYPE_ID='COMPANY')";
command.ExecuteNonQuery();

command.CommandText = $"ADD SENSITIVITY CLASSIFICATION TO {tableName}"


+ ".ContactName WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Person Name',
INFORMATION_TYPE_ID='NAME')";
command.ExecuteNonQuery();

command.CommandText = $"ADD SENSITIVITY CLASSIFICATION TO {tableName}"


+ ".Phone WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Contact Information',
INFORMATION_TYPE_ID='CONTACT')";
command.ExecuteNonQuery();
command.CommandText = $"ADD SENSITIVITY CLASSIFICATION TO {tableName}"
+ ".Fax WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Contact Information',
INFORMATION_TYPE_ID='CONTACT')";
command.ExecuteNonQuery();
}
}

/// <summary>
/// Run query to fetch result set from target table.
/// </summary>
/// <param name="connection">The SqlConnection to work with.</param>
/// <param name="rankEnabled">True if rank information is enabled and false otherwise</param>
private static void RunTests(SqlConnection connection, bool rankEnabled = false)
{
SqlCommand command = new SqlCommand(null, connection);
command.CommandText = $"SELECT * FROM {tableName}";
using (SqlDataReader reader = command.ExecuteReader())
{
PrintSensitivityClassification(reader, rankEnabled);
}
}

/// <summary>
/// Prints Sensitivity Classification data as received in the result set.
/// </summary>
/// <param name="reader">The SqlDataReader to work with.</param>
/// <param name="rankEnabled">True if rank information is enabled and false otherwise</param>
private static void PrintSensitivityClassification(SqlDataReader reader, bool rankEnabled = false)
{
if (reader.SensitivityClassification != null)
{
for (int columnPos = 0; columnPos < reader.SensitivityClassification.ColumnSensitivities.Count;
columnPos++)
{
foreach (SensitivityProperty sp in
reader.SensitivityClassification.ColumnSensitivities[columnPos].SensitivityProperties)
{
if (sp.Label != null)
{
Console.WriteLine($"Labels received for Column : {columnPos}");
Console.WriteLine($"Label ID: {sp.Label.Id}");
Console.WriteLine($"Label Name: {sp.Label.Name}");
Console.WriteLine();
}

if (sp.InformationType != null)
{
Console.WriteLine($"Information Types received for Column : {columnPos}");
Console.WriteLine($"Information Type ID: {sp.InformationType.Id}");
Console.WriteLine($"Information Type: {sp.InformationType.Name}");
Console.WriteLine();
}

Console.WriteLine($"Sensitivity Rank: {sp.SensitivityRank.ToString()}");


}
}
Console.Writeline($"reader.SensitivityClassification.SensitivityRank :
{reader.SensitivityClassification.SensitivityRank.ToString()}");
}
}

/// <summary>
/// Deletes the table created for this sample program.
/// </summary>
/// <param name="connection">The SqlConnection to work with.</param>
private static void DropTable(SqlConnection connection)
{
SqlCommand command = new SqlCommand(null, connection);
command.CommandText = $"DROP TABLE {tableName}";
command.ExecuteNonQuery();
}
}

See also
SQL Server features and ADO.NET
sys.sensitivity_classifications (Transact-SQL)
ADD SENSITIVITY CLASSIFICATION
Microsoft JDBC Driver for SQL Server
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


In our continued commitment to interoperability, Microsoft provides a Java Database Connectivity (JDBC) driver
for use with SQL Server, Azure SQL Database, and Azure SQL Managed Instance. The driver is available at no
extra charge and provides Java database connectivity from any Java application, application server, or Java-
enabled applet. This driver is a Type 4 JDBC driver that provides database connectivity through the standard
JDBC application program interfaces (APIs).
The Microsoft JDBC Driver for SQL Server has been tested against major application servers such as IBM
WebSphere and SAP NetWeaver.

Getting started
Step 1: Configure development environment for Java development
Step 2: Create a SQL database for Java development
Step 3: Proof of concept connecting to SQL using Java

Documentation
Getting Started
Overview
Programming Guide
Security
Performance and Reliability
Troubleshooting
Code Samples
Compliance and Legal

Community
Feedback and finding additional JDBC driver information

Download
Download Microsoft JDBC Driver for SQL Server - has additional information about Maven projects, and more.

Samples
Sample JDBC driver applications
Getting started with Java on Windows
Getting started with Java on macOS
Getting started with Java on Ubuntu
Getting started with Java on Red Hat Enterprise Linux (RHEL)
Getting started with Java on SUSE Linux Enterprise Server (SLES)
Getting started with the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver

Getting started
Step 1: Configure development environment for Java development
Step 2: Create a SQL database for Java development
Step 3: Proof of concept connecting to SQL using Java
Step 1: Configure development environment for
Java development
4/27/2022 • 2 minutes to read • Edit Online

Windows
Identify which version of the JDBC driver you'll use, based on your environment, as noted here: System
Requirements for the JDBC Driver
Download and install applicable JDBC Driver here: Download Microsoft JDBC Driver for SQL Server
Set class path based on the driver version, as noted here: Using the JDBC Driver
Step 2: Create a SQL database for Java
development
4/27/2022 • 2 minutes to read • Edit Online

The samples in this section only work with the AdventureWorks schema, on either Microsoft SQL Server or
Azure SQL Database.

Azure SQL Database


Create a SQL database in minutes using the Azure portal

Microsoft SQL Server


Microsoft SQL Server Samples on GitHub
Step 3: Proof of concept connecting to SQL using
Java
4/27/2022 • 2 minutes to read • Edit Online

This example should be considered a proof of concept only. The sample code is simplified for clarity, and doesn't
necessarily represent best practices recommended by Microsoft.

Step 1: Connect
Use the connection class to connect to SQL Database.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class SQLDatabaseConnection {


// Connect to your database.
// Replace server name, username, and password with your credentials
public static void main(String[] args) {
String connectionUrl =
"jdbc:sqlserver://yourserver.database.windows.net:1433;"
+ "database=AdventureWorks;"
+ "user=yourusername@yourserver;"
+ "password=yourpassword;"
+ "encrypt=true;"
+ "trustServerCertificate=false;"
+ "loginTimeout=30;";

try (Connection connection = DriverManager.getConnection(connectionUrl);) {


// Code here.
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}
}

Step 2: Execute a query


In this sample, connect to Azure SQL Database, execute a SELECT statement, and return selected rows.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SQLDatabaseConnection {

// Connect to your database.


// Replace server name, username, and password with your credentials
public static void main(String[] args) {
String connectionUrl =
"jdbc:sqlserver://yourserver.database.windows.net:1433;"
+ "database=AdventureWorks;"
+ "user=yourusername@yourserver;"
+ "password=yourpassword;"
+ "encrypt=true;"
+ "trustServerCertificate=false;"
+ "loginTimeout=30;";

ResultSet resultSet = null;

try (Connection connection = DriverManager.getConnection(connectionUrl);


Statement statement = connection.createStatement();) {

// Create and execute a SELECT SQL statement.


String selectSql = "SELECT TOP 10 Title, FirstName, LastName from SalesLT.Customer";
resultSet = statement.executeQuery(selectSql);

// Print results from select statement


while (resultSet.next()) {
System.out.println(resultSet.getString(2) + " " + resultSet.getString(3));
}
}
catch (SQLException e) {
e.printStackTrace();
}
}
}

Step 3: Insert a row


In this example, execute an INSERT statement, pass parameters, and retrieve the auto-generated Primary Key
value.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

public class SQLDatabaseConnection {

// Connect to your database.


// Replace server name, username, and password with your credentials
public static void main(String[] args) {
String connectionUrl =
"jdbc:sqlserver://yourserver.database.windows.net:1433;"
+ "database=AdventureWorks;"
+ "user=yourusername@yourserver;"
+ "password=yourpassword;"
+ "encrypt=true;"
+ "trustServerCertificate=false;"
+ "loginTimeout=30;";

String insertSql = "INSERT INTO SalesLT.Product (Name, ProductNumber, Color, StandardCost,


ListPrice, SellStartDate) VALUES "
+ "('NewBike', 'BikeNew', 'Blue', 50, 120, '2016-01-01');";

ResultSet resultSet = null;

try (Connection connection = DriverManager.getConnection(connectionUrl);


PreparedStatement prepsInsertProduct = connection.prepareStatement(insertSql,
Statement.RETURN_GENERATED_KEYS);) {

prepsInsertProduct.execute();
// Retrieve the generated key from the insert.
resultSet = prepsInsertProduct.getGeneratedKeys();

// Print the ID of the inserted row.


while (resultSet.next()) {
System.out.println("Generated: " + resultSet.getString(1));
}
}
// Handle any errors that may have occurred.
catch (Exception e) {
e.printStackTrace();
}
}
}

Additional samples
Sample JDBC driver applications
Overview of the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server is a Type 4 Java Database Connectivity (JDBC) 4.2 compliant driver
that provides robust data access to SQL Server and Azure SQL databases.

Redistribution
The JDBC Driver versions 6.0 and up are redistributable. Review the Distributable Code clause in the license
agreements.
The JDBC Driver versions 4.x are obsolete. Support for 4.x expired before 2018.

In this section
The articles in this section provide a general overview of the JDBC driver, including the system requirements
needed to use it, how it can be used, and where you can go for more information.

A RT IC L E DESC RIP T IO N

Download Microsoft JDBC Driver for SQL Server Download links for Microsoft JDBC driver for SQL Server

Release notes for the JDBC driver Describes the features that have been added to the current
release of the Microsoft JDBC driver.

System requirements for the JDBC driver Describes the system requirements needed to use the
Microsoft JDBC driver.

Using the JDBC driver Describes how to configure your environment to use the
Microsoft JDBC driver and how to make a simple connection
to a SQL Server database.

Understanding Java EE support Describes how to use the Microsoft JDBC driver within a
Java Platform, Enterprise Edition (Java EE) environment.

Deploying the JDBC driver Describes how to redistribute and deploy the Microsoft
JDBC driver on Windows and Unix operating systems.

Finding additional JDBC driver information Describes where to find additional resources about the
Microsoft JDBC driver, including links to external resources.

Microsoft JDBC Driver for SQL Server support matrix Support matrix and support lifecycle policy for the Microsoft
JDBC driver for SQL Server.

Frequently asked questions (FAQ) for JDBC driver Frequently asked questions about the Microsoft JDBC driver.

Feature dependencies of Microsoft JDBC Driver for SQL Feature dependencies of Microsoft JDBC Driver for SQL
Server Server.
A RT IC L E DESC RIP T IO N

See also
JDBC driver GitHub repository
JDBC driver API reference
Download Microsoft JDBC Driver for SQL Server
4/27/2022 • 2 minutes to read • Edit Online

The Microsoft JDBC Driver for SQL Server is a Type 4 JDBC driver that provides database connectivity through
the standard JDBC application program interfaces (APIs) available on the Java platform. The driver downloads
are available to all users at no extra charge. They provide access to SQL Server from any Java application,
application server, or Java-enabled applet.

Download
Version 10.2 is the latest general availability (GA) version. It supports Java 8, 11, and 17. If you need to use an
older Java runtime, see the Java and JDBC specification support matrix to see if there's a supported driver
version you can use. We're continually improving Java connectivity support. As such we highly recommend that
you work with the latest version of Microsoft JDBC driver.

Download Microsoft JDBC Driver 10.2 for SQL Ser ver (zip)
Download Microsoft JDBC Driver 10.2 for SQL Ser ver (tar.gz)
Version information
Release number: 10.2.0
Released: January 31, 2022
When you download the driver, there are multiple JAR files. The name of the JAR file indicates the version of
Java that it supports.

NOTE
If you are accessing this page from a non-English language version, and want to see the most up-to-date content, please
select Read in English at the top of this page. You can download different languages from the US-English version site by
selecting available languages.

Available languages
This release of Microsoft JDBC Driver for SQL Server is available in the following languages:
Microsoft JDBC Driver 10.2.0 for SQL Server (zip): Chinese (Simplified) | Chinese (Traditional) | English (United
States) | French | German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Microsoft JDBC Driver 10.2.0 for SQL Server (tar.gz): Chinese (Simplified) | Chinese (Traditional) | English (United
States) | French | German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Release notes
For details about this release, see the release notes and system requirements.
Previous releases
To download previous releases, see previous Microsoft JDBC Driver for SQL Server releases.

Using the JDBC driver with Maven Central


The JDBC driver can be added to a Maven project by adding it as a dependency in the POM.xml file with the
following code:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>10.2.0.jre11</version>
</dependency>

Unsupported drivers
Unsupported driver versions aren't available for download here. We're continually improving the Java
connectivity support. As such we highly recommend that you work with the latest version of Microsoft JDBC
driver.

Next steps
For more information about the Microsoft JDBC Driver for SQL Server, see Overview of the JDBC driver and the
JDBC driver GitHub repository.
Release notes for the Microsoft JDBC Driver for
SQL Server
4/27/2022 • 32 minutes to read • Edit Online

This article lists the releases of the Microsoft JDBC Driver for SQL Server. For each release version, the changes
are named and described.

10.2
Download Microsoft JDBC Driver 10.2.0 for SQL Ser ver (zip)
Download Microsoft JDBC Driver 10.2.0 for SQL Ser ver (tar.gz)
Release number: 10.2.0
Released: January 31, 2022
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a zip file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German |
Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
10.2 Compliance
C O M P L IA N C E C H A N GE DETA IL S

Download the latest updates for JDBC Driver 10.2. • GitHub, 10.2.0
• Maven Central

Fully compliant with JDBC API Specification 4.2. The jars in the 10.2 package are named according to Java
version compatibility.

For example, the mssql-jdbc-10.20.jre17.jar file from the


10.2 package should be used with Java 17.

Compatible with Java Development Kit (JDK) version 17.0, Microsoft JDBC Driver 10.2 for SQL Server is now
11.0, and 1.8. compatible with Java Development Kit (JDK) version 17.0 in
addition to JDK 11.0 and 1.8.

New features in 10.2


F EAT URE DETA IL S

Java 17 support The driver is now compatible with Java Development Kit
(JDK) version 17.0 in addition to JDK 11.0 and 1.8.

Idle Connection Resiliency support Idle Connection Resiliency is now supported. See Idle
Connection Resiliency.
F EAT URE DETA IL S

Multi-user Key Store Providers The driver now supports Key Store providers at the
connection and statement level to support multi-user
scenarios. See Using Always Encrypted with the JDBC driver.

Changes in 10.2
C H A N GE DETA IL S

Default encrypt to true BREAKING CHANGE TLS encryption is enabled by default.

Certificate validation when encrypt = false BREAKING CHANGE When encrypt = false but the server
requires encryption, the certificate will be validated based on
the trustServerCertificate connection setting.

aadSecurePrincipalId and aadSecurePrincipalSecret The aadSecurePrincipalId and aadSecurePrincipalSecret


deprecated connection properties have been deprecated. Use username
and password instead.

getAADSecretPrincipalId API removed BREAKING CHANGE The getAADSecretPrincipalId API has


been removed for security reasons.

SQL_Variant support Added support for SQL_Variant datatype when retrieving


DateTimeOffset.

Non-blocking random in Linux Updated to use a non-blocking random call when


generating a GUID for enclave packages.

CNAME resolution for realm Added CNAME resolution when realm is specified.

Updated dependencies Updated dependency versions for azure-identity ,


azure-security-keyvault-keys , gson , and
bouncycastle .

Fixes in 10.2
F IX DETA IL S

TDSParser stuck on TDS_COLMETADATA Fixed: TDSParser stuck on TDS_COLMETADATA, which could


result in a hang for certain queries. GitHub Issue #1661

Previous releases
9.4
Download Microsoft JDBC Driver 9.4.1 for SQL Ser ver (zip)
Download Microsoft JDBC Driver 9.4.1 for SQL Ser ver (tar.gz)
Release number: 9.4.1
Released: December 7, 2021
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a zip file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German |
Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
9.4 Compliance
C O M P L IA N C E C H A N GE DETA IL S

Download the latest updates for JDBC Driver 9.4. • GitHub, 9.4.0
• Maven Central

Fully compliant with JDBC API Specification 4.2. The jars in the 9.4 package are named according to Java
version compatibility.

For example, the mssql-jdbc-9.4.0.jre16.jar file from the 9.4


package should be used with Java 16.

Compatible with Java Development Kit (JDK) version 16.0, Microsoft JDBC Driver 9.4 for SQL Server is now compatible
11.0, and 1.8. with Java Development Kit (JDK) version 16.0 in addition to
JDK 11.0 and 1.8.

9.4 Releases
Version number: 9.4.1
Released: December 07, 2021
Fixed issues in 9.4.1:
Fixed potential hang when the driver encounters unsupported TDS_COLMETADATA
Fixed conversion of LocalDateTime and LocalTime to String in Bulk Copy
Version number: 9.4.0
Released: July 30, 2021

Download Microsoft JDBC Driver 9.4.0 for SQL Ser ver (zip)
Download Microsoft JDBC Driver 9.4.0 for SQL Ser ver (tar.gz)
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a zip file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German |
Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
New features in 9.4
F EAT URE DETA IL S

Java 16 support The driver is now compatible with Java Development Kit
(JDK) version 16.0 in addition to JDK 11.0 and 1.8.
F EAT URE DETA IL S

Replication connection support Replication connections are now supported. See Setting the
connection properties.

Custom Kerberos authentication realm The driver now supports specifying a custom authentication
realm when using Kerberos authentication. See Setting the
connection properties.

Open Connection Retry The connectRetryCount and connectRetryInterval


connection properties have been added to configure
automatic retries when opening connections. See Setting the
connection properties for details on these new properties.

Changes in 9.4
C H A N GE DETA IL S

Azure Key Vault Provider Multiple, successive connections can be opened that specify
different Azure Key Vault provider information.

Updated error messages Error messages related to Enclave exceptions now include a
link to a troubleshooting guide.
Error messages related to Active Directory authentication
failures now include the error string from the underlying
library.

Driver version sent to server The driver version is now correctly sent to the database
during PRELOGIN .

Client process ID The client process ID is now sent to the server when running
on Java 9+. Java 8 keeps the previous functionality of
sending 0 for the client process ID.

Updated dependencies Updated dependency versions for azure-identity ,


azure-security-keyvault-keys , gson , antlr , and
bouncycastle .

Removed unnecessary references Removed unused Java 9-specific class references from the
Java 8 jar

Fixes in 9.4
F IX DETA IL S

GitHub Issue #1499 Fixed: Batch fails when always encrypted is enabled in the
connection string and clearParameters is called.

GitHub Issue #1632 Fixed: Small memory leak on new connection.

GitHub Issue #1565 Fixed an issue where trustStorePassword is null when using
applicationIntent=ReadOnly
F IX DETA IL S

GitHub Issue #1568 Fixed an issue where redirected token contains named
instance in servername

GitHub Issue #1531 Fixed potential integer overflow in TDSWriter.writeString()

9.2
Download Microsoft JDBC Driver 9.2.1 for SQL Ser ver (zip)
Download Microsoft JDBC Driver 9.2.1 for SQL Ser ver (tar.gz)
Version number: 9.2.1
Released: March 02, 2021
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a zip file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German |
Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
9.2 Compliance
C O M P L IA N C E C H A N GE DETA IL S

Download the latest updates for JDBC Driver 9.2. • GitHub, 9.2.1
• Maven Central

Fully compliant with JDBC API Specification 4.2. The jars in the 9.2 package are named according to Java
version compatibility.

For example, the mssql-jdbc-9.2.1.jre15.jar file from the 9.2


package should be used with Java 15.

Compatible with Java Development Kit (JDK) version 15.0, Microsoft JDBC Driver 9.2 for SQL Server is now compatible
11.0, and 1.8. with Java Development Kit (JDK) version 15.0 in addition to
JDK 11.0 and 1.8.

9.2 Releases
Version number: 9.2.1
Released: March 02, 2021
Fixed issues in 9.2.1:
Fixed an issue with client secret being empty during ActiveDirectoryServicePrincipal authentication in Azure
environment.
Version number: 9.2.0
Released: January 29, 2021

Download Microsoft JDBC Driver 9.2.0 for SQL Ser ver (zip)
Download Microsoft JDBC Driver 9.2.0 for SQL Ser ver (tar.gz)
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a zip file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German |
Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Support for JDK 15
Microsoft JDBC Driver 9.2 for SQL Server is now compatible with Java Development Kit (JDK) version 15.0 in
addition to JDK 11.0 and 1.8.
Added support for Azure Active Directory Interactive Authentication
A UT H EN T IC AT IO N T Y P E A DDIT IO N DETA IL S

Microsoft JDBC Driver 9.2 for SQL Server now supports See Connecting using Azure Active Directory authentication.
authentication to Azure Key Vault via interactive
authentication.

Added support for Azure Active Directory Service Principal Authentication


A UT H EN T IC AT IO N T Y P E A DDIT IO N DETA IL S

Microsoft JDBC Driver 9.2 for SQL Server now supports See Connecting using Azure Active Directory authentication.
authentication to Azure Key Vault using the client ID and
secret of a service principal identity.

Updated Azure Key Vault library to use modern Azure Key Vault library
L IB RA RY C H A N GES F O R A Z URE K EY VA ULT DETA IL S

Microsoft JDBC Driver 9.2 migrated from the previous- DEPENDENCY CHANGE Make sure you update your
generation Azure Key Vault library and ADAL libraries to the application dependencies if you take advantage of Azure
more modern Azure Key Vault and Azure Identity Active Directory authentication or Azure Key Vault. See the
equivalents. dependency requirements when work with the Azure Key
Vault provider or Azure Active Directory authentication

Enabled useBulkCopyForBatchInsert for non-Azure Synapse Analytics servers


USEB UL KC O P Y F O RB ATC H IN SERT C H A N GES F O R N O N
A Z URE SY N A P SE A N A LY T IC S SERVERS DETA IL S

Microsoft JDBC Driver 9.2 now allows bulk copy API for See Using bulk copy API for batch insert operation.
batch insert operation against non-Azure Synapse Analytics
servers.
8.4
Download Microsoft JDBC Driver 8.4 for SQL Ser ver (zip)
Download Microsoft JDBC Driver 8.4 for SQL Ser ver (tar.gz)
Version number: 8.4.1
Released: August 27, 2020
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a zip file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German |
Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
8.4 Compliance
C O M P L IA N C E C H A N GE DETA IL S

Download the latest updates for JDBC Driver 8.4. • GitHub, 8.4.1
• Maven Central

Fully compliant with JDBC API Specification 4.2. The jars in the 8.4 package are named according to Java
version compatibility.

For example, the mssql-jdbc-8.4.1.jre14.jar file from the 8.4


package should be used with Java 14.

Compatible with Java Development Kit (JDK) version 14.0, Microsoft JDBC Driver 8.4 for SQL Server is now compatible
11.0, and 1.8. with Java Development Kit (JDK) version 14.0 in addition to
JDK 11.0 and 1.8.

8.4 Releases
Version number: 8.4.1
Released: August 27, 2020
Fixed issues:
Fixed an issue with SQLServerConnectionPoolProxy not being compatible with delayLoadingLobs
Fixed a potential NullPointerException issue with delayLoadingLobs
Fixed an issue with decrypting column encryption keys when using the Windows Certificate Store
Version number: 8.4.0
Released: July 31, 2020
Support for JDK 14
Microsoft JDBC Driver 8.4 for SQL Server is now compatible with Java Development Kit (JDK) version 14.0 in
addition to JDK 11.0 and 1.8.
Added support for authentication to Azure Key Vault using Managed Identity
A UT H EN T IC AT IO N T Y P E A DDIT IO N DETA IL S

Microsoft JDBC Driver 8.4 for SQL Server now supports See Using Always Encrypted with the JDBC driver.
authentication to Azure Key Vault using Managed Identity.
A UT H EN T IC AT IO N T Y P E A DDIT IO N DETA IL S

Extended support for bulk copy for Azure Data Warehouse


B UL K C O P Y C H A N GES F O R A Z URE DATA WA REH O USE DETA IL S

Microsoft JDBC Driver 8.4 adds a new connection property, See Using bulk copy with the JDBC driver.
sendTemporalDataTypesAsStringForBulkCopy . This
boolean property is TRUE by default.

Added support for Azure SQL DNS caching


DN S C A C H IN G DETA IL S

Microsoft JDBC Driver 8.4 for SQL Server now supports DNS
caching against Azure SQL Servers.

Added backwards compatibility for streaming LOB objects


LO B ST REA M IN G DETA IL S

Microsoft JDBC Driver 8.4 for SQL Server added a new Setting delayLoadingLobs to FALSE will cause all LOB
connection property delayLoadingLobs . objects retrieved from the ResultSet to not be streamed. This
means that the driver will load the entire LOB object into
memory at once, similar to how the driver was functioning
before version 6.4 release.

Added support for client certificate authentication for loopback scenarios


C L IEN T C ERT IF IC AT E A UT H EN T IC AT IO N DETA IL S

Microsoft JDBC Driver 8.4 for SQL Server added a new See Client Certificate Authentication for Loopback Scenarios.
authentication method called client certificate authentication
for loopback scenarios.

8.2
Download Microsoft JDBC Driver 8.2 for SQL Ser ver (zip)
Download Microsoft JDBC Driver 8.2 for SQL Ser ver (tar.gz)
Version number: 8.2.2 Released: March 24, 2020
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a zip file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German |
Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
8.2 Compliance
C O M P L IA N C E C H A N GE DETA IL S

Download the latest updates for JDBC Driver 8.2. • GitHub, 8.2.2
• Maven Central

Fully compliant with JDBC API Specification 4.2. The jars in the 8.2 package are named according to Java
version compatibility.

For example, the mssql-jdbc-8.2.2.jre11.jar file from the 8.2


package should be used with Java 11.

Compatible with Java Development Kit (JDK) version 13.0, Microsoft JDBC Driver 8.2 for SQL Server is now compatible
11.0, and 1.8. with Java Development Kit (JDK) version 13.0 in addition to
JDK 11.0 and 1.8.

8.2 Releases
Version number: 8.2.2
Released: March 24, 2020
Fixed issues:
Added an option to configure the list of trusted Azure Key Vault endpoints
Version number: 8.2.1
Released: February 26, 2020
Fixed issues:
Fixed a potential NullPointerException issue when retrieving data as java.time.LocalTime or
java.time.LocalDate type with SQLServerResultSet.getObject()

Version number: 8.2.0


Released: January 31, 2020
Support for JDK 13
Microsoft JDBC Driver 8.2 for SQL Server is now compatible with Java Development Kit (JDK) version 13.0 in
addition to JDK 11.0 and 1.8.
Always Encrypted with secure enclaves
A L WAY S EN C RY P T ED C H A N GE DETA IL S

Microsoft JDBC Driver 8.2 for SQL Server now supports


Always Encrypted with secure enclaves. The details can be
found here: Always Encrypted with secure enclaves.

More details and sample code. See Always Encrypted with secure enclaves.

Performance Improvement when Retrieving Temporal Datatypes from SQL Server 1


T EM P O RA L DATAT Y P ES C H A N GE DETA IL S

Microsoft JDBC Driver 8.2 for SQL Server has improved This change eliminates unnecessary temporal datatype
performance when retrieving temporal datatypes from SQL conversions by eliminating the use of java.util.Calendar
Server. wherever possible.

The following is a list of the temporal datatypes that have date (java.sql.Date), datetime (java.sql.Timestamp),
been affected by this performance improvement; in format datetime2 (java.sql.Timestamp), smalldatetime
SQL Server datatype followed by the respective Java (java.sql.Timestamp), and time (java.sql.Time).
mapping.

1 Due to the differences in howtime zones are handled between java.util.Calendar and java.time.LocalDateTime
API, temporal datatypes with a user provided java.util.Calendar object associated with it or
microsoft.sql.DateTimeOffset datatypes do not benefit from this improvement.
Deployment of mssql-jdbc_auth-<version>-<arch>.dll (previously sqljdbc_auth.dll) to Maven Repository
SQ L JDB C _A UT H . DL L C H A N GE DETA IL S

Starting from Microsoft JDBC Driver 8.2 for SQL Server, the
driver relies on mssql-jdbc_auth-<version>-<arch>.dll
instead of sqljdbc_auth.dll to use Azure Active Directory
Authentication feature.

The DLL has also been uploaded to Maven repository for See this page.
easier access.

8.2 Known issues


K N O W N ISSUES DETA IL S

When using Always Encrypted with secure enclaves with Users must include BouncyCastle Provider as a dependency
Java 8. OR map/load a security provider which supports the
RSASSA-PSS signature algorithm.

7.4.1
Download Microsoft JDBC Driver 7.4.1 for SQL Ser ver (self-extracting exe)
Download Microsoft JDBC Driver 7.4.1 for SQL Ser ver (tar.gz)
Version number: 7.4.1
Released: August 2, 2019
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a self-extracting exe file: Chinese (Simplified) | Chinese (Traditional) | English (United States) |
French | German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
7.4 Compliance
C O M P L IA N C E C H A N GE DETA IL S

Download the latest updates for JDBC Driver 7.4. • GitHub, 7.4.1
• Maven Central

Fully compliant with JDBC API Specification 4.2. The jars in the 7.4 package are named according to Java
version compatibility.

For example, the mssql-jdbc-7.4.1.jre11.jar file from the 7.4


package should be used with Java 11.

Compatible with Java Development Kit (JDK) version 12.0, Microsoft JDBC Driver 7.4 for SQL Server is now compatible
11.0, and 1.8. with Java Development Kit (JDK) version 12.0 in addition to
JDK 11.0 and 1.8.

7.4 Releases
Version number: 7.4.1
Released: August 2, 2019
Fixed issues:
Reverted new hashCode() and equals() API implementations from SQLServerDataTable and
SQLServerDataColumn as the API change broke backwards compatibility

Version number: 7.4.0


Released: July 31, 2019
Support for JDK 12
Microsoft JDBC Driver 7.4 for SQL Server is now compatible with Java Development Kit (JDK) version 12.0 in
addition to JDK 11.0 and 1.8.
Introduces NTLM authentication
N T L M C H A N GE DETA IL S

Supports NTLM authentication mode. This mode of authentication allows both Windows and non-
Windows clients to authenticate themselves against SQL
Server using Windows domain users.

More details and a sample application to use this See Connecting using NTLM Authentication.
authentication mode.

Introduces querying ParameterMetaData via useFmtOnly


USEF M TO N LY C H A N GE DETA IL S

useFmtOnly connection property added. This feature allows users to optionally query
ParameterMetaData via the SET FMTONLY ON legacy API.
This is useful for scenarios where
sp_describe_undeclared_parameters doesn't perform as
expected.
USEF M TO N LY C H A N GE DETA IL S

More details and limitations. See Using useFmtOnly

Updated Microsoft Azure Key Vault SDK for Java, version 1.2.1
K EY VA ULT SDK C H A N GE DETA IL S

Updated its Maven dependency on Microsoft Azure Key


Vault SDK for Java to version 1.2.1.

Removes Microsoft Azure SDK for Key Vault WebKey as a


Maven dependency.

Additional details. See Feature dependencies of the Microsoft JDBC Driver for
SQL Server.

7.4 Known issues


K N O W N ISSUES DETA IL S

When using NTLM Authentication. Enabling Extended Protection and encrypted connections at
the same time is currently not supported.

When using useFmtOnly. There are some issues with the feature, which are caused by
deficiencies in SQL parsing logic. See Using useFmtOnly for
more details and workaround suggestions.

7.2.2
Download Microsoft JDBC Driver 7.2.2 for SQL Ser ver (self-extracting exe)
Download Microsoft JDBC Driver 7.2.2 for SQL Ser ver (tar.gz)
Version number: 7.2.2
Released: April 16, 2019
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a self-extracting exe file: Chinese (Simplified) | Chinese (Traditional) | English (United States) |
French | German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
7.2 Compliance
C O M P L IA N C E C H A N GE DETA IL S

Download the latest updates for JDBC Driver 7.2. • GitHub, 7.2.2
• Maven Central
C O M P L IA N C E C H A N GE DETA IL S

Fully compliant with JDBC API Specification 4.2. The jars in the 7.2 package are named according to Java
version compatibility.

For example, the mssql-jdbc-7.2.2.jre11.jar file from the 7.2


package should be used with Java 11.

Compatible with Java Development Kit (JDK) version 11.0 in Microsoft JDBC Driver 7.2 for SQL Server is now compatible
addition to JDK 1.8. with Java Development Kit (JDK) version 11.0 in addition to
JDK 1.8.

7.2 Releases
Version number: 7.2.2
Released: April 16, 2019
Fixed issues:
Fixed issues with ActivityIDs not getting cleaned up properly
Version number: 7.2.1
Released: February 11, 2019
Fixed issues:
Fixed parsing issues with certain parameterized queries
Version number: 7.2.0
Released: January 31, 2019
Active Directory Managed Identity (MSI ) authentication
M SI C H A N GE DETA IL S

Supports Active Directory Managed Identity (MSI) This mode of authentication is applicable on Azure Resources
authentication mode. with support for the "Identity" feature enabled.

Both types of Managed Identities (MSI) are supported by


the driver to acquire accessToken for establishing secure
connection.

More details and a sample application to use this See Connecting using Azure Active Directory Authentication.
authentication mode.

Introduces Open Service Gateway Initiative (OSGi) support


O SGI C H A N GE DETA IL S

DataSourceFactor y implementation added. • org.osgi.service.jdbc.DataSourceFactory



com.microsoft.sqlserver.jdbc.osgi.SQLServerDataSourceFactory
O SGI C H A N GE DETA IL S

Activator implementation added. • org.osgi.framework.BundleActivator


• com.microsoft.sqlserver.jdbc.osgi.Activator

Introduces SQLServerError APIs


ERRO R A P I C H A N GE DETA IL S

SQLServerError API introduced. Getter APIs to retrieve additional details about the error
generated from the server.

• SQLServerException.getSQLServerError()
• SQLServerError

Additional details. See Handling Errors.

Updated Microsoft Azure Active Directory Authentication Library (ADAL4J ) for Java, version 1.6.3
A DA L 4J C H A N GE DETA IL S

Updated its Maven dependency on ADAL4J to version 1.6.3.

Introduces Java Client Runtime for AutoRest as a Maven


dependency, version 1.6.5.

Additional details. See Feature dependencies of the Microsoft JDBC Driver for
SQL Server.

Updated Microsoft Azure Key Vault SDK for Java, version 1.2.0
K EY VA ULT SDK C H A N GE DETA IL S

Updated its Maven dependency on Microsoft Azure Key


Vault SDK for Java to version 1.2.0.

Introduces Microsoft Azure SDK for Key Vault WebKey as a


Maven dependency, version 1.2.0.

Additional details. See Feature dependencies of the Microsoft JDBC Driver for
SQL Server.

7.2 Known issues


K N O W N ISSUES DETA IL S
K N O W N ISSUES DETA IL S

Parameterized queries, in certain cases. An update of the 7.2.0 version, v7.2.1, was released in
February 2019 to address this issue.

Cleaning up of ActivityIds. An update of the 7.2.1 version, v7.2.2, was released in April
2019 to address this issue.

7.0
Download Microsoft JDBC Driver 7.0 for SQL Ser ver (self-extracting exe)
Download Microsoft JDBC Driver 7.0 for SQL Ser ver (tar.gz)
Version number: 7.0.0
Released: July 31, 2018
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a self-extracting exe file: Chinese (Simplified) | Chinese (Traditional) | English (United States) |
French | German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Microsoft JDBC Driver 7.0 for SQL Server is fully compliant with JDBC API Specification 4.2. The jars in the 7.0
package are named according to Java version compatibility. For example, the mssql-jdbc-7.0.0.jre10.jar file from
the 7.0 package should be used with Java 10.
Support for JDK 10
Microsoft JDBC Driver 7.0 for SQL Server is now compatible with Java Development Kit (JDK) version 10.0 in
addition to JDK 1.8. This update also exposes the driver's Automatic-Module-Name as
com.microsoft.sqlserver.jdbc through its MANIFEST file.

Support for spatial datatypes


Microsoft JDBC Driver 7.0 for SQL Server now provides support for SQL Server spatial datatypes Geography
and Geometry. For more information about spatial datatype APIs and how to use them, see Using spatial
datatypes.
Implementation for JDBC 4.3 introduced java.sql.Connection APIs beginRequest() and endRequest()
Microsoft JDBC Driver 7.0 for SQL Server now implements beginRequest() and endRequest() APIs from the
java.sql.Connection class. These APIs were introduced with JDBC 4.3 specifications and JDK 9. For more
information about the driver's implementation of these APIs, see JDBC 4.3 compliance for the JDBC Driver.
Support for SQL Data Discovery and Classification
Microsoft JDBC Driver 7.0 for SQL Server provides support for SQL Data Discovery and Classification with any
target database that supports this feature. The driver now exposes
SQLServerResultSet.getSensitivityClassification() APIs to extract this information from the fetched ResultSet .

For more information about how to use this feature with the JDBC Driver, see the sample in SQL Data Discovery
and Classification.
Added connection property: useBulkCopyForBatchInsert
Microsoft JDBC Driver 7.0 for SQL Server introduces a new connection property, useBulkCopyForBatchInsert .
This property is supported only for Azure Synapse Analytics.
This property is disabled by default. You can enable it to increase performance of user applications when you're
pushing large amounts data to Azure Synapse Analytics. Enabling this property changes the behavior of batch
insert operations to switch to bulk copy operations with user-provided data. For more information about this
property and its limitations, see Using Bulk Copy API for batch insert operation.
Added connection property: cancelQueryTimeout
Microsoft JDBC Driver 7.0 for SQL Server introduces a new connection property, cancelQueryTimeout , to cancel
queryTimeout on java.sql.Connection and java.sql.Statement objects.

Added Azure Key Vault Provider constructors


Microsoft JDBC Driver 7.0 for SQL Server reintroduces a previously removed constructor, for
SQLServerColumnEncryptionAzureKeyVaultProvider . It allowed authentication through a custom method
implemented over SQLServerKeyVaultAuthenticationCallback to fetch an access token.
The new constructors have the following definition:

/* This constructor is added to provide backward compatibility with 6.0


* version of the driver. It is marked deprecated for removal in the next
* stable release.
*/
@Deprecated
public SQLServerColumnEncryptionAzureKeyVaultProvider(
SQLServerKeyVaultAuthenticationCallback authenticationCallback,
ExecutorService executorService) throws SQLServerException;

/*New constructor to replace the above constructor*/


public SQLServerColumnEncryptionAzureKeyVaultProvider(
SQLServerKeyVaultAuthenticationCallback authenticationCallback) throws SQLServerException;

Updated "Microsoft Azure Active Directory Authentication Library (ADAL4J) for Java" version: 1.6.0
Microsoft JDBC Driver 7.0 for SQL Server has updated its Maven dependency on "Microsoft Azure Active
Directory Authentication Library (ADAL4J) for Java" to version 1.6.0. For more information about dependencies,
see Feature dependencies of the Microsoft JDBC Driver for SQL Server.

6.4
Download Microsoft JDBC Driver 6.4 for SQL Ser ver (self-extracting exe)
Download Microsoft JDBC Driver 6.4 for SQL Ser ver (tar.gz)
Version number: 6.4.0
Released: February 27, 2018
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a self-extracting exe file: Chinese (Simplified) | Chinese (Traditional) | English (United States) |
French | German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Microsoft JDBC Driver 6.4 for SQL Server is fully compliant with JDBC specifications 4.1 and 4.2. The jars in the
6.4 package are named according to Java version compatibility. For example, the mssql-jdbc-6.4.0.jre8.jar file
from the 6.4 package must be used with Java 8.
Support for JDK 9
The driver supports JDK version 9.0 in addition to JDK 8.0 and 7.0.
JDBC 4.3 compliance
The driver supports the Java Database Connectivity API 4.3 specification, in addition to 4.1 and 4.2. The JDBC 4.3
API methods are added but not implemented yet. For details, see JDBC 4.3 compliance for the JDBC Driver.
Added connection property: sslProtocol
A new connection property lets users specify the TLS protocol keyword. Possible values are: "TLS", "TLSv1",
"TLSv1.1", and "TLSv1.2". For details, see SSLProtocol.
Deprecated connection property: fipsProvider
The connection property fipsProvider is removed from the list of accepted connection properties. For details,
see the related GitHub pull request.
Added connection properties for specifying a custom TrustManager
The driver now supports specifying a custom TrustManager with added trustManagerClass and
trustManagerConstructorArg connection properties. You can dynamically specify a set of certificates that are
trusted on a per-connection basis without modifying the global settings for the Java virtual machine (JVM)
environment.
Added support for datetime/smallDatetime in table -valued parameters
The driver now supports the datatypes datetime and smallDatetime when you're using table-valued
parameters (TVPs).
Added support for the sql_variant datatype
The JDBC Driver now supports sql_variant datatypes to be used with SQL Server. The sql_variant datatype is
also supported with features such as TVPs and bulk copy with the following limitations:
For date values :
When you're using a TVP to populate a table that contains datetime , smalldatetime , or date values
stored in a sql_variant column, calling the getDateTime() , getSmallDateTime() , or getDate() method
on the result set doesn't work and throws the following exception:
java java.lang.String cannot be cast to java.sql.Timestamp

As a workaround, use the getString() or getObject() method instead.


Using a TVP with sql_variant for null values :
If you're using a TVP to populate a table and send a NULL value to the sql_variant column type, you'll
encounter an exception. Inserting a NULL value with the column type sql_variant in a TVP is currently
not supported.
Implemented prepared statement metadata caching
The JDBC Driver has implemented prepared statement metadata caching for performance improvement. The
driver now supports caching prepared statement metadata in the driver with disableStatementPooling and
statementPoolingCacheSize connection properties. This feature is disabled by default. For more information, see
Prepared statement metadata caching for the JDBC Driver.
Added support for Azure AD Integrated Authentication on Linux/macOS
The JDBC Driver now supports Azure Active Directory (Azure AD) Integrated Authentication on all supported
operating systems (Windows, Linux, and macOS) with Kerberos. Alternatively, on Windows operating systems,
users can authenticate with mssql-jdbc_auth-<version>-<arch>.dll.
Updated "Microsoft Azure Active Directory Authentication Library (ADAL4J) for Java" version: 1.4.0
The JDBC Driver has updated its Maven dependency on "Microsoft Azure Active Directory Authentication
Library (ADAL4J) for Java" to version 1.4.0. For more information about dependencies, see Feature
dependencies of the Microsoft JDBC Driver for SQL Server.

6.2
Download Microsoft JDBC Driver 6.2 for SQL Ser ver (self-extracting exe)
Download Microsoft JDBC Driver 6.2 for SQL Ser ver (tar.gz)
Version number: 6.2.2
Released: September 29, 2017
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a self-extracting exe file: Chinese (Simplified) | Chinese (Traditional) | English (United States) |
French | German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Microsoft JDBC Driver 6.2 for SQL Server is fully compliant with JDBC specifications 4.1 and 4.2. The jars in the
6.2 package are named according to Java version compatibility. For example, the mssql-jdbc-6.2.2.jre8.jar file
from the 6.2 package is recommended for use with Java 8.
6.2 Releases
Version number: 6.2.2
Released: October 3, 2017
Fixed issues:
Updated ADAL4J dependency to version 1.2.0 and Azure Key Vault dependency to version 1.0.0
Version number: 6.2.1
Released: July 14, 2017
Fixed issues:
Fixed an issue when running queries without parameters using preparedStatement

Version number: 6.2.0


Released: June 30, 2017

NOTE
An issue with the metadata caching improvement was found in the JDBC 6.2 RTW released on June 29, 2017. The
improvement was rolled back and new jars (version 6.2.1) were released on July 17, 2017.
Another improvement upgraded the Azure Key Vault dependent library version to 1.0.0, and new jars (version 6.2.2) were
released on October 19, 2017.
Download the latest updates for JDBC Driver 6.2 via the above links, GitHub, or Maven Central. Please update your
projects to use the 6.2.2 release jars. For more information, view release notes for 6.2.1 and 6.2.2.

Azure AD support for Linux


Connect your Linux applications to Azure SQL Database by using Azure AD authentication via
username/password and access token methods.
FIPS -enabled JVMs
The JDBC Driver can now be used on JVMs that run in Federal Information Processing Standard (FIPS) 140
compliance mode to meet federal standards on compliance.
Kerberos authentication improvements
The JDBC Driver now has support for:
Principal/password method for applications where the Kerberos configuration can't be modified or can't
retrieve a new token or keytab. This method can be used for authenticating to a SQL Server instance that
allows only Kerberos authentication.
Cross-realm authentication that uses Kerberos Integrated Authentication without explicitly setting the server
SPN. The driver now automatically computes the realm even when it isn't provided.
Kerberos Constrained Delegation by accepting impersonated user credentials as a GSS credential object via
data source. This impersonated credential is then used to establish a Kerberos connection.
Added timeouts
The JDBC Driver now supports the following configurable timeouts. You can change them based on your
application's needs.
Query timeout to control the number of seconds to wait before a timeout occurs when you're running a
query.
Socket timeout to specify the number of milliseconds to wait before a timeout occurs on a socket read or
accept.

6.1
Version number: 6.1.0
Released: November 17, 2016
Microsoft JDBC Driver 6.1 for SQL Server is fully compliant with JDBC specifications 4.1 and 4.2. This is the
initial open-source release of the JDBC Driver. The source code can be found at the GitHub v6.1.0 tag. It builds
the mssql-jdbc-6.1.0.jre8.jar and mssql-jdbc-6.1.0.jre7.jar files, which correspond to Java version compatibility.

6.0
Download Microsoft JDBC Driver 6.0 for SQL Ser ver (self-extracting exe)
Download Microsoft JDBC Driver 6.0 for SQL Ser ver (tar.gz)
Version number: 6.0.8112
Released: January 17, 2017
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a self-extracting exe file: Chinese (Simplified) | Chinese (Traditional) | English (United States) |
French | German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Microsoft JDBC Driver 6.0 for SQL Server is fully compliant with JDBC specifications 4.1 and 4.2. The jars in the
6.0 package are named according to their compliance with the JDBC API version. For example, the sqljdbc42.jar
file from the 6.0 package is JDBC API 4.2 compliant. Similarly, the sqljdbc41.jar file is compliant with JDBC API
4.1.
To ensure that you have the right sqljdbc42.jar or sqljdbc41.jar file, run the following lines of code. If the output
is "Driver version: 6.0.7507.100", you have the JDBC Driver 6.0 package.

Connection conn = DriverManager.getConnection("jdbc:sqlserver://<server>;user=<user>;password=<password>;");


System.out.println("Driver version: " + conn.getMetaData().getDriverVersion());
Always Encrypted
The driver supports the Always Encrypted feature in SQL Server 2016. This feature ensures that sensitive data is
never seen in plaintext in a SQL Server instance. Always Encrypted works by transparently encrypting the data
in the application, so that SQL Server will handle only the encrypted data and not plaintext values. Even if the
SQL Server instance or the host machine is compromised, all an attacker can get is ciphertext of sensitive data.
For details, see Using Always Encrypted with the JDBC Driver.
Internationalized domain names
The driver supports internationalized domain names (IDNs) for server names. For details, see "Using
International Domain Names" in the International features of the JDBC Driver article.
Parameterized queries
The driver now supports retrieving parameter metadata with prepared statements for complex queries, such as
subqueries and/or joins. Note that this improvement is available only when you're using SQL Server 2012 and
newer versions.
Azure Active Directory
Azure AD authentication is a mechanism of connecting to Azure SQL Database using identities in Azure AD. Use
Azure AD authentication to centrally manage identities of database users and as an alternative to SQL Server
authentication.
You can use JDBC Driver 6.0 to specify your Azure AD credentials in the JDBC connection string to connect to
Azure SQL Database. For details, see the authentication property in the Setting the connection properties article.
Table -valued parameters
TVPs provide an easy way to marshal multiple rows of data from a client application to SQL Server without
requiring multiple round trips or special server-side logic for processing the data. You can use TVPs to
encapsulate rows of data in a client application and send the data to the server in a single parameterized
command. The incoming data rows are stored in a table variable that you can then operate on by using Transact-
SQL. For details, see Using table-valued parameters.
Always On Availability Groups
The driver now supports transparent connections to Always On Availability Groups. The driver quickly discovers
the current Always On topology of your server infrastructure and connects to the current active server
transparently.

4.2
Download Microsoft JDBC Driver 4.2 for SQL Ser ver (self-extracting exe)
Download Microsoft JDBC Driver 4.2 for SQL Ser ver (tar.gz)
Version number: 4.2.8112
Released: August 24, 2015
If you need to download the driver in a language other than the one detected for you, you can use these direct
links.
For the driver in a self-extracting exe file: Chinese (Simplified) | Chinese (Traditional) | English (United States) |
French | German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the driver in a tar.gz file: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French |
German | Italian | Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Microsoft JDBC Driver 4.2 for SQL Server is fully compliant with JDBC specifications 4.1 and 4.2. The jars in the
4.2 package are named according to their compliance with the JDBC API version. For example, the sqljdbc42.jar
file from the 4.2 package is JDBC API 4.2 compliant. Similarly, the sqljdbc41.jar file is compliant with JDBC API
4.1.
To ensure you have the right sqljdbc42.jar or sqljdbc41.jar file, run the following lines of code. If the output is
"Driver version: 4.2.6420.100", you have the JDBC Driver 4.2 package.

Connection conn = DriverManager.getConnection("jdbc:sqlserver://<server>;user=<user>;password=<password>;");


System.out.println("Driver version: " + conn.getMetaData().getDriverVersion());

Support for JDK 8


The driver supports JDK version 8.0 in addition to JDK 7.0, 6.0, and 5.0.
JDBC 4.1 and 4.2 compliance
The driver supports Java Database Connectivity API 4.1 and 4.2 specifications, in addition to 4.0. For details, see
JDBC 4.1 compliance for the JDBC Driver and JDBC 4.2 compliance for the JDBC Driver.
Bulk copy
You use the bulk copy feature to quickly copy large amounts of data into tables or views in SQL Server
databases. For details, see Using bulk copy with the JDBC Driver.
XA transaction rollback option
The driver has new timeout options for existing automatic rollback of unprepared transactions. For details, see
Understanding XA transactions.
New Kerberos principal connection property
The driver uses a new connection property to facilitate flexibility with Kerberos connections. For details, see
Using Kerberos Integrated Authentication to connect to SQL Server.

4.1
Version number: 4.1.8112
Released: December 12, 2014
Support for JDK 7
The driver supports JDK version 7.0 in addition to JDK 6.0 and 5.0.

Itanium not supported for JDBC Driver applications


Microsoft JDBC Driver for SQL Server applications aren't supported to run on an Itanium computer.

See also
Overview of the JDBC Driver
System requirements for the JDBC driver
4/27/2022 • 15 minutes to read • Edit Online

Download JDBC Driver


To use the Microsoft JDBC Driver for SQL Server to access data from a SQL Server or Azure SQL Database, you
must have the following components installed on your computer:
Microsoft JDBC Driver for SQL Server (download)
Java Runtime Environment

Java Runtime Environment requirements


As of Microsoft JDBC Driver 10.2 for SQL Server, Java Development Kit (JDK) 17.0 and Java Runtime
Environment (JRE) 17.0 are supported.
As of Microsoft JDBC Driver 9.4 for SQL Server, Java Development Kit (JDK) 16.0 and Java Runtime Environment
(JRE) 16.0 are supported.
As of Microsoft JDBC Driver 9.2 for SQL Server, Java Development Kit (JDK) 15.0 and Java Runtime Environment
(JRE) 15.0 are supported.
As of Microsoft JDBC Driver 8.4 for SQL Server, Java Development Kit (JDK) 14.0 and Java Runtime Environment
(JRE) 14.0 are supported.
As of Microsoft JDBC Driver 8.2 for SQL Server, Java Development Kit (JDK) 13.0 and Java Runtime Environment
(JRE) 13.0 are supported.
As of Microsoft JDBC Driver 7.4 for SQL Server, Java Development Kit (JDK) 12.0 and Java Runtime Environment
(JRE) 12.0 are supported.
As of Microsoft JDBC Driver 7.2 for SQL Server, Java Development Kit (JDK) 11.0 and Java Runtime Environment
(JRE) 11.0 are supported.
As of Microsoft JDBC Driver 7.0 for SQL Server, Java Development Kit (JDK) 10.0 and Java Runtime Environment
(JRE) 10.0 are supported.
As of Microsoft JDBC Driver 6.4 for SQL Server, Java Development Kit (JDK) 9.0 and Java Runtime Environment
(JRE) 9.0 are supported.
As of Microsoft JDBC Driver 4.2 for SQL Server, Java Development Kit (JDK) 8.0 and Java Runtime Environment
(JRE) 8.0 are supported. Support for JDBC Spec API has been extended to include the JDBC 4.1 and 4.2 API.
As of Microsoft JDBC Driver 4.1 for SQL Server, Java Development Kit (JDK) 7.0 and Java Runtime Environment
(JRE) 7.0 are supported.
As of Microsoft JDBC Driver 4.0 for SQL Server, the JDBC driver support for JDBC Spec API has been extended to
include the JDBC 4.0 API. The JDBC 4.0 API was introduced as part of the Java Development Kit (JDK) 6.0 and
Java Runtime Environment (JRE) 6.0. JDBC 4.0 is a superset of the JDBC 3.0 API.
When you deploy the Microsoft JDBC Driver for SQL Server on Windows and UNIX operating systems, you
must use the installation packages, sqljdbc_<version>_enu.exe, and sqljdbc_<version>_enu.tar.gz, respectively.
For more information about how to deploy the JDBC driver, see Deploying the JDBC driver article.
Microsoft JDBC Driver 10.2 for SQL Ser ver :
The JDBC Driver 10.2 includes three JAR class libraries in each installation package: mssql-jdbc-
10.2.0.jre8.jar , mssql-jdbc-10.2.0.jre11.jar , and mssql-jdbc-10.2.0.jre17.jar .
The JDBC Driver 10.2 is designed to work with, and supports all major Java virtual machines, but is tested only
on OpenJDK 1.8, OpenJDK 11.0, OpenJDK 17.0, Azul Zulu JRE 1.8, Azul Zulu JRE 11.0, and Azul Zulu JRE 17.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers
10.2 for SQL Server:

JDB C VERSIO N REC O M M EN DED JAVA


JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-10.2.0.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 1.8.
Using JRE 1.7 or lower
throws an exception.

mssql-jdbc-10.2.0.jre11.jar 4.3 11 Requires a Java Runtime


Environment (JRE) 11.0.
Using JRE 10.0 or lower
throws an exception.

mssql-jdbc-10.2.0.jre17.jar 4.3 17 Requires a Java Runtime


Environment (JRE) 17.0.
Using JRE 17.0 or lower
throws an exception.

The JDBC Driver 10.2 is available on the Maven Central Repository, and can be added to a Maven project with
the following code in the POM.XML:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>10.2.0.jre11</version>
</dependency>

Microsoft JDBC Driver 9.4 for SQL Ser ver :


The JDBC Driver 9.4 includes three JAR class libraries in each installation package: mssql-jdbc-9.4.1.jre8.jar ,
mssql-jdbc-9.4.1.jre11.jar , and mssql-jdbc-9.4.1.jre16.jar .
The JDBC Driver 9.4 is designed to work with, and supports all major Java virtual machines, but is tested only on
OpenJDK 1.8, OpenJDK 11.0, OpenJDK 16.0, Azul Zulu JRE 1.8, Azul Zulu JRE 11.0, and Azul Zulu JRE 16.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers 9.4
for SQL Server:

JDB C VERSIO N REC O M M EN DED JAVA


JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-9.4.1.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 1.8.
Using JRE 1.7 or lower
throws an exception.
JDB C VERSIO N REC O M M EN DED JAVA
JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-9.4.1.jre11.jar 4.3 11 Requires a Java Runtime


Environment (JRE) 11.0.
Using JRE 10.0 or lower
throws an exception.

mssql-jdbc-9.4.1.jre16.jar 4.3 16 Requires a Java Runtime


Environment (JRE) 16.0.
Using JRE 15.0 or lower
throws an exception.

The JDBC Driver 9.4 is available on the Maven Central Repository and can be added to a Maven project with the
following code in the POM.XML:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.4.1.jre11</version>
</dependency>

Microsoft JDBC Driver 9.2 for SQL Ser ver :


The JDBC Driver 9.2 includes three JAR class libraries in each installation package: mssql-jdbc-9.2.1.jre8.jar ,
mssql-jdbc-9.2.1.jre11.jar , and mssql-jdbc-9.2.1.jre15.jar .
The JDBC Driver 9.2 is designed to work with, and supports all major Java virtual machines, but is tested only on
OpenJDK 1.8, OpenJDK 11.0, OpenJDK 15.0, Azul Zulu JRE 1.8, Azul Zulu JRE 11.0, and Azul Zulu JRE 15.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers 9.2
for SQL Server:

JDB C VERSIO N REC O M M EN DED JAVA


JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-9.2.1.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 1.8.
Using JRE 1.7 or lower
throws an exception.

New Features in 9.2 include:


JDK 15 support, support
for Azure Active Directory
Interactive Authentication,
support for Azure Active
Directory Service Principal
Authentication, and
support for
useBulkCopyForBatchInsert
for non-Azure Synapse
Analytics servers.
JDB C VERSIO N REC O M M EN DED JAVA
JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-9.2.1.jre11.jar 4.3 11 Requires a Java Runtime


Environment (JRE) 11.0.
Using JRE 10.0 or lower
throws an exception.

New Features in 9.2 include:


JDK 15 support, support
for Azure Active Directory
Interactive Authentication,
support for Azure Active
Directory Service Principal
Authentication, and
support for
useBulkCopyForBatchInsert
for non-Azure Synapse
Analytics servers.

mssql-jdbc-9.2.1.jre15.jar 4.3 15 Requires a Java Runtime


Environment (JRE) 15.0.
Using JRE 14.0 or lower
throws an exception.

New Features in 9.2 include:


JDK 15 support, support
for Azure Active Directory
Interactive Authentication,
support for Azure Active
Directory Service Principal
Authentication, and
support for
useBulkCopyForBatchInsert
for non-Azure Synapse
Analytics servers.

The JDBC Driver 9.2 is available on the Maven Central Repository and can be added to a Maven project with the
following code in the POM.XML:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.2.1.jre11</version>
</dependency>

Microsoft JDBC Driver 8.4 for SQL Ser ver :


The JDBC Driver 8.4 includes three JAR class libraries in each installation package: mssql-jdbc-8.4.1.jre8.jar ,
mssql-jdbc-8.4.1.jre11.jar , and mssql-jdbc-8.4.1.jre14.jar .
The JDBC Driver 8.4 is designed to work with, and supports all major Java virtual machines, but is tested only on
OpenJDK 1.8, OpenJDK 11.0, OpenJDK 14.0, Azul Zulu JRE 1.8, Azul Zulu JRE 11.0, and Azul Zulu JRE 14.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers 8.4
for SQL Server:
JDB C VERSIO N REC O M M EN DED JAVA
JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-8.4.1.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 1.8.
Using JRE 1.7 or lower
throws an exception.

New Features in 8.4 include:


JDK 14 support, support
for authentication to Azure
Key Vault using Managed
Identity, extended support
for bulk copy for Azure
Data Warehouse, Azure SQL
DNS caching, support for
backwards compatibility for
streaming LOB objects, and
client certificate
authentication for loopback
scenarios.

mssql-jdbc-8.4.1.jre11.jar 4.3 11 Requires a Java Runtime


Environment (JRE) 11.0.
Using JRE 10.0 or lower
throws an exception.

New Features in 8.4 include:


JDK 14 support, support
for authentication to Azure
Key Vault using Managed
Identity, extended support
for bulk copy for Azure
Data Warehouse, Azure SQL
DNS caching, support for
backwards compatibility for
streaming LOB objects, and
client certificate
authentication for loopback
scenarios.

mssql-jdbc-8.4.1.jre13.jar 4.3 14 Requires a Java Runtime


Environment (JRE) 14.0.
Using JRE 13.0 or lower
throws an exception.

New Features in 8.4 include:


JDK 14 support, support
for authentication to Azure
Key Vault using Managed
Identity, extended support
for bulk copy for Azure
Data Warehouse, Azure SQL
DNS caching, support for
backwards compatibility for
streaming LOB objects, and
client certificate
authentication for loopback
scenarios.

The JDBC Driver 8.4 is available on the Maven Central Repository and can be added to a Maven project with the
following code in the POM.XML:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>8.4.1.jre11</version>
</dependency>

Microsoft JDBC Driver 8.2 for SQL Ser ver :


The JDBC Driver 8.2 includes three JAR class libraries in each installation package: mssql-jdbc-8.2.2.jre8.jar ,
mssql-jdbc-8.2.2.jre11.jar , and mssql-jdbc-8.2.2.jre13.jar .
The JDBC Driver 8.2 is designed to work with, and supports all major Java virtual machines, but is tested only on
OpenJDK 1.8, OpenJDK 11.0, OpenJDK 13.0, Azul Zulu JRE 1.8, Azul Zulu JRE 11.0, and Azul Zulu JRE 13.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers 8.2
for SQL Server:

JDB C VERSIO N REC O M M EN DED JAVA


JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-8.2.2.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 1.8.
Using JRE 1.7 or lower
throws an exception.

New Features in 8.2 include:


JDK 13 support, Always
Encrypted with secure
enclaves, and temporal
datatype performance
improvements.

mssql-jdbc-8.2.2.jre11.jar 4.3 11 Requires a Java Runtime


Environment (JRE) 11.0.
Using JRE 10.0 or lower
throws an exception.

New Features in 8.2 include:


JDK 13 support, Always
Encrypted with secure
enclaves, and temporal
datatype performance
improvements.

mssql-jdbc-8.2.2.jre13.jar 4.3 13 Requires a Java Runtime


Environment (JRE) 13.0.
Using JRE 11.0 or lower
throws an exception.

New Features in 8.2 include:


JDK 13 support, Always
Encrypted with secure
enclaves, and temporal
datatype performance
improvements.

The JDBC Driver 8.2 is available on the Maven Central Repository and can be added to a Maven project with the
following code in the POM.XML:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>8.2.2.jre11</version>
</dependency>

Microsoft JDBC Driver 7.4 for SQL Ser ver :


The JDBC Driver 7.4 includes three JAR class libraries in each installation package: mssql-jdbc-7.4.1.jre8.jar ,
mssql-jdbc-7.4.1.jre11.jar , and mssql-jdbc-7.4.1.jre12.jar .
The JDBC Driver 7.4 is designed to work with, and supports all major Java virtual machines, but is tested only on
OpenJDK 1.8, OpenJDK 11.0, OpenJDK 12.0, Azul Zulu JRE 1.8, Azul Zulu JRE 11.0, and Azul Zulu JRE 12.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers 7.4
for SQL Server:

JDB C VERSIO N REC O M M EN DED JAVA


JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-7.4.1.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 1.8.
Using JRE 1.7 or lower
throws an exception.

New Features in 7.4 include:


JDK 12 support, NTLM
authentication, and
useFmtOnly.

mssql-jdbc-7.4.1.jre11.jar 4.3 11 Requires a Java Runtime


Environment (JRE) 11.0.
Using JRE 10.0 or lower
throws an exception.

New Features in 7.4 include:


JDK 12 support, NTLM
authentication, and
useFmtOnly.

mssql-jdbc-7.4.1.jre12.jar 4.3 12 Requires a Java Runtime


Environment (JRE) 12.0.
Using JRE 11.0 or lower
throws an exception.

New Features in 7.4 include:


JDK 12 support, NTLM
authentication, and
useFmtOnly.

The JDBC Driver 7.4 is available on the Maven Central Repository and can be added to a Maven project with the
following code in the POM.XML:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>7.4.1.jre11</version>
</dependency>
Microsoft JDBC Driver 7.2 for SQL Ser ver :
The JDBC Driver 7.2 includes two JAR class libraries in each installation package: mssql-jdbc-7.2.2.jre8.jar ,
and mssql-jdbc-7.2.2.jre11.jar .
The JDBC Driver 7.2 is designed to work with, and supports all major Java virtual machines, but is tested only on
OpenJDK 8.0, OpenJDK 11.0, Azul Zulu JRE 8.0, and Azul Zulu JRE 11.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers 7.2
for SQL Server:

JDB C VERSIO N REC O M M EN DED JAVA


JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-7.2.2.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 8.0.
Using JRE 7.0 or lower
throws an exception.

New Features in 7.2 include:


JDK 11 support, Active
Directory Managed Identity
(MSI) authentication, OSGi
support, SQLServerError
APIs.

mssql-jdbc-7.2.2.jre11.jar 4.3 10 Requires a Java Runtime


Environment (JRE) 11.0.
Using JRE 10.0 or lower
throws an exception.

New Features in 7.2 include:


JDK 11 support, Active
Directory Managed Identity
(MSI) authentication, OSGi
support, SQLServerError
APIs.

The JDBC Driver 7.2 is available on the Maven Central Repository and can be added to a Maven project with the
following code in the POM.XML:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>7.2.2.jre11</version>
</dependency>

Microsoft JDBC Driver 7.0 for SQL Ser ver :


The JDBC Driver 7.0 includes two JAR class libraries in each installation package: mssql-jdbc-7.0.0.jre8.jar ,
and mssql-jdbc-7.0.0.jre10.jar .
The JDBC Driver 7.0 is designed to work with, and supports all major Java virtual machines, but is tested only on
OpenJDK 8.0, and 10.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers 7.0
for SQL Server:
JDB C VERSIO N REC O M M EN DED JAVA
JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-7.0.0.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 8.0.
Using JRE 7.0 or lower
throws an exception.

New Features in 7.0 include:


JDK 10 support, updated
default compliance level to
JDBC 4.2 specifications,
Spatial Datatypes support,
cancelQueryTimeout
connection property,
Request Boundary
methods,
useBulkCopyForBatchInsert
connection property, Data
Discovery and Classification
information, UTF-8 feature
extension, and CityHash
support.

mssql-jdbc-7.0.0.jre10.jar 4.3 10 Requires a Java Runtime


Environment (JRE) 10.0.
Using JRE 9.0 or lower
throws an exception.

New Features in 7.0 include:


JDK 10 support, updated
default compliance level to
JDBC 4.2 specifications,
Spatial Datatypes support,
cancelQueryTimeout
connection property,
Request Boundary
methods,
useBulkCopyForBatchInsert
connection property, Data
Discovery and Classification
information, UTF-8 feature
extension, and CityHash
support.

The JDBC Driver 7.0 is available on the Maven Central Repository and can be added to a Maven project with the
following code in the POM.XML:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>7.0.0.jre10</version>
</dependency>

Microsoft JDBC Driver 6.4 for SQL Ser ver :


The JDBC Driver 6.4 includes three JAR class libraries in each installation package: mssql-jdbc-6.4.0.jre7.jar ,
mssql-jdbc-6.4.0.jre8.jar , and mssql-jdbc-6.4.0.jre9.jar .
The JDBC Driver 6.4 is designed to work with, and supports all major Java virtual machines, but is tested only on
OpenJDK 7.0, 8.0, and 9.0.
The following chart summarizes support provided by the three JAR files included with Microsoft JDBC Drivers
6.4 for SQL Server:

JDB C VERSIO N REC O M M EN DED JAVA


JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-6.4.0.jre7.jar 4.1 7 Requires a Java Runtime


Environment (JRE) 7.0.
Using JRE 6.0 or lower
throws an exception.

New Features in 6.4 include:


Azure AD authentication for
Linux, Principal/Password
method for Kerberos,
automatic detection of
REALM in SPN for Cross-
Domain authentication,
Kerberos Constrained
Delegation, Query Timeout,
Socket Timeout, and
prepared statement handle
reuse.

mssql-jdbc-6.4.0.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 8.0.
Using JRE 7.0 or lower
throws an exception.

New Features in 6.4 include:


Azure AD authentication for
Linux, Principal/Password
method for Kerberos,
automatic detection of
REALM in SPN for Cross-
Domain authentication,
Kerberos Constrained
Delegation, Query Timeout,
Socket Timeout, and
prepared statement handle
reuse.

mssql-jdbc-6.4.0.jre9.jar 4.3 9 Requires a Java Runtime


Environment (JRE) 9.0.
Using JRE 8.0 or lower
throws an exception.

New Features in 6.4 include:


Azure AD authentication for
Linux, Principal/Password
method for Kerberos,
automatic detection of
REALM in SPN for Cross-
Domain authentication,
Kerberos Constrained
Delegation, Query Timeout,
Socket Timeout, and
prepared statement handle
reuse.

The JDBC Driver 6.4 is available on the Maven Central Repository and can be added to a Maven project with the
following code in the POM.XML
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.4.0.jre9</version>
</dependency>

Microsoft JDBC Driver 6.2 for SQL Ser ver :


The JDBC Driver 6.2 includes two JAR class libraries in each installation package: mssql-jdbc-6.2.2.jre7.jar ,
and mssql-jdbc-6.2.2.jre8.jar .
The JDBC Driver 6.2 is designed to work with, and supports all major Java virtual machines, but is tested only on
Sun JRE 5.0, 6.0, 7.0, and 8.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers 6.0
and 4.2 for SQL Server:

JDB C VERSIO N REC O M M EN DED JAVA


JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

mssql-jdbc-6.2.2.jre7.jar 4.1 7 Requires a Java Runtime


Environment (JRE) 7.0.
Using JRE 6.0 or lower
throws an exception.

New Features in 6.2 include:


Azure AD authentication for
Linux, Principal/Password
method for Kerberos,
automatic detection of
REALM in SPN for Cross-
Domain authentication,
Kerberos Constrained
Delegation, Query Timeout,
Socket Timeout, and
prepared statement handle
reuse.

mssql-jdbc-6.2.3.jre8.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 8.0.
Using JRE 7.0 or lower
throws an exception.

New Features in 6.2 include:


Azure AD authentication for
Linux, Principal/Password
method for Kerberos,
automatic detection of
REALM in SPN for Cross-
Domain authentication,
Kerberos Constrained
Delegation, Query Timeout,
Socket Timeout, and
prepared statement handle
reuse

The JDBC Driver 6.2 is available on the Maven Central Repository and can be added to a Maven project with the
following code in the POM.XML
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.2.2.jre8</version>
</dependency>

Microsoft JDBC Driver 6.0 and 4.2 for SQL Ser ver :
The JDBC Drivers 6.0 and 4.2 include two JAR class libraries in each installation package: sqljdbc41.jar , and
sqljdbc42.jar .
The JDBC Drivers 6.0 and 4.2 are designed to work with, and supports all major Java virtual machines, but is
tested only on Sun JRE 5.0, 6.0, 7.0, and 8.0.
The following chart summarizes support provided by the two JAR files included with Microsoft JDBC Drivers 6.0
and 4.2 for SQL Server:

JDB C VERSIO N REC O M M EN DED JAVA


JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

sqljdbc41.jar 4.1 7 Requires a Java Runtime


Environment (JRE) 7.0.
Using JRE 6.0 or lower
throws an exception.

New Features in 6.0 & 4.2


packages include: JDBC 4.1
Compliance and Bulk Copy

In Addition, new Features in


only the 6.0 package
include: Always Encrypted,
Table-Valued Parameters,
Azure Active Directory
Authentication, transparent
connections to Always On
Availability Groups,
improvement in parameter
metadata retrieval for
prepared queries and
Internationalized Domain
Name (IDN)
JDB C VERSIO N REC O M M EN DED JAVA
JA R C O M P L IA N C E VERSIO N DESC RIP T IO N

sqljdbc42.jar 4.2 8 Requires a Java Runtime


Environment (JRE) 8.0.
Using JRE 7.0 or lower
throws an exception.

New Features in 6.0 & 4.2


packages include: JDBC 4.1
Compliance, JDBC 4.2
Compliance, and Bulk Copy

In Addition, new Features in


only the 6.0 package
include: Always Encrypted,
Table-Valued Parameters,
Azure Active Directory
Authentication, transparent
connections to Always On
Availability Groups,
improvement in parameter
metadata retrieval for
prepared queries and
Internationalized Domain
Name (IDN)

Microsoft JDBC Driver 4.1 for SQL Ser ver :


The JDBC Driver 4.1 includes one JAR class library in each installation package: sqljdbc41.jar .

JA R DESC RIP T IO N

sqljdbc41.jar sqljdbc41.jar class library provides support for JDBC 4.0


API. It includes all of the features of the JDBC 4.0 driver and
the JDBC 4.0 API methods. JDBC 4.1 isn't supported (throws
an exception "SQLFeatureNotSupportedException").

sqljdbc41.jar class library requires a Java Runtime


Environment (JRE) 7.0. Using sqljdbc41.jar on JRE 6.0 and
5.0 throws an exception.

The JDBC driver is designed to work with, and supports all major Java virtual machines, but is tested on Sun JRE
5.0, 6.0 and 7.0.
The following chart summarizes support provided by the JAR file included with Microsoft JDBC Driver 4.1 for
SQL Server.

JA R JDB C VERSIO N JRE ( C A N RUN ) JDK ( C A N C O M P IL E)

sqljdbc41.jar 4 7 765

SQL Server requirements


The JDBC driver supports connections to Azure SQL database and SQL Server. For Microsoft JDBC Driver 4.2
and 4.1 for SQL Server, support begins with SQL Server 2008.

Operating System requirements


The JDBC driver is designed to work on any operating system that supports the use of a Java Virtual Machine
(JVM). However, only Sun Solaris, SUSE Linux, Ubuntu Linux, CentOS Linux, macOS, and Windows operating
systems have officially been tested.

Supported languages
The JDBC driver supports all SQL Server column collations. For more information about the collations
supported by the JDBC driver, see International features of the JDBC driver.
For more information about collations, see "Working with Collations" in SQL Server Books Online.

See also
Overview of the JDBC driver
Microsoft JDBC Driver for SQL Server support
matrix
4/27/2022 • 5 minutes to read • Edit Online

Download JDBC Driver


This page contains the support matrix and support lifecycle policy for the Microsoft JDBC Driver for SQL Server.

Microsoft JDBC Driver support lifecycle matrix and policy


The Microsoft Support Lifecycle (MSL) policy provides transparent, predictable information regarding the
support lifecycle of Microsoft products. JDBC driver versions 4.x, 6.x, 7.x, 8.x, 9.x, and 10.x have five-year
Mainstream support from the driver release date. Mainstream support is defined on the Microsoft support
lifecycle website.
Extended and custom support options are not available for the Microsoft JDBC Driver.
The following Microsoft JDBC Drivers are supported, until the indicated End of Support date.

EN D O F M A IN ST REA M
DRIVER N A M E DRIVER PA C K A GE VERSIO N A P P L IC A B L E JA R( S) SUP P O RT

Microsoft JDBC Driver 10.2 10.2 mssql-jdbc-10.2.0.jre17.jar January 31, 2027


for SQL Server mssql-jdbc-10.2.0.jre11.jar
mssql-jdbc-10.2.0.jre8.jar

Microsoft JDBC Driver 9.4 9.4 mssql-jdbc-9.4.1.jre16.jar July 30, 2026


for SQL Server mssql-jdbc-9.4.1.jre11.jar
mssql-jdbc-9.4.1.jre8.jar

Microsoft JDBC Driver 9.2 9.2 mssql-jdbc-9.2.1.jre15.jar January 29, 2026


for SQL Server mssql-jdbc-9.2.1.jre11.jar
mssql-jdbc-9.2.1.jre8.jar

Microsoft JDBC Driver 8.4 8.4 mssql-jdbc-8.4.1.jre14.jar July 31, 2025


for SQL Server mssql-jdbc-8.4.1.jre11.jar
mssql-jdbc-8.4.1.jre8.jar

Microsoft JDBC Driver 8.2 8.2 mssql-jdbc-8.2.2.jre13.jar January 31, 2025


for SQL Server mssql-jdbc-8.2.2.jre11.jar
mssql-jdbc-8.2.2.jre8.jar

Microsoft JDBC Driver 7.4 7.4 mssql-jdbc-7.4.1.jre12.jar July 31, 2024


for SQL Server mssql-jdbc-7.4.1.jre11.jar
mssql-jdbc-7.4.1.jre8.jar

Microsoft JDBC Driver 7.2 7.2 mssql-jdbc-7.2.2.jre11.jar January 31, 2024


for SQL Server mssql-jdbc-7.2.2.jre8.jar

Microsoft JDBC Driver 7.0 7.0 mssql-jdbc-7.0.0.jre10.jar July 31, 2023


for SQL Server mssql-jdbc-7.0.0.jre8.jar
EN D O F M A IN ST REA M
DRIVER N A M E DRIVER PA C K A GE VERSIO N A P P L IC A B L E JA R( S) SUP P O RT

Microsoft JDBC Driver 6.4 6.4 mssql-jdbc-6.4.0.jre9.jar February 27, 2023


for SQL Server mssql-jdbc-6.4.0.jre8.jar
mssql-jdbc-6.4.0.jre7.jar

Microsoft JDBC Driver 6.2 6.2 mssql-jdbc-6.2.2.jre8.jar June 30, 2022


for SQL Server mssql-jdbc-6.2.2.jre7.jar

The following Microsoft JDBC Drivers are no longer supported.

DRIVER N A M E DRIVER PA C K A GE VERSIO N EN D O F M A IN ST REA M SUP P O RT

Microsoft JDBC Driver 6.0 for SQL 6.0 July 14, 2021
Server

Microsoft JDBC Driver 4.2 for SQL 4.2 August 24, 2020
Server

Microsoft JDBC Driver 4.1 for SQL 4.1 December 12, 2019
Server

Microsoft JDBC Driver 4.0 for SQL 4.0 March 6, 2017


Server

Microsoft SQL Server JDBC Driver 3.0 3.0 April 23, 2015

Microsoft SQL Server JDBC Driver 2.0 2.0 December 31, 2012

Microsoft SQL Server 2005 JDBC 1.2 June 25, 2011


Driver 1.2

Microsoft SQL Server 2005 JDBC 1.1 June 25, 2011


Driver 1.1

Microsoft SQL Server 2005 JDBC 1.0 June 25, 2011


Driver 1.0

Microsoft SQL Server 2000 JDBC 2000 July 9, 2010


Driver

SQL version compatibility


DATA
B A SE
VERSI
ON → A Z UR A Z UR
↓ E E SQ L SQ L
DRIVE A Z UR SY N A MAN SQ L SQ L SQ L SQ L SQ L P DW SERVE SQ L
R E SQ L P SE A GED SERVE SERVE SERVE SERVE SERVE 2008R R SERVE
VERSI DATA ANAL IN STA R R R R R 2 2008 R
ON B A SE Y T IC S NCE 2019 2017 2016 2014 2012 A U3 4 R2 2008

10.2 Yes Yes Yes Yes Yes Yes Yes Yes

9.4 Yes Yes Yes Yes Yes Yes Yes Yes


DATA
B A SE
VERSI
ON → A Z UR A Z UR
↓ E E SQ L SQ L
DRIVE A Z UR SY N A MAN SQ L SQ L SQ L SQ L SQ L P DW SERVE SQ L
R E SQ L P SE A GED SERVE SERVE SERVE SERVE SERVE 2008R R SERVE
VERSI DATA ANAL IN STA R R R R R 2 2008 R
ON B A SE Y T IC S NCE 2019 2017 2016 2014 2012 A U3 R2 2008

9.2 Yes Yes Yes Yes Yes Yes Yes Yes

8.4 Yes Yes Yes Yes Yes Yes Yes Yes Yes

8.2 Yes Yes Yes Yes Yes Yes Yes Yes Yes

7.4 Yes Yes Yes Yes Yes Yes Yes Yes Yes

7.2 Yes Yes Yes Yes Yes Yes Yes Yes Yes

7.0 Yes Yes Yes Yes Yes Yes Yes Yes Yes

6.4 Yes Yes Yes Yes Yes Yes Yes Yes Yes

6.2 Yes Yes Yes Yes Yes Yes Yes Yes Yes

6.1 Yes Yes Yes Yes Yes Yes Yes

6.0 Yes Yes Yes Yes Yes Yes Yes

4.2 Yes Yes Yes Yes Yes Yes Yes

4.1 Yes Yes Yes Yes Yes Yes Yes

4.0 Yes Yes Yes Yes Yes Yes Yes

3.0 Yes2 Yes5 Yes1 Yes Yes

2.0 Yes3 Yes3

1.2 Yes3

1 Microsoft SQL Server JDBC Driver version 3.0 can connect to SQL Server 2012 as a down-level client.
2 Support forAzure SQL Database was introduced in the 3.0 driver as a hotfix. We recommend that Azure SQL
Database customers use the latest driver version available.
3 Microsoft SQL Server JDBC Driver version 2.0 and Microsoft SQL Server 2005 JDBC Driver version 1.2 can
connect to SQL Server 2008 as a down-level client. When down-level conversions are allowed, applications can
execute queries and perform updates on the new SQL Server 2008 data types, such as time, date, datetime2,
datetimeoffset, and FILESTREAM. For more information about how to use these new data types with the JDBC
driver, see Working with SQL Server 2008 Date/Time Data Types using JDBC Driver and Working with SQL
Server 2008 FileStream using JDBC Driver. For more information about the down-level compatibility of these
new data types, see Using Date and Time Dataand FILESTREAM Support topics in SQL Server Books Online.
4 Support for connections between the Microsoft JDBC Driver and Parallel Data Warehouse was first introduced
in the Microsoft JDBC Driver 4.0 for SQL Server and Microsoft SQL Server 2008 R2 Parallel Data Warehouse
Appliance Update 3.
5 Microsoft SQL Server JDBC Driver version 3.0 can connect to SQL Server 2014 as a down-level client.

Java and JDBC specification support


JDB C DRIVER VERSIO N JRE VERSIO N S JDB C A P I VERSIO N

10.2 1.8, 11, 17 4.2, 4.3 (partially)

9.4 1.8, 11, 16 4.2, 4.3 (partially)

9.2 1.8, 11, 15 4.2, 4.3 (partially)

8.4 1.8, 11, 14 4.2, 4.3 (partially)

8.2 1.8, 11, 13 4.2, 4.3 (partially)

7.4 1.8, 11, 12 4.2, 4.3 (partially)

7.2 1.8, 11 4.2, 4.3 (partially)

7.0 1.8, 10 4.2, 4.3 (partially)

6.4 1.7, 1.8, 9 4.1, 4.2, 4.3 (partially)

6.2 1.7, 1.8 4.1, 4.2

6.1 1.7, 1.8 4.1, 4.2

6.0 1.7, 1.8 4.1, 4.2

4.2 1.7, 1.8 4.1, 4.2

4.1 1.7 4.0

4.0 1.5, 1.6, 1.7 3.0, 4.0

3.0 1.5, 1.6, 3.0, 4.0

2.0 1.5, 1.6 3.0, 4.0

1.2 1.4, 1.5, 1.6 3.0

1.1 1.4 3.0

1.0 1.4 3.0

2000 1.4 3.0

Supported operating systems


The Microsoft JDBC driver is designed to work on any operating system that supports the use of a Java Virtual
Machine (JVM). Some commonly used platforms include Windows 10, Windows 8.1, Windows 8, Windows 7,
Windows Server 2008 R2, Linux, Unix, AIX, macOS, and others.
The JDBC product team tests our driver on Windows, Sun Solaris, SUSE Linux, Ubuntu Linux, CentOS Linux, and
macOS.

Application server support


The Microsoft JDBC Driver for SQL Server is tested with various application servers. Consult your application
server vendor for additional details on which driver version is compatible with their product.
Using the JDBC driver
4/27/2022 • 10 minutes to read • Edit Online

Download JDBC Driver


This section provides quickstart instructions to make a simple connection to a SQL Server database using the
Microsoft JDBC Driver for SQL Server. Before you connect to a SQL Server database, SQL Server must first be
installed on either your local computer or a server, and the JDBC driver must be installed on your local
computer.

Choose the right JAR file


The Microsoft JDBC Driver provides different Jars to be used in correspondence with your preferred Java
Runtime Environment (JRE) settings, as under:
The Microsoft JDBC Driver 10.2 for SQL Server provides mssql-jdbc-10.2.0.jre8.jar , mssql-jdbc-
10.2.0.jre11.jar , and mssql-jdbc-10.2.0.jre17.jar class library files.
The Microsoft JDBC Driver 9.4 for SQL Server provides mssql-jdbc-9.4.1.jre8.jar , mssql-jdbc-
9.4.1.jre11.jar , and mssql-jdbc-9.4.1.jre16.jar class library files.
The Microsoft JDBC Driver 9.2 for SQL Server provides mssql-jdbc-9.2.1.jre8.jar , mssql-jdbc-
9.2.1.jre11.jar , and mssql-jdbc-9.2.1.jre15.jar class library files.
The Microsoft JDBC Driver 8.4 for SQL Server provides mssql-jdbc-8.4.1.jre8.jar , mssql-jdbc-
8.4.1.jre11.jar , and mssql-jdbc-8.4.1.jre14.jar class library files.
The Microsoft JDBC Driver 8.2 for SQL Server provides mssql-jdbc-8.2.2.jre8.jar , mssql-jdbc-
8.2.2.jre11.jar , and mssql-jdbc-8.2.2.jre13.jar class library files.
The Microsoft JDBC Driver 7.4 for SQL Server provides mssql-jdbc-7.4.1.jre8.jar , mssql-jdbc-
7.4.1.jre11.jar , and mssql-jdbc-7.4.1.jre12.jar class library files.
The Microsoft JDBC Driver 7.2 for SQL Server provides mssql-jdbc-7.2.2.jre8.jar , and mssql-jdbc-
7.2.2.jre11.jar class library files.
The Microsoft JDBC Driver 7.0 for SQL Server provides mssql-jdbc-7.0.0.jre8.jar , and mssql-jdbc-
7.0.0.jre10.jar class library files.
The Microsoft JDBC Driver 6.4 for SQL Server provides mssql-jdbc-6.4.0.jre7.jar , mssql-jdbc-6.4.0.jre8.jar ,
and mssql-jdbc-6.4.0.jre9.jar class library files.
The Microsoft JDBC Driver 6.2 for SQL Server provides mssql-jdbc-6.2.2.jre7.jar , and mssql-jdbc-
6.2.2.jre8.jar class library files.
The Microsoft JDBC Drivers 6.0 and 4.2 for SQL Server provide sqljdbc41.jar , and sqljdbc42.jar class library
files.
The Microsoft JDBC Driver 4.1 for SQL Server provides the sqljdbc41.jar class library file.
Your choice will determines the available features. For more information about which JAR file to choose, see
System requirements for the JDBC driver.

Setting the classpath


The Microsoft JDBC driver jars aren't part of the Java SDK and must be included in Classpath of user application.
If using JDBC Driver 10.2, set the classpath to include the mssql-jdbc-10.2.0.jre8.jar , mssql-jdbc-
10.2.0.jre11.jar , or mssql-jdbc-10.2.0.jre17.jar .
If using JDBC Driver 9.4, set the classpath to include the mssql-jdbc-9.4.1.jre8.jar , mssql-jdbc-
9.4.1.jre11.jar , or mssql-jdbc-9.4.1.jre16.jar .
If using JDBC Driver 9.2, set the classpath to include the mssql-jdbc-9.2.1.jre8.jar , mssql-jdbc-
9.2.1.jre11.jar , or mssql-jdbc-9.2.1.jre15.jar .
If using JDBC Driver 8.4, set the classpath to include the mssql-jdbc-8.4.1.jre8.jar , mssql-jdbc-
8.4.1.jre11.jar , or mssql-jdbc-8.4.1.jre14.jar .
If using JDBC Driver 8.2, set the classpath to include the mssql-jdbc-8.2.2.jre8.jar , mssql-jdbc-
8.2.2.jre11.jar , or mssql-jdbc-8.2.2.jre13.jar .
If using JDBC Driver 7.4, set the classpath to include the mssql-jdbc-7.4.1.jre8.jar , mssql-jdbc-
7.4.1.jre11.jar , or mssql-jdbc-7.4.1.jre12.jar .
If using JDBC Driver 7.2, set the classpath to include the mssql-jdbc-7.2.2.jre8.jar or mssql-jdbc-
7.2.2.jre11.jar .
If using JDBC Driver 7.0, set the classpath to include the mssql-jdbc-7.0.0.jre8.jar or mssql-jdbc-
7.0.0.jre10.jar .
If using JDBC Driver 6.4, set the classpath to include the mssql-jdbc-6.4.0.jre7.jar , mssql-jdbc-
6.4.0.jre8.jar , or mssql-jdbc-6.4.0.jre9.jar .
If using JDBC Driver 6.2, set the classpath to include the mssql-jdbc-6.2.2.jre7.jar or mssql-jdbc-
6.2.2.jre8.jar .
If using JDBC Driver 4.1 or 4.2, set the classpath to include sqljdbc41.jar or sqljdbc42.jar file from the
respective driver download.
If the classpath is missing an entry for the right Jar file, an application will throw the common Class not found
exception.
For Microsoft JDBC Driver 10.2
The mssql-jdbc-10.2.0.jre8.jar , mssql-jdbc-10.2.0.jre11.jar , or mssql-jdbc-10.2.0.jre17.jar files are
installed in the following locations:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-10.2.0.jre8.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-10.2.0.jre11.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-10.2.0.jre17.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 10.2 for SQL Server\sqljdbc_10.2\enu\mssql-jdbc-
10.2.0.jre11.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_10.2/enu/mssql-jdbc-10.2.0.jre11.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-10.2.0.jre8.jar , mssql-jdbc-10.2.0.jre11.jar , or mssql-jdbc-10.2.0.jre17.jar .
For Microsoft JDBC Driver 9.4
The mssql-jdbc-9.4.1.jre8.jar , mssql-jdbc-9.4.1.jre11.jar , or mssql-jdbc-9.4.1.jre16.jar files are installed
in the following locations:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-9.4.1.jre8.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-9.4.1.jre11.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-9.4.1.jre16.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 9.4 for SQL Server\sqljdbc_9.4\enu\mssql-jdbc-
9.4.1.jre11.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_9.4/enu/mssql-jdbc-9.4.1.jre11.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-9.4.1.jre8.jar , mssql-jdbc-9.4.1.jre11.jar , or mssql-jdbc-9.4.1.jre16.jar .
For Microsoft JDBC Driver 9.2
The mssql-jdbc-9.2.1.jre8.jar , mssql-jdbc-9.2.1.jre11.jar , or mssql-jdbc-9.2.1.jre15.jar files are installed
in the following locations:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-9.2.1.jre8.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-9.2.1.jre11.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-9.2.1.jre15.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 9.2 for SQL Server\sqljdbc_9.2\enu\mssql-jdbc-
9.2.1.jre11.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_9.2/enu/mssql-jdbc-9.2.1.jre11.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-9.2.1.jre8.jar , mssql-jdbc-9.2.1.jre11.jar , or mssql-jdbc-9.2.1.jre15.jar .
For Microsoft JDBC Driver 8.4
The mssql-jdbc-8.4.1.jre8.jar , mssql-jdbc-8.4.1.jre11.jar , or mssql-jdbc-8.4.1.jre14.jar files are installed
in the following locations:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-8.4.1.jre8.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-8.4.1.jre11.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-8.4.1.jre14.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 8.4 for SQL Server\sqljdbc_8.4\enu\mssql-jdbc-
8.4.1.jre11.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_8.4/enu/mssql-jdbc-8.4.1.jre11.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-8.4.1.jre8.jar , mssql-jdbc-8.4.1.jre11.jar , or mssql-jdbc-8.4.1.jre14.jar .
For Microsoft JDBC Driver 8.2
The mssql-jdbc-8.2.2.jre8.jar , mssql-jdbc-8.2.2.jre11.jar , or mssql-jdbc-8.2.2.jre13.jar files are installed
in the following locations:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-8.2.2.jre8.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-8.2.2.jre11.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-8.2.2.jre13.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 8.2 for SQL Server\sqljdbc_8.2\enu\mssql-jdbc-
8.2.2.jre11.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_8.2/enu/mssql-jdbc-8.2.2.jre11.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-8.2.2.jre8.jar , mssql-jdbc-8.2.2.jre11.jar , or mssql-jdbc-8.2.2.jre13.jar .
For Microsoft JDBC Driver 7.4
The mssql-jdbc-7.4.1.jre8.jar , mssql-jdbc-7.4.1.jre11.jar , or mssql-jdbc-7.4.1.jre12.jar files are installed
in the following locations:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-7.4.1.jre8.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-7.4.1.jre11.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-7.4.1.jre12.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 7.4 for SQL Server\sqljdbc_7.4\enu\mssql-jdbc-
7.4.1.jre11.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_7.4/enu/mssql-jdbc-7.4.1.jre11.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-7.4.1.jre8.jar , mssql-jdbc-7.4.1.jre11.jar , or mssql-jdbc-7.4.1.jre12.jar .
For Microsoft JDBC Driver 7.2
The mssql-jdbc-7.2.2.jre8.jar or mssql-jdbc-7.2.2.jre11.jar files are installed in the following locations:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-7.2.2.jre8.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-7.2.2.jre11.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 7.2 for SQL Server\sqljdbc_7.2\enu\mssql-jdbc-
7.2.2.jre11.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_7.2/enu/mssql-jdbc-7.2.2.jre11.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-7.2.2.jre8.jar or mssql-jdbc-7.2.2.jre11.jar .
For Microsoft JDBC Driver 7.0
The mssql-jdbc-7.0.0.jre8.jar or mssql-jdbc-7.0.0.jre10.jar files are installed in the following locations:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-7.0.0.jre8.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-7.0.0.jre10.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 7.0 for SQL Server\sqljdbc_7.0\enu\mssql-jdbc-
7.0.0.jre10.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_7.0/enu/mssql-jdbc-7.0.0.jre10.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-7.0.0.jre8.jar or mssql-jdbc-7.0.0.jre10.jar .
For Microsoft JDBC Driver 6.4
The mssql-jdbc-6.4.0.jre7.jar , **mssql-jdbc-6.4.0.jre8.jar, or mssql-jdbc-6.4.0.jre9.jar files are installed in
the following location:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-6.4.0.jre7.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-6.4.0.jre8.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-6.4.0.jre9.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 6.4 for SQL Server\sqljdbc_6.4\enu\mssql-jdbc-
6.4.0.jre9.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_6.4/enu/mssql-jdbc-6.4.0.jre9.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-6.4.0.jre7.jar , **mssql-jdbc-6.4.0.jre8.jar, or mssql-jdbc-6.4.0.jre9.jar .
For Microsoft JDBC Driver 6.2
The mssql-jdbc-6.2.2.jre7.jar or mssql-jdbc-6.2.2.jre8.jar files are installed in the following locations:

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-6.2.2.jre7.jar

\<installation directory>\sqljdbc_<version>\<language>\mssql-jdbc-6.2.2.jre8.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 6.2 for SQL Server\sqljdbc_6.2\enu\mssql-jdbc-
6.2.2.jre8.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_6.2/enu/mssql-jdbc-6.2.2.jre8.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either mssql-jdbc-6.2.2.jre7.jar or mssql-jdbc-6.2.2.jre8.jar.
For Microsoft JDBC Driver 4.1, 4.2, and 6.0
The sqljdbc.jar file, sqljdbc4.jar file, sqljdbc41.jar, or sqljdbc42.jar file are installed in the following location:

\<installation directory>\sqljdbc_<version>\<language>\sqljdbc.jar

\<installation directory>\sqljdbc_<version>\<language>\sqljdbc4.jar

\<installation directory>\sqljdbc_<version>\<language>\sqljdbc41.jar

\<installation directory>\sqljdbc_<version>\<language>\sqljdbc42.jar

The following snippet is an example of the CLASSPATH statement that is used for a Windows application:
CLASSPATH =.;C:\Program Files\Microsoft JDBC Driver 6.0 for SQL Server\sqljdbc_4.2\enu\sqljdbc42.jar

The following snippet is an example of the CLASSPATH statement that is used for a Unix/Linux application:
CLASSPATH =.:/home/usr1/mssqlserverjdbc/Driver/sqljdbc_4.2/enu/sqljdbc42.jar

Make sure that the CLASSPATH statement contains only one Microsoft JDBC Driver for SQL Server, such as
either sqljdbc.jar, sqljdbc4.jar, sqljdbc41.jar, or sqljdbc42.jar.

NOTE
On Windows systems, directory names longer than the 8.3 filename convention or folder names with spaces may cause
problems with classpaths. If you suspect these types of issues, you should temporarily move the sqljdbc.jar file,
sqljdbc4.jar file, or the sqljdbc41.jar file into a simple directory name such as C:\Temp , change the classpath, and
determine whether that addresses the problem.

Applications that are run directly at the command prompt


The classpath is configured in the operating system. Append sqljdbc.jar, sqljdbc4.jar, or sqljdbc41.jar to the
classpath of the system. Alternatively, you can specify the classpath on the Java command line that runs the
application with the java -classpath option.
Applications that run in an IDE
Each IDE vendor provides a different method to set the classpath in its IDE. Just setting the classpath in the
operating system won't work. You must add sqljdbc.jar, sqljdbc4.jar, or sqljdbc41.jar to the IDE classpath.
Servlets and JSPs
Servlets and JSPs are run in a servlet/JSP engine such as Tomcat. The classpath must be set according to the
servlet/JSP engine documentation. Just setting the classpath in the operating system won't work. Some
servlet/JSP engines provide setup screens that you can use to set the classpath of the engine. In that situation,
you must append the correct JDBC Driver JAR file to the existing engine classpath and restart the engine. In
other situations, you can deploy the driver by copying sqljdbc.jar, sqljdbc4.jar, or sqljdbc41.jar to a specific
directory, such as lib, during engine installation. The engine driver classpath can also be specified in an engine-
specific configuration file.
Enterprise Java Beans
Enterprise Java Beans (EJB) are run in an EJB container. EJB containers are sourced from various vendors. Java
applets run in a browser but are downloaded from a web server. Copy sqljdbc.jar, sqljdbc4.jar, or sqljdbc41.jar to
the web server root and specify the name of the JAR file in the HTML archive tab of the applet, for example,
<applet ... archive=mssql-jdbc-***.jar> .

Make a simple connection to a database


To use the sqljdbc.jar class library, applications must first register the driver as follows:
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

When the driver is loaded, you can establish a connection with a connection URL and the getConnection method
of the DriverManager class:

String connectionUrl =
"jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks;user=MyUserName;password=*****;";
Connection con = DriverManager.getConnection(connectionUrl);

Starting from JDBC API 4.0, the DriverManager.getConnection() method is enhanced to load JDBC drivers
automatically. Therefore, applications don't need to call the Class.forName method to register or load the driver
when using driver jar libraries.
When the getConnection method of the DriverManager class is called, an appropriate driver is located from the
set of registered JDBC drivers. sqljdbc4.jar, sqljdbc41.jar, or sqljdbc42.jar file includes "META-
INF/services/java.sql.Driver" file, which contains the com.microsoft.sqlser ver.jdbc.SQLSer verDriver as a
registered driver. The existing applications, which currently load the drivers by using the Class.forName method,
will continue to work without modification.

NOTE
sqljdbc4.jar, sqljdbc41.jar, or sqljdbc42.jar class library cannot be used with older versions of the Java Runtime
Environment (JRE). See System requirements for the JDBC driver for the list of JRE versions supported by the Microsoft
JDBC Driver for SQL Server.

For more information about how to connect with data sources and use a connection URL, see Building the
connection URL and Setting the connection properties.

See also
Overview of the JDBC driver
Parsing the results
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This article describes how SQL Server expects users to fully process results returned from any query.

Update counts and result sets


This section will talk about the two most common results returned from SQL Server: Update Count and
ResultSet. In general, any query a user executes will cause one or more of these results to be returned. Users are
expected to handle both when processing results.
The following code is an example of how a user could iterate through all results from the server:

try (Connection connection = DriverManager.getConnection(URL); Statement statement =


connection.createStatement()) {
boolean resultsAvailable = statement.execute(USER_SQL);
int updateCount = -2;
while (true) {
updateCount = statement.getUpdateCount();
if (!resultsAvailable && updateCount == -1)
break;
if (resultsAvailable) {
// handle ResultSet
} else {
// handle Update Count
}
resultsAvailable = statement.getMoreResults();
}
}

Exceptions
When you execute a statement that results in an error or an informational message, SQL Server can respond
differently. For example, if it can't generate an execution plan, the error message will be thrown immediately on
execute() . If an error is related to statement processing, the application needs to parse the result set to see the
exception.
When SQL Server is unable to generate an execution plan, the exception is thrown immediately.

String SQL = "SELECT * FROM nonexistentTable;";


try (Statement statement = connection.createStatement();) {
statement.execute(SQL);
} catch (SQLException e) {
e.printStackTrace();
}

When SQL Server returns an error message in a result set, the result set needs to be processed to retrieve the
exception.
String SQL = "SELECT 1/0;";
try (Statement statement = connection.createStatement();) {
boolean hasResult = statement.execute(SQL);
if (hasResult) {
try (ResultSet rs = statement.getResultSet()) {
// Exception is thrown on next().
while (rs.next()) {}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

If statement execution generates multiple result sets, each result set needs to be processed until the one with the
exception is reached.

String SQL = "SELECT 1; SELECT * FROM nonexistentTable;";


try (Statement statement = connection.createStatement();) {
// Does not throw an exception on execute().
boolean hasResult = statement.execute(SQL);
while (hasResult) {
try (ResultSet rs = statement.getResultSet()) {
while (rs.next()) {
System.out.println(rs.getString(1));
}
}
// Moves the next result set that generates the exception.
hasResult = statement.getMoreResults();
}
} catch (SQLException e) {
e.printStackTrace();
}

For example, String SQL = "SELECT * FROM nonexistentTable; SELECT 1;"; , throws an exception immediately on
execute() and SELECT 1 isn't executed at all.

If the error from SQL Server has severity of 0 to 9 , it's considered as an informational message and returned
as SQLWarning .

String SQL = "RAISERROR ('WarningLevel5', 5, 2);";


try (Statement statement = connection.createStatement();) {
boolean hasResult = statement.execute(SQL);
SQLWarning warning = statement.getWarnings();
System.out.println(warning);
}

See also
Overview of the JDBC driver
Retrieving ParameterMetaData via useFmtOnly
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server includes an alternative way to query Parameter Metadata from the
server, useFmtOnly . This feature was first introduced in version 7.4 of the driver, and is required as a
workaround for known issues in sp_describe_undeclared_parameters .
The driver primarily uses the stored procedure sp_describe_undeclared_parameters to query Parameter
Metadata. This procedure is the recommended approach for Parameter Metadata retrieval under most
circumstances. However, executing the stored procedure currently fails under the following use cases:
Against Always Encrypted columns
Against temporary tables and table variables
Against views
The proposed solution for these use cases is to parse the user's SQL query for parameters and table targets,
then execute a SELECT query with FMTONLY enabled. The following snippet will help visualize the feature.

--create a normal table 'Foo' and a temporary table 'Bar'


CREATE TABLE Foo(c1 int);
CREATE TABLE #Bar(c1 int);

EXEC sp_describe_undeclared_parameters N'SELECT * FROM Foo WHERE c1 = @p0' --works fine


EXEC sp_describe_undeclared_parameters N'SELECT * FROM #Bar WHERE c1 = @p0' --fails with "Invalid object
name '#Bar'"

SET FMTONLY ON;


SELECT c1 FROM Foo; --works
SET FMTONLY OFF;
SET FMTONLY ON;
SELECT c1 FROM #Bar; --works
SET FMTONLY OFF;

Turning the feature on/off


The feature useFmtOnly is off by default. Users can enable this feature through the connection string by
specifying useFmtOnly=true . For example:
jdbc:sqlserver://<server>:<port>;databaseName=<databaseName>;user=<user>;password=<password>;useFmtOnly=true;
.
The feature is also available through SQLServerDataSource .
SQLServerDataSource ds = new SQLServerDataSource();
ds.setServerName(<server>);
ds.setPortNumber(<port>);
ds.setDatabaseName("<databaseName>");
ds.setUser("<user>");
ds.setPassword("<password>");
ds.setUseFmtOnly(true);
try (Connection c = ds.getConnection()) {
// do work with connection
}

The feature is also available on the Statement level. Users can turn the feature on/off through
PreparedStatement.setUseFmtOnly(boolean) .

NOTE
The driver will prioritize the Statement level property over the Connection level property.

Using the feature


Once enabled, the driver will internally start using the new feature instead of sp_describe_undeclared_parameters
when querying Parameter Metadata. There's no further action necessary from the end user.

final String sql = "INSERT INTO #Bar VALUES (?)";


try (Connection c = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
try (Statement s = c.createStatement()) {
s.execute("CREATE TABLE #Bar(c1 int)");
}
try (PreparedStatement p1 = c.prepareStatement(sql); PreparedStatement p2 = c.prepareStatement(sql)) {
((SQLServerPreparedStatement) p1).setUseFmtOnly(true);
ParameterMetaData pmd1 = p1.getParameterMetaData();
System.out.println(pmd1.getParameterTypeName(1)); // prints int
ParameterMetaData pmd2 = p2.getParameterMetaData(); // throws exception, Invalid object name '#Bar'
}
}

NOTE
The feature only supports SELECT/INSERT/UPDATE/DELETE queries. Queries should start with one of the 4 supported key
words or a Common Table Expression followed by one of the supported queries. Parameters within Common Table
Expressions are not supported.

Known issues
There are currently some issues with the feature, which are caused by gaps in the SQL parsing logic. These
issues may be addressed in a future update to the feature, and are documented below along with workaround
suggestions.
A. Using a 'forward declared' alias
CREATE TABLE Foo(c1 int)

DELETE fooAlias FROM Foo fooAlias WHERE c1 > ?; --Invalid object name 'fooAlias'

--Workaround #1: Specify AS keyword


DELETE fooAlias FROM Foo AS fooAlias WHERE c1 > ?;
--Workaround #2: Use the table name
DELETE Foo FROM Foo fooAlias WHERE c1 > ?;

B. Ambiguous Column Name when tables have shared column names

CREATE TABLE Foo(c1 int, c2 int, c3 int)


CREATE TABLE Bar(c1 int, c2 int, c3 int)

SELECT c1,c2 FROM Foo WHERE c3 IN (SELECT c3 FROM Bar WHERE c1 > ? and c2 < ? and c3 = ?); --Ambiguous
Column Name

--Workaround: Use aliases


SELECT c1,c2 FROM Foo WHERE c3 IN (SELECT c3 FROM Bar b WHERE b.c1 = ? and b.c2 = ? and b.c3 = ?);

C. SELECT from a subquery with parameters

CREATE TABLE Foo(c1 int)

SELECT * FROM (SELECT * FROM Foo WHERE c1 = ?) WHERE c1 = ?; --Incorrect syntax near '?'

--Workaround: N/A

D. Subqueries in a SET clause

CREATE TABLE Foo(c1 int)

UPDATE Foo SET c1 = (SELECT c1 FROM Foo) WHERE c1 = ?; --Incorrect syntax near ')'

--Workaround: Add a 'delimiting' condition


UPDATE Foo SET c1 = (SELECT c1 FROM Foo HAVING (HASH JOIN)) WHERE c1 = ?;

See also
Setting the connection properties
Understanding Java EE support
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following sections document how the Microsoft JDBC Driver for SQL Server provides support for the Java
Platform, Enterprise Edition (Java EE), and JDBC 3.0 optional API features. The source code examples provided in
this Help system provide a good reference to get started with these features.
First, make sure that your Java environment (JDK, JRE) includes the javax.sql package. This package is required
for any JDBC application that uses the optional API. JDK 1.5 and later versions already contain this package, so
you don't have to install it separately.

Driver name
The driver class name is com.microsoft.sqlser ver.jdbc.SQLSer verDriver .
For JDBC Driver 10.2, the driver is contained in mssql-jdbc-10.2.0.jre8.jar , mssql-jdbc-10.2.0.jre11.jar , or
mssql-jdbc-10.2.0.jre17.jar .
For JDBC Driver 9.4, the driver is contained in mssql-jdbc-9.4.1.jre8.jar , mssql-jdbc-9.4.1.jre11.jar , or
mssql-jdbc-9.4.1.jre16.jar .
For JDBC Driver 9.2, the driver is contained in mssql-jdbc-9.2.1.jre8.jar , mssql-jdbc-9.2.1.jre11.jar , or
mssql-jdbc-9.2.1.jre15.jar .
For JDBC Driver 8.4, the driver is contained in mssql-jdbc-8.4.1.jre8.jar , mssql-jdbc-8.4.1.jre11.jar , or
mssql-jdbc-8.4.1.jre14.jar .
For JDBC Driver 8.2, the driver is contained in mssql-jdbc-8.2.2.jre8.jar , mssql-jdbc-8.2.2.jre11.jar , or
mssql-jdbc-8.2.2.jre13.jar .
For JDBC Driver 7.4, the driver is contained in mssql-jdbc-7.4.1.jre8.jar , mssql-jdbc-7.4.1.jre11.jar , or
mssql-jdbc-7.4.1.jre12.jar .
For JDBC Driver 7.2, the driver is contained in mssql-jdbc-7.2.2.jre8.jar , or mssql-jdbc-7.2.2.jre11.jar .
For JDBC Driver 7.0, the driver is contained in mssql-jdbc-7.0.0.jre8.jar , or mssql-jdbc-7.0.0.jre10.jar .
For JDBC Driver 6.4, the driver is contained in mssql-jdbc-6.4.0.jre7.jar , mssql-jdbc-6.4.0.jre8.jar , or
mssql-jdbc-6.4.0.jre9.jar .
For JDBC Driver 6.2, the driver is contained in mssql-jdbc-6.2.2.jre7.jar or mssql-jdbc-6.2.2.jre8.jar .
For JDBC Drivers 4.1, 4.2, and 6.0, the driver is contained in the sqljdbc.jar , sqljdbc4.jar , sqljdbc41.jar , or
sqljdbc42.jar files.
The class name is used whenever you load the driver with the JDBC DriverManager class, and whenever you
specify the class name of the driver in any driver configuration. For example, to configure a data source within a
Java EE application server might require you enter the driver class name.

Data sources
The JDBC driver provides support for Java EE / JDBC 3.0 data sources. The JDBC driver SQLServerXADataSource
class is implemented by com.microsoft.sqlserver.jdbc.SQLServerXADataSource .
Datasource names
You can make database connections by using data sources. The data sources available with JDBC driver are
described in the following table:

DATA SO URC E T Y P E C L A SS N A M E A N D DESC RIP T IO N

DataSource com.microsoft.sqlserver.jdbc.SQLServerDataSource

The non pooling data source.

ConnectionPoolDataSource com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource

The data source to configure JAVA EE application server


connection pools. Typically used when the application runs
within a JAVA EE application server.

XADataSource com.microsoft.sqlserver.jdbc.SQLServerXADataSource

The data source to configure JAVA EE XA data sources.


Typically used when the application runs within a JAVA EE
application server and an XA transaction manager.

Data source properties


All data sources support the ability to set and get any property that is associated with the underlying driver's
property set.
Examples:
setServerName("localhost");
setDatabaseName("AdventureWorks");

The following shows how an application connects by using a data source:

//initialize JNDI ..
Context ctx = new InitialContext(System.getProperties());
...
DataSource ds = (DataSource) ctx.lookup("MyDataSource");
Connection c = ds.getConnection("user", "pwd");

For more information about the data source properties, see Setting the data source properties.

See also
Overview of the JDBC driver
Deploying the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you deploy an application that depends on the Microsoft JDBC Driver for SQL Server, you must
redistribute the JDBC driver together with your application. Unlike Windows Data Access Components
(Windows DAC), which is a component of the Windows operating system, the JDBC driver is considered to be a
component of SQL Server.
There are two approaches to deploying the JDBC driver with your application. One is to include the JDBC driver
files as part of your own custom installation package. The second approach involves using the JDBC installation
package provided by Microsoft, which you can download from the Microsoft JDBC Driver for SQL Server
download page.
The following sections discuss how to use the JDBC installation package on Windows and UNIX operating
systems.

NOTE
For information about deploying Java applications in general, see the Java website.

Deploying the JDBC driver on Windows systems


When you deploy the JDBC driver on Windows operating systems, you must unpack the zipped installation
package, which is typically named sqljdbc_<version>_<language>.zip .

Deploying the driver on UNIX systems


When you deploy the JDBC driver on UNIX operating systems, you must use the gzip file version of the
installation package, which is typically named sqljdbc_<version>_<language>.tar.gz .
Before you install the JDBC driver, make sure that both the gzip and tar utilities are installed on the user's
system, and that the folders that contain the executables for both utilities are added to the PATH environment
variable.
To unpack the zipped tar file, navigate to the directory where you want the driver unpacked and type the
following command:
gzip -d sqljdbc_<version>_<language>.tar.gz

To unpack the tar file, move it to the directory where you want the driver installed and type the following
command:
tar -xf sqljdbc_<version>_<language>.tar

Legalities of driver redistribution


The JDBC Driver versions 6.0, 6.2, 6.4, 7.0, 7.2, 7.4, 8.2, and 8.4 are redistributable. Review the Distributable Code
clause in the license agreements.
The JDBC Driver versions 4.x are old and obsolete. Support for 4.x expired before 2018.
See also
Overview of the JDBC driver
Finding additional JDBC driver information
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For more information about the Microsoft JDBC Driver for SQL Server and SQL Server development in general,
see the following online resources:

Remarks
RESO URC E DESC RIP T IO N

JDBC Driver for SQL Server GitHub Repository This repository contains the source code for the JDBC Driver
for SQL Server. Use this site to interact directly with
members of the JDBC driver team. Here you can file issues,
provide feedback, and contribute directly to the driver.

Data Access and Storage Developer Center This site provides documentation, technical articles, sample
code, and other resources for all data access technologies at
Microsoft.

SQL Server Data Access Forum This site serves as a community forum for data access to
SQL Server by using SQL Server Native Client, OLE DB,
ODBC, ADO, MDAC, JDBC, or SOAP/HTTP.

JDBC Blog This blog is used to provide information about the Microsoft
JDBC Driver for SQL Server.

See also
Overview of the JDBC driver
Feature dependencies of the Microsoft JDBC Driver
for SQL Server
4/27/2022 • 5 minutes to read • Edit Online

Download JDBC Driver


This article lists libraries that the Microsoft JDBC Driver for SQL Server depends on. The project has the
following dependencies:

Compile time
com.azure:azure-security-keyvault-keys : Microsoft Azure Client Library For KeyVault Keys for JDBC driver
version 9.2 and above or com.microsoft.azure:azure-keyvault : Microsoft Azure SDK For Key Vault for JDBC
driver version 8.4 and below for Always Encrypted Azure Key Vault feature. (optional)
com.azure:azure-identity : Microsoft Azure Client Library For Identity for JDBC driver version 9.2 and above
or com.microsoft.azure:adal4j : Microsoft Azure Active Directory Authentication Library for JDBC driver
version 8.4 and below for Azure Active Directory Authentication features and Azure Key Vault feature.
(optional)
org.antlr:antlr4-runtime : ANTLR 4 Runtime for useFmtOnly feature. (optional)
org.osgi:org.osgi.core : OSGi Core library for OSGi Framework support.
org.osgi:org.osgi.compendium : OSGi Compendium library for OSGi Framework support.
com.google.code.gson : JSON parser for Always Encrypted with secure enclaves feature. (optional)
org.bouncycastle.bcprov-jdk15on : Bouncy Castle Provider for Always Encrypted with secure enclaves feature
for JAVA 8 only. (optional)

Run time
Projects that require any of the preceding features must explicitly declare the respective dependencies in their
POM file that match the dependencies of the version of the driver used.
For example: If you're using the Azure Active Directory Authentication feature with JDBC driver version 10.2
and above, you must declare the azure-identity dependency in your project POM file. See the following
snippet:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>10.2.0.jre11</version>
</dependency>

<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.4.3</version>
</dependency>

For example: If you're using the Azure Active Directory Authentication feature with JDBC driver version 8.4 and
below, you must declare the adal4j and client-runtimes dependencies in your project POM file. See the
following snippet:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.2.1.jre11</version>
</dependency>

<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>adal4j</artifactId>
<version>1.6.5</version>
</dependency>

<dependency>
<groupId>com.microsoft.rest</groupId>
<artifactId>client-runtime</artifactId>
<version>1.7.4</version>
</dependency>

For example: If you're using the Azure Key Vault feature with JDBC driver version 10.2 and above, you must
declare the azure-security-keyvault-keys and azure-identity dependencies in your project POM file. See the
following snippet:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>10.2.0.jre11</version>
</dependency>

<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.4.3</version>
</dependency>

<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-keys</artifactId>
<version>4.3.6</version>
</dependency>

For example: If you're using the Azure Key Vault feature with JDBC driver version 8.4 and below, you must
declare the azure-keyvault , adal4j , and client-runtime dependencies in your project POM file. See the
following snippet:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.2.1.jre11</version>
</dependency>

<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>adal4j</artifactId>
<version>1.6.5</version>
</dependency>

<dependency>
<groupId>com.microsoft.rest</groupId>
<artifactId>client-runtime</artifactId>
<version>1.7.4</version>
</dependency>

<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault</artifactId>
<version>1.2.4</version>
</dependency>

NOTE
Make sure to use the version of the POM file that's shipped with the version of the JDBC driver you're using. The
dependencies and versions may have changed.

If you're using Maven to build or test your project, Maven automatically downloads dependent libraries in the
POM file along with their transitive libraries. You can also use the Maven Dependency Plugin to download all
project dependencies to a desired location. If you're not using Maven, you have to download dependencies and
transitive dependencies manually to make sure you have all the correct versions of each library. Once you've
downloaded the required dependent libraries, add them to your project classpath to run your application.

Dependency requirements for the JDBC driver


Work with the Azure Key Vault provider
JDBC driver version 10.2.0 — Dependency versions: Azure-security-keyvault-keys (version 4.3.6), and Azure-
identity(version 1.4.3), and their dependencies (sample application)
JDBC driver version 9.4.1 — Dependency versions: Azure-security-keyvault-keys (version 4.2.8), and Azure-
identity(version 1.3.3), and their dependencies (sample application)
JDBC driver version 9.2.1 — Dependency versions: Azure-security-keyvault-keys (version 4.2.1), and Azure-
identity(version 1.1.3), and their dependencies (sample application)
JDBC driver version 8.4.1 — Dependency versions: Azure-Keyvault (version 1.2.4), Adal4j (version 1.6.5),
Client-Runtime-for-AutoRest (version 1.7.4), and their dependencies (sample application)
JDBC driver version 8.2.2 — Dependency versions: Azure-Keyvault (version 1.2.2), Adal4j (version 1.6.4),
Client-Runtime-for-AutoRest (version 1.7.0), and their dependencies (sample application)
JDBC driver version 7.4.1 — Dependency versions: Azure-Keyvault (version 1.2.1), Adal4j (version 1.6.4),
Client-Runtime-for-AutoRest (version 1.6.10), and their dependencies (sample application)
JDBC driver version 7.2.2 — Dependency versions: Azure-Keyvault (version 1.2.0), Azure-Keyvault-Webkey
(version 1.2.0), Adal4j (version 1.6.3), Client-Runtime-for-AutoRest (1.6.5), and their dependencies (sample
application)
JDBC driver version 7.0.0 — Dependency versions: Azure-Keyvault (version 1.0.0), Adal4j (version 1.6.0), and
their dependencies (sample application)
JDBC driver version 6.4.0 — Dependency versions: Azure-Keyvault (version 1.0.0), Adal4j (version 1.4.0), and
their dependencies (sample application)
JDBC driver version 6.2.2 — Dependency versions: Azure-Keyvault (version 1.0.0), Adal4j (version 1.4.0), and
their dependencies (sample application)
JDBC driver version 6.0.0 — Dependency versions: Azure-Keyvault (version 0.9.7), Adal4j (version 1.3.0), and
their dependencies ( sample application)

NOTE
With 6.2.2 and 6.4.0 driver versions, the azure-keyvault-java dependency had been updated to version 1.0.0. However,
the new version was not compatible with the previous version (0.9.7) and breaks the existing implementation in the driver.
The new implementation in the driver required API changes, which in turn breaks client programs that use the Azure Key
Vault Provider.
This problem is resolved with latest driver version(s) (7.0.0 onwards). The removed constructor that used the
authentication callback mechanism is added back to the Azure Key Vault Provider for backward compatibility.

Work with Azure Active Directory authentication


JDBC driver version 10.2.0 — Dependency versions: Azure-identity(version 1.4.3), and their dependencies.
JDBC driver version 9.4.1 — Dependency versions: Azure-identity(version 1.3.3), and their dependencies.
JDBC driver version 9.2.1 — Dependency versions: Azure-identity(version 1.1.3), and their dependencies.
JDBC Driver version 8.4.1 — Dependency versions: Adal4j (version 1.6.5), Client-Runtime-for-AutoRest
(1.7.4), and their dependencies.
JDBC Driver version 8.2.2 — Dependency versions: Adal4j (version 1.6.4), Client-Runtime-for-AutoRest
(1.7.0), and their dependencies. In this version of the driver, 'sqljdbc_auth.dll' has been renamed to 'mssql-
jdbc_auth-<version>-<arch>.dll'.
JDBC Driver version 7.4.1 — Dependency versions: Adal4j (version 1.6.4), Client-Runtime-for-AutoRest
(1.6.10), and their dependencies
JDBC Driver version 7.2.2 — Dependency versions: Adal4j (version 1.6.3), Client-Runtime-for-AutoRest
(1.6.5), and their dependencies
JDBC Driver version 7.0.0 — Dependency versions: Adal4j (version 1.6.0) and its dependencies
JDBC Driver version 6.4.0 — Dependency versions: Adal4j (version 1.4.0) and its dependencies
JDBC Driver version 6.2.2 — Dependency versions: Adal4j (version 1.4.0) and its dependencies
JDBC Driver version 6.0.0 — Dependency versions: Adal4j (version 1.3.0), and its dependencies. In this
version of the driver, you can connect by using ActiveDirectoryIntegrated Authentication Mode only on a
Windows operating system and by using sqljdbc_auth.dll and Active Directory Authentication Library for
SQL Server (ADALSQL.DLL).
From driver version 6.4.0 onward, applications don't necessarily require using ADALSQL.DLL on Windows
operating systems. For non-Windows operating systems, the driver requires a Kerberos ticket to work with
ActiveDirectoryIntegrated Authentication. For more information about how to connect to Active Directory by
using Kerberos, see Set Kerberos ticket on Windows, Linux, and macOS.
For Windows operating systems, the driver looks for sqljdbc_auth.dll by default and doesn't require Kerberos
ticket setup or Azure library dependencies. If sqljdbc_auth.dll isn't available, the driver looks for the Kerberos
ticket to authenticate to Active Directory as on other operating systems.
From driver version 8.2.2 onward, 'sqljdbc_auth.dll' is renamed to 'mssql-jdbc_auth-<version>-<arch>.dll'. For
example, 'mssql-jdbc_auth-8.2.2.x64.dll'.
In addition to the mssql-jdbc_auth-<version>-<arch>.dll (available in the JDBC driver package), the Azure
Active Directory Authentication Library (ADAL.DLL ) also must be installed for Active Directory Integrated
authentication. Microsoft Azure Active Directory Authentication Library can be installed from Microsoft ODBC
Driver for SQL Server or Microsoft OLE DB Driver for SQL Server. The JDBC driver only supports version
1.0.2028.318 and higher for ADAL.DLL.
You can get a sample application that uses this feature.

See also
JDBC Driver GitHub repository
JDBC Driver API reference
JDBC driver API reference
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver

Overview
The Microsoft JDBC Driver for SQL Server provides an API that can be used within Java programming code to
connect to and interact with a MicrosoftSQL Server database.
JavaDoc.io website is primary
The Microsoft JDBC API Reference documentation is hosted for your viewing on the JavaDoc.io website.
JavaDoc.io is now our primary website for JDBC reference documentation. Our JDBC reference documentation
on JavaDoc.io is available at the following direct link:
https://javadoc.io/doc/com.microsoft.sqlserver/mssql-jdbc/
JavaDoc.io has our JDBC reference documentation starting with version 6.0.
Only legacy JDBC documentation is here on docs
The JDBC API Reference documentation here on this website is no longer being updated. However, the articles
here do contain the reference for JDBC driver versions 4.1 and 4.2.
Documentation for JDBC driver version 6.0, and some later versions, is also here. For any version 6.0 or later, use
the JavaDoc.io website.
Important notes

NOTE
For conceptual information about using the JDBC driver, see Overview of the JDBC Driver.
IMPORTANT
For JDBC 4.1 and 4.2 compliance support, use Microsoft JDBC Driver 4.2 (or higher) for SQL Server. The previous
Microsoft JDBC Drivers 4.1 and 4.0 releases do not support new methods introduced with JDBC 4.1 or 4.2.
API details for JDBC 4.1 compliance are not in this section. See JDBC 4.1 Compliance for the JDBC Driver.
API details for JDBC 4.2 compliance are not found in this section. See JDBC 4.2 Compliance for the JDBC Driver.
API details for Bulk Copy, available starting with Microsoft JDBC Driver 4.2 for SQL Server, are not found in this section.
See Using Bulk Copy with the JDBC Driver.
API details for Always Encrypted, available starting with Microsoft JDBC Driver 6.0 for SQL Server, are not found in this
section. See Always Encrypted API Reference for the JDBC Driver
API details for Using Table-Valued Parameters, available starting with Microsoft JDBC Driver 6.0 for SQL Server, are not
found in this section. See Using Table-Valued Parameters
Microsoft JDBC Driver 6.4 supports compilation with JDK 7.0, 8.0, and 9.0.
Microsoft JDBC Driver 6.2 supports compilation with JDK 7.0, and 8.0.
Microsoft JDBC Drivers 6.0 and 4.2 support compilation with JDK 5.0, 6.0, 7.0, and 8.0.
Microsoft JDBC Driver 4.1 supports compilation with JDK 5.0, 6.0, and 7.0.

Interfaces
IN T ERFA C E N A M E DESC RIP T IO N

ISQLServerCallableStatement Interface Lets you specify the stored procedure name to call along
with input and output parameters.

ISQLServerConnection Interface Represents a JDBC connection to a SQL Server database.

SQLServerDataSource Class Represents a list of properties specific to connecting to a


SQL Server database by using a ISQLServerConnection
object.

ISQLServerPreparedStatement Represents the basic implementation of JDBC prepared


statement functionality.

ISQLServerResultSet Represents a JDBC result set.

ISQLServerStatement Represents the basic implementation of JDBC statement


functionality.

Classes
C L A SS N A M E DESC RIP T IO N

DateTimeOffset Represents an object of type microsoft.sql.DateTimeOffset.

SQLServerBlob Represents a binary large object (BLOB).


C L A SS N A M E DESC RIP T IO N

SQLServerCallableStatement Implements ISQLServerCallableStatement.

SQLServerClob Represents a character large binary object (CLOB).

SQLServerConnection Implements ISQLServerConnectopn.

SQLServerConnectionPoolDataSource Represents physical database connections for connection


pool managers.

SQLServerDatabaseMetaData Represents the metadata for the database.

SQLServerDataSource Represents a list of properties specific to connecting to a


SQL Server database by using a SQLServerConnection
object.

SQLServerDataSourceObjectFactory Represents an object factory to materialize data sources


from the Java Naming and Directory Interface (JNDI).

SQLServerDriver Represents the JDBC driver. This class includes methods for
connecting to a SQL Server database, and for obtaining
information about the JDBC driver.

SQLServerException Represents an unsuccessful or incomplete running of an SQL


statement.

SQLServerNClob Class Represents a character large binary object using the National
Character Set.

SQLServerParameterMetaData Represents the metadata for prepared statement


parameters.

SQLServerPooledConnection Represents a physical database connection in a connection


pool.

SQLServerPreparedStatement Implements ISQLServerPreparedStatement.

SQLServerResource Represents a localized error string resource. This class is


intended for internal use only.

SQLServerResultSet Implements ISQLServerResultSet.

SQLServerResultSetMetaData Represents the metadata of the columns that are contained


within a result set.

SQLServerSavepoint Represents the checkpoint to which a transaction can be


rolled back.

SQLServerStatement Implements ISQLServerStatement.

SQLServerXAConnection Represents JDBC connections that can participate in


distributed (XA) transactions.
C L A SS N A M E DESC RIP T IO N

SQLServerXADataSource Represents a factory for SQLServerXAConnection objects


that is used internally.

SQLServerXAResource Represents an XAResource for XA distributed transaction


management.

See also
Overview of the JDBC driver
ISQLServerCallableStatement Interface
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents JDBC callable statements. This interface was added in SQL Server JDBC Driver 3.0.
Package: com.microsoft.sqlserver.jdbc
Extends: java.sql.CallableStatement, ISQLServerPreparedStatement

Syntax
public interface ISQLServerCallableStatement

Remarks
This interface is implemented by SQLServerCallableStatement Class.
This interface exposes the following Microsoft JDBC Driver for SQL Server-specific methods:

M ET H O D F O R M O RE IN F O RM AT IO N , SEE

microsoft.sql.DateTimeOffset getDateTimeOffset(int) getDateTimeOffset(int)

microsoft.sql.DateTimeOffset getDateTimeOffset(String) getDateTimeOffset(String)

void setDateTimeOffset(String, microsoft.sql.DateTimeOffset) setDateTimeOffset

See Also
JDBC Driver API Reference
ISQLServerConnection Interface
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a JDBC connection to a MicrosoftSQL Server database. This interface was added in SQL Server JDBC
Driver 3.0.
Package: com.microsoft.sqlserver.jdbc
Extends: java.sql.Connection

Syntax
public interface ISQLServerConnection

Remarks
This interface is implemented by SQLServerConnection Class.
This interface exposes the following Microsoft JDBC Driver for SQL Server-specific field:

F IEL D F O R M O RE IN F O RM AT IO N , SEE

public final static int TRANSACTION_SNAPSHOT TRANSACTION_SNAPSHOT

public UUID getClientConnectionId() getClientConnectionID()

See Also
JDBC Driver API Reference
ISQLServerDataSource Interface
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


A factory to create connections to the data source represented by this object. This interface was added in SQL
Server JDBC Driver 3.0.
Package: com.microsoft.sqlserver.jdbc
Extends: java.sql.CommonDataSource

Syntax
public interface ISQLServerDataSource

Remarks
This interface is implemented by SQLServerDataSource Class.
This interface exposes the following Microsoft JDBC Driver for SQL Server-specific methods:

M ET H O D F O R M O RE IN F O RM AT IO N , SEE

public String getApplicationName() getApplicationName

public String getDatabaseName() getDatabaseName

public String getDescription() getDescription

public boolean getEncrypt() getEncrypt

public String getFailoverPartner() getFailoverPartner

public String getHostNameInCertificate() getHostNameInCertificate

public String getInstanceName() getInstanceName

public boolean getLastUpdateCount() getLastUpdateCount

public int getLockTimeout() getLockTimeout

public boolean getMultiSubnetFailover() getMultiSubnetFailover

public int getPacketSize() getPacketSize

public int getPortNumber() getPortNumber


M ET H O D F O R M O RE IN F O RM AT IO N , SEE

public String getResponseBuffering() getResponseBuffering

public String getSelectMethod() getSelectMethod

public boolean getSendStringParametersAsUnicode() getSendStringParametersAsUnicode

public boolean getSendTimeAsDatetime() getSendTimeAsDatetime

public String getServerName() getServerName

public boolean getTrustServerCertificate() getTrustServerCertificate

public String getTrustStore() getTrustStore

public String getURL() getURL

public String getUser() getUser

public String getWorkstationID() getWorkstationID

public boolean getXopenStates() getXopenStates

public void setApplicationName(String) setApplicationName

public void setAuthenticationSceme(String) setAuthenticationSceme

public void setDatabaseName(String) setDatabaseName

public void setDescription(String) setDescription

public void setEncrypt(boolean) setEncrypt

public void setFailoverPartner(String) setFailoverPartner

public void setHostNameInCertificate(String) setHostNameInCertificate

public void setInstanceName(String) setInstanceName

public void setIntegratedSecurity(boolean) setIntegratedSecurity

public void setLastUpdateCount(boolean) setLastUpdateCount

public void setLockTimeout(int) setLockTimeout

public void setMultiSubnetFailover(boolean setMultiSubnetFailover


multiSubnetFailover)

public void setPacketSize(int) setPacketSize

public void setPassword(String) setPassword


M ET H O D F O R M O RE IN F O RM AT IO N , SEE

public void setPortNumber(int) setPortNumber

public void setResponseBuffering(String) setResponseBuffering

public void setSelectMethod(String) setSelectMethod

public void setSendStringParametersAsUnicode(boolean) setSendStringParametersAsUnicode

public void setSendTimeAsDatetime(boolean) setSendTimeAsDatetime

public void setServerName(String) setServerName

public void setTrustServerCertificate(boolean) setTrustServerCertificate

public void setTrustStore(String) setTrustStore

public void setTrustStorePassword(String) setTrustStorePassword

public void setURL(String url) setURL

public void setUser(String) setUser

public void setWorkstationID(String) setWorkstationID

public void setXopenStates(boolean) setXopenStates

See Also
JDBC Driver API Reference
ISQLServerPreparedStatement Interface
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents the basic implementation of JDBC prepared statement functionality. This interface was added in SQL
Server JDBC Driver 3.0.
Package: com.microsoft.sqlserver.jdbc
Extends: java.sql.PreparedStatement, ISQLServerStatement

Syntax
public interface ISQLServerPreparedStatement

Remarks
This interface is implemented by SQLServerPreparedStatement Class.
This interface exposes the following Microsoft JDBC Driver for SQL Server-specific methods:

M ET H O D F O R M O RE IN F O RM AT IO N , SEE

public void setDateTimeOffset(int, setDateTimeOffset


microsoft.sql.DateTimeOffset)

See Also
JDBC Driver API Reference
ISQLServerResultSet Interface
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a JDBC result set. This interface was added in SQL Server JDBC Driver 3.0.
Package: com.microsoft.sqlserver.jdbc
Extends: java.sql.ResultSet

Syntax
public interface ISQLServerResultSet

Remarks
This interface is implemented by SQLServerResultSet Class.
This interface exposes the Microsoft JDBC Driver for SQL Server-specific methods:

M ET H O D F O R M O RE IN F O RM AT IO N , SEE

public microsoft.sql.DateTimeOffset getDateTimeOffset(int) getDateTimeOffset

public microsoft.sql.DateTimeOffset getDateTimeOffset


getDateTimeOffset(String)

public void updateDateTimeOffset(int, updateDateTimeOffset


microsoft.sql.DateTimeOffset)

public void updateDateTimeOffset(String, updateDateTimeOffset


microsoft.sql.DateTimeOffset)

This interface exposes the following Microsoft JDBC Driver for SQL Server-specific fields:

F IEL D F O R M O RE IN F O RM AT IO N , SEE

public static final int CONCUR_SS_OPTIMISTIC_CC CONCUR_SS_OPTIMISTIC_CC

public static final int CONCUR_SS_OPTIMISTIC_CCVAL CONCUR_SS_OPTIMISTIC_CCVAL

public static final int CONCUR_SS_SCROLL_LOCKS CONCUR_SS_SCROLL_LOCKS

public static final int TYPE_SS_DIRECT_FORWARD_ONLY TYPE_SS_DIRECT_FORWARD_ONLY

public static final int TYPE_SS_SCROLL_DYNAMIC TYPE_SS_SCROLL_DYNAMIC

public static final int TYPE_SS_SCROLL_KEYSET TYPE_SS_SCROLL_KEYSET


F IEL D F O R M O RE IN F O RM AT IO N , SEE

public static final int TYPE_SS_SCROLL_STATIC TYPE_SS_SCROLL_STATIC

public static final int TYPE_SS_SERVER_CURSOR_FORWARD_ONLY


TYPE_SS_SERVER_CURSOR_FORWARD_ONLY

See Also
JDBC Driver API Reference
ISQLServerStatement Interface
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents the basic implementation of JDBC statement functionality. This interface was added in SQL Server
JDBC Driver 3.0.
Package: com.microsoft.sqlserver.jdbc
Extends: java.sql.Statement

Syntax
public interface ISQLServerStatement

Remarks
This interface is implemented by SQLServerStatement Class.
This interface exposes the following Microsoft JDBC Driver for SQL Server-specific methods:

M ET H O D F O R M O RE IN F O RM AT IO N , SEE

public String getResponseBuffering getResponseBuffering

public void setResponseBuffering setResponseBuffering

See Also
JDBC Driver API Reference
DateTimeOffset Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This type represents an object of type microsoft.sql.DateTimeOffset and is the Java type that corresponds to the
SQL Server datetimeoffset data type.
Package: microsoft.sql
Extends: java.lang.Object
Implements: java.lang.Comparable<DateTimeOffset>, java.io.Serializable

Syntax
public final class DateTimeOffset

Remarks
For more information about data types, see Understanding the JDBC Driver Data Types.

See Also
JDBC Driver API Reference
DateTimeOffset Members
DateTimeOffset Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the DateTimeOffset Class class.

Constructors
None.

Fields
None.

Methods
NAME DESC RIP T IO N

compareTo Compares this DateTimeOffset object to another


DateTimeOffset object based on their time at GMT.

equals Compares this DateTimeOffset object to another Object .

getMinutesOffset Returns the offset, in minutes from GMT, of this


DateTimeOffset object.

getTimestamp Returns the point in time represented by this


DateTimeOffset object as a java.sql.Timestamp.

hashCode Returns a hash code value for the object.

toString Returns a string representation of the DateTimeOffset


object.

valueOf Creates a DateTimeOffset object representing a point in


time at a particular offset from GMT.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

class java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait,

See Also
DateTimeOffset Class
DateTimeOffset Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of DateTimeOffset, see DateTimeOffset Members.

See Also
DateTimeOffset Class
compareTo Method (DateTimeOffset)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Compares this DateTimeOffset object to another DateTimeOffset object based on the time at GMT.

Syntax
public int compareTo(DateTimeOffset other)

Parameters
A DateTimeOffset value that you want to compare to the current instance.

Return Value
The following table describes the return value of this method:

RET URN VA L UE DESC RIP T IO N

0 Both DateTimeOffset objects represent the same point in


time.

negative number This DateTimeOffset object represents a point in time that


is before other.

positive number This DateTimeOffset object represents a point in time that


is after other.

Remarks
When two DateTimeOffset objects have the same time at GMT, there is no additional ordering of the objects
based on the offset.

See Also
DateTimeOffset Class
DateTimeOffset Members
equals Method (DateTimeOffset)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Compares this DateTimeOffset object to another Object .

Syntax
public boolean equals(Object o)

Parameters
o
The object you want compare to the current instance.

Return Value
Returns true if this DateTimeOffset object represents the same point in time at the same offset from GMT as
another DateTimeOffset .

See Also
DateTimeOffset Class
DateTimeOffset Members
getMinutesOffset Method (DateTimeOffset)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the offset, in minutes from GMT, of this DateTimeOffset object.

Syntax
public int getMinutesOffset()

Return Value
The offset in minutes.

Remarks
For a DateTimeOffset object representing 8 March 2010, 11:35:48 -0800, getMinutesOffset returns the value
480.

See Also
DateTimeOffset Class
DateTimeOffset Members
getTimestamp Method (DateTimeOffset)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the point in time represented by this DateTimeOffset object as a java.sql.Timestamp.

Syntax
public java.sql.Timestamp getTimestamp()

Return Value
A value of type java.sql.Timestamp.

See Also
DateTimeOffset Class
DateTimeOffset Members
hashCode Method (DateTimeOffset)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a hash code value for the object.

Syntax
public int hashCode()

Return Value
The hash code for the object.

See Also
DateTimeOffset Class
DateTimeOffset Members
toString Method (DateTimeOffset)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a string representation of the DateTimeOffset object.

Syntax
public String toString()

Return Value
A string representation of the DateTimeOffset object.

Remarks
The string has the format YYYY-MM-DD HH:mm:ss[.fffffff] [+|-]HH:mm .
The fractional seconds of the returned string are zero padded to the declared precision. For example, a
datetimeoffset(6) with a value of "2010-03-10 12:34:56.78 -08:00" will be formatted by
DateTimeOffset.toString as "2010-03-10 12:34:56.780000 -08:00".

See Also
DateTimeOffset Class
DateTimeOffset Members
valueOf Method (DateTimeOffset)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a DateTimeOffset object representing a point in time at a particular offset from GMT.

Overload List
NAME DESC RIP T IO N

valueOf(java.sql.Timestamp, int) Creates a DateTimeOffset object representing a point in


time at a particular offset from GMT given a
java.sql.Timestamp value and a value indicating the offset in
minutes.

valueOf(java.sql.Timestamp, java.util.Calendar) Creates a DateTimeOffset object representing a point in


time at a particular offset from GMT given a
java.sql.Timestamp value and a java.util.Calendar value
indicating the offset.

See Also
DateTimeOffset Class
DateTimeOffset Members
valueOf Method ( java.sql.Timestamp, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a DateTimeOffset object representing a point in time at a particular offset from GMT given a
java.sql.Timestamp value and a value indicating the offset in minutes.

Syntax
public static DateTimeOffset valueOf(java.sql.Timestamp timestamp, int minutesOffset)

Parameters
timestamp
Ajava.sql.Timestamp value.
minutesOffset
The offset in minutes.

Return Value
Returns a DateTimeOffset object representing the point in time given by the java.sql.Timestamp object at the
given offset, in minutes, from GMT.

See Also
DateTimeOffset Class
DateTimeOffset Members
valueOf Method ( java.sql.Timestamp,
java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a DateTimeOffset object representing a point in time at a particular offset from GMT given a
java.sql.Timestamp value and a java.util.Calendar value indicating the offset.

Syntax
public static DateTimeOffset valueOf(java.sql.Timestamp timestamp, java.util.Calendar calendar)

Parameters
timestamp
Ajava.sql.Timestamp value.
calendar
The offset value. The date and time components of calendar will be set according to the timestamp value.

Return Value
Returns a DateTimeOffset object representing the point in time given by the java.sql.Timestamp object at the
given java.util.Calendar object's time zone.

Remarks
This method also sets the java.util.Calendar object to the point in time given by the java.sql.Timestamp object.

See Also
DateTimeOffset Class
DateTimeOffset Members
SQLServerBlob Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a binary large object (BLOB).
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: java.sql.Blob, java.io.Serializable

Syntax
public class SQLServerBlob

Remarks
A BLOB is stored in SQL Server as an IMAGE data type.

See Also
SQLServerBlob Members
JDBC Driver API Reference
SQLServerBlob Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerBlob class.

Constructors
NAME DESC RIP T IO N

SQLServerBlob Initializes a new instance of the SQLServerBlob class.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

free This method frees the BLOB object and releases the
resources that it holds.

getBinaryStream Returns an input stream to read data from the BLOB.

getBytes Gets the BLOB data as an array of bytes.

length Returns the number of bytes in the BLOB object.

position Returns the position of a specified pattern in the BLOB based


on the given pattern and the starting index.

setBinaryStream Retrieves a stream that can be used to write to the BLOB


value.

setBytes Writes the given array of bytes into the BLOB starting at the
given position, and then returns the number of bytes
written.

truncate Truncates a BLOB given the length.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

See Also
SQLServerBlob Class
SQLServerBlob Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerBlob, see SQLServerBlob Members.

See Also
SQLServerBlob Class
SQLServerBlob Constructor (SQLServerConnection,
byte)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerBlob class when given a SQLServerConnection object and a byte
array.

NOTE
This method has been deprecated in JDBC Driver version 2.0. Instead, use the createBlob method of the
SQLServerConnection class.

Syntax
public SQLServerBlob(SQLServerConnection connection,
byte[] data)

Parameters
connection
A SQLServerConnection object.
data
A byte array.

See Also
SQLServerBlob Constructors
SQLServerBlob Members
SQLServerBlob Class
SQLServerBlob Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerBlob, see SQLServerBlob Members.

See Also
SQLServerBlob Class
free Method (SQLServerBlob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method frees the BLOB object and releases the resources that it holds.

Syntax
public void free()

Exceptions
SQLServerException

Remarks
This free method is specified by the free method in the java.sql.Blob interface.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
getBinaryStream Method (SQLServerBlob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an input stream to read data from the BLOB.

Overload List
NAME DESC RIP T IO N

getBinaryStream Method () Returns an input stream to read data from the BLOB.

getBinaryStream Method (long, long) Returns an input stream object that contains a partial BLOB
value by using the specified starting position and the length.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
getBinaryStream Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an input stream to read data from the BLOB.

Syntax
public java.io.InputStream getBinaryStream()

Return Value
An input stream that contains the BLOB data.

Exceptions
SQLServerException

Remarks
This getBinaryStream method is specified by the getBinaryStream method in the java.sql.Blob interface.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
getBytes Method (SQLServerBlob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the BLOB data as an array of bytes.

Syntax
public byte[] getBytes(long pos,
int length)

Parameters
pos
The starting position, starting at 1 (not 0).
length
The length of the data to get.

Return Value
A byte array containing the requested data.

Exceptions
SQLServerException

Remarks
This getBytes method is specified by the getBytes method in the java.sql.Blob interface.
If you have a null or zero length BLOB, and try to get exactly zero bytes at position 1, an empty byte array is
returned (byte array of length 0).
If you have a null or zero length BLOB, and try to get any length of bytes at a position other than 1, a position
exception will be thrown.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
length Method (SQLServerBlob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the number of bytes in the BLOB object.

Syntax
public long length()

Return Value
A long value that specifies the number of bytes.

Exceptions
SQLServerException

Remarks
This length method is specified by the length method in the java.sql.Blob interface.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
position Method (SQLServerBlob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the position of a specified pattern in the BLOB based on the given pattern and the starting index.

Overload List
NAME DESC RIP T IO N

position (java.sql.Blob, long) Returns the position of a specified pattern in the BLOB based
on the given pattern and the starting index.

position (byte[], long) Returns the position of a specified pattern in the BLOB based
on the given byte array pattern and the starting index.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
position Method ( java.sql.Blob, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the position of a specified pattern in the BLOB based on the given pattern and starting index.

Syntax
public long position(java.sql.Blob pattern,
long start)

Parameters
pattern
The pattern to search for.
start
The start index to search at.

Return Value
A long value of the position where the pattern was found, or -1 if it was not found.

Exceptions
SQLServerException

Remarks
This position method is specified by the position method in the java.sql.Blob interface.

See Also
position Method (SQLServerBlob)
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
position Method (byte, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the position of a specified pattern in the BLOB based on the given byte array pattern and starting index.

Syntax
public long position(byte[] bPattern,
long start)

Parameters
bPattern
The pattern to search for.
start
The start index to search at.

Return Value
A long value of the position where the pattern was found, or -1 if it was not found.

Exceptions
SQLServerException

Remarks
This position method is specified by the position method in the java.sql.Blob interface.

See Also
position Method (SQLServerBlob)
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
setBinaryStream Method (SQLServerBlob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a stream that can be used to write to the BLOB value.

Syntax
public java.io.OutputStream setBinaryStream(long pos)

Parameters
Pos
The position in the BLOB value at which to start writing)

Return Value
An output stream.

Exceptions
java.sql.SQLException

Remarks
This setBinaryStream method is specified by the setBinaryStream method in the java.sql.Blob interface.
Data in the BLOB is overwritten by the output stream starting at the specified position and can over-run the
initial length of the BLOB. Specifying a position+1 value will append bytes. Passing a position+2 or greater (or
zero or less) value will cause a position error to be thrown.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
setBytes Method (SQLServerBlob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Writes the given array of bytes into the BLOB starting at the given position, and then returns the number of
bytes written.

Overload List
NAME DESC RIP T IO N

setBytes (long, byte[]) Writes the given array of bytes into the BLOB starting at the
given position, and then returns the number of bytes
written.

setBytes (long, byte[], int, int) Writes all or part of the given array of bytes into the BLOB
starting at the given position, offset, and length, and then
returns the number of bytes written.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
setBytes Method (long, byte)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Writes the given array of bytes into the BLOB starting at the given position, and then returns the number of
bytes written.

Syntax
public int setBytes(long pos,
byte[] bytes)

Parameters
pos
The position (1-based) in the BLOB at which to start writing the data.
bytes
The array of bytes to be written into the BLOB.

Return Value
A long value that specifies the number of bytes written.

Exceptions
java.sql.SQLException

Remarks
This setBytes method is specified by the setBytes method in the java.sql.Blob interface.
Data is overwritten starting at the specified position and can overrun the initial length of the BLOB. Specifying a
position+1 values will append bytes. Passing a position+2 or greater (or zero or less) value will cause a position
error to be thrown. Passing a zero-length byte array will return zero because no bytes were written.

See Also
setBytes Method (SQLServerBlob)
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
setBytes Method (long, byte, int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Writes all or part of the given array of bytes into the BLOB starting at the given position, offset, and length; and
then returns the number of bytes written.

Syntax
public int setBytes(long pos,
byte[] bytes,
int offset,
int len)

Parameters
pos
The position (1 based) in the BLOB at which to start writing the data.
bytes
The array of bytes to be written into the BLOB.
offset
The offset in the bytes array where to start reading data from the byte array.
len
The number of bytes to attempt to read from the bytes array into the BLOB.

Return Value
An int containing the number of bytes written.

Exceptions
java.sql.SQLException

Remarks
This setBytes method is specified by the setBytes method in the java.sql.Blob interface.
Data is overwritten starting at the specified position and can over-run the initial length of the BLOB. Specifying a
position+1 values will append bytes. Passing a position+2 or greater (or zero or less) value will cause a position
error to be thrown. Passing a zero-length byte array will return zero because no bytes were written.

See Also
setBytes Method (SQLServerBlob)
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
truncate Method (SQLServerBlob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Truncates a BLOB, given the length.

Syntax
public void truncate(long len)

Parameters
len
The new length for the BLOB.

Exceptions
java.sql.SQLException

Remarks
This truncate method is specified by the truncate method in the java.sql.Blob interface.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
SQLServerCallableStatement Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Lets you specify the stored procedure name to call along with input and output parameters. This class also
provides the ability to retrieve the return status value with the ? = call( ?, ..) syntax.
Package: com.microsoft.sqlserver.jdbc
Implements: ISQLServerCallableStatement
Extends: SQLServerPreparedStatement

Syntax
public final class SQLServerCallableStatement

Remarks
SQLServerCallableStatement lets you specify the stored procedure name to call along with input and output
parameters. SQLServerCallableStatement also provides the ability to retrieve the return status value with the
? = call( ?, ..) syntax.

This class supports unwrapping to SQLServerCallableStatement class, ISQLServerCallableStatement interface,


java.sql.CallableStatement interface, and the classes and interfaces supported by SQLServerPreparedStatement
for unwrapping. For more information, see Wrappers and Interfaces.
When one of the SQLServerCallableStatement set methods is called for a type, if that type conflicts with the type
specified with registerOutParameter, the type specified by the last SQLServerCallableStatement set method is
used. However, this may cause incompatible data type conversion errors. If a SQLServerCallableStatement set
method is not called, the type specified with the first registerOutParameter call is used.
The SQL Server JDBC Driver 3.0 is compliant with the JDBC 4.0 recommendation that a result set and update
counts must be retrieved before retrieving OUT parameters. If OUT parameters are retrieved before the result
set and update counts have been completely processed, any result sets and update counts that have not been
processed are lost.

See Also
SQLServerCallableStatement Members
JDBC Driver API Reference
SQLServerCallableStatement Members
4/27/2022 • 8 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerCallableStatement class.

Constructors
None.

Fields
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.sql.Statement CLOSE_ALL_RESULTS, CLOSE_CURRENT_RESULT,


EXECUTE_FAILED, KEEP_CURRENT_RESULT,
NO_GENERATED_KEYS, RETURN_GENERATED_KEYS,
SUCCESS_NO_INFO

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

addBatch (Inherited from SQLServerPreparedStatement.) Adds a set of


parameters to the batch of commands for this
CallableStatement object.

cancel (Inherited from SQLServerStatement.) Cancels the SQL


statement that is currently being run by this
CallableStatement object.

clearBatch (Inherited from SQLServerPreparedStatement.) Empties the


current list of SQL commands for this CallableStatement
object.

clearParameters (Inherited from SQLServerPreparedStatement.) Clears the


current parameter values immediately.

clearWarnings (Inherited from SQLServerStatement.) Clears all the warnings


that are reported on this CallableStatement object.

close (Inherited from SQLServerPreparedStatement.) Releases the


database and JDBC resources of this CallableStatement
object immediately instead of waiting for them to be
automatically released.
NAME DESC RIP T IO N

execute (Inherited from SQLServerPreparedStatement.) Runs the SQL


statement in this CallableStatement object, which can be any
kind of SQL statement.

executeBatch (Inherited from SQLServerPreparedStatement.) Submits a


batch of commands to the database to be run. If all
commands run successfully, returns an array of update
counts.

executeQuery (Inherited from SQLServerPreparedStatement.) Runs the SQL


query in this CallableStatement object and returns the
SQLServerResultSet object that is generated by the query.

executeUpdate (Inherited from SQLServerPreparedStatement.) Runs the SQL


statement in this CallableStatement object, which must be an
SQL INSERT, UPDATE, MERGE, or DELETE statement; or an
SQL statement that returns nothing, such as a DDL
statement.

getConnection (Inherited from SQLServerStatement.) Retrieves the


SQLServerConnection object that produced this
CallableStatement object.

getDateTimeOffset Retrieves the value of the specified column as a


DateTimeOffset Class object.

getFetchDirection (Inherited from SQLServerStatement.) Retrieves the direction


for fetching rows from database tables that is the default for
result sets generated from this CallableStatement object.

getFetchSize (Inherited from SQLServerStatement.) Retrieves the number


of result set rows that is the default fetch size for result set
objects generated from this CallableStatement object.

getGeneratedKeys (Inherited from SQLServerStatement.) Retrieves any auto-


generated keys that are created as a result of running this
CallableStatement object.

getMaxFieldSize (Inherited from SQLServerStatement.) Retrieves the


maximum number of bytes that can be returned for
character and binary column values in a SQLServerResultSet
object produced by this CallableStatement object.

getMaxRows (Inherited from SQLServerStatement.) Retrieves the


maximum number of rows that a SQLServerResultSet object
produced by this CallableStatement object can contain.

getMetaData (Inherited from SQLServerPreparedStatement.) Retrieves a


SQLServerResultSetMetaData Class object that contains
information about the columns of the SQLServerResultSet
object that will be returned when this CallableStatement
object is run.

getMoreResults (Inherited from SQLServerStatement.) Moves to the next


result of this CallableStatement object.
NAME DESC RIP T IO N

getParameterMetaData (Inherited from SQLServerPreparedStatement.) Retrieves the


number, types, and properties of the parameters for this
CallableStatement object.

getArray Retrieves the value of the designated parameter as an Array


object.

getAsciiStream Retrieves the value of the designated parameter as a stream


of ASCII characters.

getBigDecimal Retrieves the value of the designated parameter as


java.math.BigDecimal.

getBinaryStream Retrieves the value of the designated parameter as a binary


stream of uninterrupted bytes.

getBlob Retrieves the value of the designated JDBC Blob parameter


as a Blob object in the Java programming language.

getboolean Retrieves the value of the designated parameter as a


Boolean value.

getByte Retrieves the value of the designated parameter as a byte


value.

getBytes Retrieves the value of the designated parameter as an array


of bytes.

getCharacterStream Retrieves the value of the designated parameter as a


java.io.Reader object.

getClob Retrieves the value of the designated JDBC Blob parameter


as a Clob object in the Java programming language.

getDate Retrieves the value of the designated parameter as a


java.sql.Date object in the Java programming language.

getDateTimeOffset Retrieves the value of the specified column as


aDateTimeOffset Class object.

getDouble Retrieves the value of the designated parameter as a double


in the Java programming language.

getFloat Retrieves the value of the designated parameter as a float in


the Java programming language.

getInt Retrieves the value of the designated parameter as an int in


the Java programming language.

getLong Retrieves the value of the designated parameter as a long in


the Java programming language.

getNCharacterStream Retrieves the value of the designated parameter as a Reader


object.
NAME DESC RIP T IO N

getNClob Retrieves the value of the designated JDBC NCLOB


parameter as an NClob object in the Java programming
language.

getNString Retrieves the value of the designated NCHAR, NVARCHAR


or LONGNVARCHAR parameter as a String in the Java
programming language.

getObject Retrieves the value of the designated parameter as an object


in the Java programming language.

getQueryTimeout (Inherited from SQLServerStatement.) Retrieves the number


of seconds the Microsoft JDBC Driver for SQL Server will
wait for this CallableStatement object to run.

getRef Retrieves the value of the designated parameter as a Ref


object in the Java programming language.

getResponseBuffering (Inherited from SQLServerStatement.) Retrieves the response


buffering mode for this SQLServerStatement object.

getResultSet (Inherited from SQLServerStatement.) Retrieves the current


result as a SQLServerResultSet object.

getResultSetConcurrency (Inherited from SQLServerStatement.) Retrieves the result set


concurrency for SQLServerResultSet objects that are
generated by this CallableStatement object.

getResultSetHoldability (Inherited from SQLServerStatement.) Retrieves the result set


holdability for SQLServerResultSet objects that are generated
by this CallableStatement object.

getResultSetType (Inherited from SQLServerStatement.) Retrieves the result set


type for SQLServerResultSet objects that are generated by
this CallableStatement object.

getShort Retrieves the value of the designated parameter as a shor t


in the Java programming language.

getString Retrieves the value of the designated parameter as a String


in the Java programming language.

getSQLXML Retrieves the value of the designated parameter as a


java.sql.SQLXML object.

getTime Retrieves the value of the designated parameter as a


java.sql.Time object in the Java programming language.

getTimestamp Retrieves the value of the designated parameter as a


java.sql.Timestamp object in the Java programming
language.

getUpdateCount (Inherited from SQLServerStatement.) Retrieves the current


result as an update count.
NAME DESC RIP T IO N

getURL Retrieves the value of the designated parameter as a URL


object in the Java programming language.

getWarnings (Inherited from SQLServerStatement.) Retrieves the first


warning that is reported by calls on this CallableStatement
object.

isClosed (Inherited from SQLServerStatement.) Indicates whether this


Statement object has been closed.

isPoolable (Inherited from SQLServerStatement.) Returns a value


indicating if a statement can be added to the user-provided
statement pool.

isWrapperFor Indicates whether this statement object is a wrapper for the


specified interface.

registerOutParameter Registers the OUT parameter.

setArray (Inherited from SQLServerPreparedStatement.) Sets the


designated parameter number to the given Array object.

setAsciiStream Sets the designated parameter to the given input stream.

setBigDecimal Sets the designated parameter number to the given


BigDecimal object.

setBinaryStream Sets the designated parameter to the specified input stream.

setBlob (Inherited from SQLServerPreparedStatement.) Sets the


designated parameter to the given Blob object.

setboolean Sets the designated parameter to the given Boolean value.

setByte Sets the designated parameter to the given byte value.

setBytes Sets the designated parameter to the given array of byte


values.

setCharacterStream Sets the designated parameter to the given Reader object.

setClob (Inherited from SQLServerPreparedStatement.) Sets the


designated parameter to the specified object.

setCursorName (Inherited from SQLServerStatement.) Sets the SQL cursor


name to the given String, which will be used by subsequent
execute methods.

setDate Sets the designated parameter to the given date value.

setDateTimeOffset Sets the value of the column specified to the DateTimeOffset


Class value.
NAME DESC RIP T IO N

setDouble Sets the designated parameter to the given double value.

setEscapeProcessing (Inherited from SQLServerStatement.) Sets the escape


processing mode.

setFetchDirection (Inherited from SQLServerStatement.) Gives the JDBC driver


a hint as to the direction in which result set rows should be
processed.

setFetchSize (Inherited from SQLServerStatement.) Gives the JDBC driver


a hint as to the number of rows that should be fetched from
the database when more rows are needed.

setFloat Sets the designated parameter to the specified float value.

setInt Sets the designated parameter to the specified int value.

setLong Sets the designated parameter to the specified long value.

setMaxFieldSize (Inherited from SQLServerStatement.) Sets the limit for the


maximum number of bytes in a SQLServerResultSet column
storing character or binary values to the specified number of
bytes.

setMaxRows (Inherited from SQLServerStatement.) Sets the limit for the


maximum number of rows that any SQLServerResultSet
object can contain to the specified number.

setNCharacterStream Sets the designated parameter to the specified Reader


object.

setNClob Sets the designated parameter to the specified object.

setNString Sets the designated parameter to the specified String object.

setNull Sets the designated parameter to a null value, given the type
of parameter to set.

setObject Sets the value of the designated parameter using the given
object.

setPoolable (Inherited from SQLServerStatement.) Requests that a


statement be pooled or not pooled. By default, a
SQLServerCallableStatement object is poolable when created.

setQueryTimeout (Inherited from SQLServerStatement.) Sets the number of


seconds the driver will wait for a CallableStatement object to
run to the specified number of seconds.

setRef (Inherited from SQLServerPreparedStatement.) Sets the


designated parameter to the specified Ref object.
NAME DESC RIP T IO N

setResponseBuffering (Inherited from SQLServerStatement.) Sets the response


buffering mode for this SQLServerStatement object to case-
insensitive String full or adaptive .

setShort Sets the designated parameter to the specified shor t value.

setString Sets the designated parameter to the specified Java String


value.

setSQLXML Sets the designated parameter to the specified SQLXML


object.

setTime Sets the designated parameter to the specified time value.

setTimestamp Sets the designated parameter to the specified timestamp


value.

setUnicodeStream (Inherited from SQLServerPreparedStatement.) Sets the


designated parameter number to the given input stream,
which will have the specified number of bytes.

setURL Sets the designated parameter to the specified URL value.

unwrap Returns an object that implements the specified interface to


allow access to the Microsoft JDBC Driver for SQL Server-
specific methods.

wasNull Retrieves whether the last OUT parameter read had the
value of SQL NULL.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement addBatch, clearBatch, clearParameters, close, execute,


executeBatch, executeQuery, executeUpdate, getMetaData,
getParameterMetaData, setArray, setAsciiStream,
setBigDecimal, setBinaryStream, setBlob, setboolean, setByte,
setBytes, setCharacterStream, setClob, setDate, setDouble,
setFloat, setInt, setLong, setNull, setObject, setRef, setShort,
setString, setTime, setTimestamp, setUnicodeStream, setURL

com.microsoft.sqlserver.jdbc.SQLServerStatement cancel, clearWarnings, execute, executeUpdate,


getConnection, getFetchDirection, getFetchSize,
getGeneratedKeys, getMaxFieldSize, getMaxRows,
getMoreResults, getQueryTimeout, getResultSet,
getResultSetConcurrency, getResultSetHoldability,
getResultSetType, getUpdateCount, getWarnings, isPoolable,
setCursorName, setEscapeProcessing, setFetchDirection,
setFetchSize, setMaxFieldSize, setMaxRows, setPoolable,
setQueryTimeout

class java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait,
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.sql.PreparedStatement addBatch, clearParameters, execute, executeQuery,


executeUpdate, getMetaData, getParameterMetaData,
getSQLXML, setArray, setAsciiStream, setBigDecimal,
setBinaryStream, setBlob, setboolean, setByte, setBytes,
setCharacterStream, setClob, setDate, setDate, setDouble,
setFloat, setInt, setLong, setNull, setObject, setRef, setShort,
setString, setSQLXML, setTime, setTimestamp,
setUnicodeStream, setURL

java.sql.Statement addBatch, cancel, clearBatch, clearWarnings, close, execute,


executeBatch, executeQuery, executeUpdate, getConnection,
getFetchDirection, getFetchSize, getGeneratedKeys,
getMaxFieldSize, getMaxRows, getMoreResults,
getQueryTimeout, getResultSet, getResultSetConcurrency,
getResultSetHoldability, getResultSetType, getUpdateCount,
getWarnings, setCursorName, setEscapeProcessing,
setFetchDirection, setFetchSize, setMaxFieldSize,
setMaxRows, setQueryTimeout

java.sql.Wrapper isWrapperFor, unwrap

See Also
SQLServerCallableStatement Class
SQLServerCallableStatement Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerCallableStatement, see SQLServerCallableStatement
Members.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getArray Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an Array object.

Overload List
NAME DESC RIP T IO N

getArray (int) Retrieves the value of the designated parameter as an Array


object given the parameter index.

getArray (java.lang.String) Retrieves the value of the designated parameter as an Array


object given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getArray Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an Array object given the parameter index.

Syntax
public java.sql.Array getArray(int i)

Parameters
i
An int that indicates the parameter index.

Return Value
An Array object.

Exceptions
SQLServerException

Remarks
This getArray method is specified by the getArray method in the java.sql.CallableStatement interface.

See Also
getArray Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getArray Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an Array object given the parameter name.

Syntax
public java.sql.Array getArray(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
An Array object.

Exceptions
SQLServerException

Remarks
This getArray method is specified by the getArray method in the java.sql.CallableStatement interface.

See Also
getArray Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getAsciiStream Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a stream of ASCII characters.

Overload List
NAME DESC RIP T IO N

getAsciiStream (int) Retrieves the value of the designated parameter as a stream


of ASCII characters given the parameter index.

getAsciiStream (java.lang.String) Retrieves the value of the designated parameter as a stream


of ASCII characters given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getAsciiStream (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a stream of ASCII characters given the parameter index.

Syntax
public final java.io.InputStream getAsciiStream(int paramIndex)

Parameters
paramIndex
An int that indicates the parameter index.

Return Value
An InputStream object.

Exceptions
SQLServerException

See Also
getAsciiStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getAsciiStream ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a stream of ASCII characters given the parameter name.

Syntax
public final java.io.InputStream getAsciiStream(java.lang.String paramName)

Parameters
paramName
A String that indicates the parameter name.

Return Value
An InputStream object.

Exceptions
SQLServerException

See Also
getAsciiStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBigDecimal Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as java.math.BigDecimal.

Overload List
NAME DESC RIP T IO N

getBigDecimal (int) Retrieves the value of the designated parameter as


java.math.BigDecimal with full precision given the parameter
index.

getBigDecimal (int, int) (Deprecated) Retrieves the value of the designated


parameter as java.math.BigDecimal given the parameter
index and scale.

getBigDecimal (java.lang.String) Retrieves the value of the designated parameter as


java.math.BigDecimal with full precision given the parameter
name.

getBigDecimal (java.lang.String, int) (Deprecated) Retrieves the value of the designated


parameter as java.math.BigDecimal given the parameter
name and scale.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBigDecimal Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as java.math.BigDecimal with full precision given the parameter
index.

Syntax
public java.math.BigDecimal getBigDecimal(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This getBigDecimal method is specified by the getBigDecimal method in the java.sql.CallableStatement interface.

See Also
getBigDecimal Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBigDecimal Method (int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as java.math.BigDecimal given the parameter index and scale.

NOTE
This method has been deprecated from the JDBC specification. Instead, you should use the getBigDecimal (int) method.

Syntax
public java.math.BigDecimal getBigDecimal(int index,
int scale)

Parameters
index
An int that indicates the parameter index.
scale
An int that indicates the number of digits to the right of the decimal point.

Return Value
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This getBigDecimal method is specified by the getBigDecimal method in the java.sql.CallableStatement interface.

See Also
getBigDecimal Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBigDecimal Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as java.math.BigDecimal with full precision given the parameter
name.

Syntax
public java.math.BigDecimal getBigDecimal(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This getBigDecimal method is specified by the getBigDecimal method in the java.sql.CallableStatement interface.

See Also
getBigDecimal Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBigDecimal Method ( java.lang.String, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as java.math.BigDecimal given the parameter name and scale.

NOTE
This method has been deprecated from the JDBC specification. Instead, you should use the getBigDecimal
(java.lang.String) method.

Syntax
public java.math.BigDecimal getBigDecimal(java.lang.String sCol,
int scale)

Parameters
sCol
A String that contains the parameter name.
scale
An int that indicates the number of digits to the right of the decimal point.

Return Value
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This getBigDecimal method is specified by the getBigDecimal method in the java.sql.CallableStatement interface.

See Also
getBigDecimal Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBinaryStream Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a binary stream of uninterrupted bytes.

Overload List
NAME DESC RIP T IO N

getBinaryStream (int) Retrieves the value of the designated parameter as a binary


stream of uninterrupted bytes given the parameter index.

getBinaryStream (java.lang.String) Retrieves the value of the designated parameter as a binary


stream of uninterrupted bytes given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBinaryStream (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a binary stream of uninterrupted bytes given the parameter
index.

Syntax
public final java.io.InputStream getBinaryStream(int paramIndex)

Parameters
paramIndex
An int that indicates the parameter index.

Return Value
An InputStream object.

Exceptions
SQLServerException

See Also
getBinaryStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBinaryStream ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a binary stream of uninterrupted bytes given the parameter
name.

Syntax
public final java.io.InputStream getBinaryStream(java.lang.String paramName)

Parameters
paramName
A String that indicates the parameter name.

Return Value
An InputStream object.

Exceptions
SQLServerException

See Also
getBinaryStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBlob Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated JDBC BLOB parameter as a Blob object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getBlob (int) Retrieves the value of the designated JDBC BLOB parameter
as a Blob object in the Java programming language given
the parameter index.

getBlob (java.lang.String) Retrieves the value of the designated JDBC BLOB parameter
as a Blob object in the Java programming language given
the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBlob Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated JDBC BLOB parameter as a Blob object in the Java programming language
given the parameter index.

Syntax
public java.sql.Blob getBlob(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A Blob object.

Exceptions
SQLServerException

Remarks
This getBlob method is specified by the getBlob method in the java.sql.CallableStatement interface.

See Also
getBlob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBlob Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated JDBC BLOB parameter as a Blob object in the Java programming language
given the parameter name.

Syntax
public java.sql.Blob getBlob(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A Blob object.

Exceptions
SQLServerException

Remarks
This getBlob method is specified by the getBlob method in the java.sql.CallableStatement interface.

See Also
getBlob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBoolean Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a boolean value.

Overload List
NAME DESC RIP T IO N

getBoolean (int) Retrieves the value of the designated parameter as a


boolean value given the parameter index.

getBoolean (java.lang.String) Retrieves the value of the designated parameter as a


boolean value given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBoolean Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a boolean value given the parameter index.

Syntax
public boolean getBoolean(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A boolean value.

Exceptions
SQLServerException

Remarks
This getBoolean method is specified by the getBoolean method in the java.sql.CallableStatement interface.

See Also
getBoolean Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBoolean Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a boolean value given the parameter name.

Syntax
public boolean getBoolean(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A boolean value.

Exceptions
SQLServerException

Remarks
This getBoolean method is specified by the getBoolean method in the java.sql.CallableStatement interface.

See Also
getBoolean Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getByte Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a byte value.

Overload List
NAME DESC RIP T IO N

getByte (int) Retrieves the value of the designated parameter as a byte


value given the parameter index.

getByte (java.lang.String) Retrieves the value of the designated parameter as a byte


value given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getByte Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a byte value given the parameter index.

Syntax
public byte getByte(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A byte value.

Exceptions
SQLServerException

Remarks
This getByte method is specified by the getByte method in the java.sql.CallableStatement interface.

See Also
getByte Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getByte Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a byte value given the parameter name.

Syntax
public byte getByte(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A byte value.

Exceptions
SQLServerException

Remarks
This getByte method is specified by the getByte method in the java.sql.CallableStatement interface.

See Also
getByte Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBytes Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an array of bytes.

Overload List
NAME DESC RIP T IO N

getBytes (int) Retrieves the value of the designated parameter as an array


of bytes value given the parameter index.

getBytes (java.lang.String) Retrieves the value of the designated parameter as an array


of bytes value given the parameter name.

Remarks
In a previous version of the Microsoft JDBC Driver for SQL Server, you could use
SQLServerCallableStatement.getBytes to convert values between byte arrays and SQL Server data type date ,
time , datetime2 , or datetimeoffset . Now, using this method with those data types will cause an exception
indicating that the conversion is not supported.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getBytes Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an array of bytes value given the parameter index.

Syntax
public byte[] getBytes(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
An array of byte values.

Exceptions
SQLServerException

Remarks
In a previous version of Microsoft JDBC Driver for SQL Server, you could use
SQLServerCallableStatement.getBytes to convert values between byte arrays and SQL Server data type date ,
time , datetime2 , or datetimeoffset . Now, using this method with those data types will cause an exception
indicating that the conversion is not supported.
This getBytes method is specified by the getBytes method in the java.sql.CallableStatement interface.

See Also
getBytes Method (SQLServerCallableStatement)
SQLServerCallableStatement Class
getBytes Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an array of bytes value given the parameter name.

Syntax
public byte[] getBytes(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
An array of byte values.

Exceptions
SQLServerException

Remarks
In a previous version of Microsoft JDBC Driver for SQL Server, you could use
SQLServerCallableStatement.getBytes to convert values between byte arrays and SQL Server data type date ,
time , datetime2 , or datetimeoffset . Now, using this method with those data types will cause an exception
indicating that the conversion is not supported.
This getBytes method is specified by the getBytes method in the java.sql.CallableStatement interface.

See Also
getBytes Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getCharacterStream Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.io.Reader object.

Overload List
NAME DESC RIP T IO N

getCharacterStream (int) Retrieves the value of the designated parameter as a


java.io.Reader object given the parameter index.

getCharacterStream (java.lang.String) Retrieves the value of the designated parameter as a


java.io.Reader object given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getCharacterStream (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.io.Reader object given the parameter index.

Syntax
public final java.io.Reader getCharacterStream(int paramIndex)

Parameters
paramIndex
An int that indicates the parameter index.

Return Value
A Reader object.

Exceptions
SQLServerException

See Also
getCharacterStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getCharacterStream ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.io.Reader object given the parameter name.

Syntax
public final java.io.Reader getCharacterStream(java.lang.String paramName)

Parameters
paramName
A String that indicates the parameter name.

Return Value
A Reader object.

Exceptions
SQLServerException

See Also
getCharacterStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getClob Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated JDBC BLOB parameter as a Clob object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getClob (int) Retrieves the value of the designated JDBC BLOB parameter
as a Clob object in the Java programming language given
the parameter index.

getClob (java.lang.String) Retrieves the value of the designated JDBC BLOB parameter
as a Clob object in the Java programming language given
the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getClob Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated JDBC BLOB parameter as a Clob object in the Java programming language
given the parameter index.

Syntax
public java.sql.Clob getClob(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A Clob object.

Exceptions
SQLServerException

Remarks
This getClob method is specified by the getClob method in the java.sql.CallableStatement interface.

See Also
getClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getClob Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated JDBC BLOB parameter as a Clob object in the Java programming language
given the parameter name.

Syntax
public java.sql.Clob getClob(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A Clob object.

Exceptions
SQLServerException

Remarks
This getClob method is specified by the getClob method in the java.sql.CallableStatement interface.

See Also
getClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDate Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Date object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getDate (int) Retrieves the value of the designated parameter as a


java.sql.Date object in the Java programming language given
the parameter index.

getDate (int, java.util.Calendar) Retrieves the value of the designated parameter as a


java.sql.Date object in the Java programming language given
the parameter index and Calendar object.

getDate (java.lang.String) Retrieves the value of the designated parameter as a


java.sql.Date object in the Java programming language given
the parameter name.

getDate (java.lang.String, java.util.Calendar) Retrieves the value of the designated parameter as a


java.sql.Date object in the Java programming language given
the parameter name and Calendar object.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDate Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Date object in the Java programming language
given the parameter index.

Syntax
public java.sql.Date getDate(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A Date object.

Exceptions
SQLServerException

Remarks
This getDate method is specified by the getDate method in the java.sql.CallableStatement interface.
This method returns a valid date part of a SQL Server datetime or smalldatetime data type, with the time part
set to the Java time baseline of 00:00 (midnight).

See Also
getDate Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDate Method (int, java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Date object in the Java programming language
given the parameter index and Calendar object.

Syntax
public java.sql.Date getDate(int index,
java.util.Calendar cal)

Parameters
index
An int that indicates the parameter index.
cal
A Calendar object.

Return Value
A Date object.

Exceptions
SQLServerException

Remarks
This getDate method is specified by the getDate method in the java.sql.CallableStatement interface.
This method returns a valid date part of a SQL Server datetime or smalldatetime data type, with the time part
set to the Java time baseline of 00:00 (midnight).

See Also
getDate Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDate Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Date object in the Java programming language
given the parameter name.

Syntax
public java.sql.Date getDate(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A Date object.

Exceptions
SQLServerException

Remarks
This getDate method is specified by the getDate method in the java.sql.CallableStatement interface.
This method returns a valid date part of a SQL Server datetime or smalldatetime data type, with the time part
set to the Java time baseline of 00:00 (midnight).

See Also
getDate Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDate Method ( java.lang.String,
java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Date object in the Java programming language
given the parameter name and Calendar object.

Syntax
public java.sql.Date getDate(java.lang.String sCol,
java.util.Calendar cal)

Parameters
sCol
A String that contains the parameter name.
cal
A Calendar object.

Return Value
A Date object.

Exceptions
SQLServerException

Remarks
This getDate method is specified by the getDate method in the java.sql.CallableStatement interface.
This method returns a valid date part of a SQL Server datetime or smalldatetime data type, with the time part
set to the Java time baseline of 00:00 (midnight).

See Also
getDate Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDateTimeOffset Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in MicrosoftSQL Server JDBC Driver 3.0.
Retrieves the value of the designated parameter as a DateTimeOffset Class object in the Java programming
language given the parameter index.
You can set a DateTimeOffset Class parameter value with SQLServerCallableStatement.setDateTimeOffset.

Overload List
NAME DESC RIP T IO N

getDateTimeOffset(int) Retrieves the value of the designated parameter as a


DateTimeOffset Class object in the Java programming
language given the parameter index.

getDateTimeOffset(String) Retrieves the value of the designated parameter as a


DateTimeOffset Class object in the Java programming
language given the parameter index.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDateTimeOffset Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in Microsoft SQL Server JDBC Driver 3.0.
Retrieves the value of the designated parameter as a DateTimeOffset Class object in the Java programming
language given the parameter index.

Syntax
public microsoft.sql.DateTimeOffset getDateTimeOffset(int index)

Parameters
index
The one-based parameter ordinal.

Return Value
A DateTimeOffset Class object.

Exceptions
SQLServerException

Remarks
You can set a DateTimeOffset Class parameter value with SQLServerCallableStatement.setDateTimeOffset.

See Also
getDateTimeOffset Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDateTimeOffset Method (String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in MicrosoftSQL Server JDBC Driver 3.0.
Retrieves the value of the designated parameter as a DateTimeOffset Class object in the Java programming
language given the parameter index.

Syntax
public microsoft.sql.DateTimeOffset getDateTimeOffset(String sCol)

Parameters
sCol
The name of a parameter.

Return Value
A DateTimeOffset Class object.

Exceptions
SQLServerException

Remarks
You can set a DateTimeOffset Class parameter value with SQLServerCallableStatement.setDateTimeOffset.

See Also
getDateTimeOffset Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDouble Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a double in the Java programming language.

Overload List
NAME DESC RIP T IO N

getDouble (int) Retrieves the value of the designated parameter as a double


in the Java programming language given the parameter
index.

getDouble (java.lang.String) Retrieves the value of the designated parameter as a double


in the Java programming language given the parameter
name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDouble Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a double in the Java programming language given the
parameter index.

Syntax
public double getDouble(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A double value.

Exceptions
SQLServerException

Remarks
This getDouble method is specified by the getDouble method in the java.sql.CallableStatement interface.
This method returns all number-based data types with Java double fidelity.

See Also
getDouble Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getDouble Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a double in the Java programming language given the
parameter name.

Syntax
public double getDouble(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A double value.

Exceptions
SQLServerException

Remarks
This getDouble method is specified by the getDouble method in the java.sql.CallableStatement interface.
This method returns all number-based data types with Java double fidelity.

See Also
getDouble Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getFloat Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a float in the Java programming language.

Overload List
NAME DESC RIP T IO N

getFloat (int) Retrieves the value of the designated parameter as a float in


the Java programming language given the parameter index.

getFloat (java.lang.String) Retrieves the value of the designated parameter as a float in


the Java programming language given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getFloat Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a float in the Java programming language given the
parameter index.

Syntax
public float getFloat(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A float value.

Exceptions
SQLServerException

Remarks
This getFloat method is specified by the getFloat method in the java.sql.CallableStatement interface.
This method returns all number-based types with Java float fidelity.

See Also
getFloat Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getFloat Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a float in the Java programming language given the
parameter name.

Syntax
public float getFloat(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A float value.

Exceptions
SQLServerException

Remarks
This getFloat method is specified by the getFloat method in the java.sql.CallableStatement interface.
This method returns all number-based types with Java float fidelity.

See Also
getFloat Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getInt Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an int in the Java programming language.

Overload List
NAME DESC RIP T IO N

getInt (int) Retrieves the value of the designated parameter as an int in


the Java programming language given the parameter index.

getInt (java.lang.String) Retrieves the value of the designated parameter as an int in


the Java programming language given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getInt Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an int in the Java programming language given the
parameter index.

Syntax
public int getInt(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
An int value.

Exceptions
SQLServerException

Remarks
This getInt method is specified by the getInt method in the java.sql.CallableStatement interface.
This method is supported only on SQL Server data types that can safely return an integer value such as int,
smallint, tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getInt Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getInt Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an int in the Java programming language given the
parameter name.

Syntax
public int getInt(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
An int value.

Exceptions
SQLServerException

Remarks
This getInt method is specified by the getInt method in the java.sql.CallableStatement interface.
This method is supported only on SQL Server data types that can safely return an integer value such as int,
smallint, tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getInt Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getLong Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a long in the Java programming language.

Overload List
NAME DESC RIP T IO N

getLong (int) Retrieves the value of the designated parameter as a long in


the Java programming language given the parameter index.

getLong (java.lang.String) Retrieves the value of the designated parameter as a long in


the Java programming language given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getLong Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a long in the Java programming language given the
parameter index.

Syntax
public long getLong(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A long value.

Exceptions
SQLServerException

Remarks
This getLong method is specified by the getLong method in the java.sql.CallableStatement interface.
This method is supported only on SQL Server data types that can safely return an integer value such as bigint,
int, smallint, tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getLong Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getLong Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a long in the Java programming language given the
parameter name.

Syntax
public long getLong(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A long value.

Exceptions
SQLServerException

Remarks
This getLong method is specified by the getLong method in the java.sql.CallableStatement interface.
This method is supported only on SQL Server data types that can safely return an integer value such as bigint ,
int , smallint , tinyint , and bit . Using this method on any other data types will cause an exception to be thrown.

See Also
getLong Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getNCharacterStream Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.io.Reader object.

Overload List
NAME DESC RIP T IO N

getNCharacterStream Method (int) Retrieves the value of the designated parameter as a


java.io.Reader object given the parameter index.

getNCharacterStream Method (java.lang.String) Retrieves the value of the designated parameter as a


java.io.Reader object given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getNCharacterStream Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a Reader object given the parameter index.

Syntax
public final java.io.Reader getNCharacterStream(int parameterIndex)

Parameters
parameterIndex
An int that indicates the parameter index.

Return Value
AReaderobject.

Exceptions
SQLServerException

Remarks
This method should be used when accessing NCHAR , NVARCHAR and LONGNVARCHAR parameters.
This getNCharacterStream method is specified by the getNCharacterStream method in the
java.sql.CallableStatement interface.

See Also
getNCharacterStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
getNCharacterStream Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a Reader object given the parameter name.

Syntax
public final java.io.Reader getNCharacterStream(java.lang.String columnLabel)

Parameters
columnLabel
A String that contains the column label.

Return Value
AReaderobject.

Exceptions
SQLServerException

Remarks
This method should be used when accessing NCHAR , NVARCHAR and LONGNVARCHAR parameters.
This getNCharacterStream method is specified by the getNCharacterStream method in the
java.sql.CallableStatement interface.

See Also
getNCharacterStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
getNClob Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated JDBC NCLOB parameter as an NClob object in the Java programming
language.

Overload List
NAME DESC RIP T IO N

getNClob Method (int) Retrieves the value of the designated JDBC NCLOB
parameter as an NClob object in the Java programming
language.

getNClob Method (java.lang.String) Retrieves the value of a JDBC NCLOB parameter as an


NClob object in the Java programming language.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getNClob Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated JDBC NCLOB parameter as a NClob object in the Java programming
language.

Syntax
public java.sql.NClob getNClob(int parameterIndex)

Parameters
parameterIndex
An int that indicates the parameter index.

Return Value
ANClobobject.

Exceptions
SQLServerException

Remarks
This getNClob method is specified by the getNClob method in the java.sql.CallableStatement interface.
This method only supports retrieving NCHAR , NVARCHAR , NTEXT , and XML parameters. Calling these
methods on other data type parameters will cause an exception.

See Also
getNClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
getNClob Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of a JDBC NCLOB parameter as a NClob object in the Java programming language.

Syntax
public java.sql.NClob getNClob(java.lang.String parameterName)

Parameters
parameterName
A String that contains the parameter name.

Return Value
ANClobobject.

Exceptions
SQLServerException

Remarks
This getNClob method is specified by the getNClob method in the java.sql.CallableStatement interface.
This method only supports retrieving NCHAR , NVARCHAR , NTEXT , and XML parameters. Calling these
methods on other data type parameters will cause an exception.

See Also
getNClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
getNString Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated NCHAR , NVARCHAR , or LONGNVARCHAR parameter as a String in the
Java programming language.

Overload List
NAME DESC RIP T IO N

getNString Method (int) Retrieves the value of the designated NCHAR, NVARCHAR,
or LONGNVARCHAR parameter as a String in the Java
programming language.

getNString Method (java.lang.String) Retrieves the value of the designated NCHAR, NVARCHAR,
or LONGNVARCHAR parameter as a String in the Java
programming language.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getNString Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated NCHAR , NVARCHAR , or LONGNVARCHAR parameter as a String in the
Java programming language.

Syntax
public final java.lang.String getNString(int parameterIndex)

Parameters
parameterIndex
An int that indicates the parameter index.

Return Value
AStringobject.

Exceptions
SQLServerException

Remarks
This getNString method is specified by the getNString method in the java.sql.CallableStatement interface.

See Also
getNString Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
getNString Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated NCHAR , NVARCHAR , or LONGNVARCHAR parameter as a String in the
Java programming language.

Syntax
public final java.lang.String getNString(java.lang.String parameterName)

Parameters
parameterName
A String that contains the parameter name.

Return Value
AStringobject.

Exceptions
SQLServerException

Remarks
This getNString method is specified by the getNString method in the java.sql.CallableStatement interface.

See Also
getNString Method (SQLServerCallableStatement)
SQLServerCallableStatement Methods
getObject Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getObject (int) Retrieves the value of the designated parameter as an object


in the Java programming language given the parameter
index.

getObject (int, java.util.Map) Retrieves the value of the designated parameter as an object
in the Java programming language given the parameter
index, using the given Map object.

getObject (java.lang.String) Retrieves the value of the designated parameter as an object


in the Java programming language given the parameter
name.

getObject (java.lang.String, java.util.Map) Retrieves the value of the designated parameter as an object
in the Java programming language given the parameter
name, using the given Map object.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getObject Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an object in the Java programming language given the
parameter index.

Syntax
public java.lang.Object getObject(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
An Object value.

Exceptions
SQLServerException

Remarks
This getObject method is specified by the getObject method in the java.sql.CallableStatement interface.
This method will return the value of the given column as a Java object. The type of the Java object will be the
default Java object type corresponding to the SQL type of the column, following the mapping for built-in types
that is specified in the JDBC specification. If the value is an SQL NULL, the driver returns a Java null.
This method can also be used to read database-specific abstract data types. In JDBC 2.0, the behavior of the
getObject method was extended to materialize data of SQL user-defined types. When a column contains a
structured or distinct value, the behavior of this method is as if it were a call to
getObject(columnIndex, this.getStatement().getConnection().getTypeMap()) .

Beginning in the SQL Server JDBC Driver 3.0:


A value of type date will be returned as a java.sql.Date object.
A value of type time will be returned as a java.sql.Time object.
A value of type datetime2 will be returned as a java.sql.Timestamp object.
A value of type datetimeoffset will be returned as a microsoft.sql.DateTimeOffset object.

See Also
getObject Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getObject Method (int, java.util.Map)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an object in the Java programming language given the
parameter index, using the given Map object.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server. Using this method will always return
the default mapping.

Syntax
public java.lang.Object getObject(int index,
java.util.Map map)

Parameters
index
An int that indicates the parameter index.
map
A Map object.

Return Value
An Object value.

Exceptions
SQLServerException

Remarks
This getObject method is specified by the getObject method in the java.sql.CallableStatement interface.
This method will return the value of the given column as a Java object. The type of the Java object will be the
default Java object type corresponding to the SQL type of the column, following the mapping for built-in types
that is specified in the JDBC specification. If the value is an SQL NULL, the driver returns a Java null.
This method can also be used to read database-specific abstract data types. In the JDBC 2.0 API, the behavior of
the getObject method is extended to materialize data of SQL user-defined types. When a column contains a
structured or distinct value, the behavior of this method is as if it were a call to
getObject(columnIndex, this.getStatement().getConnection().getTypeMap()) .

Beginning in the SQL Server JDBC Driver 3.0:


A value of type date will be returned as a java.sql.Date object.
A value of type time will be returned as a java.sql.Time object.
A value of type datetime2 will be returned as a java.sql.Timestamp object.
A value of type datetimeoffset will be returned as a microsoft.sql.DateTimeOffset object.

See Also
getObject Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getObject Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an object in the Java programming language given the
parameter name.

Syntax
public java.lang.Object getObject(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
An Object value.

Exceptions
SQLServerException

Remarks
This getObject method is specified by the getObject method in the java.sql.CallableStatement interface.
This method will return the value of the given column as a Java object. The type of the Java object will be the
default Java object type corresponding to the SQL type of the column, following the mapping for built-in types
that is specified in the JDBC specification. If the value is an SQL NULL, the driver returns a Java null.
This method can also be used to read database-specific abstract data types. In the JDBC 2.0 API, the behavior of
the getObject method is extended to materialize data of SQL user-defined types. When a column contains a
structured or distinct value, the behavior of this method is as if it were a call to
getObject(columnIndex, this.getStatement().getConnection().getTypeMap()) .

Beginning in the SQL Server JDBC Driver 3.0:


A value of type date will be returned as a java.sql.Date object.
A value of type time will be returned as a java.sql.Time object.
A value of type datetime2 will be returned as a java.sql.Timestamp object.
A value of type datetimeoffset will be returned as a microsoft.sql.DateTimeOffset object.

See Also
getObject Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getObject Method ( java.lang.String, java.util.Map)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as an object in the Java programming language given the
parameter name, by using the given Map object.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server. Using this method will always return
the default mapping.

Syntax
public java.lang.Object getObject(java.lang.String sCol,
java.util.Map m)

Parameters
sCol
A String that contains the parameter name.
m
A Map object.

Return Value
An Object value.

Exceptions
SQLServerException

Remarks
This getObject method is specified by the getObject method in the java.sql.CallableStatement interface.
This method will return the value of the given column as a Java object. The type of the Java object will be the
default Java object type corresponding to the SQL type of the column, following the mapping for built-in types
that is specified in the JDBC specification. If the value is an SQL NULL, the driver returns a Java null.
This method can also be used to read database-specific abstract data types. In the JDBC 2.0 API, the behavior of
the getObject method is extended to materialize data of SQL user-defined types. When a column contains a
structured or distinct value, the behavior of this method is as if it were a call to
getObject(columnIndex, this.getStatement().getConnection().getTypeMap()) .

Beginning in the SQL Server JDBC Driver 3.0:


A value of type date will be returned as a java.sql.Date object.
A value of type time will be returned as a java.sql.Time object.
A value of type datetime2 will be returned as a java.sql.Timestamp object.
A value of type datetimeoffset will be returned as a microsoft.sql.DateTimeOffset object.

See Also
getObject Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getRef Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a Ref object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getRef (int) Retrieves the value of the designated parameter as a Ref


object in the Java programming language given the
parameter index.

getRef (java.lang.String) Retrieves the value of the designated parameter as a Ref


object in the Java programming language given the
parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getRef Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a Ref object in the Java programming language given the
parameter index.

Syntax
public java.sql.Ref getRef(int i)

Parameters
i
An int that indicates the parameter index.

Return Value
A Ref object.

Exceptions
SQLServerException

Remarks
This getRef method is specified by the getRef method in the java.sql.CallableStatement interface.

See Also
getRef Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getRef Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a Ref object in the Java programming language given the
parameter name.

Syntax
public java.sql.Ref getRef(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A Ref object.

Exceptions
SQLServerException

Remarks
This getRef method is specified by the getRef method in the java.sql.CallableStatement interface.

See Also
getRef Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getShort Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a shor t in the Java programming language.

Overload List
NAME DESC RIP T IO N

getShort (int) Retrieves the value of the designated parameter as a shor t


in the Java programming language given the parameter
index.

getShort (java.lang.String) Retrieves the value of the designated parameter as a shor t


in the Java programming language given the parameter
name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getShort Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a shor t in the Java programming language given the
parameter index.

Syntax
public short getShort(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A shor t value.

Exceptions
SQLServerException

Remarks
This getShort method is specified by the getShort method in the java.sql.CallableStatement interface.
This method is supported only on SQL Server data types that can safely return an integer value such as
smallint , tinyint , and bit . Using this method on any other data types will cause an exception to be thrown.

See Also
getShort Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getShort Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a shor t in the Java programming language given the
parameter name.

Syntax
public short getShort(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A shor t value.

Exceptions
SQLServerException

Remarks
This getShort method is specified by the getShort method in the java.sql.CallableStatement interface.
This method is only supported on SQL Server data types that can safely return an integer value such as smallint,
tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getShort Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getSQLXML Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.SQLXML object.

Overload List
NAME DESC RIP T IO N

getSQLXML Method (int) Retrieves the value of the designated parameter as a


SQLXML object given the parameter index.

getSQLXML Method (java.lang.String) Retrieves the value of the designated parameter as a


SQLXML object given the parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getSQLXML Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a SQLXML object given the parameter index.

Syntax
public final java.sql.SQLXML getSQLXML(int parameterIndex)

Parameters
parameterIndex
An int that indicates the parameter index.

Return Value
ASQLXMLobject.

Exceptions
SQLServerException

Remarks
This getSQLXML method is specified by the getSQLXML method in the java.sql.CallableStatement interface.

See Also
getSQLXML Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
getSQLXML Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a SQLXML object given the parameter name.

Syntax
public final java.sql.SQLXML getSQLXML(java.lang.String parameterName)

Parameters
parameterName
A String that indicates the parameter name.

Return Value
ASQLXMLobject.

Exceptions
SQLServerException

Remarks
This getSQLXML method is specified by the getSQLXML method in the java.sql.CallableStatement interface.

See Also
getSQLXML Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
getString Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a String in the Java programming language.

Overload List
NAME DESC RIP T IO N

getString (int) Retrieves the value of the designated parameter as a String


in the Java programming language given the parameter
index.

getString (java.lang.String) Retrieves the value of the designated parameter as a String


in the Java programming language given the parameter
name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getString Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a String in the Java programming language given the
parameter index.

Syntax
public java.lang.String getString(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A String value.

Exceptions
SQLServerException

Remarks
This getString method is specified by the getString method in the java.sql.CallableStatement interface.
All columns in SQL Server can be returned as a string. This means that a string representation of all number-
based and character-based types, and a hex-string representation of binary columns such as binary, varbinary,
varbinary(max), image, timestamp, and uniqueidentifier, can be returned.
Location-sensitive types such as money, smallmoney, datetime, smalldatetime, float, real, decimal, and numeric
will return the canonical toString() format for the underlying value of the type.
User-defined types are returned as hexadecimal string values.

See Also
getString Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getString Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a String in the Java programming language given the
parameter name.

Syntax
public java.lang.String getString(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A String value.

Exceptions
SQLServerException

Remarks
This getString method is specified by the getString method in the java.sql.CallableStatement interface.
All columns in SQL Server can be returned as a string. This means that a string representation of all number-
based and character-based types, and a hex-string representation of binary columns such as binary, varbinary,
varbinary(max), image, timestamp, and uniqueidentifier, can be returned.
Location-sensitive types such as money, smallmoney, datetime, smalldatetime, float, real, decimal, and numeric
will return the canonical toString() format for the underlying value of the type.
User-defined types are returned as hexadecimal string values.

See Also
getString Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTime Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Time object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getTime (int) Retrieves the value of the designated parameter as a


java.sql.Time object in the Java programming language given
the parameter index.

getTime (int, java.util.Calendar) Retrieves the value of the designated parameter as a


java.sql.Time object in the Java programming language given
the parameter index, using the given Calendar object.

getTime (java.lang.String) Retrieves the value of the designated parameter as a


java.sql.Time object in the Java programming language given
the parameter name.

getTime (java.lang.String, java.util.Calendar) Retrieves the value of the designated parameter as a


java.sql.Time object in the Java programming language given
the parameter name, using the given Calendar object.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTime Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Time object in the Java programming language
given the parameter index.

Syntax
public java.sql.Time getTime(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A Time object.

Exceptions
SQLServerException

Remarks
This getTime method is specified by the getTime method in the java.sql.CallableStatement interface.
See the chart titled "Getter Method Conversions" in Understanding Data Type Conversions to see which SQL
Server data types can be retrieved with this method.

See Also
getTime Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTime Method (int, java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Time object in the Java programming language,
given the parameter index, by using the given Calendar object.

Syntax
public java.sql.Time getTime(int index,
java.util.Calendar cal)

Parameters
index
An int that indicates the parameter index.
cal
A Calendar object.

Return Value
A Time object.

Exceptions
SQLServerException

Remarks
This getTime method is specified by the getTime method in the java.sql.CallableStatement interface.
See the chart titled "Getter Method Conversions" in Understanding Data Type Conversions to see which SQL
Server data types can be retrieved with this method.

See Also
getTime Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTime Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Time object in the Java programming language
given the parameter name.

Syntax
public java.sql.Time getTime(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A Time object.

Exceptions
SQLServerException

Remarks
This getTime method is specified by the getTime method in the java.sql.CallableStatement interface.
See the chart titled "Getter Method Conversions" in Understanding Data Type Conversions to see which SQL
Server data types can be retrieved with this method.

See Also
getTime Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTime Method ( java.lang.String,
java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Time object in the Java programming language,
given the parameter name, by using the given Calendar object.

Syntax
public java.sql.Time getTime(java.lang.String sCol,
java.util.Calendar cal)

Parameters
sCol
A String that contains the parameter name.
cal
A Calendar object.

Return Value
A Time object.

Exceptions
SQLServerException

Remarks
This getTime method is specified by the getTime method in the java.sql.CallableStatement interface.
See the chart titled "Getter Method Conversions" in Understanding Data Type Conversions to see which SQL
Server data types can be retrieved with this method.

See Also
getTime Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTimestamp Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Timestamp object in the Java programming
language.

Overload List
NAME DESC RIP T IO N

getTimestamp (int) Retrieves the value of the designated parameter as a


java.sql.Timestamp object in the Java programming language
given the parameter index.

getTimestamp (int, java.util.Calendar) Retrieves the value of the designated parameter as a


java.sql.Timestamp object in the Java programming language
given the parameter index, using a Calendar object.

getTimestamp (java.lang.String) Retrieves the value of the designated parameter as a


java.sql.Timestamp object in the Java programming language
given the parameter name.

getTimestamp (java.lang.String, java.util.Calendar) Retrieves the value of the designated parameter as a


java.sql.Timestamp object in the Java programming language
given the parameter name, using a Calendar object.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTimestamp Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Timestamp object in the Java programming
language given the parameter index.

Syntax
public java.sql.Timestamp getTimestamp(int index)

Parameters
index
An int that indicates the parameter index.

Return Value
A Timestamp object.

Exceptions
SQLServerException

Remarks
This getTimestamp method is specified by the getTimestamp method in the java.sql.CallableStatement interface.
This method returns values only from SQL Server datetime and smalldatetime columns.

See Also
getTimestamp Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTimestamp Method (int, java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Timestamp object in the Java programming
language, given the parameter index, by using a Calendar object.

Syntax
public java.sql.Timestamp getTimestamp(int index,
java.util.Calendar cal)

Parameters
index
An int that indicates the parameter index.
cal
A Calendar object.

Return Value
A Timestamp object.

Exceptions
SQLServerException

Remarks
This getTimestamp method is specified by the getTimestamp method in the java.sql.CallableStatement interface.
This method returns values only from SQL Server datetime and smalldatetime columns.

See Also
getTimestamp Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTimestamp Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Timestamp object in the Java programming
language given the parameter name.

Syntax
public java.sql.Timestamp getTimestamp(java.lang.String sCol)

Parameters
sCol
A String that contains the parameter name.

Return Value
A Timestamp object.

Exceptions
SQLServerException

Remarks
This getTimestamp method is specified by the getTimestamp method in the java.sql.CallableStatement interface.
This method returns values only from SQL Server datetime and smalldatetime columns.

See Also
getTimestamp Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getTimestamp Method ( java.lang.String,
java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a java.sql.Timestamp object in the Java programming
language, given the parameter name, by using a Calendar object.

Syntax
public java.sql.Timestamp getTimestamp(java.lang.String name,
java.util.Calendar cal)

Parameters
name
A String that contains the parameter name.
cal
A Calendar object.

Return Value
A Timestamp object.

Exceptions
SQLServerException

Remarks
This getTimestamp method is specified by the getTimestamp method in the java.sql.CallableStatement interface.
This method returns values only from SQL Server datetime and smalldatetime columns.

See Also
getTimestamp Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getURL Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a URL object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getURL (int) Retrieves the value of the designated parameter as a URL


object in the Java programming language given the
parameter index.

getURL (java.lang.String) Retrieves the value of the designated parameter as a URL


object in the Java programming language given the
parameter name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getURL Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a URL object in the Java programming language given the
parameter index.

Syntax
public java.net.URL getURL(int n)

Parameters
n
An int that indicates the parameter index.

Return Value
A URL object.

Exceptions
SQLServerException

Remarks
This getURL method is specified by the getURL method in the java.sql.CallableStatement interface.

See Also
getURL Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
getURL Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated parameter as a URL object in the Java programming language given the
parameter name.

Syntax
public java.net.URL getURL(java.lang.String s)

Parameters
s
A String that contains the parameter name.

Return Value
A URL object.

Exceptions
SQLServerException

Remarks
This getURL method is specified by the getURL method in the java.sql.CallableStatement interface.

See Also
getURL Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
isWrapperFor Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this statement object is a wrapper for the specified interface.

Syntax
public boolean isWrapperFor(Class iface)

Parameters
iface
A class defining an interface.

Return Value
true if this object implements the interface or wraps an object that implements the interface. Otherwise, false .

Exceptions
SQLServerException

Remarks
The isWrapperFor method and the unwrap method are defined by the java.sql.Wrapper interface, which is
introduced in JDBC 4.0.
If this method returns true , calling unwrap with the same argument will succeed.
For more information, see Wrappers and Interfaces.

See Also
unwrap Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
registerOutParameter Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Registers the OUT parameter.

Overload List
NAME DESC RIP T IO N

registerOutParameter (int, int) Registers the OUT parameter in the specified ordinal position
to the given JDBC type.

registerOutParameter (int, int, int) Registers the OUT parameter in the specified ordinal position
to the given JDBC type and scale.

registerOutParameter (int, int, java.lang.String) Registers the OUT parameter in the specified ordinal position
to the given JDBC type and type name.

registerOutParameter (java.lang.String, int) Registers the OUT parameter with the specified name to the
given JDBC type.

registerOutParameter (java.lang.String, int, int) Registers the OUT parameter with the specified name to the
given JDBC type and scale.

registerOutParameter (java.lang.String, int, java.lang.String) Registers the OUT parameter with the specified name to the
given JDBC type and type name.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
registerOutParameter Method (int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Registers the OUT parameter in the specified ordinal position to the given JDBC type.

Syntax
public void registerOutParameter(int index,
int sqlType)

Parameters
index
An int that indicates the ordinal position of the parameter.
sqlType
A JDBC type code as defined in java.sql.Types.

Exceptions
SQLServerException

Remarks
This registerOutParameter method is specified by the registerOutParameter method in the
java.sql.CallableStatement interface.
Beginning with SQL Server JDBC Driver 3.0, when sqlType is of type java.sql.Types.TIME, the behavior of this
method is modified by the sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
registerOutParameter Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
registerOutParameter Method (int, int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Registers the OUT parameter in the specified ordinal position to the given JDBC type and scale.

Syntax
public void registerOutParameter(int index,
int sqlType,
int scale)

Parameters
index
An int that indicates the ordinal position of the parameter.
sqlType
A JDBC type code as defined in java.sql.Types.
scale
An int that indicates the number of digits to be placed to the right of the decimal point.

Exceptions
SQLServerException

Remarks
This registerOutParameter method is specified by the registerOutParameter method in the
java.sql.CallableStatement interface.
Beginning with SQL Server JDBC Driver 3.0, when sqlType is of type java.sql.Types.TIME, the behavior of this
method is modified by the sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
registerOutParameter Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
registerOutParameter Method (int, int,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Registers the OUT parameter in the specified ordinal position to the given JDBC type and type name.

Syntax
public void registerOutParameter(int index,
int sqlType,
java.lang.String typeName)

Parameters
index
An int that indicates the ordinal position of the parameter.
sqlType
A JDBC type code as defined in java.sql.Types.
typeName
A String that contains the fully qualified SQL type name.

Exceptions
SQLServerException

Remarks
This registerOutParameter method is specified by the registerOutParameter method in the
java.sql.CallableStatement interface.
Beginning with SQL Server JDBC Driver 3.0, when sqlType is of type java.sql.Types.TIME, the behavior of this
method is modified by the sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
registerOutParameter Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
registerOutParameter Method ( java.lang.String, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Registers the OUT parameter with the specified name to the given JDBC type.

Syntax
public void registerOutParameter(java.lang.String s,
int n)

Parameters
s
A String that contains the parameter name.
n
A JDBC type code as defined in java.sql.Types.

Exceptions
SQLServerException

Remarks
This registerOutParameter method is specified by the registerOutParameter method in the
java.sql.CallableStatement interface.

See Also
registerOutParameter Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
registerOutParameter Method ( java.lang.String, int,
int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Registers the OUT parameter with the specified name to the given JDBC type and scale.

Syntax
public void registerOutParameter(java.lang.String s,
int n,
int n1)

Parameters
s
A String that contains the parameter name.
sqlType
A JDBC type code as defined in java.sql.Types.
scale
An int that indicates the number of digits to be placed to the right of the decimal point.

Exceptions
SQLServerException

Remarks
This registerOutParameter method is specified by the registerOutParameter method in the
java.sql.CallableStatement interface.

See Also
registerOutParameter Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
registerOutParameter Method ( java.lang.String, int,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Registers the OUT parameter with the specified name to the given JDBC type and type name.

Syntax
public void registerOutParameter(java.lang.String s,
int n,
java.lang.String s1)

Parameters
s
A String that contains the parameter name.
n
A JDBC type code as defined in java.sql.Types.
s1
A String that contains the fully qualified SQL type name.

Exceptions
SQLServerException

Remarks
This registerOutParameter method is specified by the registerOutParameter method in the
java.sql.CallableStatement interface.

See Also
registerOutParameter Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setAsciiStream (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter number to the specified input stream.

Overload List
NAME DESC RIP T IO N

setAsciiStream Method (java.lang.String, java.io.InputStream) Sets the designated parameter to the specified input stream.

setAsciiStream Method (java.lang.String, java.io.InputStream, Sets the designated parameter to the specified input stream,
int) which will have the specified number of bytes.

setAsciiStream Method (java.lang.String, java.io.InputStream, Sets the designated parameter number to specified input
long) stream, which will have the specified number of bytes.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setAsciiStream Method ( java.lang.String,
java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified input stream.

Syntax
public final void setAsciiStream(java.lang.String parameterName,
java.io.InputStream x)

Parameters
parameterName
A String that contains the parameter name.
x
An InputStream object.

Exceptions
SQLServerException

Remarks
This setAsciiStream method is specified by the setAsciiStream method in the java.sql.PreparedStatement
interface.

See Also
setAsciiStream (SQLServerCallableStatement)
SQLServerCallableStatement Members
setAsciiStream Method ( java.lang.String,
java.io.InputStream, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given input stream, which will have the specified number of bytes.

Syntax
public void setAsciiStream(java.lang.String parameterName,
java.io.InputStream value,
int length)

Parameters
parameterName
A String that contains the parameter name.
value
An InputStream object.
length
An int that indicates the length in number of bytes.

Exceptions
SQLServerException

Remarks
This setAsciiStream method is specified by the setAsciiStream method in the java.sql.CallableStatement interface.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setAsciiStream Method ( java.lang.String, java.io.InputStream) when the application wants to update the column
from a stream whose length is unknown.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setAsciiStream Method ( java.lang.String,
java.io.InputStream, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specifiedinput stream, which will have the specified number of bytes.

Syntax
public final void setAsciiStream(java.lang.String parameterName,
java.io.InputStream x,
long length)

Parameters
parameterName
A String that contains the parameter name.
x
An InputStream object.
length
A long that indicates the number of bytes.

Exceptions
SQLServerException

Remarks
This setAsciiStream method is specified by the setAsciiStream method in the java.sql.PreparedStatement
interface.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setAsciiStream Method ( java.lang.String, java.io.InputStream) when the application wants to update the column
from a stream whose length is unknown.

See Also
setAsciiStream (SQLServerCallableStatement)
SQLServerCallableStatement Members
setBigDecimal Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter number to the given BigDecimal object.

Syntax
public void setBigDecimal(java.lang.String sCol,
java.math.BigDecimal bd)

Parameters
sCol
A String that contains the parameter name.
bd
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This setBigDecimal method is specified by the setBigDecimal method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setBinaryStream (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified input stream.

Overload List
NAME DESC RIP T IO N

setBinaryStream Method (java.lang.String, Sets the designated parameter to the specified input stream.
java.io.InputStream)

setBinaryStream Method (java.lang.String, Sets the designated parameter to the specified input stream,
java.io.InputStream, int) which will have the specified number of bytes.

setBinaryStream Method (java.lang.String, Sets the designated parameter to the specified input stream,
java.io.InputStream, long) which will have the specified number of bytes.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setBinaryStream Method ( java.lang.String,
java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified input stream.

Syntax
public void setBinaryStream(java.lang.String parameterName,
java.io.InputStream x)

Parameters
parameterName
A String that contains the name of the parameter.
x
An InputStream object.

Exceptions
SQLServerException

Remarks
This setBinaryStream method is specified by the setBinaryStream method in the java.sql.CallableStatement
interface.

See Also
setBinaryStream (SQLServerCallableStatement)
SQLServerCallableStatement Members
setBinaryStream Method ( java.lang.String,
java.io.InputStream, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified input stream, which will have the specified number of bytes.

Syntax
public void setBinaryStream(java.lang.String parameterName,
java.io.InputStream value,
int length)

Parameters
parameterName
A String that contains the name of the parameter.
value
An InputStream object.
length
An int that indicates the length in number of bytes.

Exceptions
SQLServerException

Remarks
This setBinaryStream method is specified by the setBinaryStream method in the java.sql.CallableStatement
interface.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setBinaryStream Method ( java.lang.String, java.io.InputStream) when the application wants to update the
column from a stream whose length is unknown.

See Also
setBinaryStream (SQLServerCallableStatement)
SQLServerCallableStatement Members
setBinaryStream Method ( java.lang.String,
java.io.InputStream, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified input stream, which will have the specified number of bytes.

Syntax
public void setBinaryStream(java.lang.String parameterName,
java.io.InputStream x,
long length)

Parameters
parameterName
A String that contains the name of the parameter.
x
An InputStream object.
length
A long that indicates the length in the number of bytes.

Exceptions
SQLServerException

Remarks
This setBinaryStream method is specified by the setBinaryStream method in the java.sql.CallableStatement
interface.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setBinaryStream Method ( java.lang.String, java.io.InputStream) when the application wants to update the
column from a stream whose length is unknown.

See Also
setBinaryStream (SQLServerCallableStatement)
SQLServerCallableStatement Members
setBoolean Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given boolean value.

Syntax
public void setBoolean(java.lang.String sCol,
boolean b)

Parameters
sCol
A String that contains the parameter name.
b
A boolean value, either true or false .

Exceptions
SQLServerException

Remarks
This setBoolean method is specified by the setBoolean method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setByte Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given byte value.

Syntax
public void setByte(java.lang.String sCol,
byte b)

Parameters
sCol
A String that contains the parameter name.
b
A byte value.

Exceptions
SQLServerException

Remarks
This setByte method is specified by the setByte method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setBytes Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given array of byte values.

Syntax
public void setBytes(java.lang.String sCol,
byte[] b)

Parameters
sCol
A String that contains the parameter name.
b
An array of byte values.

Exceptions
SQLServerException

Remarks
In a previous version of the driver, you could use SQLServerCallableStatement.setBytes to convert values
between byte arrays and SQL Server data type date , time , datetime2 , or datetimeoffset . Now, using this
method with those data types will cause an exception indicating that the conversion is not supported.
This setBytes method is specified by the setBytes method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setCharacterStream Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified java.io.Reader object.

Overload List
NAME DESC RIP T IO N

setCharacterStream Method (java.lang.String, java.io.Reader) Sets the designated parameter to the specified java.io.Reader
object.

setCharacterStream Method (java.lang.String, java.io.Reader, Sets the designated parameter to the specified java.io.Reader
int) object, which is the specified number of characters long.

setCharacterStream Method (java.lang.String, java.io.Reader, Sets the designated parameter to the specified java.io.Reader
long) object, which is the specified number of characters long.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setCharacterStream Method ( java.lang.String,
java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object.

Syntax
public final void setCharacterStream(java.lang.String parameterName,
java.io.Reader reader)

Parameters
parameterName
A String that contains the parameter name.
reader
A Reader object that contains the Unicode data.

Exceptions
SQLServerException

Remarks
This setCharacterStream method is specified by the setCharacterStream method in the
java.sql.CallableStatement interface.

See Also
setCharacterStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setCharacterStream Method ( java.lang.String,
java.io.Reader, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specifiedReader object, which is the specifiednumber of characters long.

Syntax
public final void setCharacterStream(java.lang.String parameterName,
java.io.Reader value,
int length)

Parameters
parameterName
A String that contains the name of the parameter.
value
A Reader object that contains the Unicode data.
length
An int that indicates the length in number of characters.

Exceptions
SQLServerException

Remarks
This setCharacterStream method is specified by the setCharacterStream method in the
java.sql.CallableStatement interface.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setCharacterStream Method ( java.lang.String, java.io.Reader) when the application wants to update the column
from a stream whose length is unknown.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setCharacterStream Method ( java.lang.String,
java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified java.io.Reader object, which is the specified number of characters
long.

Syntax
public final void setCharacterStream(java.lang.String parameterName
java.io.Reader reader,
long length)

Parameters
parameterName
A String that contains the parameter name.
reader
A Reader object that contains the Unicode data.
length
A long that indicates the number of characters in the stream.

Exceptions
SQLServerException

Remarks
This setCharacterStream method is specified by the setCharacterStream method in the
java.sql.CallableStatement interface.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setCharacterStream Method ( java.lang.String, java.io.Reader) when the application wants to update the column
from a stream whose length is unknown.

See Also
setCharacterStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setClob Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified object.

Overload List
NAME DESC RIP T IO N

setClob Method (java.lang.String, java.sql.Clob) Sets the designated parameter to the specified Clob object.

setClob Method (java.lang.String, java.io.Reader) Sets the designated parameter to the specified Reader
object.

setClob Method (java.lang.String, java.io.Reader, long) Sets the designated parameter to the specified Reader
object, which is the specified number of characters long.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setClob Method ( java.lang.String, java.sql.Clob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Clob object.

Syntax
public final void setClob(java.lang.String parameterName,
java.sql.Clob x)

Parameters
parameterName
A String that contains the parameter name.
x
A Clob object.

Exceptions
SQLServerException

Remarks
This setClob method is specified by the setClob method in the java.sql.CallableStatement interface.

See Also
setClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setClob Method ( java.lang.String, java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object.

Syntax
public final void setClob(java.lang.String parameterName,
java.io.Reader reader)

Parameters
parameterName
A String that contains the parameter name.
reader
A Reader object.

Exceptions
SQLServerException

Remarks
This setClob method is specified by the setClob method in the java.sql.CallableStatement interface.

See Also
setClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setClob Method ( java.lang.String, java.io.Reader,
long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object, which is the specified number of characters long.

Syntax
public final void setClob(java.lang.String parameterName,
java.io.Reader value,
long length)

Parameters
parameterName
A String that contains the parameter name.
value
A Reader object.
length
A long that indicates the number of characters in the stream.

Exceptions
SQLServerException

Remarks
This setClob method is specified by the setClob method in the java.sql.CallableStatement interface.

See Also
setClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setDate Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given date value.

Overload List
NAME DESC RIP T IO N

setDate (java.lang.String, java.sql.Date) Sets the designated parameter to the given date value.

setDate (java.lang.String, java.sql.Date, java.util.Calendar) Sets the designated parameter to the given date and
calendar values.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setDate Method ( java.lang.String, java.sql.Date)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given date value.

Syntax
public void setDate(java.lang.String sCol,
java.sql.Date d)

Parameters
sCol
A String that contains the parameter name.
d
A Date object.

Exceptions
SQLServerException

Remarks
This setDate method is specified by the setDate method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setDate Method ( java.lang.String, java.sql.Date,
java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given date and calendar values.

Syntax
public void setDate(java.lang.String sCol,
java.sql.Date x,
java.util.Calendar c)

Parameters
n
An int that indicates the parameter number.
x
A Date object.
c
A Calendar object.

Exceptions
SQLServerException

Remarks
This setDate method is specified by the setDate method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setDateTimeOffset Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in MicrosoftSQL Server JDBC Driver 3.0.
Sets the value of the column specified to the DateTimeOffset Class value.

Syntax
public void setDateTimeOffset(String sCol, microsoft.sql.DateTimeOffset t)

Parameters
sCol
The name of a column.
t
The DateTimeOffset Class object.

Exceptions
SQLServerException

Remarks
You can retrieve a DateTimeOffset Class value with SQLServerCallableStatement.getDateTimeOffset.
setDateTimeOffset takes the ordinal of the column.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setDouble Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given double value.

Syntax
public void setDouble(java.lang.String sCol,
double d)

Parameters
sCol
A String that contains the parameter name.
d
A double value.

Exceptions
SQLServerException

Remarks
This setDouble method is specified by the setDouble method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setFloat Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given float value.

Syntax
public void setFloat(java.lang.String sCol,
float f)

Parameters
sCol
A String that contains the parameter name.
f
A float value.

Exceptions
SQLServerException

Remarks
This setFloat method is specified by the setFloat method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setInt Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given int value.

Syntax
public void setInt(java.lang.String sCol,
int i)

Parameters
sCol
A String that contains the parameter name.
i
An int value.

Exceptions
SQLServerException

Remarks
This setInt method is specified by the setInt method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setLong Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given long value.

Syntax
public void setLong(java.lang.String sCol,
long l)

Parameters
sCol
A String that contains the parameter name.
l
A long value.

Exceptions
SQLServerException

Remarks
This setLong method is specified by the setLong method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setNCharacterStream Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object.

Overload List
NAME DESC RIP T IO N

setNCharacterStream Method (java.lang.String, Sets the designated parameter to the specified Reader
java.io.Reader) object.

setNCharacterStream Method (java.lang.String, Sets the designated parameter to the specified Reader
java.io.Reader, long) object, which is the specified number of characters long.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setNCharacterStream Method ( java.lang.String,
java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object.

Syntax
public final void setNCharacterStream(java.lang.String parameterName,
java.io.Reader value)

Parameters
parameterName
A String that indicates the parameter name.
value
A Reader object.

Exceptions
SQLServerException

Remarks
This setNCharacterStream method is specified by the setNCharacterStream method in the
java.sql.CallableStatement interface.
This method should be used for NCHAR , NVARCHAR , NTEXT , and XML data types.

See Also
setNCharacterStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setNCharacterStream Method ( java.lang.String,
java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object, which is the specified number of characters long.

Syntax
public final void setNCharacterStream(java.lang.String parameterName,
java.io.Reader value,
long length)

Parameters
parameterName
A String that indicates the parameter name.
value
A Reader object.
length
A long that indicates the number of characters in the stream.

Exceptions
SQLServerException

Remarks
This setNCharacterStream method is specified by the setNCharacterStream method in the
java.sql.CallableStatement interface.
This method should be used for NCHAR , NVARCHAR , NTEXT , and XML data types.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setNCharacterStream Method ( java.lang.String, java.io.Reader) when the application wants to update the column
from a stream whose length is unknown.

See Also
setNCharacterStream Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setNClob Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified object.

Overload List
NAME DESC RIP T IO N

setNClob Method (java.lang.String, java.sql.NClob) Sets the designated parameter to the specified NClob object.

setNClob Method (java.lang.String, java.io.Reader) Sets the designated parameter to the specified Reader
object.

setNClob Method (java.lang.String, java.io.Reader, long) Sets the designated parameter to the specified Reader
object, which is the specified number of characters long.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setNClob Method ( java.lang.String, java.sql.NClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified NClob object.

Syntax
public final void setNClob(java.lang.String parameterName,
java.sql.NClob value)

Parameters
parameterName
A String that contains the parameter name.
value
A NClob object.

Exceptions
SQLServerException

Remarks
This method should be used for NCHAR , NVARCHAR , NTEXT , and XML parameter data types.
This setNClob method is specified by the setNClob method in the java.sql.CallableStatement interface.

See Also
setNClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setNClob Method ( java.lang.String, java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object.

Syntax
public final void setNClob(java.lang.String parameterName,
java.io.Reader reader)

Parameters
parameterName
A String that contains the parameter name.
reader
A Reader object.

Exceptions
SQLServerException

Remarks
This method should be used for NCHAR , NVARCHAR , NTEXT , and XML parameter data types.
This setNClob method is specified by the setNClob method in the java.sql.CallableStatement interface.

See Also
setNClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setNClob Method ( java.lang.String, java.io.Reader,
long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object, which is the specified number of characters long.

Syntax
public final void setNClob(java.lang.String parameterName,
java.io.Reader reader,
long length)

Parameters
parameterName
A String that contains the parameter name.
reader
A Reader object.
length
A long that indicates the number of characters in the stream.

Exceptions
SQLServerException

Remarks
This method should be used for NCHAR , NVARCHAR , NTEXT , and XML parameter data types.
This setNClob method is specified by the setNClob method in the java.sql.CallableStatement interface.

See Also
setNClob Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
setNull Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to a null value, given the type of parameter to set.

Overload List
NAME DESC RIP T IO N

setNull (java.lang.String, int) Sets the designated parameter to a null value, given the type
of parameter to set.

setNull (java.lang.String, int, java.lang.String) Sets the designated parameter to a null value, given the type
and name of the parameter to set.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setNull Method ( java.lang.String, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to a null value, given the type of parameter to set.

Syntax
public void setNull(java.lang.String sCol,
int nType)

Parameters
sCol
A String that contains the parameter name.
nType
A JDBC type code that is defined by java.sql.Types.

Exceptions
SQLServerException

Remarks
This setNull method is specified by the setNull method in the java.sql.CallableStatement interface.

See Also
setNull Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setNull Method ( java.lang.String, int,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to a null value, given the type and name of the parameter to set.

Syntax
public void setNull(java.lang.String sCol,
int nType,
java.lang.String sTypeName)

Parameters
sCol
A String contthat contains aining the parameter name.
nType
A JDBC type code that is defined by java.sql.Types.
sTypeName
A String that indicates the fully qualified name of the parameter that is being set.

Exceptions
SQLServerException

Remarks
This setNull method is specified by the setNull method in the java.sql.CallableStatement interface.

See Also
setNull Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setNString Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified String object.

Syntax
public final void setNString(java.lang.String parameterName, java.lang.String value)

Parameters
parameterName
A String that indicates the parameter name.
value
A String object.

Exceptions
SQLServerException

Remarks
This method should be used for NCHAR , NVARCHAR , NTEXT , and XML data types.
This setNString method is specified by the setNString method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setObject Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the designated parameter using the given object.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

Overload List
NAME DESC RIP T IO N

setObject (java.lang.String, java.lang.Object) Sets the value of the designated parameter using the given
object.

setObject (java.lang.String, java.lang.Object, int) Sets the value of the designated parameter using the given
object and target type.

setObject (java.lang.String, java.lang.Object, int, int) Sets the value of the designated parameter using the given
object, target type, and scale.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setObject Method ( java.lang.String,
java.lang.Object)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the designated parameter using the given object.

Syntax
public void setObject(java.lang.String sCol,
java.lang.Object o)

Parameters
sCol
A String that contains the parameter name.
o
An Object value.

Exceptions
SQLServerException

Remarks
This setObject method is specified by the setObject method in the java.sql.CallableStatement interface.
This method converts the specified parameter to a CHAR if a NULL is given, before sending it to the database. If
the parameter is declared as a binary, varbinary or image SQL type, then an exception will be thrown when the
statement is executed.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
setObject Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setObject Method ( java.lang.String,
java.lang.Object, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the designated parameter by using the given object and target type.

Syntax
public void setObject(java.lang.String sCol,
java.lang.Object o,
int n)

Parameters
sCol
A String that contains the parameter name.
o
An Object value.
n
An int that indicates the target type as defined in java.sql.Types.

Exceptions
SQLServerException

Remarks
This setObject method is specified by the setObject method in the java.sql.CallableStatement interface.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
setObject Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setObject Method ( java.lang.String,
java.lang.Object, int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the designated parameter by using the given object, target type, and scale.

Syntax
public void setObject(java.lang.String sCol,
java.lang.Object o,
int n,
int m)

Parameters
sCol
A String that contains the parameter name.
o
An Object value.
n
An int that indicates the target type as defined in java.sql.Types.
m
An int that indicates the number of digits to the right of the decimal point. This parameter is ignored for all
types except for NUMERIC and DECIMAL.

Exceptions
SQLServerException

Remarks
This setObject method is specified by the setObject method in the java.sql.CallableStatement interface.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
setObject Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setShort Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given shor t value.

Syntax
public void setShort(java.lang.String sCol,
short s)

Parameters
sCol
A String that contains the parameter name.
s
A shor t value.

Exceptions
SQLServerException

Remarks
This setShort method is specified by the setShort method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setSQLXML Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified SQLXML object.

Syntax
public final void setSQLXML(java.lang.String parameterName,
java.sql.SQLXML xmlObject)

Parameters
parameterName
An String that indicates the parameter name.
xmlObject
A SQLXML object that contains the parameter value.

Exceptions
SQLServerException

Remarks
This setSQLXML method is specified by the setSQLXML method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
setString Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given Java String value.

Syntax
public void setString(java.lang.String sCol,
java.lang.String s)

Parameters
sCol
A String that contains the name of the parameter.
s
A String value.

Exceptions
SQLServerException

Remarks
This setString method is specified by the setString method in the java.sql.CallableStatement interface.
String to binary conversions are performed only when Microsoft JDBC Driver for SQL Server knows the
destination type is binary. In cases where the JDBC driver does not know the underlying type, it will pass the
String literal and return a server error if the server cannot perform the conversion.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setTime Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given time value.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

Overload List
NAME DESC RIP T IO N

setTime (java.lang.String, java.sql.Time) Sets the designated parameter to the given time value.

setTime (java.lang.String, java.sql.Time, java.util.Calendar) Sets the designated parameter to the given time and
calendar values.

See Also
SQLServerCallableStatement Methods
SQLServerCallableStatement Class
setTime Method ( java.lang.String, java.sql.Time)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given time value.

Syntax
public void setTime(java.lang.String sCol,
java.sql.Time t)

Parameters
sCol
A String that contains the parameter name.
t
A Time object.

Exceptions
SQLServerException

Remarks
This setTime method is specified by the setTime method in the java.sql.CallableStatement interface.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
setTime Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setTime Method ( java.lang.String, java.sql.Time,
java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given time and calendar values.

Syntax
public void setTime(java.lang.String sCol,
java.sql.Time x,
java.util.Calendar c)

Parameters
sCol
A String that contains the parameter name.
x
A Time object.
c
A Calendar object.

Exceptions
SQLServerException

Remarks
This setTime method is specified by the setTime method in the java.sql.CallableStatement interface.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
setTime Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setTimestamp Method
(SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given timestamp value.

Overload List
NAME DESC RIP T IO N

setTimestamp (java.lang.String, java.sql.Timestamp) Sets the designated parameter to the given timestamp
value.

setTimestamp (java.lang.String, java.sql.Timestamp, Sets the designated parameter to the given timestamp and
java.util.Calendar) calendar values.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setTimestamp Method ( java.lang.String,
java.sql.Timestamp)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given timestamp value.

Syntax
public void setTimestamp(java.lang.String sCol,
java.sql.Timestamp t)

Parameters
sCol
A String that contains the parameter name.
t
A Timestamp object.

Exceptions
SQLServerException

Remarks
This setTimestamp method is specified by the setTimestamp method in the java.sql.CallableStatement interface.

See Also
setTimestamp Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setTimestamp Method ( java.lang.String,
java.sql.Timestamp, java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given timestamp and calendar values.

Syntax
public void setTimestamp(java.lang.String sCol,
java.sql.Timestamp x,
java.util.Calendar c)

Parameters
sCol
A String that contains the parameter name.
x
A Timestamp object.
c
A Calendar object.

Exceptions
SQLServerException

Remarks
This setTimestamp method is specified by the setTimestamp method in the java.sql.CallableStatement interface.

See Also
setTimestamp Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
setURL Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given URL value.

Syntax
public void setURL(java.lang.String sCol,
java.net.URL u)

Parameters
sCol
A String that contains the name of the parameter.
u
A URL object.

Exceptions
SQLServerException

Remarks
This setURL method is specified by the setURL method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
wasNull Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the last OUT parameter read had the value of SQL NULL.

Syntax
public boolean wasNull()

Return Value
true if the last parameter read was null. Otherwise, false .

Exceptions
SQLServerException

Remarks
This wasNull method is specified by the wasNull method in the java.sql.CallableStatement interface.

See Also
SQLServerCallableStatement Members
SQLServerCallableStatement Class
unwrap Method (SQLServerCallableStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an object that implements the specified interface to allow access to the Microsoft JDBC Driver for SQL
Server-specific methods.

Syntax
public <T> T unwrap(Class<T> iface)

Parameters
iface
A class of type T defining an interface.

Return Value
An object that implements the specified interface.

Exceptions
SQLServerException

Remarks
The unwrap method is defined by the java.sql.Wrapper interface, which is introduced in the JDBC 4.0 Spec.
Applications might need to access extensions to the JDBC API that are specific to the Microsoft JDBC Driver for
SQL Server. The unwrap method supports unwrapping to public classes that this object extends, if the classes
expose vendor extensions.
SQLServerCallableStatement implements ISQLServerPreparedStatement, which is extended from the
ISQLServerStatement. When this method is called, the object unwraps to the following classes:
SQLServerStatement, SQLServerPreparedStatement, and SQLServerCallableStatement.
For more information, see Wrappers and Interfaces.
The following code example demonstrates how to use the isWrapperFor and unwrap methods to check the
driver extensions and invoke the vendor-specific methods, such as setResponseBuffering and
getResponseBuffering.
public static void executeStoredProcedure(Connection con) {
try {
CallableStatement cstmt =
con.prepareCall("{call dbo.stored_proc_name(?, ?)}");

// The recommended way to access the JDBC


// Driver-specific methods is to use the JDBC 4.0 Wrapper
// functionality.
// The following code statements demonstrates how to use the
// isWrapperFor and unwrap methods
// to access the driver-specific response buffering methods.

if (cstmt.isWrapperFor(
com.microsoft.sqlserver.jdbc.SQLServerCallableStatement.class)) {
// The CallableStatement object can unwrap to
// SQLServerCallableStatement.
SQLServerCallableStatement SQLcstmt =
cstmt.unwrap(
com.microsoft.sqlserver.jdbc.SQLServerCallableStatement.class);
SQLcstmt.setResponseBuffering("adaptive");
System.out.println("Response buffering mode has been set to " +
SQLcstmt.getResponseBuffering());
}

if (cstmt.isWrapperFor(
com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.class)) {
// The CallableStatement object can unwrap to
// SQLServerPreparedStatement.
SQLServerPreparedStatement SQLpstmt =
cstmt.unwrap(
com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.class);
SQLpstmt.setResponseBuffering("adaptive");
System.out.println("Response buffering mode has been set to " +
SQLpstmt.getResponseBuffering());
}
if (cstmt.isWrapperFor(
com.microsoft.sqlserver.jdbc.SQLServerStatement.class)) {

// The CallableStatement object can unwrap to SQLServerStatement.


SQLServerStatement SQLstmt =
cstmt.unwrap(
com.microsoft.sqlserver.jdbc.SQLServerStatement.class);
SQLstmt.setResponseBuffering("adaptive");
System.out.println("Response buffering mode has been set to " +
SQLstmt.getResponseBuffering());
}
}
catch (Exception e) {
e.printStackTrace();
}
}

See Also
isWrapperFor Method (SQLServerCallableStatement)
SQLServerCallableStatement Members
SQLServerCallableStatement Class
SQLServerClob Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a character large binary object (CLOB).
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: java.sql.Clob, java.io.Serializable

Syntax
public class SQLServerClob

Remarks
A CLOB is stored in SQL Server as a TEXT or NTEXT data type.

See Also
SQLServerClob Members
JDBC Driver API Reference
SQLServerClob Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members exposed by the SQLServerClob class.

Constructors
NAME DESC RIP T IO N

SQLServerClob Initializes a new instance of the SQLServerClob class.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

free This method frees the CLOB object and releases the
resources that it holds.

getAsciiStream Materializes the Clob as an ASCII stream.

getCharacterStream Returns the Clob data as a java.io.Reader object or as a


stream of characters.

getSubString Returns a copy of the specified substring in the Clob based


on the specified starting position and number of characters
to copy.

length Returns the number of characters in the Clob.

position Returns the character position of the specified Clob object or


substring in the Clob based on the specified starting
position.

setAsciiStream Returns a stream to be used to write ASCII characters to the


Clob starting at the specified position.

setCharacterStream Returns a stream to be used to write a stream of Unicode


characters to the Clob starting at the specified position.
NAME DESC RIP T IO N

setString Writes the given string to the Clob starting at the specified
position.

truncate Truncates the Clob to the specified length.

Inherited Methods
C L A SS IN H ERIT ED F RO M M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

See Also
SQLServerClob Class
SQLServerClob Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerClob class, see SQLServerClob Members.
SQLServerClob Constructor (SQLServerConnection,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerClob class when given a SQLServerConnection object and a string of
data.

NOTE
This method has been deprecated in JDBC Driver version 2.0. Instead, use the createClob method of the
SQLServerConnection class.

Syntax
public SQLServerClob(SQLServerConnection connection,
java.lang.String data)

Parameters
connection
A SQLServerConnection object.
data
The CLOB data.

See Also
SQLServerClob Constructors
SQLServerClob Members
SQLServerClob Class
SQLServerClob Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerClob class, see SQLServerClob Members.
free Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method frees the CLOB object and releases the resources that it holds.

Syntax
public void free()

Exceptions
SQLServerException

Remarks
This free method is specified by the free method in the java.sql.Clob interface.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
getAsciiStream Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Materializes the CLOB as an ASCII stream.

Syntax
public java.io.InputStream getAsciiStream()

Return Value
An input stream that contains the CLOB data.

Exceptions
SQLServerException

Remarks
This getAsciiStream method is specified by the getAsciiStream method in the java.sql.Clob interface.
Always returns a stream of bytes and assumes that the data in the CLOB is in an ASCII format because it has no
way of knowing if it is in Unicode or any other multi-byte code page.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
getCharacterStream Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the Clob value designated by the java.sql.Clob object as a java.io.Reader object.

Overload List
NAME DESC RIP T IO N

getCharacterStream Method () Returns the Clob data as a java.io.Reader object or as a


stream of characters.

getCharacterStream Method (long, long) Returns the Clob data as a java.io.Reader object or as a
stream of characters with the specified position and length.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
getCharacterStream Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the CLOB data as a Reader object or as a stream of characters.

Syntax
public java.io.Reader getCharacterStream()

Return Value
A Reader object that contains the CLOB data.

Exceptions
SQLServerException

Remarks
This getCharacterStream method is specified by the getCharacterStream method in the java.sql.Clob interface.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
getCharacterStream Method (long, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the Clob data as a Reader object or as a stream of characters with the specified position and length.

Syntax
public java.io.Reader getCharacterStream(long pos,
long length)

Parameters
pos
A long that indicates the offset to the first character of the partial value to be retrieved.
length
A long that indicates the length in characters of the partial value to be retrieved.

Return Value
A Reader object that contains the Clob data.

Exceptions
SQLServerException

Remarks
This getCharacterStream method is specified by the getCharacterStream method in the java.sql.Clob interface.

See Also
getCharacterStream Method (SQLServerClob)
SQLServerClob Methods
SQLServerClob Members
getSubString Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a copy of the specified substring in the CLOB based on the given starting position and the number of
characters to copy.

Syntax
public java.lang.String getSubString(long pos,
int length)

Parameters
pos
The first character of the substring to be extracted. The first character is at position 1.
length
The number of consecutive characters to be copied.

Return Value
A String that is the specified substring in the CLOB.

Exceptions
SQLServerException

Remarks
This getSubString method is specified by the getSubString method in the java.sql.Clob interface.
Trying to get zero characters from a null or zero-length CLOB returns an empty string. Trying to get any length
of characters at any position other than position 1 in a zero-length CLOB will cause a position exception to be
thrown.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
length Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the number of characters in the CLOB.

Syntax
public long length()

Return Value
The length of the CLOB in number characters.

Exceptions
SQLServerException

Remarks
This length method is specified by the length method in the java.sql.Clob interface.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
position Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the character position of the specified CLOB object or substring in the CLOB based on the given starting
position.

Overload List
NAME DESC RIP T IO N

position (java.sql.Clob, long) Returns the character position of the specified CLOB object
in the CLOB based on the given starting position.

position (java.lang.String, long) Returns the character position of the specified substring in
the CLOB based on the given starting position.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
position Method ( java.sql.Clob, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the character position of the specified CLOB object in the CLOB based on the given starting position.

Syntax
public long position(java.sql.Clob searchstr,
long start)

Parameters
searchstr
The substring to search for.
start
The position at which to begin searching. The first position is 1.

Return Value
The position at which the substring appears, or -1 if it is not present. The first position is 1.

Exceptions
SQLServerException

Remarks
This position method is specified by the position method in the java.sql.Clob interface.

See Also
position Method (SQLServerClob)
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
position Method ( java.lang.String, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the character position of the specified substring in the CLOB based on the given starting position.

Syntax
public long position(java.lang.String searchstr,
long start)

Parameters
searchstr
The substring for which to search.
start
The position at which to begin searching; the first position is 1.

Return Value
The position at which the substring appears or -1 if it is not present; the first position is 1.

Exceptions
SQLServerException

Remarks
This position method is specified by the position method in the java.sql.Clob interface.

See Also
position Method (SQLServerClob)
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
setAsciiStream Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a stream to be used to write ASCII characters to the CLOB starting at the given position.

Syntax
public java.io.OutputStream setAsciiStream(long pos)

Parameters
pos
The position at which to start writing to the CLOB object.

Return Value
The stream to which ASCII encoded characters can be written.

Exceptions
java.sql.SQLException

Remarks
This setAsciiStream method is specified by the setAsciiStream method in the java.sql.Clob interface.
Character data in the CLOB is overwritten by the output stream starting at the given position and can overrun
the initial length of the CLOB. Specifying a position+1 value will append ASCII characters. Specifying a
position+2 or greater (or zero or less) value will cause a position error to be thrown.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
setCharacterStream Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a stream to be used to write a stream of Unicode characters to the CLOB, starting at the given position.

Syntax
public java.io.Writer setCharacterStream(long pos)

Parameters
pos
The position at which to start writing to the CLOB object.

Return Value
A stream to which Unicode encoded characters can be written.

Exceptions
java.sql.SQLException

Remarks
This setCharacterStream method is specified by the setCharacterStream method in the java.sql.Clob interface.
Character data in the CLOB is overwritten by the writer starting at the specified position and can over-run the
initial length of the CLOB. Specifying a position+1 value will append characters. Specifying a position+2 or
greater (or zero or less) value will cause a position error to be thrown.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
setString Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Writes the given String to the CLOB starting at the given position.

Overload List
NAME DESC RIP T IO N

setString (long, java.lang.String) Writes the given stringto the CLOB starting at the given
position.

setString (long, java.lang.String, int, int) Writes the given string to the CLOB starting at the given
position, based on the given offset and length.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
setString Method (long, java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Writes the given String to the CLOB starting at the given position.

Syntax
public int setString(long pos,
java.lang.String s)

Parameters
pos
The position at which to start writing to the CLOB.
s
The String to be written to the CLOB.

Return Value
The number of characters written.

Exceptions
java.sql.SQLException

Remarks
This setString method is specified by the setString method in the java.sql.Clob interface.
Character data is overwritten starting at the specified position and can over-run the initial length of the CLOB.
Specifying a position+1 value will append the string. Specifying a position+2 or greater (or zero or less) values
will cause a position error to be thrown.

See Also
setString Method (SQLServerClob)
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
setString Method (long, java.lang.String, int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Writes the given string to the CLOB starting at the given position, based on the given offset and length.

Syntax
public int setString(long pos,
java.lang.String str,
int offset,
int len)

Parameters
pos
The position at which to start writing to the CLOB.
str
The string to be written to the CLOB.
offset
The offset within the string to start reading the characters from.
len
The number of characters to be written.

Return Value
The number of characters written.

Exceptions
java.sql.SQLException

Remarks
This setString method is specified by the setString method in the java.sql.Clob interface.
Character data is overwritten starting at the specified position and can overwrite the initial length of the CLOB.
Specifying a position+1 value will append the string. Specifying a position+2 or greater (or zero or less) value
will cause a position error to be thrown.

See Also
setString Method (SQLServerClob)
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
truncate Method (SQLServerClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Truncates the CLOB to the given length.

Syntax
public void truncate(long len)

Parameters
len
The length, in characters, to which the CLOB should be truncated.

Exceptions
java.sql.SQLException

Remarks
This truncate method is specified by the truncate method in the java.sql.Clob interface.

See Also
SQLServerClob Methods
SQLServerClob Members
SQLServerClob Class
SQLServerConnection Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a JDBC connection to a Microsoft SQL Server database.
Package: com.microsoft.sqlserver.jdbc
Implements: ISQLServerConnection, java.io.Serializable

Syntax
public class SQLServerConnection

Remarks
SQLServerConnection supports JDBC connection pooling and can be either a physical JDBC connection or a
logical JDBC connection. SQLServerConnection manages transaction control for all statements that were created
from it, and it can participate in XA distributed transactions managed via a XAResource adapter.
SQLServerConnection manages a pool of prepared statement handles. Prepared statements are prepared once
and are typically run many times with different data values for their parameters. Prepared statements are also
maintained across logical (pooled) connection closes.

NOTE
SQLServerConnection is not thread safe. However, multiple statements that are created from a single connection can be
processed simultaneously in concurrent threads.

This class supports unwrapping to SQLServerConnection class, java.sql.connection interface, and


ISQLServerConnection interface. For more information, see Wrappers and Interfaces.

See Also
SQLServerConnection Members
JDBC Driver API Reference
SQLServerConnection Members
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerConnection class.

Constructors
None.

Fields
NAME DESC RIP T IO N

TRANSACTION_SNAPSHOT Used to specify the snapshot transaction isolation level.

Inherited Fields
C L A SS IN H ERIT ED F RO M : DESC RIP T IO N

java.sql.Connection TRANSACTION_NONE, TRANSACTION_READ_COMMITTED,


TRANSACTION_READ_UNCOMMITTED,
TRANSACTION_REPEATABLE_READ,
TRANSACTION_SERIALIZABLE

Methods
NAME DESC RIP T IO N

clearWarnings Clears all warnings reported for this SQLServerConnection


object.

close Releases the database for this SQLServerConnection object


and JDBC resources immediately instead of waiting for them
to be automatically released.

closeUnreferencedPreparedStatementHandles Forces the un-prepare requests for any outstanding


discarded prepared statements to be executed.

commit Makes all changes made since the previous commit or


rollback permanent, and releases any database locks that are
currently held by this SQLServerConnection object.

createBlob Creates a java.sql.Blob object without any data.

createClob Creates a java.sql.Clob object without any data.

createNClob Creates a java.sql.NClob object without any data.


NAME DESC RIP T IO N

createStatement Creates a SQLServerStatement object for sending SQL


statements to the database.

createSQLXML Creates a java.sql.SQLXML object without any data.

getAutoCommit Retrieves the current auto-commit mode for this


SQLServerConnection object.

getCatalog Retrieves the current catalog name for this


SQLServerConnection object.

getClientConnectionID Method (SQLServerConnection) Gets the connection ID of the most recent connection
attempt, regardless of whether the attempt succeeded or
failed.

getClientInfo Retrieves information regarding the client information


properties supported by the JDBC driver.

getDisableStatementPooling Returns the value of disableStatementPooling connection


property. This setting controls whether statement pooling is
enabled or not for this connection.

getDiscardedServerPreparedStatementCount Returns the number of currently outstanding prepared


statement unprepare actions.

getEnablePrepareOnFirstPreparedStatementCall Returns the value of


enablePrepareOnFirstPreparedStatementCall
connection property.

getHoldability Retrieves the current holdability of SQLServerResultSet


objects that are created by using this SQLServerConnection
object.

getMetaData Retrieves a SQLServerDatabaseMetaData object that


contains metadata about the database to which this
SQLServerConnection object represents a connection.

getServerPreparedStatementDiscardThreshold Returns the value of


ser verPreparedStatementDiscardThreshold connection
property.

getStatementHandleCacheEntryCount Returns the current number of pooled prepared statement


handles.

getStatementPoolingCacheSize Returns the size of the prepared statement cache for this
connection.

getTransactionIsolation Retrieves the current transaction isolation level for this


SQLServerConnection object.

getTypeMap Retrieves the Map object that is associated with this


SQLServerConnection object.
NAME DESC RIP T IO N

getWarnings Retrieves the first warning reported by calls on this


SQLServerConnection object.

isClosed Indicates whether this SQLServerConnection object has been


closed.

isReadOnly Indicates whether this SQLServerConnection object is in


read-only mode.

isStatementPoolingEnabled Returns whether statement pooling is enabled or not for this


connection.

isValid Indicates whether this SQLServerConnection object has not


been closed and is still valid.

nativeSQL Converts the given SQL statement into the native SQL
grammar of the database server.

prepareCall Creates a SQLServerCallableStatement object for calling


database stored procedures.

prepareStatement Creates a SQLServerPreparedStatement object for sending


parameterized SQL statements to the database.

releaseSavepoint Removes the specified SQLServerSavepoint object from the


current transaction.

rollback Undoes all changes made in the current transaction and


releases any database locks currently held by this
SQLServerConnection object.

setAutoCommit Sets the auto-commit mode for this SQLServerConnection


object to the given state.

setCatalog Sets the specified catalog name to select a subspace of this


SQLServerConnection object's database in which to work.

setClientInfo Sets the value of the client information properties.

setDisableStatementPooling Sets statement pooling to true or false.

setEnablePrepareOnFirstPreparedStatementCall Specifies the new value of the


enablePrepareOnFirstPreparedStatementCall
connection property.

setHoldability Changes the holdability of SQLServerResultSet objects that


are created by using this SQLServerSavepoint object to the
given holdability.

setReadOnly Puts this SQLServerConnection object in read-only mode as


a hint to the JDBC driver to enable database optimizations.
NAME DESC RIP T IO N

setSavepoint Creates an unnamed savepoint in the current transaction


and returns the new SQLServerSavepoint object that
represents it.

setServerPreparedStatementDiscardThreshold Sets the new value of the


ser verPreparedStatementDiscardThreshold connection
property.

setStatementPoolingCacheSize Sets the size of the prepared statement cache for this
connection.

setTransactionIsolation Tries to change the transaction isolation level for this


SQLServerConnection object to the one given.

setTypeMap Installs the given TypeMap object as the type map for this
SQLServerConnection object.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

java.lang.Wrapper isWrapperFor, unwrap

See Also
SQLServerConnection Class
SQLServerConnection Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of ISQLServerConnection, see SQLServerConnection Members.

See Also
SQLServerConnection Class
clearWarnings Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Clears all warnings reported for this SQLServerConnection object.

Syntax
public void clearWarnings()

Exceptions
SQLServerException

Remarks
This clearWarnings method is specified by the clearWarnings method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
close Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Releases this SQLServerConnection object's database and JDBC resources immediately instead of waiting for
them to be automatically released.

Syntax
public void close()

Exceptions
SQLServerException

Remarks
This close method is specified by the close method in the java.sql.Connection interface.
Calling the close method in the middle of a transaction causes the transaction to be rolled back.

See Also
SQLServerConnection Members
SQLServerConnection Class
closeUnreferencedPreparedStatementHandles
Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Forces the un-prepare requests for any outstanding discarded prepared statements to be executed.

Syntax
public void closeUnreferencedPreparedStatementHandles()

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
commit Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Makes all changes made since the previous commit or rollback permanent, and releases any database locks
currently held by this SQLServerConnection object.

Syntax
public void commit()

Exceptions
SQLServerException

Remarks
This commit method is specified by the commit method in the java.sql.Connection interface.
This method should be used only when auto-commit mode has been disabled.
Note that this method will fail and throw an exception if the client starts a manual transaction and then for some
reason SQL Server rolls back the manual transaction. For example, an exception is thrown if the client calls a
stored procedure that explicitly calls ROLLBACK TRANSACTION, and then the client calls the commit method. In
addition, if SQL Server raises an error of sufficient severity (16 or higher) to roll back the client initiated manual
transaction; a subsequent call to the commit method will throw an exception.

See Also
SQLServerConnection Members
SQLServerConnection Class
createBlob Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a Blob object without any data.

Syntax
public java.sql.Blob createBlob()

Return Value
A Blob object.

Exceptions
SQLServerException

Remarks
This createBlob method is specified by the createBlob method in the java.sql.Connection interface.
This method replaces the need for SQLServerBlob Constructor (SQLServerConnection, byte).

See Also
SQLServerConnection Members
SQLServerConnection Class
createClob Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a Clob object without any data.

Syntax
public java.sql.Clob createClob()

Return Value
A Clob object.

Exceptions
SQLServerException

Remarks
This createClob method is specified by the createClob method in the java.sql.Connection interface.
This method replaces the need for SQLServerClob Constructor (SQLServerConnection, java.lang.String).

See Also
SQLServerConnection Members
SQLServerConnection Class
createNClob Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a NClob object without any data.

Syntax
public java.sql.NClob createNClob()

Return Value
A NClob object.

Exceptions
SQLServerException

Remarks
This createNClob method is specified by the createNClob method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
createStatement Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerStatement object for sending SQL statements to the database.

Overload List
NAME DESC RIP T IO N

createStatement () Creates a SQLServerStatement object for sending SQL


statements to the database.

createStatement (int, int) Creates a SQLServerStatement object that generates


SQLServerResultSet objects with the given type and
concurrency.

createStatement (int, int, int) Creates a SQLServerStatement object that generates


SQLServerResultSet objects with the given type, concurrency,
and holdability.

See Also
SQLServerConnection Members
SQLServerConnection Class
createStatement Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerStatement object for sending SQL statements to the database.

Syntax
public java.sql.Statement createStatement()

Return Value
The Statement object.

Exceptions
SQLServerException

Remarks
This createStatement method is specified by the createStatement method in the java.sql.Connection interface.

See Also
createStatement Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
createStatement Method (int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerStatement object that generates SQLServerResultSet objects with the given type and
concurrency.

Syntax
public java.sql.Statement createStatement(int resultSetType,
int resultSetConcurrency)

Parameters
resultSetType
The int value representing the result set type.
resultSetConcurrency
The int value representing the result set concurrency type.

Return Value
The Statement object.

Exceptions
SQLServerException

Remarks
This createStatement method is specified by the createStatement method in the java.sql.Connection interface.

See Also
createStatement Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
createStatement Method (int, int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerStatement object that generates SQLServerResultSet objects with the given type,
concurrency, and holdability.

Syntax
public java.sql.Statement createStatement(int nType,
int nConcur,
int nHold)

Parameters
resultSetType
The int value that represents the result set type.
nConcur
The int value that represents the result set concurrency type.
nHold
The int value that represents the holdability.

Return Value
The Statement object.

Exceptions
SQLServerException

Remarks
This createStatement method is specified by the createStatement method in the java.sql.Connection interface.

See Also
createStatement Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
createSQLXML Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLXML object without any data.

Syntax
public java.sql.SQLXML createSQLXML()

Return Value
A SQLXML object.

Exceptions
SQLServerException

Remarks
This createSQLXML method is specified by the createSQLXML method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
getAutoCommit Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the current auto-commit mode for this SQLServerConnection object.

Syntax
public boolean getAutoCommit()

Return Value
true if auto-commit mode is enabled, false if it is not.

Exceptions
SQLServerException

Remarks
This getAutoCommit method is specified by the getAutoCommit method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
getCatalog Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the current catalog name of this SQLServerConnection object.

Syntax
public java.lang.String getCatalog()

Return Value
A String that contains the catalog name.

Exceptions
SQLServerException

Remarks
This getCatalog method is specified by the getCatalog method in the java.sql.Connection interface.
Returns the current catalog property of the SQLServerConnection object, or null if it is not set. The catalog
property is set explicitly with the setCatalog method, or is implicitly updated by reading the environment change
on TDS for the current catalog.

See Also
SQLServerConnection Members
SQLServerConnection Class
getClientConnectionID Method
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the connection ID of the most recent connection attempt, regardless of whether the attempt succeeded or
failed.

Syntax
public Java.util.UUID SQLServerConnection.getClientConnectionID();

Return Value
A 16-byte GUID representing the connection ID of the most recent connection attempt. Or, NULL if there is a
failure after the connection request is initiated and the pre-login handshake.

Exceptions
SQLServerException

Remarks
For more information about accessing diagnostic information in the extended events log, see Accessing
Diagnostic Information in the Extended Events Log.
The following sample shows how to get the connection ID:

Connection con = DriverManager.getConnection(connectionUrl);


UUID id = ((ISQLServerConnection)con).getClientConnectionId();

The following sample shows another way to get the connection ID:

SQLServerConnectionPoolDataSource ds = new SQLServerConnectionPoolDataSource();


ds.setUser("...");
ds.setPassword("...");
ds.setServerName("...");
PooledConnection pcon= ds.getPooledConnection();
Connection cn = pcon.getConnection();
UUID conid = ((ISQLServerConnection)cn).getClientConnectionId();

getClientConnectionID works regardless of which version of the server you connect to, but extended events
logs and entry on connectivity ring buffer errors will not be present in SQL Server 2008 R2 and earlier.
You can locate the connection ID in the extended events log to see if the failure was on the server if the extended
event for logging connection ID is enabled. You can also locate the connection ID in the connection ring buffer
(Connectivity troubleshooting in SQL Server 2008 with the Connectivity Ring Buffer) for certain connection
errors. If the connection ID is not in the connection ring buffer, you can assume a network error.
See Also
SQLServerConnection Members
SQLServerConnection Class
getClientInfo Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves information regarding the client information properties supported by the JDBC driver.

Overload List
NAME DESC RIP T IO N

getClientInfo Method () Retrieves a list that contains the name and current value of
each client information property supported by the JDBC
driver.

getClientInfo Method (java.lang.String) Retrieves the value of a specified client information property.

See Also
SQLServerConnection Members
SQLServerConnection Class
getClientInfo Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a list that contains the name and current value of each client information property supported by the
JDBC driver.

Syntax
public java.util.Properties getClientInfo()

Return Value
A Properties object that contains the name and current value of each of the client information properties
supported by the driver.

Exceptions
SQLServerException

Remarks
This getClientInfo method is specified by the getClientInfo method in the java.sql.Connection interface.
The Microsoft JDBC Driver for SQL Server does not support any client information properties. As a result, this
method returns an empty Properties object.
Similarly, applications can use the getClientInfoProperties method of the SQLServerDatabaseMetaData class to
retrieve a list of the client information properties that the driver supports. The getClientInfoProperties method
returns an empty result set.

See Also
getClientInfo Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
getClientInfo Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of a specified client information property.

Syntax
public java.lang.String getClientInfo (java.lang.String name)

Parameters
name
A String that contains the name of the client information property to retrieve.

Return Value
A String that contains the value of the client information property.

Exceptions
SQLServerException

Remarks
This getClientInfo method is specified by the getClientInfo method in the java.sql.Connection interface.
The Microsoft JDBC Driver for SQL Server does not support any client info properties. As a result, this method
returns null .
Similarly, applications can use the getClientInfoProperties method of the SQLServerDatabaseMetaData class to
retrieve a list of the client information properties that the driver supports. The getClientInfoProperties method
returns an empty result set.

See Also
getClientInfo Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
getDisableStatementPooling Method
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the value of disableStatementPooling connection property. This setting controls whether statement
pooling is enabled or not for this connection.

Syntax
public boolean getDisableStatementPooling()

Return Value
A boolean that contains the value of disableStatementPooling connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
getDiscardedServerPreparedStatementCount
Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the number of currently outstanding prepared statement unprepare actions.

Syntax
public int getDiscardedServerPreparedStatementCount()

Return Value
An int that contains the number of currently outstanding prepared statement unprepare actions.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
getEnablePrepareOnFirstPreparedStatementCall
Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the value of enablePrepareOnFirstPreparedStatementCall connection property. If false the first
execution will call sp_executesql and not prepare a statement, once the second execution happens it will call
sp_prepexec and actually set up a prepared statement handle. Following executions will call sp_execute. This
relieves the need for sp_unprepare on prepared statement close if the statement is only executed once. The
default for this option can be changed by calling setDefaultEnablePrepareOnFirstPreparedStatementCall().

Syntax
public boolean getEnablePrepareOnFirstPreparedStatementCall()

Return Value
A boolean that contains the value of enablePrepareOnFirstPreparedStatementCall connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
getHoldability Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the current holdability of SQLServerResultSet objects created by using this SQLServerConnection
object.

Syntax
public int getHoldability()

Return Value
An int value that contains one of the following holdability levels:
HOLD_CURSORS_OVER_COMMIT
CLOSE_CURSORS_AT_COMMIT

Exceptions
SQLServerException

Remarks
This getHoldability method is specified by the getHoldability method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
getMetaData Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a SQLServerDatabaseMetaData object that contains metadata about the database to which this
SQLServerConnection object represents a connection.

Syntax
public java.sql.DatabaseMetaData getMetaData()

Return Value
The DatabaseMetaData object.

Exceptions
SQLServerException

Remarks
This getMetaData method is specified by the getMetaData method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
getServerPreparedStatementDiscardThreshold
Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the value of ser verPreparedStatementDiscardThreshold connection property. This setting controls
how many outstanding prepared statement discard actions (sp_unprepare) can be outstanding per connection
before a call to clean up the outstanding handles on the server is executed. If the setting is <= 1, unprepare
actions are executed immediately on prepared statement close. If it's set to > 1, these calls are batched together
to avoid overhead of calling sp_unprepare too often. The default for this option can be changed by calling
getDefaultServerPreparedStatementDiscardThreshold().

Syntax
public int getServerPreparedStatementDiscardThreshold()

Return Value
An int that contains the value of ser verPreparedStatementDiscardThreshold connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
getStatementHandleCacheEntryCount Method
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the current number of pooled prepared statement handles.

Syntax
public int getStatementHandleCacheEntryCount()

Return Value
An int that contains the current number of pooled prepared statement handles.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
getStatementPoolingCacheSize Method
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the size of the prepared statement cache for this connection. '0' means caching not enabled.

Syntax
public int getStatementPoolingCacheSize()

Return Value
An int that contains the value of statementPoolingCacheSize connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
getTransactionIsolation Method
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the current transaction isolation level of this SQLServerConnection object.

Syntax
public int getTransactionIsolation()

Return Value
An int value that contains one of the following isolation levels:
TRANSACTION_NONE
TRANSACTION_READ_UNCOMMITTED
TRANSACTION_READ_COMMITTED
TRANSACTION_REPEATABLE_READ
TRANSACTION_SERIALIZABLE
TRANSACTION_SNAPSHOT = 0x1000

Exceptions
SQLServerException

Remarks
This getTransactionIsolation method is specified by the getTransactionIsolation method in the
java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
getTypeMap Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the Map object associated with this SQLServerConnection object.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server.

Syntax
public java.util.Map getTypeMap()

Return Value
A Map object.

Exceptions
SQLServerException

Remarks
This getTypeMap method is specified by the getTypeMap method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
getWarnings Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the first warning reported by calls on this SQLServerConnection object.

Syntax
public java.sql.SQLWarning getWarnings()

Return Value
A SQLWarning object.

Exceptions
SQLServerException

Remarks
This getWarnings method is specified by the getWarnings method in the java.sql.Connection interface.
Subsequent warnings are chained to the first SQLWarning and called with the getNextWarning method. If called
on a closed connection, an exception will be thrown.

See Also
SQLServerConnection Members
SQLServerConnection Class
isClosed Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this SQLServerConnection object has been closed.

Syntax
public boolean isClosed()

Return Value
true if the connection is close, false if it is not.

Exceptions
SQLServerException

Remarks
This isClosed method is specified by the isClosed method in the java.sql.Connection interface.
Verifies the state of the called SQLServerConnection object. A connection is closed if the close method has been
called on it, or if certain fatal errors have occurred. This method will return true only when it is called after the
close method has been called.

See Also
SQLServerConnection Members
SQLServerConnection Class
isReadOnly Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this SQLServerConnection object is in read-only mode.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server.

Syntax
public boolean isReadOnly()

Return Value
true if the connection is in read-only mode, false if it is not.

Exceptions
SQLServerException

Remarks
This isReadOnly method is specified by the isReadOnly method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
isStatementPoolingEnabled Method
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns whether statement pooling is enabled or not for this connection.

Syntax
public boolean isStatementPoolingEnabled()

Return Value
A boolean that contains the flag indicating whether statement pooling is enabled or not.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
isValid Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this SQLServerConnection object has not been closed and is still valid.

Syntax
public boolean isValid(int timeout)

Parameters
timeout
An int that specifies the number of seconds to wait for validating the connection.

Return Value
true if the connection is valid; false if the connection is not valid or the validity of the connection cannot be
determined before the timeout expires.

Exceptions
SQLServerException

Remarks
This isValid method is specified by the isValid method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
nativeSQL Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Converts the given SQL statement into the native SQL grammar of the database server.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server.

Syntax
public java.lang.String nativeSQL(java.lang.String sql)

Parameters
sql
A String containing an SQL statement.

Return Value
A String containing the converted SQL statement.

Exceptions
SQLServerException

Remarks
This nativeSQL method is specified by the nativeSQL method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
prepareCall Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerCallableStatement object for calling database stored procedures.

Overload List
NAME DESC RIP T IO N

prepareCall (java.lang.String) Creates a SQLServerCallableStatement object for calling


database stored procedures.

prepareCall (java.lang.String, int, int) Creates a SQLServerCallableStatement object that generates


SQLServerResultSet objects with the given type and
concurrency.

prepareCall (java.lang.String, int, int, int) Creates a SQLServerCallableStatement object that generates
SQLServerResultSet objects with the given type, concurrency,
and holdability.

See Also
SQLServerConnection Members
SQLServerConnection Class
prepareCall Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerCallableStatement object for calling database stored procedures.

Syntax
public java.sql.CallableStatement prepareCall(java.lang.String sql)

Parameters
sql
A String containing an SQL statement.

Return Value
A CallableStatement object.

Exceptions
SQLServerException

Remarks
This prepareCall method is specified by the prepareCall method in the java.sql.Connection interface.

See Also
prepareCall Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
prepareCall Method ( java.lang.String, int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerCallableStatement object that generates SQLServerResultSet objects with the given type
and concurrency.

Syntax
public java.sql.CallableStatement prepareCall(java.lang.String sql,
int resultSetType,
int resultSetConcurrency)

Parameters
sql
A String containing an SQL statement.
resultSetType
An int that indicates the result set type.
resultSetConcurrency
An int that indicates the result set concurrency type.

Return Value
A CallableStatement object.

Exceptions
SQLServerException

Remarks
This prepareCall method is specified by the prepareCall method in the java.sql.Connection interface.

See Also
prepareCall Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
prepareCall Method ( java.lang.String, int, int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerCallableStatement object that generates SQLServerResultSet objects with the given type,
concurrency, and holdability.

Syntax
public java.sql.CallableStatement prepareCall(java.lang.String sql,
int nType,
int nConcur,
int nHold)

Parameters
sql
A String containing an SQL statement.
nType
An int that indicates the result set type.
nConcur
An int that indicates the result set concurrency type.
nHold
An int that indicates the result set holdability.

Return Value
A CallableStatement object.

Exceptions
SQLServerException

Remarks
This prepareCall method is specified by the prepareCall method in the java.sql.Connection interface.

See Also
prepareCall Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
prepareStatement Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerPreparedStatement object for sending parameterized SQL statements to the database.

Overload List
NAME DESC RIP T IO N

prepareStatement (java.lang.String) Creates a SQLServerPreparedStatement object for sending


parameterized SQL statements to the database.

prepareStatement (java.lang.String, int) Creates a SQLServerPreparedStatement object for sending


parameterized SQL statements to the database, and has the
capability to retrieve auto-generated keys.

prepareStatement (java.lang.String, int[]) Creates a SQLServerPreparedStatement object for sending


parameterized SQL statements to the database, and that is
capable of returning the auto-generated keys that are
designated by the given array.

prepareStatement (java.lang.String, int, int) Creates a SQLServerPreparedStatement object that


generates SQLServerResultSet objects with the given type
and concurrency.

prepareStatement (java.lang.String, int, int, int) Creates a SQLServerPreparedStatement object that


generates SQLServerResultSet objects with the given type,
concurrency, and holdability.

prepareStatement (java.lang.String, java.lang.String[]) Creates a SQLServerPreparedStatement object for sending


parameterized SQL statements to the database.

See Also
SQLServerConnection Members
SQLServerConnection Class
prepareStatement Method ( java.lang.String, int[])
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerPreparedStatement object for sending parameterized SQL statements to the database, and
that is capable of returning the auto-generated keys designated by the given array.

Syntax
public java.sql.PreparedStatement prepareStatement(java.lang.String sql,
int[] columnIndexes)

Parameters
sql
A String that contains an SQL statement.
columnIndexes
An array of ints.

Return Value
A PreparedStatement object.

Exceptions
SQLServerException

Remarks
This prepareStatement method is specified by the prepareStatement method in the java.sql.Connection interface.

See Also
prepareStatement Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
prepareStatement Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Creates a SQLServerPreparedStatement object for sending parameterized SQL statements to the database.

Syntax
public java.sql.PreparedStatement prepareStatement(java.lang.String sql)

Parameters
sql
A String containing an SQL statement.

Return Value
A PreparedStatement object.

Exceptions
SQLServerException

Remarks
This prepareStatement method is specified by the prepareStatement method in the java.sql.Connection interface.

See Also
prepareStatement Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
prepareStatement Method ( java.lang.String, int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerPreparedStatement object that generates SQLServerResultSet objects with the given type
and concurrency.

Syntax
public java.sql.PreparedStatement prepareStatement(java.lang.String sSql,
int resultSetType,
int resultSetConcurrency)

Parameters
sSql
A String containing an SQL statement.
resultSetType
An int that indicates the result set type.
resultSetConcurrency
An int that indicates the result set concurrency type.

Return Value
A PreparedStatement object.

Exceptions
SQLServerException

Remarks
This prepareStatement method is specified by the prepareStatement method in the java.sql.Connection interface.

See Also
SQLServerConnection Methods
SQLServerConnection Members
SQLServerConnection Class
prepareStatement Method ( java.lang.String, int, int,
int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerPreparedStatement object that generates SQLServerResultSet objects with the given type,
concurrency, and holdability.

Syntax
public java.sql.PreparedStatement prepareStatement(java.lang.String sql,
int nType,
int nConcur,
int nHold)

Parameters
sql
A String containing an SQL statement.
nType
An int that indicates the result set type.
nConcur
An int that indicates the result set concurrency type.
nHold
An int that indicates the result set holdability.

Return Value
A PreparedStatement object.

Exceptions
SQLServerException

Remarks
This prepareStatement method is specified by the prepareStatement method in the java.sql.Connection interface.

See Also
prepareStatement Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
prepareStatement Method ( java.lang.String,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a SQLServerPreparedStatement object for sending parameterized SQL statements to the database.

Syntax
public java.sql.PreparedStatement prepareStatement(java.lang.String sql,
java.lang.String[] columnNames)

Parameters
sql
A String containing an SQL statement.
columnNames
A String array of column names.

Return Value
A PreparedStatement object.

Exceptions
SQLServerException

Remarks
This prepareStatement method is specified by the prepareStatement method in the java.sql.Connection interface.

See Also
prepareStatement Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
releaseSavepoint Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Removes the given SQLServerSavepoint object from the current transaction.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server.

Syntax
public void releaseSavepoint(java.sql.Savepoint savepoint)

Parameters
savepoint
The SavePoint object to remove.

Exceptions
SQLServerException

Remarks
This releaseSavepoint method is specified by the releaseSavepoint method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
rollback Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Undoes all changes made in the current transaction and releases any database locks currently held by this
SQLServerConnection object.

Overload List
NAME DESC RIP T IO N

rollback () Undoes all changes made in the current transaction and


releases any database locks currently held by this
SQLServerConnection object.

rollback (java.sql.Savepoint) Undoes all changes made after the given


SQLServerSavepoint object was set.

See Also
SQLServerConnection Members
SQLServerConnection Class
rollback Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Undoes all changes made in the current transaction and releases any database locks currently held by this
SQLServerConnection object.

Syntax
public void rollback()

Exceptions
SQLServerException

Remarks
This rollBack method is specified by the rollBack method in the java.sql.Connection interface.
This method should be used only when auto-commit mode has been disabled.

See Also
rollback Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
rollback Method ( java.sql.Savepoint)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Undoes all changes made after the given SQLServerSavepoint object was set.

Syntax
public void rollback(java.sql.Savepoint s)

Parameters
s
The SavePoint object to rollback to.

Exceptions
SQLServerException

Remarks
This rollBack method is specified by the rollBack method in the java.sql.Connection interface.
This method should be used only when auto-commit mode has been disabled.

See Also
rollback Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
setAutoCommit Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the autocommit mode for this SQLServerConnection object to the given state.

Syntax
public void setAutoCommit(boolean value)

Parameters
value
true to enable autocommit mode for the connection, false to disable it.

Exceptions
SQLServerException

Remarks
This setAutoCommit method is specified by the setAutoCommit method in the java.sql.Connection interface.
If a connection is in autocommit mode, then all its SQL statements are run and committed as individual
transactions. Otherwise, its SQL statements are grouped into transactions that are ended by a call to either the
commit method or the rollback method. By default, new connections are in autocommit mode.
The commit occurs when the statement completes or the next run occurs, whichever comes first. When
statements return a SQLServerResultSet object, the statement completes when the last row of the result set has
been retrieved, or when the result set has been closed. In advanced cases, a single statement might return
multiple results in addition to output parameter values. In these cases, the commit occurs when all results and
output parameter values have been retrieved.
When the autocommit mode is false , the JDBC driver will implicitly start a new transaction after each commit.

NOTE
If this method is called during a transaction, the transaction is committed.

See Also
SQLServerConnection Members
SQLServerConnection Class
setCatalog Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the given catalog name to select a subspace of this SQLServerConnection object's database in which to
work.

Syntax
public void setCatalog(java.lang.String catalog)

Parameters
catalog
A String that contains the catalog name.

Exceptions
SQLServerException

Remarks
This setCatalog method is specified by the setCatalog method in the java.sql.Connection interface.
The catalog argument is escaped by the Microsoft JDBC Driver for SQL Server automatically. Using this method
sets the catalog property for the Connection object. It is not set implicitly in any other way.

See Also
SQLServerConnection Members
SQLServerConnection Class
setClientInfo Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the client information properties.

Overload List
NAME DESC RIP T IO N

setClientInfo Method (java.util.Properties) Sets the value of the connection's client information
properties.

setClientInfo Method (java.lang.String, java.lang.String) Sets the value of the specified client information property.

See Also
SQLServerConnection Members
SQLServerConnection Class
setClientInfo Method ( java.util.Properties)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the connection's client information properties.

Syntax
public void setClientInfo (java.util.Properties properties)

Parameters
properties
A Properties object that contains the list of client information properties to set.

Exceptions
SQLServerException

Remarks
This setClientInfo method is specified by the setClientInfo method in the java.sql.Connection interface.
The Microsoft JDBC Driver for SQL Server does not support any client information properties. This method
generates warnings if the properties input parameter does not refer to an empty property set. In other words,
this method generates warnings for the properties that the application wants to set. Applications should use
getWarnings method of the SQLServerConnection class to retrieve each warning.

See Also
setClientInfo Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
setClientInfo Method ( java.lang.String,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the specified client information property.

Syntax
public void setClientInfo (java.lang.String name,
java.lang.String value)

Parameters
name
A String that contains the name of the client information property to set.
value
A String that contains the value to set the client information property to.

Exceptions
SQLServerException

Remarks
This setClientInfo method is specified by the setClientInfo method in the java.sql.Connection interface.
The Microsoft JDBC Driver for SQL Server does not support any client information properties. In the 2.0 JDBC
Driver, this method generates a warning for a property. Applications should use getWarnings method of the
SQLServerConnection class to retrieve a warning.

See Also
setClientInfo Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
setDisableStatementPooling Method
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets statement pooling to true or false. If false, enables statement pooling to be used in coupling with
statementPoolingCacheSize value > 0.

Syntax
public void setDisableStatementPooling(boolean disableStatementPooling)

Parameters
disableStatementPooling
The new value of the disableStatementPooling connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
setEnablePrepareOnFirstPreparedStatementCall
Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Specifies the behavior for a specific connection instance. If value is false the first execution will call sp_executesql
and not prepare a statement, once the second execution happens it will call sp_prepexec and actually set up a
prepared statement handle. Following executions will call sp_execute. This relieves the need for sp_unprepare on
prepared statement close if the statement is only executed once.

Syntax
public void setEnablePrepareOnFirstPreparedStatementCall(boolean enablePrepareOnFirstPreparedStatementCall)

Parameters
enablePrepareOnFirstPreparedStatementCall
The new value of the enablePrepareOnFirstPreparedStatementCall connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
setHoldability Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Changes the holdability of SQLServerResultSet objects that are created by using this SQLServerSavepoint object
to the given holdability.

Syntax
public void setHoldability(int nNewHold)

Parameters
nNewHold
An int value that contains one of the following holdability levels:
HOLD_CURSORS_OVER_COMMIT
CLOSE_CURSORS_AT_COMMIT

Exceptions
SQLServerException

Remarks
This setHoldability method is specified by the setHoldability method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
setReadOnly Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Puts this SQLServerConnection object in read-only mode as a hint to the JDBC driver to enable database
optimizations.

NOTE
This method is not supported by the Microsoft JDBC Driver for SQL Server.

Syntax
public void setReadOnly(boolean readOnly)

Parameters
readOnly
true if the connection is to be read-only. Otherwise, false .

Exceptions
SQLServerException

Remarks
This setReadOnly method is specified by the setReadOnly method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
setSavepoint Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates an unnamed savepoint in the current transaction and returns the new SQLServerSavepoint object that
represents it.

Overload List
NAME DESC RIP T IO N

setSavepoint () Creates an unnamed savepoint in the current transaction


and returns the new SQLServerSavepoint object that
represents it.

setSavepoint (java.lang.String) Creates a savepoint with the given name in the current
transaction and returns the new SQLServerSavepoint object
that represents it.

See Also
SQLServerConnection Members
SQLServerConnection Class
setSavepoint Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates an unnamed savepoint in the current transaction, and returns the new SQLServerSavepoint object that
represents it.

Syntax
public java.sql.Savepoint setSavepoint()

Return Value
A SavePoint object.

Exceptions
SQLServerException

Remarks
This setSavePoint method is specified by the setSavePoint method in the java.sql.Connection interface.

See Also
setSavepoint Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
setSavepoint Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates a savepoint with the given name in the current transaction, and returns the new SQLServerSavepoint
object that represents it.

Syntax
public java.sql.Savepoint setSavepoint(java.lang.String sName)

Parameters
sName
A String value that contains the name of the savepoint.

Return Value
A SavePoint object.

Exceptions
SQLServerException

Remarks
This setSavePoint method is specified by the setSavePoint method in the java.sql.Connection interface.
The sName argument is automatically escaped by the Microsoft JDBC Driver for SQL Server.

See Also
setSavepoint Method (SQLServerConnection)
SQLServerConnection Members
SQLServerConnection Class
setServerPreparedStatementDiscardThreshold
Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Specifies the behavior for a specific connection instance. This setting controls how many outstanding prepared
statement discard actions (sp_unprepare) can be outstanding per connection before a call to clean up the
outstanding handles on the server is executed. When the setting is <= 1 un-prepare actions are executed
immediately on prepared statement close. If the value is set to > 1 these calls are batched together to avoid
overhead of calling sp_unprepare too often.

Syntax
public void setServerPreparedStatementDiscardThreshold(boolean thresholdValue)

Parameters
thresholdValue
The new value of the ser verPreparedStatementDiscardThreshold connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
setStatementPoolingCacheSize Method
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the size of the prepared statement cache for this connection. Works if disableStatementPooling is set to
false and value > 0.

Syntax
public void setStatementPoolingCacheSize(int statementPoolingCacheSize)

Parameters
statementPoolingCacheSize
The new value of the statementPoolingCacheSize connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerConnection Members
SQLServerConnection Class
setTransactionIsolation Method
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to change the transaction isolation level for this SQLServerConnection object to the one given.

Syntax
public void setTransactionIsolation(int level)

Parameters
level
An int value that contains one of the following isolation levels:
TRANSACTION_READ_UNCOMMITTED
TRANSACTION_READ_COMMITTED
TRANSACTION_REPEATABLE_READ
TRANSACTION_SERIALIZABLE
TRANSACTION_SNAPSHOT = 0x1000

Exceptions
SQLServerException

Remarks
This setTransactionIsolation method is specified by the setTransactionIsolation method in the java.sql.Connection
interface.
Transactions are not committed if this method is called in the middle of a transaction.

See Also
SQLServerConnection Members
SQLServerConnection Class
setTypeMap Method (SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Installs the given TypeMap object as the type map for this SQLServerConnection object.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server.

Syntax
public void setTypeMap(java.util.Map map)

Parameters
map
A TypeMap object.

Exceptions
SQLServerException

Remarks
This setTypeMap method is specified by the setTypeMap method in the java.sql.Connection interface.

See Also
SQLServerConnection Members
SQLServerConnection Class
ISQLServerConnection Fields
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerConnection, see SQLServerConnection Members.

See Also
SQLServerConnection Class
TRANSACTION_SNAPSHOT Field
(SQLServerConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to specify the snapshot transaction isolation level.

Syntax
public static final int TRANSACTION_SNAPSHOT

Field Value
An int value.

See Also
SQLServerConnection Members
SQLServerConnection Class
SQLServerConnectionPoolDataSource Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents physical database connections for connection pool managers.
Package: com.microsoft.sqlserver.jdbc
Extends: SQLServerDataSource
Implements: javax.sql.ConnectionPoolDataSource

Syntax
public class SQLServerConnectionPoolDataSource

Remarks
SQLServerConnectionPoolDataSource is typically used in Java Application Server environments that support
built-in connection pooling and require a ConnectionPoolDataSource to provide physical connections, such as
Java Platform, Enterprise Edition (Java EE) application servers that provide JDBC 3.0 API spec connection
pooling.

See Also
SQLServerConnectionPoolDataSource Members
JDBC Driver API Reference
SQLServerConnectionPoolDataSource Members
4/27/2022 • 4 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerConnectionPoolDataSource class.

Constructors
NAME DESC RIP T IO N

SQLServerConnectionPoolDataSource () Initializes a new instance of the


SQLServerConnectionPoolDataSource class.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

getApplicationIntent (Inherited from SQLServerDataSource) Returns the value of


the applicationIntent connection property.

getApplicationName (Inherited from SQLServerDataSource) Returns the


application name.

getConnection (Inherited from SQLServerDataSource) Tries to establish a


connection with the data source that this DataSource object
represents.

getDatabaseName (Inherited from SQLServerDataSource) Returns the database


name.

getDescription (Inherited from SQLServerDataSource) Returns a description


of the data source.

getFailoverPartner (Inherited from SQLServerDataSource) Returns the name of


the failover server that is used in a database mirroring
configuration.

getInstanceName (Inherited from SQLServerDataSource) Returns the SQL


Server instance name.
NAME DESC RIP T IO N

getLastUpdateCount (Inherited from SQLServerDataSource) Returns a boolean


value that indicates if the lastUpdateCount property is
enabled.

getLockTimeout (Inherited from SQLServerDataSource) Returns an int value


that indicates the number of milliseconds that the database
will wait before reporting a lock time out.

getLoginTimeout (Inherited from SQLServerDataSource) Returns the number


of seconds that this DataSource object will wait while trying
to make a connection.

getLogWriter (Inherited from SQLServerDataSource) Returns a character


output stream to be used for all logging and tracing
messages.

getMultiSubnetFailover (Inherited from SQLServerDataSource) Returns the value of


the multiSubnetFailover connection property.

getPooledConnection Tries to establish a physical database connection that can be


used as a pooled connection.

getPortNumber (Inherited from SQLServerDataSource) Returns the current


port number that is used to communicate with SQL Server.

getReference Returns a reference to this DataSource object.

getSelectMethod (Inherited from SQLServerDataSource) Returns the default


cursor type that is used for all result sets that are created by
using this DataSource object.

getSendStringParametersAsUnicode (Inherited from SQLServerDataSource) Returns a Boolean


value that indicates if sending string parameters to the
server in UNICODE format is enabled.

getServerName (Inherited from SQLServerDataSource) Returns the name of


the computer that is running SQL Server.

getURL (Inherited from SQLServerDataSource) Returns the URL that


is used to connect to the data source.

getUser (Inherited from SQLServerDataSource) Returns the user


name that is used to connect the data source.

getWorkstationID (Inherited from SQLServerDataSource) Returns the name of


the client computer name that is used to connect to the
data source.

getXopenStates (Inherited from SQLServerDataSource) Returns a Boolean


value that indicates if converting SQL states to XOPEN
compliant states is enabled.

isWrapperFor Indicates whether this object is a wrapper for the specified


interface.
NAME DESC RIP T IO N

setApplicationIntent (Inherited from SQLServerDataSource) Sets the value of the


applicationIntent connection property.

setApplicationName (Inherited from SQLServerDataSource) Sets the application


name.

setAuthenticationSceme (Inherited from SQLServerDataSource) Indicates the kind of


integrated security you want your application to use.

setDatabaseName (Inherited from SQLServerDataSource) Sets the database


name to connect to.

setDescription (Inherited from SQLServerDataSource) Sets the description


of the data source.

setFailoverPartner (Inherited from SQLServerDataSource) Sets the name of the


failover server that is used in a database mirroring
configuration.

setInstanceName (Inherited from SQLServerDataSource) Sets the SQL Server


instance name.

setIntegratedSecurity (Inherited from SQLServerDataSource) Sets a Boolean value


that indicates if the integratedSecurity property is enabled.

setLastUpdateCount (Inherited from SQLServerDataSource) Sets a Boolean value


that indicates if the lastUpdateCount property is enabled.

setLockTimeout (Inherited from SQLServerDataSource) Sets an int value that


indicates the number of milliseconds to wait before the
database reports a lock time out.

setLoginTimeout (Inherited from SQLServerDataSource) Sets the number of


seconds that this DataSource object will wait while trying to
make a connection.

setLogWriter (Inherited from SQLServerDataSource) Sets a character


output stream to be used for all logging and tracing
messages.

setMultiSubnetFailover (Inherited from SQLServerDataSource) Sets the value of the


multiSubnetFailover connection property.

setPassword (Inherited from SQLServerDataSource) Sets the password


that will be used to connect to SQL Server.

setPortNumber (Inherited from SQLServerDataSource) Sets the port number


to be used to communicate with SQL Server.

setSelectMethod (Inherited from SQLServerDataSource) Sets the default


cursor type that is used for all result sets that are created by
using this DataSource object.
NAME DESC RIP T IO N

setSendStringParametersAsUnicode (Inherited from SQLServerDataSource) Sets a Boolean value


that indicates if sending string parameters to the server in
UNICODE format is enabled.

setServerName (Inherited from SQLServerDataSource) Sets the name of the


computer that is running SQL Server.

setURL (Inherited from SQLServerDataSource) Sets the URL that is


used to connect to the data source.

setUser (Inherited from SQLServerDataSource) Sets the user name


that is used to connect the data source.

setWorkstationID (Inherited from SQLServerDataSource) Sets the client


computer name that is used to connect to the data source.

setXopenStates (Inherited from SQLServerDataSource) Sets a boolean value


that indicates if converting SQL states to XOPEN compliant
states is enabled.

unwrap Returns an object that implements the specified interface to


allow access to the Microsoft JDBC Driver for SQL Server-
specific methods.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

com.microsoft.sqlserver.jdbc.SQLServerDataSource getApplicationName, getConnection, getDatabaseName,


getDescription, getFailoverPartner, getInstanceName,
getLastUpdateCount, getLockTimeout, getLoginTimeout,
getLogWriter, getPortNumber, getSelectMethod,
getSendStringParametersAsUnicode, getServerName,
getURL, getUser, getWorkstationID, getXopenStates,
setApplicationName, setDatabaseName, setDescription,
setFailoverPartner, setInstanceName, setIntegratedSecurity,
setLastUpdateCount, setLockTimeout, setLoginTimeout,
setLogWriter, setPassword, setPortNumber, setSelectMethod,
setSendStringParametersAsUnicode, setServerName, setURL,
setUser, setWorkstationID, setXopenStates

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

java.sql.Wrapper isWrapperFor, unwrap

javax.sql.ConnectionPoolDataSource getLoginTimeout, getLogWriter, setLoginTimeout,


setLogWriter, getPooledConnection

See Also
SQLServerConnectionPoolDataSource Class
SQLServerConnectionPoolDataSource Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerConnectionPoolDataSource, see
SQLServerConnectionPoolDataSource Members.
SQLServerConnectionPoolDataSource Constructor
()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerConnectionPoolDataSource class.

Syntax
public SQLServerConnectionPoolDataSource()

See Also
SQLServerConnectionPoolDataSource Constructors
SQLServerConnectionPoolDataSource Members
SQLServerConnectionPoolDataSource Class
SQLServerConnectionPoolDataSource Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerConnectionPoolDataSource, see
SQLServerConnectionPoolDataSource Members.

See Also
SQLServerConnectionPoolDataSource Class
getPooledConnection Method
(SQLServerConnectionPoolDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to establish a physical database connection that can be used as a pooled connection.

Overload List
NAME DESC RIP T IO N

getPooledConnection () Tries to establish a physical database connection that can be


used as a pooled connection.

getPooledConnection (java.lang.String, java.lang.String) Tries to establish a physical database connection that can be
used as a pooled connection based on the given user name
and password.

See Also
SQLServerConnectionPoolDataSource Methods
SQLServerConnectionPoolDataSource Members
SQLServerConnectionPoolDataSource Class
getPooledConnection Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to establish a physical database connection that can be used as a pooled connection.

Syntax
public javax.sql.PooledConnection getPooledConnection()

Return Value
A SQLServerPooledConnection object.

Exceptions
java.sql.SQLException

Remarks
This getPooledConnection method is specified by the getPooledConnection method in the
javax.sql.ConnectionPoolDataSource interface.

See Also
getPooledConnection
SQLServerConnectionPoolDataSource Methods
SQLServerConnectionPoolDataSource Members
SQLServerConnectionPoolDataSource Class
getPooledConnection Method ( java.lang.String,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to establish a physical database connection that can be used as a pooled connection based on the given
user name and password.

Syntax
public javax.sql.PooledConnection getPooledConnection(java.lang.String user,
java.lang.String password)

Parameters
user
A String that contains the user name.
passwword
A String that contains the password.

Return Value
A SQLServerPooledConnection object.

Exceptions
java.sql.SQLException

Remarks
This getPooledConnection method is specified by the getPooledConnection method in the
javax.sql.ConnectionPoolDataSource interface.

See Also
getPooledConnection
SQLServerConnectionPoolDataSource Methods
SQLServerConnectionPoolDataSource Members
SQLServerConnectionPoolDataSource Class
getReference Method
(SQLServerConnectionPoolDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a reference to this SQLServerConnectionPoolDataSource object.

Syntax
public javax.naming.Reference getReference()

Return Value
A Reference object.

Remarks
This getReference method is specified by the getReference method in the javax.naming.Referenceable interface.
It overrides the getReference method of the SQLServerDataSource class.

See Also
SQLServerConnectionPoolDataSource Methods
SQLServerConnectionPoolDataSource Members
SQLServerConnectionPoolDataSource Class
isWrapperFor Method
(SQLServerConnectionPoolDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this object is a wrapper for the specified interface.

Syntax
public boolean isWrapperFor(Class iface)

Parameters
iface
A class defining an interface.

Return Value
true if this object implements the interface or wraps an object that implements the interface. Otherwise, false .

Exceptions
SQLServerException

Remarks
The isWrapperFor method and the unwrap method are defined by the java.sql.Wrapper interface, which is
introduced in the JDBC 4.0 Spec.
If this method returns true, calling unwrap with the same argument will succeed.
For more information, see Wrappers and Interfaces.

See Also
unwrap Method (SQLServerConnectionPoolDataSource)
SQLServerConnectionPoolDataSource Methods
SQLServerConnectionPoolDataSource Members
SQLServerConnectionPoolDataSource Class
unwrap Method
(SQLServerConnectionPoolDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an object that implements the specified interface to allow access to the Microsoft JDBC Driver for SQL
Server-specific methods.

Syntax
public <T> T unwrap(Class<T> iface)

Parameters
iface
A class of type T defining an interface.

Return Value
An object that implements the specified interface.

Exceptions
SQLServerException

Remarks
The unwrap method is defined by the java.sql.Wrapper interface, which is introduced in the JDBC 4.0 Spec.
Applications might need to access extensions to the JDBC API that are specific to the Microsoft JDBC Driver for
SQL Server. The unwrap method supports unwrapping to public classes that this object extends, if the classes
expose vendor extensions.
The SQLServerConnectionPoolDataSource class extends the SQLServerDataSource class. When this method is
called, the object unwraps to the SQLServerDataSource class and the SQLServerConnectionPoolDataSource
class.
For more information, see Wrappers and Interfaces.

See Also
SQLServerConnectionPoolDataSource Methods
SQLServerConnectionPoolDataSource Members
SQLServerConnectionPoolDataSource Class
SQLServerDatabaseMetaData Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents the metadata for the database.
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: java.sql.DatabaseMetaData, java.io.Serializable

Syntax
public final class SQLServerDatabaseMetaData

See Also
SQLServerDatabaseMetaData Members
JDBC Driver API Reference
SQLServerDatabaseMetaData Members
4/27/2022 • 12 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerDatabaseMetaData class.

Constructors
None.

Fields
None.

Inherited Fields
NAME DESC RIP T IO N

java.sql.DatabaseMetaData attributeNoNulls, attributeNullable,


attributeNullableUnknown, bestRowNotPseudo,
bestRowPseudo, bestRowSession, bestRowTemporary,
bestRowTransaction, bestRowUnknown, columnNoNulls,
columnNullable, columnNullableUnknown,
importedKeyCascade, importedKeyInitiallyDeferred,
importedKeyInitiallyImmediate, importedKeyNoAction,
importedKeyNotDeferrable, importedKeyRestrict,
importedKeySetDefault, importedKeySetNull,
procedureColumnIn, procedureColumnInOut,
procedureColumnOut, procedureColumnResult,
procedureColumnReturn, procedureColumnUnknown,
procedureNoNulls, procedureNoResult, procedureNullable,
procedureNullableUnknown, procedureResultUnknown,
procedureReturnsResult, sqlStateSQL, sqlStateSQL99,
sqlStateXOpen, tableIndexClustered, tableIndexHashed,
tableIndexOther, tableIndexStatistic, typeNoNulls,
typeNullable, typeNullableUnknown, typePredBasic,
typePredChar, typePredNone, typeSearchable,
versionColumnNotPseudo, versionColumnPseudo,
versionColumnUnknown

Methods
NAME DESC RIP T IO N

allProceduresAreCallable Retrieves whether the current user has permissions to call all
the procedures returned by the getProcedures method.

allTablesAreSelectable Retrieves whether the current user has permissions to use all
the tables returned by the getTables method in a SELECT
statement.
NAME DESC RIP T IO N

autoCommitFailureClosesAllResultSets Indicates whether the JDBC driver closes all the open result
sets, including the holdable ones, when an auto-commit is
enabled and an exception is raised.

dataDefinitionCausesTransactionCommit Retrieves whether a data definition statement within a


transaction forces the transaction to commit.

dataDefinitionIgnoredInTransactions Retrieves whether this database ignores a data definition


statement within a transaction.

deletesAreDetected Retrieves whether or not a visible row delete can be detected


by calling the rowDeleted method of the SQLServerResultSet
class.

doesMaxRowSizeIncludeBlobs Retrieves whether the return value for the getMaxRowSize


method includes the SQL data types LONGVARCHAR and
LONGVARBINARY.

getAttributes Retrieves a description of the given attribute of the given


type for a user-defined type that is available in the given
schema and catalog.

getBestRowIdentifier Retrieves a description of the optimal set of columns of a


table that uniquely identifies a row.

getCatalogs Retrieves the catalog names that are available in the


connected server.

getCatalogSeparator Retrieves the String that this database uses as the separator
between a catalog and table name.

getCatalogTerm Retrieves the database vendor's preferred term for "catalog".

getClientInfoProperties Retrieves a list of the client information properties that the


driver supports.

getColumnPrivileges Retrieves a description of the access rights for the columns in


a table.

getColumns Retrieves a description of the table columns that are


available in the specified catalog.

getConnection Retrieves the connection that produced this metadata object.

getCrossReference Retrieves a description of the foreign key columns in the


given foreign key table that references the primary key
columns of the given primary key table.

getDatabaseMajorVersion Retrieves the major version number of the underlying


database.

getDatabaseMinorVersion Retrieves the minor version number of the underlying


database.
NAME DESC RIP T IO N

getDatabaseProductName Retrieves the name of this database product.

getDatabaseProductVersion Retrieves the version number of this database product.

getDefaultTransactionIsolation Retrieves the default transaction isolation level for this


database.

getDriverMajorVersion Retrieves the major version number of this JDBC driver.

getDriverMinorVersion Retrieves the minor version number of this JDBC driver.

getDriverName Retrieves the name of this JDBC driver.

getDriverVersion Retrieves the version number of this JDBC driver.

getExportedKeys Retrieves a description of the foreign key columns that


reference the given table's primary key columns.

getExtraNameCharacters Retrieves all the extra characters that can be used in


unquoted identifier names, for example, those beyond a-z,
A-Z, 0-9, and _.

getFunctions Retrieves a description of the system and user functions.

getFunctionColumns Retrieves a description of the specified catalog's system- or


user-function parameters and return type.

getIdentifierQuoteString Retrieves the String that is used to quote SQL identifiers.

getImportedKeys Retrieves a description of the primary key columns that are


referenced by a table's foreign key columns.

getIndexInfo Retrieves a description of the indexes and statistics of the


given table.

getJDBCMajorVersion Retrieves the major JDBC version number for this driver.

getJDBCMinorVersion Retrieves the minor JDBC version number for this driver.

getMaxBinaryLiteralLength Retrieves the maximum number of hex characters that this


database allows in an inline binary literal.

getMaxCatalogNameLength Retrieves the maximum number of characters that this


database allows in a catalog name.

getMaxCharLiteralLength Retrieves the maximum number of characters that this


database allows for a character literal.

getMaxColumnNameLength Retrieves the maximum number of characters that this


database allows for a column name.
NAME DESC RIP T IO N

getMaxColumnsInGroupBy Retrieves the maximum number of columns that this


database allows in a GROUP BY clause.

getMaxColumnsInIndex Retrieves the maximum number of columns that this


database allows in an index.

getMaxColumnsInOrderBy Retrieves the maximum number of columns that this


database allows in an ORDER BY clause.

getMaxColumnsInSelect Retrieves the maximum number of columns that this


database allows in a SELECT list.

getMaxColumnsInTable Retrieves the maximum number of columns that this


database allows in a table.

getMaxConnections Retrieves the maximum number of concurrent connections


to this database that are possible.

getMaxCursorNameLength Retrieves the maximum number of characters that this


database allows in a cursor name.

getMaxIndexLength Retrieves the maximum number of bytes that this database


allows for an index, including all of the parts of the index.

getMaxProcedureNameLength Retrieves the maximum number of characters that this


database allows in a procedure name.

getMaxRowSize Retrieves the maximum number of bytes that this database


allows in a single row.

getMaxSchemaNameLength Retrieves the maximum number of characters that this


database allows in a schema name.

getMaxStatementLength Retrieves the maximum number of characters that this


database allows in an SQL statement.

getMaxStatements Retrieves the maximum number of active statements to this


database that can be open at the same time.

getMaxTableNameLength Retrieves the maximum number of characters that this


database allows in a table name.

getMaxTablesInSelect Retrieves the maximum number of tables that this database


allows in a SELECT statement.

getMaxUserNameLength Retrieves the maximum number of characters that this


database allows in a user name.

getNumericFunctions Retrieves a comma-separated list of math functions that are


available with this database.

getPrimaryKeys Retrieves a description of the primary key columns of the


given table.
NAME DESC RIP T IO N

getProcedureColumns Retrieves a description of the stored procedure parameters


and result columns.

getProcedures Retrieves a description of the stored procedures that are


available in the given catalog, schema, or stored procedure
name pattern.

getProcedureTerm Retrieves the preferred term for "procedure" in this database.

getResultSetHoldability Retrieves the default holdability of result sets for this


database.

getRowIdLifetime Returns a status indicating whether or not SQL RowId data


type is supported. If supported, it returns the lifetime for
which a RowId object remains valid.

getSchemas Retrieves the schema names that are available in the current
database.

getSchemaTerm Retrieves the preferred term for "schema" in this database.

getSearchStringEscape Retrieves the String that can be used to escape wildcard


characters.

getSQLKeywords Retrieves a comma-separated list of all of this database's SQL


keywords that are not also SQL92 keywords.

getSQLStateType Indicates whether the SQLSTATE returned by the


SQLException.getSQLState method is X/Open (now known
as Open Group), SQL CLI, SQL99 (JDBC 3.0), or SQL:2003
(JDBC 4.0).

getStringFunctions Retrieves a comma-separated list of String functions that


are available with this database.

getSuperTables Retrieves a description of the table hierarchies that are


defined in a particular schema in this database.

getSuperTypes Retrieves a description of the user-defined type hierarchies


that are defined in a particular schema in this database.

getSystemFunctions Retrieves a comma-separated list of system functions that


are available with this database.

getTablePrivileges Retrieves a description of the access rights for each table


that is available in the given catalog, schema, or table name
pattern.

getTables Retrieves a description of the tables that are available in the


given catalog, schema, or table name pattern.

getTableTypes Retrieves the table types that are available in the current
database.
NAME DESC RIP T IO N

getTimeDateFunctions Retrieves a comma-separated list of the time and date


functions that are available with this database.

getTypeInfo Retrieves a description of all the standard SQL types that are
supported by the current database.

getUDTs Retrieves a description of the user-defined types that are


defined in a particular schema.

getURL Retrieves the URL for this database.

getUserName Retrieves the user name as known to this database.

getVersionColumns Retrieves a description of the columns of a table that is


automatically updated when any value in a row is updated.

insertsAreDetected Retrieves whether or not a visible row insert can be detected


by calling the method rowInserted method of the
SQLServerResultSet class.

isCatalogAtStart Retrieves whether a catalog appears at the start of a fully


qualified table name.

isReadOnly Retrieves whether this database is in read-only mode.

locatorsUpdateCopy Indicates whether updates made to a LOB are made on a


copy or directly to the LOB.

nullPlusNonNullIsNull Indicates whether this database supports concatenations


between NULL and non-NULL values being NULL.

nullsAreSortedAtEnd Retrieves whether NULL values are sorted at the end


regardless of sort order.

nullsAreSortedAtStart Retrieves whether NULL values are sorted at the start


regardless of sort order.

nullsAreSortedHigh Retrieves whether NULL values are sorted high.

nullsAreSortedLow Retrieves whether NULL values are sorted low.

othersDeletesAreVisible Retrieves whether deletes that are made by others are


visible.

othersInsertsAreVisible Retrieves whether inserts that are made by others are visible.

othersUpdatesAreVisible Retrieves whether updates that are made by others are


visible.

ownDeletesAreVisible Retrieves whether a result set's own deletes are visible.

ownInsertsAreVisible Retrieves whether a result set's own inserts are visible.


NAME DESC RIP T IO N

ownUpdatesAreVisible Retrieves whether the result set's own updates are visible.

storesLowerCaseIdentifiers Retrieves whether this database treats mixed-case SQL


identifiers that are not enclosed in quotation marks as case-
insensitive and stores them in lowercase.

storesLowerCaseQuotedIdentifiers Retrieves whether this database treats mixed-case SQL


identifiers that are enclosed in quotation marks as case-
insensitive and stores them in lowercase.

storesMixedCaseIdentifiers Retrieves whether this database treats mixed-case SQL


identifiers that are not enclosed in quotation marks as case-
insensitive and stores them in mixed case.

storesMixedCaseQuotedIdentifiers Retrieves whether this database treats mixed-case SQL


identifiers that are enclosed in quotation marks as case-
insensitive and stores them in mixed case.

storesUpperCaseIdentifiers Retrieves whether this database treats mixed-case SQL


identifiers that are not enclosed in quotation marks as case-
insensitive and stores them in uppercase.

storesUpperCaseQuotedIdentifiers Retrieves whether this database treats mixed-case SQL


identifiers that are enclosed in quotation marks as case-
insensitive and stores them in uppercase.

supportsAlterTableWithAddColumn Retrieves whether this database supports ALTER TABLE with


add column.

supportsAlterTableWithDropColumn Retrieves whether this database supports ALTER TABLE with


drop column.

supportsANSI92EntryLevelSQL Retrieves whether this database supports the ANSI92 entry


level SQL grammar.

supportsANSI92FullSQL Retrieves whether this database supports the ANSI92 full


SQL grammar.

supportsANSI92IntermediateSQL Retrieves whether this database supports the ANSI92


intermediate SQL grammar.

supportsBatchUpdates Retrieves whether this database supports batch updates.

supportsCatalogsInDataManipulation Retrieves whether a catalog name can be used in a data


manipulation statement.

supportsCatalogsInIndexDefinitions Retrieves whether a catalog name can be used in an index


definition statement.

supportsCatalogsInPrivilegeDefinitions Retrieves whether a catalog name can be used in a privilege


definition statement.

supportsCatalogsInProcedureCalls Retrieves whether a catalog name can be used in a


procedure call statement.
NAME DESC RIP T IO N

supportsCatalogsInTableDefinitions Retrieves whether a catalog name can be used in a table


definition statement.

supportsColumnAliasing Retrieves whether this database supports column aliasing.

supportsConvert Retrieves whether this database supports the CONVERT


function between SQL types.

supportsCoreSQLGrammar Retrieves whether this database supports the ODBC Core


SQL grammar.

supportsCorrelatedSubqueries Retrieves whether this database supports correlated


subqueries.

supportsDataDefinitionAndDataManipulationTransactions Retrieves whether this database supports both data


definition and data manipulation statements within a
transaction.

supportsDataManipulationTransactionsOnly Retrieves whether this database supports only data


manipulation statements within a transaction.

supportsDifferentTableCorrelationNames Retrieves whether, when table correlation names are


supported, they are restricted to being different from the
names of the tables.

supportsExpressionsInOrderBy Retrieves whether this database supports expressions in


ORDER BY lists.

supportsExtendedSQLGrammar Retrieves whether this database supports the ODBC


Extended SQL grammar.

supportsFullOuterJoins Retrieves whether this database supports full nested outer


joins.

supportsGetGeneratedKeys Retrieves whether auto-generated keys can be retrieved


after a statement has been executed.

supportsGroupBy Retrieves whether this database supports some form of the


GROUP BY clause.

supportsGroupByBeyondSelect Retrieves whether this database supports using columns not


included in the SELECT statement in a GROUP BY clause
provided that all of the columns in the SELECT statement are
included in the GROUP BY clause.

supportsGroupByUnrelated Retrieves whether this database supports using a column


that is not in the SELECT statement in a GROUP BY clause.

supportsIntegrityEnhancementFacility Retrieves whether this database supports the SQL Integrity


Enhancement Facility.

supportsLikeEscapeClause Retrieves whether this database supports specifying a LIKE


escape clause.
NAME DESC RIP T IO N

supportsLimitedOuterJoins Retrieves whether this database provides limited support for


outer joins.

supportsMinimumSQLGrammar Retrieves whether this database supports the ODBC


Minimum SQL grammar.

supportsMixedCaseIdentifiers Retrieves whether this database treats mixed-case SQL


identifiers that are not enclosed in quotation marks as case-
insensitive and stores them in mixed case.

supportsMixedCaseQuotedIdentifiers Retrieves whether this database treats mixed-case SQL


identifiers that are enclosed in quotation marks as case-
insensitive and stores them in mixed case.

supportsMultipleOpenResults Retrieves whether it is possible to have multiple


SQLServerResultSet objects returned from a
SQLServerCallableStatement object simultaneously.

supportsMultipleResultSets Retrieves whether this database supports getting multiple


SQLServerResultSet objects from a single call to the execute
method of the SQLServerCallableStatement class.

supportsMultipleTransactions Retrieves whether this database allows having multiple


transactions open at once on different connections.

supportsNamedParameters Retrieves whether this database supports named parameters


in callable statements.

supportsNonNullableColumns Retrieves whether columns in this database can be defined


as non-nullable.

supportsOpenCursorsAcrossCommit Retrieves whether this database supports keeping cursors


open across commits.

supportsOpenCursorsAcrossRollback Retrieves whether this database supports keeping cursors


open across rollbacks.

supportsOpenStatementsAcrossCommit Retrieves whether this database supports keeping


statements open across commits.

supportsOpenStatementsAcrossRollback Retrieves whether this database supports keeping


statements open across rollbacks.

supportsOrderByUnrelated Retrieves whether this database supports using a column


that is not in the SELECT statement in an ORDER BY clause.

supportsOuterJoins Retrieves whether this database supports some form of


outer join.

supportsPositionedDelete Retrieves whether this database supports positioned DELETE


statements.

supportsPositionedUpdate Retrieves whether this database supports positioned


UPDATE statements.
NAME DESC RIP T IO N

supportsResultSetConcurrency Retrieves whether this database supports the given


concurrency type in combination with the given result set
type.

supportsResultSetHoldability Retrieves whether this database supports the given result


set holdability.

supportsResultSetType Retrieves whether this database supports the given result


set type.

supportsSavepoints Retrieves whether this database supports savepoints.

supportsSchemasInDataManipulation Retrieves whether a schema name can be used in a data


manipulation statement.

supportsSchemasInIndexDefinitions Retrieves whether a schema name can be used in an index


definition statement.

supportsSchemasInPrivilegeDefinitions Retrieves whether a schema name can be used in a privilege


definition statement.

supportsSchemasInProcedureCalls Retrieves whether a schema name can be used in a


procedure call statement.

supportsSchemasInTableDefinitions Retrieves whether a schema name can be used in a table


definition statement.

supportsSelectForUpdate Retrieves whether this database supports SELECT FOR


UPDATE statements.

supportsStatementPooling Retrieves whether this database supports statement pooling.

supportsStoredFunctionsUsingCallSyntax Indicates whether the current database supports invoking


user- or vendor-defined functions by using the stored
procedure escape syntax.

supportsStoredProcedures Retrieves whether this database supports stored procedure


calls that use the stored procedure escape syntax.

supportsSubqueriesInComparisons Retrieves whether this database supports subqueries in


comparison expressions.

supportsSubqueriesInExists Retrieves whether this database supports subqueries in


EXISTS expressions.

supportsSubqueriesInIns Retrieves whether this database supports subqueries in IN


statements.

supportsSubqueriesInQuantifieds Retrieves whether this database supports subqueries in


quantified expressions.

supportsTableCorrelationNames Retrieves whether this database supports table correlation


names.
NAME DESC RIP T IO N

supportsTransactionIsolationLevel Retrieves whether this database supports the given


transaction isolation level.

supportsTransactions Retrieves whether this database supports transactions.

supportsUnion Retrieves whether this database supports SQL UNION.

supportsUnionAll Retrieves whether this database supports SQL UNION ALL.

updatesAreDetected Retrieves whether or not a visible row update can be


detected by calling the rowUpdated method of the
SQLServerResultSet class.

usesLocalFilePerTable Retrieves whether this database uses a file for each table.

usesLocalFiles Retrieves whether this database stores tables in a local file.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

java.sql.Wrapper isWrapperFor, unwrap

See Also
SQLServerDatabaseMetaData Class
SQLServerDatabaseMetaData Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerDatabaseMetaData, see SQLServerDatabaseMetaData
Members.
allProceduresAreCallable Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the current user has permissions to call all the procedures that are returned by the
getProcedures method.

Syntax
public boolean allProceduresAreCallable()

Return Value
true if the user has permissions to call all the procedures. Otherwise, false .

Exceptions
SQLServerException

Remarks
This allProceduresAreCallable method is specified by the allProceduresAreCallable method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
allTablesAreSelectable Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the current user has permissions to use all the tables that are returned by the getTables
method in a SELECT statement.

Syntax
public boolean allTablesAreSelectable()

Return Value
true if the user has permissions to call use all the tables. Otherwise, false .

Exceptions
SQLServerException

Remarks
This allTablesAreSelectable method is specified by the allTablesAreSelectable method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
autoCommitFailureClosesAllResultSets Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether the JDBC driver closes all the open result sets, including the holdable ones, when an auto-
commit is enabled and an exception is raised.

Syntax
public boolean autoCommitFailureClosesAllResultSets()

Return Value
true if all the open result sets, including the holdable ones, are closed when an auto-commit is enabled and an
exception is raised. Otherwise, false .

Exceptions
SQLServerException

Remarks
This autoCommitFailureClosesAllResultSets method is specified by the autoCommitFailureClosesAllResultSets
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
dataDefinitionCausesTransactionCommit Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a data definition statement within a transaction forces the transaction to commit.

Syntax
public boolean dataDefinitionCausesTransactionCommit()

Return Value
true if the DDL statement forces a commit. Otherwise, false .

Exceptions
SQLServerException

Remarks
This dataDefinitionCausesTransactionCommit method is specified by the
dataDefinitionCausesTransactionCommit method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
dataDefinitionIgnoredInTransactions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database ignores a data definition statement within a transaction.

Syntax
public boolean dataDefinitionIgnoredInTransactions()

Return Value
true if DDL statements are ignored within transactions. Otherwise, false .

Exceptions
SQLServerException

Remarks
This dataDefinitionIgnoredInTransactions method is specified by the dataDefinitionIgnoredInTransactions
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
deletesAreDetected Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether or not a visible row delete can be detected by calling the rowDeleted method of the
SQLServerResultSet class.

Syntax
public boolean deletesAreDetected(int type)

Parameters
type
An int that indicates the result set type, which can be one of the following values as defined in java.sql.ResultSet
or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if a gap replaces the deleted row. false if the deleted row is removed.
When using the Microsoft JDBC Driver for SQL Server with a SQL Server database, this method returns true for
TYPE_SS_SCROLL_KEYSET cursors and false for all other result set types.

Exceptions
SQLServerException

Remarks
This deletesAreDetected method is specified by the deletesAreDetected method in the
java.sql.DatabaseMetaData interface.

NOTE
SQL Server detects deleted rows for all updatable cursor types, although the detection is transient for forward and
dynamic cursors.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
doesMaxRowSizeIncludeBlobs Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the return value for the getMaxRowSize method includes the SQL data types LONGVARCHAR
and LONGVARBINARY.

Syntax
public boolean doesMaxRowSizeIncludeBlobs()

Return Value
true if the return value includes the data types. Otherwise, false .

Exceptions
SQLServerException

Remarks
This doesMoxRowSizeIncludeBlobs method is specified by the doesMoxRowSizeIncludeBlobs method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getAttributes Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the given attribute of the given type for a user-defined type that is available in the
given schema and catalog.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server. If called, it will always return an
empty result set.

Syntax
public java.sql.ResultSet getAttributes(java.lang.String catalog,
java.lang.String schemaPattern,
java.lang.String typeNamePattern,
java.lang.String attributeNamePattern)

Parameters
catalog
A String that contains the catalog name.
schemaPattern
A String that contains the schema name pattern.
typeNamePattern
A String that contains the type name pattern.
attributePattern
A String that contains the attribute name pattern.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getAttributes method is specified by the getAttributes method in the java.sql.DatabaseMetaData interface.
See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getBestRowIdentifier Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the optimal set of columns of a table that uniquely identifies a row.

Syntax
public java.sql.ResultSet getBestRowIdentifier(java.lang.String catalog,
java.lang.String schema,
java.lang.String table,
int scope,
boolean nullable)

Parameters
catalog
A String that contains the catalog name.
schema
A String that contains the schema name.
table
A String that contains the table name.
scope
An int that indicates the scope of interest. Values can include the following:
bestRowTemporary (0)
bestRowTransaction (1)
bestRowSession (2)
nullable
true to include nullable columns. Otherwise, false .

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getBestRowIdentifier method is specified by the getBestRowIdentifier method in the
java.sql.DatabaseMetaData interface.
The result set returned by the getBestRowIdentifier method will contain the following information:

NAME TYPE DESC RIP T IO N

SCOPE short The scope of the returned results. It


can be one of the following values:

bestRowTemporary (0)

bestRowTransaction (1)

bestRowSession (2)

COLUMN_NAME String The name of the column.

DATA_TYPE short The SQL data type from java.sql.Types.

TYPE_NAME String The name of the data type.

COLUMN_SIZE int The precision of the column.

BUFFER_LENGTH int The buffer length.

DECIMAL_DIGITS short The scale of the column.

PSEUDO_COLUMN short Indicates if the column is a pseudo


column. It can be one of the following
values:

bestRowUnknown (0)

bestRowNotPseudo (1)

bestRowPseudo (2)

Example
The following example demonstrates how to use the getBestRowIdentifier method to return information about
the best row identifier for the Person.Contact table in the sample database.
public static void executeGetBestRowIdentifier(Connection con) {
try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getBestRowIdentifier(null, "Person", "Contact", 0, true);
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getCatalogs Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the catalog names that are available in the connected server.

Syntax
public java.sql.ResultSet getCatalogs()

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getCatalogs method is specified by the getCatalogs method in the java.sql.DatabaseMetaData interface.

NOTE
On Azure SQL Database, you should connect to the master database to call
SQLSer verDatabaseMetaData.getCatalogs . SQL Database does not support returning the entire set of catalogs
from a user database. SQLSer verDatabaseMetaData.getCatalogs uses the sys.databases view to get the catalogs.
Please refer to the discussion of permissions in sys.database_usage (Azure SQL Database) to understand
SQLSer verDatabaseMetaData.getCatalogs behavior on SQL > On Azure SQL Database, you should connect to the
master database to call SQLSer verDatabaseMetaData.getCatalogs . SQL Database does not support returning the
entire set of catalogs from a user database. SQLSer verDatabaseMetaData.getCatalogs uses the sys.databases view
to get the catalogs. Please refer to the discussion of permissions in sys.database_usage (Azure SQL Database) to
understand SQLSer verDatabaseMetaData.getCatalogs behavior on SQL Database. .

The result set returned by the getCatalogs method will contain the following information:

NAME TYPE DESC RIP T IO N

TABLE_CAT String The name of the catalog, including


system databases in Microsoft SQL
Server.

Example
The following example demonstrates how to use the getCatalogs method to return the names of all the
databases that are contained in Microsoft SQL Server, including the system databases.

public static void executeGetCatalogs(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getCatalogs();
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getCatalogSeparator Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the String that this database uses as the separator between a catalog and table name.

Syntax
public java.lang.String getCatalogSeparator()

Return Value
A String that contains the catalog separator.

Exceptions
SQLServerException

Remarks
This getCatalogSeparator method is specified by the getCatalogSeparator method in the
java.sql.DatabaseMetaData interface.
When using the Microsoft JDBC Driver for SQL Server with a SQL Server database, this method returns a period
(".") as the catalog separator.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getCatalogTerm Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the database vendor's preferred term for "catalog".

Syntax
public java.lang.String getCatalogTerm()

Return Value
A String that contains the catalog term.

Exceptions
SQLServerException

Remarks
This getCatalogTerm method is specified by the getCatalogTerm method in the java.sql.DatabaseMetaData
interface.
When using the Microsoft JDBC Driver for SQL Server with a SQL Server database, this method will return the
term "database".

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getClientInfoProperties Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a list of the client information properties that the driver supports.

Syntax
public java.sql.ResultSet getClientInfoProperties()

Return Value
A ResultSet object.

Exceptions
SQLServerException

Remarks
This getClientInfoProperties method is specified by the getClientInfoProperties method in the
java.sql.DatabaseMetaData interface.

NOTE
This method returns an empty result set. The driver supports setting only the applicationName and sets the
applicationName only at connection time. SQL Server does not support updating the client application information
after the connection is established.

See Also
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getColumnPrivileges Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the access rights for the columns in a table.

Syntax
public java.sql.ResultSet getColumnPrivileges(java.lang.String catalog,
java.lang.String schema,
java.lang.String table,
java.lang.String col)

Parameters
catalog
A String that contains the catalog name.
schema
A String that contains the schema name.
table
A String that contains the table name.
col
A String that contains the column name pattern.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getColumnPrivileges method is specified by the getColumnPrivileges method in the
java.sql.DatabaseMetaData interface.
The result set returned by the getColumnPrivileges method will contain the following information:

NAME TYPE DESC RIP T IO N

TABLE_CAT String The catalog name.


NAME TYPE DESC RIP T IO N

TABLE_SCHEM String The table schema name.

TABLE_NAME String The table name.

COLUMN_NAME String The column name.

GRANTOR String The object granting the access.

GRANTEE String The object receiving the access.

PRIVILEGE String The type of access granted.

IS_GRANTABLE String Indicates if the grantee is allowed to


grant access to other users.

NOTE
For more information about the data returned by the getColumnPrivileges method, see "sp_column_privileges (Transact-
SQL)" in SQL Server Books Online.

Example
The following example demonstrates how to use the getColumnPrivileges method to return the access rights for
the FirstName column in the Person.Contact table in the sample database.

public static void executeGetColumnPrivileges(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getColumnPrivileges("AdventureWorks", "Person", "Contact", "FirstName");
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getColumns Method
(SQLServerDatabaseMetaData)
4/27/2022 • 5 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the table columns that are available in the specified catalog.

Syntax
public java.sql.ResultSet getColumns(java.lang.String catalog,
java.lang.String schema,
java.lang.String table,
java.lang.String col)

Parameters
catalog
A String that contains the catalog name.
schema
A String that contains the schema name pattern.
table
A String that contains the table name pattern.
col
A String that contains the column name pattern.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getColumns method is specified by the getColumns method in the java.sql.DatabaseMetaData interface.
The result set returned by the getColumns method will contain the following information:

NAME TYPE DESC RIP T IO N

TABLE_CAT String The catalog name.

TABLE_SCHEM String The table schema name.


NAME TYPE DESC RIP T IO N

TABLE_NAME String The table name.

COLUMN_NAME String The column name.

DATA_TYPE smallint The SQL data type from java.sql.Types.

TYPE_NAME String The name of the data type.

COLUMN_SIZE int The precision of the column.

BUFFER_LENGTH smallint Transfer size of the data.

DECIMAL_DIGITS smallint The scale of the column.

NUM_PREC_RADIX smallint The radix of the column.

NULLABLE smallint Indicates if the column is nullable. It


can be one of the following values:

columnNoNulls (0)

columnNullable (1)

REMARKS String The comments associated with the


column.

Note: SQL Server always returns null


for this column.

COLUMN_DEF String The default value of the column.

SQL_DATA_TYPE smallint Value of the SQL data type as it


appears in the TYPE field of the
descriptor. This column is the same as
the DATA_TYPE column, except for the
datetime and SQL-92 interval data
types. This column always returns a
value.

SQL_DATETIME_SUB smallint Subtype code for datetime and SQL-


92 interval data types. For other data
types, this column returns NULL.

CHAR_OCTET_LENGTH int The maximum number of bytes in the


column.

ORDINAL_POSITION int The index of the column within the


table.

IS_NULLABLE String Indicates if the column allows null


values.

SS_IS_SPARSE smallint If the column is a sparse column, this


has the value 1; otherwise, 0.1
NAME TYPE DESC RIP T IO N

SS_IS_COLUMN_SET smallint If the column is the sparse column_set


column, this has the value 1;
otherwise, 0. 1

SS_IS_COMPUTED smallint Indicates if a column in a TABLE_TYPE


is a computed column. 1

IS_AUTOINCREMENT String "YES" if the column is auto


incremented. "NO" if the column is not
auto incremented. "" (empty string) if
the driver cannot determine if the
column is auto incremented. 1

SS_UDT_CATALOG_NAME String The name of the catalog that contains


the user-defined type (UDT). 1

SS_UDT_SCHEMA_NAME String The name of the schema that contains


the user-defined type (UDT). 1

SS_UDT_ASSEMBLY_TYPE_NAME String The fully-qualified name user-defined


type (UDT). 1

SS_XML_SCHEMACOLLECTION_CATAL String The name of the catalog where an


OG_NAME XML schema collection name is
defined. If the catalog name cannot be
found, this variable contains an empty
string. 1

SS_XML_SCHEMACOLLECTION_SCHE String The name of the schema where an


MA_NAME XML schema collection name is
defined. If the schema name cannot be
found, this is an empty string. 1

SS_XML_SCHEMACOLLECTION_NAME String The name of an XML schema


collection. If the name cannot be
found, this is an empty string. 1

SS_DATA_TYPE tinyint The SQL Server data type that is used


by extended stored procedures.

Note For more information about the


data types returned by SQL Server, see
"Data Types (Transact-SQL)" in SQL
Server Books Online.

(1) This column will not be present if you are connecting to SQL Server 2005 (9.x).

NOTE
For more information about the data returned by the getColumns method, see "sp_columns (Transact-SQL)" in SQL Server
Books Online.

In the MicrosoftSQL Server JDBC Driver 3.0, you will see the following behavior changes from earlier versions of
the JDBC Driver:
The DATA_TYPE column has the following changes:

RET URN T Y P E IN JDB C DRIVER 2. 0 ( O R,


IF C O N N EC T ED TO SQ L SERVER 2005 RET URN T Y P E IN JDB C DRIVER 3. 0
( 9. X) ) A N D A SSO C IAT ED N UM ERIC W H EN C O N N EC T ED TO SQ L SERVER
SQ L SERVER DATA T Y P E C O N STA N T 2008 O R L AT ER

user-defined type larger than 8 kB LONGVARBINARY (-4) VARBINARY (-3)

geography LONGVARBINARY (-4) VARBINARY (-3)

geometry LONGVARBINARY (-4) VARBINARY (-3)

varbinary(max) LONGVARBINARY (-4) VARBINARY (-3)

nvarchar(max) LONGVARCHAR (-1) or VARCHAR (12) or NVARCHAR (JDBC 4)


LONGNVARCHAR (JDBC 4) (-16) (-9)

varchar(max) LONGVARCHAR (-1) VARCHAR (12)

time VARCHAR (12) or NVARCHAR (JDBC 4) TIME (-154)


(-9)

date VARCHAR (12) or NVARCHAR (JDBC 4) DATE (91)


(-9)

datetime2 VARCHAR (12) or NVARCHAR (JDBC 4) TIMESTAMP (93)


(-9)

datetimeoffset VARCHAR (12) or NVARCHAR (JDBC 4) microsoft.sql.Types.DATETIMEOFFSET


(-9) (-155)

The COLUMN_SIZE column has the following changes:

SQ L SERVER DATA T Y P E RET URN T Y P E IN JDB C DRIVER 2. 0 RET URN T Y P E IN JDB C DRIVER 3. 0

nvarchar(max) 1073741823 2147483647 (database metadata)

xml 1073741823 2147483647 (database metadata)

user-defined type less than or equal to 8 kB (result set and parameter Actual size returned by the stored
8 kB metadata) procedure.

time The length in characters of the string


representation of the type, assuming
the maximum allowed precision of the
fractional seconds' component.

date same as time

datetime2 same as time

datetimeoffset same as time

The BUFFER_LENGTH column has the following change:


SQ L SERVER DATA T Y P E RET URN T Y P E IN JDB C DRIVER 2. 0 RET URN T Y P E IN JDB C DRIVER 3. 0

user-defined type larger than 8 kB 2147483647

The TYPE_NAME column has the following changes:

SQ L SERVER DATA T Y P E RET URN T Y P E IN JDB C DRIVER 2. 0 RET URN T Y P E IN JDB C DRIVER 3. 0

varchar(max) text varchar

varbinary(max) image varbinary

The DECIMAL_DIGITS column has the following changes:

SQ L SERVER T Y P E JDB C DRIVER 2. 0 JDB C DRIVER 3. 0

time null 7 (or smaller if specified)

date null null

datetime2 null 7 (or smaller if specified)

datetimeoffset null 7 (or smaller if specified)

The SQL_DATA_TYPE column has the following changes:

SQ L SERVER 2008 DATA VA L UE IN JDB C SQ L SERVER 2008 DATA VA L UE IN JDB C


SQ L SERVER DATA T Y P E DRIVER 2. 0 DRIVER 3. 0

varchar(max) -10 -9

nvarchar(max) -1 -9

xml -10 -152

user-defined type less than or equal to -3 -151


8 kB

user-defined type larger than 8 kB Not available in JDBC Driver 2.0 -151

geography -4 -151

geometry -4 -151

hierarchyid -4 -151

time -9 92

date -9 91

datetime2 -9 93

datetimeoffset -9 -155
Example
The following example demonstrates how to use the getColumns method to return information for the
Person.Contact table in the sample database.

import java.sql.*;
public class c1 {
public static void main(String[] args) {
String connectionUrl =
"jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks;integratedsecurity=true";

Connection con = null;


Statement stmt = null;
ResultSet rs = null;

try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
con = DriverManager.getConnection(connectionUrl);
DatabaseMetaData dbmd = con.getMetaData();
rs = dbmd.getColumns("AdventureWorks", "Person", "Contact", "FirstName");

ResultSet r = dbmd.getColumns(null, null, "Contact", null);


ResultSetMetaData rm = r.getMetaData();
int noofcols = rm.getColumnCount();

if (r.next())
for (int i = 0 ; i < noofcols ; i++ )
System.out.println(rm.getColumnName( i + 1 ) + ": \t\t" + r.getString( i + 1 ));
}

catch (Exception e) {}
finally {}
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getConnection Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the connection that produced this metadata object.

Syntax
public java.sql.Connection getConnection()

Return Value
A SQLServerConnection object.

Exceptions
SQLServerException

Remarks
This getConnection method is specified by the getConnection method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getCrossReference Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the foreign key columns in the given foreign key table that references the primary key
columns of the given primary key table.

Syntax
public java.sql.ResultSet getCrossReference(java.lang.String cat1,
java.lang.String schem1,
java.lang.String tab1,
java.lang.String cat2,
java.lang.String schem2,
java.lang.String tab2)

Parameters
cat1
A String that contains the catalog name of the table that contains the primary key.
schem1
A String that contains the schema name of the table that contains the primary key.
tab1
A String that contains the table name of the table that contains the primary key.
cat2
A String that contains the catalog name of the table that contains the foreign key.
schem2
A String that contains the schema name of the table that contains the foreign key.
tab2
A String that contains the table name of the table that contains the foreign key.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getCrossReference method is specified by the getCrossReference method in the java.sql.DatabaseMetaData
interface.
The result set returned by the getCrossReference method will contain the following information:

NAME TYPE DESC RIP T IO N

PKTABLE_CAT String The name of the catalog that contains


the primary key table.

PKTABLE_SCHEM String The name of the schema of the


primary key table.

PKTABLE_NAME String The name of the primary key table.

PKCOLUMN_NAME String The column name of the primary key.

FKTABLE_CAT String The name of the catalog that contains


the foreign key table.

FKTABLE_SCHEM String The name of the schema of the foreign


key table.

FKTABLE_NAME String The name of the foreign key table.

FKCOLUMN_NAME String The column name of the foreign key.

KEY_SEQ shor t The sequence number of the column in


a multicolumn primary key.

UPDATE_RULE shor t The action applied to the foreign key


when the SQL operation is an update.
It can be one of the following values:

importedKeyNoAction (3)

importedKeyCascade (0)

importedKeySetNull (2)

importedKeySetDefault (4)

importedKeyRestrict (1)

DELETE_RULE shor t The action applied to the foreign key


when the SQL operation is a deletion.
It can be one of the following values:

importedKeyNoAction (3)

importedKeyCascade (0)

importedKeySetNull (2)

importedKeySetDefault (4)

importedKeyRestrict (1)
NAME TYPE DESC RIP T IO N

FK_NAME String The name of the foreign key.

PK_NAME String The name of the primary key.

DEFERRABILITY shor t Indicates if the evaluation of the


foreign key constraint can be deferred
until a commit. It can be one of the
following values:

importedKeyInitiallyDeferred (5)

importedKeyInitiallyImmediate (6)

importedKeyNotDeferrable (7)

NOTE
For more information about the data returned by the getCrossReference method, see "sp_fkeys (Transact-SQL)" in SQL
Server Books Online.

Example
The following example demonstrates how to use the getCrossReference method to return information about the
primary and foreign key relationship between the Person.Contact and HumanResources.Employee tables in the
sample database.

public static void executeGetCrossReference(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getCrossReference("AdventureWorks", "Person", "Contact", null, "HumanResources",
"Employee");
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getDatabaseMajorVersion Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the major version number of the underlying database.

Syntax
public int getDatabaseMajorVersion()

Return Value
An int that indicates the database major version.

Exceptions
SQLServerException

Remarks
This getDatabaseMajorVersion method is specified by the getDatabaseMajorVersion method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getDatabaseMinorVersion Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the minor version number of the underlying database.

Syntax
public int getDatabaseMinorVersion()

Return Value
An int that indicates the database minor version.

Exceptions
SQLServerException

Remarks
This getDatabaseMinorVersion method is specified by the getDatabaseMinorVersion method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getDatabaseProductName Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the name of this database product.

Syntax
public java.lang.String getDatabaseProductName()

Return Value
A String that contains the database product name.

Exceptions
SQLServerException

Remarks
This getDatabaseProductName method is specified by the getDatabaseProductName method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getDatabaseProductVersion Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the version number of this database product.

Syntax
public java.lang.String getDatabaseProductVersion()

Return Value
A String that contains the database product version number.

Exceptions
SQLServerException

Remarks
This getDatabaseProductVersion method is specified by the getDatabaseProductVersion method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getDefaultTransactionIsolation Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the default transaction isolation level for this database.

Syntax
public int getDefaultTransactionIsolation()

Return Value
An int that indicates the default transaction isolation level.

Exceptions
SQLServerException

Remarks
This getDefaultTransactionIsolation method is specified by the getDefaultTransactionIsolation method in the
java.sql.DatabaseMetaData interface.
When using the Microsoft JDBC Driver for SQL Server with a SQL Server database, this method returns either a
value of TRANSACTION_READ_COMMITTED, or the int value 2.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getDriverMajorVersion Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the major version number of this JDBC driver.

Syntax
public int getDriverMajorVersion()

Return Value
An int that indicates the JDBC driver major version.

Exceptions
SQLServerException

Remarks
This getDriverMajorVersion method is specified by the getDriverMajorVersion method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getDriverMinorVersion Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the minor version number of this JDBC driver.

Syntax
public int getDriverMinorVersion()

Return Value
An int that indicates the JDBC driver minor version.

Exceptions
SQLServerException

Remarks
This getDriverMinorVersion method is specified by the getDriverMinorVersion method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getDriverName Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the name of this JDBC driver.

Syntax
public java.lang.String getDriverName()

Return Value
A String that contains the JDBC driver name.

Exceptions
SQLServerException

Remarks
This getDriverName method is specified by the getDriverName method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getDriverVersion Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the version number of this JDBC driver.

Syntax
public java.lang.String getDriverVersion()

Return Value
A String that contains the JDBC driver version.

Exceptions
SQLServerException

Remarks
This getDriverVersion method is specified by the getDriverVersion method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getExportedKeys Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the foreign key columns that reference the primary key columns of the given table.

Syntax
public java.sql.ResultSet getExportedKeys(java.lang.String cat,
java.lang.String schema,
java.lang.String table)

Parameters
cat
A String that contains the catalog name.
schema
A String that contains the schema name.
table
A String that contains the table name.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getExportedKeys method is specified by the getExportedKeys method in the java.sql.DatabaseMetaData
interface.
The result set returned by the getExportedKeys method will contain the following information:

NAME TYPE DESC RIP T IO N

PKTABLE_CAT String The name of the catalog that contains


the primary key table.

PKTABLE_SCHEM String The name of the schema of the


primary key table.
NAME TYPE DESC RIP T IO N

PKTABLE_NAME String The name of the primary key table.

PKCOLUMN_NAME String The column name of the primary key.

FKTABLE_CAT String The name of the catalog that contains


the foreign key table.

FKTABLE_SCHEM String The name of the schema of the foreign


key table.

FKTABLE_NAME String The name of the foreign key table.

FKCOLUMN_NAME String The column name of the foreign key.

KEY_SEQ shor t The sequence number of the column in


a multicolumn primary key.

UPDATE_RULE shor t The action applied to the foreign key


when the SQL operation is an update.
It can be one of the following values:

importedKeyNoAction (3)

importedKeyCascade (0)

importedKeySetNull (2)

importedKeySetDefault (4)

importedKeyRestrict (1)

DELETE_RULE shor t The action applied to the foreign key


when the SQL operation is a deletion.
It can be one of the following values:

importedKeyNoAction (3)

importedKeyCascade (0)

importedKeySetNull (2)

importedKeySetDefault (4)

importedKeyRestrict (1)

FK_NAME String The name of the foreign key.

PK_NAME String The name of the primary key.


NAME TYPE DESC RIP T IO N

DEFERRABILITY shor t Indicates if the evaluation of the


foreign key constraint can be deferred
until a commit. It can be one of the
following values:

importedKeyInitiallyDeferred (5)

importedKeyInitiallyImmediate (6)

importedKeyNotDeferrable (7)

NOTE
For more information about the data returned by the getExportedKeys method, see "sp_fkeys (Transact-SQL)" in SQL
Server Books Online.

Example
The following example demonstrates how to use the getExportedKeys method to return information about all
the foreign keys that reference the primary keys of the Person.Contact table in the sample database.

public static void executeGetExportedKeys(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getExportedKeys("AdventureWorks", "Person", "Contact");
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getExtraNameCharacters Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves all the extra characters that can be used in unquoted identifier names, such as those beyond a-z, A-Z,
0-9, and _.

Syntax
public java.lang.String getExtraNameCharacters()

Return Value
A String that contains the extra characters.

Exceptions
SQLServerException

Remarks
This getExtraNameCharacters method is specified by the getExtraNameCharacters method in the
java.sql.DatabaseMetaData interface.
When using the Microsoft JDBC Driver for SQL Server with a SQL Server database, this method returns the $, #,
and @ extra characters.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getFunctions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the system and user functions.

Syntax
public ResultSet getFunctions(java.lang.String catalog,
java.lang.String schemaPattern,
java.lang.String functionNamePattern)

Parameters
catalog
The name of a catalog in the database. If it is an empty string "", the result includes the functions without a
catalog. If it is null , the catalog name is not used for search.
schemaPattern
The name of a schema. If it is an empty string "", the result includes the functions without a schema. If it is null ,
the schema name is not used for search.
functionNamePattern
The name of a function.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getFunctions method is specified by the getFunctions method in the java.sql.DatabaseMetaData interface.
This method returns only the system and user functions that match the specified schema and function name.

IMPORTANT
The returned result set can contain functions that the calling user does not have permissions to execute.

Each function description includes the following columns:


NAME TYPE DESC RIP T IO N

FUNCTION_CAT String The name of the database in which the


function resides.

FUNCTION_SCHEM String The name of the schema in which the


function resides.

FUNCTION_NAME String The name of the function.

NUM_INPUT_PARAMS int Reserved for future use, currently


returns a -1 value.

NUM_OUTPUT_PARAMS int Reserved for future use, currently


returns a -1 value.

NUM_RESULT_SETS int Reserved for future use, currently


returns a -1 value.

REMARKS String The comments about the function.

FUNCTION_TYPE shor t The type of the function. It can be one


of the following values:

SQL_PT_UNKNOWN (0)

SQL_PT_PROCEDURE (1)

SQL_PT_FUNCTION (2)

All the descriptions in the returned result set are ordered by FUNCTION_CAT, FUNCTION_SCHEM,
FUNCTION_NAME, and SPECIFIC_NAME.

See Also
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getFunctionColumns Method
(SQLServerDatabaseMetaData)
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the specified catalog's system- or user-function parameters and return type.

Syntax
public ResultSet getFunctionColumns(java.lang.String catalog,
java.lang.String schemaPattern,
java.lang.String functionNamePattern
java.lang.String columnNamePattern)

Parameters
catalog
A String that contains the catalog name. If it is an empty string "", the result includes the functions without a
catalog. If it is null , the catalog name is not used for search.
schemaPattern
A String that contains the schema name pattern. If it is an empty string "", the result includes the functions
without a schema. If it is null , the schema name is not used for search.
functionNamePattern
A String that contains the name of a function.
columnNamePattern
A String that contains the name of a parameter.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getFunctionColumns method is specified by the getFunctionColumns method in the
java.sql.DatabaseMetaData interface.
This method returns only the functions and parameters matching the specified schema, function name, and
parameter name within the specified catalog.
Each row in the result set includes the following columns for a parameter description, a column description, or a
return type:
NAME TYPE DESC RIP T IO N

FUNCTION_CAT String The name of the database in which the


function resides.

FUNCTION_SCHEM String The schema for the function.

FUNCTION_NAME String The name of the function.

COLUMN_NAME String The name of a parameter or column.

COLUMN_TYPE shor t The type of the column. It can be


one of the following values:

functionColumnUnknown (0):
Unknown type.

functionColumnIn (1): Input parameter.

functionColumnInOut (2):
Input/Output parameter.

functionColumnOut (3): Output


parameter.

functionReturn (4): Function return


value.

functionColumnResult (5): A parameter


or column is a column in the result set.

DATA_TYPE smallint The SQL data type value from


Java.sql.Types.

TYPE_NAME String The name of the data type.

PRECISION int The total number of significant digits.

LENGTH int The length of the data in bytes.

SCALE shor t The number of digits to the right of


the decimal point.

RADIX shor t The base for numeric types.


NAME TYPE DESC RIP T IO N

NULLABLE shor t Indicates if the parameter or return


value can contain a null value.

It can be one of the following


values:

functionNoNulls (0): NULL value is not


allowed.

functionNullable (1): NULL value is


allowed.

functionNullableUnknown (2):
Unknown.

REMARKS String The comments about a column or a


parameter.

COLUMN_DEF String The default value of the column.

Note: This information is available


with SQL Server and is JDBC driver-
specific.

SQL_DATA_TYPE smallint This column is the same as the


DATA_TYPE column, except for the
datetime and ISO inter val data
types.

Note: This information is available


with SQL Server and is JDBC driver-
specific.

SQL_DATETIME_SUB smallint The datetime ISO inter val subcode if


the value of SQL_DATA_TYPE is
SQL_DATETIME or SQL_INTERVAL .
For data types other than datetime
and ISO inter val, this column is NULL.

Note: This information is available


with SQL Server and is JDBC driver-
specific.

CHAR_OCTET_LENGTH int The maximum length of binary and


character based parameters or
columns. For other data types, it is
NULL.

ORDINAL_POSITION int For input and output parameters, it


represents the position starting from
1.

For result set columns, it is the


position of the column in the result set
starting from 1.

For return value, it is 0.


NAME TYPE DESC RIP T IO N

IS_NULLABLE String Determines the nullability of a


parameter or column.

It can be one of the following values:

YES: The parameter or column can


include NULL values.

NO : The parameter or column can not


include NULL values.

Empty string (""): Unknown.

SS_TYPE_CATALOG_NAME String The name of the catalog that contains


the user-defined type (UDT).

SS_TYPE_SCHEMA_NAME String The name of the schema that contains


the user-defined type (UDT).

SS_UDT_CATALOG_NAME String The fully-qualified name user-defined


type (UDT).

SS_UDT_SCHEMA_NAME String The name of the catalog where an


XML schema collection name is
defined. If the catalog name cannot be
found, this variable contains an empty
string.

SS_UDT_ASSEMBLY_TYPE_NAME String The name of the schema where an


XML schema collection name is
defined. If the schema name cannot be
found, this is an empty string.

SS_XML_SCHEMACOLLECTION_CATAL String The name of an XML schema


OG_NAME collection. If the name cannot be
found, this is an empty string.

SS_XML_SCHEMACOLLECTION_SCHE String The name of the catalog that contains


MA_NAME the user-defined type (UDT).

SS_XML_SCHEMACOLLECTION_NAME String The name of the schema that contains


the user-defined type (UDT).

SS_DATA_TYPE tinyint The SQL Server data type that is used


by extended stored procedures.

Note For more information about the


data types returned by SQL Server, see
"Data Types (Transact-SQL)" in SQL
Server Books Online.

See Also
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getIdentifierQuoteString Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the String that is used to quote SQL identifiers.

Syntax
public java.lang.String getIdentifierQuoteString()

Return Value
A String that contains the quote identifiers.

Exceptions
SQLServerException

Remarks
This getIdentifierQuoteString method is specified by the getIdentifierQuoteString method in the
java.sql.DatabaseMetaData interface.
When using the Microsoft JDBC Driver with a SQL Server database, this method returns double quotation
marks ("").

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getImportedKeys Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the primary key columns that are referenced by the foreign key columns in a table.

Syntax
public java.sql.ResultSet getImportedKeys(java.lang.String cat,
java.lang.String schema,
java.lang.String table)

Parameters
cat
A String that contains the catalog name.
schema
A String that contains the schema name.
table
A String that contains the table name.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getImportedKeys method is specified by the getImportedKeys method in the java.sql.DatabaseMetaData
interface.
The result set returned by the getImportedKeys method will contain the following information:

NAME TYPE DESC RIP T IO N

PKTABLE_CAT String The name of the catalog that contains


the primary key table.

PKTABLE_SCHEM String The name of the schema of the


primary key table.
NAME TYPE DESC RIP T IO N

PKTABLE_NAME String The name of the primary key table.

PKCOLUMN_NAME String The column name of the primary key.

FKTABLE_CAT String The name of the catalog that contains


the foreign key table.

FKTABLE_SCHEM String The name of the schema of the foreign


key table.

FKTABLE_NAME String The name of the foreign key table.

FKCOLUMN_NAME String The column name of the foreign key.

KEY_SEQ shor t The sequence number of the column in


a multicolumn primary key.

UPDATE_RULE shor t The action applied to the foreign key


when the SQL operation is an update.
It can be one of the following values:

importedKeyNoAction (3)

importedKeyCascade (0)

importedKeySetNull (2)

importedKeySetDefault (4)

importedKeyRestrict (1)

DELETE_RULE shor t The action applied to the foreign key


when the SQL operation is a deletion.
It can be one of the following values:

importedKeyNoAction (3)

importedKeyCascade (0)

importedKeySetNull (2)

importedKeySetDefault (4)

importedKeyRestrict (1)

FK_NAME String The name of the foreign key.

PK_NAME String The name of the primary key.


NAME TYPE DESC RIP T IO N

DEFERRABILITY shor t Indicates if the evaluation of the


foreign key constraint can be deferred
until a commit. It can be one of the
following values:

importedKeyInitiallyDeferred (5)

importedKeyInitiallyImmediate (6)

importedKeyNotDeferrable (7)

NOTE
For more information about the data returned by the getImportedKeys method, see "sp_fkeys (Transact-SQL)" in SQL
Server Books Online.

Example
The following example demonstrates how to use the getImportedKeys method to return information about all
the primary keys that reference the foreign keys of the Person.Address table in the sample database.

public static void executeGetImportedKeys(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getImportedKeys("AdventureWorks", "Person", "Address");
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getIndexInfo Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the indexes and statistics for the given table.

Syntax
public java.sql.ResultSet getIndexInfo(java.lang.String cat,
java.lang.String schema,
java.lang.String table,
boolean unique,
boolean approximate)

Parameters
cat
A String that contains the catalog name.
schema
A String that contains the schema name.
table
A String that contains the table name.
unique
true if only indexes for unique values are returned. false if all indexes are returned.
approximate
true if the results reflect approximate or out-of-date values. false if the results are accurate.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getIndexInfo method is specified by the getIndexInfo method in the java.sql.DatabaseMetaData interface.
The result set returned by the getIndexInfo method will contain the following information:
NAME TYPE DESC RIP T IO N

TABLE_CAT String The name of the database in which the


specified table resides.

TABLE_SCHEM String The schema for the table.

TABLE_NAME String The name of the table.

NON_UNIQUE boolean Indicates whether the index values can


be non-unique.

INDEX_QUALIFIER String The name of the index owner. It will be


null when TYPE is tableIndexStatistic.

INDEX_NAME String The name of the index.

TYPE shor t The type of the index. It can be one of


the following values:

tableIndexStatistic (0)

tableIndexClustered (1)

tableIndexHashed (2)

tableIndexOther (3)

ORDINAL_POSITION shor t The ordinal position of the column in


the index. The first column in the index
is 1.

COLUMN_NAME String The name of the column.

ASC_OR_DESC String The order used in the collation of the


index. It can be one of the following
values:

A (ascending)

D (descending)

NULL (not applicable)

Note: SQL Server always returns "A".

CARDINALITY int The number of rows in the table or


unique values in the index.

PAGES int The number of pages used to store the


index or table.

FILTER_CONDITION String The filter condition.

Note: SQL Server always returns null.


NOTE
For more information about the data returned by the getIndexInfo method, see "sp_indexes (Transact-SQL)" in SQL Server
Books Online.

Example
The following example demonstrates how to use the getIndexInfo method to return information about the
indexes and statistics of the Person.Contact table in the sample database.

public static void executeGetIndexInfo(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getIndexInfo("AdventureWorks", "Person", "Contact", false, true);
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getJDBCMajorVersion Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the major JDBC version number for this driver.

Syntax
public int getJDBCMajorVersion()

Return Value
An int that indicates the major JDBC version.

Exceptions
SQLServerException

Remarks
This getJDBCMajorVersion method is specified by the getJDBCMajorVersion method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getJDBCMinorVersion Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the minor JDBC version number for this driver.

Syntax
public int getJDBCMinorVersion()

Return Value
An int that indicates the minor JDBC version.

Exceptions
SQLServerException

Remarks
This getJDBCMinorVersion method is specified by the getJDBCMinorVersion method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxBinaryLiteralLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of hex characters this database allows in an inline binary literal.

Syntax
public int getMaxBinaryLiteralLength()

Return Value
An int that indicates the maximum number of hexadecimal characters.

Exceptions
SQLServerException

Remarks
This getMaxBinaryLiteralLength method is specified by the getMaxBinaryLiteralLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxCatalogNameLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of characters that this database allows in a catalog name.

Syntax
public int getMaxCatalogNameLength()

Return Value
An int that indicates the maximum number of characters allowed.

Exceptions
SQLServerException

Remarks
This getMaxCatalogNameLength method is specified by the getMaxCatalogNameLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxCharLiteralLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of characters that this database allows for a character literal.

Syntax
public int getMaxCharLiteralLength()

Return Value
An int that indicates the maximum number of characters allowed.

Exceptions
SQLServerException

Remarks
This getMaxCharLiteralLength method is specified by the getMaxCharLiteralLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxColumnNameLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of characters that this database allows for a column name.

Syntax
public int getMaxColumnNameLength()

Return Value
An int that indicates the maximum number of characters allowed.

Exceptions
SQLServerException

Remarks
This getMaxColumnNameLength method is specified by the getMaxColumnNameLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxColumnsInGroupBy Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of columns that this database allows in a GROUP BY clause.

Syntax
public int getMaxColumnsInGroupBy()

Return Value
An int that indicates the maximum number of columns allowed.

Exceptions
SQLServerException

Remarks
This getMaxColumnsInGroupBy method is specified by the getMaxColumnsInGroupBy method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxColumnsInIndex Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of columns that this database allows in an index.

Syntax
public int getMaxColumnsInIndex()

Return Value
An int that indicates the maximum number of columns allowed.

Exceptions
SQLServerException

Remarks
This getMaxColumnsInIndex method is specified by the getMaxColumnsInIndex method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxColumnsInOrderBy Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of columns this database allows in an ORDER BY clause.

Syntax
public int getMaxColumnsInOrderBy()

Return Value
An int that indicates the maximum number of columns allowed.

Exceptions
SQLServerException

Remarks
This getMaxColumnsInOrderBy method is specified by the getMaxColumnsInOrderBy method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxColumnsInSelect Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of columns that this database allows in a SELECT list.

Syntax
public int getMaxColumnsInSelect()

Return Value
An int that indicates the maximum number of columns allowed.

Exceptions
SQLServerException

Remarks
This getMaxColumnsInSelect method is specified by the getMaxColumnsInSelect method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxColumnsInTable Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of columns this database allows in a table.

Syntax
public int getMaxColumnsInTable()

Return Value
An int that indicates the maximum number of columns allowed.

Exceptions
SQLServerException

Remarks
This getMaxColumnsInTable method is specified by the getMaxColumnsInTable method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxConnections Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of concurrent connections to this database that are possible.

Syntax
public int getMaxConnections()

Return Value
An int that indicates the maximum number of concurrent connections allowed.

Exceptions
SQLServerException

Remarks
This getMaxConnections method is specified by the getMaxConnections method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxCursorNameLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of characters that this database allows in a cursor name.

Syntax
public int getMaxCursorNameLength()

Return Value
An int that indicates the maximum number of characters allowed.

Exceptions
SQLServerException

Remarks
This getMaxCursorNameLength method is specified by the getMaxCursorNameLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxIndexLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of bytes that this database allows for an index, including all of the parts of the
index.

Syntax
public int getMaxIndexLength()

Return Value
An int that indicates the maximum number of bytes allowed.

Exceptions
SQLServerException

Remarks
This getMaxIndexLength method is specified by the getMaxIndexLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxProcedureNameLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of characters that this database allows in a procedure name.

Syntax
public int getMaxProcedureNameLength()

Return Value
An int that indicates the maximum number of characters allowed.

Exceptions
SQLServerException

Remarks
This getMaxProcedureNameLength method is specified by the getMaxProcedureNameLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxRowSize Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of bytes that this database allows in a single row.

Syntax
public int getMaxRowSize()

Return Value
An int that indicates the maximum number of bytes allowed.

Exceptions
SQLServerException

Remarks
This getMaxRowSize method is specified by the getMaxRowSize method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxSchemaNameLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of characters that this database allows in a schema name.

Syntax
public int getMaxSchemaNameLength()

Return Value
An int that indicates the maximum number of characters allowed.

Exceptions
SQLServerException

Remarks
This getMaxSchemaNameLength method is specified by the getMaxSchemaNameLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxStatementLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of characters this database allows in an SQL statement.

Syntax
public int getMaxStatementLength()

Return Value
An int that indicates the maximum number of characters allowed.

Exceptions
SQLServerException

Remarks
This getMaxStatementLength method is specified by the getMaxStatementLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxStatements Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of active statements to this database that can be open at the same time.

Syntax
public int getMaxStatements()

Return Value
An int that indicates the maximum number of active statements allowed.

Exceptions
SQLServerException

Remarks
This getMaxStatements method is specified by the getMaxStatements method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxTableNameLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of characters that this database allows in a table name.

Syntax
public int getMaxTableNameLength()

Return Value
An int that indicates the maximum number of characters allowed.

Exceptions
SQLServerException

Remarks
This getMaxTableNameLength method is specified by the getMaxTableNameLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxTablesInSelect Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of tables this database allows in a SELECT statement.

Syntax
public int getMaxTablesInSelect()

Return Value
An int that indicates the maximum number of tables allowed.

Exceptions
SQLServerException

Remarks
This getMaxTablesInSelect method is specified by the getMaxTablesInSelect method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getMaxUserNameLength Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of characters that this database allows in a user name.

Syntax
public int getMaxUserNameLength()

Return Value
An int that indicates the maximum number of characters allowed.

Exceptions
SQLServerException

Remarks
This getMaxUserNameLength method is specified by the getMaxUserNameLength method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getNumericFunctions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a comma-separated list of math functions that are available with this database.

Syntax
public java.lang.String getNumericFunctions()

Return Value
A String that contains the available math functions.

Exceptions
SQLServerException

Remarks
This getNumericFunctions method is specified by the getNumericFunctions method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getPrimaryKeys Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the primary key columns of the given table.

Syntax
public java.sql.ResultSet getPrimaryKeys(java.lang.String cat,
java.lang.String schema,
java.lang.String table)

Parameters
cat
A String that contains the catalog name.
schema
A String that contains the schema name.
table
A String that contains the table name.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getPrimaryKeys method is specified by the getPrimaryKeys method in the java.sql.DatabaseMetaData
interface.
The result set returned by the getPrimaryKeys method will contain the following information:

NAME TYPE DESC RIP T IO N

TABLE_CAT String The name of the database in which the


specified table resides.

TABLE_SCHEM String The schema for the table.

TABLE_NAME String The name of the table.


NAME TYPE DESC RIP T IO N

COLUMN_NAME String The name of the column.

KEY_SEQ short The sequence number of the column in


a multicolumn primary key.

PK_NAME String The name of the primary key.

NOTE
For more information about the data returned by the getPrimaryKeys method, see "sp_pkeys (Transact-SQL)" in SQL
Server Books Online.

Example
The following example demonstrates how to use the getPrimaryKeys method to return information about the
primary keys of the Person.Contact table in the sample database.

public static void executeGetPrimaryKeys(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getPrimaryKeys("AdventureWorks", "Person", "Contact");
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getProcedureColumns Method
(SQLServerDatabaseMetaData)
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the stored procedure parameters and result columns.

Syntax
public java.sql.ResultSet getProcedureColumns(java.lang.String sCatalog,
java.lang.String sSchema,
java.lang.String proc,
java.lang.String col)

Parameters
sCatalog
A String that contains the catalog name. Providing a null to this parameter indicates that the catalog name does
not need to be used.
sSchema
A String that contains the schema name pattern. Providing a null to this parameter indicates that the schema
name does not need to be used.
proc
A String that contains the procedure name pattern.
col
A String that contains the column name pattern. Providing a null to this parameter returns a row for each
column.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getProcedureColumns method is specified by the getProcedureColumns method in the
java.sql.DatabaseMetaData interface.
The result set returned by the getProcedureColumns method will contain the following information:
NAME TYPE DESC RIP T IO N

PROCEDURE_CAT String The name of the database in which the


specified stored procedure resides.

PROCEDURE_SCHEM String The schema for the stored procedure.

PROCEDURE_NAME String The name of the stored procedure.

COLUMN_NAME String The name of the column.

COLUMN_TYPE shor t The type of the column. It can be one


of the following values:

procedureColumnUnknown (0)

procedureColumnIn (1)

procedureColumnInOut (2)

procedureColumnOut (4)

procedureColumnReturn (5)

procedureColumnResult (3)

DATA_TYPE smallint The SQL data type from java.sql.Types.

TYPE_NAME String The name of the data type.

PRECISION int The total number of significant digits.

LENGTH int The length of the data in bytes.

SCALE shor t The number of digits to the right of


the decimal point.

RADIX shor t The base for numeric types.

NULLABLE shor t Indicates if the column can contain a


null value. It can be one of the
following values:

procedureNoNulls (0)

procedureNullable (1)

procedureNullableUnknown (2)

REMARKS String The description of the procedure


column.

Note: SQL Server does not return a


value for this column.
NAME TYPE DESC RIP T IO N

COLUMN_DEF String The default value of the column.

SQL_DATA_TYPE smallint This column is the same as the


DATA_TYPE column, except for the
datetime and ISO inter val data
types.

SQL_DATETIME_SUB smallint The datetime ISO inter val subcode if


the value of SQL_DATA_TYPE is
SQL_DATETIME or SQL_INTERVAL .
For data types other than datetime
and ISO inter val, this column is NULL.

CHAR_OCTET_LENGTH int The maximum number of bytes in the


column.

ORDINAL_POSITION int The index of the column within the


table.

IS_NULLABLE String Indicates if the column allows null


values.

SS_TYPE_CATALOG_NAME String The name of the catalog that contains


the user-defined type (UDT).

SS_TYPE_SCHEMA_NAME String The name of the schema that contains


the user-defined type (UDT).

SS_UDT_CATALOG_NAME String The fully-qualified name user-defined


type (UDT).

SS_UDT_SCHEMA_NAME String The name of the catalog where an


XML schema collection name is
defined. If the catalog name cannot be
found, this variable contains an empty
string.

SS_UDT_ASSEMBLY_TYPE_NAME String The name of the schema where an


XML schema collection name is
defined. If the schema name cannot be
found, this is an empty string.

SS_XML_SCHEMACOLLECTION_CATAL String The name of an XML schema


OG_NAME collection. If the name cannot be
found, this is an empty string.

SS_XML_SCHEMACOLLECTION_SCHE String The name of the catalog that contains


MA_NAME the user-defined type (UDT).

SS_XML_SCHEMACOLLECTION_NAME String The name of the schema that contains


the user-defined type (UDT).
NAME TYPE DESC RIP T IO N

SS_DATA_TYPE tinyint The SQL Server data type that is used


by extended stored procedures.

Note: For more information about the


data types returned by SQL Server, see
"Data Types (Transact-SQL)" in SQL
Server Books Online.

NOTE
For more information about the data returned by the getProcedureColumns method, see "sp_sproc_columns (Transact-
SQL)" in SQL Server Books Online.

Example
The following example demonstrates how to use the getProcedureColumns method to return information about
the uspGetBillOfMaterials stored procedure in the sample database.

public static void executeGetProcedureColumns(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getProcedureColumns(null, null, "uspGetBillOfMaterials", null);
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getProcedures Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the stored procedures that are available in the given catalog, schema, or stored
procedure name pattern.

Syntax
public java.sql.ResultSet getProcedures(java.lang.String sCatalog,
java.lang.String sSchema,
java.lang.String proc)

Parameters
sCatalog
A String that contains the catalog name. Providing a null to this parameter indicates that the catalog name does
not need to be used.
sSchema
A String that contains the schema name pattern. Providing a null to this parameter indicates that the schema
name does not need to be used.
proc
A String that contains the procedure name pattern.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getProcedures method is specified by the getProcedures method in the java.sql.DatabaseMetaData
interface.
The result set returned by the getProcedures method will contain the following information:

NAME TYPE DESC RIP T IO N

PROCEDURE_CAT String The name of the database in which the


specified stored procedure resides.
NAME TYPE DESC RIP T IO N

PROCEDURE_SCHEM String The schema for the stored procedure.

PROCEDURE_NAME String The name of the stored procedure.

NUM_INPUT_PARAMS int Reserved for future use, currently


returns a -1 value.

NUM_OUTPUT_PARAMS int Reserved for future use, currently


returns a -1 value.

NUM_RESULT_SETS int Reserved for future use, currently


returns a -1 value.

REMARKS String The description of the procedure


column.

Note: SQL Server does not return a


value for this column.

PROCEDURE_TYPE smallint The type of stored procedure. It can be


one of the following values:

SQL_PT_UNKNOWN (0)

SQL_PT_PROCEDURE (1)

SQL_PT_FUNCTION (2)

NOTE
For more information about the data returned by the getProcedures method, see "sp_stored_procedures (Transact-SQL)"
in SQL Server Books Online.

Example
The following example demonstrates how to use the getProcedures method to return information about the
uspGetBillOfMaterials stored procedure in the sample database.
public static void executeGetProcedures(Connection con) {
try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getProcedures(null, null, "uspGetBillOfMaterials");
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getProcedureTerm Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the preferred term for "procedure" in this database.

Syntax
public java.lang.String getProcedureTerm()

Return Value
A String that contains the procedure term.

Exceptions
SQLServerException

Remarks
This getProcedureTerm method is specified by the getProcedureTerm method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getResultSetHoldability Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the default holdability of result sets for this database.

Syntax
public int getResultSetHoldability()

Return Value
An int that indicates the default holdability.

Exceptions
SQLServerException

Remarks
This getResultSetHoldability method is specified by the getResultSetHoldability method in the
java.sql.DatabaseMetaData interface.
When using the Microsoft JDBC Driver for SQL Server with a SQL Server database, this methods returns 1,
which is equivalent to the ResultSet.HOLD_CURSORS_OVER_COMMIT constant.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getRowIdLifetime Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a status indicating whether or not SQL RowId data type is supported. If supported, it returns the lifetime
for which a RowId object remains valid.

Syntax
public java.sql.RowIdLifetime getRowIdLifetime()

Return Value
A RowIdLifetime object.

NOTE
In the JDBC Driver version 2.0 release, this method returns java.sql.RowIdLifetime.ROWID_UNSUPPORTED value.

Exceptions
SQLServerException

Remarks
This getRowIdLifetime method is specified by the getRowIdLifetime method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSchemas Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the schema names that are available in the current database.

Overload List
NAME DESC RIP T IO N

getSchemas Method () Retrieves the schema names that are available in the current
database.

getSchemas Method (String, String) Retrieves the schema names that are available in the current
database by using the specified catalog name and the
schema name.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSchemas Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the schema names that are available in the current database.

Syntax
public java.sql.ResultSet getSchemas()

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getSchemas method is specified by the getSchemas method in the java.sql.DatabaseMetaData interface.
The result set returned by the getSchemas method contains the following information:

NAME TYPE DESC RIP T IO N

TABLE_SCHEM String The name of the schema.

TABLE_CATALOG String The catalog name for the schema.

The results are ordered by TABLE_CATALOG, and then TABLE_SCHEM. Each row has TABLE_SCHEM as the first
column and TABLE_CATALOG as the second column.

NOTE
For more information about the data returned by the getSchemas method, see "sys.schemas (Transact-SQL)" in SQL
Server Books Online.

Example
The following example demonstrates how to use the getSchemas method to return information about the
catalog and its associated schema names in SQL Server when the connection argument specifies the database
to be used.
public static void executeGetSchemas(Connection con) {
try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getSchemas();
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSchemas Method (String, String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the schema names that are available in the current database by using the specified catalog name and
the schema name.

Syntax
public ResultSet getSchemas(java.lang.String catalog,
java.lang.String schemaPattern)

Parameters
catalog
The name of a catalog in the database. If it is an empty string "", the result includes the schemas without a
catalog. If it is null , the catalog name is not used for search.
schemaPattern
The name of a schema. If it is null , the schema name is not used for search.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getSchemas method is specified by the getSchemas method in the java.sql.DatabaseMetaData interface.
The result set returned by the getSchemas method contains the following information:

NAME TYPE DESC RIP T IO N

TABLE_SCHEM String The name of the schema.

TABLE_CATALOG String The catalog name for the schema.

The results are ordered by TABLE_CATALOG and then TABLE_SCHEM. Each row has TABLE_SCHEM as the first
column and TABLE_CATALOG as the second column.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSchemaTerm Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the preferred term for "schema" in this database.

Syntax
public java.lang.String getSchemaTerm()

Return Value
A String that contains the preferred term.

Exceptions
SQLServerException

Remarks
This getSchemaTerm method is specified by the getSchemaTerm method in the java.sql.DatabaseMetaData
interface.
When using the Microsoft JDBC Driver for SQL Server with a SQL Server database, this method returns
"schema" as the preferred term.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSearchStringEscape Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the String that can be used to escape wildcard characters.

Syntax
public java.lang.String getSearchStringEscape()

Return Value
A String that contains the escape wildcard character String.

Exceptions
SQLServerException

Remarks
This getSearchStringEscape method is specified by the getSearchStringEscape method in the
java.sql.DatabaseMetaData interface.
This method is used only for metadata pattern searches. It returns "\". A String search pattern can escape
wildcards ("%" and "_") and provide them as literals by prepending a backslash. This translates "\%" to "[%]" and
"\_" to "[_]".

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSQLKeywords Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a comma-separated list of all of this database's SQL keywords that are not also SQL92 keywords.

Syntax
public java.lang.String getSQLKeywords()

Return Value
A String that contains the SQL keywords.

Exceptions
SQLServerException

Remarks
This getSQLKeywords method is specified by the getSQLKeywords method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSQLStateType Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether the SQLSTATE that is returned by the SQLException.getSQLState method is X/Open (now
known as Open Group) SQL CLI, SQL99 (JDBC 3.0), or SQL:2003 (JDBC 4.0).

Syntax
public int getSQLStateType()

Return Value
An int that indicates the type of SQLSTATE, which can be one of the following values:
For Java Runtime Environment version 5.0: If the xopenStates connection property is set to true , this
method returns DatabaseMetaData.sqlStateXOpen. Otherwise, DatabaseMetaData.sqlStateSQL99.
For Java Runtime Environment version 6.0: If the xopenStates connection property is set to true , this
method returns DatabaseMetaData.sqlStateXOpen. Otherwise, DatabaseMetaData.sqlStateSQL.

Exceptions
SQLServerException

Remarks
This getSQLStateType method is specified by the getSQLStateType method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getStringFunctions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a comma-separated list of String functions that are available with this database.

Syntax
public java.lang.String getStringFunctions()

Return Value
A String that contains the String functions.

Exceptions
SQLServerException

Remarks
This getStringFunctions method is specified by the getStringFunctions method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSuperTables Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the table hierarchies that are defined in a particular schema in this database.

NOTE
This method is not currently supported with the Microsoft JDBC Driver for SQL Server. When used, this method will
always return an empty result set.

Syntax
public java.sql.ResultSet getSuperTables(java.lang.String catalog,
java.lang.String schemaPattern,
java.lang.String tableNamePattern)

Parameters
catalog
A String that contains the catalog name.
schemaPattern
A String that contains the schema name pattern.
tableNamePattern
A String that contains the table name pattern.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getSuperTables method is specified by the getSuperTables method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSuperTypes Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the user-defined type hierarchies that are defined in a particular schema in this
database.

NOTE
This method is not currently supported with the Microsoft JDBC Driver for SQL Server. When used, this method will
always return an empty result set.

Syntax
public java.sql.ResultSet getSuperTypes(java.lang.String catalog,
java.lang.String schemaPattern,
java.lang.String typeNamePattern)

Parameters
catalog
A String that contains the catalog name.
schemaPattern
A String that contains the schema name pattern.
tableNamePattern
A String that contains the table name pattern.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getSuperTypes method is specified by the getSuperTypes method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getSystemFunctions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a comma-separated list of system functions that are available with this database.

Syntax
public java.lang.String getSystemFunctions()

Return Value
A String that contains the list of system functions.

Exceptions
SQLServerException

Remarks
This getSystemFunctions method is specified by the getSystemFunctions method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getTablePrivileges Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the access rights for each table that is available in the given catalog, schema, or table
name pattern.

Syntax
public java.sql.ResultSet getTablePrivileges(java.lang.String catalog,
java.lang.String schema,
java.lang.String table)

Parameters
catalog
A String that contains the catalog name. Providing a null to this parameter indicates that the catalog name does
not need to be used.
schema
A String that contains the schema name pattern. Providing a null to this parameter indicates that the schema
name does not need to be used.
table
A String that contains the table name pattern.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getTablePrivileges method is specified by the getTablePrivileges method in the java.sql.DatabaseMetaData
interface.
The result set returned by the getTablePrivileges method will contain the following information:

NAME TYPE DESC RIP T IO N

TABLE_CAT String The catalog name.

TABLE_SCHEM String The table schema name.


NAME TYPE DESC RIP T IO N

TABLE_NAME String The table name.

GRANTOR String The object granting the access.

GRANTEE String The object receiving the access.

PRIVILEGE String The type of access granted.

IS_GRANTABLE String Indicates if the grantee is allowed to


grant access to other users.

NOTE
For more information about the data returned by the getTablePrivileges method, see "sp_table_privileges (Transact-SQL)"
in SQL Server Books Online.

Example
The following example demonstrates how to use the getTablePrivileges method to return the access rights for
the Person.Contact table in the sample database.

public static void executeGetTablePrivileges(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getTablePrivileges("AdventureWorks", "Person", "Contact");
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getTables Method (SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the tables that are available in the given catalog, schema, or table name pattern.

Syntax
public java.sql.ResultSet getTables(java.lang.String catalog,
java.lang.String schema,
java.lang.String table,
java.lang.String[] types)

Parameters
catalog
A String that contains the catalog name. Providing a null to this parameter indicates that the catalog name does
not need to be used.
schema
A String that contains the schema name pattern. Providing a null to this parameter indicates that the schema
name does not need to be used.
tableName
A String that contains the table name pattern.
types
An array of strings that contain the types of tables to include. Null indicates that all types of tables should be
included.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getTables method is specified by the getTables method in the java.sql.DatabaseMetaData interface.
The result set returned by the getTables method will contain the following information:

NAME TYPE DESC RIP T IO N

TABLE_CAT String The name of the database in which the


specified table resides.
NAME TYPE DESC RIP T IO N

TABLE_SCHEM String The table schema name.

TABLE_NAME String The table name.

TABLE_TYPE String The table type.

REMARKS String The description of the table.

Note: SQL Server does not return a


value for this column.

TYPE_CAT String Not supported by the JDBC driver.

TYPE_SCHEM String Not supported by the JDBC driver.

TYPE_NAME String Not supported by the JDBC driver.

SELF_REFERENCING_COL_NAME String Not supported by the JDBC driver.

REF_GENERATION String Not supported by the JDBC driver.

NOTE
For more information about the data returned by the getTables method, see "sp_tables (Transact-SQL)" in SQL Server
Books Online.

Example
The following example demonstrates how to use the getTables method to return the table description
information for the Person.Contact table in the sample database.

public static void executeGetTables(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getTables("AdventureWorks", "Person", "Contact", null);
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getTableTypes Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the table types that are available in the current database.

Syntax
public java.sql.ResultSet getTableTypes()

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getTableTypes method is specified by the getTableTypes method in the java.sql.DatabaseMetaData interface.
The result set returned by the getTableTypes method will contain the following information:

NAME TYPE DESC RIP T IO N

TABLE_TYPE String The table type.

NOTE
For more information about the data returned by the getTableTypes method, see "sp_tables (Transact-SQL)" in SQL Server
Books Online.

Example
The following example demonstrates how to use the getTableTypes method to return the table type information
in the sample database, given that the database is specified in the connection String.
public static void executeGetTableTypes(Connection con) {
try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getTableTypes();
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getTimeDateFunctions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a comma-separated list of the time and date functions that are available with this database.

Syntax
public java.lang.String getTimeDateFunctions()

Return Value
A String that contains a list of the time and date functions.

Exceptions
SQLServerException

Remarks
This getTimeDateFunctions method is specified by the getTimeDateFunctions method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getTypeInfo Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of all the standard SQL types that are supported by the current database.

Syntax
public java.sql.ResultSet getTypeInfo()

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getTypeInfo method is specified by the getTypeInfo method in the java.sql.DatabaseMetaData interface.
The result set returned by the getTypeInfo method will contain the following information:

NAME TYPE DESC RIP T IO N

TYPE_NAME String The name of the data type.

DATA_TYPE shor t The SQL data type from java.sql.Types.

PRECISION int The total number of significant digits.

LITERAL_PREFIX String The character or characters used


before a constant.

LITERAL_SUFFIX String The character or characters used to


terminate a constant.

CREATE_PARAMS String The description of the creation


parameters for the data type.
NAME TYPE DESC RIP T IO N

NULLABLE shor t Indicates if the column can contain a


null value. It can be one of the
following values:

typeNoNulls (0)

typeNullable (1)

typeNullableUnknown (2)

CASE_SENSITIVE boolean Indicates if the data type is case


sensitive. "true " if the type is case
sensitive; otherwise, "false ".

SEARCHABLE shor t Indicates if the column can be used in


a SQL WHERE clause. It can be one of
the following values:

typePredNone (0)

typePredChar (1)

typePredBasic (2)

typeSeachable (3)

UNSIGNED_ATTRIBUTE boolean Indicates the sign of the data type.


"true " if the type is unsigned;
otherwise, "false ".

FIXED_PREC_SCALE boolean Indicates that the data type can be a


money value. "true " if the data type is
money type; otherwise, "false ".

AUTO_INCREMENT boolean Indicates that the data type can be


automatically incremented. "true " if
the type can be auto incremented;
otherwise, "false ".

LOCAL_TYPE_NAME String The localized name of the data type.

MINIMUM_SCALE shor t The maximum number of digits to the


right of the decimal point.

MAXIMUM_SCALE shor t The minimum number of digits to the


right of the decimal point.

SQL_DATA_TYPE int Not supported by the JDBC driver.

SQL_DATETIME_SUB int Not supported by the JDBC driver.

NUM_PREC_RADIX int The number of bits or digits for


calculating the maximum number that
a column can hold.

INTERVAL_PRECISION smallint The value of interval leading precision.


NAME TYPE DESC RIP T IO N

USERTYPE smallint The user type value from the


systypes table. For more information,
see SQL Server Books Online.

NOTE
For more information about the data returned by the getTypeInfo method, see "sp_datatype_info (Transact-SQL)" in SQL
Server Books Online.

Example
The following example demonstrates how to use the getTypeInfo method to return information about the data
types used in a SQL Server 2005 (9.x) (or later) database.

public static void executeGetTypeInfo(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getTypeInfo();
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getUDTs Method (SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the user-defined types that are defined in a particular schema.

NOTE
This method is not currently supported with Microsoft JDBC Driver for SQL Server. When used, this method will always
return an empty result set.

Syntax
public java.sql.ResultSet getUDTs(java.lang.String catalog,
java.lang.String schemaPattern,
java.lang.String typeNamePattern,
int[] types)

Parameters
catalog
A String that contains the catalog name.
schemaPattern
A String that contains the schema name pattern.
typeNamePattern
A String that contains the type name pattern.
types
An array of ints that contain the data types to include. Null indicates that all types should be included.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getUDTs method is specified by the getUDTs method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getURL Method (SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the URL for this database.

Syntax
public java.lang.String getURL()

Return Value
A String that contains the URL.

Exceptions
SQLServerException

Remarks
This getURL method is specified by the getURL method in the java.sql.DatabaseMetaData interface.
When using the Microsoft JDBC Driver for SQL Server with a SQL Server database, this method returns a String
value that contains the following information:
A URL value of "jdbc:sqlserver://"
Optional connection properties, such as ser verName , instanceName , and por tNumber
Other connection properties set by the user and all connection properties with non-empty or non-null
driver default values except userName , password , and integratedSecurity .

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getUserName Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the user name as known to this database.

Syntax
public java.lang.String getUserName()

Return Value
A String that contains the user name.

Exceptions
SQLServerException

Remarks
This getUserName method is specified by the getUserName method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
getVersionColumns Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a description of the columns of a table that is automatically updated when any value in a row is
updated.

Syntax
public java.sql.ResultSet getVersionColumns(java.lang.String catalog,
java.lang.String schema,
java.lang.String table)

Parameters
catalog
A String that contains the catalog name.
schema
A String that contains the schema name pattern.
table
A String that contains the table name.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This getVersionColumns method is specified by the getVersionColumns method in the
java.sql.DatabaseMetaData interface.
The result set returned by the getVersionColumns method will contain the following information:

NAME TYPE DESC RIP T IO N

SCOPE shor t Not supported by the JDBC driver.

COLUMN_NAME String The column name.

DATA_TYPE shor t The SQL data type from java.sql.Types.


NAME TYPE DESC RIP T IO N

TYPE_NAME String The name of the data type.

COLUMN_SIZE int The precision of the column.

BUFFER_LENGTH int The length of the column in bytes.

DECIMAL_DIGITS shor t The scale of the column.

PSEUDO_COLUMN shor t Indicates if the column is a pseudo


column. It can be one of the following
values:

versionColumnUnknown (0)

versionColumnNotPseudo (1)

versionColumnPseudo (2)

NOTE
For more information about the data returned by the getVersionColumns method, see "sp_datatype_info (Transact-SQL)"
in SQL Server Books Online.

Example
The following example demonstrates how to use the getVersionColumns method to return information about
the columns that are automatically updated in the Person.Contact table in the sample database.

public static void executeGetVersionColumns(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
ResultSet rs = dbmd.getVersionColumns("AdventureWorks", "Person", "Contact");
ResultSetMetaData rsmd = rs.getMetaData();

// Display the result set data.


int cols = rsmd.getColumnCount();
while(rs.next()) {
for (int i = 1; i <= cols; i++) {
System.out.println(rs.getString(i));
}
}
rs.close();
}

catch (Exception e) {
e.printStackTrace();
}
}

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
insertsAreDetected Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether or not a visible row insert can be detected by calling the method rowInserted method of the
SQLServerResultSet class.

Syntax
public boolean insertsAreDetected(int type)

Parameters
type
An integer that indicates the result set type, which can be one of the following values as defined in
java.sql.ResultSet or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if the row insert can be detected. Otherwise, false .

Exceptions
SQLServerException

Remarks
This insertsAreDetected method is specified by the insertsAreDetected method in the java.sql.DatabaseMetaData
interface.
NOTE
SQL Server does not detect inserted rows for any cursor type.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
isCatalogAtStart Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a catalog appears at the start of a fully qualified table name.

Syntax
public boolean isCatalogAtStart()

Return Value
true if the catalog name is first. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isCatalogAtStart method is specified by the isCatalogAtStart method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
isReadOnly Method (SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database is in read-only mode.

Syntax
public boolean isReadOnly()

Return Value
true if the database is in read-only mode. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isReadOnly method is specified by the isReadOnly method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
locatorsUpdateCopy Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether updates made to a LOB are made on a copy or directly to the LOB.

Syntax
public boolean locatorsUpdateCopy()

Return Value
true if updates are made to a copy. false if updates are made directly.

Exceptions
java.sql.SQLException

Remarks
This locatorsUpdateCopy method is specified by the locatorsUpdateCopy method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
nullPlusNonNullIsNull Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this database supports concatenations between NULL and non-NULL values being NULL.

Syntax
public boolean nullPlusNonNullIsNull()

Return Value
true if the concatenations are supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This nullPlusNonNullIsNull method is specified by the nullPlusNonNullIsNull method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
nullsAreSortedAtEnd Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether NULL values are sorted at the end, regardless of sort order.

Syntax
public boolean nullsAreSortedAtEnd()

Return Value
true if sorted at the end. Otherwise, false .

Exceptions
SQLServerException

Remarks
This nullsAreSortedAtEnd method is specified by the nullsAreSortedAtEnd method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
nullsAreSortedAtStart Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether NULL values are sorted at the start, regardless of sort order.

Syntax
public boolean nullsAreSortedAtStart()

Return Value
true if sorted at the start. Otherwise, false .

Exceptions
SQLServerException

Remarks
This nullsAreSortedAtStart method is specified by the nullsAreSortedAtStart method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
nullsAreSortedHigh Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether NULL values are sorted high.

Syntax
public boolean nullsAreSortedHigh()

Return Value
true if the values are sorted high. Otherwise, false .

Exceptions
SQLServerException

Remarks
This nullsAreSortedHigh method is specified by the nullsAreSortedHigh method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
nullsAreSortedLow Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether NULL values are sorted low.

Syntax
public boolean nullsAreSortedLow()

Return Value
true if the values are sorted low. Otherwise, false .

Exceptions
SQLServerException

Remarks
This nullsAreSortedLow method is specified by the nullsAreSortedLow method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
othersDeletesAreVisible Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether deletes that are made by others are visible.

Syntax
public boolean othersDeletesAreVisible(int type)

Parameters
type
An int that indicates the result set type, which can be one of the following values as defined in java.sql.ResultSet
or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if the deletes are visible. Otherwise, false .

Exceptions
SQLServerException

Remarks
This othersDeletesAreVisible method is specified by the othersDeletesAreVisible method in the
java.sql.DatabaseMetaData interface.
See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
othersInsertsAreVisible Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether inserts that are made by others are visible.

Syntax
public boolean othersInsertsAreVisible(int type)

Parameters
type
An int that indicates the result set type, which can be one of the following values as defined in java.sql.ResultSet
or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if the inserts are visible. Otherwise, false .

Exceptions
SQLServerException

Remarks
This othersInsertsAreVisible method is specified by the othersInsertsAreVisible method in the
java.sql.DatabaseMetaData interface.
See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
othersUpdatesAreVisible Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether updates that are made by others are visible.

Syntax
public boolean othersUpdatesAreVisible(int type)

Parameters
type
An int that indicates the result set type, which can be one of the following values as defined in java.sql.ResultSet
or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if the updates are visible. Otherwise, false .

Exceptions
SQLServerException

Remarks
This othersUpdatesAreVisible method is specified by the othersUpdatesAreVisible method in the
java.sql.DatabaseMetaData interface.
See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
ownDeletesAreVisible Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a result set's own deletes are visible.

Syntax
public boolean ownDeletesAreVisible(int type)

Parameters
type
An int that indicates the result set type, which can be one of the following values as defined in java.sql.ResultSet
or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if the deletes are visible. Otherwise, false .

Exceptions
SQLServerException

Remarks
This ownDeletesAreVisible method is specified by the ownDeletesAreVisible method in the
java.sql.DatabaseMetaData interface.
See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
ownInsertsAreVisible Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a result set's own inserts are visible.

Syntax
public boolean ownInsertsAreVisible(int type)

Parameters
type
An int that indicates the result set type, which can be one of the following values as defined in java.sql.ResultSet
or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if the inserts are visible. Otherwise, false .

Exceptions
SQLServerException

Remarks
This ownInsertsAreVisible method is specified by the ownInsertsAreVisible method in the
java.sql.DatabaseMetaData interface.
See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
ownUpdatesAreVisible Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the result set's own updates are visible.

Syntax
public boolean othersUpdatesAreVisible(int type)

Parameters
type
An integer that indicates the result set type, which can be one of the following values as defined in
java.sql.ResultSet or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if the updates are visible. Otherwise, false .

Exceptions
SQLServerException

Remarks
This ownUpdatesAreVisible method is specified by the ownUpdatesAreVisible method in the
java.sql.DatabaseMetaData interface.
See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
storesLowerCaseIdentifiers Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database treats mixed-case SQL identifiers that are not enclosed in quotation marks as
case-insensitive and stores them in lowercase.

Syntax
public boolean storesLowerCaseIdentifiers()

Return Value
true if the identifiers are stored in lowercase. Otherwise, false .

Exceptions
SQLServerException

Remarks
This storesLowerCaseIdentifiers method is specified by the storesLowerCaseIdentifiers method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
storesLowerCaseQuotedIdentifiers Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database treats mixed-case SQL identifiers that are enclosed in quotation marks as case-
insensitive and stores them in lowercase.

Syntax
public boolean storesLowerCaseQuotedIdentifiers()

Return Value
true if the identifiers are stored in lowercase. Otherwise, false .

Exceptions
SQLServerException

Remarks
This storesLowerCaseQuotedIdentifiers method is specified by the storesLowerCaseQuotedIdentifiers method in
the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
storesMixedCaseIdentifiers Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database treats mixed-case SQL identifiers that are not enclosed in quotation marks as
case-insensitive and stores them in mixed case.

Syntax
public boolean storesMixedCaseIdentifiers()

Return Value
true if the identifiers are stored in mixed case. Otherwise, false .

Exceptions
SQLServerException

Remarks
This storesMixedCaseIdentifiers method is specified by the storesMixedCaseIdentifiers method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
storesMixedCaseQuotedIdentifiers Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database treats mixed-case SQL identifiers that are enclosed in quotation marks as case-
insensitive and stores them in mixed case.

Syntax
public boolean storesMixedCaseQuotedIdentifiers()

Return Value
true if the identifiers are stored in mixed case. Otherwise, false .

Exceptions
SQLServerException

Remarks
This storesMixedCaseQuotedIdentifiers method is specified by the storesMixedCaseQuotedIdentifiers method in
the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
storesUpperCaseIdentifiers Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database treats mixed-case SQL identifiers that are not enclosed in quotation marks as
case-insensitive and stores them in uppercase.

Syntax
public boolean storesUpperCaseIdentifiers()

Return Value
true if the identifiers are stored in uppercase. Otherwise, false .

Exceptions
SQLServerException

Remarks
This storesUpperCaseIdentifiers method is specified by the storesUpperCaseIdentifiers method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
storesUpperCaseQuotedIdentifiers Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database treats mixed-case SQL identifiers that are enclosed in quotation marks as case-
insensitive and stores them in uppercase.

Syntax
public boolean storesUpperCaseQuotedIdentifiers()

Return Value
true if the identifiers are stored in uppercase. Otherwise, false .

Exceptions
SQLServerException

Remarks
This storesUpperCaseQuotedIdentifiers method is specified by the storesUpperCaseQuotedIdentifiers method in
the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsAlterTableWithAddColumn Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports ALTER TABLE with add column.

Syntax
public boolean supportsAlterTableWithAddColumn()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsAlterTableWithAddColumn method is specified by the supportsAlterTableWithAddColumn method
in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsAlterTableWithDropColumn Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports ALTER TABLE with drop column.

Syntax
public boolean supportsAlterTableWithDropColumn()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsAlterTableWithDropColumn method is specified by the supportsAlterTableWithDropColumn
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsANSI92EntryLevelSQL Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the ANSI92 entry level SQL grammar.

Syntax
public boolean supportsANSI92EntryLevelSQL()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsANSI92EntryLevelSQL method is specified by the supportsANSI92EntryLevelSQL method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsANSI92FullSQL Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the ANSI92 full SQL grammar.

Syntax
public boolean supportsANSI92FullSQL()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsANSI92FullSQL method is specified by the supportsANSI92FullSQL method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsANSI92IntermediateSQL Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the ANSI92 intermediate SQL grammar.

Syntax
public boolean supportsANSI92IntermediateSQL()

Return value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsANSI92IntermediateSQL method is specified by the supportsANSI92IntermediateSQL method in
the java.sql.DatabaseMetaData interface.

See also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsBatchUpdates Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports batch updates.

Syntax
public boolean supportsBatchUpdates()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsBatchUpdates method is specified by the supportsBatchUpdates method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsCatalogsInDataManipulation Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a catalog name can be used in a data manipulation statement.

Syntax
public boolean supportsCatalogsInDataManipulation()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsCatalogInDataManipulation method is specified by the supportsCatalogInDataManipulation
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsCatalogsInIndexDefinitions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a catalog name can be used in an index definition statement.

Syntax
public boolean supportsCatalogsInIndexDefinitions()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsCatalogsInIndexDefinitions method is specified by the supportsCatalogsInIndexDefinitions method
in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsCatalogsInPrivilegeDefinitions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a catalog name can be used in a privilege definition statement.

Syntax
public boolean supportsCatalogsInPrivilegeDefinitions()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsCatalogsInPrivilegeDefinitions method is specified by the supportsCatalogsInPrivilegeDefinitions
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsCatalogsInProcedureCalls Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a catalog name can be used in a procedure call statement.

Syntax
public boolean supportsCatalogsInProcedureCalls()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsCatalogsInProcedureCalls method is specified by the supportsCatalogsInProcedureCalls method in
the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsCatalogsInTableDefinitions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a catalog name can be used in a table definition statement.

Syntax
public boolean supportsCatalogsInTableDefinitions()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsCatalogsInTableDefinitions method is specified by the supportsCatalogsInTableDefinitions method
in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsColumnAliasing Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports column aliasing.

Syntax
public boolean supportsColumnAliasing()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsColumnAliasing method is specified by the supportsColumnAliasing method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsConvert Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the CONVERT function between SQL types.

Overload List
NAME DESC RIP T IO N

supportsConvert () Retrieves whether this database supports the CONVERT


function between SQL types.

supportsConvert (int, int) Retrieves whether this database supports the CONVERT for
two given SQL types.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsConvert Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the CONVERT function between SQL types.

Syntax
public boolean supportsConvert()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsConvert method is specified by the supportsConvert method in the java.sql.DatabaseMetaData
interface.

See Also
supportsConvert Method (SQLServerDatabaseMetaData)
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsConvert Method (int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the CONVERT for two given SQL types.

Syntax
public boolean supportsConvert(int fromType,
int toType)

Parameters
fromType
The JDBC type to convert from.
toType
The JDBC type to convert to.

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsConvert method is specified by the supportsConvert method in the java.sql.DatabaseMetaData
interface.

See Also
supportsConvert Method (SQLServerDatabaseMetaData)
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsCoreSQLGrammar Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the ODBC Core SQL grammar.

Syntax
public boolean supportsCoreSQLGrammar()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsCoreSQLGrammer method is specified by the supportsCoreSQLGrammer method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsCorrelatedSubqueries Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports correlated subqueries.

Syntax
public boolean supportsCorrelatedSubqueries()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsCorelatedSubqueries method is specified by the supportsCorelatedSubqueries method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsDataDefinitionAndDataManipulationTransactions
Method (SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports both data definition and data manipulation statements within a
transaction.

Syntax
public boolean supportsDataDefinitionAndDataManipulationTransactions()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This suportsDataDefinitionAndDataManipulationTransactions method is specified by the
suportsDataDefinitionAndDataManipulationTransactions method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsDataManipulationTransactionsOnly Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports only data manipulation statements within a transaction.

Syntax
public boolean supportsDataManipulationTransactionsOnly()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsDataManipulationTransactionsOnly method is specified by the
supportsDataManipulationTransactionsOnly method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsDifferentTableCorrelationNames Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether, when table correlation names are supported, they are restricted to being different from the
names of the tables.

Syntax
public boolean supportsDifferentTableCorrelationNames()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsDifferentTableCorrelationNames method is specified by the
supportsDifferentTableCorrelationNames method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsExpressionsInOrderBy Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports expressions in ORDER BY lists.

Syntax
public boolean supportsExpressionsInOrderBy()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsExpressionsInOrderBy method is specified by the supportsExpressionsInOrderBy method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsExtendedSQLGrammar Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the ODBC Extended SQL grammar.

Syntax
public boolean supportsExtendedSQLGrammar()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsExtendedSQLGrammer method is specified by the supportsExtendedSQLGrammer method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsFullOuterJoins Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports full nested outer joins.

Syntax
public boolean supportsFullOuterJoins()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsFullOuterJoins method is specified by the supportsFullOuterJoins method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsGetGeneratedKeys Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether auto-generated keys can be retrieved after a statement has been executed.

Syntax
public boolean supportsGetGeneratedKeys()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsGetGeneratedKeys method is specified by the supportsGetGeneratedKeys method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsGroupBy Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports some form of the GROUP BY clause.

Syntax
public boolean supportsGroupBy()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsGroupBy method is specified by the supportsGroupBy method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsGroupByBeyondSelect Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports using columns that are not included in the SELECT statement in a
GROUP BY clause, provided that all the columns in the SELECT statement are included in the GROUP BY clause.

Syntax
public boolean supportsGroupByBeyondSelect()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsGroupByBeyondSelect method is specified by the supportsGroupByBeyondSelect method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsGroupByUnrelated Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports using a column that is not in the SELECT statement in a GROUP BY
clause.

Syntax
public boolean supportsGroupByUnrelated()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsGroupByUnrelated method is specified by the supportsGroupByUnrelated method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsIntegrityEnhancementFacility Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the SQL Integrity Enhancement Facility.

Syntax
public boolean supportsIntegrityEnhancementFacility()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsIntegrityEnhancementFacility method is specified by the supportsIntegrityEnhancementFacility
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsLikeEscapeClause Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports specifying a LIKE escape clause.

Syntax
public boolean supportsLikeEscapeClause()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsLikeEscapeClause method is specified by the supportsLikeEscapeClause method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsLimitedOuterJoins Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database provides limited support for outer joins.

Syntax
public boolean supportsLimitedOuterJoins()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsLimitedOuterJoins method is specified by the supportsLimitedOuterJoins method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsMinimumSQLGrammar Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the ODBC Minimum SQL grammar.

Syntax
public boolean supportsMinimumSQLGrammar()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsMinimumSQLGrammer method is specified by the supportsMinimumSQLGrammer method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsMixedCaseIdentifiers Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database treats mixed-case SQL identifiers that are not enclosed in quotation marks as
case-sensitive and stores them in mixed case.

Syntax
public boolean supportsMixedCaseIdentifiers()

Return Value
true if the identifiers are stored in mixed case. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsMixedCaseIdentifiers method is specified by the supportsMixedCaseIdentifiers method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsMixedCaseQuotedIdentifiers Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database treats mixed-case SQL identifiers that are enclosed in quotation marks as case-
sensitive and stores them in mixed case.

Syntax
public boolean supportsMixedCaseQuotedIdentifiers()

Return Value
true if the identifiers are stored in mixed case. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsMixedCaseQuotedIdentifiers method is specified by the supportsMixedCaseQuotedIdentifiers
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsMultipleOpenResults Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether it is possible to have multiple SQLServerResultSet objects returned from a
SQLServerCallableStatement object simultaneously.

Syntax
public boolean supportsMultipleOpenResults()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsMultipleOpenResults method is specified by the supportsMultipleOpenResults method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsMultipleResultSets Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports getting multiple SQLServerResultSet objects from a single call to the
execute method of the SQLServerCallableStatement class.

Syntax
public boolean supportsMultipleResultSets()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsMultipleResultSets method is specified by the supportsMultipleResultSets method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsMultipleTransactions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database allows having multiple transactions open at once on different connections.

Syntax
public boolean supportsMultipleTransactions()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsMultipleTransactions method is specified by the supportsMultipleTransactions method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsNamedParameters Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports named parameters in callable statements.

Syntax
public boolean supportsNamedParameters()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsNamedParameters method is specified by the supportsNamedParameters method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsNonNullableColumns Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether columns in this database can be defined as non-nullable.

Syntax
public boolean supportsNonNullableColumns()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsNonNullableColumns method is specified by the supportsNonNullableColumns method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsOpenCursorsAcrossCommit Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports keeping cursors open across commits.

Syntax
public boolean supportsOpenCursorsAcrossCommit()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsOpenCursorsAcrossCommit method is specified by the supportsOpenCursorsAcrossCommit
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsOpenCursorsAcrossRollback Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports keeping cursors open across rollbacks.

Syntax
public boolean supportsOpenCursorsAcrossRollback()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsOpenCursorsAcrossRollback method is specified by the supportsOpenCursorsAcrossRollback
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsOpenStatementsAcrossCommit Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports keeping statements open across commits.

Syntax
public boolean supportsOpenStatementsAcrossCommit()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsOpenStatementsAcrossCommit method is specified by the
supportsOpenStatementsAcrossCommit method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsOpenStatementsAcrossRollback Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports keeping statements open across rollbacks.

Syntax
public boolean supportsOpenStatementsAcrossRollback()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsOpenStatementsAcrossRollback method is specified by the
supportsOpenStatementsAcrossRollback method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsOrderByUnrelated Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports using a column that is not in the SELECT statement in an ORDER BY
clause.

Syntax
public boolean supportsOrderByUnrelated()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsOrderByUnrelated method is specified by the supportsOrderByUnrelated method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsOuterJoins Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports some form of outer join.

Syntax
public boolean supportsOuterJoins()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsOuterJoins method is specified by the supportsOuterJoins method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsPositionedDelete Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports positioned DELETE statements.

Syntax
public boolean supportsPositionedDelete()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsPositionedDelete method is specified by the supportsPositionedDelete method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsPositionedUpdate Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports positioned UPDATE statements.

Syntax
public boolean supportsPositionedUpdate()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsPositionedUpdate method is specified by the supportsPositionedUpdate method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsResultSetConcurrency Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the given concurrency type in combination with the given result set
type.

Syntax
public boolean supportsResultSetConcurrency(int type,
int concurrency)

Parameters
type
An int that indicates the result set type, which can be one of the following values as defined in java.sql.ResultSet
or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC
concurrency
An int that indicates the result set concurrency level, which can be one of the following values as defined in
java.sql.ResultSet or SQLServerResultSet:

Concurrency java.sql.ResultSet Types


CONCUR_READ_ONLY
CONCUR_UPDATABLE
Concurrency SQLServerResultSet Types
CONCUR_SS_OPTIMISTIC_CC
CONCUR_SS_SCROLL_LOCKS
CONCUR_SS_OPTIMISTIC_VAL

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsResultSetConcurrency method is specified by the supportsResultSetConcurrency method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsResultSetHoldability Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the given result set holdability.

Syntax
public boolean supportsResultSetHoldability(int holdability)

Parameters
holdability
An int that indicates the result set holdability, which can be one of the following values:
ResultSet.HOLD_CURSORS_OVER_COMMIT
ResultSet.CLOSE_CURSORS_AT_COMMIT

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsResultSetHoldability method is specified by the supportsResultSetHoldability method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsResultSetType Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the given result set type.

Syntax
public boolean supportsResultSetType(int type)

Parameters
type
An int that indicates the result set type, which can be one of the following values as defined in java.sql.ResultSet
or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsResultSetType method is specified by the supportsResultSetType method in the
java.sql.DatabaseMetaData interface.
See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSavepoints Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports savepoints.

Syntax
public boolean supportsSavepoints()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSavepoints method is specified by the supportsSavepoints method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSchemasInDataManipulation Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a schema name can be used in a data manipulation statement.

Syntax
public boolean supportsSchemasInDataManipulation()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSchemasInDataManipulation method is specified by the supportsSchemasInDataManipulation
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSchemasInIndexDefinitions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a schema name can be used in an index definition statement.

Syntax
public boolean supportsSchemasInIndexDefinitions()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSchemasInIndexDefinitions method is specified by the supportsSchemasInIndexDefinitions
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSchemasInPrivilegeDefinitions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a schema name can be used in a privilege definition statement.

Syntax
public boolean supportsSchemasInPrivilegeDefinitions()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSchemasInPrivilegeDefinitions method is specified by the supportsSchemasInPrivilegeDefinitions
method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSchemasInProcedureCalls Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a schema name can be used in a procedure call statement.

Syntax
public boolean supportsSchemasInProcedureCalls()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSchemasInProcedureCalls method is specified by the supportsSchemasInProcedureCalls method
in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSchemasInTableDefinitions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a schema name can be used in a table definition statement.

Syntax
public boolean supportsSchemasInTableDefinitions()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSchemasInTableDefinitions method is specified by the supportsSchemasInTableDefinitions method
in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSelectForUpdate Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports SELECT FOR UPDATE statements.

Syntax
public boolean supportsSelectForUpdate()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSelectForUpdate method is specified by the supportsSelectForUpdate method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsStatementPooling Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports statement pooling.

Syntax
public boolean supportsStatementPooling()

Return Value
true if supported. Otherwise, false .

Exceptions
java.sql.SQLException

Remarks
This supportsStatementPooling method is specified by the supportsStatementPooling method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsStoredProcedures Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports stored procedure calls that use the stored procedure escape syntax.

Syntax
public boolean supportsStoredProcedures()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsStoredProcedures method is specified by the supportsStoredProcedures method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsStoredFunctionsUsingCallSyntax Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether the current database supports invoking user- or vendor-defined functions by using the stored
procedure escape syntax.

Syntax
public boolean supportsStoredFunctionsUsingCallSyntax()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsStoredFunctionsUsingCallSyntax method is specified by the
supportsStoredFunctionsUsingCallSyntax method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSubqueriesInComparisons Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports subqueries in comparison expressions.

Syntax
public boolean supportsSubqueriesInComparisons()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSubqueriesInComparisons method is specified by the supportsSubqueriesInComparisons method
in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSubqueriesInExists Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports subqueries in EXISTS expressions.

Syntax
public boolean supportsSubqueriesInExists()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSubqueriesInExists method is specified by the supportsSubqueriesInExists method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSubqueriesInIns Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports subqueries in IN statements.

Syntax
public boolean supportsSubqueriesInIns()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSubqueriesInIns method is specified by the supportsSubqueriesInIns method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsSubqueriesInQuantifieds Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports subqueries in quantified expressions.

Syntax
public boolean supportsSubqueriesInQuantifieds()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsSubqueriesInQuantifieds method is specified by the supportsSubqueriesInQuantifieds method in
the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsTableCorrelationNames Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports table correlation names.

Syntax
public boolean supportsTableCorrelationNames()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsTableCorrelationNames method is specified by the supportsTableCorrelationNames method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsTransactionIsolationLevel Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports the given transaction isolation level.

Syntax
public boolean supportsTransactionIsolationLevel(int level)

Parameters
level
An int that indicates the transaction isolation level.

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsTransactionIsolationLevel method is specified by the supportsTransactionIsolationLevel method in
the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsTransactions Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports transactions.

Syntax
public boolean supportsTransactions()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsTransactions method is specified by the supportsTransactions method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsUnion Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports SQL UNION.

Syntax
public boolean supportsUnion()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsUnion method is specified by the supportsUnion method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
supportsUnionAll Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database supports SQL UNION ALL.

Syntax
public boolean supportsUnionAll()

Return Value
true if supported. Otherwise, false .

Exceptions
SQLServerException

Remarks
This supportsUnionAll method is specified by the supportsUnionAll method in the java.sql.DatabaseMetaData
interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
updatesAreDetected Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether or not a visible row update can be detected by calling the rowUpdated method of the
SQLServerResultSet class.

Syntax
public boolean updatesAreDetected(int type)

Parameters
type
An int that indicates the result set type, which can be one of the following values as defined in java.sql.ResultSet
or SQLServerResultSet:

java.sql.ResultSet Types
TYPE_FORWARD_ONLY
TYPE_SCROLL_SENSITIVE
TYPE_SCROLL_INSENSITIVE

SQLServerResultSet Types
TYPE_SS_SCROLL_STATIC
TYPE_SS_SCROLL_KEYSET
TYPE_SS_DIRECT_FORWARD_ONLY
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
TYPE_SS_SCROLL_DYNAMIC

Return Value
true if the row update can be detected. Otherwise, false .

Exceptions
SQLServerException

Remarks
This updatesAreDetected method is specified by the updatesAreDetected method in the
java.sql.DatabaseMetaData interface.
See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
usesLocalFilePerTable Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database uses a file for each table.

Syntax
public boolean usesLocalFilePerTable()

Return Value
true uses a file for each table. Otherwise, false .

Exceptions
SQLServerException

Remarks
This usesLocalFilePerTable method is specified by the usesLocalFilePerTable method in the
java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
usesLocalFiles Method
(SQLServerDatabaseMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether this database stores tables in a local file.

Syntax
public boolean usesLocalFiles()

Return Value
true if the database uses local files. Otherwise, false .

Exceptions
SQLServerException

Remarks
This usesLocalFiles method is specified by the usesLocalFiles method in the java.sql.DatabaseMetaData interface.

See Also
SQLServerDatabaseMetaData Methods
SQLServerDatabaseMetaData Members
SQLServerDatabaseMetaData Class
SQLServerDataSource Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a list of properties specific to connecting to a SQL Server database by using a SQLServerConnection
object.
Package: com.microsoft.sqlserver.jdbc
Implements: ISQLServerDataSource, DataSource, java.io.Serializable, javax.naming.Referenceable

Syntax
public class SQLServerDataSource

Remarks
This class supports unwrapping to SQLServerDataSource class, the ISQLServerDataSource interface, and the
DataSource interface. For more information, see Wrappers and Interfaces.

See Also
SQLServerDataSource Members
JDBC Driver API Reference
SQLServerDataSource Members
4/27/2022 • 4 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members exposed by the SQLServerDataSource class.

Constructors
NAME DESC RIP T IO N

SQLServerDataSource () Initializes a new instance of the SQLServerDataSource class.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

getApplicationIntent Returns the value of the applicationIntent connection


property.

getApplicationName Returns the application name.

getConnection Tries to establish a connection with the data source that this
SQLServerDataSource object represents.

getDatabaseName Returns the database name.

getDisableStatementPooling Returns the value of disableStatementPooling connection


property. This setting controls whether statement pooling is
enabled or not for this connection.

getEnablePrepareOnFirstPreparedStatementCall Returns the value of


enablePrepareOnFirstPreparedStatementCall
connection property.

getEncrypt Returns a Boolean value indicating whether the encrypt


property is enabled.

getDescription Returns a description of the data source.

getFailoverPartner Returns the name of the failover server used in a database


mirroring configuration.
NAME DESC RIP T IO N

getHostNameInCertificate Returns the host name used in validating the SQL Server
Transport Layer Security (TLS), previously known as Secure
Sockets Layer (SSL), certificate.

getInstanceName Returns the SQL Server instance name.

getLastUpdateCount Returns a boolean value indicating whether the


lastUpdateCount property is enabled.

getLockTimeout Returns an int value indicating the number of milliseconds


the database waits before reporting a lock time out.

getLoginTimeout Returns the number of seconds this SQLServerDataSource


object waits while trying to make a connection.

getLogWriter Returns a character output stream to be used for all logging


and tracing messages.

getMultiSubnetFailover Returns the value of the multiSubnetFailover connection


property.

getPacketSize Returns the current network packet size used to


communicate with SQL Server, specified in bytes.

getPortNumber Returns the current port number used to communicate with


SQL Server.

getReference Returns a reference to this SQLServerDataSource object.

getResponseBuffering Returns the response buffering mode for this


SQLServerDataSource object.

getSelectMethod Returns the default cursor type used for all result sets
created by using this SQLServerDataSource object.

getSendStringParametersAsUnicode Returns a Boolean value indicating whether sending string


parameters to the server in UNICODE format is enabled.

getSendTimeAsDatetime Returns the setting of the SendTimeAsDatetime


connection property.

getServerName Returns the name of the computer running SQL Server.

getServerPreparedStatementDiscardThreshold Returns the value of


ser verPreparedStatementDiscardThreshold connection
property.

getStatementPoolingCacheSize Returns the size of the prepared statement cache for this
connection.

getTrustManagerClass Returns the string value of the TrustManagerClass


connection property.
NAME DESC RIP T IO N

getTrustManagerConstructorArg Returns the string value of the TrustManagerConstructorArg


connection property.

getTrustServerCertificate Returns a Boolean value indicating whether the


trustServerCertificate property is enabled.

getTrustStore Returns the path (including file name) to the certificate


trustStore file.

getURL Returns the URL used to connect to the data source.

getUser Returns the user name used to connect the data source.

getUseSQLServerBaseDate Returns the setting of the useSQLServerBaseDate


connection property.

getWorkstationID Returns the name of the client computer name used to


connect to the data source.

getXopenStates Returns a Boolean value indicating whether converting SQL


states to XOPEN compliant states is enabled.

isWrapperFor Indicates whether this data source object is a wrapper for


the specified interface.

setApplicationIntent Sets the value of the applicationIntent connection


property.

setApplicationName Sets the application name.

setAuthenticationScheme Indicates the kind of integrated security you want your


application to use.

setDatabaseName Sets the database name to connect to.

setDescription Sets the description of the data source.

setDisableStatementPooling Sets statement pooling to true or false.

setEnablePrepareOnFirstPreparedStatementCall Specifies the new value of the


enablePrepareOnFirstPreparedStatementCall
connection property.

setEncrypt Sets a Boolean value indicating whether the encrypt


property is enabled.

setFailoverPartner Sets the name of the failover server used in a database


mirroring configuration.

setHostNameInCertificate Sets the host name to be used in validating the SQL Server
Transport Layer Security (TLS), previously known as Secure
Sockets Layer (SSL), certificate.
NAME DESC RIP T IO N

setInstanceName Sets the SQL Server instance name.

setIntegratedSecurity Sets a Boolean value indicating whether the


integratedSecurity property is enabled.

setLastUpdateCount Sets a Boolean value indicating whether the


lastUpdateCount property is enabled.

setLockTimeout Sets an int value indicating the number of milliseconds to


wait before the database reports a lock time out.

setLoginTimeout Sets the number of seconds that this SQLServerDataSource


object waits while trying to make a connection.

setLogWriter Sets a character output stream to be used for all logging and
tracing messages.

setMultiSubnetFailover Sets the value of the multiSubnetFailover connection


property.

setPacketSize Sets the current network packet size used to communicate


with SQL Server, specified in bytes.

setPassword Sets the password used to connect to SQL Server.

setPortNumber Sets the port number used to communicate with SQL Server.

setResponseBuffering Sets the response buffering mode for connections created by


using this SQLServerDataSource object.

setSelectMethod Sets the default cursor type used for all result sets created
by using this SQLServerDataSource object.

setSendStringParametersAsUnicode Sets a Boolean value indicating whether sending string


parameters to the server in UNICODE format is enabled.

setSendTimeAsDatetime Specifies how to send java.sql.Time values to the server.

setServerName Sets the name of the computer running SQL Server.

setServerPreparedStatementDiscardThreshold Sets the new value of the


ser verPreparedStatementDiscardThreshold connection
property.

setStatementPoolingCacheSize Sets the size of the prepared statement cache for this
connection.

setTrustManagerClass Sets the string value of the TrustManagerClass connection


property.

setTrustManagerConstructorArg Sets the string value of the TrustManagerConstructorArg


connection property.
NAME DESC RIP T IO N

setTrustServerCertificate Sets a Boolean value indicating whether the


trustServerCertificate property is enabled.

setTrustStore Sets the path (including file name) to the certificate


trustStore file.

setTrustStorePassword Sets the password that is used to check the integrity of the
trustStore data.

setURL Sets the URL used to connect to the data source.

setUser Sets the user name used to connect the data source.

setWorkstationID Sets the name of the client computer used to connect to the
data source.

setXopenStates Sets a Boolean value indicating whether converting SQL


states to XOPEN compliant states is enabled.

unwrap Returns an object that implements the specified interface to


allow access to the Microsoft JDBC Driver for SQL Server-
specific methods.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

java.sql.Wrapper isWrapperFor, unwrap

See Also
SQLServerDataSource Class
SQLServerDataSource Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For more information on the SQLServerDataSource constructors, see SQLServerDataSource Members.

See Also
SQLServerDataSource Class
SQLServerDataSource Constructor ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerDataSource class.

Syntax
public SQLServerDataSource()

See Also
SQLServerDataSource Members
SQLServerDataSource Class
SQLServerDataSource Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerDataSource, see SQLServerDataSource Members.

See Also
SQLServerDataSource Class
getApplicationIntent Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the value of the applicationIntent connection property.

Syntax
public java.lang.String getApplicationIntent();

Return Value
Returns the value of the applicationIntent connection property.

Remarks
For more information about the applicationIntent connection property, see Setting the Connection Properties.

See Also
SQLServerDataSource.setApplicationIntent
SQLServerDataSource Members
SQLServerDataSource Class
getApplicationName Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the application name.

Syntax
public java.lang.String getApplicationName()

Return Value
A String that contains the application name, or " Microsoft JDBC Driver for SQL Server" if no value is set.

Remarks
The application name is used to identify the specific application in various SQL Server profiling and logging
tools. If the application name is not set, the getApplicationName method returns the non-localized string "
Microsoft JDBC Driver for SQL Server".

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getConnection Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to establish a connection with the data source that this SQLServerDataSource object represents.

Overload List
NAME DESC RIP T IO N

getConnection () Tries to establish a connection with the data source that this
SQLServerDataSource object represents.

getConnection (java.lang.String, java.lang.String) Tries to establish a connection with the data source that this
SQLServerDataSource object represents by using the given
user name and password.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getConnection Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to establish a connection with the data source that this SQLServerDataSource object represents.

Syntax
public java.sql.Connection getConnection()

Return Value
A SQLServerConnection object.

Exceptions
java.sql.SQLException

Remarks
This getConnection method is specified by the getConnection method in the javax.sql.DataSource interface.

See Also
getConnection Method (SQLServerDataSource)
SQLServerDataSource Members
SQLServerDataSource Class
getConnection Method ( java.lang.String,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to establish a connection with the data source that this SQLServerDataSource object represents by using
the given user name and password.

Syntax
public java.sql.Connection getConnection(java.lang.String username,
java.lang.String password)

Parameters
username
A String that contains the user name.
password
A String that contains the password.

Return Value
A SQLServerConnection object.

Exceptions
java.sql.SQLException

Remarks
This getConnection method is specified by the getConnection method in the javax.sql.DataSource interface.
Calling the getConnection method with a non-null user name or password will replace the user name and
password properties that are set on the SQLServerDataSource class when initializing the SQLServerConnection
object. For example, if the caller has called setUser and setPassword on the data source, and then calls
getConnection and supplies a non-null user name or a non-null password, the user name and password set by
setUser and setPassword will be replaced by the user name and password passed into getConnection.

NOTE
The user name and password that are set inside the URL by using a call to the setURL method will not be changed in this
case.

See Also
getConnection Method (SQLServerDataSource)
SQLServerDataSource Members
SQLServerDataSource Class
getDatabaseName Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the database name.

Syntax
public java.lang.String getDatabaseName()

Return Value
A String that contains the database name or null if no value is set.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getDescription Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a description of the data source.

Syntax
public java.lang.String getDescription()

Return Value
A String that contains the data source description or null if no value is set.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getDisableStatementPooling Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the value of disableStatementPooling connection property. This setting controls whether statement
pooling is enabled or not for this connection.

Syntax
public boolean getDisableStatementPooling();

Return Value
A boolean that contains the value of disableStatementPooling connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getEnablePrepareOnFirstPreparedStatementCall
Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the value of enablePrepareOnFirstPreparedStatementCall connection property. If this
configuration returns false the first execution of a prepared statement will call sp_executesql and not prepare a
statement, once the second execution happens it will call sp_prepexec and actually setup a prepared statement
handle. Following executions will call sp_execute. This relieves the need for sp_unprepare on prepared statement
close if the statement is only executed once.

Syntax
public boolean getEnablePrepareOnFirstPreparedStatementCall();

Return Value
Returns the boolean value of the enablePrepareOnFirstPreparedStatementCall connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getEncrypt Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a Boolean value that indicates if the encrypt property is enabled.

Syntax
public boolean getEncypt()

Return Value
true if encrypt is enabled. Otherwise, false .

Remarks
If the encrypt property is set to true , the Microsoft JDBC Driver for SQL Server ensures that SQL Server uses
TLS encryption for all data sent between the client and the server if the server has a certificate installed.
If the encrypt property is unspecified or set to false , the driver will not enforce the SQL Server to support TLS
encryption. If the SQL Server instance is not configured to force the TLS encryption, a connection is established
without any encryption. If the SQL Server instance is configured to force the TLS encryption, the Microsoft JDBC
Driver for SQL Server will automatically enable TLS encryption when running on properly configured Java
Virtual Machine (JVM), or else the connection is terminated and the driver will raise an error. If the encryption
property is not set, the getEncrypt method returns the default value of false .

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getFailoverPartner Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the name of the failover server that is used in a database mirroring configuration.

Syntax
public string getFailoverPartner()

Return Value
A String that contains the name of the failover partner, or null if none is set.

Remarks
The value returned by this method reflects the failover partner name set using the setFailoverPartner method.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getHostNameInCertificate Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the host name used in validating the SQL Server Transport Layer Security (TLS), previously known as
Secure Sockets Layer (SSL), certificate.

Syntax
public java.lang.String getHostNameInCertificate()

Return Value
A String that contains the host name, or null if no value is set.

Remarks
The host name is used to validate the SQL Server TLS/SSL certificate value when the communication layer is
encrypted using TLS/SSL.
If the host name is not set, the getHostNameInCertificate method returns null.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getInstanceName Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the SQL Server instance name.

Syntax
public java.lang.String getInstanceName()

Return Value
A String that contains the instance name, or null if no value is set.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getLastUpdateCount Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a Boolean value that indicates if the lastUpdateCount property is enabled.

Syntax
public boolean getLastUpdateCount()

Return Value
true if lastUpdateCount is enabled. Otherwise, false .

Remarks
If the lastUpdateCount property is set to true , the Microsoft JDBC Driver for SQL Server will return only the last
update count from an SQL statement passed to the server. If the lastUpdateCount property is set to false , the
driver will return all update counts including those returned by any triggers that may have fired. If the
lastUpdateCount property is not set, the getLastUpdateCount method returns the default value of true .

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getLockTimeout Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an int value that indicates the number of milliseconds that the database will wait before reporting a
lock time out.

Syntax
public int getLockTimeout()

Return Value
An int value that contains the number of milliseconds that the database will wait.

Remarks
The lock time out is the number of milliseconds to wait before the database reports a lock time out. The default
value of -1 means that it will wait indefinitely. If specified, this value will be the default for all statements on the
connection.

NOTE
A value of 0 means no wait. If the lockTimeout property is not set, the getLockTimeout method returns the default value
of -1.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getLoginTimeout Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the number of seconds that this SQLServerDataSource object will wait while trying to make a
connection.

Syntax
public int getLoginTimeout()

Return Value
An int value that represents the number of seconds to wait.

Remarks
If the application does not specify a timeout value explicitly, this method returns a default value of 15 seconds.
This getLoginTimeout method is specified by the getLoginTimeout method in the javax.sql.DataSource interface.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getLogWriter Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method is for internal use only. For more information about logging, see Tracing Driver Operation.

Syntax
public java.io.PrintWriter getLogWriter()

Return Value
A PrintWriter object.

Remarks
This getLogWriter method is specified by the getLogWriter method in the javax.sql.DataSource interface.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getMultiSubnetFailover Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the value of the multiSubnetFailover connection property.

Syntax
public boolean getMultiSubnetFailover();

Return Value
Returns true or false, depending on the current setting of the connection property.

Remarks
For more information about the multiSubnetFailover connection property, see Setting the Connection
Properties.

See Also
SQLServerDataSource.setMultiSubnetFailover
SQLServerDataSource Members
SQLServerDataSource Class
getPacketSize Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the current network packet size used to communicate with SQL Server, specified in bytes.

Syntax
public int getPacketSize()

Return Value
An int value containing the current network packet size.

Remarks
If the packetSize property is not set, the getPacketSize method returns the default value of 8000.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getPortNumber Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the current port number that is used to communicate with SQL Server.

Syntax
public int getPortNumber()

Return Value
An int value that contains the current port number.

Remarks
The port number is the TCP/IP port number that is used when opening a socket connection to SQL Server. If the
portNumber property is not set, the getPortNumber method returns the default value of 1433.

NOTE
The setPortNumber method does not do any range checking on the port value passed in. You can pass tort numbers that
are not valid, like 99999, without triggering an error.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getReference Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a reference to this SQLServerDataSource object.

Syntax
public javax.naming.Reference getReference()

Return Value
A Reference object.

Remarks
This getReference method is specified by the getReference method in the javax.naming.Referenceable interface.
Prior to SQL Server JDBC Driver 3.0, if SQLServerDataSource.setTrustStorePassword was called on a
SQLServerDataSource object, the password would be present in the object returned by
SQLServerDataSource.getReference, allowing the object to be used to make additional connections. In JDBC
Driver 3.0, you will need to set the password on the object returned by SQLServerDataSource.getReference
before you make connections with the object.
Also, if you set SQLServerDataSource.setTrustStorePassword before binding the data source properties, you
must call SQLServerDataSource.setTrustStorePassword before getting the connection. For example,

ctx = new InitialContext(System.getProperties());

SQLServerDataSource ds1 = (SQLServerDataSource) ctx.lookup(jndiName);

ds1.setTrustStorePassword("XXXXX");
Connection con = ds1.getConnection("user", "XXXXXX");

ctx.rebind(jndiName, ds1);
SQLServerDataSource ds2 = (SQLServerDataSource) ctx.lookup(jndiName);
ds2.setTrustStorePassword("XXXXX"); // reset the truststore password
con = ds2.getConnection("user", "XXXXXX"); // provide userid and password again

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getResponseBuffering Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the response buffering mode for this SQLServerDataSource object.

Syntax
public java.lang.String getResponseBuffering()

Return Value
A String that contains a lower-case full or adaptive .

Remarks
The full value specifies reading the entire result from the server at run time.
The adaptive value specifies buffering the minimum possible data when necessary. The adaptive value is the
default buffering mode.
For more information about using the response buffering mode, see Using Adaptive Buffering.

See Also
setResponseBuffering Method (SQLServerDataSource)
SQLServerDataSource Members
SQLServerDataSource Class
getSelectMethod Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the default cursor type used for all result sets that are created by using this SQLServerDataSource
object.

Syntax
public java.lang.String getSelectMethod()

Return Value
A String value that contains the default cursor type.

Remarks
The selectMethod property specifies the default cursor type that is used for a result set. This property is useful
when you are dealing with large result sets and do not want to store the entire result set in memory on the
client side. By setting the property to "cursor," you can create a server-side cursor that can fetch smaller chunks
of data at a time. If the selectMethod property is not set, getSelectMethod returns the default value of "direct".

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getSendStringParametersAsUnicode Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a boolean value that indicates if sending string parameters to the server in UNICODE format is
enabled.

Syntax
public boolean getSendStringParametersAsUnicode()

Return Value
true if string parameters are sent to the server in UNICODE format. Otherwise, false .

Remarks
If the sendStringParametersAsUnicode property is set to true , which is the default value, string parameters are
sent to the server in UNICODE format. If sendStringParametersAsUnicode is set to false , string parameters are
sent to the server in an ASCII/MBCS format, not in UNICODE. If sendStringParametersAsUnicode is not set,
getSendStringParametersAsUnicode returns the default value of true .
For more information about the sendStringParametersAsUnicode connection property, see Setting the
Connection Properties.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getServerName Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the name of the SQL Server instance.

Syntax
public java.lang.String getServerName()

Return Value
A String that contains the server name or null if no value is set.

Remarks
The server name is the host name of the target computer that is running SQL Server. If the getServerName
property is not set, getServerName returns the default value of null.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getServerPreparedStatementDiscardThreshold
Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the value of ser verPreparedStatementDiscardThreshold connection property. This setting controls
how many outstanding prepared statement discard actions (sp_unprepare) can be outstanding per connection
before a call to clean up the outstanding handles on the server is executed. When the setting is <= 1 unprepare
actions are executed immediately on prepared statement close. If this value set to > 1 these calls are batched
together to avoid overhead of calling sp_unprepare too often.

Syntax
public int getServerPreparedStatementDiscardThreshold();

Return Value
Returns the int value of the ser verPreparedStatementDiscardThreshold connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getStatementPoolingCacheSize Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the value of statementPoolingCacheSize connection property. Returns the size of the prepared
statement cache for this connection. '0' means caching not enabled.

Syntax
public boolean getStatementPoolingCacheSize();

Return Value
The int value of the statementPoolingCacheSize connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getTrustManagerClass Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the String value of the TrustManagerClass connection property.

Syntax
public java.lang.String getTrustManagerClass()

Return Value
A String that contains the value of the TrustManagerClass connection property, or null if no value is set.

Remarks
If the TrustManagerClass property is not set, the getTrustManagerClass method returns null.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getTrustManagerConstructorArg Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the String value of the TrustManagerConstructorArg connection property.

Syntax
public java.lang.String getTrustManagerConstructorArg()

Return Value
A String that contains the value of the TrustManagerConstructorArg connection property, or null if no value is
set.

Remarks
If the TrustManagerClass property is not set, the getTrustManagerConstructorArg method returns null.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getTrustServerCertificate Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a Boolean value that indicates if the trustServerCertificate property is enabled.

Syntax
public boolean getTrustServerCertificate()

Return Value
true if trustServerCertificate is enabled. Otherwise, false .

Remarks
If the trustServerCertificate property is set to true , the SQL Server Transport Layer Security (TLS), previously
known as Secure Sockets Layer (SSL), certificate is automatically trusted when the communication layer is
encrypted using TLS. In other words, the Microsoft JDBC Driver for SQL Server will not validate the SQL Server
TLS/SSL certificate. The default value is false .
If the trustServerCertificate property is set to false , the Microsoft JDBC Driver for SQL Server will validate the
server TLS/SSL certificate.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getTrustStore Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the path (including file name) to the certificate trustStore file.

Syntax
public java.lang.String getTrustStore()

Return Value
A String that contains the path (including file name) to the certificate trustStore file, or null if no value is set.

Remarks
If the trustStore property is not set, the getTrustStore method returns null.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getURL Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the URL that is used to connect to the data source.

Syntax
public java.lang.String getURL()

Return Value
A String that contains the URL.

Remarks
For security reasons, you should not include the password in the URL that is supplied to the setURL method. The
reason for this is that third-party Java Application Servers will very often display the value set for the URL
property in their data source configuration user interface. Instead, use the setPassword method to set the
password value. Java Application Servers will not display a password that is set in their data source in the
configuration user interface.

NOTE
If the setURL method is not called before calling the getURL method, getURL returns the default value of
"jdbc:sqlserver://".

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getSendTimeAsDatetime Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in SQL Server JDBC Driver 3.0.
Returns the setting of the sendTimeAsDatetime connection property.

Syntax
public boolean getSendTimeAsDatetime();

Return Value
true if java.sql.Time values will be sent to the server as a SQL Server datetime type. false if java.sql.Time
values will be sent to the server as a SQL Server time type.

Remarks
See Setting the Connection Properties for more information about the sendTimeAsDatetime connection
property.
SQLServerDataSource.setSendTimeAsDatetime lets you programmatically set the sendTimeAsDatetime
connection property.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getUser Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the user name that is used to connect the data source.

Syntax
public java.lang.String getUser()

Return Value
A String that contains the user name.

Remarks
The setUser method sets the user name that will be used when connecting to the instance of SQL Server. If user
name value is not set, the getUser method returns the default value of null.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getWorkstationID Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the name of the client computer name that is used to connect to the data source.

Syntax
public java.lang.String getWorkstationID()

Return Value
A String that contains the client computer name.

Remarks
The workstationID is the name of the client computer or workstation. If the workstationID property is not set, the
default value is constructed by calling InetAddress.getLocalHost().getHostName() method. If getHostName
returns a blank value, the getHostAddress().toString() method is called.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
getXopenStates Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a boolean value that indicates if converting SQL states to XOPEN compliant states is enabled.

Syntax
public boolean getXopenStates()

Return Value
true if converting SQL states to XOPEN compliant states is enabled. Otherwise, false .

Remarks
If the xopenStates property is set to true , the Microsoft JDBC Driver for SQL Server will convert SQL states to
XOPEN compliant states. The default is false , which causes the JDBC driver to generate SQL 99 state codes. If
xopenStates is not set, the getXopenStates method returns the default value of false .

See Also
SQLServerDataSource Members
SQLServerDataSource Class
isWrapperFor Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this data source object is a wrapper for the specified interface.

Syntax
public boolean isWrapperFor(Class iface)

Parameters
iface
A class defining an interface.

Return Value
true if this object implements the interface or wraps an object that implements the interface. Otherwise, false .

Exceptions
SQLServerException

Remarks
The isWrapperFor method and the unwrap method are defined by the java.sql.Wrapper interface, which is
introduced in the JDBC 4.0 Spec.
If this method returns true, calling unwrap with the same argument will succeed.
For more information, see Wrappers and Interfaces.

See Also
unwrap Method (SQLServerDataSource)
SQLServerDataSource Members
SQLServerDataSource Class
setApplicationIntent Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the applicationIntent connection property.

Syntax
public void setApplicationIntent(java.lang.String applicationIntent);

Parameters
applicationIntent
The new value of the applicationIntent connection property.

Remarks
For more information about the applicationIntent connection property, see Setting the Connection Properties.

See Also
SQLServerDataSource.getApplicationIntent
SQLServerDataSource Members
SQLServerDataSource Class
setApplicationName Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the application name.

Syntax
public void setApplicationName(java.lang.String applicationName)

Parameters
applicationName
A String that contains the name of the application.

Remarks
The application name is used to identify the specific application in various SQL Server profiling and logging
tools. If the application name is not set, the getApplicationName method returns the non-localized string "
Microsoft JDBC Driver for SQL Server".

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setAuthenticationScheme (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates the kind of integrated security you want your application to use.

Syntax
public void setAuthenticationScheme(String authenticationScheme);

Parameters
authenticationScheme
Values are "JavaKerberos" and the default "NativeAuthentication" . For more information, see Using
Kerberos Integrated Authentication to Connect to SQL Server.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setDatabaseName Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the database name to connect to.

Syntax
public void setDatabaseName(java.lang.String databaseName)

Parameters
databaseName
A String that contains the database name.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setDescription Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the description of the data source.

Syntax
public void setDescription(java.lang.String description)

Parameters
description
A String that contains the description.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setDisableStatementPooling Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the disableStatementPooling connection property. If false, enables statement pooling to be
used in coupling with statementPoolingCacheSize value > 0.

Syntax
public void setDisableStatementPooling(boolean disableStatementPooling);

Parameters
disableStatementPooling
The new value of the disableStatementPooling connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setEnablePrepareOnFirstPreparedStatementCall
Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Specifies the behavior for a specific connection instance. If this configuration is false the first execution of a
prepared statement will call sp_executesql and not prepare a statement, once the second execution happens it
will call sp_prepexec and actually setup a prepared statement handle. Following executions will call sp_execute.
This relieves the need for sp_unprepare on prepared statement close if the statement is only executed once.

Syntax
public void setEnablePrepareOnFirstPreparedStatementCall(boolean enablePrepareOnFirstPreparedStatementCall);

Parameters
enablePrepareOnFirstPreparedStatementCall
The new value of the enablePrepareOnFirstPreparedStatementCall connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setEncrypt Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets a Boolean value that indicates if the encrypt property is enabled.

Syntax
public void setEncypt(boolean encrypt)

Parameters
encrypt
true if the Transport Layer Security (TLS), previously known as Secure Sockets Layer (SSL), encryption is
enabled between the client and the SQL Server. Otherwise, false .

Remarks
If the encrypt property is set to true , the Microsoft JDBC Driver for SQL Server ensures that SQL Server uses
TLS encryption for all data sent between the client and server if the server has a certificate installed. The default
value is false .
The JDBC driver detects the Java Virtual Machine (JVM) it is running on when trying to establish a TLS
handshake.
If the encrypt property is set to true , the Microsoft JDBC Driver for SQL Server uses the JVM's default JSSE
security provider to negotiate TLS encryption with SQL Server. The default security provider may not support all
of the features required to negotiate TLS encryption successfully. For example, the default security provider may
not support the size of the RSA public key used in the SQL Server TLS/SSL certificate. In this case, the default
security provider might raise an error that will cause the JDBC driver to terminate the connection. In order to
resolve this issue, do one of the following:
Configure the SQL Server with a server certificate that has a smaller RSA public key
Configure the JVM to use a different JSSE security provider in the "<java-
home>/lib/security/java.security" security properties file
Use a different JVM
If the encrypt property is unspecified or set to false , the driver will not enforce the SQL Server to support TLS
encryption. If the SQL Server instance is not configured to force the TLS encryption, a connection is established
without any encryption. If the SQL Server instance is configured to force the TLS encryption, the Microsoft JDBC
Driver for SQL Server will automatically enable TLS encryption when running on properly configured JVM, or
else the connection is terminated and the driver will raise an error.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setFailoverPartner Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the name of the failover server that is used in a database mirroring configuration.

Syntax
public void setFailoverPartner(java.lang.String serverName)

Parameters
serverName
A String that contains the failover server name.

Remarks
The value set by this method is used in the case of an initial connection failure to the principal server; after the
initial connection is made, this value is ignored. The setDatabaseName method should also be used in
conjunction with this method or an exception will be thrown.
The driver does not support specifying the port number of the failover server when the failover server name is
set. However, calling the setServerName method and the setInstanceName method with the setFailoverPartner
method is supported.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setHostNameInCertificate Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the host name to be used in validating the SQL Server Transport Layer Security (TLS), previously known as
Secure Sockets Layer (SSL), certificate.

Syntax
public void setHostNameInCertificate(java.lang.String hostNameInCertificate)

Parameters
hostNameInCertificate
A String that contains the host name.

Remarks
The hostNameInCertificate value is used to validate the SQL Server TLS/SSL certificate when the
communication layer is encrypted by using TLS. The default value is null.
If the hostNameInCertificate property is set to null or unspecified, the Microsoft JDBC Driver for SQL Server will
use the serverName property value to validate against the SQL Server TLS/SSL certificate. If the
hostNameInCertificate property is set to a string or an empty string "", the driver will use that value to validate
the server TLS/SSL certificate.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setInstanceName Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the SQL Server instance name.

Syntax
public void setInstanceName(java.lang.String instanceName)

Parameters
instanceName
A String that contains the instance name.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setIntegratedSecurity Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets a Boolean value that indicates if the integratedSecurity property is enabled.

Syntax
public void setIntegratedSecurity(boolean enable)

Parameters
enable
true if integratedSecurity is enabled. Otherwise, false .

Remarks
Set to "true " to indicate that Windows credentials will be used by SQL Server to authenticate the user of the
application. If "true ", the Microsoft JDBC Driver for SQL Server will search the local computer credential cache
for credentials that have already been provided at the computer or network logon. If "false ", the username and
password must be supplied.

NOTE
This property is only supported on Microsoft Windows operating systems.

For more information about using integrated authentication, see Building the Connection URL.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setLastUpdateCount Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets a Boolean value that indicates if the lastUpdateCount property is enabled.

Syntax
public void setLastUpdateCount(boolean lastUpdateCount)

Parameters
lastUpdateCount
true if lastUpdateCount is enabled. Otherwise, false .

Remarks
If the lastUpdateCount property is set to true , Microsoft JDBC Driver for SQL Server will return only the last
update count from an SQL statement passed to the server. If the lastUpdateCount property is set to false , the
driver will return all update counts including those returned by any triggers that may have fired. If the
lastUpdateCount property is not set, the getLastUpdateCount method returns the default value of true .

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setLockTimeout Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets an int value that indicates the number of milliseconds to wait before the database reports a lock time out.

Syntax
public void setLockTimeout(int lockTimeout)

Parameters
lockTimeout
An int value that contains the number of milliseconds to wait.

Remarks
The lock time out is the number of milliseconds to wait before the database reports a lock time out. The default
value of -1 means that it will wait indefinitely. If specified, this value will be the default for all statements on the
connection.

NOTE
A value of 0 means no wait. If the lockTimeout property is not set, the getLockTimeout method returns the default value
of -1.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setLoginTimeout Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the number of seconds that this SQLServerDataSource object will wait while trying to make a connection.

Syntax
public void setLoginTimeout(int loginTimeout)

Parameters
loginTimeout
An int value that represents the number of seconds to wait. Zero means that the timeout is the default system
timeout, which is specified as 15 seconds by default.

Remarks
This setLoginTimeout method is specified by the setLoginTimeout method in the javax.sql.DataSource interface.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setLogWriter Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method is for internal use only. For more information about logging, see Tracing Driver Operation.

Syntax
public void setLogWriter(java.io.PrintWriter out)

Parameters
out
A PrintWriter object.

Remarks
This setLogWriter method is specified by the setLogWriter method in the javax.sql.DataSource interface.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setMultiSubnetFailover Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the multiSubnetFailover connection property.

Syntax
public void setMultiSubnetFailover(boolean multiSubnetFailover);

Parameters
multiSubnetFailover
The new value of the multiSubnetFailover connection property.

Remarks
For more information about the multiSubnetFailover connection property, see Setting the Connection
Properties.

See Also
SQLServerDataSource.getMultiSubnetFailover
SQLServerDataSource Members
SQLServerDataSource Class
setPacketSize Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the current network packet size used to communicate with SQL Server, specified in bytes.

Syntax
public void setPacketSize(int packetSize)

Parameters
packetSize
An int value containing the network packet size.

Remarks
The acceptable range of values of this property is [-1 | 0 | 512..32767]. If this property is set to a value outside
the acceptable range, an exception will occur.
The application might want to set the packetSize property while connecting with Transport Layer Security (TLS),
previously known as Secure Sockets Layer (SSL), encryption. The Microsoft JDBC Driver for SQL Server
negotiates the packet size with the server. If the encrypt property is set to "true " and the negotiated packet size
is larger than the Java Virtual Machine (JVM)'s default security provider's TLS record size, the driver will raise an
error and terminate the connection.
In addition, the application might want to set the packetSize property without requesting the TLS encryption. In
this case, if the server requires the client to support TLS encryption, the driver checks the JVM's default security
provider's TLS record size. If the packetSize property is larger than the JVM's default security provider's TLS
record size, the driver will raise an error and terminate the connection.
For more information about using TLS, see Using encryption.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setPassword Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the password that will be used to connect to SQL Server.

Syntax
public void setPassword(java.lang.String password)

Parameters
password
A String that contains the password.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setPortNumber Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the port number to be used to communicate with SQL Server.

Syntax
public void setPortNumber(int portNumber)

Parameters
portNumber
An int value that contains the port number.

Remarks
The port number is the TCP/IP port number that is used when opening a socket connection to SQL Server. If the
portNumber property is not set, the getPortNumber method returns the default value of 1433.

NOTE
The setPortNumber method does not do any range checking on the port value passed in. You can pass a port number
that is not valid, like 99999, without triggering an error.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setResponseBuffering Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the response buffering mode for connections created by using this SQLServerDataSource object.

Syntax
public void setResponseBuffering(java.lang.String value)

Parameters
value
A String that contains the buffering and streaming mode. The valid mode can be one of the following case-
insensitive Strings: full or adaptive .

Remarks
The full value specifies reading the entire result from the server at run time.
The adaptive value specifies buffering the minimum possible data when necessary. The adaptive value is the
default buffering mode.
For more information about using the response buffering mode, see Using Adaptive Buffering.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setSelectMethod Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the default cursor type that is used for all result sets that are created by using this SQLServerDataSource
object.

Syntax
public void setSelectMethod(java.lang.String selectMethod)

Parameters
selectMethod
A String value that contains the default cursor type.

Remarks
The selectMethod is the default cursor type that is used for a result set. This property is useful when you are
dealing with large result sets and do not want to store the whole result set in memory on the client side. By
setting the property to "cursor," you can create a server-side cursor that can fetch smaller chunks of data at a
time. If the selectMethod property is not set, getSelectMethod returns the default value of "direct".

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setSendStringParametersAsUnicode Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets a boolean value that indicates if sending string parameters to the server in UNICODE format is enabled.

Syntax
public void setSendStringParametersAsUnicode(boolean sendStringParametersAsUnicode)

Parameters
sendStringParametersAsUnicode
true if string parameters are sent to the server in UNICODE format. Otherwise, false .

Remarks
If the sendStringParametersAsUnicode property is set to true , which is the default value, string parameters are
sent to the server in UNICODE format. If sendStringParametersAsUnicode is set to false string parameters are
sent to the server in an ASCII/MBCS format, not in UNICODE. If sendStringParametersAsUnicode is not set,
getSendStringParametersAsUnicode returns the default value of true .
For more information about the sendStringParametersAsUnicode connection property, see Setting the
Connection Properties.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setSendTimeAsDatetime Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in SQL Server JDBC Driver 3.0.
Modifies the setting of the sendTimeAsDatetime connection property.

Syntax
public void setSendTimeAsDatetime(boolean sendTimeAsDateTime)

Parameters
sendTimeAsDateTime
A Boolean value. When true, causes java.sql.Time values to be sent to the server as SQL Server datetime types.
When false, causes java.sql.Time values to be sent to the server as SQL Server time types.

Remarks
SQLServerDataSource.getSendTimeAsDatetime returns the setting of the sendTimeAsDatetime connection
property.
For more information on the sendTimeAsDatetime connection property, see Setting the Connection
Properties.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setServerName Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the name of the computer that is running SQL Server.

Syntax
public void setServerName(java.lang.String serverName)

Parameters
serverName
A String that contains the server name.

Remarks
The server name is the host name of the target computer that is running SQL Server. If the serverName
property is not set, getServerName returns the default value of null.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setServerPreparedStatementDiscardThreshold
Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of serverPreparedStatementDiscardThreshold connection property. This setting controls how
many outstanding prepared statement discard actions (sp_unprepare) can be outstanding per connection before
a call to clean up the outstanding handles on the server is executed. When the setting is <= 1 unprepare actions
are executed immediately on prepared statement close. If the value is set to > 1 these calls are batched together
to avoid overhead of calling sp_unprepare too often

Syntax
public void setServerPreparedStatementDiscardThreshold(int enablePrepareOnFirstPreparedStatementCall);

Parameters
serverPreparedStatementDiscardThreshold
The new value of the ser verPreparedStatementDiscardThreshold connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setStatementPoolingCacheSize Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the size of the prepared statement cache for this connection. Works if disableStatementPooling is set to
false and value > 0.

Syntax
public void setStatementPoolingCacheSize(boolean statementPoolingCacheSize);

Parameters
statementPoolingCacheSize
The new value of the statementPoolingCacheSize connection property.

Exceptions
SQLServerException

Remarks
This method is available from JDBC driver version 6.4 and onward.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setTrustManagerClass Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the String value of the TrustManagerClass connection property.

Syntax
public void setTrustManagerClass(java.lang.String trustManagerClass)

Parameters
trustManagerClass
A String that contains the fully qualified class name of a custom javax.net.ssl.TrustManager.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setTrustManagerConstructorArg Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the String value of the TrustManagerConstructorArg connection property.

Syntax
public void setTrustManagerConstructorArg(java.lang.String trustManagerClass)

Parameters
trustManagerClass
A String that contains the fully qualified class name of a custom javax.net.ssl.TrustManager.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setTrustServerCertificate Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets a Boolean value that indicates if the trustServerCertificate property is enabled.

Syntax
public void setTrustServerCertificate(boolean trustServerCertificate)

Parameters
trustServerCertificate
true if the server Transport Layer Security (TLS), previously known as Secure Sockets Layer (SSL), certificate
should be automatically trusted when the communication layer is encrypted using TLS. Otherwise, false .

Remarks
If the trustServerCertificate property is set to true , the SQL Server TLS/SSL certificate is automatically trusted
when the communication layer is encrypted using TLS. In other words, the Microsoft JDBC Driver for SQL Server
will not validate the SQL Server TLS/SSL certificate. The default value is false .
If the trustServerCertificate property is set to false , the Microsoft JDBC Driver for SQL Server will validate the
server TLS/SSL certificate.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setTrustStore Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the path (including file name) to the certificate trustStore file.

Syntax
public void setTrustStore(java.lang.String trustStore)

Parameters
trustStore
A String that contains the path (including file name) to the certificate trustStore file.

Remarks
If the trustStore property is unspecified or set to null, the Microsoft JDBC Driver for SQL Server will rely on the
trust manager factory's look up rules to determine which certificate store to use. The default SunX509
TrustManagerFactory tries to find the trust material in the following locations in this order:
1. A file specified by the "javax.net.ssl.trustStore" Java Virtual Machine (JVM) system property.
2. "<java-home>/lib/security/jssecacerts" file.
3. "<java-home>/lib/security/cacerts" file.
For more information, see the SunX509 TrustManager Interface documentation on the Sun Microsystems Web
site.
If the trustStore property is set to a string or an empty string "", the driver will use that value to find the
trustStore file to validate the server TLS/SSL certificate.
The trustStorePassword property can be specified along with the trustStore property and its value is used to
open the trustStore file. For more information, see setTrustStorePassword.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setTrustStorePassword Method
(SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the password that is used to check the integrity of the trustStore data.

Syntax
public void setTrustStorePassword(java.lang.String trustStorePassword)

Parameters
trustStorePassword
A String that contains the password that is used to check the integrity of the trustStore data.

Remarks
The trustStorePassword property can be specified along with the trustStore property and its value is used to
check the integrity of the trustStore file.
If the trustStore property is set but the trustStorePassword property is not set, the integrity of the trustStore is
not checked.
When both trustStore and trustStorePassword properties are unspecified, the driver will use the Java Virtual
Machine (JVM) system properties, "javax.net.ssl.trustStore" and "javax.net.ssl.trustStorePassword". If the
"javax.net.ssl.trustStorePassword" system property is not specified, the integrity of the trustStore is not checked.
If the trustStore property is not set but the trustStorePassword property is set, the JDBC driver will use the file
specified by the "javax.net.ssl.trustStore" as a trust store and the integrity of the trust store is checked by using
the specified trustStorePassword. This might be needed when the client application does not want to store the
password in the JVM system property.
For more information, see Setting the Connection Properties.
Beginning in JDBC Driver 3.0, if you set SQLServerDataSource.setTrustStorePassword before binding the data
source properties, you must call SQLServerDataSource.setTrustStorePassword before getting the connection.
For more information, see SQLServerDataSource.getReference.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setURL Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the URL that is used to connect to the data source.

Syntax
public void setURL(java.lang.String url)

Parameters
url
A String that contains the URL.

Remarks
For security reasons, you should not include the password in the URL supplied to the setURL method. The
reason for this is that third-party Java Application Servers will very often display the value set for the URL
property in their data source configuration user interface. Instead, use the setPassword method to set the
password value. Java Application Servers will not display a password that is set in their data source in the
configuration user interface.

NOTE
If the setURL method is not called before calling the getURL method, getURL returns the default value of
"jdbc:sqlserver://".

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setUser Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the user name that is used to connect the data source.

Syntax
public void setUser(java.lang.String user)

Parameters
user
A String that contains the user name.

Remarks
The setUser method sets the user name that will be used to connect to SQL Server. If user name value is not set,
the getUser method returns the default value of null.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setWorkstationID Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the name of the client computer name that is used to connect to the data source.

Syntax
public void setWorkstationID(java.lang.String workstationID)

Parameters
workstationID
A String that contains the client computer name.

Remarks
The workstationID is the name of the client computer or workstation. If the workstationID property is not set, the
default value is constructed by calling InetAddress.getLocalHost().getHostName() method. If getHostName
returns a blank value, the getHostAddress().toString() method is called.

See Also
SQLServerDataSource Members
SQLServerDataSource Class
setXopenStates Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets a Boolean value that indicates if converting SQL states to XOPEN compliant states is enabled.

Syntax
public void setXopenStates(boolean xopenStates)

Parameters
xopenStates
true if converting SQL states to XOPEN compliant states is enabled. Otherwise, false .

Remarks
If the xopenStates property is set to true , the Microsoft JDBC Driver for SQL Server will convert SQL states to
XOPEN compliant states. The default is false , which causes the JDBC driver to generate SQL 99 state codes. If
xopenStates is not set, the getXopenStates method returns the default value of false .

See Also
SQLServerDataSource Members
SQLServerDataSource Class
unwrap Method (SQLServerDataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an object that implements the specified interface to allow access to the Microsoft JDBC Driver for SQL
Server-specific methods.

Syntax
public <T> T unwrap(Class<T> iface)

Parameters
iface
A class of type T defining an interface.

Return Value
An object that implements the specified interface.

Exceptions
SQLServerException

Remarks
The unwrap method is defined by the java.sql.Wrapper interface, which is introduced in the JDBC 4.0 Spec.
Applications might need to access extensions to the JDBC API that are specific to the Microsoft JDBC Driver for
SQL Server. The unwrap method supports unwrapping to public classes that this object extends if the classes
expose vendor extensions.
When this method is called, the object unwraps to the SQLServerDataSource class.
For more information, see Wrappers and Interfaces.

See Also
isWrapperFor Method (SQLServerDataSource)
SQLServerDataSource Members
SQLServerDataSource Class
SQLServerDataSourceObjectFactory Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents an object factory to materialize data sources from the Java Naming and Directory Interface (JNDI).
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: javax.naming.spi.ObjectFactory

Syntax
public class SQLServerDataSourceObjectFactory

Remarks
This method is inherited by all the data source classes. As part of its support for the Referenceable interface,
Microsoft JDBC Driver for SQL Server exposes this class that implements an ObjectFactory. Java Application
Servers will call getReference on a data source class, and this will create a Reference object that internally uses
the class name as its class factory.
When the Java Application Server has to dereference the Reference object, it creates an instance of the
SQLServerDataSourceObjectFactory object and calls the getObjectInstance method, passing in the Reference
object, to retrieve the data source instance.

See Also
SQLServerDataSourceObjectFactory Members
JDBC Driver API Reference
SQLServerDataSourceObjectFactory Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members exposed by the SQLServerDataSourceObjectFactory class.

Constructors
NAME DESC RIP T IO N

SQLServerDataSourceObjectFactory () Initializes a new instance of the


SQLServerDataSourceObjectFactory class.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

getObjectInstance Retrieves an instance of the specified data source object.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

See Also
SQLServerDataSourceObjectFactory Class
SQLServerDataSourceObjectFactory Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerDataSourceObjectFactory, see
SQLServerDataSourceObjectFactory Members.
SQLServerDataSourceObjectFactory Constructor ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerDataSourceObjectFactory class.

Syntax
public SQLServerDataSourceObjectFactory()

See Also
SQLServerDataSourceObjectFactory Constructors
SQLServerDataSourceObjectFactory Members
SQLServerDataSourceObjectFactory Class
SQLServerDataSourceObjectFactory Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerDataSourceObjectFactory, see
SQLServerDataSourceObjectFactory Members.
getObjectInstance Method
(SQLServerDataSourceObjectFactory)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves an instance of the specified data source object.

Syntax
public java.lang.Object getObjectInstance(java.lang.Object ref,
javax.naming.Name name,
javax.naming.Context c,
java.util.Hashtable h)

Parameters
ref
An Object value.
name
The name of the object.
c
The context relative to the specified name.
h
The environment that is used in creating the object.

Return Value
An Object value.

Exceptions
java.sql.SQLException

Remarks
This getObjectInstance method is specified by the getObjectInstance method in the
javax.naming.spi.ObjectFactory interface.

See Also
SQLServerDataSourceObjectFactory Methods
SQLServerDataSourceObjectFactory Members
SQLServerDataSourceObjectFactory Class
SQLServerDriver Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents the Microsoft JDBC Driver for SQL Server. This class includes methods for connecting to a SQL
Server database, and for obtaining information about the JDBC driver.
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: java.sql.Driver

Syntax
public final class SQLServerDriver

See Also
SQLServerDriver Members
JDBC Driver API Reference
SQLServerDriver Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerDriver class.

Constructors
NAME DESC RIP T IO N

SQLServerDriver () Initializes a new instance of the SQLServerDriver class.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

acceptsURL Verifies that the given URL is valid.

connect Makes a connection to the database.

getMajorVersion Returns the major version number of the JDBC driver.

getMinorVersion Returns the minor version number of the JDBC driver.

getPropertyInfo Used to discover the properties needed to connect to a


database.

jdbcCompliant Verifies if the JDBC driver is compliant with the JDBC


specification.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

See Also
SQLServerDriver Class
SQLServerDriver Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information on members of SQLServerDriver, see SQLServerDriver Members.
SQLServerDriver Constructor ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerDriver class.

Syntax
public SQLServerDriver()

See Also
SQLServerDriver Constructors
SQLServerDriver Members
SQLServerDriver Class
SQLServerDriver Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information on members of SQLServerDriver, see SQLServerDriver Members.
acceptsURL Method (SQLServerDriver)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Checks if the given URL is valid.

Syntax
public boolean acceptsURL(java.lang.String url)

Parameters
url
A String value containing the URL used to connect to the database.

Return Value
true if the given URL is valid. Otherwise, false .

Exceptions
SQLServerException

Remarks
This acceptsURL method is specified by the acceptsURL method in the java.sql.Driver interface.

See Also
SQLServerDriver Methods
SQLServerDriver Members
SQLServerDriver Class
connect Method (SQLServerDriver)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Makes a connection to the database.

Syntax
public java.sql.Connection connect(java.lang.String Url,
java.util.Properties suppliedProperties)

Parameters
Url
A String value that contains the URL that is used to connect to the database.
suppliedProperties
A set of string value pairs used as connection arguments.

Return Value
A Connection object.

Exceptions
SQLServerException

Remarks
This connect method is specified by the connect method in the java.sql.Driver interface.

See Also
SQLServerDriver Methods
SQLServerDriver Members
SQLServerDriver Class
getMajorVersion Method (SQLServerDriver)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the major version number of the Microsoft JDBC Driver for SQL Server.

Syntax
public int getMajorVersion()

Return Value
An int that contains the major version number of the JDBC driver.

Remarks
This getMajorVersion method is specified by the getMajorVersion method in the java.sql.Driver interface.

See Also
SQLServerDriver Methods
SQLServerDriver Members
SQLServerDriver Class
getMinorVersion Method (SQLServerDriver)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the minor version number of the Microsoft JDBC Driver for SQL Server.

Syntax
public int getMinorVersion()

Return Value
An int that contains the minor version number of the JDBC driver.

Remarks
This getMinorVersion method is specified by the getMinorVersion method in the java.sql.Driver interface.

See Also
SQLServerDriver Methods
SQLServerDriver Members
SQLServerDriver Class
getPropertyInfo Method (SQLServerDriver)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to discover the properties needed to connect to a database.

Syntax
public java.sql.DriverPropertyInfo[] getPropertyInfo(java.lang.String Url,
java.util.Properties Info)

Parameters
Url
A String value that contains the URL that is used to connect to the database.
Info
A list of property value pairs, null on first use.

Return Value
An array of DriverPropertyInfo objects.

Exceptions
SQLServerException

Remarks
This getPropertyInfo method is specified by the getPropertyInfo method in the java.sql.Driver interface.

See Also
SQLServerDriver Methods
SQLServerDriver Members
SQLServerDriver Class
jdbcCompliant Method (SQLServerDriver)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Verifies that the Microsoft JDBC Driver for SQL Server is compliant with the JDBC specification.

Syntax
public boolean jdbcCompliant()

Return Value
true if the JDBC driver meets the minimum requirements. Otherwise, false .

Remarks
This jdbcCompliant method is specified by the jdbcCompliant method in the java.sql.Driver interface.

See Also
SQLServerDriver Methods
SQLServerDriver Members
SQLServerDriver Class
SQLServerException Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents an unsuccessful or incomplete running of an SQL statement.
Package: com.microsoft.sqlserver.jdbc
Extends: java.sql.SQLException
Implements: java.io.Serializable

Syntax
public final class SQLServerException

Remarks
The SQLServerException class handles both SQL 92 and XOPEN state codes. They are switchable by using a
user-specified connection property. Exceptions are written to any open log files that have been specified.

See Also
SQLServerException Members
JDBC Driver API Reference
SQLServerException Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members exposed by the SQLServerException class.

Constructors
NAME DESC RIP T IO N

SQLServerException Initializes a new instance of the SQLServerException class.

Fields
None.

Inherited Fields
None.

Methods
None.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.sql.SQLException getErrorCode, getNextException, getSQLState, iterator,


setNextException

java.lang.Throwable fillInStackTrace, getCause, getLocalizedMessage, getMessage,


getStackTrace, initCause, printStackTrace, printStackTrace,
printStackTrace, setStackTrace, toString

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


wait

See Also
SQLServerException Class
SQLServerException Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerException class.
For information about the members of SQLServerException, see SQLServerException Members.
SQLServerException Constructor ( java.lang.Object,
java.lang.String, java.lang.String, int, boolean)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerException class when given an object , a string object, a string
object, an int , and a boolean .

Syntax
public SQLServerException(java.lang.Object obj,
java.lang.String errText,
java.lang.String errState,
int errNum,
boolean bStack)

Parameters
obj
The IO buffer that generated the exception.
errText
A string containing the error text.
sqlState
An enum object that contains the SQL state.
errNum
An int that contain the error code for the exception.
bStack
A boolean that indicates if the stack trace should be generated.

See Also
SQLServerException Constructors
SQLServerException Members
SQLServerException Class
SQLServerException Constructor ( java.lang.Object,
java.lang.String, java.lang.String, StreamError,
boolean)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerException class when given an object , a string object, a string
object, a StreamError object, and a boolean .

Syntax
public SQLServerException(java.lang.Object obj,
java.lang.String errText,
java.lang.String errState,
StreamError streamError,
boolean bStack)

Parameters
obj
The IO buffer that generated the exception.
errText
A string containing the error text.
sqlState
An enum object that contains the SQL state.
streamError
A StreamError object that contains details about the error.
bStack
A boolean that indicates if the stack trace should be generated.

See Also
SQLServerException Constructors
SQLServerException Members
SQLServerException Class
SQLServerException Constructor ( java.lang.String,
SQLState, DriverError, java.lang.Throwable)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerException class when given a string object, a sqlstate object, a
drivererror object, and a throwable object.

Syntax
public SQLServerException(java.lang.String errText,
SQLState sqlState,
DriverError driverError,
java.lang.Throwable cause)

Parameters
errText
A string that holds the error text.
sqlState
An enum object that holds the SQL state.
driverError
An enum object that holds the driver error.
cause
A throwable object that holds the cause of the exception.

See Also
SQLServerException Constructors
SQLServerException Members
SQLServerException Class
SQLServerException Constructor ( java.lang.String,
java.lang.String, int, java.lang.Throwable)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerException class when given a string object, a string object, an int ,
and a throwable object.

Syntax
public SQLServerException(java.lang.String errText,
SQLState errState,
int errNum,
java.lang.Throwable cause)

Parameters
errText
A string containing the error text.
errState
A string containing the state of the error.
errNum
An int that contains the error code for the exception.
cause
A throwable object that contains the cause of the exception.

See Also
SQLServerException Constructors
SQLServerException Members
SQLServerException Class
SQLServerException Constructor ( java.lang.String,
java.lang.Throwable)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerException class when given a string object, and a throwable object.

Syntax
public SQLServerException(java.lang.String errText,
java.lang.Throwable cause)

Parameters
errText
A string containing the error text.
cause
A throwable object that contains the cause of the exception.

See Also
SQLServerException Constructors
SQLServerException Members
SQLServerException Class
SQLServerException Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerException, see SQLServerException Members.
SQLServerNClob Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a character large object (CLOB) using the National Character Set.
Package: com.microsoft.sqlserver.jdbc
Extends: SQLServerClob
Implements: java.sql.NClob

Syntax
public class SQLServerNClob

See Also
SQLServerNClob Members
JDBC Driver API Reference
SQLServerNClob Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members exposed by the SQLServerNClob class.

Constructors
None.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

free This method frees the NCLOB object and releases the
resources that it holds.

getAsciiStream Retrieves the NCLOB value designated by the


java.sql.NClob object as an ASCII stream.

getCharacterStream Retrieves the NCLOB value designated by the


java.sql.NClob object.

getSubString Retrieves a copy of the specified substring in the NCLOB


value designated by the java.sql.NClob object.

length Retrieves the number of characters in the NCLOB value


designated by the java.sql.NClob object.

position Retrieves the character position of the specified


java.sql.NClob object or substring in the java.sql.NClob
based on the specified starting position.

setAsciiStream Retrieves a stream to be used to write ASCII characters to


the NCLOB value that this java.sql.NClob object
represents, starting at the specified position.

setCharacterStream Retrieves a stream to be used to write a stream of Unicode


characters to the NCLOB value that this java.sql.NClob
object represents, starting at the specified position.
NAME DESC RIP T IO N

setString Writes the specified String to the NCLOB starting at the


specified position.

truncate Truncates the NCLOB value to the specified length.

Inherited Methods
C L A SS IN H ERIT ED F RO M M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

java.sql.Clob free, getAsciiStream, getCharacterStream, getSubString,


length, position, setAsciiStream, setCharacterStream,
setString, truncate

See Also
SQLServerClob Class
SQLServerNClob Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information on the members of SQLServerNClob, see SQLServerNClob Members.
free Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method frees the NCLOB object and releases the resources that it holds.

Syntax
public void free()

Exceptions
SQLServerException

Remarks
This free method is specified by the free method in the java.sql.NClob interface.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
getAsciiStream Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the NCLOB value designated by this NClob object as an ASCII stream.

Syntax
public java.sql.InputStream getAsciiStream()

Return Value
An InputStream object that contains the NCLOB data.

Exceptions
SQLServerException

Remarks
This getAsciiStream method is specified by the getAsciiStream method in the java.sql.SQLServerNClob interface.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
getCharacterStream Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the NCLOB value designated by this java.sql.NClob object as a java.io.Reader object.

Overload List
NAME DESC RIP T IO N

getCharacterStream Method () (SQLServerNClob) Retrieves the NCLOB data as a Reader object or as a


stream of characters.

getCharacterStream Method (long, long) (SQLServerNClob) Retrieves the NCLOB data as a Reader object or as a
stream of characters with the specified position and length.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
getCharacterStream Method (long, long)
(SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the NCLOB data as a Reader object or as a stream of characters with a specified position and length.

Syntax
public java.io.Reader getCharacterStream(long pos,
long length)

Parameters
pos
A long that indicates the offset to the first character of the partial value to be retrieved.
length
A long that indicates the length in characters of the partial value to be retrieved.

Return Value
A Reader object that contains the NCLOB data.

Exceptions
SQLServerException

Remarks
This getCharacterStream method is specified by the getCharacterStream method in the java.sql.NClob interface.

See Also
getCharacterStream Method (SQLServerNClob)
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
getSubString Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a copy of the specified substring in the NCLOB based on the specified starting position and the
number of characters to copy.

Syntax
public java.lang.String getSubString(long pos,
int length)

Parameters
pos
The first character of the substring to be extracted. The first character is at position 1.
length
The number of consecutive characters to be copied.

Return Value
A String that is the specified substring in the NCLOB .

Exceptions
SQLServerException

Remarks
This getSubString method is specified by the getSubString method in the java.sql.NClob interface.
Trying to get zero characters from a null or zero-length NCLOB returns an empty string. Trying to get any length
of characters at any position other than position 1 in a zero-length NCLOB will cause a position exception to be
thrown.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
length Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the number of characters in the NClob .

Syntax
public long length()

Return Value
The length of the NClob in number of characters.

Exceptions
SQLServerException

Remarks
This length method is specified by the length method in the java.sql.NClob interface.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
position Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the character position of the specified NClob object or substring in the NClob based on the specified
starting position.

Overload List
NAME DESC RIP T IO N

position Method (java.sql.NClob, long) Retrieves the character position at which the specified
NClob object searchstr appears in this NClob object.

position Method (java.lang.String, long) (SQLServerNClob) Retrieves the character position at which the specified
substring searchstr appears in the NCLOB value
represented by this NClob object.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
position Method ( java.sql.NClob, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the character position at which the specified NClob object searchstr appears in this NClob object.

Syntax
long position(java.sql.NClob searchstr,
long start)

Parameters
searchstr
A NClob object for which to search.
start
The position at which to begin searching; the first position is 1.

Return Value
The position at which the substring appears, or -1 if it is not present. The first position is 1.

Exceptions
SQLServerException

Remarks
This position method is specified by the position method in the java.sql.NClob interface.

See Also
position Method (SQLServerNClob)
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
position Method ( java.lang.String, long)
(SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the character position at which the specified substring searchstr appears in the NCLOB value
represented by this NClob object.

Syntax
public long position(java.lang.String searchstr,
long start)

Parameters
searchstr
The substring for which to search.
start
The position at which to begin searching; the first position is 1.

Return Value
The position at which the substring appears, or -1 if it is not present. The first position is 1.

Exceptions
SQLServerException

Remarks
This position method is specified by the position method in the java.sql.NClob interface.

See Also
position Method (SQLServerNClob)
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
setAsciiStream Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a stream to be used to write ASCII characters to the NCLOB value that this java.sql.NClob object
represents, starting at the specified position.

Syntax
public java.io.OutputStream setAsciiStream(long pos)

Parameters
pos
The position at which to start writing to the NCLOB object; the first position is 1.

Return Value
An OutputStream object that represents the stream to which ASCII encoded characters can be written.

Exceptions
SQLServerException

Remarks
This setAsciiStream method is specified by the setAsciiStream method in the java.sql.NClob interface.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
setCharacterStream Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a stream to be used to write a stream of Unicode characters to the NCLOB value that this
java.sql.NClob object represents, starting at the specified position.

Syntax
public java.io.Writer setCharacterStream(long pos)

Parameters
pos
The position at which to start writing to the NCLOB value; the first position is 1.

Return Value
A Writer object that represents the stream to which Unicode encoded characters can be written.

Exceptions
SQLServerException

Remarks
This setCharacterStream method is specified by the setCharacterStream method in the java.sql.NClob interface.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
setString Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Writes the specified String to the NCLOB starting at the specified position.

Overload List
NAME DESC RIP T IO N

setString Method (long, java.lang.String) (SQLServerNClob) Writes the specified String to the NCLOB starting at the
specified position.

setString Method (long, java.lang.String, int, int) Writes the specified string to the NCLOB starting at the
(SQLServerNClob) specified position, and based on the specified offset and
length.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
setString Method (long, java.lang.String)
(SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Writes the specified String to the NCLOB starting at the specified position.

Syntax
public int setString(long pos,
java.lang.String str)

Parameters
pos
The position at which to start writing to the NCLOB ; the first position is 1.
str
The String to be written to the NCLOB .

Return Value
The number of characters written.

Exceptions
SQLServerException

Remarks
This setString method is specified by the setString method in the java.sql.NClob interface.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
setString Method (long, java.lang.String, int, int)
(SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Writes the specified string to the NCLOB starting at the specified position, based on the specified offset and
length.

Syntax
int setString(long pos,
java.lang.String str,
int offset,
int len)

Parameters
pos
The position at which to start writing to the NCLOB ; the first position is 1.
str
The String to be written to the NCLOB .
offset
The offset into str to start reading the characters to be written.
len
The number of characters to be written.

Exceptions
SQLServerException

Remarks
This setString method is specified by the setString method in the java.sql.NClob interface.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
truncate Method (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Truncates the NCLOB to the specified length.

Syntax
public void truncate(long len)

Parameters
len
The length, in characters, to which the NCLOB value should be truncated.

Exceptions
SQLServerException

Remarks
This truncate method is specified by the truncate method in the java.sql.NClob interface.

See Also
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
SQLServerParameterMetaData Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents the metadata for prepared statement parameters.
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: java.sql.ParameterMetaData

Syntax
public class SQLServerParameterMetaData

Remarks
To retrieve parameter metadata, prepared statements are run with SET FMT ONLY. Callable statements call
sp_sproc_columns to retrieve names and metadata for the procedure parameters.

See Also
SQLServerParameterMetaData Members
JDBC Driver API Reference
SQLServerParameterMetaData Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerParameterMetaData class.

Constructors
None.

Fields
None.

Inherited Fields
NAME DESC RIP T IO N

java.sql.ParameterMetaData parameterModeIn, parameterModeInOut,


parameterModeOut, parameterModeUnknown,
parameterNoNulls, parameterNullable,
parameterNullableUnknown

Methods
NAME DESC RIP T IO N

getParameterClassName Retrieves the fully-qualified name of the Java class whose


instances should be passed to the setObject method of the
SQLServerPreparedStatement class.

getParameterCount Retrieves the number of parameters in the


SQLServerPreparedStatement object for which this
SQLServerParameterMetaData object contains information.

getParameterMode Retrieves the mode of the designated parameter.

getParameterType Retrieves the SQL type of the designated parameter.

getParameterTypeName Retrieves the database-specific type name of the designated


parameter.

getPrecision Retrieves the number of decimal digits for the designated


parameter.

getScale Retrieves the number of digits to the right of the decimal


point for the designated parameter.
NAME DESC RIP T IO N

isNullable Retrieves whether null values are allowed in the designated


parameter.

isSigned Retrieves whether values for the designated parameter can


be signed numbers.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

java.sql.Wrapper isWrapperFor, unwrap

See Also
SQLServerParameterMetaData Class
SQLServerParameterMetaData Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information on the members of SQLServerParameterMetaData, see SQLServerParameterMetaData
Members.
getParameterClassName Method
(SQLServerParameterMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the fully-qualified name of the Java class whose instances should be passed to the setObject method
of the SQLServerPreparedStatement class.

Syntax
public java.lang.String getParameterClassName(int param)

Parameters
param
An int that indicates parameter index.

Return Value
A String that contains the fully-qualified class name.

Exceptions
SQLServerException

Remarks
This getParameterClassName method is specified by the getParameterClassName method in the
java.sql.ParameterMetaData interface.

See Also
SQLServerParameterMetaData Methods
SQLServerParameterMetaData Members
SQLServerParameterMetaData Class
getParameterCount Method
(SQLServerParameterMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the number of parameters in the SQLServerPreparedStatement object for which this
SQLServerParameterMetaData object contains information.

Syntax
public int getParameterCount()

Return Value
An int that indicates the number of parameters.

Exceptions
SQLServerException

Remarks
This getParameterCount method is specified by the getParameterCount method in the
java.sql.ParameterMetaData interface.

See Also
SQLServerParameterMetaData Methods
SQLServerParameterMetaData Members
SQLServerParameterMetaData Class
getParameterMode Method
(SQLServerParameterMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the mode of the designated parameter.

Syntax
public int getParameterMode(int param)

Parameters
param
An int that indicates parameter index.

Return Value
An int that indicates the mode of the designated parameter, which can be one of the following values:
ParameterMetaData.parameterModeIn
ParameterMetaData.parameterModeInOut
ParameterMetaData.parameterModeOut
ParameterMetaData.parameterModeUnknown

Exceptions
SQLServerException

Remarks
This getParameterMode method is specified by the getParameterMode method in the
java.sql.ParameterMetaData interface.

See Also
SQLServerParameterMetaData Methods
SQLServerParameterMetaData Members
SQLServerParameterMetaData Class
getParameterType Method
(SQLServerParameterMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the SQL type of the designated parameter.

Syntax
public int getParameterType(int param)

Parameters
param
An int that indicates parameter index.

Return Value
An int that indicates the JDBC type code as defined in java.sql.Types.

Exceptions
SQLServerException

Remarks
This getParameterType method is specified by the getParameterType method in the java.sql.ParameterMetaData
interface.

See Also
SQLServerParameterMetaData Methods
SQLServerParameterMetaData Members
SQLServerParameterMetaData Class
getParameterTypeName Method
(SQLServerParameterMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the database-specific type name of the designated parameter.

Syntax
public java.lang.String getParameterTypeName(int param)

Parameters
param
An int that indicates parameter index.

Return Value
A String that contains type name.

Exceptions
SQLServerException

Remarks
This getParameterTypeName method is specified by the getParameterTypeName method in the
java.sql.ParameterMetaData interface.

See Also
SQLServerParameterMetaData Methods
SQLServerParameterMetaData Members
SQLServerParameterMetaData Class
getPrecision Method
(SQLServerParameterMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the number of decimal digits of the designated parameter.

Syntax
public int getPrecision(int param)

Parameters
param
An int that indicates parameter index.

Return Value
An int that indicates the precision of the designated parameter.

Exceptions
SQLServerException

Remarks
This getPrecision method is specified by the getPrecision method in the java.sql.ParameterMetaData interface.
For number types, this method gets the number of decimal digits. For character types, it gets the maximum
length in characters. For binary types, it gets the maximum length in bytes. Where the number of digits is
unknown, this method returns "0".

See Also
SQLServerParameterMetaData Methods
SQLServerParameterMetaData Members
SQLServerParameterMetaData Class
getScale Method (SQLServerParameterMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the number of digits to the right of the decimal point for the designated parameter.

Syntax
public int getScale(int param)

Parameters
param
An int that indicates parameter index.

Return Value
In int that indicates the scale of the designated parameter.

Exceptions
SQLServerException

Remarks
This getScale method is specified by the getScale method in the java.sql.ParameterMetaData interface.
This method gets column digits to the right of the decimal point. For types that do not have a decimal point, this
method returns "0".

See Also
SQLServerParameterMetaData Methods
SQLServerParameterMetaData Members
SQLServerParameterMetaData Class
isNullable Method (SQLServerParameterMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether null values are allowed in the designated parameter.

Syntax
public int isNullable(int param)

Parameters
param
An int that indicates parameter index.

Return Value
An int that indicates the nullability of the designated parameter, which can be one of the following values:
ParameterMetaData.parameterNoNulls
ParameterMetaData.parameterNullable
ParameterMetaData.parameterNullabilityUnknown

Exceptions
SQLServerException

Remarks
This isNullable method is specified by the isNullable method in the java.sql.ParameterMetaData interface.

See Also
SQLServerParameterMetaData Methods
SQLServerParameterMetaData Members
SQLServerParameterMetaData Class
isSigned Method (SQLServerParameterMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether values for the designated parameter can be signed numbers.

Syntax
public boolean isSigned(int param)

Parameters
param
An int that indicates parameter index.

Return Value
true if the designated parameter can contain signed numbers. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isSigned method is specified by the isSigned method in the java.sql.ParameterMetaData interface.

See Also
SQLServerParameterMetaData Methods
SQLServerParameterMetaData Members
SQLServerParameterMetaData Class
SQLServerPooledConnection Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a physical database connection in a connection pool.
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: javax.sql.PooledConnection

Syntax
public final class SQLServerPoolingDataSource

Remarks
The SQLServerPooledConnection class provides methods for the connection pool manager to manage the
connection pool. Applications typically do not instantiate these connections directly.

See Also
SQLServerPooledConnection Members
JDBC Driver API Reference
SQLServerPooledConnection Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerPooledConnection class.

Constructors
None.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

addConnectionEventListener Registers the given event listener so that it will be notified


when an event occurs on this SQLServerPooledConnection
object.

close Closes the physical connection that this


SQLServerPooledConnection object represents.

getConnection Creates an object handle for the physical connection that


this SQLServerPooledConnection object represents.

removeConnectionEventListener Removes the given event listener.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

See Also
SQLServerPooledConnection Class
SQLServerPooledConnection Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerPooledConnection, see SQLServerPooledConnection
Members.
addConnectionEventListener Method
(SQLServerPooledConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Registers the given event listener so that it will be notified when an event occurs on this
SQLServerPooledConnection object.

Syntax
public void addConnectionEventListener(javax.sql.ConnectionEventListener listener)

Parameters
listener
A ConnectionEventListener object.

Remarks
This addConnectionEventListener method is specified by the addConnectionEventListener method in the
javax.sql.PooledConnection interface.

See Also
SQLServerPooledConnection Methods
SQLServerPooledConnection Members
SQLServerPooledConnection Class
close Method (SQLServerPooledConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Closes the physical connection that this SQLServerPooledConnection object represents.

Syntax
public void close()

Exceptions
java.sql.SQLException

Remarks
This close method is specified by the close method in the javax.sql.PooledConnection interface.

See Also
SQLServerPooledConnection Methods
SQLServerPooledConnection Members
SQLServerPooledConnection Class
getConnection Method
(SQLServerPooledConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Creates an object handle for the physical connection that this SQLServerPooledConnection object represents.

Syntax
public java.sql.Connection getConnection()

Return Value
A Connection object.

Exceptions
java.sql.SQLException

Remarks
This getConnection method is specified by the getConnection method in the javax.sql.PooledConnection
interface.

See Also
SQLServerPooledConnection Methods
SQLServerPooledConnection Members
SQLServerPooledConnection Class
removeConnectionEventListener Method
(SQLServerPooledConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Removes the given event listener.

Syntax
public void removeConnectionEventListener(javax.sql.ConnectionEventListener listener)

Parameters
listener
A ConnectionEventListener object.

Remarks
This removeConnectionEventListener method is specified by the removeConnectionEventListener method in the
javax.sql.PooledConnection interface.

See Also
SQLServerPooledConnection Methods
SQLServerPooledConnection Members
SQLServerPooledConnection Class
SQLServerPreparedStatement Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents the basic implementation of JDBC prepared statement functionality.
Package: com.microsoft.sqlserver.jdbc
Extends: SQLServerStatement
Implements: ISQLServerPreparedStatement

Syntax
public class SQLServerPreparedStatement

Remarks
SQLServerPreparedStatement provides methods that let you supply parameters as any native Java type and
many Java object types. SQLServerPreparedStatement prepares a statement by using the SQL Server
sp_prepare stored procedure, and then reuses the returned statement handle for each subsequent running of
the statement, typically using different parameters provided by the user.
SQLServerPreparedStatement supports batching, where a set of prepared statements are run in a single
database round trip, to improve runtime performance.
This class supports unwrapping to SQLServerPreparedStatement class, ISQLServerPreparedStatement interface,
java.sql.PreparedStatement interface, and the classes and interfaces supported by SQLServerStatement for
unwrapping. For more information, see Wrappers and Interfaces.

See Also
SQLServerPreparedStatement Members
JDBC Driver API Reference
SQLServerPreparedStatement Members
4/27/2022 • 5 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerPreparedStatement class.

Constructors
None.

Fields
None.

Inherited Fields
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.sql.Statement CLOSE_ALL_RESULTS, CLOSE_CURRENT_RESULT,


EXECUTE_FAILED, KEEP_CURRENT_RESULT,
NO_GENERATED_KEYS, RETURN_GENERATED_KEYS,
SUCCESS_NO_INFO

Methods
NAME DESC RIP T IO N

addBatch Adds a set of parameters to the batch of commands for this


Statement object.

cancel (Inherited from SQLServerStatement.) Cancels the SQL


statement that is currently being run by this Statement
object.

clearBatch Empties the current list of SQL commands for this


SQLServerStatement object.

clearParameters Clears the current parameter values immediately.

clearWarnings (Inherited from SQLServerStatement.) Clears all the warnings


that are reported on this Statement object.

close Releases the database and JDBC resources of this Statement


object immediately instead of waiting for them to be
automatically released.

execute Runs the SQL statement in this Statement object, which can
be any kind of SQL statement.
NAME DESC RIP T IO N

executeBatch Submits a batch of commands to the database to be run. If


all commands run successfully, returns an array of update
counts.

executeQuery Runs the SQL query in this Statement object and returns the
SQLServerResultSet object that is generated by the query.

executeUpdate Runs the SQL statement in this Statement object, which


must be an SQL INSERT, UPDATE, MERGE, or DELETE
statement; or an SQL statement that returns nothing, such
as a DDL statement.

getConnection (Inherited from SQLServerStatement.) Retrieves the


SQLServerConnection object that produced this Statement
object.

getFetchDirection (Inherited from SQLServerStatement.) Retrieves the direction


for fetching rows from database tables that is the default for
result sets generated from this Statement object.

getFetchSize (Inherited from SQLServerStatement.) Retrieves the number


of result set rows that is the default fetch size for result set
objects generated from this Statement object.

getGeneratedKeys (Inherited from SQLServerStatement.) Retrieves any auto-


generated keys that are created as a result of running this
Statement object.

getMaxFieldSize (Inherited from SQLServerStatement.) Retrieves the


maximum number of bytes that can be returned for
character and binary column values in a SQLServerResultSet
object produced by this Statement object.

getMaxRows (Inherited from SQLServerStatement.) Retrieves the


maximum number of rows that a SQLServerResultSet object
produced by this Statement object can contain.

getMetaData Retrieves a SQLServerResultSetMetaData Class object that


contains information about the columns of the
SQLServerResultSet object that will be returned when this
Statement object is executed.

getMoreResults (Inherited from SQLServerStatement.) Moves to the next


result of this Statement object.

getParameterMetaData Retrieves the number, types, and properties of the


parameters for this Statement object.

getResponseBuffering (Inherited from SQLServerStatement.) Retrieves the response


buffering mode for this SQLServerStatement object.

getQueryTimeout (Inherited from SQLServerStatement.) Retrieves the number


of seconds the Microsoft JDBC Driver for SQL Server will
wait for this Statement object to run.
NAME DESC RIP T IO N

getResultSet (Inherited from SQLServerStatement.) Retrieves the current


result as a SQLServerResultSet object.

getResultSetConcurrency (Inherited from SQLServerStatement.) Retrieves the result set


concurrency for SQLServerResultSet objects that are
generated by this Statement object.

getResultSetHoldability (Inherited from SQLServerStatement.) Retrieves the result set


holdability for SQLServerResultSet objects that are generated
by this Statement object.

getResultSetType (Inherited from SQLServerStatement.) Retrieves the result set


type for SQLServerResultSet objects that are generated by
this Statement object.

getUpdateCount (Inherited from SQLServerStatement,) Retrieves the current


result as an update count.

getWarnings (Inherited from SQLServerStatement.) Retrieves the first


warning that is reported by calls on this Statement object.

isClosed (Inherited from SQLServerStatement.) Indicates whether this


Statement object has been closed.

isPoolable (Inherited from SQLServerStatement.) Returns a value


indicating if a statement can be added to the user-provided
statement pool.

isWrapperFor Indicates whether this statement object is a wrapper for the


specified interface.

setArray Sets the designated parameter number to the given Array


object.

setAsciiStream Sets the designated parameter number to the given


InputStream object.

setBigDecimal Sets the designated parameter number to the given


BigDecimal object.

setBinaryStream Sets the designated parameter to the specified input stream.

setBlob Sets the designated parameter to the specified Blob object.

setboolean Sets the designated parameter to the specified Boolean


value.

setByte Sets the designated parameter to the specified byte value.

setBytes Sets the designated parameter to the specified array of


bytes.

setCharacterStream Sets the designated parameter to the specified Reader


object.
NAME DESC RIP T IO N

setClob Sets the designated parameter to the given Clob object.

setCursorName (Inherited from SQLServerStatement.) Sets the SQL cursor


name to the specified String, which will be used by
subsequent execute methods.

setDate Sets the designated parameter to the specified date value.

setDateTimeOffset Sets the value of the column specified to the DateTimeOffset


Class value.

setDouble Sets the designated parameter to the specified double


value.

setEscapeProcessing (Inherited from SQLServerStatement.) Sets the escape


processing mode.

setFetchDirection (Inherited from SQLServerStatement.) Gives the JDBC driver


a hint as to the direction in which result set rows should be
processed.

setFetchSize (Inherited from SQLServerStatement.) Gives the JDBC driver


a hint as to the number of rows that should be fetched from
the database when more rows are needed.

setFloat Sets the designated parameter to the specified float value.

setInt Sets the designated parameter to the specified int value.

setLong Sets the designated parameter to the specified long value.

setMaxFieldSize (Inherited from SQLServerStatement.) Sets the limit for the


maximum number of bytes in a SQLServerResultSet column
storing character or binary values to the given number of
bytes.

setMaxRows (Inherited from SQLServerStatement.) Sets the limit for the


maximum number of rows that any SQLServerResultSet
object can contain to the given number.

setNCharacterStream Sets the designated parameter to the specified Reader


object.

setNClob Sets the designated parameter to the specified object.

setNull Sets the designated parameter to a null value, given the type
of parameter to set.

setNString Sets the designated parameter to the specified String


object.

setObject Sets the value of the designated parameter using the given
object.
NAME DESC RIP T IO N

setPoolable (Inherited from SQLServerStatement.) Requests that a


statement be pooled or not pooled. By default, a
SQLServerPreparedStatement object is poolable when
created.

setQueryTimeout (Inherited from SQLServerStatement.) Sets the number of


seconds the driver will wait for a Statement object to run to
the specified number of seconds.

setRef Sets the designated parameter to the specified Ref object.

setResponseBuffering (Inherited from SQLServerStatement.) Sets the response


buffering mode for this SQLServerStatement object to case-
insensitive String full or adaptive .

setShort Sets the designated parameter to the specified shor t value.

setString Sets the designated parameter to the specified String value.

setSQLXML Sets the designated parameter to the specified SQLXML


object.

setTime Sets the designated parameter to the specified time value.

setTimestamp Sets the designated parameter to the specified timestamp


value.

setUnicodeStream Sets the designated parameter number to the specified input


stream, which will have the specified number of bytes.

setURL Sets the designated parameter to the specified URL value.

unwrap Returns an object that implements the specified interface to


allow access to the Microsoft JDBC Driver for SQL Server-
specific methods.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

com.microsoft.sqlserver.jdbc.SQLServerStatement cancel, clearWarnings, execute, executeUpdate,


getConnection, getFetchDirection, getFetchSize,
getGeneratedKeys, getMaxFieldSize, getMaxRows,
getMoreResults, getQueryTimeout, getResultSet,
getResultSetConcurrency, getResultSetHoldability,
getResultSetType, getUpdateCount, getWarnings, isPoolable,
setCursorName, setEscapeProcessing, setFetchDirection,
setFetchSize, setMaxFieldSize, setMaxRows, setPoolable,
setQueryTimeout

java.lang.Object clone, equals, getClass, hashCode, notify, notifyAll, toString,


wait
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.sql.Statement cancel, clearWarnings, execute, executeUpdate,


getConnection, getFetchDirection, getFetchSize,
getGeneratedKeys, getMaxFieldSize, getMaxRows,
getMoreResults, getQueryTimeout, getResultSet,
getResultSetConcurrency, getResultSetHoldability,
getResultSetType, getUpdateCount, getWarnings,
setCursorName, setEscapeProcessing, setFetchDirection,
setFetchSize, setMaxFieldSize, setMaxRows, setQueryTimeout

java.sql.Wrapper isWrapperFor, unwrap

See Also
SQLServerPreparedStatement Class
SQLServerPreparedStatement Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerPreparedStatement, see SQLServerPreparedStatement
Members.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
addBatch Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Adds a set of parameters to the batch of commands for this SQLServerPreparedStatement object.

Overload List
NAME DESC RIP T IO N

addBatch () Adds a set of parameters to the batch of commands to this


SQLServerPreparedStatement object.

addBatch (java.lang.String) Adds the given SQL command to the current list of
commands for this SQLServerPreparedStatement object.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
addBatch Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Adds a set of parameters to the batch of commands for this SQLServerPreparedStatement object.

Syntax
public final void addBatch()

Exceptions
SQLServerException

Remarks
This addBatch method is specified by the addBatch method in the java.sql.PreparedStatement interface.

See Also
addBatch Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
addBatch Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Adds the given SQL command to the current list of commands for this SQLServerPreparedStatement object.

Syntax
public void addBatch(java.lang.String sql)

Parameters
sql
A String that contains an SQL statement.

Exceptions
SQLServerException

Remarks
This addBatch method is specified by the addBatch method in the java.sql.Statement interface.
Calling this method will result in an exception since the SQL statement for the SQLServerPreparedStatement
object is specified when the object is created.

See Also
addBatch Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
clearBatch Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Empties the current list of SQL commands for this SQLServerStatement object.

Syntax
public final void clearBatch()

Exceptions
SQLServerException

Remarks
This clearBatch method is specified by the clearBatch method in the java.sql.Statement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
clearParameters Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Clears the current parameter values immediately.

Syntax
public final void clearParameters()

Exceptions
SQLServerException

Remarks
This clearParameters method is specified by the clearParameters method in the java.sql.PreparedStatement
interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
close Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Releases the database and JDBC resources of this Statement object immediately instead of waiting for them to
be automatically released.

Syntax
public void close()

Exceptions
SQLServerException

Remarks
This close method is specified by the close method in the java.sql.Statement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
execute Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the SQL statement in this SQLServerPreparedStatement object, which can be any kind of SQL statement.

Overload List
NAME DESC RIP T IO N

execute () Runs the SQL statement in this


SQLServerPreparedStatement object, which can be any kind
of SQL statement.

execute (java.lang.String) Runs the given SQL statement, which can return multiple
results.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
execute Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the SQL statement in this SQLServerPreparedStatement object, which can be any kind of SQL statement.

Syntax
public boolean execute()

Return Value
true if the statement returns a result set. false if it returns an update count or no result.

Exceptions
SQLServerException

Remarks
This execute method is specified by the execute method in the java.sql.PreparedStatement interface.

See Also
execute Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
execute Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement, which can return multiple results.

Syntax
public final boolean execute(java.lang.String sql)

Parameters
sql
A String that contains an SQL statement.

Return Value
true if the statement returns a result set. false if it returns an update count or no result.

Exceptions
SQLServerException

Remarks
This execute method is specified by the execute method in the java.sql.Statement interface.
This method overrides the execute method that is found in the SQLServerStatement class.
Calling this method will result in an exception since the SQL statement for the SQLServerPreparedStatement
object is specified when the object is created.

See Also
execute Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
executeBatch Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Submits a batch of commands to the database to be run. If all commands run successfully, returns an array of
update counts.

Syntax
public int[] executeBatch()

Return Value
An array of ints that contains the update counts.

Exceptions
SQLServerException
java.sql.BatchUpdateException

Remarks
This executeBatch method is specified by the executeBatch method in the java.sql.Statement interface.
This method overrides SQLServerStatement.executeBatch.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
executeQuery Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the SQL query in this SQLServerPreparedStatement object and returns the SQLServerResultSet object
generated by the query.

Overload List
NAME DESC RIP T IO N

executeQuery () Runs the SQL query in this SQLServerPreparedStatement


object and returns the SQLServerResultSet object that is
generated by the query.

executeQuery (java.lang.String) Runs the given SQL statement and returns a single
SQLServerResultSet object.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
executeQuery Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the SQL query in this SQLServerPreparedStatement object and returns the SQLServerResultSet object that
is generated by the query.

Syntax
public java.sql.ResultSet executeQuery()

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This executeQuery method is specified by the executeQuery method in the java.sql.PreparedStatement interface.

See Also
executeQuery Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
executeQuery Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement and returns a single SQLServerResultSet object.

Syntax
public final java.sql.ResultSet executeQuery(java.lang.String sql)

Parameters
sql
A String that contains an SQL statement.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This executeQuery method is specified by the executeQuery method in the java.sql.Statement interface.
This method overrides the executeQuery method that is found in the SQLServerStatement class.
Calling this method will result in an exception since the SQL statement for the SQLServerPreparedStatement
object is specified when the object is created.
SQLServerException is thrown if the given SQL statement produces anything other than a single
SQLServerResultSet object.

See Also
executeQuery Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
executeUpdate Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the SQL statement in this SQLServerPreparedStatement object, which must be an SQL INSERT, UPDATE,
MERGE, or DELETE statement; or an SQL statement that returns nothing, such as a DDL statement.

Overload List
NAME DESC RIP T IO N

executeUpdate () Runs the SQL statement in this


SQLServerPreparedStatement object, which must be an SQL
INSERT, UPDATE, MERGE, or DELETE statement; or an SQL
statement that returns nothing, such as a DDL statement.

executeUpdate (java.lang.String) Runs the given SQL statement, which can be an INSERT,
UPDATE, MERGE, or DELETE statement; or an SQL statement
that returns nothing, such as an SQL DDL statement.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
executeUpdate Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the SQL statement in this SQLServerPreparedStatement object, which must be an SQL INSERT, UPDATE,
MERGE, or DELETE statement; or an SQL statement that returns nothing, such as a DDL statement.

Syntax
public int executeUpdate()

Return Value
An int that indicates the number of rows affected, or 0 if using a DDL statement.

Exceptions
SQLServerException

Remarks
This executeUpdate method is specified by the executeUpdate method in the java.sql.PreparedStatement
interface.

See Also
executeUpdate Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
executeUpdate Method ( java.lang.String, int[])
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement and signals Microsoft JDBC Driver for SQL Server that the auto-generated keys
that are indicated in the given array should be made available for retrieval.

Syntax
public final int executeUpdate(java.lang.String sql,
int[] columnIndexes)

Parameters
sql
A String that contains an SQL statement.
columnIndexes
An array of ints that indicate the column indexes of the auto-generated keys that should be made available.

Return Value
An int that indicates the number of rows affected, or 0 if using a DDL statement.

Exceptions
SQLServerException

Remarks
This executeUpdate method is specified by the executeUpdate method in the java.sql.Statement interface.
If executing a stored procedure results in an update count that is greater than one, or that generates more than
one result set, use the execute method to execute the stored procedure.

See Also
executeUpdate Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
executeUpdate Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Runs the given SQL statement, which can be an INSERT, UPDATE, MERGE, or DELETE statement; or an SQL
statement that returns nothing, such as an SQL DDL statement.

Syntax
public final int executeUpdate(java.lang.String sql)

Parameters
sql
A String that contains the SQL statement.

Return Value
An int that indicates the number of rows affected, or 0 if using a DDL statement.

Exceptions
SQLServerException

Remarks
This executeUpdate method is specified by the executeUpdate method in the java.sql.PreparedStatement
interface.
Calling this method will result in an exception since the SQL statement for the SQLServerPreparedStatement
object is specified when the object is created.

See Also
executeUpdate Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
getMetaData Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a SQLServerResultSetMetaData Class object that contains information about the columns of the
SQLServerResultSet object that will be returned when this SQLServerPreparedStatement object is run.

Syntax
public final java.sql.ResultSetMetaData getMetaData()

Return Value
A ResultSetMetaData object.

Exceptions
SQLServerException

Remarks
This getMetaData method is specified by the getMetaData method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
getParameterMetaData Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the number, types, and properties of the parameters of this SQLServerPreparedStatement object.

Syntax
public final java.sql.ParameterMetaData getParameterMetaData()

Return Value
A SQLServerParameterMetaData object.

Exceptions
SQLServerException

Remarks
This getParameterMetaData method is specified by the getParameterMetaData method in the
java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
isWrapperFor Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this statement object is a wrapper for the specified interface.

Syntax
public boolean isWrapperFor(Class iface)

Parameters
iface
A class defining an interface.

Return Value
true if this object implements the interface or wraps an object that implements the interface. Otherwise, false .

Exceptions
SQLServerException

Remarks
The isWrapperFor method and the unwrap method are defined by the java.sql.Wrapper interface, which is
introduced in the JDBC 4.0 Spec.
If this method returns true, calling unwrap with the same argument will succeed.
For more information, see Wrappers and Interfaces.

See Also
unwrap Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setArray Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter number to the given Array object.

Syntax
public final void setArray(int i,
java.sql.Array x)

Parameters
i
An int that indicates the parameter number.
x
An Array object.

Exceptions
SQLServerException

Remarks
This setArray method is specified by the setArray method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setAsciiStream Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter number to the specified java.io.InputStream object.

Overload List
NAME DESC RIP T IO N

setAsciiStream Method (int, java.io.InputStream) Sets the designated parameter number to the specified
java.io.InputStream object.

setAsciiStream Method (int, java.io.InputStream, int) Sets the designated parameter number to the specified
java.io.InputStream object with the specified number of
bytes.

setAsciiStream Method (int, java.io.InputStream, long) Sets the designated parameter number to the specified
java.io.InputStream object with the specified number of
bytes.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setAsciiStream Method (int, java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter number to the given java.io.InputStream object.

Syntax
public final void setAsciiStream(int parameterIndex,
java.io.InputStream x)

Parameters
parameterIndex
An int that indicates the parameter number.
x
A java.io.InputStream object.

Exceptions
SQLServerException

Remarks
This setAsciiStream method is specified by the setAsciiStream method in the java.sql.PreparedStatement
interface.

See Also
setAsciiStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setAsciiStream Method (int, java.io.InputStream, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter number to the given InputStream object with the given number of bytes.

Syntax
public final void setAsciiStream(int n,
java.io.InputStream x,
int length)

Parameters
n
An int that indicates the parameter number.
x
An InputStream object.
length
The number of bytes.

Exceptions
SQLServerException

Remarks
This setAsciiStream method is specified by the setAsciiStream method in the java.sql.PreparedStatement
interface.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setAsciiStream Method (int, java.io.InputStream) when the application wants to update the column from a
stream whose length is unknown.

See Also
setAsciiStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setAsciiStream Method (int, java.io.InputStream,
long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter number to the specified java.io.InputStream object with the specified number of
bytes.

Syntax
public final void setAsciiStream(int parameterIndex,
java.io.InputStream x,
long length)

Parameters
parameterIndex
An int that indicates the parameter number.
x
A java.io.InputStream object.
length
A long that indicates the number of bytes.

Exceptions
SQLServerException

Remarks
This setAsciiStream method is specified by the setAsciiStream method in the java.sql.PreparedStatement
interface.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setAsciiStream Method (int, java.io.InputStream) when the application wants to update the column from a
stream whose length is unknown.

See Also
setAsciiStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setBigDecimal Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter number to the given BigDecimal object.

Syntax
public final void setBigDecimal(int n,
java.math.BigDecimal x)

Parameters
n
An int that indicates the parameter number.
x
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This setBigDecimal method is specified by the setBigDecimal method in the java.sql.PreparedStatement
interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setBinaryStream Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified input stream.

Overload List
NAME DESC RIP T IO N

setBinaryStream Method (int, java.io.InputStream) Sets the designated parameter to the specified input stream.

setBinaryStream Method (int, java.io.InputStream, int) Sets the designated parameter to the specified input stream,
which will have the specified number of bytes.

setBinaryStream Method (int, java.io.InputStream, long) Sets the designated parameter to the specified input stream,
which will have the specified number of bytes.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setBinaryStream Method (int, java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified input stream.

Syntax
public final void setAsciiStream(int parameterIndex,
java.io.InputStream x)

Parameters
parameterIndex
An int that indicates the parameter number.
x
A java.io.InputStream object.

Exceptions
SQLServerException

Remarks
This setBinaryStream method is specified by the setBinaryStream method in the java.sql.PreparedStatement
interface.

See Also
setBinaryStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setBinaryStream Method (int, java.io.InputStream,
int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified input stream, which will have the specified number of bytes.

Syntax
public final void setBinaryStream(int n,
java.io.InputStream x,
int length)

Parameters
n
An int that indicates the parameter number.
x
An InputStream object.
length
An int that indicates the number of bytes.

Exceptions
SQLServerException

Remarks
This setBinaryStream method is specified by the setBinaryStream method in the java.sql.PreparedStatement
interface.
If the length of the stream is different from what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setBinaryStream Method (int, java.io.InputStream) when the application wants to update the column from a
stream whose length is unknown.

See Also
setBinaryStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setBinaryStream Method (int, java.io.InputStream,
long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified input stream, which will have the specified number of bytes.

Syntax
public final void setBinaryStream(int parameterIndex,
java.io.InputStream x,
long length)

Parameters
parameterIndex
An int that indicates the parameter number.
x
A java.io.InputStream object.
length
A long that indicates the number of bytes.

Exceptions
SQLServerException

Remarks
This setBinaryStream method is specified by the setBinaryStream method in the java.sql.PreparedStatement
interface.
If the length of the stream is different from what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setBinaryStream Method (int, java.io.InputStream) when the application wants to update the column from a
stream whose length is unknown.

See Also
setBinaryStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setBlob Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given Blob object.

Syntax
public final void setBlob(int i,
java.sql.Blob x)

Parameters
i
An int that indicates the parameter number.
x
A Blob object.

Exceptions
SQLServerException

Remarks
This setBlob method is specified by the setBlob method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setBoolean Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given boolean value.

Syntax
public final void setBoolean(int n,
boolean x)

Parameters
n
An int that indicates the parameter number.
x
A boolean value, either true or false .

Exceptions
SQLServerException

Remarks
This setboolean method is specified by the setboolean method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setByte Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given byte value.

Syntax
public final void setByte(int n,
byte x)

Parameters
n
An int that indicates the parameter number.
x
A byte value.

Exceptions
SQLServerException

Remarks
This setByte method is specified by the setByte method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setBytes Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given array of bytes.

Syntax
public final void setBytes(int n,
byte[] x)

Parameters
n
An int that indicates the parameter number.
x
An array of bytes.

Exceptions
SQLServerException

Remarks
This setBytes method is specified by the setBytes method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setCharacterStream Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given java.io.Reader object.

Overload List
NAME DESC RIP T IO N

setCharacterStream Method (int, java.io.Reader) Sets the designated parameter to the specified java.io.Reader
object.

setCharacterStream Method (int, java.io.Reader, int) Sets the designated parameter to the specified java.io.Reader
object, which is the specified number of characters long.

setCharacterStream Method (int, java.io.Reader, long) Sets the designated parameter to the specified java.io.Reader
object, which is the specified number of characters long.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setCharacterStream Method (int, java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified java.io.Reader object.

NOTE
This feature is introduced starting with the MicrosoftSQL Server JDBC Driver version 2.0.

Syntax
public final void setCharacterStream(int parameterIndex,
java.io.Reader reader)

Parameters
parameterIndex
An int that indicates the parameter number.
reader
The java.io.Reader object that contains the Unicode data.

Exceptions
SQLServerException

Remarks
This setCharacterStream method is specified by the setCharacterStream method in the
java.sql.PreparedStatement interface.

See Also
setCharacterStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setCharacterStream Method (int, java.io.Reader, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given Reader object, which is the given number of characters long.

Syntax
public final void setCharacterStream(int n,
java.io.Reader reader,
int length)

Parameters
n
An int that indicates the parameter number.
reader
A Reader object.
length
The number of characters.

Exceptions
SQLServerException

Remarks
This setCharacterStream method is specified by the setCharacterStream method in the
java.sql.PreparedStatement interface.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setCharacterStream Method (int, java.io.Reader) when the application wants to update the column from a stream
whose length is unknown.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setCharacterStream Method (int, java.io.Reader,
long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the java.io.Reader object, which is the specified number of characters long.

Syntax
public final void setCharacterStream(int parameterIndex,
java.io.Reader reader,
long length)

Parameters
parameterIndex
An int that indicates the parameter number.
reader
The java.io.Reader object that contains the Unicode data.
length
A long that indicates the number of characters in the stream.

Exceptions
SQLServerException

Remarks
This setCharacterStream method is specified by the setCharacterStream method in the
java.sql.PreparedStatement interface.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setCharacterStream Method (int, java.io.Reader) when the application wants to update the column from a stream
whose length is unknown.

See Also
setCharacterStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setClob Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to a java.sql.Clob object.

Overload List
NAME DESC RIP T IO N

setClob Method (int, java.io.Reader) Sets the designated parameter to a java.sql.Clob object.

setClob Method (int, java.sql.Clob) Sets the designated parameter to the given java.sql.Clob
object.

setClob Method (int, java.io.Reader, long) Sets the designated parameter to a java.sql.Clob object,
which is the specified number of characters long.

Remarks
No server driver behavior. For details see JSE 6 API spec.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setClob Method (int, java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object.

Syntax
public final void setClob(int parameterIndex,
java.io.Reader reader)

Parameters
parameterIndex
An int that indicates the parameter index.
reader
A Reader object.

Exceptions
SQLServerException

Remarks
This setClob method is specified by the setClob method in the java.sql.PreparedStatement interface.

See Also
setClob Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setClob Method (int, java.sql.Clob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given Clob object.

Syntax
public final void setClob(int parameterIndex,
java.sql.Clob clobValue)

Parameters
parameterIndex
An int that indicates the parameter number.
clobValue
A Clob object.

Exceptions
SQLServerException

Remarks
This setClob method is specified by the setClob method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Methods
SQLServerPreparedStatement Class
setClob Method (int, java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object, which is the given number of characters long.

Syntax
public final void setClob(int parameterIndex,
java.io.Reader reader,
long length)

Parameters
parameterIndex
An int that indicates the parameter index.
reader
A Reader object.
length
A long that indicates the number of characters in the parameter value.

Remarks
This setClob method is specified by the setClob method in the java.sql.PreparedStatement interface.

Exceptions
SQLServerException

See Also
setClob Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setDate Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given date value.

Overload List
NAME DESC RIP T IO N

setDate (int, java.sql.Date) Sets the designated parameter to the given date value.

setDate (int, java.sql.Date, java.util.Calendar) Sets the designated parameter to the given date and
calendar values.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setDate Method (int, java.sql.Date)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given date value.

Syntax
public final void setDate(int n,
java.sql.Date x)

Parameters
n
An int that indicates the parameter number.
x
A Date object.

Exceptions
SQLServerException

Remarks
This setDate method is specified by the setDate method in the java.sql.PreparedStatement interface.

See Also
setDate Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setDate Method (int, java.sql.Date,
java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given date and calendar values.

Syntax
public final void setDate(int n,
java.sql.Date x,
java.util.Calendar cal)

Parameters
n
An int that indicates the parameter number.
x
A Date object.
cal
A Calendar object.

Exceptions
SQLServerException

Remarks
This setDate method is specified by the setDate method in the java.sql.PreparedStatement interface.

See Also
setDate Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setDouble Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given double value.

Syntax
public final void setDouble(int n,
double x)

Parameters
n
An int that indicates the parameter number.
x
A double value.

Exceptions
SQLServerException

Remarks
This setDouble method is specified by the setDouble method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setDateTimeOffset Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in MicrosoftSQL Server JDBC Driver 3.0.
Sets the value of the column specified to the DateTimeOffset Class value.

Syntax
public final void setDateTimeOffset(int n, microsoft.sql.DateTimeOffset x)

Parameters
n
The zero-based ordinal of a column.
x
The DateTimeOffset Class object.

Exceptions
SQLServerException

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setFloat Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given float value.

Syntax
public final void setFloat(int n,
float x)

Parameters
n
An int that indicates the parameter number.
x
A float value.

Exceptions
SQLServerException

Remarks
This setFloat method is specified by the setFloat method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setInt Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given int value.

Syntax
public final void setInt(int n,
int value)

Parameters
n
An int that indicates the parameter number.
value
An int value.

Exceptions
SQLServerException

Remarks
This setInt method is specified by the setInt method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setLong Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given long value.

Syntax
public final void setLong(int n,
long x)

Parameters
n
An int that indicates the parameter number.
x
A long value.

Exceptions
SQLServerException

Remarks
This setLong method is specified by the setLong method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setNCharacterStream Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given java.io.Reader object.

Overload List
NAME DESC RIP T IO N

setNCharacterStream Method (int, java.io.Reader) Sets the designated parameter to the specified java.io.Reader
object.

setNCharacterStream Method (int, java.io.Reader, long) Sets the designated parameter to the specified java.io.Reader
object.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setNCharacterStream Method (int, java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object.

Syntax
public final void setNCharacterStream(int parameterIndex,
java.io.Reader value)

Parameters
parameterIndex
An int that indicates the parameter index.
value
A Reader object that contains the parameter value.

Exceptions
SQLServerException

Remarks
This setNCharacterStream method is specified by the setNCharacterStream method in the
java.sql.PreparedStatement interface.
This method should be used for NCHAR , NVARCHAR , NTEXT , and XML data types.

See Also
setNCharacterStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setNCharacterStream Method (int, java.io.Reader,
long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object.

Syntax
public final void setNCharacterStream(int parameterIndex,
java.io.Reader value,
long length)

Parameters
parameterIndex
An int that indicates the parameter index.
value
A Reader object that contains the parameter value.
length
A long that indicates the number of characters in the parameter value.

Exceptions
SQLServerException

Remarks
This setNCharacterStream method is specified by the setNCharacterStream method in the
java.sql.PreparedStatement interface.
This method should be used for NCHAR , NVARCHAR , NTEXT , and XML data types.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
setNCharacterStream Method (int, java.io.Reader) when the application wants to update the column from a
stream whose length is unknown.

See Also
setNCharacterStream Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setNClob Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified object.

Overload List
NAME DESC RIP T IO N

setNClob Method (int, java.sql.NClob) Sets the designated parameter to the specified
java.sql.NClob object.

setNClob Method (int, java.io.Reader) Sets the designated parameter to the specified java.io.Reader
object.

setNClob Method (int, java.io.Reader, long) Sets the designated parameter to the specified java.io.Reader
object, which is the specified number of characters long.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setNClob Method (int, java.sql.NClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified NClob object.

Syntax
public final void setNClob(int parameterIndex,
java.sql.NClob value)

Parameters
parameterIndex
An int that indicates the parameter index.
value
A NClob object that indicates the parameter value.

Exceptions
SQLServerException

Remarks
This setNClob method is specified by the setNClob method in the java.sql.PreparedStatement interface.

See Also
setNClob Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setNClob Method (int, java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object.

Syntax
public final void setNClob(int parameterIndex,
java.io.Reader reader)

Parameters
parameterIndex
An int that indicates the parameter index.
reader
A Reader object that indicates the parameter value.

Exceptions
SQLServerException

Remarks
This setNClob method is specified by the setNClob method in the java.sql.PreparedStatement interface.

See Also
setNClob Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setNClob Method (int, java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified Reader object, which is the specified number of characters long.

Syntax
public final void setNClob(int parameterIndex,
java.io.Reader reader,
long length)

Parameters
parameterIndex
An int that indicates the parameter index.
reader
A Reader object that indicates the parameter value.
length
An long that indicates the number of characters in the parameter value.

Exceptions
SQLServerException

Remarks
This setNClob method is specified by the setNClob method in the java.sql.PreparedStatement interface.

See Also
setNClob Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
setNString Method (int, java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified String object.

Syntax
public final void setNString(int parameterIndex,
java.lang.String value)

Parameters
parameterIndex
An int that indicates the parameter index.
value
A String object that contains the parameter value.

Exceptions
SQLServerException

Remarks
This method should be used for NCHAR , NVARCHAR , NTEXT , and XML data types.
This setNString method is specified by the setNString method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
setNull Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to a null value, given the type of parameter to set.

Overload List
NAME DESC RIP T IO N

setNull (int, int) Sets the designated parameter to a null value, given the type
of parameter to set.

setNull (int, int, java.lang.String) Sets the designated parameter to a null value, given the type
and name of the parameter to set.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setNull Method (int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to a null value, given the type of parameter to set.

Syntax
public final void setNull(int index,
int jdbcType)

Parameters
index
An int that indicates the parameter number.
jdbcType
A JDBC type code that is defined by java.sql.Types.

Exceptions
SQLServerException

Remarks
This setNull method is specified by the setNull method in the java.sql.PreparedStatement interface.

See Also
setNull Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setNull Method (int, int, java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to a null value, given the type and name of the parameter to set.

Syntax
public final void setNull(int paramIndex,
int sqlType,
java.lang.String typeName)

Parameters
paramIndex
An int that indicates the parameter number.
sqlType
A JDBC type code defined by java.sql.Types.
typeName
A String that indicates the fully qualified name of the parameter that is being set.

Exceptions
SQLServerException

Remarks
This setNull method is specified by the setNull method in the java.sql.PreparedStatement interface.

See Also
setNull Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setObject Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the designated parameter by using the given object.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

Overload List
NAME DESC RIP T IO N

setObject (int, java.lang.Object) Sets the value of the designated parameter by using the
given object.

setObject (int, java.lang.Object, int) Sets the value of the designated parameter by using the
given object and target type.

setObject (int, java.lang.Object, int, int) Sets the value of the designated parameter by using the
given object, target type, and scale.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setObject Method (int, java.lang.Object)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the designated parameter by using the given object.

Syntax
public final void setObject(int index,
java.lang.Object obj)

Parameters
index
An int that indicates the parameter number.
obj
An object.

Exceptions
SQLServerException

Remarks
This setObject method is specified by the setObject method in the java.sql.PreparedStatement interface.
Before calling this setObject method, the application might set the specified parameter by using one of the
following methods:
The set<Type> methods of the SQLServerPreparedStatement class or the SQLServerCallableStatement
class
The setNull methods of the SQLServerPreparedStatement class or the SQLServerCallableStatement class
The registerOutParameter method of the SQLServerCallableStatement class
In such a case, the type of the parameter is automatically set. If the application calls this setObject method with
an obj value NULL, the driver assumes that the type of the parameter is one that is set by the previously called
method.
If the obj value is NULL and no type information for that parameter can be determined, this setObject method
converts the specified parameter to a CHAR before sending it to the database.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.
See Also
setObject Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setObject Method (int, java.lang.Object, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the designated parameter by using the given object and target type.

Syntax
public final void setObject(int n,
java.lang.Object obj,
int targetSqlType)

Parameters
n
An int that indicates the parameter number.
obj
An object.
targetSqlType
An int that indicates the target type as defined in java.sql.Types.

Exceptions
SQLServerException

Remarks
This setObject method is specified by the setObject method in the java.sql.PreparedStatement interface.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
setObject Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setObject Method (int, java.lang.Object, int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the value of the designated parameter by using the given object, target type, and scale.

Syntax
public final void setObject(int n,
java.lang.Object obj,
int targetSqlType,
int scale)

Parameters
n
An int that indicates the parameter number.
obj
An object.
targetSqlType
An int that indicates the target type as defined in java.sql.Types.
scale
An int that indicates the number of digits to the right of the decimal point. This parameter is ignored for all
types other than NUMERIC and DECIMAL.

Exceptions
SQLServerException

Remarks
This setObject method is specified by the setObject method in the java.sql.PreparedStatement interface.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
setObject Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setRef Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given Ref object.

Syntax
public final void setRef(int i,
java.sql.Ref x)

Parameters
i
An int that indicates the parameter number.
x
A Ref object.

Exceptions
SQLServerException

Remarks
This setRef method is specified by the setRef method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setShort Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given shor t value.

Syntax
public final void setShort(int index,
short x)

Parameters
index
An int that indicates the parameter number.
x
A shor t value.

Exceptions
SQLServerException

Remarks
This setShort method is specified by the setShort method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setSQLXML Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the specified SQLXML object.

Syntax
public final void setSQLXML(int parameterIndex,
java.sql.SQLXML xmlObject)

Parameters
parameterIndex
An int that indicates the parameter index.
xmlObject
A SQLXML object that contains the parameter value.

Exceptions
SQLServerException

Remarks
This setSQLXML method is specified by the setSQLXML method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
setString Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given String value.

Syntax
public final void setString(int index,
java.lang.String str)

Parameters
index
An int that indicates the parameter number.
str
A String value.

Exceptions
SQLServerException

Remarks
This setString method is specified by the setString method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setTime Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given time value.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

Overload List
NAME DESC RIP T IO N

setTime (int, java.sql.Time) Sets the designated parameter to the given time value.

setTime (int, java.sql.Time, java.util.Calendar) Sets the designated parameter to the given time and
calendar values.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setTime Method (int, java.sql.Time)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given time value.

Syntax
public final void setTime(int n,
java.sql.Time x)

Parameters
n
An int that indicates the parameter number.
x
A Time object.

Exceptions
SQLServerException

Remarks
This setTime method is specified by the setTime method in the java.sql.PreparedStatement interface.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
setTime Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setTime Method (int, java.sql.Time,
java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given time and calendar values.

Syntax
public final void setTime(int n,
java.sql.Time x,
java.util.Calendar cal)

Parameters
n
An int that indicates the parameter number.
x
A Time object.
cal
A Calendar object.

Exceptions
SQLServerException

Remarks
This setTime method is specified by the setTime method in the java.sql.PreparedStatement interface.
Beginning with SQL Server JDBC Driver 3.0, the behavior of this method is modified by the
sendTimeAsDatetime connection property (Setting the Connection Properties) and
SQLServerDataSource.setSendTimeAsDatetime.
For more information, see Configuring How java.sql.Time Values are Sent to the Server.

See Also
setTime Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setTimestamp Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given timestamp value.

Overload List
NAME DESC RIP T IO N

setTimestamp (int, java.sql.Timestamp) Sets the designated parameter to the given timestamp
value.

setTimestamp (int, java.sql.Timestamp, java.util.Calendar) Sets the designated parameter to the given timestamp and
calendar values.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setTimestamp Method (int, java.sql.Timestamp)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given timestamp value.

Syntax
public final void setTimestamp(int n,
java.sql.Timestamp x)

Parameters
n
An int that indicates the parameter number.
x
A Timestamp object.

Exceptions
SQLServerException

Remarks
This setTimestamp method is specified by the setTimestamp method in the java.sql.PreparedStatement interface.

See Also
setTimestamp Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setTimestamp Method (int, java.sql.Timestamp,
java.util.Calendar)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given timestamp and calendar values.

Syntax
public final void setTimestamp(int n,
java.sql.Timestamp x,
java.util.Calendar cal)

Parameters
n
An int that indicates the parameter number.
x
An Timestamp object.
cal
A Calendar object.

Exceptions
SQLServerException

Remarks
This setTimestamp method is specified by the setTimestamp method in the java.sql.PreparedStatement interface.

See Also
setTimestamp Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setUnicodeStream Method
(SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter number to the given input stream, which will have the specified number of bytes.

NOTE
This method has been deprecated from the JDBC specification, and calling it will cause a "not implemented" exception to
be thrown.

Syntax
public final void setUnicodeStream(int n,
java.io.InputStream x,
int length)

Parameters
n
An int that indicates the parameter number.
x
An InputStream object.
length
The number of bytes.

Exceptions
SQLServerException

Remarks
This setUnicodeStream method is specified by the setUnicodeStream method in the java.sql.PreparedStatement
interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
setURL Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given URL value.

Syntax
public final void setURL(int parameterIndex,
java.net.URL x)

Parameters
parameterindex
An int that indicates the parameter number.
x
A URL object.

Exceptions
SQLServerException

Remarks
This setURL method is specified by the setURL method in the java.sql.PreparedStatement interface.

See Also
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
unwrap Method (SQLServerPreparedStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an object that implements the specified interface to allow access to the Microsoft JDBC Driver for SQL
Server-specific methods.

Syntax
public <T> T unwrap(Class<T> iface)

Parameters
iface
A class of type T defining an interface.

Return Value
An object that implements the specified interface.

Exceptions
SQLServerException

Remarks
The unwrap method is defined by the java.sql.Wrapper interface, which is introduced in the JDBC 4.0 Spec.
Applications might need to access extensions to the JDBC API that are specific to the Microsoft JDBC Driver for
SQL Server. The unwrap method supports unwrapping to public classes that this object extends, if the classes
expose vendor extensions.
When this method is called, the object unwraps to the following classes: SQLServerStatement and
SQLServerPreparedStatement.
For example code, see unwrap Method (SQLServerCallableStatement).
For more information, see Wrappers and Interfaces.

See Also
isWrapperFor Method (SQLServerPreparedStatement)
SQLServerPreparedStatement Members
SQLServerPreparedStatement Class
SQLServerResource Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a localized error string resource. This class is intended for internal use only.
Package: com.microsoft.sqlserver.jdbc
Extends: java.util.ListResourceBundle

Syntax
public class SQLServerResource

See Also
SQLServerResource Members
JDBC Driver API Reference
SQLServerResource Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerResource class.

Constructors
NAME DESC RIP T IO N

SQLServerResource () Initializes a new instance of the SQLServerResource class.


This constructor is for internal use only.

Fields
None.

Inherited Fields
NAME DESC RIP T IO N

java.util.ResourceBundle parent

Methods
NAME DESC RIP T IO N

getContents Retrieves error string information. This method is intended


for internal use only.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.util.ListResourceBundle getKeys, handleGetObject

java.util.ResourceBundle getBundle, getLocale, getObject, getString, getStringArray,


setParent

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

See Also
SQLServerResource Class
SQLServerResource Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerResource, see SQLServerResource Members.
SQLServerResource Constructor ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerResource class. This constructor is intended for internal use only.

Syntax
public SQLServerResource()

See Also
SQLServerResource Constructors
SQLServerResource Members
SQLServerResource Class
SQLServerResource Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerResource, see SQLServerResource Members.
getContents Method (SQLServerResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves error string information. This method is intended for internal use only.

Syntax
protected java.lang.Object[][] getContents()

Return Value
A multi-dimensional array of Object values.

See Also
SQLServerResource Methods
SQLServerResource Members
SQLServerResource Class
SQLServerResultSet Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a JDBC result set.
Package: com.microsoft.sqlserver.jdbc
Implements: ISQLServerResultSet

Syntax
public final class SQLServerResultSet

Remarks
There are two types of result sets: client-side and server-side.
Client-side result sets are used when the results can fit in the client process memory. These results provide the
fastest performance and are read by the Microsoft JDBC Driver for SQL Server in their entirety from the
database. These result sets do not impose additional load on the database by incurring the overhead of creating
server-side cursors. However, these types of result sets are not updatable.
Server-side result sets can be used when the results do not fit in the client process memory or when the result
set is to be updatable. With this type of result set, the JDBC driver creates a server-side cursor and fetches rows
of the result set transparently as the user scrolls through it.
The SQLServerResultSet class provides many methods to let you update the result set with any native Java data
type and many Java object types.
This class supports unwrapping to SQLServerResultSet class, ISQLServerResultSet interface, and
java.sql.ResultSet interface. For more information, see Wrappers and Interfaces.

See Also
SQLServerResultSet Members
JDBC Driver API Reference
SQLServerResultSet Members
4/27/2022 • 7 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerResultSet class.

Constructors
None.

Fields
NAME DESC RIP T IO N

CONCUR_SS_OPTIMISTIC_CC Used to specify a SQL Server read/write optimistic


concurrency type with no row locks.

CONCUR_SS_OPTIMISTIC_CCVAL Used to specify a SQL Server read/write optimistic


concurrency type with no row locks.

CONCUR_SS_SCROLL_LOCKS Used to specify a SQL Server read/write optimistic


concurrency type with row locks.

TYPE_SS_DIRECT_FORWARD_ONLY Used to specify a SQL Server fast forward-only, read-only


cursor type.

TYPE_SS_SCROLL_DYNAMIC Used to specify a SQL Server dynamic cursor type.

TYPE_SS_SCROLL_KEYSET Used to specify a SQL Server keyset cursor type.

TYPE_SS_SCROLL_STATIC Used to specify a SQL Server static cursor type.

TYPE_SS_SERVER_CURSOR_FORWARD_ONLY Used to specify a SQL Server fast forward-only, read-only


cursor type.

Inherited Fields
C L A SS IN H ERIT ED F RO M : DESC RIP T IO N

java.sql.ResultSet CLOSE_CURSORS_AT_COMMIT, CONCUR_READ_ONLY,


CONCUR_UPDATABLE, FETCH_FORWARD, FETCH_REVERSE,
FETCH_UNKNOWN, HOLD_CURSORS_OVER_COMMIT,
TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE,
TYPE_SCROLL_SENSITIVE

Methods
NAME DESC RIP T IO N

absolute Moves the cursor to the specified row in this


SQLServerResultSet object.

afterLast Moves the cursor to after the last row of this


SQLServerResultSet object.

beforeFirst Moves the cursor to before the first row of this


SQLServerResultSet object.

cancelRowUpdates Cancels the updates made to the current row in this


SQLServerResultSet object.

clearWarnings Clears all warnings reported on this SQLServerResultSet


object.

close Releases this SQLServerResultSet object's database and JDBC


resources immediately instead of waiting for this to happen
when it is automatically closed.

deleteRow Deletes the current row from thisSQLServerResultSet object


and from the underlying database.

finalize Explicitly closes this SQLServerResultSet object.

findColumn Retrieves the index of the first matching column for the
specified column name in this SQLServerResultSet object.

first Moves the cursor to the first row of this SQLServerResultSet


object.

getArray Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as an Array object.

getAsciiStream Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a stream of ASCII
characters.

getBigDecimal Retrieves the value of the designated column index in the


current row of this SQLServerResultSet object as a
java.math.BigDecimal.

getBinaryStream Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a binary stream of
uninterpreted bytes.

getBlob Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a Blob object in the
Java programming language.

getBoolean Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a boolean in the
Java programming language.
NAME DESC RIP T IO N

getByte Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a byte in the Java
programming language.

getBytes Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a byte array in the
Java programming language.

getCharacterStream Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a java.io.Reader
object.

getClob Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a Clob object in the
Java programming language.

getConcurrency Retrieves the concurrency mode of this SQLServerResultSet


object.

getCursorName Retrieves the name of the SQL cursor used by this


SQLServerResultSet object.

getDate Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a java.sql.Date
object in the Java programming language.

getDateTimeOffset Retrieves the value of the specified column as


aDateTimeOffset Class object.

getDouble Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a double in the
Java programming language.

getFetchDirection Retrieves the fetch direction for this SQLServerResultSet


object.

getFetchSize Retrieves the fetch size for this SQLServerResultSet object.

getFloat Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a float in the Java
programming language.

getHoldability Retrieves the holdability of this SQLServerResultSet object.

getInt Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as an int in the Java
programming language.

getLong Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a long in the Java
programming language.

getMetaData Retrieves the number, types, and properties of this


SQLServerResultSet object's columns.
NAME DESC RIP T IO N

getNCharacterStream Retrieves the value of the designated column in the current


row of the SQLServerResultSet object as a Reader object.

getNClob Retrieves the value of the designated column in the current


row of the SQLServerResultSetobject as an NClob object in
the Java programming language.

getNString Retrieves the value of the designated column in the current


row of the SQLServerResultSet object as a String in the Java
programming language.

getObject Gets the value of the designated column in the current row
of this SQLServerResultSet object as an object in the Java
programming language.

getRef Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a Ref object in the
Java programming language.

getRow Retrieves the current row number.

getShort Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a shor t in the Java
programming language.

getStatement Retrieves the SQLServerStatement object that produced this


SQLServerResultSet object.

getString Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a String in the Java
programming language.

getSQLXML Retrieves the value of the designated column in the current


row of the SQLServerResultSet object as a SQLXML object.

getTime Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a java.sql.Time
object in the Java programming language.

getTimestamp Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming
language.

getType Retrieves the cursor type of this SQLServerResultSet object.

getUnicodeStream Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a stream of
Unicode characters.

getURL Retrieves the value of the designated column in the current


row of this SQLServerResultSet object as a URL object.

getWarnings Retrieves the first warning reported by calls on this


SQLServerResultSet object.
NAME DESC RIP T IO N

insertRow Inserts the contents of the insert row into this


SQLServerResultSet object and into the database.

isAfterLast Retrieves whether the cursor is after the last row in this
SQLServerResultSet object.

isBeforeFirst Retrieves whether the cursor is before the first row in this
SQLServerResultSet object.

isClosed Indicates whether this SQLServerResultSet object has been


closed.

isFirst Retrieves whether the cursor is on the first row of this


SQLServerResultSet object.

isLast Retrieves whether the cursor is on the last row of this


SQLServerResultSet object.

last Moves the cursor to the last row in this SQLServerResultSet


object.

moveToCurrentRow Moves the cursor to the remembered cursor position,


usually the current row.

moveToInsertRow Moves the cursor to the insert row.

next Moves the cursor down one row from its current position.

previous Moves the cursor to the previous row in this


SQLServerResultSet object.

refreshRow Refreshes the current row with its most recent value in the
database.

relative Moves the cursor the given amount of rows, relative to the
current row, in either a positive or a negative direction.

rowDeleted Retrieves whether a row has been deleted.

rowInserted Retrieves whether the current row has had an insertion.

rowUpdated Retrieves whether the current row has been updated.

setFetchDirection Gives a hint as to the direction in which the rows in this


SQLServerResultSet object will be processed.

setFetchSize Gives the JDBC driver a hint as to the number of rows that
should be fetched from the database when more rows are
needed for this SQLServerResultSet object.
NAME DESC RIP T IO N

updateArray Updates the designated column with an Array object.

updateAsciiStream Updates the designated column with an ASCII stream value.

updateBigDecimal Updates the designated column with a BigDecimal object.

updateBinaryStream Updates the designated column with a binary stream value.

updateBlob Updates the designated column with a java.sql.Blob value.

updateBoolean Updates the designated column with a boolean value.

updateByte Updates the designated column with a byte value.

updateBytes Updates the designated column with an array of byte


values.

updateCharacterStream Updates the designated column with a character stream


value.

updateClob Updates the designated column with a java.sql.Clob value.

updateDate Updates the designated column with a date value.

updateDateTimeOffset Updates a DateTimeOffset Class column.

updateDouble Updates the designated column with a double value.

updateFloat Updates the designated column with a float value.

updateInt Updates the designated column with an int value.

updateLong Updates the designated column with a long value.

updateNCharacterStream Updates the designated column with a character stream


value.

updateNClob Updates the designated column with the specified object


value.

updateNString Updates the designated column with a String value.

updateNull Updates the designated column with a null value.

updateObject Updates the designated column with an Object value.

updateRef Updates the designated column with a java.sql.Ref value.

updateRow Updates the underlying database with the new contents of


the current row of this SQLServerResultSet object.
NAME DESC RIP T IO N

updateShort Updates the designated column with a shor t value.

updateString Updates the designated column with a String value.

updateSQLXML Updates the designated column with a SQLXML value.

updateTime Updates the designated column with a time value.

updateTimestamp Updates the designated column with a timestamp value.

wasNull Verifies whether the last value read was a null value.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, getClass, hashCode, notify, notifyAll, toString,


wait

java.sql.Wrapper isWrapperFor, unwrap

See Also
SQLServerResultSet Class
SQLServerResultSet Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerResultSet, see SQLServerResultSet Members.

See Also
SQLServerResultSet Class
absolute Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor to the given row in this SQLServerResultSet object.

Syntax
public boolean absolute(int row)

Parameters
row
An int that indicates the row number to move to. Can be positive, negative, or 0.

Return Value
true if the cursor is moved to the given position. false if it is before the first row or after the last row.

Exceptions
SQLServerException

Remarks
This absolute method is specified by the absolute method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
afterLast Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor to after the last row of this SQLServerResultSet object.

Syntax
public void afterLast()

Exceptions
SQLServerException

Remarks
This afterLast method is specified by the afterLast method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
beforeFirst Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor to before the first row of this SQLServerResultSet object.

Syntax
public void beforeFirst()

Exceptions
SQLServerException

Remarks
This beforeFirst method is specified by the beforeFirst method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
cancelRowUpdates Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Cancels the updates made to the current row in this SQLServerResultSet object.

Syntax
public void cancelRowUpdates()

Exceptions
SQLServerException

Remarks
This cancelRowUpdates method is specified by the cancelRowUpdates method in the java.sql.ResultSet interface.
This method can be called after calling an updater method and before calling the updateRow method to roll
back the updates that were made to a row. If no updates have been made or updateRow has already been called,
this method has no effect.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
clearWarnings Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Clears all warnings reported on this SQLServerResultSet object.

NOTE
This method is not currently implemented by the Microsoft JDBC Driver for SQL Server. If called, it will always return null.

Syntax
public void clearWarnings()

Exceptions
SQLServerException

Remarks
This clearWarnings method is specified by the clearWarnings method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
close Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Releases this SQLServerResultSet object's database and JDBC resources immediately instead of waiting for this
to happen when it is automatically closed.

Syntax
public void close()

Exceptions
SQLServerException

Remarks
This close method is specified by the close method in the java.sql.ResultSet interface.
A SQLServerResultSet object is automatically closed by the SQLServerStatement object that generated it when
that SQLServerStatement object is closed, re-run, or used to retrieve the next result from a sequence of multiple
results. A SQLServerResultSet object is also automatically closed when it is garbage collected.
When executing a statement that produces a single large forward-only, read-only result set, you might only be
interested in some initial set of rows in the returned result set. In this case, the application might call the cancel
method of the associated statement object before closing the result set in order to minimize the processing time
needed to discard the remaining unnecessary rows. We recommend considering the tradeoff between the
processing time that would be saved and the time and the additional round trip to the server needed to cancel
the execution when deciding whether to use this technique or not.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
deleteRow Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Deletes the current row from thisSQLServerResultSet object and from the underlying database.

Syntax
public void deleteRow()

Exceptions
SQLServerException

Remarks
This deleteRow method is specified by the deleteRow method in the java.sql.ResultSet interface.
This method cannot be called when the cursor is on the insert row.
When using keyset cursors, this method leaves a gap in the result set. You can test for this gap by using the
rowDeleted method. The row numbers of the rows in the result set do not change.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
finalize Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Explicitly closes this SQLServerResultSet object.

Syntax
public void finalize()

Remarks
Closes the result set if the application does not. This method exists only to conform to the JDBC specification.
Because the Java Virtual Machine (JVM) does not guarantee when a finalizer will have a chance to run,
applications that neglect to explicitly close their result sets could still deadlock on another statement that is
using the same connection and is blocked on a common server resource, such as row locks.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
findColumn Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the index of the first matching column for the given column name in this SQLServerResultSet object.

Syntax
public int findColumn(java.lang.String columnName)

Parameters
columnName
A String that contains the name of the column.

Return Value
An int that indicates the column index.

Exceptions
SQLServerException

Remarks
This findColumn method is specified by the findColumn method in the java.sql.ResultSet interface.
If there are multiple columns with the same name, the findColumn method returns the first case-sensitive
match. If there is no case-sensitive match, this method returns the first case-insensitive match.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
first Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor to the first row of this SQLServerResultSet object.

Syntax
public boolean first()

Return Value
true if the cursor is moved to the first row. Otherwise, false .

Exceptions
SQLServerException

Remarks
This first method is specified by the first method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getArray Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as an Array
object.

Overload List
NAME DESC RIP T IO N

getArray Method (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as an Array
object.

getArray Method (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as an Array
object.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getArray Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as an
Array object.

Syntax
public java.sql.Array getArray(int i)

Parameters
i
An int that indicates the column index.

Return Value
An Array object.

Exceptions
SQLServerException

Remarks
This getArray method is specified by the getArray method in the java.sql.ResultSet interface.

See Also
getArray Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getArray Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as an
Array object.

Syntax
public java.sql.Array getArray(java.lang.String colName)

Parameters
colName
A String that contains the column name.

Return Value
An Array object.

Exceptions
SQLServerException

Remarks
This getArray method is specified by the getArray method in the java.sql.ResultSet interface.

See Also
getArray Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getAsciiStream Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a stream of
ASCII characters.

Overload List
NAME DESC RIP T IO N

getAsciiStream (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a stream of
ASCII characters.

getAsciiStream (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a stream of
ASCII characters.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getAsciiStream Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
stream of ASCII characters.

Syntax
public java.io.InputStream getAsciiStream(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
An InputStream object.

Exceptions
SQLServerException

Remarks
This getAsciiStream method is specified by the getAsciiStream method in the java.sql.ResultSet interface.

See Also
getAsciiStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getAsciiStream Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
stream of ASCII characters.

Syntax
public java.io.InputStream getAsciiStream(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
An InputStream object.

Exceptions
SQLServerException

Remarks
This getAsciiStream method is specified by the getAsciiStream method in the java.sql.ResultSet interface.

See Also
getAsciiStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBigDecimal Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
java.math.BigDecimal.

Overload List
NAME DESC RIP T IO N

getBigDecimal Method (int) (SQLServerResultSet) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a
java.math.BigDecimal with full precision.

getBigDecimal Method (int, int) (SQLServerResultSet) (Deprecated) Retrieves the value of the designated column
index in the current row of this SQLServerResultSet object
using the given scale.

getBigDecimal Method (java.lang.String) Retrieves the value of the designated column name in the
(SQLServerResultSet) current row of this SQLServerResultSet object as a
java.math.BigDecimal with full precision.

getBigDecimal Method (java.lang.String, int) (Deprecated) Retrieves the value of the designated column
(SQLServerResultSet) name in the current row of this SQLServerResultSet object
using the given scale.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getBigDecimal Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
java.math.BigDecimal with full precision.

Syntax
public java.math.BigDecimal getBigDecimal(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This getBigDecimal method is specified by the getBigDecimal method in the java.sql.ResultSet interface.

See Also
getBigDecimal Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBigDecimal Method (int, int)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object using
the given scale.

NOTE
This method has been deprecated from the JDBC specification. Instead, you should use the getBigDecimal (int) method.

Syntax
public java.math.BigDecimal getBigDecimal(int columnIndex,
int scale)

Parameters
columnIndex
An int that indicates the column index.
scale
An int that indicates the number of digits to the right of the decimal point.

Return Value
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This getBigDecimal method is specified by the getBigDecimal method in the java.sql.ResultSet interface.

See Also
getBigDecimal Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBigDecimal Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
java.math.BigDecimal with full precision.

Syntax
public java.math.BigDecimal getBigDecimal(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This getBigDecimal method is specified by the getBigDecimal method in the java.sql.ResultSet interface.

See Also
getBigDecimal Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBigDecimal Method ( java.lang.String, int)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object using
the given scale.

NOTE
This method has been deprecated from the JDBC specification. Instead, you should use the getBigDecimal
(java.lang.String) method.

Syntax
public java.math.BigDecimal getBigDecimal(java.lang.String columnName,
int scale)

Parameters
columnName
A String that contains the column name.
scale
An int that indicates the number of digits to the right of the decimal point.

Return Value
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This getBigDecimal method is specified by the getBigDecimal method in the java.sql.ResultSet interface.

See Also
getBigDecimal Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBinaryStream Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a binary
stream of uninterpreted bytes.

Overload List
NAME DESC RIP T IO N

getBinaryStream (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a binary
stream of uninterpreted bytes.

getBinaryStream (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a binary
stream of uninterpreted bytes.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getBinaryStream Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
binary stream of uninterpreted bytes.

Syntax
public java.io.InputStream getBinaryStream(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
An InputStream object.

Exceptions
SQLServerException

Remarks
This getBinaryStream method is specified by the getBinaryStream method in the java.sql.ResultSet interface.
This method can be used only with SQL Server data types of binary, varbinary, varbinary(max), and image.
Trying to use it with other data types will cause an exception to be thrown.
After this method gets the value as a stream, the value can then be read in chunks from the stream. This method
is particularly suitable for retrieving large LONGVARBINARY values.

NOTE
All the data in the returned stream must be read before getting the value of any other column. The next call to a getter
method implicitly closes the stream. Also, a stream can return 0 when the method InputStream.available is called, whether
there is data available or not.

See Also
getBinaryStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBinaryStream Method (long, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an input stream object that contains a partial BLOB value by using the specified starting position and
the length.

Syntax
public java.io.InputStream getBinaryStream(long pos, long length)

Parameters
pos
The offset to the first byte of the partial value to be retrieved.
length
The length in bytes of the partial value to be retrieved.

Return Value
An input stream that contains the BLOB data.

Exceptions
SQLServerException

Remarks
This getBinaryStream method is specified by the getBinaryStream method in the java.sql.Blob interface.

See Also
SQLServerBlob Methods
SQLServerBlob Members
SQLServerBlob Class
getBinaryStream Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
binary stream of uninterpreted bytes.

Syntax
public java.io.InputStream getBinaryStream(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
An InputStream object.

Exceptions
SQLServerException

Remarks
This getBinaryStream method is specified by the getBinaryStream method in the java.sql.ResultSet interface.
This method can be used only with SQL Server data types of binary, varbinary, varbinary(max), and image.
Trying to use it with other data types will cause an exception to be thrown.
After this method gets the value as a stream, the value can then be read in chunks from the stream. This method
is particularly suitable for retrieving large LONGVARBINARY values.

NOTE
All the data in the returned stream must be read before getting the value of any other column. The next call to a getter
method implicitly closes the stream. Also, a stream can return 0 when the method InputStream.available is called, whether
there is data available or not.

See Also
getBinaryStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBlob Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a Blob
object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getBlob (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a Blob
object in the Java programming language.

getBlob (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a Blob
object in the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getBlob Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
Blob object in the Java programming language.

Syntax
public java.sql.Blob getBlob(int i)

Parameters
i
An int that indicates the column index.

Return Value
A Blob object.

Exceptions
SQLServerException

Remarks
This getBlob method is specified by the getBlob method in the java.sql.ResultSet interface.

See Also
getBlob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBlob Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
Blob object in the Java programming language.

Syntax
public java.sql.Blob getBlob(java.lang.String colName)

Parameters
colName
A String that contains the column name.

Return Value
A Blob object.

Exceptions
SQLServerException

Remarks
This getBlob method is specified by the getBlob method in the java.sql.ResultSet interface.

See Also
getBlob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBoolean Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a boolean
in the Java programming language.

Overload List
NAME DESC RIP T IO N

getBoolean (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a boolean
in the Java programming language.

getBoolean (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a boolean
in the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getBoolean Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
boolean in the Java programming language.

Syntax
public boolean getBoolean(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A boolean value.

Exceptions
SQLServerException

Remarks
This getBoolean method is specified by the getBoolean method in the java.sql.ResultSet interface.
This method is supported only on number and character data types. It converts values "1", 1, and "true " to true ,
and values "0", 0, and "false " to false . For all other values the behavior is undefined.

See Also
getBoolean Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBoolean Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
boolean in the Java programming language.

Syntax
public boolean getBoolean(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A boolean value.

Exceptions
SQLServerException

Remarks
This getBoolean method is specified by the getBoolean method in the java.sql.ResultSet interface.
This method is supported only on number and character data types. It converts values "1", 1, and "true " to true ,
and values "0", 0, and "false " to false . For all other values the behavior is undefined.

See Also
getBoolean Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getByte Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a byte in
the Java programming language.

Overload List
NAME DESC RIP T IO N

getByte (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a byte in
the Java programming language.

getByte (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a byte in
the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getByte Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
byte in the Java programming language.

Syntax
public byte getByte(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A byte value.

Exceptions
SQLServerException

Remarks
This getByte method is specified by the getByte method in the java.sql.ResultSet interface.
This method is supported only on SQL Server data types that can safely return a byte value, such as tinyint and
bit. All other data types will cause an exception to be thrown.

See Also
getByte Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getByte Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
byte in the Java programming language.

Syntax
public byte getByte(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A byte value.

Exceptions
SQLServerException

Remarks
This getByte method is specified by the getByte method in the java.sql.ResultSet interface.
This method is supported only on SQL Server data types that can safely return a byte value, such as tinyint and
bit. All other data types will cause an exception to be thrown.

See Also
getByte Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBytes Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a byte
array in the Java programming language.

Overload List
NAME DESC RIP T IO N

getBytes (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a byte
array in the Java programming language.

getBytes (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a byte
array in the Java programming language.

Remarks
In a previous version of the Microsoft JDBC Driver for SQL Server, you could use SQLServerResultSet.getBytes
to convert values between byte arrays and SQL Server data type date , time , datetime2 , or datetimeoffset .
Now, using this method with those data types will cause an exception indicating that the conversion is not
supported.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getBytes Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
byte array in the Java programming language.

Syntax
public byte[] getBytes(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
An array of byte values.

Exceptions
SQLServerException

Remarks
This getBytes method is specified by the getBytes method in the java.sql.ResultSet interface.
This method supports retrieving all columns as a raw read of bytes from the server. It returns an array of bytes
directly from the server, in the format that is stored on the server.
In a previous version of the Microsoft JDBC Driver for SQL Server, you could use SQLServerResultSet.getBytes
to convert values between byte arrays and SQL Server data type date , time , datetime2 , or datetimeoffset .
Now, using this method with those data types will cause an exception indicating that the conversion is not
supported.

See Also
getBytes Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getBytes Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
byte array in the Java programming language.

Syntax
public byte[] getBytes(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
An array of byte values.

Exceptions
SQLServerException

Remarks
This getBytes method is specified by the getBytes method in the java.sql.ResultSet interface.
This method supports retrieving all columns as a raw read of bytes from the server. It returns an array of bytes
directly from the server, in the format that is stored on the server.
In a previous version of the Microsoft JDBC Driver for SQL Server, you could use SQLServerResultSet.getBytes
to convert values between byte arrays and SQL Server data type date , time , datetime2 , or datetimeoffset .
Now, using this method with those data types will cause an exception indicating that the conversion is not
supported.

See Also
getBytes Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getCharacterStream Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a
java.io.Reader object.

Overload List
NAME DESC RIP T IO N

getCharacterStream (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a
java.io.Reader object.

getCharacterStream (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a
java.io.Reader object.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getCharacterStream Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
java.io.Reader object.

Syntax
public java.io.Reader getCharacterStream(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A Reader object.

Exceptions
SQLServerException

Remarks
This getCharacterStream method is specified by the getCharacterStream method in the java.sql.ResultSet
interface.
This method will read only SQL Server Unicode character data types such as nchar, nvarchar, nvarchar(max), and
ntext. All other data types, including the ASCII character types, will cause an exception to be thrown. To read the
ASCII data types, use the getAsciiStream method.

See Also
getCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getCharacterStream Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
java.io.Reader object.

Syntax
public java.io.Reader getCharacterStream(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A Reader object.

Exceptions
SQLServerException

Remarks
This getCharacterStream method is specified by the getCharacterStream method in the java.sql.ResultSet
interface.
This method will read only SQL Server Unicode character data types such as nchar, nvarchar, nvarchar(max), and
ntext. All other data types, including the ASCII character types, will cause an exception to be thrown. To read the
ASCII data types, use the getAsciiStream method.

See Also
getCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getCharacterStream Method () (SQLServerNClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the NCLOB data as a Reader object or as a stream of characters.

Syntax
public java.io.Reader getCharacterStream()

Exceptions
SQLServerException

Return Value
A Reader object that contains the NCLOB data.

Remarks
This getCharacterStream method is specified by the getCharacterStream method in the java.sql.NClob interface.

See Also
getCharacterStream Method (SQLServerNClob)
SQLServerNClob Methods
SQLServerNClob Members
SQLServerNClob Class
getClob Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a Clob
object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getClob (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a Clob
object in the Java programming language.

getClob (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a Clob
object in the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getClob Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
Clob object in the Java programming language.

Syntax
public java.sql.Clob getClob(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A Clob object.

Exceptions
SQLServerException

Remarks
This getClob method is specified by the getClob method in the java.sql.ResultSet interface.

See Also
getClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getClob Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
Clob object in the Java programming language.

Syntax
public java.sql.Clob getClob(java.lang.String colName)

Parameters
colName
A String that contains the column name.

Return Value
A Clob object.

Exceptions
SQLServerException

Remarks
This getClob method is specified by the getClob method in the java.sql.ResultSet interface.

See Also
getClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getConcurrency Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the concurrency mode of this SQLServerResultSet object.

Syntax
public int getConcurrency()

Return Value
An int that indicates the concurrency type, which can be one of the following values:
ResultSet.CONCUR_READ_ONLY
ResultSet.CONCUR_UPDATABLE

Exceptions
SQLServerException

Remarks
This getConcurrency method is specified by the getConcurrency method in the java.sql.ResultSet interface.
The concurrency used is determined by the SQLServerStatement object that created the result set.
This method can be used to determine the actual concurrency. If the application selected CONCUR_READ_ONLY
or CONCUR_UPDATABLE, these will be returned. If the application used default concurrency,
CONCUR_READ_ONLY will be returned.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getCursorName Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the name of the SQL cursor that is used by this SQLServerResultSet object.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server. If called, an exception will be thrown.

Syntax
public java.lang.String getCursorName()

Return Value
A String that contains the cursor name.

Exceptions
SQLServerException

Remarks
This getCursorName method is specified by the getCursorName method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getDate Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a
java.sql.Date object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getDate Method (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a
java.sql.Date object in the Java programming language.

getDate (int, java.util.Calendar) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a
java.sql.Date object in the Java programming language,
using the given Calendar object.

getDate (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a
java.sql.Date object in the Java programming language.

getDate (java.lang.String, java.util.Calendar) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a
java.sql.Date object in the Java programming language,
using the given Calendar object.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getDate Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
java.sql.Date object in the Java programming language.

Syntax
public java.sql.Date getDate(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A Date object.

Exceptions
SQLServerException

Remarks
This getDate method is specified by the getDate method in the java.sql.ResultSet interface.
This method returns a valid date part of a SQL Server datetime or smalldatetime data type, with the time part
set to the Java time baseline of 00:00 (midnight).

See Also
getDate Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getDate Method (int, java.util.Calendar)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
java.sql.Date object in the Java programming language, using the given Calendar object.

Syntax
public java.sql.Date getDate(int columnIndex,
java.util.Calendar cal)

Parameters
columnIndex
An int that indicates the column index.
cal
A Calendar object.

Return Value
A Date object.

Exceptions
SQLServerException

Remarks
This getDate method is specified by the getDate method in the java.sql.ResultSet interface.
This method returns a valid date part of a SQL Server datetime or smalldatetime data type, with the time part
set to the Java time baseline of 00:00 (midnight) in the supplied Calendar's timezone.

See Also
getDate Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getDate Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
java.sql.Date object in the Java programming language.

Syntax
public java.sql.Date getDate(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A Date object.

Exceptions
SQLServerException

Remarks
This getDate method is specified by the getDate method in the java.sql.ResultSet interface.
This method returns a valid date part of a SQL Server datetime or smalldatetime data type, with the time part
set to the Java time baseline of 00:00 (midnight).

See Also
getDate Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getDate Method ( java.lang.String,
java.util.Calendar) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
java.sql.Date object in the Java programming language, using the given Calendar object.

Syntax
public java.sql.Date getDate(java.lang.String colName,
java.util.Calendar cal)

Parameters
colName
A String that contains the column name.
cal
A Calendar object.

Return Value
A Date object.

Exceptions
SQLServerException

Remarks
This getDate method is specified by the getDate method in the java.sql.ResultSet interface.
This method returns a valid date part of a SQL Server datetime or smalldatetime data type, with the time part
set to the Java time baseline of 00:00 (midnight) in the supplied Calendar's timezone.

See Also
getDate Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getDateTimeOffset (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column as a DateTimeOffset Class object in the Java programming
language given the parameter index.

Overload List
NAME DESC RIP T IO N

getDateTimeOffset Method (int) Retrieves the value of the designated column as a


DateTimeOffset Class object in the Java programming
language given the parameter index.

getDateTimeOffset (java.lang.string) Retrieves the value of the designated column as a


DateTimeOffset Class object in the Java programming
language given the parameter index.

See Also
setDateTimeOffset(int, java.sql.DateTimeOffset) (SQLServerStatement)
getDateTimeOffset(int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in MicrosoftSQL Server JDBC Driver 3.0.
Retrieves the value of the designated column as a DateTimeOffset Class object in the Java programming
language given the parameter index.

Syntax
public microsoft.sql.DateTimeOffset getDateTimeOffset(int columnIndex)

Parameters
columnIndex
The column ordinal.

Return Value
A DateTimeOffset Class object.

Exceptions
SQLServerException

Remarks
You can update a DateTimeOffset Class value with SQLServerResultSet.updateDateTimeOffset.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getDateTimeOffset( java.lang.string)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in MicrosoftSQL Server JDBC Driver 3.0.
Retrieves the value of the designated column as a DateTimeOffset Class object in the Java programming
language given the parameter index.

Syntax
public microsoft.sql.DateTimeOffset getDateTimeOffset(String columnName)

Parameters
columnName
The name of the column.

Return Value
A DateTimeOffset Class object.

Exceptions
SQLServerException

Remarks
You can update a DateTimeOffset Class value with SQLServerResultSet.updateDateTimeOffset.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getDouble Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a double
in the Java programming language.

Overload List
NAME DESC RIP T IO N

getDouble (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a double in
the Java programming language.

getDouble (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a double in
the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getDouble Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
double in the Java programming language.

Syntax
public double getDouble(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A double value.

Exceptions
SQLServerException

Remarks
This getDouble method is specified by the getDouble method in the java.sql.ResultSet interface.
This method returns all number-based data types with Java double fidelity.

See Also
getDouble Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getDouble Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
double in the Java programming language.

Syntax
public double getDouble(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A double value.

Exceptions
SQLServerException

Remarks
This getDouble method is specified by the getDouble method in the java.sql.ResultSet interface.
This method returns all number-based data types with Java double fidelity.

See Also
getDouble Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getFetchDirection Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the fetch direction for this SQLServerResultSet object.

Syntax
public int getFetchDirection()

Return Value
An int that indicates the current fetch direction.

Exceptions
SQLServerException

Remarks
This getFetchDirection method is specified by the getFetchDirection method in the java.sql.ResultSet interface.
This method returns FETCH_FORWARD for forward-only cursors, the last setting made by a call to the
setFetchDirection method for other cursor types, and will return FETCH_UNKNOWN these cursor types if the
setFetchDirection method has never been called.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getFetchSize Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the fetch size for this SQLServerResultSet object.

Syntax
public int getFetchSize()

Return Value
An int that indicates the current fetch size.

Exceptions
SQLServerException

Remarks
This getFetchSize method is specified by the getFetchSize method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getFloat Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a float in
the Java programming language.

Overload List
NAME DESC RIP T IO N

getFloat (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a float in
the Java programming language.

getFloat (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a float in
the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getFloat Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
float in the Java programming language.

Syntax
public float getFloat(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A float value.

Exceptions
SQLServerException

Remarks
This getFloat method is specified by the getFloat method in the java.sql.ResultSet interface.
This method returns all number-based types with Java float fidelity.

See Also
getFloat Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getFloat Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
float in the Java programming language.

Syntax
public float getFloat(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A float value.

Exceptions
SQLServerException

Remarks
This getFloat method is specified by the getFloat method in the java.sql.ResultSet interface.
This method returns all number-based types with Java float fidelity.

See Also
getFloat Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getHoldability Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the holdability of this SQLServerResultSet object.

Syntax
public int getHoldability()

Return Value
An int value that contains one of the following holdability levels:
HOLD_CURSORS_OVER_COMMIT
CLOSE_CURSORS_AT_COMMIT

Exceptions
SQLServerException

Remarks
This getHoldability method is specified by the getHoldability method in the java.sql.ResultSet interface.
To set the result set holdability, applications can use the setHoldability method of the SQLServerConnection
class. After the setHoldability method is called and the statement object and its result set object are created and
the statement is executed, the application may need to change the holdability again.
For server cursors, when connected to SQL Server 2005 or later, setting holdability affects only the holdability of
new result sets that are yet to be created on that connection. However, with SQL Server 2000, setting holdability
affects the holdability of both existing result sets and new result sets that are yet to be created on that
connection.
When the holdability is reset and the getHoldability method is called on the previously created result set object,
the value returned by this method may be different than the holdability value returned by the following
methods: Statement.getResultSetHoldability, Connection.getHoldability, or
DatabaseMetaData.getResultSetHoldability.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getInt Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as an int in
the Java programming language.

Overload List
NAME DESC RIP T IO N

getInt (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as an int in
the Java programming language.

getInt (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as an int in
the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getInt Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as an
int in the Java programming language.

Syntax
public int getInt(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
An int value.

Exceptions
SQLServerException

Remarks
This getInt method is specified by the getInt method in the java.sql.ResultSet interface.
This method is supported only on SQL Server data types that can safely return an integer value such as int,
smallint, tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getInt Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getInt Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as an
int in the Java programming language.

Syntax
public int getInt(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
An int value.

Exceptions
SQLServerException

Remarks
This getInt method is specified by the getInt method in the java.sql.ResultSet interface.
This method is supported only on SQL Server data types that can safely return an integer value such as int,
smallint, tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getInt Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getLong Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a long in
the Java programming language.

Overload List
NAME DESC RIP T IO N

getLong (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a long in
the Java programming language.

getLong (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a long in
the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getLong Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
long in the Java programming language.

Syntax
public long getLong(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A long value.

Exceptions
SQLServerException

Remarks
This getLong method is specified by the getLong method in the java.sql.ResultSet interface.
This method is supported only on SQL Server data types that can safely return an integer value such as bigint,
int, smallint, tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getLong Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getLong Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
long in the Java programming language.

Syntax
public long getLong(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A long value.

Exceptions
SQLServerException

Remarks
This getLong method is specified by the getLong method in the java.sql.ResultSet interface.
This method is supported only on SQL Server data types that can safely return an integer value such as bigint,
int, smallint, tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getLong Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getMetaData Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the number, types, and properties of the columns for this SQLServerResultSet object.

Syntax
public java.sql.ResultSetMetaData getMetaData()

Return Value
A SQLServerResultSetMetaData object.

Exceptions
SQLServerException

Remarks
This getMetaData method is specified by the getMetaData method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getNCharacterStream Method
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of the SQLServerResultSet object as a Reader
object.

Overload List
NAME DESC RIP T IO N

getNCharacterStream Method (int) (SQLServerResultSet) Retrieves the value of the designated column in the current
row of the SQLServerResultSet object as a Reader object.

getNCharacterStream Method (java.lang.String) Retrieves the value of the designated column in the current
(SQLServerResultSet) row of the SQLServerResultSet object as a Reader object.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getNCharacterStream Method (int)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of a designated column in the current row of the SQLServerResultSet object as a Reader
object.

Syntax
public java.io.Reader getNCharacterStream(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A Reader object.

Exceptions
SQLServerException

Remarks
This getNCharacterStream method is specified by the getNCharacterStream method in the java.sql.ResultSet
interface.
This method can be used to retrieve the value of an nvarchar , nchar , nvarchar(max) , ntext , or xml column in
the current row of this SQLServerResultSet object. If you try to use this method to retrieve values of other data
types, an exception will be thrown.

See Also
getNCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
getNCharacterStream Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of the SQLServerResultSet object as a Reader
object.

Syntax
public java.io.Reader getNCharacterStream(java.lang.String columnLabel)

Parameters
columnLabel
A String that contains the column label.

Return Value
A Reader object.

Exceptions
SQLServerException

Remarks
This getNCharacterStream method is specified by the getNCharacterStream method in the java.sql.ResultSet
interface.
This method can be used to retrieve the value of an nvarchar , nchar , nvarchar(max) , ntext , or xml column in
the current row of this SQLServerResultSet object. If you try to use this method to retrieve values of other data
types, an exception will be thrown.

See Also
getNCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
getNClob Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of the SQLServerResultSet object as an NClob
object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getNClob Method (int) (SQLServerResultSet) Retrieves the value of the designated column in the current
row of the SQLServerResultSet object as an NClob object in
the Java programming language.

getNClob Method (java.lang.String) (SQLServerResultSet) Retrieves the value of the designated column in the current
row of the SQLServerResultSet object as an NClob object in
the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getNClob Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of the SQLServerResultSet object as an NClob
object in the Java programming language.

Syntax
public java.sql.NClob getNClob(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A NClob object.

Exceptions
SQLServerException

Remarks
This getNClob method is specified by the getNClob method in the java.sql.ResultSet interface.
This method is supported only on nvarchar(max) , ntext , and xml columns. Using this method on any other
data types will cause an exception to be thrown.

See Also
getNClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getNClob Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of the SQLServerResultSet object as a NClob
object in the Java programming language.

Syntax
public java.sql.NClob getNClob(java.lang.String columnLabel)

Parameters
columnLabel
A String that contains the column label.

Return Value
A NClob object.

Exceptions
SQLServerException

Remarks
This getNClob method is specified by the getNClob method in the java.sql.ResultSet interface.
This method is supported only on nvarchar(max) , ntext , and xml columns. Using this method on any other
data types will cause an exception to be thrown.

See Also
getNClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getNString Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of the SQLServerResultSet object as a String in
the Java programming language.

Overload List
NAME DESC RIP T IO N

getNString Method (int) (SQLServerResultSet) Retrieves the value of the designated column in the current
row of the SQLServerResultSet object as a String in the Java
programming language.

getNString Method (java.lang.String) (SQLServerResultSet) Retrieves the value of the designated column in the current
row of the SQLServerResultSet object as a String in the Java
programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getNString Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of the SQLServerResultSet object as a String
object.

Syntax
public java.lang.String getNString(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A String object.

Exceptions
SQLServerException

Remarks
This getNString method is specified by the getNString method in the java.sql.SQLServerResultSet interface.
This method can be used to retrieve the value of an nvarchar , nchar , nvarchar(max) , ntext , or xml column in
the current row of this SQLServerResultSet object. If you try to use this method to retrieve values of other data
types, an exception will be thrown.

See Also
getNString Method (SQLServerResultSet)
SQLServerResultSet Members
getNString Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of the SQLServerResultSet object as a
java.lang.String object.

Syntax
public java.lang.String getNString(java.lang.String columnLabel)

Parameters
columnLabel
A String that contains the column label.

Return Value
A String object.

Exceptions
SQLServerException

Remarks
This getNString method is specified by the getNString method in the java.sql.SQLServerResultSet interface.
This method can be used to retrieve the value of an nvarchar , nchar , nvarchar(max) , ntext , or xml column in
the current row of this SQLServerResultSet object. If you try to use this method to retrieve values of other data
types, an exception will be thrown.

See Also
getNString Method (SQLServerResultSet)
SQLServerResultSet Members
getObject Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the value of the designated column in the current row of this SQLServerResultSet object as an object in the
Java programming language.

Overload List
NAME DESC RIP T IO N

getObject (int) Gets the value of the designated column index in the current
row of this SQLServerResultSet object as an object in the
Java programming language.

getObject (int, java.util.Map) Gets the value of the designated column index in the current
row of this SQLServerResultSet object as an object in the
Java programming language, using the given Map object.

getObject (java.lang.String) Gets the value of the designated column name in the
current row of this SQLServerResultSet object as an object in
the Java programming language.

getObject (java.lang.String, java.util.Map) Gets the value of the designated column name in the
current row of this SQLServerResultSet object as an object in
the Java programming language, using the given Map
object.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getObject Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the value of the designated column index in the current row of this SQLServerResultSet object as an object
in the Java programming language.

Syntax
public java.lang.Object getObject(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
An Object value.

Exceptions
SQLServerException

Remarks
This getObject method is specified by the getObject method in the java.sql.ResultSet interface.
This method will return the value of the given column as a Java object. The type of the Java object will be the
default Java object type corresponding to the SQL type of the column, following the mapping for built-in types
that is specified in the JDBC specification. If the value is an SQL NULL, the driver returns a Java null.
This method can also be used to read database-specific abstract data types. In the JDBC 2.0 API, the behavior of
the getObject method is extended to materialize data of SQL user-defined types. When a column contains a
structured or distinct value, the behavior of this method is as if it were a call to
getObject(columnIndex, this.getStatement().getConnection().getTypeMap()) .

Beginning in the SQL Server JDBC Driver 3.0:


A value of type date will be returned as a java.sql.Date object.
A value of type time will be returned as a java.sql.Time object.
A value of type datetime2 will be returned as a java.sql.Timestamp object.
A value of type datetimeoffset will be returned as a microsoft.sql.DateTimeOffset object.

See Also
getObject Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getObject Method (int, java.util.Map)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the value of the designated column index in the current row of this SQLServerResultSet object as an object
in the Java programming language, using the given Map object.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server. Using this method will always return
the default mapping.

Syntax
public java.lang.Object getObject(int i,
java.util.Map map)

Parameters
i
An int that indicates the column index.
map
A Map object.

Return Value
An Object value.

Exceptions
SQLServerException

Remarks
This getObject method is specified by the getObject method in the java.sql.ResultSet interface.
This method will return the value of the given column as a Java object. The type of the Java object will be the
default Java object type corresponding to the SQL type of the column, following the mapping for built-in types
that is specified in the JDBC specification. If the value is an SQL NULL, the driver returns a Java null.
This method can also be used to read database-specific abstract data types. In the JDBC 2.0 API, the behavior of
the getObject method is extended to materialize data of SQL user-defined types. When a column contains a
structured or distinct value, the behavior of this method is as if it were a call to
getObject(columnIndex, this.getStatement().getConnection().getTypeMap()) .

Beginning in the SQL Server JDBC Driver 3.0:


A value of type date will be returned as a java.sql.Date object.
A value of type time will be returned as a java.sql.Time object.
A value of type datetime2 will be returned as a java.sql.Timestamp object.
A value of type datetimeoffset will be returned as a microsoft.sql.DateTimeOffset object.

See Also
getObject Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getObject Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the value of the designated column name in the current row of this SQLServerResultSet object as an object
in the Java programming language.

Syntax
public java.lang.Object getObject(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
An Object value.

Exceptions
SQLServerException

Remarks
This getObject method is specified by the getObject method in the java.sql.ResultSet interface.
This method will return the value of the given column as a Java object. The type of the Java object will be the
default Java object type corresponding to the SQL type of the column, following the mapping for built-in types
that is specified in the JDBC specification. If the value is an SQL NULL, the driver returns a Java null.
This method can also be used to read database-specific abstract data types. In the JDBC 2.0 API, the behavior of
the getObject method is extended to materialize data of SQL user-defined types. When a column contains a
structured or distinct value, the behavior of this method is as if it were a call to
getObject(columnIndex, this.getStatement().getConnection().getTypeMap()) .

Beginning in the SQL Server JDBC Driver 3.0:


A value of type date will be returned as a java.sql.Date object.
A value of type time will be returned as a java.sql.Time object.
A value of type datetime2 will be returned as a java.sql.Timestamp object.
A value of type datetimeoffset will be returned as a microsoft.sql.DateTimeOffset object.

See Also
getObject Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getObject Method ( java.lang.String, java.util.Map)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the value of the designated column name in the current row of this SQLServerResultSet object as an object
in the Java programming language, using the given Map object.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server. Using this method will always return
the default mapping.

Syntax
public java.lang.Object getObject(java.lang.String colName,
java.util.Map map)

Parameters
colName
A String that contains the column name.
map
A Map object.

Return Value
An Object value.

Exceptions
SQLServerException

Remarks
This getObject method is specified by the getObject method in the java.sql.ResultSet interface.
This method will return the value of the given column as a Java object. The type of the Java object will be the
default Java object type corresponding to the SQL type of the column, following the mapping for built-in types
that is specified in the JDBC specification. If the value is an SQL NULL, the driver returns a Java null.
This method can also be used to read database-specific abstract data types. In the JDBC 2.0 API, the behavior of
the getObject method is extended to materialize data of SQL user-defined types. When a column contains a
structured or distinct value, the behavior of this method is as if it were a call to
getObject(columnIndex, this.getStatement().getConnection().getTypeMap()) .

Beginning in the SQL Server JDBC Driver 3.0:


A value of type date will be returned as a java.sql.Date object.
A value of type time will be returned as a java.sql.Time object.
A value of type datetime2 will be returned as a java.sql.Timestamp object.
A value of type datetimeoffset will be returned as a microsoft.sql.DateTimeOffset object.

See Also
getObject Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getRef Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a Ref
object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getRef (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a Ref object
in the Java programming language.

getRef (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a Ref object
in the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getRef Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a Ref
object in the Java programming language.

Syntax
public java.sql.Ref getRef(int i)

Parameters
i
An int that indicates the column index.

Return Value
A Ref object.

Exceptions
SQLServerException

Remarks
This getRef method is specified by the getRef method in the java.sql.ResultSet interface.

See Also
getRef Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getRef Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a Ref
object in the Java programming language.

Syntax
public java.sql.Ref getRef(java.lang.String colName)

Parameters
colName
A String that contains the column name.

Return Value
A Ref object.

Exceptions
SQLServerException

Remarks
This getRef method is specified by the getRef method in the java.sql.ResultSet interface.

See Also
getRef Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getRow Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the current row number.

Syntax
public int getRow()

Return Value
An int that indicates the current row number, 0 if there is no row.

Exceptions
SQLServerException

Remarks
This getRow method is specified by the getRow method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getShort Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a shor t in
the Java programming language.

Overload List
NAME DESC RIP T IO N

getShort (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a shor t in
the Java programming language.

getShort (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a shor t in
the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getShort Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
shor t in the Java programming language.

Syntax
public short getShort(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A shor t value.

Exceptions
SQLServerException

Remarks
This getShort method is specified by the getShort method in the java.sql.ResultSet interface.
This method is only supported on SQL Server data types that can safely return an integer value such as smallint,
tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getShort Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getShort Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
shor t in the Java programming language.

Syntax
public short getShort(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A shor t value.

Exceptions
SQLServerException

Remarks
This getShort method is specified by the getShort method in the java.sql.ResultSet interface.
This method is supported only on SQL Server data types that can safely return an integer value such as smallint,
tinyint, and bit. Using this method on any other data types will cause an exception to be thrown.

See Also
getShort Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getSQLXML Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of the SQLServerResultSet object as a SQLXML
object.

Overload List
NAME DESC RIP T IO N

getSQLXML Method (int) (SQLServerResultSet) Retrieves the value of a designated column in the current
row of the SQLServerResultSet object as a SQLXML object.

getSQLXML Method (java.lang.String) Retrieves the value of a designated column in the current
row of the SQLServerResultSet object as a SQLXML object.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getSQLXML Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of a designated column in the current row of the SQLServerResultSet object as a SQLXML
object.

Syntax
public final java.sql.SQLXML getSQLXML(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
ASQLXMLobject.

Exceptions
SQLServerException

Remarks
This getSQLXML method is specified by the getSQLXML method in the java.sql.ResultSet interface.

See Also
getSQLXML Method (SQLServerResultSet)
SQLServerResultSet Members
getSQLXML Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of a designated column in the current row of the SQLServerResultSet object as a SQLXML
object.

Syntax
public final java.sql.SQLXML getSQLXML(java.lang.String columnLabel)

Parameters
columnName
A String that indicates the column label.

Return Value
ASQLXMLobject.

Exceptions
SQLServerException

Remarks
This getSQLXML method is specified by the getSQLXML method in the java.sql.ResultSet interface.

See Also
getSQLXML Method (SQLServerResultSet)
SQLServerResultSet Members
getStatement Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the SQLServerStatement object that produced this SQLServerResultSet object.

Syntax
public java.sql.Statement getStatement()

Return Value
A SQLServerStatement object.

Exceptions
SQLServerException

Remarks
This getStatement method is specified by the getStatement method in the java.sql.ResultSet interface.
If the result set was generated some other way, such as by a SQLServerDatabaseMetaData method, this method
returns null.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getString Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a String in
the Java programming language.

Overload List
NAME DESC RIP T IO N

getString (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a String in
the Java programming language.

getString (java.lang.String)) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a String in
the Java programming language.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getString Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
String in the Java programming language.

Syntax
public java.lang.String getString(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A String value.

Exceptions
SQLServerException

Remarks
This getString method is specified by the getString method in the java.sql.ResultSet interface.
All columns in SQL Server can be returned as a String. This means that a String representation of all number-
based and character-based types, and a hex-string representation of binary columns such as binary, varbinary,
varbinary(max), image, timestamp, and uniqueidentifier, can be returned.
Location-sensitive types such as money, smallmoney, datetime, smalldatetime, float, real, decimal, and numeric
will return the canonical toString() format for the underlying value of the type.
User-defined types are returned as hexadecimal String values.

See Also
getString Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getString Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
String in the Java programming language.

Syntax
public java.lang.String getString(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A String value.

Exceptions
SQLServerException

Remarks
This getString method is specified by the getString method in the java.sql.ResultSet interface.
All columns in SQL Server can be returned as a String. This means that a String representation of all number-
based and character-based types, and a hex-string representation of binary columns such as binary, varbinary,
varbinary(max), image, timestamp, and uniqueidentifier, can be returned.
Location sensitive types such as money, smallmoney, datetime, smalldatetime, float, real, decimal, and numeric
will return the canonical toString() format for the underlying value of the type.
User defined types are returned as hexadecimal String values.

See Also
getString Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getTime Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a
java.sql.Time object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getTime (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a
java.sql.Time object in the Java programming language.

getTime (int, java.util.Calendar) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a
java.sql.Time object in the Java programming language,
using the given Calendar object.

getTime (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a
java.sql.Time object in the Java programming language.

getTime (java.lang.String, java.util.Calendar) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a
java.sql.Time object in the Java programming language,
using the given Calendar object.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getTime Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
java.sql.Time object in the Java programming language.

Syntax
public java.sql.Time getTime(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A Time object.

Exceptions
SQLServerException

Remarks
This getTime method is specified by the getTime method in the java.sql.ResultSet interface.
This method returns a valid time part of a SQL Server datetime or smalldatetime data type, with the date part
set to the Java baseline date of 1970/01/01.

See Also
getTime Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getTime Method (int, java.util.Calendar)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
java.sql.Time object in the Java programming language, using the given Calendar object.

Syntax
public java.sql.Time getTime(int columnIndex,
java.util.Calendar cal)

Parameters
columnIndex
An int that indicates the column index.
cal
A Calendar object.

Return Value
A Time object.

Exceptions
SQLServerException

Remarks
This getTime method is specified by the getTime method in the java.sql.ResultSet interface.
This method returns a valid time part of a SQL Server datetime or smalldatetime data type, with the date part
set to the Java baseline date of 1970/01/01 in the supplied Calendar's timezone.

See Also
getTime Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getTime Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
java.sql.Time object in the Java programming language.

Syntax
public java.sql.Time getTime(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A Time object.

Exceptions
SQLServerException

Remarks
This getTime method is specified by the getTime method in the java.sql.ResultSet interface.
This method returns a valid time part of a SQL Server datetime or smalldatetime data type, with the date part
set to the Java baseline date of 1970/01/01.

See Also
getTime Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getTime Method ( java.lang.String,
java.util.Calendar) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
java.sql.Time object in the Java programming language, using the given Calendar object.

Syntax
public java.sql.Time getTime(java.lang.String colName,
java.util.Calendar cal)

Parameters
colName
A String that contains the column name.
cal
A Calendar object.

Return Value
A Time object.

Exceptions
SQLServerException

Remarks
This getTime method is specified by the getTime method in the java.sql.ResultSet interface.
This method returns a valid time part of a SQL Server datetime or smalldatetime data type, with the date part
set to the Java baseline date of 1970/01/01 in the supplied Calendar's timezone.

See Also
getTime Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getTimestamp Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming language.

Overload List
NAME DESC RIP T IO N

getTimestamp (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming
language.

getTimestamp (int, java.util.Calendar) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming
language, using a Calendar object.

getTimestamp (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming
language.

getTimestamp (java.lang.String, java.util.Calendar) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming
language, using a Calendar object.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getTimestamp Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming language.

Syntax
public java.sql.Timestamp getTimestamp(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A Timestamp object.

Exceptions
SQLServerException

Remarks
This getTimestamp method is specified by the getTimestamp method in the java.sql.ResultSet interface.
This method returns values only from SQL Server datetime and smalldatetime columns.

See Also
getTimestamp Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getTimestamp Method (int, java.util.Calendar)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming language, using a Calendar object.

Syntax
public java.sql.Timestamp getTimestamp(int columnIndex,
java.util.Calendar cal)

Parameters
columnIndex
An int that indicates the column index.
cal
A Calendar object.

Return Value
A Timestamp object.

Exceptions
SQLServerException

Remarks
This getTimestamp method is specified by the getTimestamp method in the java.sql.ResultSet interface.
This method returns values only from SQL Server datetime and smalldatetime columns.

See Also
getTimestamp Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getTimestamp Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming language.

Syntax
public java.sql.Timestamp getTimestamp(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
A Timestamp object.

Exceptions
SQLServerException

Remarks
This getTimestamp method is specified by the getTimestamp method in the java.sql.ResultSet interface.
This method returns values only from SQL Server datetime and smalldatetime columns.

See Also
getTimestamp Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getTimestamp Method ( java.lang.String,
java.util.Calendar) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
java.sql.Timestamp object in the Java programming language, using a Calendar object.

Syntax
public java.sql.Timestamp getTimestamp(java.lang.String colName,
java.util.Calendar cal)

Parameters
colName
A String that contains the column name.
cal
A Calendar object.

Return Value
A Timestamp object.

Exceptions
SQLServerException

Remarks
This getTimestamp method is specified by the getTimestamp method in the java.sql.ResultSet interface.
This method returns values only from SQL Server datetime and smalldatetime columns.

See Also
getTimestamp Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getType Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the cursor type of this SQLServerResultSet object.

Syntax
public int getType()

Return Value
An int that indicates the current cursor type, which can be one of the following values:
ResultSet.TYPE_FORWARD_ONLY
ResultSet.TYPE_SCROLL_INSENSITIVE
ResultSet.TYPE_SCROLL_SENSITIVE

Exceptions
SQLServerException

Remarks
This getType method is specified by the getType method in the java.sql.ResultSet interface.
This method can be used to determine the actual cursor type. If the application selected TYPE_FORWARD_ONLY
or used a default cursor type, TYPE_FORWARD_ONLY will be returned.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getUnicodeStream Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a stream of
Unicode characters.

NOTE
This method has been deprecated from the JDBC specification, and calling it will cause a "not implemented" exception to
be thrown. Instead, you should use the getCharacterStream method.

Overload List
NAME DESC RIP T IO N

getUnicodeStream Method (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a stream of
Unicode characters.

getUnicodeStream Method (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a stream of
Unicode characters.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getUnicodeStream Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
stream of Unicode characters.

NOTE
This method has been deprecated from the JDBC specification, and calling it will cause a "not implemented" exception to
be thrown. Instead, you should use the getCharacterStream method.

Syntax
public java.io.InputStream getUnicodeStream(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
An InputStream object.

Exceptions
SQLServerException

Remarks
This getUnicodeString method is specified by the getUnicodeString method in the java.sql.ResultSet interface.

See Also
getUnicodeStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getUnicodeStream Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
stream of Unicode characters.

NOTE
This method has been deprecated from the JDBC specification, and calling it will cause a "not implemented" exception to
be thrown. Instead, you should use the getCharacterStream method.

Syntax
public java.io.InputStream getUnicodeStream(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Return Value
An InputStream object.

Exceptions
SQLServerException

Remarks
This getUnicodeString method is specified by the getUnicodeString method in the java.sql.ResultSet interface.

See Also
getUnicodeStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getURL Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column in the current row of this SQLServerResultSet object as a URL
object.

Overload List
NAME DESC RIP T IO N

getURL (int) Retrieves the value of the designated column index in the
current row of this SQLServerResultSet object as a URL
object.

getURL (java.lang.String) Retrieves the value of the designated column name in the
current row of this SQLServerResultSet object as a URL
object.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
getURL Method (int) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column index in the current row of this SQLServerResultSet object as a
URL object.

Syntax
public java.net.URL getURL(int columnIndex)

Parameters
columnIndex
An int that indicates the column index.

Return Value
A URL object.

Exceptions
SQLServerException

Remarks
This getURL method is specified by the getURL method in the java.sql.ResultSet interface.

See Also
getURL Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getURL Method ( java.lang.String)
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the value of the designated column name in the current row of this SQLServerResultSet object as a
URL object.

Syntax
public java.net.URL getURL(java.lang.String sColumn)

Parameters
sColumn
A String that contains the column name.

Return Value
A URL object.

Exceptions
SQLServerException

Remarks
This getURL method is specified by the getURL method in the java.sql.ResultSet interface.

See Also
getURL Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
getWarnings Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the first warning reported by calls on this SQLServerResultSet object.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server. If called this method will always
return a null value.

Syntax
public java.sql.SQLWarning getWarnings()

Return Value
An SQLWarning object.

Exceptions
SQLServerException

Remarks
This getWarnings method is specified by the getWarnings method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
insertRow Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Adds the contents of the insert row to this SQLServerResultSet object and to the database.

Syntax
public void insertRow()

Exceptions
SQLServerException

Remarks
This insertRow method is specified by the insertRow method in the java.sql.ResultSet interface.
The cursor must be on the insert row when this method is called. After this method is called, the cursor remains
on the insert row and the result set remains in insert mode.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
isAfterLast Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the cursor is after the last row in this SQLServerResultSet object.

Syntax
public boolean isAfterLast()

Return Value
true if the cursor is after the last row. false if the cursor is at any other position or if the result set contains no
rows.

Exceptions
SQLServerException

Remarks
This isAfterLast method is specified by the isAfterLast method in the java.sql.ResultSet interface.
If this method is used with dynamic cursors, including forward-only read-only cursors, and the selectMethod
connection property is set to "cursor", an exception will occur.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
isBeforeFirst Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the cursor is before the first row in this SQLServerResultSet object.

Syntax
public boolean isBeforeFirst()

Return Value
true if the cursor is before the first row. false if the cursor is at any other position or if the result set contains no
rows.

Exceptions
SQLServerException

Remarks
This isBeforeFirst method is specified by the isBeforeFirst method in the java.sql.ResultSet interface.
If this method is used with dynamic cursors, including forward-only read-only cursors, and the selectMethod
connection property is set to "cursor", an exception will occur.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
isClosed Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this SQLServerResultSet object has been closed.

Syntax
public boolean isClosed()

Return Value
true if this SQLServerResultSet object is closed, false if it is still open.

Exceptions
SQLServerException

Remarks
This isClosed method is specified by the isClosed method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
isFirst Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the cursor is on the first row of this SQLServerResultSet object.

Syntax
public boolean isFirst()

Return Value
true if the cursor is on the first row. false if the cursor is at any other position or if the result set contains no
rows.

Exceptions
SQLServerException

Remarks
This isFirst method is specified by the isFirst method in the java.sql.ResultSet interface.
If this method is used with forward and dynamic cursors, an exception is thrown.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
isLast Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the cursor is on the last row of this SQLServerResultSet object.

Syntax
public boolean isLast()

Return Value
true if the cursor is on the last row. false if the cursor is at any other position or if the result set contains no
rows.

Exceptions
SQLServerException

Remarks
This isLast method is specified by the isLast method in the java.sql.ResultSet interface.
If this method is used with forward and dynamic cursors, an exception is thrown.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
last Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor to the last row in this SQLServerResultSet object.

Syntax
public boolean last()

Return Value
true if the new current row is valid. false if there are no more rows to process.

Exceptions
SQLServerException

Remarks
This last method is specified by the last method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
moveToCurrentRow Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor to the remembered cursor position, which is usually the current row.

Syntax
public void moveToCurrentRow()

Exceptions
SQLServerException

Remarks
This moveToCurrentRow method is specified by the moveToCurrentRow method in the java.sql.ResultSet
interface.
This method has no effect if the cursor is not on the insert row.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
moveToInsertRow Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor to the insert row.

Syntax
public void moveToInsertRow()

Exceptions
SQLServerException

Remarks
This moveToInsertRow method is specified by the moveToInsertRow method in the java.sql.ResultSet interface.
The current cursor position is remembered while the cursor is positioned on the insert row. The insert row is a
special row that is associated with an updatable result set. It is essentially a buffer where a new row can be
constructed by calling the updater methods before adding the row to the result set.
Only the updater, getter, and insertRow methods can be called when the cursor is on the insert row. All the
columns in a result set must be given a value each time this method is called, and before calling insertRow. An
updater method must be called before a getter method can be called on a column value.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
next Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor down one row from its current position.

Syntax
public boolean next()

Return Value
true if the new current row is valid. false if there are no more rows to process.

Exceptions
SQLServerException

Remarks
This next method is specified by the next method in the java.sql.ResultSet interface.
A result set cursor is initially positioned before the first row. The first call to the next method makes the first row
the current row, the second call makes the second row the current row, and so on.
If an input stream is open for the current row, a call to the next method will implicitly close it. A warning chain
for the SQLServerResultSet object is cleared when a new row is read.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
previous Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor to the previous row in this SQLServerResultSet object.

Syntax
public boolean previous()

Return Value
true if the new current row is valid. false if there are no more rows to process.

Exceptions
SQLServerException

Remarks
This previous method is specified by the previous method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
refreshRow Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Refreshes the current row with its most recent value in the database.

Syntax
public void refreshRow()

Exceptions
SQLServerException

Remarks
This refreshRow method is specified by the refreshRow method in the java.sql.ResultSet interface.
This method cannot be called when the cursor is on the insert row.
This method provides a way for an application to explicitly tell the JDBC driver to refetch rows from the
database. An application might need to call this method when the Microsoft JDBC Driver for SQL Server is
caching or prefetching to fetch the latest value of a row from the database. The JDBC driver might actually
refresh multiple rows at the same time if the fetch size is greater than one.
All values are refetched subject to the transaction isolation level and cursor sensitivity. If this method is called
after calling an updater method, but before calling the updateRow method, the updates made to the row are
lost. Calling this method frequently will probably slow performance.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
relative Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves the cursor the given amount of rows, relative to the current row, in either a positive or negative direction.

Syntax
public boolean relative(int nRows)

Parameters
nRows
An int that indicates the number of rows to move.

Return Value
true if the cursor is on a row. Otherwise, false .

Exceptions
SQLServerException

Remarks
This relative method is specified by the relative method in the java.sql.ResultSet interface.
Trying to move beyond the first or last row in the result set positions the cursor before or after the first or last
row. Calling relative(0) is valid, but does not change the cursor position.
Calling the method relative(1) is identical to calling the next method. Calling the method relative(-1) is
identical to calling the previous method.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
rowDeleted Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether a row has been deleted.

Syntax
public boolean rowDeleted()

Return Value
true if a row was deleted and deletions are detected. Otherwise, false .

Exceptions
SQLServerException

Remarks
This rowDeleted method is specified by the rowDeleted method in the java.sql.ResultSet interface.
A deleted row might leave a visible hole in a result set. This method can be used to detect holes in a result set.
The value that is returned depends on whether this SQLServerResultSet object can detect deletions.

NOTE
SQL Server detects deleted rows for all updatable cursor types, though the detection is transient for forward and dynamic
cursors.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
rowInserted Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the current row has had an insertion.

Syntax
public boolean rowInserted()

Return Value
true if a row has had an insertion and insertions are detected. Otherwise, false .

Exceptions
SQLServerException

Remarks
This rowUpdated method is specified by the rowUpdated method in the java.sql.ResultSet interface.
The value that is returned depends on whether this SQLServerResultSet object can detect visible inserts.

NOTE
SQL Server does not detect inserted rows for any cursor type.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
rowUpdated Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves whether the current row has been updated.

Syntax
public boolean rowUpdated()

Return Value
true if both the row has been visibly updated by the owner or another user, and updates are detected.
Otherwise, false .

Exceptions
SQLServerException

Remarks
This rowUpdated method is specified by the rowUpdated method in the java.sql.ResultSet interface.
The value that is returned depends on whether or not the result set can detect updates.

NOTE
SQL Server does not detect updated rows for any cursor type.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
setFetchDirection Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gives a hint as to the direction in which the rows in this SQLServerResultSet object will be processed.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server. If you use this method, the JDBC
driver remembers the setting, but currently does not act on it.

Syntax
public void setFetchDirection(int direction)

Parameters
direction
An int that indicates the suggested fetch direction. Can be one of the following values:
ResultSet.FETCH_FORWARD
ResultSet.FETCH_REVERSE
ResultSet.FETCH_UNKNOWN

Exceptions
SQLServerException

Remarks
This setFetchDirection method is specified by the setFetchDirection method in the java.sql.ResultSet interface.
The initial value of this method is determined by the SQLServerStatement object that produced this
SQLServerResultSet object. The fetch direction can be changed at any time.

NOTE
Using this method when the cursor type is forward-only has no effect.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
setFetchSize Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more
rows are needed for this SQLServerResultSet object.

Syntax
public void setFetchSize(int rows)

Parameters
rows
An int indicating the number of rows to fetch.

Exceptions
SQLServerException

Remarks
This setFetchSize method is specified by the setFetchSize method in the java.sql.ResultSet interface.
If the fetch size specified is zero, the JDBC driver ignores the value and estimates what the fetch size should be.
The default value is set by the SQLServerStatement object that created the result set. The fetch size can be
changed at any time.
This method changes the block fetch size for server cursors, and takes effect the next time the JDBC driver needs
to call sp_cursorfetch. Setting the fetch size to zero restores the default fetch size for the cursor type that is
currently in use

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateArray Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an Array object.

Overload List
NAME DESC RIP T IO N

updateArray (int, java.sql.Array) Updates the designated column with an Array object given
the column index.

updateArray (java.lang.String, java.sql.Array) Updates the designated column with an Array object given
the column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateArray Method (int, java.sql.Array)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an Array object given the column index.

Syntax
public void updateArray(int columnIndex,
java.sql.Array x)

Parameters
columnIndex
An int that indicates the column index.
x
An Array object.

Exceptions
SQLServerException

Remarks
This updateArray method is specified by the updateArray method in the java.sql.ResultSet interface.

See Also
updateArray Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateArray Method ( java.lang.String,
java.sql.Array)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an Array object given the column name.

Syntax
public void updateArray(java.lang.String columnName,
java.sql.Array x)

Parameters
columnName
A String that contains the column name.
x
An Array object.

Exceptions
SQLServerException

Remarks
This updateArray method is specified by the updateArray method in the java.sql.ResultSet interface.

See Also
updateArray Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateAsciiStream Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an ASCII stream value.

Overload List
NAME DESC RIP T IO N

updateAsciiStream Method (int, java.io.InputStream) Updates the designated column with an ASCII stream value.

updateAsciiStream (int, java.io.InputStream, int) Updates the designated column index with an ASCII stream
value specific to the column index.

updateAsciiStream Method (int, java.io.InputStream, long) Updates the designated column with an ASCII stream value,
which will have the specified number of bytes.

updateAsciiStream Method (java.lang.String, Updates the designated column with an ASCII stream value.
java.io.InputStream)

updateAsciiStream (java.lang.String, java.io.InputStream, int) Updates the designated column name with an ASCII stream
value, which will have the specified number of bytes.

updateAsciiStream Method (java.lang.String, Updates the designated column with an ASCII stream value,
java.io.InputStream, long) which will have the specified number of bytes.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateAsciiStream Method (int, java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an ASCII stream value.

Syntax
public void updateAsciiStream(int columnIndex,
java.io.InputStream x)

Parameters
columnIndex
An int that indicates the column index.
x
An InputStream object.

Exceptions
SQLServerException

Remarks
This updateAsciiStream method is specified by the updateAsciiStream method in the java.sql.ResultSet interface.
This method passes ASCII characters (bytes) from an InputStream object to convertible character columns,
which are the ASCII range [0x00 - 0x7F] of Unicode, and 874, 932, 936, 949, 950, and 1250 through 1258 code
pages. This method performs a conversion to the destination collation page. Trying to update an unconvertible
destination column will cause an exception to be thrown. For binary columns, raw bytes are passed.
Using this method for the image , text , and ntext SQL Server data types might impact performance.

See Also
updateAsciiStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateAsciiStream Method (int, java.io.InputStream,
int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an ASCII stream value, which will have the specified number of bytes.

Syntax
public void updateAsciiStream(int index,
java.io.InputStream x,
int length)

Parameters
index
An int that indicates the column index.
x
An InputStream object.
length
An int that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateAsciiStream method is specified by the updateAsciiStream method in the java.sql.ResultSet interface.
This method passes ASCII characters (bytes) from an InputStream object to convertible character columns,
which are the ASCII range [0x00 - 0x7F] of Unicode, and 874, 932, 936, 949, 950, and 1250 through 1258 code
pages. This method performs a conversion to the destination collation page. Trying to update an unconvertible
destination column will cause an exception to be thrown. For binary columns, raw bytes are passed.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateAsciiStream Method (int, java.io.InputStream) when the application wants to update the column from a
stream whose length is unknown.

See Also
updateAsciiStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateAsciiStream Method (int, java.io.InputStream,
long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an ASCII stream value, which will have the specified number of bytes.

Syntax
public void updateAsciiStream(int columnIndex,
java.io.InputStream x,
long length)

Parameters
columnIndex
An int that indicates the column index.
x
An InputStream object.
length
The length of the stream.

Exceptions
SQLServerException

Remarks
This updateAsciiStream method is specified by the updateAsciiStream method in the java.sql.ResultSet interface.
This method passes ASCII characters (bytes) from an InputStream object to convertible character columns,
which are the ASCII range [0x00 - 0x7F] of Unicode, and 874, 932, 936, 949, 950, and 1250 through 1258 code
pages. This method performs a conversion to the destination collation page. Trying to update an unconvertible
destination column will cause an exception to be thrown. For binary columns, raw bytes are passed.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateAsciiStream Method (int, java.io.InputStream) when the application wants to update the column from a
stream whose length is unknown.

See Also
updateAsciiStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateAsciiStream Method ( java.lang.String,
java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an ASCII stream value.

Syntax
public void updateAsciiStream(java.lang.String columnLabel,
java.io.InputStream x)

Parameters
columnLabel
A String that contains the column label.
x
An InputStream object.

Exceptions
SQLServerException

Remarks
This updateAsciiStream method is specified by the updateAsciiStream method in the java.sql.ResultSet interface.
This method passes ASCII characters (bytes) from an InputStream object to convertible character columns,
which are the ASCII range [0x00 - 0x7F] of Unicode, and 874, 932, 936, 949, 950, and 1250 through 1258 code
pages. This method performs a conversion to the destination collation page. Trying to update an unconvertible
destination column will cause an exception to be thrown. For binary columns, raw bytes are passed.
Using this method for the image , text , and ntext SQL Server data types might impact performance.

See Also
updateAsciiStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateAsciiStream Method ( java.lang.String,
java.io.InputStream, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column name with an ASCII stream value, which will have the specified number of
bytes.

Syntax
public void updateAsciiStream(java.lang.String columnName,
java.io.InputStream x,
int length)

Parameters
columnName
A String that contains the column name.
x
An InputStream object.
length
An int that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateAsciiStream method is specified by the updateAsciiStream method in the java.sql.ResultSet interface.
This method passes ASCII characters (bytes) from an InputStream object to convertible character columns,
which are the ASCII range [0x00 - 0x7F] of Unicode, and 874, 932, 936, 949, 950, and 1250 through 1258 code
pages. This method performs a conversion to the destination collation page. Trying to update an unconvertible
destination column will cause an exception to be thrown. For binary columns, raw bytes are passed.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateAsciiStream Method ( java.lang.String, java.io.InputStream) when the application wants to update the
column from a stream whose length is unknown.

See Also
updateAsciiStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateAsciiStream Method ( java.lang.String,
java.io.InputStream, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an ASCII stream value, which will have the specified number of bytes.

Syntax
public void updateAsciiStream(java.lang.String columnName,
java.io.InputStream streamValue,
long length)

Parameters
columnName
A String that contains the column name.
streamValue
An InputStream object.
length
The length of the stream.

Exceptions
SQLServerException

Remarks
This updateAsciiStream method is specified by the updateAsciiStream method in the java.sql.ResultSet interface.
This method passes ASCII characters (bytes) from an InputStream object to convertible character columns,
which are the ASCII range [0x00 - 0x7F] of Unicode, and 874, 932, 936, 949, 950, and 1250 through 1258 code
pages. This method performs a conversion to the destination collation page. Trying to update an unconvertible
destination column will cause an exception to be thrown. For binary columns, raw bytes are passed.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateAsciiStream Method ( java.lang.String, java.io.InputStream) when the application wants to update the
column from a stream whose length is unknown.

See Also
updateAsciiStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBigDecimal Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a BigDecimal object.

Overload List
NAME DESC RIP T IO N

updateBigDecimal (int, java.math.BigDecimal) Updates the designated column with a BigDecimal object
given the column index.

updateBigDecimal (java.lang.String, java.math.BigDecimal) Updates the designated column with a BigDecimal object
given the column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateBigDecimal Method (int,
java.math.BigDecimal)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a BigDecimal object given the column index.

Syntax
public void updateBigDecimal(int index,
java.math.BigDecimal x)

Parameters
index
An int that indicates the column index.
x
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This updateBigDecimal method is specified by the updateBigDecimal method in the java.sql.ResultSet interface.

See Also
updateBigDecimal Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBigDecimal Method ( java.lang.String,
java.math.BigDecimal)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a BigDecimal object given the column name.

Syntax
public void updateBigDecimal(java.lang.String columnName,
java.math.BigDecimal x)

Parameters
columnName
A String that contains the column name.
x
A BigDecimal object.

Exceptions
SQLServerException

Remarks
This updateBigDecimal method is specified by the updateBigDecimal method in the java.sql.ResultSet interface.

See Also
updateBigDecimal Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBinaryStream Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a binary stream value.

Overload List
NAME DESC RIP T IO N

updateBinaryStream(int, java.io.InputStream) Updates the designated column with a binary stream value.

updateBinaryStream (int, java.io.InputStream, int) Updates the designated column with a binary stream value,
which will have the specified number of bytes.

updateBinaryStream(int, java.io.InputStream, long) Updates the designated column with a binary stream value,
which will have the specified number of bytes.

updateBinaryStream(java.lang.String, java.io.InputStream) Updates the designated column with a binary stream value.

updateBinaryStream (java.lang.String, java.io.InputStream, Updates the designated column with a binary stream value,
int) which will have the specified number of bytes.

updateBinaryStream(java.lang.String, java.io.InputStream, Updates the designated column with a binary stream value,
long) which will have the specified number of bytes.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateBinaryStream Method (int,
java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a binary stream value.

Syntax
public void updateBinaryStream(int columnIndex,
java.io.InputStream x)

Parameters
columnIndex
An int that indicates the column index.
x
An InputStream object.

Exceptions
SQLServerException

Remarks
This updateBinaryStream method is specified by the updateBinaryStream method in the java.sql.ResultSet
interface.
Using this method for the image , text , and ntext SQL Server data types might impact the performance.
This method passes bytes from an InputStream object to selected SQL Server binary columns such as binary,
varbinary, varbinary(max), image, xml, and udt. Updating character columns is not supported with this method.
To update character columns with an InputStream, use the updateAsciiStream method.

See Also
updateBinaryStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBinaryStream Method (int,
java.io.InputStream, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a binary stream value, which will have the specified number of bytes.

Syntax
public void updateBinaryStream(int columnIndex,
java.io.InputStream x,
int length)

Parameters
columnIndex
An int that indicates the column index.
x
An InputStream object.
length
An int that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateBinaryStream method is specified by the updateBinaryStream method in the java.sql.ResultSet
interface.
This method passes bytes from an InputStream object to selected SQL Server binary columns such as binary,
varbinary, varbinary(max), image, xml, and udt. Updating character columns is not supported with this method.
To update character columns with an InputStream, use the updateAsciiStream method.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateBinaryStream Method (int, java.io.InputStream) when the application wants to update the column from a
stream whose length is unknown.

See Also
updateBinaryStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBinaryStream Method (int,
java.io.InputStream, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a binary stream value, which will have the specified number of bytes.

Syntax
public void updateBinaryStream(int columnIndex,
java.io.InputStream x,
long length)

Parameters
columnIndex
An int that indicates the column index.
x
An InputStream object.
length
A long that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateBinaryStream method is specified by the updateBinaryStream method in the java.sql.ResultSet
interface.
This method passes bytes from an InputStream object to selected SQL Server binary columns such as binary,
varbinary, varbinary(max), image, xml, and udt. Updating character columns is not supported with this method.
To update character columns with an InputStream, use the updateAsciiStream method.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateBinaryStream Method (int, java.io.InputStream) when the application wants to update the column from a
stream whose length is unknown.

See Also
updateBinaryStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBinaryStream Method ( java.lang.String,
java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a binary stream value.

Syntax
public void updateBinaryStream(java.lang.String columnLabel,
java.io.InputStream x)

Parameters
columnLabel
A String that contains the column label.
x
An InputStream object.

Exceptions
SQLServerException

Remarks
This updateBinaryStream method is specified by the updateBinaryStream method in the java.sql.ResultSet
interface.
Using this method for the image , text , and ntext SQL Server data types might impact the performance.
This method passes bytes from an InputStream object to selected SQL Server binary columns such as binary,
varbinary, varbinary(max), image, xml, and udt. Updating character columns is not supported with this method.
To update character columns with an InputStream, use the updateAsciiStream method.

See Also
updateBinaryStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBinaryStream Method ( java.lang.String,
java.io.InputStream, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a binary stream value, which will have the specified number of bytes.

Syntax
public void updateBinaryStream(java.lang.String columnLabel,
java.io.InputStream x,
int length)

Parameters
columnLabel
AStringthat contains the column label.
x
An InputStream object.
length
An int that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateBinaryStream method is specified by the updateBinaryStream method in the java.sql.ResultSet
interface.
This method passes bytes from an InputStream object to selected SQL Server binary columns such as binary,
varbinary, varbinary(max), image, xml, and udt. Updating character columns is not supported with this method.
To update character columns with an InputStream, use the updateAsciiStream method.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateBinaryStream Method ( java.lang.String, java.io.InputStream) when the application wants to update the
column from a stream whose length is unknown.

See Also
updateBinaryStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBinaryStream Method ( java.lang.String,
java.io.InputStream, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a binary stream value, which will have the specified number of bytes.

Syntax
public void updateBinaryStream(java.lang.String columnLabel,
java.io.InputStream x,
long length)

Parameters
columnLabel
AStringthat contains the column label.
x
An InputStream object.
length
A long that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateBinaryStream method is specified by the updateBinaryStream method in the java.sql.ResultSet
interface.
This method passes bytes from an InputStream object to selected SQL Server binary columns such as binary,
varbinary, varbinary(max), image, xml, and udt. Updating character columns is not supported with this method.
To update character columns with an InputStream, use the updateAsciiStream method.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateBinaryStream Method ( java.lang.String, java.io.InputStream) when the application wants to update the
column from a stream whose length is unknown.

See Also
updateBinaryStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBlob Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with the specified object value.

Overload List
NAME DESC RIP T IO N

updateBlob (int, java.sql.Blob) Updates the designated column with a java.sql.Blob value.

updateBlob (int, java.io.InputStream) Updates the designated column using the specified input
stream.

updateBlob (int, java.io.InputStream, long) Updates the designated column using the specified input
stream, which will have the specified number of bytes.

updateBlob (java.lang.String, java.sql.Blob) Updates the designated column with a java.sql.Blob value.

updateBlob (java.lang.String, java.io.InputStream) Updates the designated column using the specified input
stream.

updateBlob (java.lang.String, java.io.InputStream, long) Updates the designated column using the specified input
stream, which will have the specified number of bytes.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateBlob Method (int, java.sql.Blob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.Blob value.

Syntax
public void updateBlob(int index,
java.sql.Blob x)

Parameters
index
An int that indicates the column index.
x
A Blob object.

Exceptions
SQLServerException

Remarks
This updateBlob method is specified by the updateBlob method in the java.sql.ResultSet interface.

See Also
updateBlob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBlob Method (int, java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified input stream.

Syntax
public void updateBlob(int columnIndex,
java.io.InputStream inputStream)

Parameters
columnIndex
An int that indicates the column index.
inputStream
An InputStream object.

Exceptions
SQLServerException

Remarks
This updateBlob method is specified by the updateBlob method in the java.sql.ResultSet interface.

See Also
updateBlob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBlob Method (int, java.io.InputStream, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified input stream, which will have the specified number of bytes.

Syntax
public void updateBlob(int columnIndex,
java.io.InputStream inputStream,
long length)

Parameters
columnIndex
An int that indicates the column index.
inputStream
An InputStream object.
length
A long that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateBlob method is specified by the updateBlob method in the java.sql.ResultSet interface.

See Also
updateBlob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBlob Method ( java.lang.String, java.sql.Blob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.Blob value.

Syntax
public void updateBlob(java.lang.String columnName,
java.sql.Blob x)

Parameters
columnName
A String that contains the column name.
x
A Blob object.

Exceptions
SQLServerException

Remarks
This updateBlob method is specified by the updateBlob method in the java.sql.ResultSet interface.

See Also
updateBlob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBlob Method ( java.lang.String,
java.io.InputStream)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified input stream.

Syntax
public void updateBlob(java.lang.String columnLabel,
java.io.InputStream inputStream)

Parameters
columnLabel
A String that contains the column label.
inputStream
An InputStream object.

Exceptions
SQLServerException

Remarks
This updateBlob method is specified by the updateBlob method in the java.sql.ResultSet interface.

See Also
updateBlob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBlob Method ( java.lang.String,
java.io.InputStream, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified input stream, which will have the specified number of bytes.

Syntax
public void updateBlob(java.lang.String columnLabel,
java.io.InputStream inputStream)
long length)

Parameters
columnLabel
A String that contains the column label.
inputStream
An InputStream object.
length
A long that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateBlob method is specified by the updateBlob method in the java.sql.ResultSet interface.

See Also
updateBlob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBoolean Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a boolean value.

Overload List
NAME DESC RIP T IO N

updateBoolean (int, boolean) Updates the designated column with a boolean value given
the column index.

updateBoolean (java.lang.String, boolean) Updates the designated column with a boolean value given
the column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateBoolean Method (int, boolean)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a boolean value given the column index.

Syntax
public void updateBoolean(int index,
boolean x)

Parameters
index
An int that indicates the column index.
x
A boolean value.

Exceptions
SQLServerException

Remarks
This updateBoolean method is specified by the updateBoolean method in the java.sql.ResultSet interface.

See Also
updateBoolean Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBoolean Method ( java.lang.String, boolean)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a boolean value given the column name.

Syntax
public void updateBoolean(java.lang.String columnName,
boolean x)

Parameters
columnName
A String that contains the column name.
x
A boolean value.

Exceptions
SQLServerException

Remarks
This updateBoolean method is specified by the updateBoolean method in the java.sql.ResultSet interface.

See Also
updateBoolean Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateByte Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a byte value.

Overload List
NAME DESC RIP T IO N

updateByte (int, byte) Updates the designated column with a byte value given the
column index.

updateByte (java.lang.String, byte) Updates the designated column with a byte value given the
column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateByte Method (int, byte)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a byte value given the column index.

Syntax
public void updateByte(int index,
byte x)

Parameters
index
An int that indicates the column index.
x
A byte value.

Exceptions
SQLServerException

Remarks
This updateByte method is specified by the updateByte method in the java.sql.ResultSet interface.

See Also
updateByte Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateByte Method ( java.lang.String, byte)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a byte value given the column name.

Syntax
public void updateByte(java.lang.String columnName,
byte x)

Parameters
columnName
A String that contains the column name.
x
A byte value.

Exceptions
SQLServerException

Remarks
This updateByte method is specified by the updateByte method in the java.sql.ResultSet interface.

See Also
updateByte Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBytes Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an array of byte values.

Overload List
NAME DESC RIP T IO N

updateBytes (int, byte[]) Updates the designated column with an array of byte values
given the column index.

updateBytes (java.lang.String, byte[]) Updates the designated column with an array of byte values
given the column name.

Remarks
In a previous version of Microsoft JDBC Driver for SQL Server, you could use SQLServerResultSet.updateBytes
to convert values between byte arrays and SQL Server data type date , time , datetime2 , or datetimeoffset .
Now, using this method with those data types will cause an exception indicating that the conversion is not
supported.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateBytes Method (int, byte)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an array of byte values given the column index.

Syntax
public void updateBytes(int index,
byte[] x)

Parameters
index
An int that indicates the column index.
x
An array of byte values.

Exceptions
SQLServerException

Remarks
This updateBytes method is specified by the updateBytes method in the java.sql.ResultSet interface.
In a previous version of Microsoft JDBC Driver for SQL Server, you could use SQLServerResultSet.updateBytes
to convert values between byte arrays and SQL Server data type date , time , datetime2 , or datetimeoffset .
Now, using this method with those data types will cause an exception indicating that the conversion is not
supported.

See Also
updateBytes Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateBytes Method ( java.lang.String, byte)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an array of byte values given the column name.

Syntax
public void updateBytes(java.lang.String columnName,
byte[] x)

Parameters
columnName
A String that contains the column name.
x
An array of byte values.

Exceptions
SQLServerException

Remarks
This updateBytes method is specified by the updateBytes method in the java.sql.ResultSet interface.
In a previous version of Microsoft JDBC Driver for SQL Server, you could use SQLServerResultSet.updateBytes
to convert values between byte arrays and SQL Server data type date , time , datetime2 , or datetimeoffset .
Now, using this method with those data types will cause an exception indicating that the conversion is not
supported.

See Also
updateBytes Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateCharacterStream Method
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value.

Overload List
NAME DESC RIP T IO N

updateCharacterStream Method (int, java.io.Reader) Updates the designated column with a character stream
value.

updateCharacterStream (int, java.io.Reader, int) Updates the designated column with a character stream
value, which will have the specified number of characters.

updateCharacterStream Method (int, java.io.Reader, long) Updates the designated column with a character stream
value, which will have the specified number of characters.

updateCharacterStream Method (java.lang.String, Updates the designated column with a character stream
java.io.Reader) value.

updateCharacterStream (java.lang.String, java.io.Reader, int) Updates the designated column with a character stream
value, which will have the specified number of characters.

updateCharacterStream Method (java.lang.String, Updates the designated column with a character stream
java.io.Reader, long) value, which will have the specified number of characters.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateCharacterStream Method (int, java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value.

Syntax
public void updateCharacterStream(int columnIndex,
java.io.Reader x)

Parameters
columnIndex
An int that indicates the column index.
x
A Reader object.

Exceptions
SQLServerException

Remarks
This updateCharacterStream method is specified by the updateCharacterStream method in the java.sql.ResultSet
interface.
This method passes Unicode characters from a Reader object to selected text and binary columns. This includes
all text columns and binar y , varbinar y , varbinar y(max) , image , and xml columns, but not udt columns.
Using this method for the image , text , and ntext SQL Server data types might impact performance.

See Also
updateCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateCharacterStream Method (int, java.io.Reader,
int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value, which will have the specified number of
characters.

Syntax
public void updateCharacterStream(int columnIndex,
java.io.Reader readerValue,
int length)

Parameters
columnIndex
An int that indicates the column index.
readerValue
A Reader object.
length
An int that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateCharacterStream method is specified by the updateCharacterStream method in the java.sql.ResultSet
interface.
This method passes Unicode characters from a Reader object to selected text and binary columns. This includes
all text columns and binar y , varbinar y , varbinar y(max) , image , and xml columns, but not udt columns.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateCharacterStream Method (int, java.io.Reader) when the application wants to update the column from a
stream whose length is unknown.

See Also
updateCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateCharacterStream Method (int, java.io.Reader,
long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value, which will have the specified number of
characters.

Syntax
public void updateCharacterStream(int columnIndex,
java.io.Reader x,
long length)

Parameters
columnIndex
An int that indicates the column index.
x
A Reader object.
length
The length of the stream.

Exceptions
SQLServerException

Remarks
This updateCharacterStream method is specified by the updateCharacterStream method in the java.sql.ResultSet
interface.
This method passes Unicode characters from a Reader object to selected text and binary columns. This includes
all text columns and binary, varbinary, varbinary(max), image, and XML columns, but not UDT columns.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateCharacterStream Method (int, java.io.Reader) when the application wants to update the column from a
stream whose length is unknown.

See Also
updateCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateCharacterStream Method ( java.lang.String,
java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value.

Syntax
public void updateCharacterStream(java.lang.String columnLabel,
java.io.Reader reader)

Parameters
columnLabel
A String that contains the column label.
reader
A Reader object.

Exceptions
SQLServerException

Remarks
This updateCharacterStream method is specified by the updateCharacterStream method in the java.sql.ResultSet
interface.
This method passes Unicode characters from a Reader object to selected text and binary columns. This includes
all text columns and binar y , varbinar y , varbinar y(max) , image , and xml columns, but not udt columns.
Using this method for the image , text , and ntext SQL Server data types might impact performance.

See Also
updateCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateCharacterStream Method ( java.lang.String,
java.io.Reader, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value, which will have the specified number of
characters.

Syntax
public void updateCharacterStream(java.lang.String columnName,
java.io.Reader readerValue,
int length)

Parameters
columnName
A String that contains the column name.
readerValue
A Reader object.
length
An int that indicates the length of the stream.

Exceptions
SQLServerException

Remarks
This updateCharacterStream method is specified by the updateCharacterStream method in the java.sql.ResultSet
interface.
This method passes Unicode characters from a Reader object to selected text and binary columns. This includes
all text columns and binar y , varbinar y , varbinar y(max) , image , and xml columns, but not udt columns.
If the length of the stream is different than that specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateCharacterStream Method ( java.lang.String, java.io.Reader) when the application wants to update the
column from a stream whose length is unknown.

See Also
updateCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateCharacterStream Method ( java.lang.String,
java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value, which will have the specified number of
characters.

Syntax
public void updateCharacterStream(java.lang.String columnLabel,
java.io.Reader reader,
long length)

Parameters
columnLabel
A String that contains the column label.
reader
A Reader object.
length
The length of the stream.

Exceptions
SQLServerException

Remarks
This updateCharacterStream method is specified by the updateCharacterStream method in the java.sql.ResultSet
interface.
This method passes Unicode characters from a Reader object to selected text and binary columns. This includes
all text columns and binary, varbinary, varbinary(max), image, and XML columns, but not UDT columns.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateCharacterStream Method ( java.lang.String, java.io.Reader) when the application wants to update the
column from a stream whose length is unknown.

See Also
updateCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateClob Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.Clob value.

Overload List
NAME DESC RIP T IO N

updateClob (int, java.sql.Clob) Updates the designated column with a java.sql.Clob value
given the column index.

updateClob Method (int, java.io.Reader) Updates the designated column using the specified Reader
object.

updateClob Method (java.lang.String, java.io.Reader, long) Updates the designated column using the specified Reader
object, which is the specified number of characters long.

updateClob (java.lang.String, java.sql.Clob) Updates the designated column with a java.sql.Clob value
given the column name.

updateClob Method (java.lang.String, java.io.Reader) Updates the designated column using the specified Reader
object.

updateClob Method (java.lang.String, java.io.Reader, long) Updates the designated column using the specified Reader
object, which is the specified number of characters long.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateClob Method (int, java.sql.Clob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.Clob value given the column index.

Syntax
public void updateClob(int columnIndex,
java.sql.Clob clobValue)

Parameters
columnIndex
An int that indicates the column index.
clobValue
A Clob object.

Exceptions
SQLServerException

Remarks
This updateClob method is specified by the updateClob method in the java.sql.ResultSet interface.

See Also
updateClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateClob Method (int, java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified Reader object.

Syntax
public void updateClob(int columnIndex,
java.io.Reader reader)

Parameters
columnIndex
An int that indicates the column index.
reader
A Reader object.

Exceptions
SQLServerException

Remarks
This updateClob method is specified by the updateClob method in the java.sql.ResultSet interface.

See Also
updateClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateClob Method (int, java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified Reader object, which is the specified number of characters
long.

Syntax
public void updateClob(int columnIndex,
java.io.Reader reader,
long length)

Parameters
columnIndex
An int that indicates the column index.
reader
A Reader object.
length
The number of characters in the parameter data.

Exceptions
SQLServerException

Remarks
This updateClob method is specified by the updateClob method in the java.sql.ResultSet interface.

See Also
updateClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateClob Method ( java.lang.String, java.sql.Clob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.Clob value given the column name.

Syntax
public void updateClob(java.lang.String columnName,
java.sql.Clob clobValue)

Parameters
columnName
A String that contains the column name.
clobValue
A Clob object.

Exceptions
SQLServerException

Remarks
This updateClob method is specified by the updateClob method in the java.sql.ResultSet interface.

See Also
updateClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateClob Method ( java.lang.String,
java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified Reader object.

Syntax
public void updateClob(java.lang.String columnLabel,
java.io.Reader reader)

Parameters
columnLabel
A String that contains the column label.
reader
A Reader object.

Exceptions
SQLServerException

Remarks
This updateClob method is specified by the updateClob method in the java.sql.ResultSet interface.

See Also
updateClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateClob Method ( java.lang.String,
java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified Reader object, which is the specified number of characters
long.

Syntax
public void updateClob(java.lang.String columnLabel,
java.io.Reader reader,
long length)

Parameters
columnLabel
A String that contains the column label.
reader
A Reader object.
length
The number of characters in the parameter data.

Exceptions
SQLServerException

Remarks
This updateClob method is specified by the updateClob method in the java.sql.ResultSet interface.

See Also
updateClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateDate Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a date value.

Overload List
NAME DESC RIP T IO N

updateDate (int, java.sql.Date) Updates the designated column with a date value given the
column index.

updateDate (java.lang.String, java.sql.Date) Updates the designated column with a date value given the
column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateDate Method (int, java.sql.Date)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a date value given the column index.

Syntax
public void updateDate(int index,
java.sql.Date x)

Parameters
index
An int that indicates the column index.
x
A date value.

Exceptions
SQLServerException

Remarks
This updateDate method is specified by the updateDate method in the java.sql.ResultSet interface.

See Also
updateDate Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateDate Method ( java.lang.String, java.sql.Date)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a date value given the column name.

Syntax
public void updateDate(java.lang.String columnName,
java.sql.Date x)

Parameters
columnName
A String that contains the column name.
x
A date value.

Exceptions
SQLServerException

Remarks
This updateDate method is specified by the updateDate method in the java.sql.ResultSet interface.

See Also
updateDate Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateDateTimeOffset (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in MicrosoftSQL Server JDBC Driver 3.0.
Updates the value of the column specified to a DateTimeOffset Class value.

Overload List
NAME DESC RIP T IO N

updateDateTimeOffset(int, microsoft.sql.DateTimeOffset) Updates the value of the column specified to the


DateTimeOffset Class value, given a zero-based column
ordinal.

updateDateTimeOffset(string, microsoft.sql.DateTimeOffset) Updates the value of the column specified to the


DateTimeOffset Class value, given a column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateDateTimeOffset(int,
microsoft.sql.DateTimeOffset) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in MicrosoftSQL Server JDBC Driver 3.0.
Updates the value of the column specified to the DateTimeOffset Class value, given a zero-based column
ordinal.

Syntax
public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x)

Parameters
index
The zero-based ordinal of a column.
x
A DateTimeOffset Class object.

Exceptions
SQLServerException

Remarks
You can retrieve a DateTimeOffset Class value with SQLServerResultSet.getDateTimeOffset.

See Also
updateDateTimeOffset (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateDateTimeOffset(string,
microsoft.sql.DateTimeOffset) (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This method was added in MicrosoftSQL Server JDBC Driver 3.0.
Updates the value of the column specified to the DateTimeOffset Class value, given a column name.

Syntax
public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x)

Parameters
columnName
The name of a column.
x
A DateTimeOffset Class object.

Exceptions
SQLServerException

Remarks
You can retrieve a DateTimeOffset Class value with SQLServerResultSet.getDateTimeOffset.

See Also
updateDateTimeOffset (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateDouble Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a double value.

Overload List
NAME DESC RIP T IO N

updateDouble (int, double) Updates the designated column with a double value given
the column index.

updateDouble (java.lang.String, double) Updates the designated column with a double value given
the column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateDouble Method (int, double)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a double value given the column index.

Syntax
public void updateDouble(int index,
double x)

Parameters
index
An int that indicates the column index.
x
A double value.

Exceptions
SQLServerException

Remarks
This updateDouble method is specified by the updateDouble method in the java.sql.ResultSet interface.

See Also
updateDouble Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateDouble Method ( java.lang.String, double)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a double value given the column name.

Syntax
public void updateDouble(java.lang.String columnName,
double x)

Parameters
columnName
A String that contains the column name.
x
A double value.

Exceptions
SQLServerException

Remarks
This updateDouble method is specified by the updateDouble method in the java.sql.ResultSet interface.

See Also
updateDouble Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateFloat Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a float value.

Overload List
NAME DESC RIP T IO N

updateFloat (int, float) Updates the designated column with a float value given the
column index.

updateFloat (java.lang.String, float) Updates the designated column with a float value given the
column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateFloat Method (int, float)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a float value given the column index.

Syntax
public void updateFloat(int index,
float x)

Parameters
index
An int that indicates the column index.
x
A float value.

Exceptions
SQLServerException

Remarks
This updateFloat method is specified by the updateFloat method in the java.sql.ResultSet interface.

See Also
updateFloat Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateFloat Method ( java.lang.String, float)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a float value given the column name.

Syntax
public void updateFloat(java.lang.String columnName,
float x)

Parameters
columnName
A String that contains the column name.
x
A float value.

Exceptions
SQLServerException

Remarks
This updateFloat method is specified by the updateFloat method in the java.sql.ResultSet interface.

See Also
updateFloat Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateInt Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an int value.

Overload List
NAME DESC RIP T IO N

updateInt (int, int) Updates the designated column with an int value given the
column index.

updateInt (java.lang.String, int) Updates the designated column with an int value given the
column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateInt Method (int, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an int value given the column index.

Syntax
public void updateInt(int index,
int x)

Parameters
index
An int that indicates the column index.
x
An int value.

Exceptions
SQLServerException

Remarks
This updateInt method is specified by the updateInt method in the java.sql.ResultSet interface.

See Also
updateInt Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateInt Method ( java.lang.String, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an int value given the column name.

Syntax
public void updateInt(java.lang.String columnName,
int x)

Parameters
columnName
A String that contains the column name.
x
An int value.

Exceptions
SQLServerException

Remarks
This updateInt method is specified by the updateInt method in the java.sql.ResultSet interface.

See Also
updateInt Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateLong Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a long value.

Overload List
NAME DESC RIP T IO N

updateLong (int, long) Updates the designated column with a long value given the
column index.

updateLong (java.lang.String, long) Updates the designated column with a long value given the
column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateLong Method (int, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a long value given the column index.

Syntax
public void updateLong(int index,
long x)

Parameters
index
An int that indicates the column index.
x
A long value.

Exceptions
SQLServerException

Remarks
This updateLong method is specified by the updateLong method in the java.sql.ResultSet interface.

See Also
updateLong Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateLong Method ( java.lang.String, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a long value given the column name.

Syntax
public void updateLong(java.lang.String columnName,
long x)

Parameters
columnName
A String that contains the column name.
x
A long value.

Exceptions
SQLServerException

Remarks
This updateLong method is specified by the updateLong method in the java.sql.ResultSet interface.

See Also
updateLong Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNCharacterStream Method
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value.

Overload List
NAME DESC RIP T IO N

updateNCharacterStream Method (int, java.io.Reader) Updates the designated column with a character stream
value.

updateNCharacterStream Method (int, java.io.Reader, long) Updates the designated column with a character stream
value, which will have the specified number of bytes.

updateNCharacterStream Method (java.lang.String, Updates the designated column with a character stream
java.io.Reader) value.

updateNCharacterStream Method (java.lang.String, Updates the designated column with a character stream
java.io.Reader, long) value, which will have the specified number of bytes.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateNCharacterStream Method (int,
java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value.

Syntax
public void updateNCharacterStream(int columnIndex,
java.io.Reader x)

Parameters
columnIndex
An int that indicates the column index.
x
A Reader object.

Exceptions
SQLServerException

Remarks
This updateNCharacterStream method is specified by the updateNCharacterStream method in the
java.sql.ResultSet interface.
This method passes Unicode characters from a Reader object to selected nchar , nvarchar(max) , ntext and xml
columns. Using this method on other data type columns will throw an exception.

See Also
updateNCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNCharacterStream Method (int,
java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value, which will have the specified number of bytes.

Syntax
public void updateNCharacterStream(int columnIndex,
java.io.Reader x,
long length)

Parameters
columnIndex
An int that indicates the column index.
x
A Reader object.
length
The length of the stream.

Exceptions
SQLServerException

Remarks
This updateNCharacterStream method is specified by the updateNCharacterStream method in the
java.sql.ResultSet interface.
This method passes Unicode characters from a Reader object to selected nchar , nvarchar(max) , ntext , and
xml columns. Using this method on other data type columns will throw an exception.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateNCharacterStream Method (int, java.io.Reader) when the application wants to update the column from a
stream whose length is unknown.

See Also
updateNCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNCharacterStream Method ( java.lang.String,
java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value.

Syntax
public void updateNCharacterStream(java.lang.String columnLabel,
java.io.Reader reader)

Parameters
columnLabel
A String that contains the column label.
reader
A Reader object.

Exceptions
SQLServerException

Remarks
This updateNCharacterStream method is specified by the updateNCharacterStream method in the
java.sql.ResultSet interface.
This method passes Unicode characters from a Reader object to selected nchar , nvarchar(max) , ntext and xml
columns. Using this method on other data type columns will throw an exception.

See Also
updateNCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNCharacterStream Method ( java.lang.String,
java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a character stream value, which will have the specified number of bytes.

Syntax
public void updateNCharacterStream(java.lang.String columnLabel,
java.io.Reader reader,
long length)

Parameters
columnLabel
A String that contains the column label.
reader
A Reader object.
length
The length of the stream.

Exceptions
SQLServerException

Remarks
This updateNCharacterStream method is specified by the updateNCharacterStream method in the
java.sql.ResultSet interface.
This method passes Unicode characters from a Reader object to selected nchar , nvarchar(max) , ntext , and
xml columns. Using this method on other data type columns will throw an exception.
If the length of the stream is different than what is specified in the length parameter, the JDBC driver throws an
exception when the row is updated or inserted.
If the length of the stream is unknown, the length parameter may be set to -1 to indicate that the driver should
accept the stream regardless of its length. With sqljdbc4.jar, we recommend that you use the JDBC 4.0 method
updateNCharacterStream Method ( java.lang.String, java.io.Reader) when the application wants to update the
column from a stream whose length is unknown.

See Also
updateNCharacterStream Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNClob Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with the specified object value.

Overload List
NAME DESC RIP T IO N

updateNClob Method (int, java.sql.NClob) Updates the designated column with an NClob value.

updateNClob Method (java.lang.String, java.sql.NClob) Updates the designated column with an NClob value.

updateNClob Method (int, java.io.Reader) Updates the designated column using the specified Reader
object.

updateNClob Method (int, java.io.Reader, long) Updates the designated column using the specified Reader
object, which is the specified number of characters long.

updateNClob Method (java.lang.String, java.io.Reader) Updates the designated column using the specified Reader
object.

updateNClob Method (java.lang.String, java.io.Reader, long) Updates the designated column using the specified Reader
object, which is the specified number of characters long.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateNClob Method (int, java.sql.NClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a NClob value.

Syntax
public void updateNClob(int columnIndex,
java.sql.NClob nClob)

Parameters
columnIndex
An int that indicates the column index.
nClob
An NClob object.

Exceptions
SQLServerException

Remarks
This updateNClob method is specified by the updateNClob method in the java.sql.ResultSet interface.
This method is supported only on nvarchar(max) , ntext , and xml columns. Using this method on any other
data types will cause an exception to be thrown.

See Also
updateNClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNClob Method (int, java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified Reader object.

Syntax
public void updateNClob(int columnIndex,
java.io.Reader reader)

Parameters
columnIndex
An int that indicates the column index.
reader
A Reader object.

Exceptions
SQLServerException

Remarks
This updateNClob method is specified by the updateNClob method in the java.sql.ResultSet interface.
This method is supported only on nvarchar(max) , ntext , and xml columns. Using this method on any other
data types will cause an exception to be thrown.

See Also
updateNClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNClob Method (int, java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified Reader object, which is the specified number of characters
long.

Syntax
public void updateNClob(int columnIndex,
java.io.Reader reader,
long length)

Parameters
columnIndex
An int that indicates the column index.
reader
A Reader object.
length
The number of characters in the parameter data.

Exceptions
SQLServerException

Remarks
This updateNClob method is specified by the updateNClob method in the java.sql.ResultSet interface.
This method is supported only on nvarchar(max) , ntext , and xml columns. Using this method on any other
data types will cause an exception to be thrown.

See Also
updateNClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNClob Method ( java.lang.String,
java.sql.NClob)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an NClob value.

Syntax
public void updateNClob(java.lang.String columnLabel,
java.sql.NClob x)

Parameters
columnLabel
A String that indicates the column label.
x
An NClob object.

Exceptions
SQLServerException

Remarks
This updateNClob method is specified by the updateNClob method in the java.sql.ResultSet interface.
This method is supported only on nvarchar(max) , ntext , and xml columns. Using this method on any other
data types will cause an exception to be thrown.

See Also
updateNClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNClob Method ( java.lang.String,
java.io.Reader)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified Readerobject.

Syntax
public void updateNClob(java.lang.String columnLabel,
java.io.Reader reader)

Parameters
columnLabel
A String that indicates the column label.
reader
A Reader object.

Exceptions
SQLServerException

Remarks
This updateNClob method is specified by the updateNClob method in the java.sql.ResultSet interface.
This method is supported only on nvarchar(max) , ntext , and xml columns. Using this method on any other
data types will cause an exception to be thrown.

See Also
updateNClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNClob Method ( java.lang.String,
java.io.Reader, long)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column using the specified Reader object, which is the specified number of characters
long.

Syntax
public void updateNClob(java.lang.String columnLabel,
java.io.Reader reader,
long length)

Parameters
columnLabel
A String that indicates the column label.
reader
A Reader object.
length
The number of characters in the parameter data.

Exceptions
SQLServerException

Remarks
This updateNClob method is specified by the updateNClob method in the java.sql.ResultSet interface.
This method is supported only on nvarchar(max) , ntext , and xml columns. Using this method on any other
data types will cause an exception to be thrown.

See Also
updateNClob Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNString Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a String value.

Overload List
NAME DESC RIP T IO N

updateNString Method (int, java.lang.String) Updates the designated column with a String value using
the specified column index.

updateNString Method (java.lang.String, java.lang.String) Updates the designated column with a String value using
the specified column label.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateNString Method (int, java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a String value using the specified column index.

Syntax
public void updateNString(int columnIndex,
java.lang.String nString)

Parameters
columnIndex
An int that indicates the column index.
nString
A String object.

Exceptions
SQLServerException

Remarks
This updateNString method is specified by the updateNString method in the java.sql.ResultSet interface.
This method passes Java String to selected nchar , nvarchar(max) , ntext , and xml columns. Using this method
on other data type columns will throw an exception.

See Also
updateNString Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNString Method ( java.lang.String,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a String value using the specified column label.

Syntax
public void updateNString(java.lang.String columnLabel,
java.lang.String nString)

Parameters
columnLabel
A String that contains the column label.
nString
A String object.

Exceptions
SQLServerException

Remarks
This updateNString method is specified by the updateNString method in the java.sql.ResultSet interface.
This method passes Java String to selected nchar , nvarchar(max) , ntext , and xml columns. Using this method
on other data type columns will throw an exception.

See Also
updateNString Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNull Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a null value.

Overload List
NAME DESC RIP T IO N

updateNull (int) Updates the designated column with a null value given the
column index.

updateNull (java.lang.String) Updates the designated column with a null value given the
column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateNull Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a null value given the column index.

Syntax
public void updateNull(int index)

Parameters
index
An int that indicates the column index.

Exceptions
SQLServerException

Remarks
This updateNull method is specified by the updateNull method in the java.sql.ResultSet interface.

See Also
updateNull Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateNull Method ( java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a null value given the column name.

Syntax
public void updateNull(java.lang.String columnName)

Parameters
columnName
A String that contains the column name.

Exceptions
SQLServerException

Remarks
This updateNull method is specified by the updateNull method in the java.sql.ResultSet interface.

See Also
updateNull Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateObject Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an Object value.

Overload List
NAME DESC RIP T IO N

updateObject (int, java.lang.Object) Updates the designated column with an Object value given
the column index.

updateObject (int, java.lang.Object, int) Updates the designated column with an Object value given
the column index and scale.

updateObject (java.lang.String, java.lang.Object) Updates the designated column with an Object value given
the column name.

updateObject (java.lang.String, java.lang.Object, int) Updates the designated column with an Object value given
the column name and scale.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateObject Method (int, java.lang.Object)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an Object value given the column index.

Syntax
public void updateObject(int index,
java.lang.Object obj)

Parameters
index
An int that indicates the column index.
obj
An Object value.

Exceptions
SQLServerException

Remarks
This updateObject method is specified by the updateObject method in the java.sql.ResultSet interface.

See Also
updateObject Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateObject Method (int, java.lang.Object, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an Object value given the column index and scale.

Syntax
public void updateObject(int index,
java.lang.Object x,
int scale)

Parameters
index
An int that indicates the column index.
obj
An Object value.
scale
For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types, this is the number of digits after the decimal point.
For all other types, this value is ignored.

Exceptions
SQLServerException

See Also
updateObject Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateObject Method ( java.lang.String,
java.lang.Object)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an Object value given the column name.

Syntax
public void updateObject(java.lang.String columnName,
java.lang.Object x)

Parameters
columnName
A String that contains the column name.
obj
An Object value.

Exceptions
SQLServerException

Remarks
This updateObject method is specified by the updateObject method in the java.sql.ResultSet interface.

See Also
updateObject Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateObject Method ( java.lang.String,
java.lang.Object, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with an Object value given the column name and scale.

Syntax
public void updateObject(java.lang.String columnName,
java.lang.Object x,
int scale)

Parameters
columnName
A String that contains the column name.
obj
An Object value.
scale
For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types, this is the number of digits after the decimal point.
For all other types this value is ignored.

Exceptions
SQLServerException

Remarks
This updateObject method is specified by the updateObject method in the java.sql.ResultSet interface.

See Also
updateObject Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateRef Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.Ref value.

Overload List
NAME DESC RIP T IO N

updateRef (int, java.sql.Ref) Updates the designated column with a java.sql.Ref value
given the column index.

updateRef (java.lang.String, java.sql.Ref) Updates the designated column with a java.sql.Ref value
given the column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateRef Method (int, java.sql.Ref )
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.Ref value given the column index.

Syntax
public void updateRef(int columnIndex,
java.sql.Ref x)

Parameters
columnIndex
An int that indicates the column index.
x
A Ref object.

Exceptions
SQLServerException

Remarks
This updateRef method is specified by the updateRef method in the java.sql.ResultSet interface.

See Also
updateRef Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateRef Method ( java.lang.String, java.sql.Ref )
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.Ref value given the column name.

Syntax
public void updateRef(java.lang.String columnName,
java.sql.Ref x)

Parameters
columnName
A String that contains the column name.
x
A Ref object.

Exceptions
SQLServerException

Remarks
This updateRef method is specified by the updateRef method in the java.sql.ResultSet interface.

See Also
updateRef Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateRow Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the underlying database with the new contents of the current row of this SQLServerResultSet object.

Syntax
public void updateRow()

Exceptions
SQLServerException

Remarks
This updateRow method is specified by the updateRow method in the java.sql.ResultSet interface.
This method cannot be called when the cursor is on the insert row.
If this method is called when no column values have changed, an exception will be thrown.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateShort Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a shor t value.

Overload List
NAME DESC RIP T IO N

updateShort (int, short) Updates the designated column with a shor t value given
the column index.

updateShort (java.lang.String, short) Updates the designated column with a shor t value given
the column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateShort Method (int, short)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a shor t value given the column index.

Syntax
public void updateShort(int index,
short x)

Parameters
index
An int that indicates the column index.
x
A shor t value.

Exceptions
SQLServerException

Remarks
This updateShort method is specified by the updateShort method in the java.sql.ResultSet interface.

See Also
updateShort Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateShort Method ( java.lang.String, short)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a shor t value given the column name.

Syntax
public void updateShort(java.lang.String columnName,
short x)

Parameters
columnName
A String that contains the column name.
x
A shor t value.

Exceptions
SQLServerException

Remarks
This updateShort method is specified by the updateShort method in the java.sql.ResultSet interface.

See Also
updateShort Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateSQLXML Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a SQLXML value.

Overload List
NAME DESC RIP T IO N

updateSQLXML Method (int, java.sql.SQLXML) Updates the designated column with a SQLXML value.

updateSQLXML Method (java.lang.String, java.sql.SQLXML) Updates the designated column with a SQLXML value.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateSQLXML Method (int, java.sql.SQLXML)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.SQLXML value

Syntax
public void updateSQLXML(int columnIndex,
java.sql.SQLXML xmlObject)

Parameters
columnIndex
An int that indicates the column index.
xmlObject
A SQLXML object.

Exceptions
SQLServerException

Remarks
This updateSQLXML method is specified by the updateSQLXML method in the java.sql.ResultSet interface.

See Also
updateSQLXML Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateSQLXML Method ( java.lang.String,
java.sql.SQLXML)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a java.sql.SQLXML value.

Syntax
public void updateSQLXML(java.lang.String columnLabel,
java.sql.SQLXML xmlObject)

Parameters
columnLabel
A String that indicates the column label.
xmlObject
A SQLXML object.

Exceptions
SQLServerException

Remarks
This updateSQLXML method is specified by the updateSQLXML method in the java.sql.ResultSet interface.

See Also
updateSQLXML Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateString Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a String value.

Overload List
NAME DESC RIP T IO N

updateString (int, java.lang.String) Updates the designated column with a String value given
the column index.

updateString (java.lang.String, java.lang.String) Updates the designated column with a String value given
the column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateString Method (int, java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a String value given the column index.

Syntax
public void updateString(int index,
java.lang.String x)

Parameters
index
An int that indicates the column index.
x
A String object.

Exceptions
SQLServerException

Remarks
This updateString method is specified by the updateString method in the java.sql.ResultSet interface.

See Also
updateString Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateString Method ( java.lang.String,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a String value given the column name.

Syntax
public void updateString(java.lang.String columnName,
java.lang.String x)

Parameters
columnName
A String that contains the column name.
x
A String object.

Exceptions
SQLServerException

Remarks
This updateString method is specified by the updateString method in the java.sql.ResultSet interface.

See Also
updateString Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateTime Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a time value.

Overload List
NAME DESC RIP T IO N

updateTime (int, java.sql.Time) Updates the designated column with a time value given the
column index.

updateTime (java.lang.String, java.sql.Time) Updates the designated column with a time value given the
column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateTime Method (int, java.sql.Time)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a time value given the column index.

Syntax
public void updateTime(int index,
java.sql.Time x)

Parameters
index
An int that indicates the column index.
x
A time value.

Exceptions
SQLServerException

Remarks
This updateTime method is specified by the updateTime method in the java.sql.ResultSet interface.

See Also
updateTime Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateTime Method ( java.lang.String, java.sql.Time)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a time value given the column name.

Syntax
public void updateTime(java.lang.String columnName,
java.sql.Time x)

Parameters
columnName
A String that contains the column name.
x
A time value.

Exceptions
SQLServerException

Remarks
This updateTime method is specified by the updateTime method in the java.sql.ResultSet interface.

See Also
updateTime Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateTimestamp Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a timestamp value.

Overload List
NAME DESC RIP T IO N

updateTimestamp (int, java.sql.Timestamp) Updates the designated column with a timestamp value
given the column index.

updateTimestamp (java.lang.String, java.sql.Timestamp) Updates the designated column with a timestamp value
given the column name.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
updateTimestamp Method (int, java.sql.Timestamp)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a timestamp value given the column index.

Syntax
public void updateTimestamp(int index,
java.sql.Timestamp x)

Parameters
index
An int that indicates the column index.
x
A timestamp value.

Exceptions
SQLServerException

Remarks
This updateTimestamp method is specified by the updateTimestamp method in the java.sql.ResultSet interface.

See Also
updateTimestamp Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
updateTimestamp Method ( java.lang.String,
java.sql.Timestamp)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Updates the designated column with a timestamp value given the column name.

Syntax
public void updateTimestamp(java.lang.String columnName,
java.sql.Timestamp x)

Parameters
columnName
A String that contains the column name.
x
A timestamp value.

Exceptions
SQLServerException

Remarks
This updateTimestamp method is specified by the updateTimestamp method in the java.sql.ResultSet interface.

See Also
updateTimestamp Method (SQLServerResultSet)
SQLServerResultSet Members
SQLServerResultSet Class
wasNull Method (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Verifies if the last value read was a null value.

Syntax
public boolean wasNull()

Return Value
true if the last value read was null. Otherwise, false .

Exceptions
SQLServerException

Remarks
This wasNull method is specified by the wasNull method in the java.sql.ResultSet interface.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
SQLServerResultSet Fields
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerResultSet, see SQLServerResultSet Members.

See Also
SQLServerResultSet Class
CONCUR_SS_OPTIMISTIC_CC Field
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to specify a SQL Server read/write optimistic concurrency type with no row locks.

Syntax
public static final int CONCUR_SS_OPTIMISTIC_CC

Field Value
An int value of 1008.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
CONCUR_SS_OPTIMISTIC_CCVAL Field
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to specify a SQL Server read/write optimistic concurrency type with no row locks.

Syntax
public static final int CONCUR_SS_OPTIMISTIC_CCVAL

Field Value
An int value of 1010.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
CONCUR_SS_SCROLL_LOCKS Field
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to specify a SQL Server read/write optimistic concurrency type with row locks.

Syntax
public static final int CONCUR_SS_SCROLL_LOCKS

Field Value
An int value of 1009.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
TYPE_SS_DIRECT_FORWARD_ONLY Field
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to specify a SQL Server fast forward-only, read-only cursor type.

Syntax
public static final int TYPE_SS_DIRECT_FORWARD_ONLY

Field Value
An int value of 2003.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
TYPE_SS_SCROLL_DYNAMIC Field
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to specify a SQL Server dynamic cursor type.

Syntax
public static final int TYPE_SS_SCROLL_DYNAMIC

Field Value
An int value of 1006.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
TYPE_SS_SCROLL_KEYSET Field
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to specify a SQL Server keyset cursor type.

Syntax
public static final int TYPE_SS_SCROLL_KEYSET

Field Value
An int value of 1005.

See Also
SQLServerResultSet Class
TYPE_SS_SCROLL_STATIC Field
(SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to specify a SQL Server static cursor type.

Syntax
public static final int TYPE_SS_SCROLL_STATIC

Field Value
An int value of 1004.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY
Field (SQLServerResultSet)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to specify a SQL Server fast forward-only, read-only cursor type.

Syntax
public static final int TYPE_SS_SERVER_CURSOR_FORWARD_ONLY

Field Value
An int value of 2004.

See Also
SQLServerResultSet Members
SQLServerResultSet Class
SQLServerResultSetMetaData Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents the metadata of the columns that are contained within a result set.
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: java.sql.ResultSetMetaData

Syntax
public final class SQLServerResultSetMetaData

See Also
SQLServerResultSetMetaData Members
JDBC Driver API Reference
SQLServerResultSetMetaData Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerResultSetMetaData class.

Constructors
None.

Fields
None.

Inherited Fields
NAME DESC RIP T IO N

java.sql.ResultSetMetaData columnNoNulls, columnNullable, columnNullableUnknown

Methods
NAME DESC RIP T IO N

getCatalogName Gets the catalog name for the table that includes the
designated column.

getColumnClassName Returns the fully-qualified name of the Java class whose


instances are manufactured if the getObject method of the
SQLServerResultSet class is called to retrieve a value from
the column.

getColumnCount Returns the number of columns in the result set.

getColumnDisplaySize Returns the normal maximum width, in characters, of the


designated column.

getColumnLabel Gets the title that is suggested for use in printouts and
displays of the designated column.

getColumnName Get the name of the designated column.

getColumnType Retrieves the SQL type of the designated column.

getColumnTypeName Retrieves the database-specific type name of the designated


column.

getPrecision Get the number of decimal digits for the designated column.
NAME DESC RIP T IO N

getScale Gets the number of digits to the right of the decimal point
for the designated column.

getSchemaName Gets the table schema name for the designated column.

getTableName Gets the table name of the designated column.

isAutoIncrement Indicates whether the designated column is automatically


numbered, which makes it read-only.

isCaseSensitive Indicates whether a column is case sensitive.

isCurrency Indicates whether the designated column is a cash value.

isDefinitelyWritable Indicates whether a write on the designated column will


definitely succeed.

isNullable Indicates the nullability of values in the designated column.

isReadOnly Indicates whether the designated column is definitely not


writable.

isSearchable Indicates whether the designated column can be used in an


SQL WHERE clause.

isSigned Indicates whether values in the designated column are


signed numbers.

isSparseColumnSet Indicates if a column in a result set is a sparse column set.

isWritable Indicates whether it is possible for a write on the designated


column to succeed.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

java.sql.Wrapper isWrapperFor, unwrap

See Also
SQLServerResultSetMetaData Class
SQLServerResultSetMetaData Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerResultSetMetaData, see SQLServerResultSetMetaData
Members.
getCatalogName Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the catalog name for the table that includes the designated column.

Syntax
public java.lang.String getCatalogName(int column)

Parameters
column
An int that indicates the column index.

Return Value
A String that contains the catalog name.

Exceptions
SQLServerException

Remarks
This getCatalogName method is specified by the getCatalogName method in the java.sql.ResultSetMetaData
interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getColumnClassName Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the fully-qualified name of the Java class whose instances are manufactured if the getObject method of
the SQLServerResultSet class is called to retrieve a value from the column.

Syntax
public java.lang.String getColumnClassName(int column)

Parameters
column
An int that indicates the column index.

Return Value
A String that contains the fully-qualified name of the class.

Exceptions
SQLServerException

Remarks
This getColumnClassName method is specified by the getColumnClassName method in the
java.sql.ResultSetMetaData interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getColumnCount Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the number of columns in the result set.

Syntax
public int getColumnCount()

Return Value
An int that indicates the number of columns.

Exceptions
SQLServerException

Remarks
This getColumnCount method is specified by the getColumnCount method in the java.sql.ResultSetMetaData
interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getColumnDisplaySize Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns the normal maximum width, in characters, for the designated column.

Syntax
public int getColumnDisplaySize(int column)

Parameters
column
An int that indicates the column index.

Return Value
An int that indicates the maximum width. If the width is not known, returns 0.

Exceptions
SQLServerException

Remarks
This getColumnDisplaySize method is specified by the getColumnDisplaySize method in the
java.sql.ResultSetMetaData interface.
Microsoft SQL Server JDBC Driver 3.0 has behavior changes in the COLUMN_SIZE column. See
SQLServerDatabaseMetaData.getColumns for more information.

See Also
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getColumnLabel Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the suggested title, for use in printouts and displays, of the designated column.

Syntax
public java.lang.String getColumnLabel(int column)

Parameters
column
An int that indicates the column index.

Return Value
A String that contains the title of the column.

Exceptions
SQLServerException

Remarks
This getColumnLabel method is specified by the getColumnLabel method in the java.sql.ResultSetMetaData
interface.
This method returns the alias name of the column. If that is not available, this method returns the column name.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getColumnName Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the name of the designated column.

Syntax
public java.lang.String getColumnName(int column)

Parameters
column
An int that indicates the column index.

Return Value
A String that contains the column name.

Exceptions
SQLServerException

Remarks
This getColumnName method is specified by the getColumnName method in the java.sql.ResultSetMetaData
interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getColumnType Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the SQL type of the designated column.

Syntax
public int getColumnType(int column)

Parameters
column
An int that indicates the column index.

Return Value
An int that indicates the JDBC type as defined in java.sql.Types.

Exceptions
SQLServerException

Remarks
This getColumnType method is specified by the getColumnType method in the java.sql.ResultSetMetaData
interface.
Microsoft SQL Server JDBC Driver 3.0 has behavior changes in the DATA_TYPE column. See
SQLServerDatabaseMetaData.getColumns for more information.

See Also
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getColumnTypeName Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the database-specific type name for the designated column.

Syntax
public java.lang.String getColumnTypeName(int column)

Parameters
column
An int that indicates the column index.

Return Value
A String that contains the server name for the column.

Exceptions
SQLServerException

Remarks
This getColumnTypeName method is specified by the getColumnTypeName method in the
java.sql.ResultSetMetaData interface.
Microsoft SQL Server JDBC Driver 3.0 has behavior changes in the TYPE_NAME column. See
SQLServerDatabaseMetaData.getColumns for more information.

See Also
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getPrecision Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Get the designated column's number of decimal digits.

Syntax
public int getPrecision(int column)

Parameters
column
An int that indicates the column index.

Return Value
An int that indicates the precision of the column.

Exceptions
SQLServerException

Remarks
This getPrecision method is specified by the getPrecision method in the java.sql.ResultSetMetaData interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getScale Method (SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the number of digits to the right of the decimal point for the designated column.

Syntax
public int getScale(int column)

Parameters
column
An int that indicates the column index.

Return Value
An int that indicates the scale of the column.

Exceptions
SQLServerException

Remarks
This getScale method is specified by the getScale method in the java.sql.ResultSetMetaData interface.
Microsoft SQL Server JDBC Driver 3.0 has behavior changes in the DECIMAL_DIGITS column. See
SQLServerDatabaseMetaData.getColumns for more information.

See Also
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getSchemaName Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the table schema name for the designated column.

Syntax
public java.lang.String getSchemaName(int column)

Parameters
column
An int that indicates the column index.

Return Value
A String that contains the schema name.

Exceptions
SQLServerException

Remarks
This getSchemaName method is specified by the getSchemaName method in the java.sql.ResultSetMetaData
interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
getTableName Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the table name of the designated column.

Syntax
public java.lang.String getTableName(int column)

Parameters
column
An int that indicates the column index.

Return Value
A String that contains the table name.

Exceptions
SQLServerException

Remarks
This getTableName method is specified by the getTableName method in the java.sql.ResultSetMetaData
interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isAutoIncrement Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether the designated column is automatically numbered, which makes it read-only.

Syntax
public boolean isAutoIncrement(int column)

Parameters
column
An int that indicates the column index.

Return Value
true if the column is automatically numbered. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isAutoIncrement method is specified by the isAutoIncrement method in the java.sql.ResultSetMetaData
interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isCaseSensitive Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether a column is case-sensitive.

Syntax
public boolean isCaseSensitive(int column)

Parameters
column
An int that indicates the column index.

Return Value
true if the column is case sensitive. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isCaseSensitive method is specified by the isCaseSensitive method in the java.sql.ResultSetMetaData
interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isCurrency Method (SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether the designated column is a cash value.

Syntax
public boolean isCurrency(int column)

Parameters
column
An int that indicates the column index.

Return Value
true if the column is a cash value. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isCurrency method is specified by the isCurrency method in the java.sql.ResultSetMetaData interface.
This method will return true only with SQL Server money and smallmoney data types.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isDefinitelyWritable Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether a write on the designated column will definitely succeed.

Syntax
public boolean isDefinitelyWritable(int column)

Parameters
column
An int that indicates the column index.

Return Value
true if the column write will definitely succeed. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isDefinitelyWritable method is specified by the isDefinitelyWritable method in the
java.sql.ResultSetMetaData interface.

NOTE
When using the Microsoft JDBC Driver for SQL Server with a SQL Server database, this method will always return false.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isNullable Method (SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates the nullability of values in the designated column.

Syntax
public int isNullable(int column)

Parameters
column
An int that indicates the column index.

Return Value
true if the column can be null. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isNullable method is specified by the isNullable method in the java.sql.ResultSetMetaData interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isReadOnly Method (SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether the designated column is definitely not writable.

Syntax
public boolean isReadOnly(int column)

Parameters
column
An int that indicates the column index.

Return Value
true if the column is read-only. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isReadOnly method is specified by the isReadOnly method in the java.sql.ResultSetMetaData interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isSearchable Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether the designated column can be used in an SQL WHERE clause.

Syntax
public boolean isSearchable(int column)

Parameters
column
An int that indicates the column index.

Return Value
true if the column the column can be used in a WHERE clause. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isSearchable method is specified by the isSearchable method in the java.sql.ResultSetMetaData interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isSigned Method (SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether values in the designated column are signed numbers.

Syntax
public boolean isSigned(int column)

Parameters
column
An int that indicates the column index.

Return Value
true if the column contains signed numbers. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isSigned method is specified by the isSigned method in the java.sql.ResultSetMetaData interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isSparseColumnSet Method
(SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates if a column in a result set is a sparse column set.

Syntax
public boolean isSparseColumnSet(int column)

Parameters
column
The (one-based) index of the column.

Return Value
true if a column in a result set is a sparse column set, otherwise false .

Remarks
This method does not retrieve information from the database.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
isWritable Method (SQLServerResultSetMetaData)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether it is possible for a write on the designated column to succeed.

Syntax
public boolean isWritable(int column)

Parameters
column
An int that indicates the column index.

Return Value
true if writes will succeed on the column. Otherwise, false .

Exceptions
SQLServerException

Remarks
This isWritable method is specified by the isWritable method in the java.sql.ResultSetMetaData interface.

See Also
SQLServerResultSetMetaData Methods
SQLServerResultSetMetaData Members
SQLServerResultSetMetaData Class
SQLServerSavepoint Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents the checkpoint to which a transaction can be rolled back.
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: java.sql.Savepoint

Syntax
public class SQLServerSavepoint

See Also
SQLServerSavepoint Members
JDBC Driver API Reference
SQLServerSavepoint Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerException class.

Constructors
NAME DESC RIP T IO N

SQLServerSavepoint (SQLServerConnection, Initializes a new instance of the SQLServerException class


java.lang.StringName) based on the given connection and name.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

getLabel Gets the name of the savepoint label.

getSavepointId Gets the ID of the savepoint.

getSavepointName Gets the name of the savepoint.

isNamed Verifies if the savepoint has been named.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

See Also
SQLServerSavepoint Class
SQLServerSavepoint Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerException, see SQLServerSavepoint Members.
SQLServerSavepoint Constructor
(SQLServerConnection, java.lang.StringName)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerException class based on the given connection and name.

Syntax
public SQLServerSavepoint(SQLServerConnection con,
java.lang.String sName)

Parameters
con
A SQLServerConnection object.
sName
A String that contains the name of the savepoint.

See Also
SQLServerSavepoint Constructors
SQLServerSavepoint Members
SQLServerSavepoint Class
SQLServerSavepoint Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerException, see SQLServerSavepoint Members.
getLabel Method (SQLServerSavepoint)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the name of the savepoint label.

Syntax
public java.lang.String getLabel()

Return Value
A String that contains the name of the savepoint label.

See Also
SQLServerSavepoint Methods
SQLServerSavepoint Members
SQLServerSavepoint Class
getSavepointId Method (SQLServerSavepoint)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the ID of the savepoint.

Syntax
public int getSavepointId()

Return Value
An int value.

Exceptions
SQLServerException

Remarks
This getSavepointId method is specified by the getSavepointId method in the java.sql.Savepoint interface.

See Also
SQLServerSavepoint Methods
SQLServerSavepoint Members
SQLServerSavepoint Class
getSavepointName Method (SQLServerSavepoint)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gets the name of the savepoint.

Syntax
public java.lang.String getSavepointName()

Return Value
A String that contains the name of the savepoint.

Exceptions
SQLServerException

Remarks
This getSavepointName method is specified by the getSavepointName method in the java.sql.Savepoint
interface.

See Also
SQLServerSavepoint Methods
SQLServerSavepoint Members
SQLServerSavepoint Class
isNamed Method (SQLServerSavepoint)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Verifies if the savepoint has been named.

Syntax
public boolean isNamed()

Return Value
true is the savepoint is named. Otherwise, false .

See Also
SQLServerSavepoint Methods
SQLServerSavepoint Members
SQLServerSavepoint Class
SQLServerStatement Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents the basic implementation of JDBC statement functionality.
Package: com.microsoft.sqlserver.jdbc
Implements: ISQLServerStatement

Syntax
public class SQLServerStatement

Remarks
The SQLServerStatement class also provides a number of base class implementation methods for the JDBC
prepared statement and callable statements. The basic role of the SQLServerStatement class is to run SQL
statements, and then return update counts and result sets to the user application.
This class supports unwrapping to SQLServerStatement class, the ISQLServerStatement interface, and the
java.sql.Statement interface. For more information, see Wrappers and Interfaces.

See Also
SQLServerStatement Members
JDBC Driver API Reference
SQLServerStatement Members
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerStatement class.

Constructors
None.

Fields
None.

Inherited Fields
NAME DESC RIP T IO N

java.sql.Statement CLOSE_ALL_RESULTS, CLOSE_CURRENT_RESULT,


EXECUTE_FAILED, KEEP_CURRENT_RESULT,
NO_GENERATED_KEYS, RETURN_GENERATED_KEYS,
SUCCESS_NO_INFO

Methods
NAME DESC RIP T IO N

addBatch Adds the given SQL command to the current list of


commands for this SQLServerStatement object.

cancel Cancels the SQL statement that is currently being run by


this SQLServerStatement object.

clearBatch Empties the current list of SQL commands for this


SQLServerStatement object.

clearWarnings Clears all the warnings that are reported on this


SQLServerStatement object.

close Releases this SQLServerStatement object's database and


JDBC resources immediately instead of waiting for them to
be automatically released.

execute Runs the given SQL statement, which can return multiple
results.

executeBatch Submits a batch of commands to the database to be run. If


all commands run successfully, returns an array of update
counts.
NAME DESC RIP T IO N

executeQuery Runs the given SQL statement and returns a single


SQLServerResultSet object.

executeUpdate Runs the given SQL statement, which can be an INSERT,


UPDATE, MERGE, or DELETE statement; or an SQL statement
that returns nothing, such as an SQL DDL statement.

getConnection Retrieves the SQLServerConnection object that produced


this SQLServerStatement object.

getFetchDirection Retrieves the direction for fetching rows from database


tables that is the default for result sets generated from this
SQLServerStatement object.

getFetchSize Retrieves the number of result set rows that is the default
fetch size for result set objects generated from this
SQLServerStatement object.

getGeneratedKeys Retrieves any auto-generated keys that are created as a


result of running this SQLServerStatement object.

getMaxFieldSize Retrieves the maximum number of bytes that can be


returned for character and binary column values in a
SQLServerResultSet object that is produced by this
SQLServerStatement object.

getMaxRows Retrieves the maximum number of rows that a


SQLServerResultSet object that is produced by this
SQLServerStatement object can contain.

getMoreResults Moves to the next result of this SQLServerStatement object.

getQueryTimeout Retrieves the number of seconds the Microsoft JDBC Driver


for SQL Server will wait for this SQLServerStatement object
to run.

getResponseBuffering Retrieves the response buffering mode for this


SQLServerStatement object.

getResultSet Retrieves the current result as a SQLServerResultSet object.

getResultSetConcurrency Retrieves the result set concurrency for SQLServerResultSet


objects that are generated by this SQLServerStatement
object.

getResultSetHoldability Retrieves the result set holdability for SQLServerResultSet


objects that are generated by this SQLServerStatement
object.

getResultSetType Retrieves the result set type for SQLServerResultSet objects


that are generated by this SQLServerStatement object.

getUpdateCount Retrieves the current result as an update count.


NAME DESC RIP T IO N

getWarnings Retrieves the first warning that is reported by calls on this


SQLServerStatement object.

isClosed Indicates whether this SQLServerStatement object has been


closed.

isPoolable Returns a value indicating if a statement can be added to the


user-provided statement pool.

isWrapperFor Indicates whether this statement object is a wrapper for the


specified interface.

setCursorName Sets the SQL cursor name to the given String, which will be
used by subsequent execute methods.

setEscapeProcessing Sets the escape processing mode.

setFetchDirection Gives the JDBC driver a hint as to the direction in which


result set rows should be processed.

setFetchSize Gives the JDBC driver a hint as to the number of rows that
should be fetched from the database when more rows are
needed.

setMaxFieldSize Sets the limit for the maximum number of bytes in a


SQLServerResultSet column storing character or binary
values to the given number of bytes.

setMaxRows Sets the limit for the maximum number of rows that any
SQLServerResultSet object can contain to the given number.

setPoolable Requests that a statement be pooled or not pooled.

setQueryTimeout Sets the number of seconds the driver will wait for a
SQLServerStatement object to run to the given number of
seconds.

setResponseBuffering Sets the response buffering mode for this


SQLServerStatement object to case-insensitive String full or
adaptive .

unwrap Returns an object that implements the specified interface to


allow access to the Microsoft JDBC Driver for SQL Server-
specific methods.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, getClass, hashCode, notify, notifyAll, toString,


wait

java.sql.Wrapper isWrapperFor, unwrap


See Also
SQLServerStatement Class
SQLServerStatement Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerStatement, see SQLServerStatement Members.

See Also
SQLServerStatement Members
SQLServerStatement Class
addBatch Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Adds the given SQL command to the current list of commands for this SQLServerStatement object.

Syntax
public void addBatch(java.lang.String sql)

Parameters
sql
A String that contains an SQL statement.

Exceptions
SQLServerException

Remarks
This addBatch method is specified by the addBatch method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
cancel Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Cancels the SQL statement that is currently being run by this SQLServerStatement object.

Syntax
public final void cancel()

Exceptions
SQLServerException

Remarks
This cancel method is specified by the cancel method in the java.sql.Statement interface.
When executing a statement that produces a single large forward-only, read-only result set, you might only be
interested in some initial set of rows in the returned result set. In this case, the application might call the cancel
method of the associated statement object before closing the result set in order to minimize the processing time
needed to discard the remaining unnecessary rows. We recommend considering the tradeoff between the
processing time that would be saved and the time and the additional round trip to the server needed to cancel
the execution when deciding whether to use this technique or not.

See Also
SQLServerStatement Members
SQLServerStatement Class
clearBatch Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Empties the current list of SQL commands for this SQLServerStatement object.

Syntax
public void clearBatch()

Exceptions
SQLServerException

Remarks
This clearBatch method is specified by the clearBatch method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
clearWarnings Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Clears all the warnings that are reported on this SQLServerStatement object.

Syntax
public final void clearWarnings()

Exceptions
SQLServerException

Remarks
This clearWarnings method is specified by the clearWarnings method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
close Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Releases this SQLServerStatement object's database and JDBC resources immediately instead of waiting for
them to be automatically released.

Syntax
public void close()

Exceptions
SQLServerException

Remarks
This close method is specified by the close method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
execute Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement, which can return multiple results.

Overload List
NAME DESC RIP T IO N

execute (java.lang.String) Runs the given SQL statement, which can return multiple
results.

execute (java.lang.String, int) Runs the given SQL statement, which can return multiple
results, and signals to Microsoft JDBC Driver for SQL Server
that any auto-generated keys should be made available for
retrieval.

execute (java.lang.String, int[]) Runs the given SQL statement, which can return multiple
results, and signals the JDBC driver that the auto-generated
keys that are indicated in the given array should be made
available for retrieval.

execute (java.lang.String, java.lang.String[]) Runs the given SQL statement, which can return multiple
results, and signals the JDBC driver that the auto-generated
keys that are indicated in the given array should be made
available for retrieval.

See Also
SQLServerStatement Members
SQLServerStatement Class
execute Method ( java.lang.String)
(SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement, which can return multiple results.

Syntax
public boolean execute(java.lang.String sql)

Parameters
sql
A String that contains an SQL statement.

Return Value
true if the first result is a result set. Otherwise, false .

Exceptions
SQLServerException

Remarks
This execute method is specified by the execute method in the java.sql.Statement interface.

See Also
execute Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
execute Method ( java.lang.String, int[])
4/27/2022 • 2 minutes to read • Edit Online

Runs the given SQL statement, which can return multiple results, and signals Microsoft JDBC Driver for SQL
Server that the auto-generated keys that are indicated in the given array should be made available for retrieval.

Syntax
public final boolean execute(
java.lang.String sql,
int[] columnIndexes)

Parameters
sql
A String that contains an SQL statement.
columnIndexes
An array of int s that indicates the column indexes of the auto-generated keys that should be made available.

Return Value
true if the first result is a result set. Otherwise, false .

Exceptions
SQLServerException

Remarks
This execute method is specified by the execute method in the java.sql.Statement interface.

See Also
execute Method (SQLServerStatement)
SQLServerStatement members
SQLServerStatement class
execute Method ( java.lang.String, java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement, which can return multiple results, and signals Microsoft JDBC Driver for SQL
Server that the auto-generated keys that are indicated in the given array should be made available for retrieval.

Syntax
public final boolean execute(java.lang.String sql,
java.lang.String[] columnNames)

Parameters
sql
A String that contains an SQL statement.
columnNames
An array of strings that indicates the column names of the auto-generated keys that should be made available.

Return Value
true if the first result is a result set. Otherwise, false .

Exceptions
SQLServerException

Remarks
This execute method is specified by the execute method in the java.sql.Statement interface.

See Also
execute Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
executeBatch Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Submits a batch of commands to the database to be run. If all commands run successfully, returns an array of
update counts.

Syntax
public int[] executeBatch()

Return Value
An array of int s that contain the update counts.

Exceptions
SQLServerException
java.sql.BatchUpdateException

Remarks
This executeBatch method is specified by the executeBatch method in the java.sql.Statement interface.
After submitting commands to the database, this method clears any command in the batch.

See Also
SQLServerStatement Members
SQLServerStatement Class
executeQuery Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement and returns a single SQLServerResultSet object.

Syntax
public java.sql.ResultSet executeQuery(java.lang.String sql)

Parameters
sql
A String that contains an SQL statement.

Return Value
A SQLServerResultSet object.

Exceptions
SQLServerException

Remarks
This executeQuery method is specified by the executeQuery method in the java.sql.Statement interface.
SQLServerException is thrown if the given SQL statement produces anything other than a single
SQLServerResultSet object.
If executing a stored procedure results in an update count that is greater than one, or that generates more than
one result set, use the execute method to execute the stored procedure.

See Also
SQLServerStatement Members
SQLServerStatement Class
executeUpdate Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement, which can be an INSERT, UPDATE, or DELETE statement; or an SQL statement that
returns nothing, such as an SQL DDL statement. Beginning in MicrosoftSQL Server JDBC Driver 3.0,
executeUpdate will return the correct number of rows updated in a MERGE operation.

Overload List
NAME DESC RIP T IO N

executeUpdate (java.lang.String) Runs the given SQL statement, which can be an INSERT,
UPDATE, DELETE, or MERGE statement; or an SQL statement
that returns nothing, such as an SQL DDL statement.

executeUpdate (java.lang.String, int) Runs the given SQL statement and signals the Microsoft
JDBC Driver for SQL Server with the given flag about
whether the auto-generated keys produced by this
SQLServerStatement object should be made available for
retrieval.

executeUpdate (java.lang.String, int[]) Runs the given SQL statement and signals the JDBC driver
that the auto-generated keys that are indicated in the given
array should be made available for retrieval.

executeUpdate (java.lang.String, java.lang.String[]) Runs the given SQL statement and signals the JDBC driver
that the auto-generated keys that are indicated in the given
array should be made available for retrieval.

See Also
SQLServerStatement Members
SQLServerStatement Class
executeUpdate Method ( java.lang.String)
(SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement, which can be an INSERT, UPDATE, or DELETE statement; or an SQL statement that
returns nothing, such as an SQL DDL statement. Beginning in MicrosoftSQL Server JDBC Driver 3.0,
executeUpdate will return the correct number of rows updated in a MERGE operation.

Syntax
public int executeUpdate(java.lang.String sql)

Parameters
sql
A String that contains the SQL statement.

Return Value
An int that indicates the number of rows affected, or 0 if using a DDL statement.

Exceptions
SQLServerException

Remarks
This executeUpdate method is specified by the executeUpdate method in the java.sql.Statement interface.
If executing a stored procedure results in an update count that is greater than one, or that generates more than
one result set, use the execute method to execute the stored procedure.

See Also
executeUpdate Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
executeUpdate Method ( java.lang.String, int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement and signals the Microsoft JDBC Driver for SQL Server with the given flag about
whether the auto-generated keys that are produced by this SQLServerStatement object should be made
available for retrieval.

Syntax
public final int executeUpdate(java.lang.String sql,
int flag)

Parameters
sql
A String that contains an SQL statement.
flag
An int value that indicates if auto-generated keys should be made available. It must be one of the following
constants:
RETURN_GENERATED_KEYS
NO_GENERATED_KEYS

Return Value
An int that indicates the number of rows affected, or 0 if using a DDL statement.

Exceptions
SQLServerException

Remarks
This executeUpdate method is specified by the executeUpdate method in the java.sql.Statement interface.
If executing a stored procedure results in an update count that is greater than one, or that generates more than
one result set, use the execute method to execute the stored procedure.

See Also
executeUpdate Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
executeUpdate Method ( java.lang.String,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Runs the given SQL statement and signals Microsoft JDBC Driver for SQL Server that the auto-generated keys
indicated in the given array should be made available for retrieval.

Syntax
public final int executeUpdate(java.lang.String sql,
java.lang.String[] columnNames)

Parameters
sql
A String that contains an SQL statement.
columnNames
An array of type String that indicates which column names of the auto-generated keys should be made
available.

Return Value
An int that indicates the number of rows affected, 0 if using a DDL statement.

Exceptions
SQLServerException

Remarks
This executeUpdate method is specified by the executeUpdate method in the java.sql.Statement interface.
If executing a stored procedure results in an update count that is greater than one, or that generates more than
one result set, use the execute method to execute the stored procedure.

See Also
executeUpdate Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
getConnection Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the SQLServerConnection object that produced this SQLServerStatement object.

Syntax
public final java.sql.Connection getConnection()

Exceptions
SQLServerException

Remarks
This getConnection method is specified by the getConnection method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
getFetchDirection Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the direction for fetching rows from database tables that is the default for result sets that are
generated from this SQLServerStatement object.

NOTE
This method is not currently implemented by the Microsoft JDBC Driver for SQL Server. Therefore, it will always return
FETCH_UNKNOWN.

Syntax
public final int getFetchDirection()

Return Value
An int that indicates the fetch direction that is specified by the setFetchDirection method.

Exceptions
SQLServerException

Remarks
This getFetchDirection method is specified by the getFetchDirection method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
getFetchSize Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the number of result set rows that is the default fetch size for result set objects generated from this
SQLServerStatement object.

Syntax
public final int getFetchSize()

Return Value
An int that indicates the fetch size, which is specified by the setFetchSize method.

Exceptions
SQLServerException

Remarks
This getFetchSize method is specified by the getFetchSize method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
getGeneratedKeys Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves any auto-generated keys that are created as a result of running this SQLServerStatement object.

Syntax
public final java.sql.ResultSet getGeneratedKeys()

Return Value
A ResultSet object.

Exceptions
SQLServerException

Remarks
This getGeneratedKeys method is specified by the getGeneratedKeys method in the java.sql.Statement interface.
For more information about how to use this method, see Using Auto Generated Keys.

See Also
SQLServerStatement Members
SQLServerStatement Class
getMaxFieldSize Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of bytes that can be returned for character and binary column values in a
SQLServerResultSet object that is produced by this SQLServerStatement object.

Syntax
public final int getMaxFieldSize()

Return Value
An int that indicates the maximum number of bytes that a column can contain, or 0 if there is no limit.

Exceptions
SQLServerException

Remarks
This getMaxFieldSize method is specified by the getMaxFieldSize method in the java.sql.Statement interface.

See Also
SQLServerStatement Methods
SQLServerStatement Class
getMaxRows Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the maximum number of rows that a SQLServerResultSet object that is produced by this
SQLServerStatement object can contain.

Syntax
public final int getMaxRows()

Return Value
An int that indicates the maximum number of rows, or 0 if there is no limit.

Exceptions
SQLServerException

Remarks
This getMaxRows method is specified by the getMaxRows method in the java.sql.Statement interface.
This getMaxRows method always returns 0 for dynamic scrollable cursors.

See Also
SQLServerStatement Members
SQLServerStatement Class
getMoreResults Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves to the next result of this SQLServerStatement object.

Overload List
NAME DESC RIP T IO N

getMoreResults () Moves to the next result of this SQLServerStatement object.

getMoreResults (int) Moves to the next result of this SQLServerStatement object,


and deals with any currently open result set objects
according to the instructions specified by the given mode.

See Also
SQLServerStatement Members
SQLServerStatement Class
getMoreResults Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves to the next result of this SQLServerStatement object.

Syntax
public final boolean getMoreResults()

Return Value
true if the returned result is a result set. Otherwise, false .

Exceptions
SQLServerException

Remarks
This getMoreResults method is specified by the getMoreResults method in the java.sql.Statement interface.
Calling the getMoreResults method implicitly closes any currently open result set objects that are obtained with
the getResultSet method.

See Also
getMoreResults Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
getMoreResults Method (int)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Moves to the next result of this SQLServerStatement object and deals with any currently open result set objects
according to the instructions specified by the given mode.

Syntax
public final boolean getMoreResults(int mode)

Parameters
mode
An int that indicates how to handle currently open result set objects. Must be one of the following constants:
CLOSE_CURRENT_RESULT
KEEP_CURRENT_RESULT (not supported by the JDBC driver)
CLOSE_ALL_RESULTS

Return Value
true if the returned result is a result set. Otherwise, false .

Exceptions
SQLServerException

Remarks
This getMoreResults method is specified by the getMoreResults method in the java.sql.Statement interface.
If the getMoreResults method is called before results are retrieved, it behaves as specified by the mode
argument and moves to the next result.

NOTE
The JDBC driver does not support using the KEEP_CURRENT_RESULT constant. If it is used, an exception will be thrown.

See Also
getMoreResults Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
getQueryTimeout Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the number of seconds Microsoft JDBC Driver for SQL Server will wait for this SQLServerStatement
object to run.

Syntax
public final int getQueryTimeout()

Return Value
An int that indicates the number of seconds that the JDBC driver will wait, or 0 if there is no limit.

Exceptions
SQLServerException

Remarks
This getQueryTimeout method is specified by the getQueryTimeout method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
getResponseBuffering Method
(SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the response buffering mode for this SQLServerStatement object.

Syntax
public final java.lang.String getResponseBuffering()

Return Value
A String that contains a lower-case full or adaptive .

Remarks
adaptive specifies buffering the minimum possible data when necessary.
full specifies reading the entire result from the server at run time.
adaptive is the default value in JDBC Driver version 2.0 and 3.0. full was the default prior to JDBC Driver
version 2.0.
For more information about using the response buffering mode, see Using Adaptive Buffering.

See Also
setResponseBuffering Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
getResultSet Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the current result as a SQLServerResultSet object.

Syntax
public final java.sql.ResultSet getResultSet()

Return Value
A ResultSet object.

Exceptions
SQLServerException

Remarks
This getResultSet method is specified by the getResultSet method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
getResultSetConcurrency Method
(SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the result set concurrency for SQLServerResultSet objects that are generated by this
SQLServerStatement object.

Syntax
public final int getResultSetConcurrency()

Return Value
An int that indicates the result set concurrency type.

Exceptions
SQLServerException

Remarks
This getResultSetConcurrency method is specified by the getResultSetConcurrency method in the
java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
getResultSetHoldability Method
(SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the result set holdability for SQLServerResultSet objects that are generated by this
SQLServerStatement object.

Syntax
public final int getResultSetHoldability()

Return Value
An int that indicates the result set holdability.

Exceptions
SQLServerException

Remarks
This getResultSetHoldability method is specified by the getResultSetHoldability method in the java.sql.Statement
interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
getResultSetType Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the result set type for SQLServerResultSet objects that are generated by this SQLServerStatement
object.

Syntax
public final int getResultSetType()

Return Value
An int that indicates the result set type.

Exceptions
SQLServerException

Remarks
This getResultSetType method is specified by the getResultSetType method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
getUpdateCount Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the current result as an update count.

Syntax
public final int getUpdateCount()

Return Value
An int that contains the update count. If the returned result is a result set object or there are no more results, -1
is returned.

Exceptions
SQLServerException

Remarks
This getUpdateCount method is specified by the getUpdateCount method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
getWarnings Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves the first warning that is reported by calls on this SQLServerStatement object.

Syntax
public final java.sql.SQLWarning getWarnings()

Return Value
An SQLWarning object.

Exceptions
SQLServerException

Remarks
This getWarnings method is specified by the getWarnings method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
isClosed Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this SQLServerStatement object has been closed.

Syntax
public boolean isClosed()

Return Value
true if this SQLServerStatement object is closed, false if it is still open.

Exceptions
SQLServerException

Remarks
This isClosed method is specified by the isClosed method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
isPoolable Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a value indicating if a statement can be added to the user-provided statement pool.

Syntax
public boolean isPoolable() throws SQLException

Return Value
true if the statement can be added to the user-provided statement pool; false otherwise.

Exceptions
SQLServerException

Remarks
setPoolable changes the poolable behavior of an object.

See Also
SQLServerStatement Members
SQLServerStatement Class
isWrapperFor Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this statement object is a wrapper for the specified interface.

Syntax
public boolean isWrapperFor(Class iface)

Parameters
iface
A class defining an interface.

Return Value
true if this object implements the interface or wraps an object that implements the interface. Otherwise, false .

Exceptions
SQLServerException

Remarks
The isWrapperFor method and the unwrap method are defined by the java.sql.Wrapper interface, which is
introduced in JDBC 4.0.
If this method returns true, calling unwrap with the same argument will succeed.
For an example code, see Updating Large Data Sample.
For more information, see Wrappers and Interfaces.

See Also
unwrap Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
setCursorName Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the SQL cursor name to the given String, which will be used by subsequent execute methods.

NOTE
This method is not currently supported by the Microsoft JDBC Driver for SQL Server. Calling this method has no effect.

Syntax
public final void setCursorName(java.lang.String name)

Parameters
name
A String that contains the cursor name.

Exceptions
SQLServerException

Remarks
This setCursorName method is specified by the setCursorName method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
setDateTimeOffset(int, java.sql.DateTimeOffset)
(SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the designated parameter to the given DateTimeOffset value.

Syntax
public void setDateTimeOffset(int parameterIndex, DateTimeOffset dateTime)

Parameters
parameterIndex
Index of the column to set.
dateTimeOffset
A DateTimeOffset object.

Exceptions
SQLServerException

Remarks
The DateTimeOffset format is "YYYY-MM-DD HH-MM-SS[.nnnnnnn] [+][-] HH:MM". Use the following table for
reference.

SQ L T Y P E IN SERT

datetime May only insert: "YYYY-MM-DD hh:mm:ss[.nnn]"

smalldatetime May only insert: "YYYY-MM-DD hh:mm:ss"

Time May only insert: "hh:mm:ss[.nnnnnnn]"

Date May only insert: "YYYY-MM-DD"

DateTime2 May only insert: "YYYY-MM-DD hh:mm:ss[.nnnnnnn]"

See Also
getDateTimeOffset (SQLServerResultSet)
SQLServerStatement Members
SQLServerStatement Class
setEscapeProcessing Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the escape processing mode.

NOTE
Escape processing for Microsoft JDBC Driver for SQL Server is always enabled. Setting this method to false has no effect.

Syntax
public final void setEscapeProcessing(boolean enable)

Parameters
enable
true to enable escape processing. Otherwise, false .

Exceptions
SQLServerException

Remarks
This setEscapeProcessing method is specified by the setEscapeProcessing method in the java.sql.Statement
interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
setFetchDirection Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gives Microsoft JDBC Driver for SQL Server a hint as to the direction in which result set rows should be
processed.

NOTE
The JDBC driver currently ignores the hint that is given by this method.

Syntax
public final void setFetchDirection(int nDir)

Parameters
nDir
An int that indicates the row processing direction, which can be one of the following values:
FETCH_FORWARD
FETCH_REVERSE
FETCH_UNKNOWN

Exceptions
SQLServerException

Remarks
This setFetchDirection method is specified by the setFetchDirection method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
setFetchSize Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Gives the Microsoft JDBC Driver for SQL Server a hint as to the number of rows that should be fetched from the
database when more rows are needed.

Syntax
public final void setFetchSize(int rows)

Parameters
rows
An int that indicates the number of rows to fetch.

Exceptions
SQLServerException

Remarks
This setFetchSize method is specified by the setFetchSize method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
setMaxFieldSize Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the limit for the maximum number of bytes in a SQLServerResultSet column storing character or binary
values to the given number of bytes.

Syntax
public final void setMaxFieldSize(int max)

Parameters
max
An int that indicates the maximum number of bytes.

Exceptions
SQLServerException

Remarks
This setMaxFieldSize method is specified by the setMaxFieldSize method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
setMaxRows Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the limit for the maximum number of rows that any SQLServerResultSet object can contain to the given
number.

Syntax
public final void setMaxRows(int max)

Parameters
max
An int that indicates the maximum number of rows, or 0 if there is no limit.

Exceptions
SQLServerException

Remarks
This setMaxRows method is specified by the setMaxRows method in the java.sql.Statement interface.
This setMaxRows method has no effect for dynamic scrollable cursors. The application should use SELECT TOP N
SQL syntax to limit the number of rows returned from potentially large result sets.
When the setMaxRows method is called, the Microsoft JDBC Driver for SQL Server executes the SET
ROWCOUNT SQL statement when it runs the application's query. This causes the JDBC driver to limit the
maximum number of rows affected by all the Transact-SQL statements executed by that query, not just the
number of rows returned by that query. If the application needs to set a limit only on the top-level
SQLServerResultSet object, it should use SELECT TOP N SQL syntax in the query instead of the setMaxRows
method.
For more information about the SET ROWCOUNT SQL statement, see the "SET ROWCOUNT (Transact-SQL)"
topic in SQL Server Books Online.

See Also
SQLServerStatement Members
SQLServerStatement Class
setPoolable Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Requests that a statement be pooled or not pooled.

Syntax
public void setPoolable(boolean poolable) throws SQLException

Parameters
poolable
If true , requests that the statement be pooled. If false , requests that the statement not be pooled.

Exceptions
SQLServerException

Remarks
The value specified in the poolable parameter is a hint to the statement pool implementation indicating if the
application wants the statement to be pooled. The statement pool manager decides if it will use the hint.
A statement's pool value applies to both internal statement caches implemented by the driver and external
statement caches implemented by application servers and other applications.
By default, a SQLServerStatement object is not poolable when created. SQLServerPreparedStatement and
SQLServerCallableStatement objects are poolable when created.
SQLServerException is thrown if this method is called on a closed statement.
isPoolable returns a value indicating if the object is poolable.

See Also
SQLServerStatement Members
SQLServerStatement Class
setResponseBuffering Method
(SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the response buffering mode for this SQLServerStatement object to case-insensitive String full or
adaptive .

Syntax
public final void setResponseBuffering(java.lang.String value)

Parameters
value
A String that contains the response buffering mode. The valid mode can be one of the following case-
insensitive Strings: full or adaptive .

Exceptions
SQLServerException

Remarks
adaptive specifies buffering the minimum possible data when necessary.
full specifies reading the entire result from the server at run time.
adaptive is the default value in JDBC Driver version 2.0 and 3.0. full was the default prior to JDBC Driver version
2.0.
The setResponseBuffering method allows you to override the responseBuffering connection String property
for the current SQLServerStatement object. For more information about using the response buffering mode, see
Using Adaptive Buffering.
If the application specifies an invalid parameter value to the setResponseBuffering method, a
SQLServerException is thrown.

See Also
SQLServerStatement Members
SQLServerStatement Class
Using Adaptive Buffering
setQueryTimeout Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the number of seconds the driver will wait for a SQLServerStatement object to run to the given number of
seconds.

Syntax
public final void setQueryTimeout(int seconds)

Parameters
seconds
An int that indicates the number of seconds to wait, or 0 if there is no limit.

Exceptions
SQLServerException

Remarks
This setQueryTimeout method is specified by the setQueryTimeout method in the java.sql.Statement interface.

See Also
SQLServerStatement Members
SQLServerStatement Class
unwrap Method (SQLServerStatement)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an object that implements the specified interface to allow access to the Microsoft JDBC Driver for SQL
Server-specific methods.

Syntax
public <T> T unwrap(Class<T> iface)

Parameters
iface
A class of type T defining an interface.

Return Value
An object that implements the specified interface.

Exceptions
SQLServerException

Remarks
The unwrap method is defined by the java.sql.Wrapper interface, which is introduced in the JDBC 4.0 Spec.
Applications might need to access extensions to the JDBC API that are specific to the Microsoft JDBC Driver for
SQL Server. The unwrap method supports unwrapping to public classes that this object extends, if the classes
expose vendor extensions.
When this method is called, the object unwraps to the SQLServerStatement class.
For example code, see Updating Large Data Sample, or unwrap Method (SQLServerCallableStatement).
For more information, see Wrappers and Interfaces.

See Also
isWrapperFor Method (SQLServerStatement)
SQLServerStatement Members
SQLServerStatement Class
SQLServerXAConnection Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents JDBC connections that can participate in distributed (XA) transactions.
Package: com.microsoft.sqlserver.jdbc
Extends: SQLServerPooledConnection
Implements: javax.sql.XAConnection

Syntax
public class SQLServerXAConnection

Remarks
A SQLServerXAConnection object can be enlisted in a distributed transaction by means of an
SQLServerXAResource object. A transaction manager, usually part of a middle tier server, manages a
SQLServerXAConnection object through the SQLServerXAResource object.

NOTE
Application programmers typically do not use this interface directly. It is primarily used by a transaction manager working
in the middle tier server.

See Also
SQLServerXAConnection Members
JDBC Driver API Reference
SQLServerXAConnection Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerXAConnection class.

Constructors
None.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

addConnectionEventListener (Inherited from SQLServerPooledConnection) Registers the


given event listener so that it will be notified when an event
occurs on this Connection object.

close (Inherited from SQLServerPooledConnection) Closes the


physical connection that this Connection object represents.

getConnection (Inherited from SQLServerPooledConnection) Creates an


object handle for the physical connection that this
Connection object represents.

getXAResource Retrieves a SQLServerXAResource object that the transaction


manager will use to manage the participation of this
SQLServerXAConnection object in a distributed transaction.

removeConnectionEventListener (Inherited from SQLServerPooledConnection) Removes the


given event listener.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

com.microsoft.sqlserver.jdbc.SQLServerPooledConnection addConnectionEventListener, close, getConnection,


removeConnectionEventListener

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait
C L A SS IN H ERIT ED F RO M : M ET H O DS

javax.sql.PooledConnection addConnectionEventListener, close, getConnection,


removeConnectionEventListener

See Also
SQLServerXAConnection Class
SQLServerXAConnection Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerXAConnection, see SQLServerXAConnection Members.
getXAResource Method (SQLServerXAConnection)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Retrieves a SQLServerXAResource object that the transaction manager will use to manage this
SQLServerXAConnection object's participation in a distributed transaction.

Syntax
public javax.transaction.xa.XAResource getXAResource()

Return Value
An XAResource object.

Exceptions
java.sql.SQLException

Remarks
This getXAResource method is specified by the getXAResource method in the javax.sql.XAConnection interface.

See Also
SQLServerXAConnection Methods
SQLServerXAConnection Members
SQLServerXAConnection Class
SQLServerXADataSource Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents a factory for SQLServerXAConnection objects that is used internally.
Package: com.microsoft.sqlserver.jdbc
Extends: SQLServerConnectionPoolDataSource
Implements: javax.sql.XADataSource

Syntax
public class SQLServerXADataSource

Remarks
An object that implements the SQLServerXADataSource interface is typically registered with a naming service
that uses the Java Naming and Directory Interface (JNDI).
The SQLServerXADataSource class provides database connections for use in distributed (XA) transactions. The
SQLServerXADataSource class also supports connection pooling of physical connections. The
SQLServerXADataSource and SQLServerXAConnection interfaces, which are defined in the package javax.sql,
are implemented by SQL Server.
A SQLServerXAConnection object is a pooled connection that can participate in a distributed transaction. More
precisely, SQLServerXAConnection extends the SQLServerPooledConnection interface by adding the method
getXAResource. This method produces a SQLServerXAResource object that can be used by a transaction
manager to coordinate the work done on this connection with the other participants in the distributed
transaction. Because they extend the SQLServerPooledConnection interface, SQLServerXAConnection objects
support all the methods of SQLServerPooledConnection objects. They are reusable physical connections to an
underlying data source and produce logical connection handles that can be passed back to a JDBC application.
SQLServerXAConnection objects are produced by a SQLServerXADataSource object.
SQLServerConnectionPoolDataSource objects and SQLServerXADataSource objects are similar because they are
both implemented below a data source layer that is visible to the JDBC application. This architecture lets SQL
Server support distributed transactions in a way that is transparent to the application. SQLServerXADataSource
can be configured to integrate with Microsoft Distributed Transaction Coordinator (DTC) to provide true,
distributed transaction processing.

See Also
SQLServerXADataSource Members
JDBC Driver API Reference
SQLServerXADataSource Members
4/27/2022 • 4 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members that are exposed by the SQLServerXADataSource class.

Constructors
NAME DESC RIP T IO N

SQLServerXADataSource () Initializes a new instance of the SQLServerXADataSource


class.

Fields
None.

Inherited Fields
None.

Methods
NAME DESC RIP T IO N

getApplicationIntent (Inherited from SQLServerDataSource) Returns the value of


the applicationIntent connection property.

getApplicationName (Inherited from SQLServerDataSource) Returns the


application name.

getConnection (Inherited from SQLServerDataSource) Tries to establish a


connection with the data source that this DataSource object
represents.

getDatabaseName (Inherited from SQLServerDataSource) Returns the database


name.

getFailoverPartner (Inherited from SQLServerDataSource) Returns the name of


the failover server that is used in a database mirroring
configuration.

getInstanceName (Inherited from SQLServerDataSource) Returns the SQL


Server instance name.

getLastUpdateCount (Inherited from SQLServerDataSource) Returns a Boolean


value that indicates if the lastUpdateCount property is
enabled.
NAME DESC RIP T IO N

getLockTimeout (Inherited from SQLServerDataSource) Returns an int value


that indicates the number of milliseconds that the database
will wait before reporting a lock time out.

getLoginTimeout (Inherited from SQLServerDataSource) Returns the number


of seconds that this DataSource object will wait while trying
to make a connection.

getLogWriter (Inherited from SQLServerDataSource) Returns a character


output stream to be used for all logging and tracing
messages.

getMultiSubnetFailover (Inherited from SQLServerDataSource) Retrieves the value of


the multiSubnetFailover connection property.

getPooledConnection (Inherited from SQLServerConnectionPoolDataSource) Tries


to establish a physical database connection that can be used
as a pooled connection.

getPortNumber (Inherited from SQLServerDataSource) Returns the current


port number that is used to communicate with SQL Server.

getReference Returns a reference to this SQLServerXADataSource object.

getSelectMethod (Inherited from SQLServerDataSource) Returns the default


cursor type that is used for all result sets that are created by
using this DataSource object.

getSendStringParametersAsUnicode (Inherited from SQLServerDataSource) Returns a Boolean


value that indicates if sending String parameters to the
server in UNICODE format is enabled.

getServerName (Inherited from SQLServerDataSource) Returns the name of


the computer that is running SQL Server.

getURL (Inherited from SQLServerDataSource) Returns the URL that


is used to connect to the data source.

getUser (Inherited from SQLServerDataSource) Returns the user


name that is used to connect the data source.

getWorkstationID (Inherited from SQLServerDataSource) Returns the name of


the client computer name that is used to connect to the
data source.

getXAConnection Tries to establish a physical database connection that can be


used in a distributed transaction.

getXopenStates (Inherited from SQLServerDataSource) Returns a Boolean


value that indicates if converting SQL states to XOPEN
compliant states is enabled.

isWrapperFor Indicates whether this object is a wrapper for the specified


interface.
NAME DESC RIP T IO N

setApplicationIntent (Inherited from SQLServerDataSource) Sets the value of the


applicationIntent connection property.

setApplicationName (Inherited from SQLServerDataSource) Sets the application


name.

setAuthenticationSceme (Inherited from SQLServerDataSource) Indicates the kind of


integrated security you want your application to use.

setDatabaseName (Inherited from SQLServerDataSource) Sets the database


name to connect to.

setDescription (Inherited from SQLServerDataSource) Sets the description


of the data source.

setFailoverPartner (Inherited from SQLServerDataSource) Sets the name of the


failover server that is used in a database mirroring
configuration.

setInstanceName (Inherited from SQLServerDataSource) Sets the SQL Server


instance name.

setIntegratedSecurity (Inherited from SQLServerDataSource) Sets a boolean value


that indicates if the integratedSecurity property is enabled.

setLastUpdateCount (Inherited from SQLServerDataSource) Sets a Boolean value


that indicates if the lastUpdateCount property is enabled.

setLockTimeout (Inherited from SQLServerDataSource) Sets an int value that


indicates the number of milliseconds to wait before the
database reports a lock time out.

setLoginTimeout (Inherited from SQLServerDataSource) Sets the number of


seconds that this DataSource object will wait while trying to
make a connection.

setLogWriter (Inherited from SQLServerDataSource) Sets a character


output stream to be used for all logging and tracing
messages.

setMultiSubnetFailover (Inherited from SQLServerDataSource) Sets the value of the


multiSubnetFailover connection property.

setPassword (Inherited from SQLServerDataSource) Sets the password


that will be used to connect to SQL Server.

setPortNumber (Inherited from SQLServerDataSource) Sets the port number


to be used to communicate with SQL Server.

setSelectMethod (Inherited from SQLServerDataSource) Sets the default


cursor type that is used for all result sets that are created by
using this DataSource object.
NAME DESC RIP T IO N

setSendStringParametersAsUnicode (Inherited from SQLServerDataSource) Sets a Boolean value


that indicates if sending String parameters to the server in
UNICODE format is enabled.

setServerName (Inherited from SQLServerDataSource) Sets the name of the


computer that is running SQL Server.

setURL (Inherited from SQLServerDataSource) Sets the URL that is


used to connect to the data source.

setUser (Inherited from SQLServerDataSource) Sets the user name


that is used to connect the data source.

setWorkstationID (Inherited from SQLServerDataSource) Sets the client


computer name that is used to connect to the data source.

setXopenStates (Inherited from SQLServerDataSource) Sets a boolean value


that indicates if converting SQL states to XOPEN compliant
states is enabled.

unwrap Returns an object that implements the specified interface to


allow access to the Microsoft JDBC Driver for SQL Server-
specific methods.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataS getPooledConnection
ource

com.microsoft.sqlserver.jdbc.SQLServerDataSource getApplicationName, getConnection, getDatabaseName,


getDescription, getFailoverPartner, getInstanceName,
getLastUpdateCount, getLockTimeout, getLoginTimeout,
getLogWriter, getPortNumber, getSelectMethod,
getSendStringParametersAsUnicode, getServerName,
getURL, getUser, getWorkstationID, getXopenStates,
setApplicationName, setDatabaseName, setDescription,
setFailoverPartner, setInstanceName, setIntegratedSecurity,
setLastUpdateCount, setLockTimeout, setLoginTimeout,
setLogWriter, setPassword, setPortNumber, setSelectMethod,
setSendStringParametersAsUnicode, setServerName, setURL,
setUser, setWorkstationID, setXopenStates

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

java.sql.Wrapper isWrapperFor, unwrap

javax.sql.XADataSource getLoginTimeout, getLogWriter, setLoginTimeout,


setLogWriter

javax.sql.ConnectionPoolDataSource getLoginTimeout, getLogWriter, setLoginTimeout,


setLogWriter
See Also
SQLServerXADataSource Class
SQLServerXADataSource Constructors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerXADataSource, see SQLServerXADataSource Members.
SQLServerXADataSource Constructor ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Initializes a new instance of the SQLServerXADataSource class.

Syntax
public SQLServerXADataSource()

See Also
SQLServerXADataSource Constructors
SQLServerXADataSource Members
SQLServerXADataSource Class
SQLServerXADataSource Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerXADataSource, see SQLServerXADataSource Members.
getReference Method (SQLServerXADataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns a reference to this SQLServerXADataSource object.

Syntax
public javax.naming.Reference getReference()

Return Value
A Reference object.

Remarks
This getReference method is specified by the getReference method in the javax.naming.Referenceable interface.

See Also
SQLServerXADataSource Methods
SQLServerXADataSource Members
SQLServerXADataSource Class
getXAConnection Method
(SQLServerXADataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to establish a physical database connection that can be used in a distributed transaction.

Overload List
NAME DESC RIP T IO N

getXAConnection () Tries to establish a physical database connection that can be


used in a distributed transaction.

getXAConnection (java.lang.String, java.lang.String) Tries to establish a physical database connection using the
given user name and password.

See Also
SQLServerXADataSource Methods
SQLServerXADataSource Members
SQLServerXADataSource Class
getXAConnection Method ()
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to establish a physical database connection that can be used in a distributed transaction.

Syntax
public javax.sql.XAConnection getXAConnection()

Return Value
An XAConnection object.

Exceptions
java.sql.SQLException

Remarks
This getXAConnection method is specified by the getXAConnection method in the javax.sql.XADataSource
interface.

NOTE
This method is typically called by XA connection pool implementations and not by regular JDBC application code.

See Also
getXAConnection Method (SQLServerXADataSource)
SQLServerXADataSource Methods
SQLServerXADataSource Members
SQLServerXADataSource Class
getXAConnection Method ( java.lang.String,
java.lang.String)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tries to establish a physical database connection using the given user name and password.

Syntax
public javax.sql.XAConnection getXAConnection(java.lang.String user,
java.lang.String password)

Parameters
user
A String that contains the user name.
password
A String that contains the password.

Return Value
An XAConnection object.

Exceptions
java.sql.SQLException

Remarks
This getXAConnection method is specified by the getXAConnection method in the javax.sql.XADataSource
interface.

NOTE
This method is typically called by XA connection pool implementations and not by regular JDBC application code.

See Also
getXAConnection Method (SQLServerXADataSource)
SQLServerXADataSource Methods
SQLServerXADataSource Members
SQLServerXADataSource Class
isWrapperFor Method (SQLServerXADataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Indicates whether this object is a wrapper for the specified interface.

Syntax
public boolean isWrapperFor(Class iface)

Parameters
iface
A class defining an interface.

Return Value
true if this object implements the interface or wraps an object that implements the interface. Otherwise, false .

Exceptions
SQLServerException

Remarks
The isWrapperFor method and the unwrap method are defined by the java.sql.Wrapper interface, which is
introduced in the JDBC 4.0 Spec.
If this method returns true, calling unwrap with the same argument will succeed.
For more information, see Wrappers and Interfaces.

See Also
unwrap Method (SQLServerXADataSource)
SQLServerXADataSource Methods
SQLServerXADataSource Members
SQLServerXADataSource Class
unwrap Method (SQLServerXADataSource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Returns an object that implements the specified interface to allow access to the Microsoft JDBC Driver for SQL
Server-specific methods.

Syntax
public <T> T unwrap(Class<T> iface)

Parameters
iface
A class of type T defining an interface.

Return Value
An object that implements the specified interface.

Exceptions
SQLServerException

Remarks
The unwrap method is defined by the java.sql.Wrapper interface, which is introduced in the JDBC 4.0 Spec.
Applications might need to access extensions to the JDBC API that are specific to the Microsoft JDBC Driver for
SQL Server. The unwrap method supports unwrapping to public classes that this object extends, if the classes
expose vendor extensions.
The SQLServerXADataSource class extends the SQLServerConnectionPoolDataSource class, which is extended
from the SQLServerDataSource class. When this method is called, the object unwraps to the following classes:
SQLServerDataSource, SQLServerConnectionPoolDataSource, and SQLServerXADataSource.
For more information, see Wrappers and Interfaces.

See Also
SQLServerXADataSource Methods
SQLServerXADataSource Members
SQLServerXADataSource Class
SQLServerXAResource Class
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Represents an XAResource for XA distributed transaction management.
Package: com.microsoft.sqlserver.jdbc
Extends: java.lang.Object
Implements: javax.transaction.xa.XAResource

Syntax
public class SQLServerXAResource

Remarks
XA transactions are implemented in SQL Server by using Microsoft Distributed Transaction Manager (DTC). The
SQLServerXAResource class makes calls to a SQL Server extended dll named sqljdbc_xa.dll, which interfaces
with DTC. XA calls that are received by SQLServerXAResource (XA_START, XA_END, XA_PREPARE, and so forth)
are mapped to the corresponding calls to DTC functions.

See Also
SQLServerXAResource Members
JDBC Driver API Reference
SQLServerXAResource Members
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following tables list the members exposed by the SQLServerXAResource class.

Constructors
None.

Fields
NAME DESC RIP T IO N

SSTRANSTIGHTLYCPLD Used to allow the tightly coupled XA transactions, which


have different XA branch transaction IDs (XIDs) but have the
same global transaction ID (GTRID).

Inherited Fields
C L A SS IN H ERIT ED F RO M : M ET H O DS

javax.transaction.xa.XAResource TMENDRSCAN, TMFAIL, TMJOIN, TMNOFLAGS,


TMONEPHASE, TMRESUME, TMSTARTRSCAN, TMSUCCESS,
TMSUSPEND, XA_OK, XA_RDONLY

Methods
NAME DESC RIP T IO N

commit Commits the global transaction specified by the given Xid


object.

end Ends the work performed on behalf of a transaction branch.

forget Tells the resource manager to forget about a heuristically


completed transaction branch.

getTransactionTimeout Obtains the current transaction timeout value set for this
SQLServerXAResource object.

isSameRM Determines if the resource manager instance represented by


the target object is the same as the resource manager
instance represented by the given XAResource object.

prepare Requests that the resource manager prepare for a


transaction commit of the transaction specified by the given
Xid object.
NAME DESC RIP T IO N

recover Obtains a list of prepared transaction branches from a


resource manager.

rollback Requests that the resource manager roll back work done on
behalf of a transaction branch.

setTransactionTimeout Sets the current transaction timeout value for this


SQLServerXAResource object.

start Starts work on behalf of a transaction branch specified in the


Xid object.

Inherited Methods
C L A SS IN H ERIT ED F RO M : M ET H O DS

java.lang.Object clone, equals, finalize, getClass, hashCode, notify, notifyAll,


toString, wait

See Also
SQLServerXAResource Class
SQLServerXAResource Methods
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerXAResource, see SQLServerXAResource Members.
commit Method (SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Commits the global transaction that is specified by the given Xid object.

Syntax
public void commit(javax.transaction.xa.Xid xid,
boolean onePhase)

Parameters
xid
An Xid object.
onePhase
A boolean value.

Exceptions
javax.transaction.xa.XAException

Remarks
This commit method is specified by the commit method in the javax.transaction.xa.XAResource interface.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
end Method (SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Ends the work performed on behalf of a transaction branch.

Syntax
public void end(javax.transaction.xa.Xid xid,
int flags)

Parameters
xid
An Xid object.
flags
An int value.

Exceptions
javax.transaction.xa.XAException

Remarks
This end method is specified by the end method in the javax.transaction.xa.XAResource interface.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
forget Method (SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Tells the resource manager to forget about a heuristically completed transaction branch.

Syntax
public void forget(javax.transaction.xa.Xid xid)

Parameters
xid
An Xid object.

Exceptions
javax.transaction.xa.XAException

Remarks
This forget method is specified by the forget method in the javax.transaction.xa.XAResource interface.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
getTransactionTimeout Method
(SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Obtains the current transaction timeout value set for this SQLServerXAResource object.

Syntax
public int getTransactionTimeout()

Exceptions
javax.transaction.xa.XAException

Remarks
This getTransactionTimeout method is specified by the getTransactionTimeout method in the
javax.transaction.xa.XAResource interface.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
isSameRM Method (SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Determines if the resource manager instance that is represented by the target object is the same as the resource
manager instance that is represented by the given XAResource object.

Syntax
public boolean isSameRM(javax.transaction.xa.XAResource xares)

Parameters
xares
An XAResource object.

Return Value
true if the instances are the same. Otherwise, false .

Exceptions
javax.transaction.xa.XAException

Remarks
This commit method is specified by the commit method in the javax.transaction.xa.XAResource interface.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
prepare Method (SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Requests that the resource manager prepare for a transaction commit of the transaction specified by the given
Xid object.

Syntax
public int prepare(javax.transaction.xa.Xid xid)

Parameters
xid
An Xid object.

Return Value
An int value.

Exceptions
javax.transaction.xa.XAException

Remarks
This prepare method is specified by the prepare method in the javax.transaction.xa.XAResource interface.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
recover Method (SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Obtains a list of prepared transaction branches from a resource manager.

Syntax
public javax.transaction.xa.Xid[] recover(int flags)

Parameters
flags
An int value that can take one of the following values: XAResource.TMSTARTRSCAN or
XAResource.TMENDRSCAN or XAResource.TMNOFLAGS or XAResource.TMSTARTTRSCAN |
XAResource.TMENDRSCAN.

Return Value
An Xid object.

Exceptions
javax.transaction.xa.XAException

Remarks
This recover method is specified by the recover method in the javax.transaction.xa.XAResource interface.
If the parameter flag is not XAResource.TMSTARTRSCAN or XAResource.TMSTARTRSCAN |
XAResource.TMENDRSCAN, a recovery scan must be in progress.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
rollback Method (SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Requests that the resource manager roll back work done on behalf of a transaction branch.

Syntax
public void rollback(javax.transaction.xa.Xid xid)

Parameters
xid
An Xid object.

Exceptions
javax.transaction.xa.XAException

Remarks
This rollback method is specified by the rollback method in the javax.transaction.xa.XAResource interface.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
setTransactionTimeout Method
(SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Sets the current transaction time out value for this SQLServerXAResource object.

Syntax
public boolean setTransactionTimeout(int seconds)

Parameters
seconds
An int value.

Return Value
true if the timeout was successfully set. Otherwise, false .

Exceptions
javax.transaction.xa.XAException

Remarks
This setTransactionTimeout method is specified by the setTransactionTimeout method in the
javax.transaction.xa.XAResource interface.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
start Method (SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Starts work on behalf of a transaction branch that is specified in the Xid object.

Syntax
public void start(javax.transaction.xa.Xid xid,
int flags)

Parameters
xid
An Xid object.
flags
An int value.

Exceptions
javax.transaction.xa.XAException

Remarks
This start method is specified by the start method in the javax.transaction.xa.XAResource interface.

See Also
SQLServerXAResource Methods
SQLServerXAResource Members
SQLServerXAResource Class
SQLServerXAResource Fields
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


For information about the members of SQLServerXAResource, see SQLServerXAResource Members.
SSTRANSTIGHTLYCPLD Field
(SQLServerXAResource)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Used to allow the tightly coupled XA transactions, which have different XA branch transaction IDs (XIDs) but
have the same global transaction ID (GTRID).

Syntax
public static final int SSTRANSTIGHTLYCPLD

Field Value
An int value of 32768.

Remarks
Each transaction is identified by an XA branch transaction ID (XID) and a global transaction ID (GTRID). In order
to allow the applications to use tightly coupled XA transactions that have different XIDs but have the same
GTRID, you must set the SSTRANSTIGHTLYCPLD on the flags parameter of the XAResource.start method. For
more information about how to use this flag, see Understanding XA Transactions.

See Also
SQLServerXAResource Fields
SQLServerXAResource Members
SQLServerXAResource Class
Securing JDBC driver applications
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Enhancing the security of a Microsoft JDBC Driver for SQL Server application is crucial. Security involves more
than avoiding common coding pitfalls. An application that accesses data has many potential failure points that
an attacker can exploit. Security failures may allow attackers to retrieve, manipulate, or destroy sensitive data. It's
important to understand all aspects of application security. From the process of threat modeling during the
design phase to eventual deployment, and continuing through ongoing maintenance.
The articles in this section describe some common security concerns including connection strings, validating
user input, and general application security.

In this section
A RT IC L E DESC RIP T IO N

Securing connection strings Describes techniques to help protect information used to


connect to a data source.

Validating user input Describes techniques to validate user input.

Application security Describes how to use Java policy permissions to help secure
a JDBC driver application.

Using encryption Describes how to establish a secure communication channel


with a SQL Server database using Transport Layer Security
(TLS), previously known as Secure Sockets Layer (SSL).

FIPS mode Describes how to use JDBC driver in FIPS-compliant mode.

See also
Overview of the JDBC driver
Securing connection strings
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Protecting access to your data source is one of the most important goals of helping to secure an application. To
limit access to your data source, you must take precautions to help secure connection information such as a user
ID, password, and data source name. Storing a user ID and password in plain text, such as in your source code,
presents a serious security issue. Even if you supply a compiled version of code that contains user ID and
password information in an external source, your compiled code can potentially be disassembled and the user
ID and password exposed. As a result, it's imperative that critical information such as a user ID and password not
exist in your code.

Recommendations
It's recommended to not store the password together with the connection URL in application source code.
Instead, consider storing the password in a separate file that has restricted access. The access to that file can be
granted to the context under which the application is running.
Another approach is to store the encrypted password in a file. Make sure you use an encryption API that doesn't
require the key to be stored somewhere and isn't derived from the password of a user. For example, you might
consider using certificate-based public/private key pairs, or use an approach where two parties use a key
agreement protocol (Diffie-Hellman algorithm) to generate identical secret keys for encryption without ever
having to transmit the secret key.
If you take connection string information from an external source, such as a user supplying a user ID and
password, you must validate any input from the source to ensure that it follows the correct format and doesn't
contain extra parameters that affect your connection.

See also
Securing JDBC driver applications
Validating user input
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you construct an application that accesses data, you should assume all user input to be malicious until
proven otherwise. Failure to do so can leave your application vulnerable to attack. One type of attack that can
occur is called SQL injection. This attack is where malicious code is added to strings that are passed to an
instance of SQL Server to be parsed and run. To avoid this type of attack, you should use stored procedures with
parameters where possible, and always validate user input.
Validating user input in client code is important so that you don't waste round trips to the server. It's equally
important to validate parameters to stored procedures on the server. That way input is caught that bypasses
client-side validation.
For more information about SQL injection and how to avoid it, see SQL injection. For more information about
validating stored procedure parameters, see Stored procedures and related articles.

See also
Securing JDBC driver applications
Application security
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you use the Microsoft JDBC Driver for SQL Server, it's important to take precautions to ensure the
security of your application. The following sections provide information about steps you can take to help secure
your application.

Using Java policy permissions


When you use the Microsoft JDBC Driver for SQL Server, it's important to specify the required Java policy
permissions that the JDBC driver requires. The Java Runtime Environment (JRE) provides an extensive security
model. That model can be used at runtime to determine whether a thread has access to a resource. Security
policy files can control this access. The policy files themselves are managed by the deployer and the sysadmin
for the container. The permissions listed in this article are ones that affect the functioning of the JDBC driver.
A typical permission in the policy file looks like the following.

// Example policy file entry.


grant [signedBy <signer>,] [codeBase <code source>] {
permission <class> [<name> [, <action list>]];
};

The following codebase should be restricted to the JDBC driver codebase to ensure that you grant the least
number of privileges.

grant codeBase "file:/install_dir/lib/-" {

// Grant access to data source.


permission java.util.PropertyPermission "java.naming.*", "read,write";

// Specify which hosts can be connected to.


permission java.net.socketPermission "host:port", "connect";

// Logger permission to take advantage of logging.


permission java.util.logging.LoggingPermission;

// Grant listen/connect/accept permissions to the driver if


// connecting to a named instance as the client driver.
// This connects to a udp service and listens for a response.
permission java.net.SocketPermission "*", "listen, connect, accept";
};

NOTE
The code "file:/install_dir/lib/-" refers to the installation directory of the JDBC driver.

Protecting server communication


When you use the JDBC driver to communicate with a SQL Server database, it's important to secure the
communication channel. You can secure the channel by using either Internet Protocol Security (IPSEC) or
Transport Layer Security (TLS), previously known as Secure Sockets Layer (SSL), or you can use both.
TLS support can be used to provide an extra level of protection besides IPSEC. For more information about
using TLS, see Using encryption.

See also
Securing JDBC driver applications
Using encryption
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Transport Layer Security (TLS) encryption enables transmitting encrypted data across the network between an
instance of SQL Server and a client application.
Transport Layer Security (TLS) is a protocol for establishing a secure communication channel to prevent the
interception of critical or sensitive information across the network and other Internet communications. TLS
allows the client and the server to authenticate the identity of each other. After the participants are
authenticated, TLS provides encrypted connections between them for secure message transmission.
The Microsoft JDBC Driver for SQL Server provides an infrastructure to enable and disable the encryption on a
particular connection based on the user specified connection properties and the server and client settings. The
user can specify the certificate store location and password, a host name to be used to validate the certificate,
and when to encrypt the communication channel.
Enabling TLS encryption increases the security of data transmitted across networks between instances of SQL
Server and applications. However, enabling encryption does slow performance.
The articles in this section describe how the Microsoft JDBC Driver for SQL Server version supports TLS
encryption, including new connection properties, and how you can configure the trust store at the client-side.

NOTE
The hostNameInCer tificate connection property is recommended to validate an TLS certificate.

In this section
A RT IC L E DESC RIP T IO N

Understanding encryption support Describes how the Microsoft JDBC Driver for SQL Server
supports TLS encryption.

Connecting with encryption Describes how to connect to a SQL Server database by using
the new TLS-specific connection properties.

Configuring the client for encryption Describes how to configure the default trust store at the
client-side and how to import a private certificate to the
client computer's trust store.

See also
Securing JDBC driver applications
Understanding encryption support
4/27/2022 • 8 minutes to read • Edit Online

Download JDBC Driver


When connecting to SQL Server, if the application requests encryption and the instance of SQL Server is
configured to support TLS encryption, the Microsoft JDBC Driver for SQL Server initiates the TLS handshake.
The handshake allows the server and client to negotiate the encryption and cryptographic algorithms to be used
to protect data. After the TLS handshake is complete, the client and server can send the encrypted data securely.
During the TLS handshake, the server sends its public key certificate to the client. The issuer of a public key
certificate is known as a Certificate Authority (CA). The client is responsible for validating that the certificate
authority is one the client trusts.
If the application doesn't request encryption, the Microsoft JDBC Driver for SQL Server won't force SQL Server
to support TLS encryption. If the SQL Server instance isn't configured to force the TLS encryption, a connection
is established without encryption. If the SQL Server instance is configured to force the TLS encryption, the driver
will automatically enable TLS encryption when running on properly configured Java Virtual Machine (JVM), or
else the connection is terminated and the driver will raise an error.

NOTE
Make sure the value passed to ser verName exactly matches the Common Name (CN) or DNS name in the Subject
Alternate Name (SAN) in the server certificate for a TLS connection to succeed.
For more information about how to configure TLS for SQL Server, see Enable encrypted connections to the Database
Engine.

Remarks
To allow applications to use TLS encryption, the Microsoft JDBC Driver for SQL Server has introduced the
following connection properties starting with the version 1.2 release: encr ypt , trustSer verCer tificate ,
trustStore , trustStorePassword , and hostNameInCer tificate . For more information, see Setting the
connection properties.
The following table summarizes how the Microsoft JDBC Driver for SQL Server version behaves for possible TLS
connection scenarios. Each scenario uses a different set of TLS connection properties. The table includes:
blank : "The property doesn't exist in the connection string"
value : "The property exists in the connection string and its value is valid"
any : "It doesn't matter whether the property exists in the connection string or its value is valid"

NOTE
The same behavior applies for SQL Server user authentication and Windows integrated authentication.
P RO P ERT Y SET T IN GS B EH AVIO R

encr ypt = false or blank The driver won't force the server to support TLS encryption.
trustSer verCer tificate = any If the server has a self-signed certificate, the driver initiates
hostNameInCer tificate = any the TLS certificate exchange. The TLS certificate won't be
trustStore = any validated and only the credentials (in the login packet) are
trustStorePassword = any encrypted.

If the server requires the client to support TLS encryption,


the driver will initiate the TLS certificate exchange. The TLS
certificate won't be validated, but the entire communication
will be encrypted.

encr ypt = true The driver requests to use TLS encryption with the server.
trustSer verCer tificate = true
hostNameInCer tificate = any If the server requires the client to support TLS encryption or
trustStore = any if the server supports encryption, the driver will initiate the
trustStorePassword = any TLS certificate exchange. If the trustSer verCer tificate
property is set to "true", the driver won't validate the TLS
certificate.

If the server isn't configured to support encryption, the


driver will raise an error and terminate the connection.

encr ypt = true The driver requests to use TLS encryption with the server.
trustSer verCer tificate = false or blank
hostNameInCer tificate = blank If the server requires the client to support TLS encryption or
trustStore = blank if the server supports encryption, the driver will initiate the
trustStorePassword = blank TLS certificate exchange.

The driver will use the ser verName property specified on


the connection URL to validate the server TLS certificate and
rely on the trust manager factory's look-up rules to
determine which certificate store to use.

If the server isn't configured to support encryption, the


driver will raise an error and terminate the connection.

encr ypt = true The driver requests to use TLS encryption with the server.
trustSer verCer tificate = false or blank
hostNameInCer tificate = value If the server requires the client to support TLS encryption or
trustStore = blank if the server supports encryption, the driver will initiate the
trustStorePassword = blank TLS certificate exchange.

The driver will validate the TLS certificate's subject value by


using the value specified for the hostNameInCer tificate
property.

If the server isn't configured to support encryption, the


driver will raise an error and terminate the connection.
P RO P ERT Y SET T IN GS B EH AVIO R

encr ypt = true The driver requests to use TLS encryption with the server.
trustSer verCer tificate = false or blank
hostNameInCer tificate = blank If the server requires the client to support TLS encryption or
trustStore = value if the server supports encryption, the driver will initiate the
trustStorePassword = value TLS certificate exchange.

The driver will use the trustStore property value to find the
certificate trustStore file and trustStorePassword property
value to check the integrity of the trustStore file.

If the server isn't configured to support encryption, the


driver will raise an error and terminate the connection.

encr ypt = true The driver requests to use TLS encryption with the server.
trustSer verCer tificate = false or blank
hostNameInCer tificate = blank If the server requires the client to support TLS encryption or
trustStore = blank if the server supports encryption, the driver will initiate the
trustStorePassword = value TLS certificate exchange.

The driver will use the trustStorePassword property value


to check the integrity of the default trustStore file.

If the server isn't configured to support encryption, the


driver will raise an error and terminate the connection.

encr ypt = true The driver requests to use TLS encryption with the server.
trustSer verCer tificate = false or blank
hostNameInCer tificate = blank If the server requires the client to support TLS encryption or
trustStore = value if the server supports encryption, the driver will initiate the
trustStorePassword = blank TLS certificate exchange.

The driver will use the trustStore property value to look up


the location of the trustStore file.

If the server isn't configured to support encryption, the


driver will raise an error and terminate the connection.

encr ypt = true The driver requests to use TLS encryption with the server.
trustSer verCer tificate = false or blank
hostNameInCer tificate = value If the server requires the client to support TLS encryption or
trustStore = blank if the server supports encryption, the driver will initiate the
trustStorePassword = value TLS certificate exchange.

The driver will use the trustStorePassword property value


to check the integrity of the default trustStore file. Also, the
driver will use the hostNameInCer tificate property value
to validate the TLS certificate.

If the server isn't configured to support encryption, the


driver will raise an error and terminate the connection.
P RO P ERT Y SET T IN GS B EH AVIO R

encr ypt = true The driver requests to use TLS encryption with the server.
trustSer verCer tificate = false or blank
hostNameInCer tificate = value If the server requires the client to support TLS encryption or
trustStore = value if the server supports encryption, the driver will initiate the
trustStorePassword = blank TLS certificate exchange.

The driver will use the trustStore property value to look up


the location of the trustStore file. Also, the driver will use the
hostNameInCer tificate property value to validate the TLS
certificate.

If the server isn't configured to support encryption, the


driver will raise an error and terminate the connection.

encr ypt = true The driver requests to use TLS encryption with the server.
trustSer verCer tificate = false or blank
hostNameInCer tificate = value If the server requires the client to support TLS encryption or
trustStore = value if the server supports encryption, the driver will initiate the
trustStorePassword = value TLS certificate exchange.

The driver will use the trustStore property value to find the
certificate trustStore file and trustStorePassword property
value to check the integrity of the trustStore file. Also, the
driver will use the hostNameInCer tificate property value
to validate the TLS certificate.

If the server isn't configured to support encryption, the


driver will raise an error and terminate the connection.

If the encrypt property is set to true , the Microsoft JDBC Driver for SQL Server uses the JVM's default JSSE
security provider to negotiate TLS encryption with SQL Server. The default security provider may not support all
of the features required to negotiate TLS encryption successfully. For example, the default security provider may
not support the size of the RSA public key used in the SQL Server TLS certificate. In this case, the default security
provider might raise an error that will cause the JDBC driver to terminate the connection. To resolve this issue,
one of the following options can be used:
Configure the SQL Server with a server certificate that has a smaller RSA public key
Configure the JVM to use a different JSSE security provider in the "<java-home>/lib/security/java.security"
security properties file
Use a different JVM

Validating server TLS certificate


During the TLS handshake, the server sends its public key certificate to the client. The JDBC driver or client has
to validate that the server certificate is issued by a certificate authority the client trusts. The driver requires the
server certificate to meet the following conditions:
The certificate was issued by a trusted certificate authority.
The certificate must be issued for server authentication.
The certificate isn't expired.
The Common Name (CN) in the Subject or a DNS name in the Subject Alternate Name (SAN) of the
certificate exactly matches the ser verName value specified in the connection string or, if specified, the
hostNameInCer tificate property value.
A DNS name can include wild-card characters. Prior version 7.2, the Microsoft JDBC Driver for SQL Server
doesn't support wild-card matching. That is, abc.com won't match *.com but *.com will match *.com. With
version 7.2 and up, standard certificate wild-card matching is supported.

See also
Using encryption
Securing JDBC driver applications
Connecting with encryption
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The examples in this article describe how to use connection string properties that allow applications to use
Transport Layer Security (TLS) encryption in a Java application. For more information about these new
connection string properties such as encr ypt , trustSer verCer tificate , trustStore , trustStorePassword , and
hostNameInCer tificate , see Setting the Connection Properties.

Configuring the connection


When the encr ypt property is set to true and the trustSer verCer tificate property is set to true , the
Microsoft JDBC Driver for SQL Server won't validate the SQL Server TLS certificate. This setting is common for
allowing connections in test environments, such as where the SQL Server instance has only a self-signed
certificate.
The following code example demonstrates how to set the trustSer verCer tificate property in a connection
string:

String connectionUrl =
"jdbc:sqlserver://localhost:1433;" +
"databaseName=AdventureWorks;integratedSecurity=true;" +
"encrypt=true;trustServerCertificate=true";

When the encr ypt property is set to true and the trustSer verCer tificate property is set to false , the
Microsoft JDBC Driver for SQL Server will validate the SQL Server TLS certificate. Validating the server
certificate is a part of the TLS handshake and ensures that the server is the correct server to connect to. To
validate the server certificate, the trust material must be supplied at connection time either by using trustStore
and trustStorePassword connection properties explicitly, or by using the underlying Java Virtual Machine
(JVM)'s default trust store implicitly.
The trustStore property specifies the path (including filename) to the certificate trustStore file, which contains
the list of certificates that the client trusts. The trustStorePassword property specifies the password used to
check the integrity of the trustStore data. For more information on using the JVM's default trust store, see the
Configuring the client for encryption.
The following code example demonstrates how to set the trustStore and trustStorePassword properties in a
connection string:

String connectionUrl =
"jdbc:sqlserver://localhost:1433;" +
"databaseName=AdventureWorks;integratedSecurity=true;" +
"encrypt=true; trustServerCertificate=false;" +
"trustStore=storeName;trustStorePassword=storePassword";

The JDBC Driver provides another property, hostNameInCer tificate , which specifies the host name of the
server. The value of this property must match the subject property of the certificate.
The following code example demonstrates how to use the hostNameInCer tificate property in a connection
string:
String connectionUrl =
"jdbc:sqlserver://localhost:1433;" +
"databaseName=AdventureWorks;integratedSecurity=true;" +
"encrypt=true; trustServerCertificate=false;" +
"trustStore=storeName;trustStorePassword=storePassword;" +
"hostNameInCertificate=hostName";

NOTE
Alternatively, you can set the value of connection properties by using the appropriate setter methods provided by the
SQLServerDataSource class.

If the encr ypt property is true and the trustSer verCer tificate property is false and if the server name in the
connection string doesn't match the server name in the TLS certificate, the following error will be issued:
The driver couldn't establish a secure connection to SQL Server by using Secure Sockets Layer (SSL)
encryption. Error: "java.security.cert.CertificateException: Failed to validate the server name in a
certificate during Secure Sockets Layer (SSL) initialization."
. With version 7.2 and up, the driver supports wildcard pattern matching in the left-most label of the server
name in the TLS certificate.

See also
Using encryption
Securing JDBC driver applications
Configuring the client for encryption
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server or client has to validate that the server is the correct server and its
certificate is issued by a certificate authority the client trusts. To validate the server certificate, the trust material
must be supplied at connection time. Also, the issuer of the server certificate must be a certificate authority that
the client trusts.
This article first describes how to supply the trust material in the client computer. Then it describes how to
import a server certificate to the client computer's trust store when the instance of SQL Server's Transport Layer
Security (TLS) certificate is issued by a private certificate authority.
For more information about validating the server certificate, see the Validating Server TLS Certificate section in
Understanding encryption support.

Configuring the client trust store


Validating the server certificate requires the trust material at connection time either by using trustStore and
trustStorePassword connection properties explicitly, or by using the underlying Java Virtual Machine (JVM)'s
default trust store implicitly. For more information about how to set the trustStore and trustStorePassword
properties in a connection string, see Connecting with encryption.
If the trustStore property is unspecified or set to null, the Microsoft JDBC Driver for SQL Server will rely on the
underlying JVM's security provider, the Java Secure Socket Extension (SunJSSE). The SunJSSE provider provides
a default TrustManager, which is used to validate X.509 certificates returned by SQL Server against the trust
material provided in a trust store.
The TrustManager tries to locate the default trustStore in the following search order:
If the system property "javax.net.ssl.trustStore" is defined, the TrustManager tries to find the default trustStore
file by using the filename specified by that system property.
If the "javax.net.ssl.trustStore" system property wasn't specified, and the file "<java-
home>/lib/security/jssecacerts" exists, that file is used.
If the file "<java-home>/lib/security/cacerts" exists, that file is used.
For more information, see the SUNX509 TrustManager interface documentation on the Sun Microsystems Web
site.
The Java Runtime Environment allows you to set the trustStore and trustStorePassword system properties as
follows:

java -Djavax.net.ssl.trustStore=C:\MyCertificates\storeName
java -Djavax.net.ssl.trustStorePassword=storePassword

In this case, any application running on this JVM will use these settings as default. To override the default
settings in your application, you should set the trustStore and trustStorePassword connection properties
either in the connection string or in the appropriate setter method of the SQLServerDataSource class.
Also, you can configure and manage the default trust store files such as "<java-home>/lib/security/jssecacerts"
and "<java-home>/lib/security/cacerts". To do that, use the JAVA "keytool" utility that is installed with the JRE
(Java Runtime Environment). For more information about the "keytool" utility, see keytool documentation on the
Oracle Web site.
Importing the server certificate to trust store
During the TLS handshake, the server sends its public key certificate to the client. The issuer of a public key
certificate is known as a Certificate Authority (CA). The client has to ensure the certificate authority is one the
client trusts. This assurance is achieved by knowing the public key of trusted CAs in advance. Normally, the JVM
ships with a predefined set of trusted certificate authorities.
If the instance of SQL Server's TLS certificate is issued by a private certificate authority, you must add the
certificate authority's certificate to the list of trusted certificates in the client computer's trust store.
To do that, use the JAVA "keytool" utility that is installed with the JRE (Java Runtime Environment). The following
command prompt demonstrates how to use the "keytool" utility to import a certificate from a file:

keytool -import -v -trustcacerts -alias myServer -file caCert.cer -keystore truststore.ks

The example uses a file named "caCert.cer" as a certificate file. You must obtain this certificate file from the
server. The following steps explain how to export the server certificate to a file:
1. Select Start and then Run, and type MMC. (MMC is an acronym for the Microsoft Management Console.)
2. In MMC, open the Certificates.
3. Expand Personal and then Certificates.
4. Right-click the server certificate, and then select All Tasks\Export.
5. Select Next to move past the welcome dialog box of the Certificate Export Wizard.
6. Confirm that No, do not export the private key is selected, and then select Next.
7. Make sure to select either DER encoded binary X.509 (.CER) or Base-64 encoded X.509 (.CER), and then select
Next.
8. Enter an export file name.
9. Select Next, and then select Finish to export the certificate.

See also
Using encryption
Securing JDBC driver applications
FIPS mode
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server supports running in JVMs configured to be FIPS 140 Compliant.

Prerequisites
FIPS configured JVM
Appropriate TLS/SSL Certificate
Appropriate policy files
Appropriate Configuration parameters

FIPS configured JVM


Generally, applications can configure the java.security file to use FIPS-compliant crypto providers. See the
documentation specific to your JVM for how to configure FIPS 140 compliance.
To see the approved modules for FIPS Configuration, refer to Validated Modules in the Cryptographic Module
Validation Program.
Vendors may have some more steps to configure a JVM with FIPS.

Appropriate TLS certificate


To connect to SQL Server in FIPS mode, a valid TLS/SSL Certificate is required. Install or import it into the Java
Key Store on the client machine (JVM) where FIPS is enabled.
Importing TLS certificate in Java keyStore
For FIPS, most likely you need to import the certificate (.cert) in either PKCS or a provider-specific format. Use
the following snippet to import the TLS/SSL certificate and store it in a working directory with the appropriate
KeyStore format. TRUST_STORE_PASSWORD is your password for Java KeyStore.
public void saveGenericKeyStore(
String provider,
String trustStoreType,
String certName,
String certPath
) throws KeyStoreException, CertificateException,
NoSuchAlgorithmException, NoSuchProviderException,
IOException
{
KeyStore ks = KeyStore.getInstance(trustStoreType, provider);
FileOutputStream os = new FileOutputStream("./MyTrustStore_" + trustStoreType);
ks.load(null, null);
ks.setCertificateEntry(certName, getCertificate(certPath));
ks.store(os, TRUST_STORE_PASSWORD.toCharArray());
os.flush();
os.close();
}

private Certificate getCertificate(String pathName)


throws FileNotFoundException, CertificateException
{
FileInputStream fis = new FileInputStream(pathName);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
return cf.generateCertificate(fis);
}

The following example is importing an Azure TLS/SSL Certificate in PKCS12 format with the BouncyCastle
Provider. The certificate is imported in the working directory named MyTrustStore_PKCS12 by using the
following snippet:
saveGenericKeyStore(BCFIPS, PKCS12, "SQLAzure SSL Certificate Name", "SQLAzure.cer");

Appropriate policy files


For some FIPS Providers, unrestricted Policy jars are needed. In such cases, for Sun / Oracle, download the Java
Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files for JRE 8 or JRE 7.

Appropriate configuration parameters


To run the JDBC Driver in FIPS-compliant mode, configure connection properties as shown in following table.
Properties
P RO P ERT Y TYPE DEFA ULT DESC RIP T IO N N OT ES

encrypt boolean ["true / "false" For FIPS enabled


false"] JVM encrypt
property should be
true

TrustServerCertificate boolean ["true / "false" For FIPS, the user


false"] needs to validate
certificate chain, so
the user should use
"false" value for this
property.
P RO P ERT Y TYPE DEFA ULT DESC RIP T IO N N OT ES

trustStore String null Your Java Keystore


file path where you
imported your
certificate. If you
install certificate on
your system, then no
need to pass
anything. Driver uses
cacerts or jssecacerts
files.

trustStorePassword String null The password used


to check the integrity
of the trustStore
data.

fips boolean ["true / "false" For FIPS enabled Added in 6.1.4


false"] JVM this property (Stable release 6.2.2)
should be true

fipsProvider String null FIPS provider Added in 6.1.2


configured in JVM. (Stable release 6.2.2),
For example, BCFIPS deprecated in 6.4.0 -
or SunPKCS11-NSS see the details Here.

trustStoreType String JKS For FIPS mode set Added in 6.1.2


trust store type (Stable release 6.2.2)
either PKCS12 or
type defined by FIPS
provider
Improving performance and reliability (JDBC)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


One aspect of application development that is common to all applications is the constant need to improve
performance and reliability. There are many techniques to satisfy this need with the Microsoft JDBC Driver for
SQL Server.
The articles in this section describe various techniques for improving application performance and reliability
when using the JDBC driver.

In this section
A RT IC L E DESC RIP T IO N

Closing objects when not in use Describes the importance of closing JDBC driver objects
when they're no longer needed.

Managing transaction size Describes techniques for improving transaction performance.

Working with statements and result sets Describes techniques for improving performance when using
the Statement or ResultSet objects.

Using adaptive buffering Describes an adaptive buffering feature, which is designed to


retrieve any kind of large-value data without the overhead
of server cursors.

Sparse columns Discusses the JDBC driver's support for SQL Server sparse
columns.

Prepared statement metadata caching for the JDBC driver Discusses the techniques for improving performance with
prepared statement queries.

Using bulk copy API for batch insert operation Describes how to enable Bulk Copy API for batch insert
operations and its benefits.

Not sending String parameters as Unicode When working with CHAR, VARCHAR, and
LONGVARCHAR data, users can set the connection
property sendStringParametersAsUnicode to false
for optimal performance gain.

See also
Overview of the JDBC driver
Closing objects when not in use
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you work with closable objects of Microsoft JDBC Driver for SQL Server, you should explicitly close them
by using their close methods when they're no longer needed. This pattern particularly applies to
SQLServerResultSet and the Statement objects like SQLServerStatement, SQLServerPreparedStatement, and
SQLServerCallableStatement. Closing improves performance by freeing up driver and server resources quickly,
instead of waiting for the Java Virtual Machine garbage collector to do it for you.
Closing objects is crucial to maintaining good concurrency on the server when you're using scroll locks. Scroll
locks in the last accessed fetch buffer are held until the result set is closed. Similarly, statement prepared handles
are held until the statement is closed. If you're reusing a connection for multiple statements, closing statements
before they go out of scope allows the server to clean up the prepared handles earlier.

See also
Improving performance and reliability with the JDBC driver
Managing transaction size
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you work with transactions, it's important to keep your transactions as brief as possible. The default mode
of autocommit, which you can enable or disable by using the setAutoCommit method, will commit every action
for you. This mode is the easiest mode to work with for most developers.
When you use manual transactions, make sure that your code commits the transaction as quickly as possible.
Holding open a transaction blocks other users from accessing the data. For example, a good programming
practice might be to put a rollback call in your catch block and a commit call in a finally block. However, this
practice depends on the design of your application.
Keep the size of your transactions small to improve concurrency. For example, if you start a manual transaction
and modify 10,000 rows in a 20,000-row table, you will have half the table blocked from all other users, even if
they are only reading the data. Reducing your modifications to 2,000 rows leaves 90 percent of the table
available.
Additionally, be sure to use the lock time-out setting if your application expects some blocking issues. You can
set the time-out by using the setLockTimeout method. The default for the lock time-out is -1, which means that
it will block indefinitely while waiting for the lock. You can set the lock time-out to 30 seconds, which will cause
the blocked connection to time out in 30 seconds if blocked by another connection.

See also
Improving performance and reliability with the JDBC driver
Working with statements and result sets
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you work with the Microsoft JDBC Driver for SQL Server and the Statement and ResultSet objects that it
provides, there are several techniques that you can use to improve the performance and reliability of your
applications.

Use the appropriate statement object


When you use one of the JDBC driver Statement objects, such as the SQLServerStatement,
SQLServerPreparedStatement, or the SQLServerCallableStatement object, make sure that you are using the
appropriate object for the job.
If you do not have OUT parameters, you do not need to use the SQLServerCallableStatement object. Instead,
use the SQLServerStatement or the SQLServerPreparedStatement object.
If you do not intend to execute the statement more than once, or do not have IN or OUT parameters, you do
not need to use the SQLServerCallableStatement or the SQLServerPreparedStatement object. Instead, use
the SQLServerStatement object.

Use the appropriate concurrency for ResultSet objects


Do not ask for updatable concurrency when you create statements that produce result sets unless you actually
intend to update the results. The default forward-only, read-only cursor model is fastest for reading small result
sets.

Limit the size of your result sets


Consider using the setMaxRows method (or SET ROWCOUNT or SELECT TOP N SQL syntax) to limit the number
of rows returned from potentially large result sets. If you must deal with large result sets, consider using an
adaptive response buffering by setting the connection string property responseBuffering=adaptive, which is the
default mode. This approach allows the application to process large result sets without requiring the server-side
cursors and minimizes the application memory usage. For more information, see Using adaptive buffering.

Use the appropriate fetch size


For read-only server cursors, the tradeoff is round trips to the server versus the amount of memory used in the
driver. For updatable server cursors, the fetch size also influences the sensitivity of the result set to changes and
concurrency on the server. Updates to rows within the current fetch buffer are not visible until an explicit
refreshRow method is issued or until the cursor leaves the fetch buffer. Large fetch buffers will have better
performance (fewer server round trips) but are less sensitive to changes and reduce concurrency on the server
if CONCUR_SS_SCROLL_LOCKS (1009) is used. For maximum sensitivity to changes, use a fetch size of 1.
However this setting will incur a round trip to the server for every row fetched.

Use streams for large IN parameters


Use streams or BLOBs and CLOBs that are incrementally materialized to handle updating large column values or
sending large IN parameters. The JDBC driver "chunks" these types to the server in multiple round trips,
allowing you to set and update values larger than what will fit in memory.
See also
Improving performance and reliability with the JDBC driver
Using adaptive buffering
4/27/2022 • 7 minutes to read • Edit Online

Download JDBC Driver


Adaptive buffering is designed to retrieve any kind of large-value data without the overhead of server cursors.
Applications can use the adaptive buffering feature with all versions of SQL Server that are supported by the
driver.
Normally, when the Microsoft JDBC Driver for SQL Server executes a query, the driver retrieves all of the results
from the server into application memory. Although this approach minimizes resource consumption on the SQL
Server, it can throw an OutOfMemoryError in the JDBC application for the queries that produce very large
results.
In order to allow applications to handle very large results, the Microsoft JDBC Driver for SQL Server provides
adaptive buffering. With adaptive buffering, the driver retrieves statement execution results from the SQL
Server as the application needs them, rather than all at once. The driver also discards the results as soon as the
application can no longer access them. The following are some examples where the adaptive buffering can be
useful:
The quer y produces a ver y large result set: The application can execute a SELECT statement that
produces more rows than the application can store in memory. In previous releases, the application had
to use a server cursor to avoid an OutOfMemoryError. Adaptive buffering provides the ability to do a
forward-only read-only pass of an arbitrarily large result set without requiring a server cursor.
The quer y produces ver y large SQLServerResultSet columns or SQLServerCallableStatement OUT
parameter values: The application can retrieve a single value (column or OUT parameter) that is too
large to fit entirely in application memory. Adaptive buffering allows the client application to retrieve
such a value as a stream, by using the getAsciiStream, the getBinaryStream, or the getCharacterStream
methods. The application retrieves the value from the SQL Server as it reads from the stream.

NOTE
With adaptive buffering, the JDBC driver buffers only the amount of data that it has to. The driver does not provide any
public method to control or limit the size of the buffer.

Setting adaptive buffering


Starting with the JDBC driver version 2.0, the default behavior of the driver is "adaptive ". In other words, in
order to get the adaptive buffering behavior, your application does not have to request the adaptive behavior
explicitly. In the version 1.2 release, however, the buffering mode was "full " by default and the application had to
request the adaptive buffering mode explicitly.
There are three ways that an application can request that statement execution should use adaptive buffering:
The application can set the connection property responseBuffering to "adaptive". For more information
on setting the connection properties, see Setting the connection properties.
The application can use the setResponseBuffering method of the SQLServerDataSource object to set the
response buffering mode for all connections created through that SQLServerDataSource object.
The application can use the setResponseBuffering method of the SQLServerStatement class to set the
response buffering mode for a particular statement object.
When using the JDBC Driver version 1.2, applications needed to cast the statement object to a
SQLServerStatement class to use the setResponseBuffering method. The code examples in the Reading large
data sample and Reading large data with stored procedures sample demonstrate this old usage.
However, with the JDBC driver version 2.0, applications can use the isWrapperFor method and the unwrap
method to access the vendor-specific functionality without any assumption about the implementation class
hierarchy. For example code, see the Updating large data sample topic.

Retrieving large data with adaptive buffering


When large values are read once by using the get<Type>Stream methods, and the ResultSet columns and the
CallableStatement OUT parameters are accessed in the order returned by the SQL Server, adaptive buffering
minimizes the application memory usage when processing the results. When using adaptive buffering:
The get<Type>Stream methods defined in the SQLServerResultSet and SQLServerCallableStatement
classes return read-once streams by default, although the streams can be reset if marked by the
application. If the application wants to reset the stream, it has to call the mark method on that stream
first.
The get<Type>Stream methods defined in the SQLServerClob and SQLServerBlob classes return streams
that can always be repositioned to the start position of the stream without calling the mark method.
When the application uses adaptive buffering, the values retrieved by the get<Type>Stream methods can only
be retrieved once. If you try to call any get<Type> method on the same column or parameter after calling the
get<Type>Stream method of the same object, an exception is thrown with the message, "The data has been
accessed and is not available for this column or parameter".

NOTE
A call to ResultSet.close() in the middle of processing a ResultSet would require the Microsoft JDBC Driver for SQL Server
to read and discard all remaining packets. This may take substantial time if the query returned a large data set and
especially if the network connection is slow.

Guidelines for using adaptive buffering


Developers should follow these important guidelines to minimize memory usage by the application:
Avoid using the connection string property selectMethod=cursor to allow the application to process a
very large result set. The adaptive buffering feature allows applications to process very large forward-
only, read-only result sets without using a server cursor. Note that when you set selectMethod=cursor ,
all forward-only, read-only result sets produced by that connection are impacted. In other words, if your
application routinely processes short result sets with a few rows, creating, reading, and closing a server
cursor for each result set will use more resources on both client-side and server-side than is the case
where the selectMethod is not set to cursor .
Read large text or binary values as streams by using the getAsciiStream, the getBinaryStream, or the
getCharacterStream methods instead of the getBlob or the getClob methods. Starting with the version 1.2
release, the SQLServerCallableStatement class provides new get<Type>Stream methods for this purpose.
Ensure that columns with potentially large values are placed last in the list of columns in a SELECT
statement and that the get<Type>Stream methods of the SQLServerResultSet are used to access the
columns in the order they are selected.
Ensure that OUT parameters with potentially large values are declared last in the list of parameters in the
SQL used to create the SQLServerCallableStatement. In addition, ensure that the get<Type>Stream
methods of the SQLServerCallableStatement are used to access the OUT parameters in the order they are
declared.
Avoid executing more than one statement on the same connection simultaneously. Executing another
statement before processing the results of the previous statement may cause the unprocessed results to
be buffered into the application memory.
There are some cases where using selectMethod=cursor instead of responseBuffering=adaptive
would be more beneficial, such as:
If your application processes a forward-only, read-only result set slowly, such as reading each row
after some user input, using selectMethod=cursor instead of responseBuffering=adaptive
might help reduce resource usage by SQL Server.
If your application processes two or more forward-only, read-only result sets at the same time on
the same connection, using selectMethod=cursor instead of responseBuffering=adaptive
might help reduce the memory required by the driver while processing these result sets.
In both cases, you need to consider the overhead of creating, reading, and closing the server cursors.
In addition, the following list provides some recommendations for scrollable and forward-only updatable result
sets:
For scrollable result sets, when fetching a block of rows the driver always reads into memory the number
of rows indicated by the getFetchSize method of the SQLServerResultSet object, even when the adaptive
buffering is enabled. If scrolling causes an OutOfMemoryError, you can reduce the number of rows
fetched by calling the setFetchSize method of the SQLServerResultSet object to set the fetch size to a
smaller number of rows, even down to 1 row, if necessary. If this does not prevent an OutOfMemoryError,
avoid including very large columns in scrollable result sets.
For forward-only updatable result sets, when fetching a block of rows the driver normally reads into
memory the number of rows indicated by the getFetchSize method of the SQLServerResultSet object,
even when the adaptive buffering is enabled on the connection. If calling the next method of the
SQLServerResultSet object results in an OutOfMemoryError, you can reduce the number of rows fetched
by calling the setFetchSize method of the SQLServerResultSet object to set the fetch size to a smaller
number of rows, even down to 1 row, if necessary. You can also force the driver not to buffer any rows by
calling the setResponseBuffering method of the SQLServerStatement object with "adaptive " parameter
before executing the statement. Because the result set is not scrollable, if the application accesses a large
column value by using one of the get<Type>Stream methods, the driver discards the value as soon as the
application reads it just as it does for the forward-only read-only result sets.

See also
Improving performance and reliability with the JDBC driver
Sparse columns
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


Sparse columns are ordinary columns that have an optimized storage for null values. Sparse columns reduce
the space requirements for null values at the cost of more overhead to retrieve non-null values. Consider using
sparse columns when the space saved is at least 20 percent to 40 percent.
The SQL Server JDBC Driver 3.0 supports sparse columns when you connect to a SQL Server 2008 (or later)
server. You can use SQLServerDatabaseMetaData.getColumns,
SQLServerDatabaseMetaData.getFunctionColumns, or SQLServerDatabaseMetaData.getProcedureColumns to
determine which column is sparse and which column is the column set column.
The code file for this sample is named SparseColumns.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\sparse

Column sets are computed columns that return all sparse columns in untyped XML form. Consider using
column sets when the number of columns in a table is large or greater than 1024 or operating on individual
sparse columns is cumbersome. A column set can contain up to 30,000 columns.

Example
Description
This sample demonstrates how to detect column sets. It also shows how to parse a column set's XML output to
get the data from the sparse columns.
The code listing is the Java source code. Before you compile the application, change the connection string.
Code

import java.io.StringReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class SparseColumns {

public static void main(String args[]) {

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";
try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt =
con.createStatement()) {

createColdCallingTable(stmt);

// Determine the column set column


String columnSetColName = null;
String strCmd = "SELECT name FROM sys.columns WHERE object_id=(SELECT OBJECT_ID('ColdCalling'))
AND is_column_set = 1";

try (ResultSet rs = stmt.executeQuery(strCmd)) {


if (rs.next()) {
columnSetColName = rs.getString(1);
System.out.println(columnSetColName + " is the column set column!");
}
}

strCmd = "SELECT * FROM ColdCalling";


try (ResultSet rs = stmt.executeQuery(strCmd)) {

// Iterate through the result set


ResultSetMetaData rsmd = rs.getMetaData();

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();


DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
while (rs.next()) {
// Iterate through the columns
for (int i = 1; i <= rsmd.getColumnCount(); ++i) {
String name = rsmd.getColumnName(i);
String value = rs.getString(i);

// If this is the column set column


if (name.equalsIgnoreCase(columnSetColName)) {
System.out.println(name);

// Instead of printing the raw XML, parse it


if (value != null) {
// Add artificial root node "sparse" to ensure XML is well formed
String xml = "<sparse>" + value + "</sparse>";

is.setCharacterStream(new StringReader(xml));
Document doc = db.parse(is);

// Extract the NodeList from the artificial root node that was added
NodeList list = doc.getChildNodes();
Node root = list.item(0); // This is the <sparse> node
NodeList sparseColumnList = root.getChildNodes(); // These are the xml
column nodes

// Iterate through the XML document


for (int n = 0; n < sparseColumnList.getLength(); ++n) {
Node sparseColumnNode = sparseColumnList.item(n);
String columnName = sparseColumnNode.getNodeName();
// The column value is not in the sparseColumNode, it is the value of
the
// first child of it
Node sparseColumnValueNode = sparseColumnNode.getFirstChild();
String columnValue = sparseColumnValueNode.getNodeValue();

System.out.println("\t" + columnName + "\t: " + columnValue);


}
}
} else { // Just print the name + value of non-sparse columns
System.out.println(name + "\t: " + value);
}
}
System.out.println();// New line between rows
System.out.println();// New line between rows
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

private static void createColdCallingTable(Statement stmt) throws SQLException {


stmt.execute("if exists (select * from sys.objects where name = 'ColdCalling')" + "drop table
ColdCalling");

String sql = "CREATE TABLE ColdCalling ( ID int IDENTITY(1,1) PRIMARY KEY, [Date] date, [Time]
time, PositiveFirstName nvarchar(50) SPARSE, PositiveLastName nvarchar(50) SPARSE, SpecialPurposeColumns
XML COLUMN_SET FOR ALL_SPARSE_COLUMNS );";
stmt.execute(sql);

sql = "INSERT ColdCalling ([Date], [Time]) VALUES ('10-13-09','07:05:24') ";


stmt.execute(sql);

sql = "INSERT ColdCalling ([Date], [Time], PositiveFirstName, PositiveLastName) VALUES ('07-20-


09','05:00:24', 'AA', 'B') ";
stmt.execute(sql);

sql = "INSERT ColdCalling ([Date], [Time], PositiveFirstName, PositiveLastName) VALUES ('07-20-


09','05:15:00', 'CC', 'DD') ";
stmt.execute(sql);
}
}

See also
Improving performance and reliability with the JDBC driver
Prepared statement metadata caching for the JDBC
driver
4/27/2022 • 5 minutes to read • Edit Online

Download JDBC Driver


This article provides information on the two changes that are implemented to enhance the performance of the
driver.

Batching of unprepare for prepared statements


Since version 6.1.6-preview, an improvement in performance was implemented through minimizing server
round trips to SQL Server. Previously, for every prepareStatement query, a call to unprepare was also sent. Now,
the driver is batching unprepare queries up to the threshold "ServerPreparedStatementDiscardThreshold",
which has a default value of 10.

NOTE
Users can change the default value with the following method: setServerPreparedStatementDiscardThreshold(int value)

One more change introduced from 6.1.6-preview is that before this version, the driver would always call
sp_prepexec . Now, for the first execution of a prepared statement, driver calls sp_executesql and for the rest it
executes sp_prepexec and assigns a handle to it. More details can be found here.

NOTE
Users can change the default behavior to the previous versions of always calling sp_prepexec by setting
enablePrepareOnFirstPreparedStatementCall to true using the following method:
setEnablePrepareOnFirstPreparedStatementCall(boolean value)

List of the new APIs introduced with this change, for batching of unprepare for prepared statements
SQLServerConnection

N EW M ET H O D DESC RIP T IO N

int getDiscardedServerPreparedStatementCount() Returns the number of currently outstanding unprepare


actions.

void closeUnreferencedPreparedStatementHandles() Forces the unprepare requests for any outstanding


discarded prepared statements to be executed.
N EW M ET H O D DESC RIP T IO N

boolean getEnablePrepareOnFirstPreparedStatementCall() Returns the behavior for a specific connection instance. If


false, the first execution calls sp_executesql and doesn't
prepare a statement. If a second execution happens, it calls
sp_prepexec and actually sets up a prepared statement
handle. Later executions call sp_execute . This behavior
relieves the need for sp_unprepare on prepared statement
close if the statement is only executed once. The default for
this option can be changed by calling
setDefaultEnablePrepareOnFirstPreparedStatementCall().

void setEnablePrepareOnFirstPreparedStatementCall(boolean Specifies the behavior for a specific connection instance. If


value) the value is false, the first execution calls sp_executesql
and doesn't prepare a statement. If a second execution
happens, it calls sp_prepexec and actually sets up a
prepared statement handle. Later executions call
sp_execute . This behavior relieves the need for
sp_unprepare on prepared statement close if the
statement is only executed once.

int getServerPreparedStatementDiscardThreshold() Returns the behavior for a specific connection instance. This
setting controls how many outstanding discard actions (
sp_unprepare ) there can be per connection before a call to
clean up the outstanding handles on the server is executed.
If the setting is <= 1, unprepare actions are executed
immediately on prepared statement close. If it's set to
{@literal >} 1, these calls are batched together to avoid the
overhead of calling sp_unprepare too often. The default for
this option can be changed by calling
getDefaultServerPreparedStatementDiscardThreshold().

void setServerPreparedStatementDiscardThreshold(int value) Specifies the behavior for a specific connection instance. This
setting controls how many outstanding discard actions (
sp_unprepare ) there can be per connection before a call to
clean up the outstanding handles on the server is executed.
If the setting is <= 1, unprepare actions are executed
immediately on prepared statement close. If it is set to > 1,
these calls are batched together to avoid overhead of calling
sp_unprepare too often.

SQLServerDataSource

N EW M ET H O D DESC RIP T IO N

void setEnablePrepareOnFirstPreparedStatementCall(boolean If this configuration is false, the first execution of a prepared


enablePrepareOnFirstPreparedStatementCall) statement calls sp_executesql and doesn't prepare a
statement. If a second execution happens it calls
sp_prepexec and actually sets up a prepared statement
handle. Later executions call sp_execute . This behavior
relieves the need for sp_unprepare on prepared statement
close if the statement is only executed once.
N EW M ET H O D DESC RIP T IO N

boolean getEnablePrepareOnFirstPreparedStatementCall() If this configuration returns false, the first execution of a


prepared statement calls sp_executesql and doesn't
prepare a statement. If a second execution happens, it calls
sp_prepexec and actually sets up a prepared statement
handle. Later executions call sp_execute . This behavior
relieves the need for sp_unprepare on prepared statement
close if the statement is only executed once.

void setServerPreparedStatementDiscardThreshold(int This setting controls how many outstanding discard actions (
serverPreparedStatementDiscardThreshold) sp_unprepare ) there can be per connection before a call to
clean up the outstanding handles on the server is executed.
If the setting is <= 1, unprepare actions are executed
immediately on prepared statement close. If it's set to
{@literal >} 1, these calls are batched together to avoid the
overhead of calling sp_unprepare too often

int getServerPreparedStatementDiscardThreshold() This setting controls how many outstanding discard actions (
sp_unprepare ) there can be per connection before a call to
clean up the outstanding handles on the server is executed.
If the setting is <= 1, unprepare actions are executed
immediately on prepared statement close. If it's set to
{@literal >} 1, these calls are batched together to avoid the
overhead of calling sp_unprepare too often.

Prepared statement metadata caching


Starting with version 6.3.0-preview, Microsoft JDBC driver for SQL Server supports prepared statement caching.
Before v6.3.0-preview, if one executes a query that has been already prepared and stored in the cache, calling
the same query again won't result in preparing it. Now, the driver looks up the query in the cache and finds the
handle and executes it with sp_execute . Prepared Statement Metadata caching is disabled by default. To enable
it, you need to call the following method on the connection object:
setStatementPoolingCacheSize(int value) //value is the desired cache size (any value bigger than 0)
setDisableStatementPooling(boolean value) //false allows the caching to take place

For example: connection.setStatementPoolingCacheSize(10) connection.setDisableStatementPooling(false)

List of the new APIs introduced with this change, for prepared statement metadata caching
SQLServerConnection

N EW M ET H O D DESC RIP T IO N

void setDisableStatementPooling(boolean value) Sets statement pooling to true or false.

boolean getDisableStatementPooling() Returns true if statement pooling is disabled.

void setStatementPoolingCacheSize(int value) Specifies the size of the prepared statement cache for this
connection. A value less than 1 means no cache.

int getStatementPoolingCacheSize() Returns the size of the prepared statement cache for this
connection. A value less than 1 means no cache.

int getStatementHandleCacheEntryCount() Returns the current number of pooled prepared statement


handles.
N EW M ET H O D DESC RIP T IO N

boolean isPreparedStatementCachingEnabled() Whether statement pooling is enabled or not for this


connection.

SQLServerDataSource

N EW M ET H O D DESC RIP T IO N

void setDisableStatementPooling(boolean Sets the statement pooling to true or false


disableStatementPooling)

boolean getDisableStatementPooling() Returns true if statement pooling is disabled.

void setStatementPoolingCacheSize(int Specifies the size of the prepared statement cache for this
statementPoolingCacheSize) connection. A value less than 1 means no cache.

int getStatementPoolingCacheSize() Returns the size of the prepared statement cache for this
connection. A value less than 1 means no cache.

See also
Improving performance and reliability with the JDBC driver
Diagnosing problems with the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


No matter how well an application is designed and developed, problems will inevitably occur. When they do, it's
important to have some techniques for diagnosing those problems. When using the Microsoft JDBC Driver for
SQL Server, some common problems that can occur aren't having the right driver version or being unable to
connect to a database.
The articles in this section discuss many techniques for diagnosing these and other problems including error
handling, checking the driver version, tracing, and troubleshooting connectivity issues.

In this section
A RT IC L E DESC RIP T IO N

Handling errors Describes how to handle errors that are returned from SQL
Server.

Getting the driver version Describes how to determine which version of the JDBC
driver is installed.

Tracing driver operation Describes how to enable tracing when using the JDBC driver.

Troubleshooting connectivity Describes how to troubleshoot database connectivity.

Accessing diagnostic information in the extended events log Describes how to use information in the server's extended
events log to understand connection failures.

See also
Overview of the JDBC driver
Handling errors
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When using the Microsoft JDBC Driver for SQL Server, all database error conditions are returned to your Java
application as exceptions using the SQLServerException class. The following methods of the
SQLServerException class are inherited from java.sql.SQLException and java.lang.Throwable; and they can be
used to return specific information about the SQL Server error that has occurred:
getSQLState() returns the standard X/Open or SQL99 state code of the exception.
getErrorCode() returns the specific database error number.
getMessage() returns the full text of the exception. The error message text describes the problem, and
frequently includes placeholders for information, such as object names, that are inserted in the error
message when it's displayed.
getNextException() returns the next SQLServerException object or null if there are no more exception
objects to return.
getSQLServerError()returns the SQLServerError object containing detailed info about the exception as
received from SQL Server. This method returns null if no server error has occurred.
The following methods of the SQLServerError class can be used to obtain more details about the error
generated from the server.
SQLServerError.getErrorMessage() returns the error message as received from the server.
SQLServerError.getErrorNumber() returns a number that identifies the type of the error.
SQLServerError.getErrorState()returns a numeric error code from SQL Server that represents an error,
warning or "no data found" message.
SQLServerError.getErrorSeverity() returns the severity level of the error received.
SQLServerError.getServerName() returns the name of the computer that is running an instance of SQL
Server that generated the error.
SQLServerError.getProcedureName() returns the name of the stored procedure or remote procedure call
(RPC) that generated the error.
SQLServerError.getLineNumber()returns the line number within the Transact-SQL command batch or
stored procedure that generated the error.
In the next example, an open connection to the SQL Server sample database is passed in to the function and a
malformed SQL statement is constructed that doesn't have a FROM clause. Then, the statement is run and an
SQL exception is processed.
public static void executeSQLException(Connection con) {
try (Statement stmt = con.createStatement();) {
String SQL = "SELECT TOP 10 * Person.Contact";
ResultSet rs = stmt.executeQuery(SQL);

while (rs.next()) {
System.out.println(rs.getString("FirstName") + " " + rs.getString("LastName"));
}
}
catch (SQLException se) {
do {
System.out.println("SQL STATE: " + se.getSQLState());
System.out.println("ERROR CODE: " + se.getErrorCode());
System.out.println("MESSAGE: " + se.getMessage());
System.out.println();
se = se.getNextException();
}
while (se != null);
}
}

See also
Diagnosing problems with the JDBC driver
Getting the driver version
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The version of the installed Microsoft JDBC Driver for SQL Server can be found in the following ways:
Call the SQLServerDatabaseMetaData methods getDriverMajorVersion, getDriverMinorVersion, or
getDriverVersion.
The version is displayed in the readme.txt file of the product distribution.
Also, the JDBC driver name can be returned from the getDriverName method call on the
SQLServerDatabaseMetaData class. It will return, for example, "Microsoft JDBC Driver 6.4 for SQL Server".
The following lines are example output from calls to the methods of the SQLServerDatabaseMetaData class:
getDriverName = Microsoft JDBC Driver 6.4 for SQL Server
getDriverMajorVersion =9
getDriverMinorVersion =2
getDriverVersion = 9.2.xxx.x (Where "xxx.x" is the final version number)

See also
Diagnosing problems with the JDBC driver
Tracing driver operation
4/27/2022 • 8 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server supports the use of tracing (or logging) to help resolve issues and
problems with the JDBC driver when it's used in your application. To enable the use of tracing, the JDBC driver
uses the logging APIs in java.util.logging, which provides a set of classes for creating Logger and LogRecord
objects.

NOTE
For the native component (sqljdbc_xa.dll) that is included with the JDBC driver, tracing is enabled by the Built-In
Diagnostics (BID) framework. For information about BID, see Data Access Tracing in SQL Server.

When you develop your application, you can make calls to Logger objects, which in turn create LogRecord
objects, which are then passed to Handler objects for processing. Logger and Handler objects both use logging
levels, and optionally logging filters, to regulate which LogRecords are processed. When the logging operations
are complete, the Handler objects can optionally use Formatter objects to publish the log information.
By default, the java.util.logging framework writes its output to a file. This output log file must have write
permissions for the context under which the JDBC driver is running.

NOTE
For more information about using the various logging objects for program tracing, see the Java Logging APIs
documentation on the Sun Microsystems Web site.

The following sections describe the logging levels and the categories that can be logged, and provide
information about how to enable tracing in your application.

Logging levels
Every log message that is created has an associated logging level. The logging level determines the importance
of the log message, which is defined by the Level class in java.util.logging. Enabling logging at one level also
enables logging at all higher levels. This section describes the logging levels for both public logging categories
and internal logging categories. For more information about the logging categories, see the Logging Categories
section in this article.
The following table describes each of the available logging levels for public logging categories.

NAME DESC RIP T IO N

SEVERE Indicates a serious failure and is the highest level of logging.


In the JDBC driver, this level is used for reporting errors and
exceptions.

WARNING Indicates a potential problem.

INFO Provides informational messages.


NAME DESC RIP T IO N

CONFIG Provides configuration messages. The JDBC driver doesn't


currently provide any configuration messages.

FINE Provides basic tracing information including all exceptions


thrown by the public methods.

FINER Provides detailed tracing information including all public


method entry and exit points with the associated parameter
data types, and all public properties for public classes. Also,
input parameters, output parameters, and method return
values except CLOB, BLOB, NCLOB, Reader, <stream> return
value types.

FINEST Provides highly detailed tracing information. This setting is


the lowest level of logging.

OFF Turns off logging.

ALL Enables logging of all messages.

The following table describes each of the available logging levels for the internal logging categories.

NAME DESC RIP T IO N

SEVERE Indicates a serious failure and is the highest level of logging.


In the JDBC driver, this level is used for reporting errors and
exceptions.

WARNING Indicates a potential problem.

INFO Provides informational messages.

FINE Provides tracing information including basic object creation


and destruction. Also, all exceptions thrown by the public
methods.

FINER Provides detailed tracing information including all public


method entry and exit points with the associated parameter
data types, and all public properties for public classes. Also,
input parameters, output parameters, and method return
values except CLOB, BLOB, NCLOB, Reader, <stream> return
value types.

The following logging categories existed in version 1.2 of the


JDBC driver and had the FINE logging level:
SQLServerConnection, SQLServerStatement, XA, and
SQLServerDataSource. Beginning in the version 2.0 release,
these categories are upgraded to the FINER level.

FINEST Provides highly detailed tracing information. This setting is


the lowest level of logging.

The following logging categories existed in version 1.2 of the


JDBC driver and had the FINEST logging level: TDS.DATA and
TDS.TOKEN. Beginning in the version 2.0 release, they keep
the FINEST logging level.
NAME DESC RIP T IO N

OFF Turns off logging.

ALL Enables logging of all messages.

Logging Categories
When you create a Logger object, you must tell the object, which named entity or category that you're interested
in getting log information from. The JDBC driver supports the following public logging categories, which are all
defined in the com.microsoft.sqlserver.jdbc driver package.

NAME DESC RIP T IO N

Connection Logs messages in the SQLServerConnection class. The


applications can set the logging level as FINER.

Statement Logs messages in the SQLServerStatement class. The


applications can set the logging level as FINER.

DataSource Logs messages in the SQLServerDataSource class. The


applications can set the logging level as FINE.

ResultSet Logs messages in the SQLServerResultSet class. The


applications can set the logging level as FINER.

Driver Logs messages in the SQLServerDriver class. The


applications can set the logging level as FINER.

Starting with the Microsoft JDBC Driver version 2.0, the driver also provides the
com.microsoft.sqlserver.jdbc.internals package, which includes the logging support for the following internal
logging categories.

NAME DESC RIP T IO N

AuthenticationJNI Logs messages about the Windows-integrated


authentication issues (when the authenticationScheme
connection property is implicitly or explicitly set to
NativeAuthentication ).

The applications can set the logging level as FINEST and


FINE.

SQLServerConnection Logs messages in the SQLServerConnection class. The


applications can set the logging level as FINE and FINER.

SQLServerDataSource Logs messages in the SQLServerDataSource,


SQLServerConnectionPoolDataSource, and
SQLServerPooledConnection classes.

The applications can set the logging level as FINER.


NAME DESC RIP T IO N

InputStream Logs messages about the following data types:


java.io.InputStream, java.io.Reader and the data types, which
have a max specifier such as varchar, nvarchar, and varbinary
data types.

The applications can set the logging level as FINER.

SQLServerException Logs messages in the SQLServerException class. The


applications can set the logging level as FINE.

SQLServerResultSet Logs messages in the SQLServerResultSet class. The


applications can set the logging level as FINE, FINER, and
FINEST.

SQLServerStatement Logs messages in the SQLServerStatement class. The


applications can set the logging level as FINE, FINER, and
FINEST.

XA Logs messages for all XA transactions in the


SQLServerXADataSource class. The applications can set the
logging level as FINE and FINER.

KerbAuthentication Logs messages about type 4 Kerberos authentication (when


the authenticationScheme connection property is set to
JavaKerberos ). The application can set the logging level as
FINE or FINER.

TDS.DATA Logs messages containing the TDS protocol-level


conversation between the driver and SQL Server. The
detailed contents of each TDS packet sent and received are
logged in ASCII and hexadecimal. The login credentials (user
names and passwords) aren't logged. All other data is
logged.

This category creates very verbose and detailed messages,


and can only be enabled by setting the logging level to
FINEST.

TDS.Channel This category traces actions of the TCP communications


channel with SQL Server. The logged messages include
socket opening and closing as well as reads and writes. It
also traces messages related to establishing a Transport
Layer Security (TLS), previously known as Secure Sockets
Layer (SSL), connection with SQL Server.

This category can only be enabled by setting the logging


level to FINE, FINER, or FINEST.

TDS.Writer This category traces writes to the TDS channel. Only the
length of the writes is traced, not the contents. This category
also traces issues when an attention signal is sent to the
server to cancel a statement's execution.

This category can only be enabled by setting the logging


level to FINEST.
NAME DESC RIP T IO N

TDS.Reader This category traces certain read operations from the TDS
channel at the FINEST level. At the FINEST level, tracing can
be verbose. At WARNING and SEVERE levels, this category
traces when the driver receives an invalid TDS protocol from
SQL Server before the driver closes the connection.

This category can only be enabled by setting the logging


level to FINER and FINEST.

TDS.Command This category traces low-level state transitions and other


information associated with executing TDS commands, such
as Transact-SQL statement executions, ResultSet cursor
fetches, commits, and so on.

This category can only be enabled by setting the logging


level to FINEST.

TDS.TOKEN This category logs only the tokens within the TDS packets,
and is less verbose than the TDS.DATA category. It can only
be enabled by setting the logging level to FINEST.

At the FINEST level, this category traces TDS tokens as


they're processed in the response. At the SEVERE level, this
category traces when an invalid TDS token is encountered.

SQLServerDatabaseMetaData Logs messages in the SQLServerDatabaseMetaData class.


The applications can set the logging level as FINE.

SQLServerResultSetMetaData Logs messages in the SQLServerResultSetMetaData class.


The applications can set the logging level as FINE.

SQLServerParameterMetaData Logs messages in the SQLServerParameterMetaData class.


The applications can set the logging level as FINE.

SQLServerBlob Logs messages in the SQLServerBlob class. The applications


can set the logging level as FINE.

SQLServerClob Logs messages in the SQLServerClob class. The applications


can set the logging level as FINE.

SQLServerSQLXML Logs messages in the internal SQLServerSQLXML class. The


applications can set the logging level as FINE.

SQLServerDriver Logs messages in the SQLServerDriver class. The


applications can set the logging level as FINE.

SQLServerNClob Logs messages in the SQLServerNClob class. The


applications can set the logging level as FINE.

Enabling tracing programmatically


Tracing can be enabled programmatically by creating a Logger object and indicating the category to be logged.
For example, the following code shows how to enable logging for SQL statements:
Logger logger = Logger.getLogger("com.microsoft.sqlserver.jdbc.Statement");
logger.setLevel(Level.FINER);

To turn off logging in your code, use the following code:

logger.setLevel(Level.OFF);

To log all available categories, use the following code:

Logger logger = Logger.getLogger("com.microsoft.sqlserver.jdbc");


logger.setLevel(Level.FINE);

To disable a specific category from being logged, use the following code:

Logger logger = Logger.getLogger("com.microsoft.sqlserver.jdbc.Statement");


logger.setLevel(Level.OFF);

Enabling tracing by using the logging.properties file


You can also enable tracing by using the logging.properties file, which can be found in the lib directory of
your Java Runtime Environment (JRE) installation. This file can be used to set the default values for the loggers
and handlers that will be used when tracing is enabled.
The following configuration is an example of the settings that you can make in the logging.properties files:

# Specify the handler, the handlers will be installed during VM startup.


handlers= java.util.logging.FileHandler

# Default global logging level.


.level= OFF

# default file output is in user's home directory.


java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 5000000
java.util.logging.FileHandler.count = 20
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level = FINEST

# Facility specific properties.


com.microsoft.sqlserver.jdbc.level=FINEST

NOTE
You can set the properties in the logging.properties file by using the LogManager object that is part of
java.util.logging.

See also
Diagnosing problems with the JDBC driver
Troubleshooting connectivity
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server requires that TCP/IP be installed and running to communicate with
your SQL Server database. You can use the SQL Server Configuration Manager to verify which network library
protocols are installed.
A database connection attempt might fail for many reasons. These can include the following:
TCP/IP is not enabled for SQL Server, or the server or port number specified is incorrect. Verify that SQL
Server is listening with TCP/IP on the specified server and port. This might be reported with an exception
similar to: "The login has failed. The TCP/IP connection to the host has failed." This indicates one of the
following:
SQL Server is installed but TCP/IP has not been installed as a network protocol for SQL Server by
using the SQL Server Network Utility for SQL Server 2000 (8.x), or the SQL Server Configuration
Manager for SQL Server 2005 (9.x) and later.
TCP/IP is installed as a SQL Server protocol, but it is not listening on the port specified in the JDBC
connection URL. The default port is 1433, but SQL Server can be configured at product installation
to listen on any port. Make sure that SQL Server is listening on port 1433. Or, if the port has been
changed, make sure that the port specified in the JDBC connection URL matches the changed port.
For more information about JDBC connection URLs, see Building the connection URL.
The address of the computer that is specified in the JDBC connection URL does not refer to a
server where SQL Server is installed and started.
The networking operation of TCP/IP between the client and server running SQL Server is not
operable. You can check TCP/IP connectivity to SQL Server by using telnet. For example, at the
command prompt, type telnet 192.168.0.0 1433 where 192.168.0.0 is the address of the
computer that is running SQL Server and 1433 is the port it is listening on. If you receive a
message that states "Telnet cannot connect," TCP/IP is not listening on that port for SQL Server
connections. Use the SQL Server Network Utility for SQL Server 2000 (8.x), or the SQL Server
Configuration Manager for SQL Server 2005 (9.x) and later to make sure that SQL Server is
configured to use TCP/IP on port 1433.
The port that is used by the server has not been opened in the firewall. This includes the port that
is used by the server or optionally, the port associated with a named instance of the server.
The specified database name is incorrect. Make sure that you are logging on to an existing SQL Server
database.
The user name or password is incorrect. Make sure that you have the correct values.
When you use SQL Server Authentication, the JDBC driver requires that SQL Server is installed with SQL
Server Authentication, which is not the default. Make sure that this option is included when you install or
configure your instance of SQL Server.

See also
Diagnosing problems with the JDBC driver
Connecting to SQL Server with the JDBC driver
Accessing diagnostic information in the extended
events log
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


In the Microsoft JDBC Driver 4.0 for SQL Server, tracing (Tracing driver operation) makes it easier to correlate
client events with diagnostic information. Things like connection failures from the server's connectivity ring
buffer and application performance information in the extended events log can be traced. For information about
reading the extended events log, see Extended Events.

Details
For connection operations, the Microsoft JDBC Driver for SQL Server will send a client connection ID. If the
connection fails, you can access the connectivity ring buffer and find the ClientConnectionID field to get
diagnostic information about the failure. For more information about the ring buffer, see Connectivity
troubleshooting in SQL Server 2008 with the Connectivity Ring Buffer. Client connection IDs are logged in the
ring buffer only if an error occurs. If a connection fails before sending the prelogin packet, a client connection ID
won't be generated.
The client connection ID is a 16-byte GUID. If the client_connection_id action is added to events in an
extended events session, the client connection ID will be in the extended events target output. For more client
driver diagnostics, you can enable tracing and rerun the connection command to see the ClientConnectionID
field in the trace.
You can get the client connection ID programmatically by using ISQLServerConnection Interface. The connection
ID will also be present in any connection-related exceptions.
When there's a connection error, the client connection ID in the server's Built In Diagnostics (BID) trace
information and in the connectivity ring buffer can help correlate the client connections to connections on the
server. For more information about BID traces on the server, see Data Access Tracing. Note, the data access
tracing article also contains information about data access trace, which doesn't apply to the Microsoft JDBC
Driver for SQL Server; see Tracing driver operation for information on doing a data access trace using the
Microsoft JDBC Driver for SQL Server.
The JDBC Driver also sends a thread-specific activity ID. If the session is started with the TRACK_CAUSAILITY
option enabled, the activity ID is captured in the extended events session. For performance issues with an active
connection, you can get the activity ID from the client's trace (ActivityID field) and then locate the activity ID in
the extended events output.
The activity ID in extended events is a 16-byte GUID (not the same as the GUID for the client connection ID)
appended with a 4-byte sequence number. The sequence number represents the order of a request within a
thread. The ActivityId is sent for SQL batch statements and RPC requests. To enable sending ActivityId to the
server, specify the following key-value pair in the Logging.Properties file:

com.microsoft.sqlserver.jdbc.traceactivity = on

Any value other than on (case sensitive) will disable sending the ActivityId.
For more information, see Tracing driver operation. This trace flag is used with corresponding JDBC object
loggers to decide whether to trace and send the ActivityId in the JDBC driver. In addition to updating the
Logging.Properties file, enable the logger com.microsoft.sqlserver.jdbc at FINER or higher. To send ActivityId to
the server for requests that are made by a particular class, enable the corresponding class logger at FINER or
FINEST. For example, if the class is, SQLServerStatement, enable the logger
com.microsoft.sqlserver.jdbc.SQLServerStatement.
The following sample uses Transact-SQL to start an extended events session that is stored in a ring buffer and
records the activity ID sent from a client on RPC and batch operations:

create event session MySession on server


add event connectivity_ring_buffer_recorded,
add event sql_statement_starting (action (client_connection_id)),
add event sql_statement_completed (action (client_connection_id)),
add event rpc_starting (action (client_connection_id)),
add event rpc_completed (action (client_connection_id))
add target ring_buffer with (track_causality=on)

See also
Diagnosing problems with the JDBC driver
Sample JDBC driver applications
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server sample applications demonstrate various features of the JDBC driver.
Additionally, they demonstrate good programming practices that you can follow when using the JDBC driver
with a SQL Server database.
All the sample applications are contained in *.java code files that can be compiled and run on your local
computer, and they are located in various subfolders in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples

The articles in this section describe how to configure and run the sample applications, and include a discussion
of what the sample applications demonstrate.

In this section
A RT IC L E DESC RIP T IO N

Connecting and Retrieving Data These sample applications demonstrate how to connect to a
SQL Server database. They also demonstrate different ways
in which to retrieve data from a SQL Server database.

Working with Data Types (JDBC) These sample applications demonstrate how to use the JDBC
driver data type methods to work with data in a SQL Server
database.

Working with Result Sets These sample applications demonstrate how to use result
sets to process data contained in a SQL Server database.

Working with Large Data These sample applications demonstrate how to use adaptive
buffering to retrieve large-value data from a SQL Server
database without the overhead of server cursors.

SQL Data Discovery and Classification This sample application demonstrates how to retrieve Data
Discovery and Classification information contained in a SQL
Server database from a ResultSet object using JDBC Driver.

See also
Overview of the JDBC driver
Connecting and retrieving data
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you are working with the Microsoft JDBC Driver for SQL Server, there are two primary methods for
establishing a connection to a SQL Server database. One is to set connection properties in the connection URL,
and then call the getConnection method of the DriverManager class to return a SQLServerConnection object.

NOTE
For a list of the connection properties supported by the JDBC driver, see Setting the connection properties.

The second method involves setting the connection properties by using setter methods of the
SQLServerDataSource class, and then calling the getConnection method to return a SQLServerConnection
object.
The topics in this section describe the different ways in which you can connect to a SQL Server database, and
they also demonstrate different techniques for retrieving data.

In this section
TO P IC DESC RIP T IO N

Connection URL Sample Describes how to use a connection URL to connect to SQL
Server and then use an SQL statement to retrieve data.

Data Source Sample Describes how to use a data source to connect to SQL
Server and then use a stored procedure to retrieve data.

See also
Sample JDBC driver applications
Connection URL sample
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to connect to a SQL Server
database by using a connection URL. It also demonstrates how to retrieve data from a SQL Server database by
using an SQL statement.
The code file for this sample is named ConnectURL.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\connections

Requirements
To run this sample application, you must set the classpath to include the mssql-jdbc jar file. You'll also need
access to the sample database. For more information about how to set the classpath, see Using the JDBC Driver.

NOTE
The Microsoft JDBC Driver for SQL Server provides mssql-jdbc class library files to be used depending on your preferred
Java Runtime Environment (JRE) settings. For more information about which JAR file to choose, see System Requirements
for the JDBC Driver.

Example
In the following example, the sample code sets various connection properties in the connection URL, and then
calls the getConnection method of the DriverManager class to return a SQLServerConnection object.
Next, the sample code uses the createStatement method of the SQLServerConnection object to create a
SQLServerStatement object, and then the executeQuery method is called to execute the SQL statement.
Finally, the sample uses the SQLServerResultSet object returned from the executeQuery method to iterate
through the results returned by the SQL statement.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class ConnectURL {


public static void main(String[] args) {

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";

try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt =


con.createStatement();) {
String SQL = "SELECT TOP 10 * FROM Person.Contact";
ResultSet rs = stmt.executeQuery(SQL);

// Iterate through the data in the result set and display it.
while (rs.next()) {
System.out.println(rs.getString("FirstName") + " " + rs.getString("LastName"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}
}

See also
Connecting and retrieving data
Data source sample
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to connect to a SQL Server
database by using a data source object. It also demonstrates how to retrieve data from a SQL Server database
by using a stored procedure.
The code file for this sample is named ConnectDataSource.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\connections

Requirements
To run this sample application, you must set the classpath to include the mssql-jdbc jar file. You'll also need
access to the sample database. For more information about how to set the classpath, see Using the JDBC Driver.

NOTE
The Microsoft JDBC Driver for SQL Server provides mssql-jdbc class library files to be used depending on your preferred
Java Runtime Environment (JRE) settings. For more information about which JAR file to choose, see System Requirements
for the JDBC Driver.

Example
In the following example, the sample code sets various connection properties by using setter methods of the
SQLServerDataSource object, and then calls the getConnection method of the SQLServerDataSource object to
return a SQLServerConnection object.
Next, the sample code uses the prepareCall method of the SQLServerConnection object to create a
SQLServerCallableStatement object, and then the executeQuery method is called to execute the stored
procedure.
Finally, the sample uses the SQLServerResultSet object returned from the executeQuery method to iterate
through the results returned by the stored procedure.
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.microsoft.sqlserver.jdbc.SQLServerDataSource;

public class ConnectDataSource {

public static void main(String[] args) {

// Create datasource.
SQLServerDataSource ds = new SQLServerDataSource();
ds.setUser("<user>");
ds.setPassword("<password>");
ds.setServerName("<server>");
ds.setPortNumber(<port>);
ds.setDatabaseName("AdventureWorks");

try (Connection con = ds.getConnection();


CallableStatement cstmt = con.prepareCall("{call dbo.uspGetEmployeeManagers(?)}");) {
// Execute a stored procedure that returns some data.
cstmt.setInt(1, 50);
ResultSet rs = cstmt.executeQuery();

// Iterate through the data in the result set and display it.
while (rs.next()) {
System.out.println("EMPLOYEE: " + rs.getString("LastName") + ", " +
rs.getString("FirstName"));
System.out.println("MANAGER: " + rs.getString("ManagerLastName") + ", " +
rs.getString("ManagerFirstName"));
System.out.println();
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}
}

See also
Connecting and retrieving data
Working with data types (JDBC)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The primary function of the Microsoft JDBC Driver for SQL Server is to allow Java developers to access data
contained in SQL Server databases. To accomplish this, the JDBC driver mediates the conversion between SQL
Server data types and Java language types and objects.

NOTE
For a detailed discussion of the SQL Server and JDBC driver data types, including their differences and how they are
converted to Java language data types, see Understanding the JDBC driver data types.

In order to work with SQL Server data types, the JDBC driver provides get<Type> and set<Type> methods for
the SQLServerPreparedStatement and SQLServerCallableStatement classes, and it provides get<Type> and
update<Type> methods for the SQLServerResultSet class. Which method you use depends on the type of data
that you are working with, and whether you are using result sets or queries.
The topics in this section describe how to use the JDBC driver data types to access SQL Server data in your Java
applications.

In this section
TO P IC DESC RIP T IO N

Basic data types sample Describes how to use result set getter methods to retrieve
basic SQL Server data type values, and how to use result set
update methods to update those values.

SQLXML data type sample Describes how to store an XML data in a relational database,
how to retrieve an XML data from a database, and how to
parse an XML data with the SQLXML Java data type.

Spatial data types sample Describes how to store and retrieve data with Spatial
Datatypes 'Geometry' and 'Geography' of SQL Server
database with Geometr y and Geography Java types
defined by Microsoft JDBC Driver.

See also
Sample JDBC driver applications
Basic data types sample
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to use result set getter
methods to retrieve basic SQL Server data type values, and how to use result set update methods to update
those values.
The code file for this sample is named BasicDataTypes.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\datatypes

Requirements
To run this sample application, you must set the classpath to include the mssql-jdbc jar file. You'll also need
access to the sample database. For more information about how to set the classpath, see Using the JDBC Driver.
The sample will create the required table and insert sample data in the sample database:

NOTE
The Microsoft JDBC Driver for SQL Server provides mssql-jdbc class library files to be used depending on your preferred
Java Runtime Environment (JRE) settings. For more information about which JAR file to choose, see System Requirements
for the JDBC Driver.

Example
In the following example, the sample code makes a connection to the database, and then retrieves a single row
of data from the DataTypesTable test table. The custom displayRow method is then called to display all the data
in the result set using various get<Type> methods of the SQLServerResultSet class.
Next, the sample uses various update<Type> methods of the SQLServerResultSet class to update the data in the
result set, and then calls the updateRow method to persist that data back to the database.
Finally, the sample refreshes the data in the result set and then calls the custom displayRow method again to
display the data in the result set.

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;

import com.microsoft.sqlserver.jdbc.SQLServerResultSet;

import microsoft.sql.DateTimeOffset;

public class DatatypesTest {


public class DatatypesTest {
private static final String tableName = "DataTypesTable";

public static void main(String[] args) {

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<database>;user=
<user>;password=<password>";

try (Connection con = DriverManager.getConnection(connectionUrl);


Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);) {

dropAndCreateTable(stmt);
insertOriginalData(con);

String SQL = "SELECT * FROM " + tableName;


ResultSet rs = stmt.executeQuery(SQL);
rs.next();
displayRow("ORIGINAL DATA", rs);

// Update the data in the result set.


rs.updateString(2, "B");
rs.updateString(3, "Some updated text.");
rs.updateBoolean(4, true);
rs.updateDouble(5, 77.89);
rs.updateDouble(6, 1000.01);
long timeInMillis = System.currentTimeMillis();
Timestamp ts = new Timestamp(timeInMillis);
rs.updateTimestamp(7, ts);
rs.updateDate(8, new Date(timeInMillis));
rs.updateTime(9, new Time(timeInMillis));
rs.updateTimestamp(10, ts);
rs.updateTimestamp(11, ts);
rs.updateObject(12, 987654321L, microsoft.sql.Types.SQL_VARIANT);

// -480 indicates GMT - 8:00 hrs


((SQLServerResultSet) rs).updateDateTimeOffset(11, DateTimeOffset.valueOf(ts, -480));

rs.updateRow();

// Get the updated data from the database and display it.
rs = stmt.executeQuery(SQL);
rs.next();
displayRow("UPDATED DATA", rs);
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

private static void displayRow(String title, ResultSet rs) throws SQLException {


System.out.println(title);
System.out.println(rs.getInt(1) + " , " + // SQL integer type
rs.getString(2) + " , " + // SQL char type
rs.getString(3) + " , " + // SQL varchar type
rs.getBoolean(4) + " , " + // SQL bit type
rs.getDouble(5) + " , " + // SQL decimal type
rs.getDouble(6) + " , " + // SQL money type
rs.getTimestamp(7) + " , " + // SQL datetime type
rs.getDate(8) + " , " + // SQL date type
rs.getTime(9) + " , " + // SQL time type
rs.getTimestamp(10) + " , " + // SQL datetime2 type
((SQLServerResultSet) rs).getDateTimeOffset(11) + " , " + // SQL datetimeoffset type
rs.getObject(12)); // SQL sqlvariant type
System.out.println();
}
private static void dropAndCreateTable(Statement stmt) throws SQLException {
stmt.executeUpdate("if object_id('" + tableName + "','U') is not null" + " drop table " +
tableName);

String sql = "create table " + tableName + " (" + "c1 int, " + "c2 char(20), " + "c3 varchar(20), "
+ "c4 bit, "
+ "c5 decimal(10,5), " + "c6 money, " + "c7 datetime, " + "c8 date, " + "c9 time(7), "
+ "c10 datetime2(7), " + "c11 datetimeoffset(7), " + "c12 sql_variant" + ");";

stmt.execute(sql);
}

private static void insertOriginalData(Connection con) throws SQLException {


String sql = "insert into " + tableName + " values( " + "?,?,?,?,?,?,?,?,?,?,?,?" + ")";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.setObject(1, 100);
pstmt.setObject(2, "original text");
pstmt.setObject(3, "original text");
pstmt.setObject(4, false);
pstmt.setObject(5, 12.34);
pstmt.setObject(6, 56.78);
pstmt.setObject(7, new java.util.Date(1453500034839L));
pstmt.setObject(8, new java.util.Date(1453500034839L));
pstmt.setObject(9, new java.util.Date(1453500034839L));
pstmt.setObject(10, new java.util.Date(1453500034839L));
pstmt.setObject(11, new java.util.Date(1453500034839L));
pstmt.setObject(12, 123456789L, microsoft.sql.Types.SQL_VARIANT);
pstmt.execute();
}
}
}

See also
Working with data types (JDBC)
SQLXML data type sample
4/27/2022 • 7 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to store XML data in a
relational database, how to retrieve XML data from a database, and how to parse XML data with the SQLXML
Java data type.
The code examples in this section use a Simple API for XML (SAX) parser. The SAX is a publicly developed
standard for the events-based parsing of XML documents. It also provides an application programming interface
for working with XML data. Applications can use any other XML parser as well, such as the Document Object
Model (DOM) or the Streaming API for XML (StAX), or so on.
The Document Object Model (DOM) provides a programmatic representation of XML documents, fragments,
nodes, or node-sets. It also provides an application programming interface for working with XML data. Similarly,
the Streaming API for XML (StAX) is a Java-based API for pull-parsing XML.

IMPORTANT
In order to use the SAX parser API, you must import the standard SAX implementation from the javax.xml package.

The code file for this sample is named SqlXmlDataType.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\datatypes

Requirements
To run this sample application, you must set the classpath to include the sqljdbc4.jar file. If the classpath is
missing an entry for sqljdbc4.jar, the sample application throws the "Class not found" exception. For more
information about how to set the classpath, see Using the JDBC Driver.
You also need access to the sample database to run this sample application.

Example
In the following example, the sample code makes a connection to the database and then calls the
createSampleTables method.
The createSampleTables method drops the test tables, TestTable1, and TestTable2, if they exist. Then, it inserts two
rows into TestTable1.
Also, the code sample includes the following three methods and one other class, which is named
ExampleContentHandler.
The ExampleContentHandler class implements a custom content handler, which defines methods for parser
events.
The showGetters method demonstrates how to parse the data in the SQLXML object by using the SAX,
ContentHandler, and XMLReader. First, the code sample creates an instance of a custom content handler, which is
ExampleContentHandler. Next, it creates and executes an SQL statement that returns a set of data from
TestTable1. Then, the code example gets a SAX parser and parses the XML data.
The showSetters method demonstrates how to set the xml column by using the SAX, ContentHandler, and
ResultSet. First, it creates an empty SQLXML object by using the createSQLXML method of the Connection class.
Then, it gets an instance of a content handler to write the data into the SQLXML object. Next, the code example
writes the data to TestTable1. Finally, the sample code iterates through the rows of data that are in the result set,
and uses the getSQLXML method to read the XML data.
The showTransformer method demonstrates how to get XML data from one table and insert that XML data into
another table by using the SAX and the Transformer. First, it retrieves the source SQLXML object from the
TestTable1. Then, it creates an empty destination SQLXML object by using the createSQLXML method of the
Connection class. Next, it updates the destination SQLXML object and writes the XML data to TestTable2. Finally,
the sample code iterates through the rows of data that are in the result set, and uses the getSQLXML method to
read the XML data in TestTable2.

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Statement;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

public class SqlXmlDataType {

public static void main(String[] args) {

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<database>;username=
<user>;password=<password>;";

// Establish the connection.


try (Connection con = DriverManager.getConnection(connectionUrl);
Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE)) {

// Create initial sample data.


createSampleTables(stmt);

// The showGetters method demonstrates how to parse the data in the


// SQLXML object by using the SAX, ContentHandler and XMLReader.
showGetters(stmt);

// The showSetters method demonstrates how to set the xml column


// by using the SAX, ContentHandler, and ResultSet.
showSetters(con, stmt);

// The showTransformer method demonstrates how to get an XML data


// from one table and insert that XML data to another table
// by using the SAX and the Transformer.
showTransformer(con, stmt);
}
// Handle any errors that may have occurred.
catch (Exception e) {
e.printStackTrace();
}
}

private static void showGetters(Statement stmt) throws IOException, SAXException, SQLException {

// Create an instance of the custom content handler.


ExampleContentHandler myHandler = new ExampleContentHandler();

// Create and execute an SQL statement that returns a


// set of data.
String SQL = "SELECT * FROM TestTable1";

try (ResultSet rs = stmt.executeQuery(SQL)) {

rs.next();

SQLXML xmlSource = rs.getSQLXML("Col3");

// Send SAX events to the custom content handler.


SAXSource sxSource = xmlSource.getSource(SAXSource.class);
XMLReader xmlReader = sxSource.getXMLReader();
xmlReader.setContentHandler(myHandler);

System.out.println("showGetters method: Parse an XML data in TestTable1 => ");


xmlReader.parse(sxSource.getInputSource());
}
}

private static void showSetters(Connection con, Statement stmt) {

// Create and execute an SQL statement, retrieving an updatable result set.


String SQL = "SELECT * FROM TestTable1;";
try (ResultSet rs = stmt.executeQuery(SQL)) {

// Create an empty SQLXML object.


SQLXML sqlxml = con.createSQLXML();

// Set the result value from SAX events.


SAXResult sxResult = sqlxml.setResult(SAXResult.class);
ContentHandler myHandler = sxResult.getHandler();

// Set the XML elements and attributes into the result.


myHandler.startDocument();
myHandler.startElement(null, "contact", "contact", null);
myHandler.startElement(null, "name", "name", null);
myHandler.endElement(null, "name", "name");
myHandler.startElement(null, "phone", "phone", null);
myHandler.endElement(null, "phone", "phone");
myHandler.endElement(null, "contact", "contact");
myHandler.endDocument();

// Update the data in the result set.


rs.moveToInsertRow();
rs.updateString("Col2", "C");
rs.updateSQLXML("Col3", sqlxml);
rs.insertRow();

// Display the data.


System.out.println("showSetters method: Display data in TestTable1 => ");
while (rs.next()) {
System.out.println(rs.getString("Col1") + " : " + rs.getString("Col2"));
SQLXML xml = rs.getSQLXML("Col3");
System.out.println("XML column : " + xml.getString());
}
} catch (Exception e) {
} catch (Exception e) {
e.printStackTrace();
}
}

private static void showTransformer(Connection con, Statement stmt) throws Exception {

// Create and execute an SQL statement that returns a


// set of data.
String SQL = "SELECT * FROM TestTable1";
try (ResultSet rs = stmt.executeQuery(SQL)) {

rs.next();

// Get the value of the source SQLXML object from the database.
SQLXML xmlSource = rs.getSQLXML("Col3");

// Get a Source to read the XML data.


SAXSource sxSource = xmlSource.getSource(SAXSource.class);

// Create a destination SQLXML object without any data.


SQLXML xmlDest = con.createSQLXML();

// Get a Result to write the XML data.


SAXResult sxResult = xmlDest.setResult(SAXResult.class);

// Transform the Source to a Result by using the identity transform.


SAXTransformerFactory stf = (SAXTransformerFactory) TransformerFactory.newInstance();
Transformer identity = stf.newTransformer();
identity.transform(sxSource, sxResult);
// Insert the destination SQLXML object into the database.
try (PreparedStatement psmt = con
.prepareStatement("INSERT INTO TestTable2" + " (Col2, Col3, Col4, Col5) VALUES (?, ?, ?,
?)")) {
psmt.setString(1, "A");
psmt.setString(2, "Test data");
psmt.setInt(3, 123);
psmt.setSQLXML(4, xmlDest);
psmt.execute();
}
}
// Execute the query and display the data.
SQL = "SELECT * FROM TestTable2";
try (ResultSet rs = stmt.executeQuery(SQL)) {

System.out.println("showTransformer method : Display data in TestTable2 => ");


while (rs.next()) {
System.out.println(rs.getString("Col1") + " : " + rs.getString("Col2"));
System.out.println(rs.getString("Col3") + " : " + rs.getInt("Col4"));

SQLXML xml = rs.getSQLXML("Col5");


System.out.println("XML column : " + xml.getString());
}
}
}

private static void createSampleTables(Statement stmt) throws SQLException {


// Drop the tables.
stmt.executeUpdate("if exists (select * from sys.objects where name = 'TestTable1')" + "drop table
TestTable1");

stmt.executeUpdate("if exists (select * from sys.objects where name = 'TestTable2')" + "drop table
TestTable2");

// Create empty tables.


stmt.execute("CREATE TABLE TestTable1 (Col1 int IDENTITY, Col2 char, Col3 xml)");
stmt.execute("CREATE TABLE TestTable2 (Col1 int IDENTITY, Col2 char, Col3 varchar(50), Col4 int,
Col5 xml)");

// Insert two rows to the TestTable1.


// Insert two rows to the TestTable1.
String row1 = "<contact><name>Contact Name 1</name><phone>XXX-XXX-XXXX</phone></contact>";
String row2 = "<contact><name>Contact Name 2</name><phone>YYY-YYY-YYYY</phone></contact>";

stmt.executeUpdate("insert into TestTable1" + " (Col2, Col3) values('A', '" + row1 + "')");
stmt.executeUpdate("insert into TestTable1" + " (Col2, Col3) values('B', '" + row2 + "')");
}
}

/**
* Handles output for XML elements for the test.
*/
class ExampleContentHandler implements ContentHandler {

public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws
SAXException {
System.out.println("startElement method: localName => " + localName);
}

public void characters(char[] text, int start, int length) throws SAXException {
System.out.println("characters method");
}

public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
System.out.println("endElement method: localName => " + localName);
}

public void setDocumentLocator(Locator locator) {


System.out.println("setDocumentLocator method");
}

public void startDocument() throws SAXException {


System.out.println("startDocument method");
}

public void endDocument() throws SAXException {


System.out.println("endDocument method");
}

public void startPrefixMapping(String prefix, String uri) throws SAXException {


System.out.println("startPrefixMapping method: prefix => " + prefix);
}

public void endPrefixMapping(String prefix) throws SAXException {


System.out.println("endPrefixMapping method: prefix => " + prefix);
}

public void skippedEntity(String name) throws SAXException {


System.out.println("skippedEntity method: name => " + name);
}

public void ignorableWhitespace(char[] text, int start, int length) throws SAXException {
System.out.println("ignorableWhiteSpace method");
}

public void processingInstruction(String target, String data) throws SAXException {


System.out.println("processingInstruction method: target => " + target);
}
}

See also
Working with data types (JDBC)
Spatial data types sample
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to create, insert, and retrieve
Spatial Data types (Geometry and Geography).
The code file for this sample is named SpatialDataTypes.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\datatypes

Requirements
To run this sample application, you must set the classpath to include the mssql-jdbc jar file. For more
information about how to set the classpath, see Using the JDBC Driver.

NOTE
The Microsoft JDBC Driver for SQL Server provides mssql-jdbc class library files to be used depending on your preferred
Java Runtime Environment (JRE) settings. For more information about which JAR file to choose, see System Requirements
for the JDBC Driver.

Example
In the following example, the sample code creates a table called SpatialDataTypesTable_JDBC_Sample that
contains 'Geometry' and 'Geography' columns.
The sample first creates 'Geometry' and 'Geography' objects from a Well-Known-Text (WKT) representing a
POINT. It uses a SQLServerPreparedStatement with a parameterized query to map the data to each column.
Finally, the sample inserts the data into the table, and retrieves it. The data is displayed in the form of WKT.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import com.microsoft.sqlserver.jdbc.Geography;
import com.microsoft.sqlserver.jdbc.Geometry;
import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement;
import com.microsoft.sqlserver.jdbc.SQLServerResultSet;

public class SpatialDataTypes {

private static String tableName = "SpatialDataTypesTable_JDBC_Sample";

public static void main(String[] args) {

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<database>;user=
<user>;password=<password>";
// Establish the connection.
try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt =
con.createStatement();) {
dropAndCreateTable(stmt);

// TODO: Implement Sample code


String geoWKT = "POINT(3 40 5 6)";
Geometry geomWKT = Geometry.STGeomFromText(geoWKT, 0);
Geography geogWKT = Geography.STGeomFromText(geoWKT, 4326);

try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con


.prepareStatement("insert into " + tableName + " values (?, ?)");) {
pstmt.setGeometry(1, geomWKT);
pstmt.setGeography(2, geogWKT);
pstmt.execute();

SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " +


tableName);
rs.next();

System.out.println("Geometry data: " + rs.getGeometry(1));


System.out.println("Geography data: " + rs.getGeography(2));
}
} catch (Exception e) {
e.printStackTrace();
}
}

private static void dropAndCreateTable(Statement stmt) throws SQLException {


stmt.executeUpdate("if object_id('" + tableName + "','U') is not null" + " drop table " +
tableName);

stmt.executeUpdate("Create table " + tableName + " (c1 geometry, c2 geography)");


}
}

See also
Working with JDBC data types
Working with result sets
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you work with the data contained in a SQL Server database, one method of manipulating the data is to
use a result set. The Microsoft JDBC Driver for SQL Server supports the use of result sets through the
SQLServerResultSet object. By using the SQLServerResultSet object, you can retrieve the data returned from an
SQL statement or stored procedure, update the data as needed, and then persist that data back to the database.
In addition, the SQLServerResultSet object provides methods for navigating through its rows of data, getting or
setting the data that it contains, and for establishing various levels of sensitivity to changes in the underlying
database.

NOTE
For more information about managing result sets, including their sensitivity to changes, see Managing result sets with the
JDBC driver.

The topics in this section describe different ways that you can use a result set to manipulate the data contained
in a SQL Server database.

In this section
TO P IC DESC RIP T IO N

Retrieving result set data sample Describes how to use a result set to retrieve data from a SQL
Server database and display it.

Modifying result set data sample Describes how to use a result set to insert, retrieve, and
modify data in a SQL Server database.

Caching result set data sample Describes how to use a result set to retrieve large amounts
of data from a SQL Server database, and to control how that
data is cached on the client.

See also
Sample JDBC driver applications
Retrieving result set data sample
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to retrieve a set of data from a
SQL Server database, and then display that data.
The code file for this sample is named RetrieveResultSet.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\resultsets

Requirements
To run this sample application, you must set the classpath to include the mssql-jdbc jar file. You'll also need
access to the sample database. For more information about how to set the classpath, see Using the JDBC Driver.

NOTE
The Microsoft JDBC Driver for SQL Server provides mssql-jdbc class library files to be used depending on your preferred
Java Runtime Environment (JRE) settings. For more information about which JAR file to choose, see System Requirements
for the JDBC Driver.

Example
In the following example, the sample code makes a connection to the sample database. Then, using an SQL
statement with the SQLServerStatement object, it runs the SQL statement and places the data that it returns into
a SQLServerResultSet object.
Next, the sample code calls the custom displayRow method to iterate through the rows of data that are in the
result set, and uses the getString method to display some of the data.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class RetrieveResultSet {

public static void main(String[] args) {

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";

try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt =


con.createStatement();) {
createTable(stmt);
String SQL = "SELECT * FROM Production.Product;";
ResultSet rs = stmt.executeQuery(SQL);
displayRow("PRODUCTS", rs);
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

private static void displayRow(String title,


ResultSet rs) throws SQLException {
System.out.println(title);
while (rs.next()) {
System.out.println(rs.getString("ProductNumber") + " : " + rs.getString("Name"));
}
}

private static void createTable(Statement stmt) throws SQLException {


stmt.execute("if exists (select * from sys.objects where name = 'Product_JDBC_Sample')"
+ "drop table Product_JDBC_Sample");

String sql = "CREATE TABLE [Product_JDBC_Sample](" + "[ProductID] [int] IDENTITY(1,1) NOT NULL,"
+ "[Name] [varchar](30) NOT NULL," + "[ProductNumber] [nvarchar](25) NOT NULL,"
+ "[MakeFlag] [bit] NOT NULL," + "[FinishedGoodsFlag] [bit] NOT NULL," + "[Color] [nvarchar]
(15) NULL,"
+ "[SafetyStockLevel] [smallint] NOT NULL," + "[ReorderPoint] [smallint] NOT NULL,"
+ "[StandardCost] [money] NOT NULL," + "[ListPrice] [money] NOT NULL," + "[Size] [nvarchar]
(5) NULL,"
+ "[SizeUnitMeasureCode] [nchar](3) NULL," + "[WeightUnitMeasureCode] [nchar](3) NULL,"
+ "[Weight] [decimal](8, 2) NULL," + "[DaysToManufacture] [int] NOT NULL,"
+ "[ProductLine] [nchar](2) NULL," + "[Class] [nchar](2) NULL," + "[Style] [nchar](2) NULL,"
+ "[ProductSubcategoryID] [int] NULL," + "[ProductModelID] [int] NULL,"
+ "[SellStartDate] [datetime] NOT NULL," + "[SellEndDate] [datetime] NULL,"
+ "[DiscontinuedDate] [datetime] NULL," + "[rowguid] [uniqueidentifier] ROWGUIDCOL NOT
NULL,"
+ "[ModifiedDate] [datetime] NOT NULL,)";

stmt.execute(sql);

sql = "INSERT Product_JDBC_Sample VALUES ('Adjustable Time','AR-


5381','0','0',NULL,'1000','750','0.00','0.00',NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,'2008-04-30
00:00:00.000',NULL,NULL,'694215B7-08F7-4C0D-ACB1-D734BA44C0C8','2014-02-08 10:01:36.827') ";
stmt.execute(sql);

sql = "INSERT Product_JDBC_Sample VALUES ('ML Bottom Bracket','BB-


8107','0','0',NULL,'1000','750','0.00','0.00',NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,'2008-04-30
00:00:00.000',NULL,NULL,'694215B7-08F7-4C0D-ACB1-D734BA44C0C8','2014-02-08 10:01:36.827') ";
stmt.execute(sql);

sql = "INSERT Product_JDBC_Sample VALUES ('Mountain-500 Black, 44','BK-M18B-


44','0','0',NULL,'1000','750','0.00','0.00',NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,'2008-04-30
00:00:00.000',NULL,NULL,'694215B7-08F7-4C0D-ACB1-D734BA44C0C8','2014-02-08 10:01:36.827') ";
stmt.execute(sql);
}
}

See also
Working with result sets
Modifying result set data sample
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to retrieve an updatable set of
data from a SQL Server database. Then, using methods of the SQLServerResultSet object, it inserts, modifies,
and then finally deletes a row of data from the set of data.
The code file for this sample is named UpdateResultSet.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\resultsets

Requirements
To run this sample application, you must set the classpath to include the mssql-jdbc jar file. You'll also need
access to the sample database. For more information about how to set the classpath, see Using the JDBC Driver.

NOTE
The Microsoft JDBC Driver for SQL Server provides mssql-jdbc class library files to be used depending on your preferred
Java Runtime Environment (JRE) settings. For more information about which JAR file to choose, see System Requirements
for the JDBC Driver.

Example
The sample code makes a connection to the sample database. Then, using an SQL statement with the
SQLServerStatement object, it runs the SQL statement and places the data that it returns into an updatable
SQLServerResultSet object.
Next, the sample code uses the moveToInsertRow method to move the result set cursor to the insert row. It then
uses a series of updateString methods to insert data into the new row. After that, it calls the insertRow method
to persist the new row of data back to the database.
After inserting the new row of data, the sample code uses an SQL statement to retrieve the previously inserted
row. From there, it uses the combination of updateString and updateRow methods to update the row of data
and again persist it back to the database.
Finally, the sample code retrieves the previously updated row of data and then deletes it from the database
using the deleteRow method.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class UpdateResultSet {

public static void main(String[] args) {

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";

try (Connection con = DriverManager.getConnection(connectionUrl);


Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);) {

// Create and execute an SQL statement, retrieving an updateable result set.


String SQL = "SELECT * FROM HumanResources.Department;";
ResultSet rs = stmt.executeQuery(SQL);

// Insert a row of data.


rs.moveToInsertRow();
rs.updateString("Name", "Accounting");
rs.updateString("GroupName", "Executive General and Administration");
rs.updateString("ModifiedDate", "08/01/2006");
rs.insertRow();

// Retrieve the inserted row of data and display it.


SQL = "SELECT * FROM HumanResources.Department WHERE Name = 'Accounting';";
rs = stmt.executeQuery(SQL);
displayRow("ADDED ROW", rs);

// Update the row of data.


rs.first();
rs.updateString("GroupName", "Finance");
rs.updateRow();

// Retrieve the updated row of data and display it.


rs = stmt.executeQuery(SQL);
displayRow("UPDATED ROW", rs);

// Delete the row of data.


rs.first();
rs.deleteRow();
System.out.println("ROW DELETED");
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

private static void displayRow(String title,


ResultSet rs) throws SQLException {
System.out.println(title);
while (rs.next()) {
System.out.println(rs.getString("Name") + " : " + rs.getString("GroupName"));
System.out.println();
}
}
}

See also
Working with result sets
Caching result set data sample
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to retrieve a large set of data
from a database. It then controls the number of rows of data that are cached on the client by using the
setFetchSize method of the SQLServerResultSet object.

NOTE
Limiting the number of rows cached on the client is different from limiting the total number of rows that a result set can
contain. To control the total number of rows that are contained in a result set, use the setMaxRows method of the
SQLServerStatement object, which is inherited by both the SQLServerPreparedStatement and SQLServerCallableStatement
objects.

To set a limit on the number of rows cached on the client, specify a cursor type that uses a server-side cursor
when creating Statement objects. For example, the JDBC driver provides the
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY cursor type, which is a fast forward-only, read-only server-side
cursor for use with SQL Server databases.

NOTE
An alternative to using the SQL Server specific cursor type is to use the selectMethod connection string property, setting
its value to "cursor". For more information about the cursor types supported by the JDBC driver, see Understanding
cursor types.

After you have run the query in the Statement object and the data is returned to the client as a result set, call
setFetchSize to control how much data is retrieved from the database at one time. For example, if you have a
table with 100 rows of data, and the fetch size is 10, only 10 rows of data are cached on the client at a time.
Although this setting can slow down the speed at which the data is processed, it uses less memory on the client.
This scenario is useful when you need to process large amounts of data without using too much memory.
The code file for this sample is named CacheResultSet.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\resultsets

Requirements
To run this sample application, set the classpath to include the mssql-jdbc jar file. You also need access to the
sample database. For more information about how to set the classpath, see Using the JDBC Driver.

NOTE
The Microsoft JDBC Driver for SQL Server provides mssql-jdbc class library files to be used depending on your preferred
Java Runtime Environment (JRE) settings. For more information about which JAR file to choose, see System Requirements
for the JDBC Driver.
Example
In the following example, the sample code makes a connection to the sample database. Then it uses an SQL
statement with the SQLServerStatement object, specifies the server-side cursor type, and runs the SQL
statement. The data is returned in a SQLServerResultSet object.
Next, the sample code calls the custom timerTest method, passing as arguments the fetch size to use and the
result set. The timerTest method then sets the fetch size of the result set by using the setFetchSize method, sets
the start time of the test, and then iterates through the result set with a While loop. As soon as the While loop
is exited, the code sets the stop time of the test, and then displays the result of the test including the fetch size,
the number of rows processed, and the time it took to execute the test.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import com.microsoft.sqlserver.jdbc.SQLServerResultSet;

public class CacheResultSet {

@SuppressWarnings("serial")
public static void main(String[] args) {

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";

try (Connection con = DriverManager.getConnection(connectionUrl);


Statement stmt = con.createStatement(SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY,
SQLServerResultSet.CONCUR_READ_ONLY);) {

String SQL = "SELECT * FROM Sales.SalesOrderDetail;";

for (int n : new ArrayList<Integer>() {


{
add(1);
add(10);
add(100);
add(1000);
add(0);
}
}) {
// Perform a fetch for every nth row in the result set.
try (ResultSet rs = stmt.executeQuery(SQL)) {
timerTest(n, rs);
}
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

private static void timerTest(int fetchSize,


ResultSet rs) throws SQLException {

// Declare the variables for tracking the row count and elapsed time.
int rowCount = 0;
long startTime = 0;
long stopTime = 0;
long runTime = 0;
// Set the fetch size then iterate through the result set to
// cache the data locally.
rs.setFetchSize(fetchSize);
startTime = System.currentTimeMillis();
while (rs.next()) {
rowCount++;
}
stopTime = System.currentTimeMillis();
runTime = stopTime - startTime;

// Display the results of the timer test.


System.out.println("FETCH SIZE: " + rs.getFetchSize());
System.out.println("ROWS PROCESSED: " + rowCount);
System.out.println("TIME TO EXECUTE: " + runTime);
System.out.println();
}
}

See also
Working with result sets
Working with large data
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The JDBC driver provides support for adaptive buffering, which allows you to retrieve any kind of large-value
data without the overhead of server cursors. With adaptive buffering, the Microsoft JDBC Driver for SQL Server
retrieves statement execution results from the SQL Server as the application needs them, rather than all at once.
The driver also discards the results as soon as the application can no longer access them.
In the MicrosoftSQL Server 2005 (9.x) JDBC Driver version 1.2, the buffering mode was "full " by default. If your
application did not set the "responseBuffering" connection property to "adaptive " either in the connection
properties or by using the setResponseBuffering method of the SQLServerStatement object, the driver
supported reading the entire result from the server at once. In order to get the adaptive buffering behavior, your
application had to set the "responseBuffering" connection property to "adaptive " explicitly.
The adaptive value is the default buffering mode and the JDBC driver buffers the minimum possible data when
necessary. For more information about using adaptive buffering, see Using adaptive buffering.
The topics in this section describe different ways that you can use to retrieve large-value data from a SQL Server
database.

In This Section
TO P IC DESC RIP T IO N

Reading large data sample Describes how to use a SQL statement to retrieve large-
value data.

Reading large data with stored procedures sample Describes how to retrieve a large CallableStatement OUT
parameter value.

Updating large data sample Describes how to update a large-value data in a database.

See also
Sample JDBC driver applications
Reading large data sample
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to retrieve a large single-
column value from a SQL Server database by using the getCharacterStream method.
The code file for this sample is named ReadLargeData.java, and it can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\adaptive

Requirements
To run this sample application, you'll need access to the sample database. You must also set the classpath to
include the mssql-jdbc jar file. For more information about how to set the classpath, see Using the JDBC Driver.

NOTE
The Microsoft JDBC Driver for SQL Server provides mssql-jdbc class library files to be used depending on your preferred
Java Runtime Environment (JRE) settings. For more information about which JAR file to choose, see System Requirements
for the JDBC Driver.

Example
In the following example, the sample code makes a connection to the database. Next, the sample code creates
sample data and updates the Production.Document table by using a parameterized query.
In addition, the sample code demonstrates how to get the adaptive buffering mode by using the
getResponseBuffering method of the SQLServerStatement class. Note that starting with the JDBC driver version
2.0 release, the responseBuffering connection property is set to "adaptive" by default.
Then, using an SQL statement with the SQLServerStatement object, the sample code runs the SQL statement
and places the data that it returns into a SQLServerResultSet object.
Finally, the sample code iterates through the rows of data that are in the result set, and uses the
getCharacterStream method to access some of the data.

import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerStatement;

public class ReadLargeData {

public static void main(String[] args) {


// Create a variable for the connection string.
String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";

// Create test data as an example.


StringBuffer buffer = new StringBuffer(4000);
for (int i = 0; i < 4000; i++)
buffer.append((char) ('A'));

try (Connection con = DriverManager.getConnection(connectionUrl);


Statement stmt = con.createStatement();
PreparedStatement pstmt = con.prepareStatement("UPDATE Production.Document SET
DocumentSummary = ? WHERE (DocumentID = 1)");) {

pstmt.setString(1, buffer.toString());
pstmt.executeUpdate();

// In adaptive mode, the application does not have to use a server cursor
// to avoid OutOfMemoryError when the SELECT statement produces very large
// results.

// Create and execute an SQL statement that returns some data.


String SQL = "SELECT Title, DocumentSummary FROM Production.Document";

// Display the response buffering mode.


SQLServerStatement SQLstmt = (SQLServerStatement) stmt;
System.out.println("Response buffering mode is: " + SQLstmt.getResponseBuffering());
SQLstmt.close();

// Get the updated data from the database and display it.
ResultSet rs = stmt.executeQuery(SQL);

while (rs.next()) {
Reader reader = rs.getCharacterStream(2);
if (reader != null) {
char output[] = new char[40];
while (reader.read(output) != -1) {
// Do something with the chunk of the data that was
// read.
}

System.out.println(rs.getString(1) + " has been accessed for the summary column.");


// Close the stream.
reader.close();
}
}
}
// Handle any errors that may have occurred.
catch (SQLException | IOException e) {
e.printStackTrace();
}
}
}

See also
Working with large data
Reading large data with stored procedures sample
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to retrieve a large OUT
parameter from a stored procedure.
The code file for this sample is named ExecuteStoredProcedure.java, and can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\adaptive

Requirements
To run this sample application, you'll need access to the sample database. Set the classpath to include the mssql-
jdbc jar file. For more information about how to set the classpath, see Using the JDBC Driver.

NOTE
The Microsoft JDBC Driver for SQL Server provides mssql-jdbc class library files to be used depending on your preferred
Java Runtime Environment (JRE) settings. For more information about which JAR file to choose, see System Requirements
for the JDBC Driver.

The sample would create the required stored procedure in the sample database:

Example
This sample code:
1. Makes a connection to the database.
2. Creates sample data and updates the Production.Document table by using a parameterized query. Finally, the
sample code gets the adaptive buffering mode by using the getResponseBuffering method of the
SQLServerStatement class and executes the GetLargeDataValue stored procedure. Starting with the JDBC
driver version 2.0 release, the responseBuffering connection property is set to "adaptive" by default.
Finally, the sample code displays the data returned with the OUT parameters and also demonstrates how to use
the mark and reset methods on the stream to re-read any portion of the data.

import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement;

public class ExecuteStoredProcedures {

public static void main(String[] args) {

String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";

try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt =


con.createStatement()) {

createTable(stmt);
createStoredProcedure(stmt);

// Create test data as an example.


StringBuffer buffer = new StringBuffer(4000);
for (int i = 0; i < 4000; i++)
buffer.append((char) ('A'));

try (PreparedStatement pstmt = con.prepareStatement(


"UPDATE Document_JDBC_Sample " + "SET DocumentSummary = ? WHERE (DocumentID = 1)")) {

pstmt.setString(1, buffer.toString());
pstmt.executeUpdate();
}

// Query test data by using a stored procedure.


try (SQLServerCallableStatement cstmt = (SQLServerCallableStatement) con
.prepareCall("{call GetLargeDataValue(?, ?, ?, ?)}")) {

cstmt.setInt(1, 1);
cstmt.registerOutParameter(2, java.sql.Types.INTEGER);
cstmt.registerOutParameter(3, java.sql.Types.CHAR);
cstmt.registerOutParameter(4, java.sql.Types.LONGVARCHAR);

// Display the response buffering mode.


System.out.println("Response buffering mode is: " + cstmt.getResponseBuffering());

cstmt.execute();
System.out.println("DocumentID: " + cstmt.getInt(2));
System.out.println("Document_Title: " + cstmt.getString(3));

try (Reader reader = cstmt.getCharacterStream(4)) {

// If your application needs to re-read any portion of the value,


// it must call the mark method on the InputStream or Reader to
// start buffering data that is to be re-read after a subsequent
// call to the reset method.
reader.mark(4000);

// Read the first half of data.


char output1[] = new char[2000];
reader.read(output1);
String stringOutput1 = new String(output1);

// Reset the stream.


reader.reset();

// Read all the data.


char output2[] = new char[4000];
reader.read(output2);
String stringOutput2 = new String(output2);

System.out.println("Document_Summary in half: " + stringOutput1);


System.out.println("Document_Summary: " + stringOutput2);
}
}
}
// Handle any errors that may have occurred.
catch (Exception e) {
e.printStackTrace();
}
}

private static void createStoredProcedure(Statement stmt) throws SQLException {


private static void createStoredProcedure(Statement stmt) throws SQLException {
String outputProcedure = "GetLargeDataValue";

String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + outputProcedure
+ "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + outputProcedure;
stmt.execute(sql);

sql = "CREATE PROCEDURE " + outputProcedure + " @p0 int, @p1 int OUTPUT, @p2 char(50) OUTPUT, "
+ "@p3 varchar(max) OUTPUT " + " AS" + " SELECT top 1 @p1=DocumentID, @p2=Title,"
+ " @p3=DocumentSummary FROM Document_JDBC_Sample where DocumentID = @p0";

stmt.execute(sql);
}

private static void createTable(Statement stmt) throws SQLException {


stmt.execute("if exists (select * from sys.objects where name = 'Document_JDBC_Sample')"
+ "drop table Document_JDBC_Sample");

String sql = "CREATE TABLE Document_JDBC_Sample(" + "[DocumentID] [int] NOT NULL identity,"
+ "[Title] [char](50) NOT NULL," + "[DocumentSummary] [varchar](max) NULL)";

stmt.execute(sql);

sql = "INSERT Document_JDBC_Sample VALUES ('title1','summary1') ";


stmt.execute(sql);

sql = "INSERT Document_JDBC_Sample VALUES ('title2','summary2') ";


stmt.execute(sql);

sql = "INSERT Document_JDBC_Sample VALUES ('title3','summary3') ";


stmt.execute(sql);
}
}

See also
Working with large data
Updating Large Data Sample
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to update a large column in a
database.
The code file for this sample is named UpdateLargeData.java, and can be found in the following location:

\<installation directory>\sqljdbc_<version>\<language>\samples\adaptive

Requirements
To run this sample application, you'll need access to the sample database. You must also set the classpath to
include the sqljdbc4.jar file. If the classpath is missing an entry for sqljdbc4.jar, the sample application will throw
the common "Class not found" exception. For more information about how to set the classpath, see Using the
JDBC Driver.

NOTE
The Microsoft JDBC Driver for SQL Server provides sqljdbc.jar, sqljdbc4.jar, sqljdbc41.jar, or sqljdbc42.jar class library files
to be used depending on your preferred Java Runtime Environment (JRE) settings. This sample uses the isWrapperFor and
unwrap methods, which are introduced in the JDBC 4.0 API, to access the driver-specific response buffering methods. In
order to compile and run this sample, you will need sqljdbc4.jar class library, which provides support for JDBC 4.0. For
more information about which JAR file to choose, see System Requirements for the JDBC Driver.

Example
In the following example, the sample code makes a connection to the database. Then, the sample code creates a
Statement object and uses the isWrapperFor method to check whether the Statement object is a wrapper for the
specified SQLServerStatement class. The unwrap method is used to access the driver-specific response buffering
methods.
Next, the sample code sets the response buffering mode as "adaptive " by using the setResponseBuffering
method of the SQLServerStatement class and also demonstrates how to get the adaptive buffering mode.
Then, it runs the SQL statement, and places the data that it returns into an updateable SQLServerResultSet
object.
Finally, the sample code iterates through the rows of data that are in the result set. If it finds an empty document
summary, it uses the combination of updateString and updateRow methods to update the row of data and again
persist it to the database. If there's already data, it uses the getString method to display some of the data.
The default behavior of the driver is "adaptive." However, for the forward-only updatable result sets and when
the data in the result set is larger than the application memory, the application has to set the adaptive buffering
mode explicitly by using the setResponseBuffering method of the SQLServerStatement class.

import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerStatement;

public class UpdateLargeData {

public static void main(String[] args) {

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";

// Establish the connection.


try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt =
con.createStatement();
Statement stmt1 = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);) {

createTable(stmt);

// Since the summaries could be large, we should make sure that


// the driver reads them incrementally from a database,
// even though a server cursor is used for the updatable result sets.

// The recommended way to access the Microsoft JDBC Driver for SQL Server
// specific methods is to use the JDBC 4.0 Wrapper functionality.
// The following code statement demonstrates how to use the
// Statement.isWrapperFor and Statement.unwrap methods
// to access the driver specific response buffering methods.

if (stmt.isWrapperFor(com.microsoft.sqlserver.jdbc.SQLServerStatement.class)) {
SQLServerStatement SQLstmt =
stmt.unwrap(com.microsoft.sqlserver.jdbc.SQLServerStatement.class);

SQLstmt.setResponseBuffering("adaptive");
System.out.println("Response buffering mode has been set to " +
SQLstmt.getResponseBuffering());
}

// Select all of the document summaries.


try (ResultSet rs = stmt1.executeQuery("SELECT Title, DocumentSummary FROM
Document_JDBC_Sample")) {

// Update each document summary.


while (rs.next()) {

// Retrieve the original document summary.


try (Reader reader = rs.getCharacterStream("DocumentSummary")) {

if (reader == null) {
// Update the document summary.
System.out.println("Updating " + rs.getString("Title"));
rs.updateString("DocumentSummary", "Work in progress");
rs.updateRow();
}
}
}
}
}
// Handle any errors that may have occurred.
catch (Exception e) {
e.printStackTrace();
}
}

private static void createTable(Statement stmt) throws SQLException {


private static void createTable(Statement stmt) throws SQLException {
stmt.execute("if exists (select * from sys.objects where name = 'Document_JDBC_Sample')"
+ "drop table Document_JDBC_Sample");

String sql = "CREATE TABLE Document_JDBC_Sample (" + "[DocumentID] [int] NOT NULL identity,"
+ "[Title] [char](50) NOT NULL," + "[DocumentSummary] [varchar](max) NULL)";

stmt.execute(sql);

sql = "INSERT Document_JDBC_Sample VALUES ('title1','summary1') ";


stmt.execute(sql);

sql = "INSERT Document_JDBC_Sample (title) VALUES ('title2') ";


stmt.execute(sql);

sql = "INSERT Document_JDBC_Sample (title) VALUES ('title3') ";


stmt.execute(sql);

sql = "INSERT Document_JDBC_Sample VALUES ('title4','summary3') ";


stmt.execute(sql);
}
}

See also
Working with Large Data
SQL Data Discovery and Classification JDBC
Sample
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


This Microsoft JDBC Driver for SQL Server sample application demonstrates how to use result set getter
methods to retrieve SQL Server 'SQL Data Discovery and Classification information' from the tables holding
such information.
The code file for this sample is named DataDiscoveryAndClassification.java, and it can be found in the following
location:

\<installation directory>\sqljdbc_<version>\<language>\samples\dataclassification

Requirements
To run this sample application, you must set the classpath to include the mssql-jdbc jar file. You'll also need
access to the sample database. For more information about how to set the classpath, see Using the JDBC Driver.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerResultSet;
import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityProperty;

public class DataDiscoveryAndClassification {

private static boolean featureSupported = false;

public static void main(String[] args) {

// Provides table name to be used for running test.


String tableName = "JDBC_SQL_DATA_DISCOVERY_CLASSIFICATION";

// Create a variable for the connection string.


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<database>;username=
<user>;password=<password>;";

// Establish the connection.


try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt =
con.createStatement()) {
verifySupportability(stmt);
if (featureSupported) {
createTable(stmt, tableName);
runTests(stmt, tableName);
drop_table(stmt, tableName);
}
} catch (Exception e) {
e.printStackTrace();
}
}

/**
/**
* Verifies if SQL Discovery and Classification feature is applicable on target server.
*
* @param stmt
* Statement object to work with
*/
private static void verifySupportability(Statement stmt) {
try {
stmt.execute("SELECT * FROM SYS.SENSITIVITY_CLASSIFICATIONS");
featureSupported = true;
} catch (SQLException e) {
// Error Code 208 : Object Not Found
if (e.getErrorCode() == 208) {
featureSupported = false;
System.err.println("This feature is not supported on the target SQL Server.");
}
}
}

/**
* Creates table for the test and sets tags for Sensitivity Classification
*
* @param stmt
* Statement to work with
* @param tableName
* Table to be created
* @throws SQLException
* If an exception occurs
*/
private static void createTable(Statement stmt, String tableName) throws SQLException {
// Creates table for storing Supplier data
stmt.execute("CREATE TABLE " + tableName + " (" + "[Id] [int] IDENTITY(1,1) NOT NULL,"
+ "[CompanyName] [nvarchar](40) NOT NULL," + "[ContactName] [nvarchar](50) NULL,"
+ "[ContactTitle] [nvarchar](40) NULL," + "[City] [nvarchar](40) NULL,"
+ "[Country] [nvarchar](40) NULL," + "[Phone] [nvarchar](30) MASKED WITH (FUNCTION =
'default()') NULL,"
+ "[Fax] [nvarchar](30) MASKED WITH (FUNCTION = 'default()') NULL," + "CONSTRAINT [PK_" +
tableName
+ "] PRIMARY KEY CLUSTERED" + "([Id] ASC "
+ ")WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]" + ") ON
[PRIMARY]");

// Set Sensitivity Classification tags to table columns


stmt.execute("ADD SENSITIVITY CLASSIFICATION TO " + tableName
+ ".CompanyName WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Company name',
INFORMATION_TYPE_ID='COMPANY', RANK='LOW')");
stmt.execute("ADD SENSITIVITY CLASSIFICATION TO " + tableName
+ ".ContactName WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Person name',
INFORMATION_TYPE_ID='NAME', RANK='MEDIUM')");
stmt.execute("ADD SENSITIVITY CLASSIFICATION TO " + tableName
+ ".Phone WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Contact Information',
INFORMATION_TYPE_ID='CONTACT', RANK='HIGH')");
stmt.execute("ADD SENSITIVITY CLASSIFICATION TO " + tableName
+ ".Fax WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Contact Information',
INFORMATION_TYPE_ID='CONTACT', RANK='CRITICAL')");
}

/**
* Runs query to fetch ResultSet from target table
*
* @param stmt
* Statement to work with
* @param tableName
* Name of table to fetch results from
* @throws SQLException
* If an exception occurs
*/
private static void runTests(Statement stmt, String tableName) throws SQLException {
String query = "SELECT * FROM " + tableName;
try (SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery(query)) {
try (SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery(query)) {
printSensitivityClassification(rs);
}
}

/**
* Prints Sensitivity Classification data as received in ResultSet
*
* @param rs
* Active ResultSet to read data from
* @throws SQLException
* If an exception occurs
*/
private static void printSensitivityClassification(SQLServerResultSet rs) throws SQLException {
if (null != rs.getSensitivityClassification()) {
for (int columnPos = 0; columnPos <
rs.getSensitivityClassification().getColumnSensitivities().size();
columnPos++) {
for (SensitivityProperty sp :
rs.getSensitivityClassification().getColumnSensitivities().get(columnPos)
.getSensitivityProperties()) {
if (sp.getLabel() != null) {
System.out.println("Labels received for Column : " + columnPos);
System.out.println("Label ID: " + sp.getLabel().getId());
System.out.println("Label Name: " + sp.getLabel().getName());
System.out.println();
}

if (sp.getInformationType() != null) {
System.out.println("Information Types received for Column : " + columnPos);
System.out.println("Information Type ID: " + sp.getInformationType().getId());
System.out.println("Information Type Name: " + sp.getInformationType().getName());
System.out.println();
}

System.out.println("Rank: " + sp.getSensitivityRank());


}

System.out.println("Rank: " + rs.getSensitivityClassification.getSensitivityRank());


}
}
}

/**
* Drops the table created for test
*
* @param stmt
* Statement to work with
* @param tableName
* Table Name to be used
* @throws SQLException
* If an exception occurs
*/
private static void drop_table(Statement stmt, String tableName) throws SQLException {
stmt.execute("DROP TABLE " + tableName);
}
}

See also
Sample JDBC driver applications
JDBC specification compliance
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


This page contains the list of JDBC compliance information for the JDBC driver.
JDBC 4.1 Compliance for the JDBC driver
JDBC 4.2 Compliance for the JDBC driver
JDBC 4.3 Compliance for the JDBC driver
JDBC 4.1 compliance for the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver

NOTE
Versions prior to Microsoft JDBC Driver 4.2 for SQL Server are compliant for Java Database Connectivity API 4.0
specifications. This section does not apply for versions prior to the 4.2 release.

The Java Database Connectivity API 4.1 specification is supported by the Microsoft JDBC Driver 4.2 for SQL
Server, with the following API methods.

SQLServerConnection class
N EW M ET H O D DESC RIP T IO N JDB C DRIVER IM P L EM EN TAT IO N

void abort(Executor executor) Terminates an open connection to SQL Implemented as described in the
Server. java.sql.Connection interface. For more
information, see java.sql.Connection.

void setSchema(String schema) Sets schema for the current SQL Server doesn't support setting
connection. schema for the current session. The
driver silently logs a warning message
if this method is called. For more
information, see java.sql.Connection.

String getSchema() Returns the schema name for the Since SQL Server doesn't support
current connection. setting schema for the current
connection, the driver instead returns
the default schema of the user. For
more information, see
java.sql.Connection.

SQLServerDatabaseMetaData class
N EW M ET H O D DESC RIP T IO N JDB C DRIVER IM P L EM EN TAT IO N

boolean Returns true as the driver supports Implemented as described in the


generatedKeyAlwaysReturned() retrieving generated keys java.sql. DatabaseMetaData interface.
For more information, see
java.sql.DatabaseMetaData.

ResultSet getPseudoColumns(String Retrieves a description of the Return an empty result set as SQL
catalog, String schemaPattern, String pseudo/hidden columns Server doesn't have a formal notion of
tableNamePattern, String pseudo-columns. For more
columnNamePattern) information, see
java.sql.DatabaseMetaData.

SQLServerStatement class
N EW M ET H O D DESC RIP T IO N JDB C DRIVER IM P L EM EN TAT IO N

void closeOnCompletion() Specifies that this Statement will be Implemented as described in the
closed when all its dependent result java.sql.Statement interface. For more
sets are closed. information, see java.sql.Statement.

boolean isCloseOnCompletion() Returns a value indicating whether this Implemented as described in the
Statement will be closed when all its java.sql.Statement interface. For more
dependent result sets are closed. information, see java.sql.Statement.

The Java Database Connectivity API 4.1 specification is supported by the Microsoft JDBC Driver 4.2 for SQL
Server, with the following features.

N EW F EAT URE DESC RIP T IO N

New Escape Function Partially supported

Limited Return Rows Escape Escape syntax: LIMIT <rows> OFFSET <row_offset>.

The Java Database Connectivity API 4.1 specification is supported by the Microsoft JDBC Driver 4.2 for SQL
Server, with the following Data Type Mappings.

DATA T Y P E M A P P IN GS DESC RIP T IO N

New data type mappings are now supported in 1. New Java to JDBC type mapping
PreparedStatement.setObject() and
PreparedStatement.setNull() methods. (a) java.math.BigInteger to JDBC BIGINT

(b) java.util.Date and java.util.Calendar to JDBC TIMESTAMP

2. New data type conversions:

(a) java.math.BigInteger to CHAR, VARCHAR,


LONGVARCHAR, and BIGINT

(b) java.util.Date and java.util.Calendar to CHAR, VARCHAR,


LONGVARCHAR, DATE, TIME, and TIMESTAMP

For more information, see JDBC 4.1 specification.


JDBC 4.2 compliance for the JDBC driver
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver

NOTE
Versions prior to Microsoft JDBC Driver 4.2 for SQL Server are compliant for Java Database Connectivity API 4.0
specifications. This section does not apply for versions prior to the 4.2 release.

The Java Database Connectivity API 4.2 specification is supported by the Microsoft JDBC Driver 4.2 for SQL
Server, with the following API methods.

SQLServerStatement class
N EW M ET H O DS DESC RIP T IO N N OT EW O RT H Y IM P L EM EN TAT IO N

long[] executeLargeBatch() Executes batch where returned update Implemented as described in the
counts can be long. java.sql.Statement interface. For more
information, see java.sql.Statement.

long executeLargeUpdate(String sql) Executes a DML/DDL statement where Implemented as described in the
returned update counts can be long. java.sql.Statement interface. For more
long executeLargeUpdate(String sql, There are 4 new (overloaded) methods information, see java.sql.Statement.
int autoGeneratedKeys) to support long update count.

long executeLargeUpdate(String sql,


int[] columnIndexes)

executeLargeUpdate(String sql, String[]


columnNames)

long getLargeMaxRows() Retrieves the maximum number of SQL Server only supports integer
rows as a long value that the ResultSet limits for max rows. For more
can contain. information, see java.sql.Statement.

long getLargeUpdateCount() Retrieves the current result as a long SQL Server only supports integer
update count. limits for max rows. For more
information, see java.sql.Statement.

void setLargeMaxRows(long max) Sets the maximum number of rows as SQL Server only supports integer
a long value that the ResultSet can limits for max rows. This method
contain. throws a not supported exception if
greater than max integer size is passed
as the parameter. For more
information, see java.sql.Statement.

SQLServerCallableStatement class
N EW M ET H O DS DESC RIP T IO N N OT EW O RT H Y IM P L EM EN TAT IO N

void registerOutParameter(int Registers the OUT parameter. There are Implemented as described in the
parameterIndex, SQLType sqlType) 6 new (overloaded) methods to java.sql.CallableStatement interface. For
support the new SQLType interface. more information, see
void registerOutParameter(int java.sql.CallableStatement.
parameterIndex, SQLType sqlType, int
scale)

void registerOutParameter(int
parameterIndex, SQLType sqlType,
String typeName)

void registerOutParameter(String
parameterName, SQLType sqlType)

void registerOutParameter(String
parameterName, SQLType sqlType, int
scale)

registerOutParameter(String
parameterName, SQLType sqlType,
String typeName)

void setObject(String parameterName, Sets the value of the parameter with Implemented as described in the
Object x, SQLType targetSqlType) the given object. There are 2 new java.sql.CallableStatement interface. For
(overloaded) methods to support the more information, see
void setObject(String parameterName, new SQLType interface java.sql.CallableStatement.
Object x, SQLType targetSqlType, int
scaleOrLength)

SQLServerPreparedStatement class
N EW M ET H O DS DESC RIP T IO N N OT EW O RT H Y IM P L EM EN TAT IO N

long executeLargeUpdate() Execute DML/DDL statement and Implemented as described in the


return long update count java.sql.PreparedStatement interface.
For more information, see
java.sql.PreparedStatement.

void setObject(int parameterIndex, Sets the value of the parameter with Implemented as described in the
Object x, SQLType targetSqlType) the given object. There are 2 new java.sql.PreparedStatement interface.
(overloaded) methods to support the For more information, see
void setObject(int parameterIndex, new SQLType interface. java.sql.PreparedStatement.
Object x, SQLType targetSqlType, int
scaleOrLength)

SQLServerDatabaseMetaData class
N EW M ET H O DS DESC RIP T IO N N OT EW O RT H Y IM P L EM EN TAT IO N

long getMaxLogicalLobSize() Retrieves the maximum number of For SQL Server, this value is 2^31-1.
bytes this database allows for the For more information, see
logical size for a LOB. java.sql.DatabaseMetaData.
N EW M ET H O DS DESC RIP T IO N N OT EW O RT H Y IM P L EM EN TAT IO N

boolean supportsRefCursors() Retrieves whether this database Returns false as SQL Server doesn't
supports REF CURSOR. support REF CURSOR. For more
information, see
java.sql.DatabaseMetaData.

SQLServerResultSet class
N EW M ET H O DS DESC RIP T IO N N OT EW O RT H Y IM P L EM EN TAT IO N

Updates the specified column with an Implemented as described in the


Object value. There are 4 new java.sql.ResultSet interface. For more
(overloaded) methods to support the information, see java.sql.ResultSet.
new SQLType interface.

The Java Database Connectivity API 4.2 specification is supported by the Microsoft JDBC Driver 4.2 for SQL
Server, with the following Data Type Mappings.

N EW DATA T Y P E M A P P IN GS DESC RIP T IO N

New Java classes in Java 8: REF_CURSOR isn't supported in SQL Server. Driver throws a
SQLFeatureNotSupportedException exception if this type is
LocalDate/LocalTime/LocalDateTime used. The driver supports all other new Java and JDBC type
mappings as specified in the JDBC 4.2 specification.
OffsetTime/OffsetDateTime

New JDBC types:

TIME_WITH_TIMEZONE

TIMESTAMP_WITH_TIMEZONE

REF_CURSOR
JDBC 4.3 compliance for the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver

NOTE
Versions prior to Microsoft JDBC Driver 6.4 for SQL Server are only compliant for Java Database Connectivity (JDBC) API
4.2 specifications. This section does not apply for versions including and prior to the 6.4 release.

As of version 6.4, Microsoft JDBC Driver for SQL Server is JAVA 9 compatible and throws
SQLFeatureNotSupportedException for new JDBC 4.3 APIs that have unimplemented methods.

With Microsoft JDBC Driver 7.0 for SQL Server release, the driver is now JAVA 10 compatible, and supports
below mentioned APIs. The driver throws SQLFeatureNotSupportedException for other unimplemented methods
from JDBC 4.3 Specifications.

N EW A P I DESC RIP T IO N N OT EW O RT H Y IM P L EM EN TAT IO N

void java.sql.connection.beginRequest() Hints to the driver that a request, an Saves the values of the connection
independent unit of work, is beginning fields that are modifiable through
on this connection. For more details, public API methods:
see java.sql.Connection. databaseAutoCommitMode ,
transactionIsolationLevel ,
networkTimeout , holdability ,
sendTimeAsDatetime ,
statementPoolingCacheSize ,
disableStatementPooling ,
serverPreparedStatementDiscardThreshold
,
enablePrepareOnFirstPreparedStatementCall
, catalogName , sqlWarnings ,
useBulkCopyForBatchInsert .

void java.sql.connection.endRequest() Hints to the driver that a request, an Closes the statements that are created
independent unit of work, has during the work unit and rolls back
completed. For more details, see any open transactions. The method
java.sql.Connection. also reverts the changes to the
connection fields that are listed above.
Programming guide for JDBC SQL driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Connecting to the SQL Server with the JDBC driver
Understanding the JDBC driver data types
Using statements with the JDBC driver
Managing result sets with the JDBC driver
Performing transactions with the JDBC driver
Handling metadata with the JDBC driver
Using bulk copy with the JDBC driver
Using Always Encrypted with the JDBC driver
Using table-valued parameters
International features of the JDBC driver
JDBC driver API reference
Connecting to SQL Server with the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


One of the most fundamental things that you'll do with the Microsoft JDBC Driver for SQL Server is to make a
connection to a SQL Server database. All interaction with the database occurs through the
SQLServerConnection object, and because the JDBC driver has such a flat architecture, almost all interesting
behavior touches the SQLServerConnection object.
If a SQL Server is only listening on an IPv6 port, set the java.net.preferIPv6Addresses system property to make
sure that IPv6 is used instead of IPv4 to connect to the SQL Server:

System.setProperty("java.net.preferIPv6Addresses", "true");

The articles in this section describe how to make and work with a connection to a SQL Server database.

In this section
A RT IC L E DESC RIP T IO N

Building the connection URL Describes how to form a connection URL for connecting to a
SQL Server database. Also describes connecting to named
instances of a SQL Server database.

Setting the connection properties Describes the various connection properties and how they
can be used when you connect to a SQL Server database.

Setting the data source Properties Describes how to use data sources in a Java Platform,
Enterprise Edition (Java EE) environment.

Working with a connection Describes the various ways in which to create an instance of
a connection to a SQL Server database.

Using connection pooling Describes how the JDBC driver supports the use of
connection pooling.

Using database mirroring (JDBC) Describes how the JDBC driver supports the use of database
mirroring.

JDBC driver support for High Availability, disaster recovery Describes how to develop an application that will connect to
an AlwaysOn availability group.

Using Kerberos Integrated Authentication to Connect to Discusses a Java implementation for applications to connect
SQL Server to a SQL Server database using Kerberos integrated
authentication.

Connecting to an Azure SQL database Discusses connectivity issues for databases on Azure SQL.

See also
Overview of the JDBC driver
Understanding the JDBC driver data types
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Microsoft JDBC Driver for SQL Server supports the use of JDBC basic and advanced data types within a Java
application that uses SQL Server as its database.
The JDBC type system mediates the conversion between SQL Server data types and Java language types and
objects. The JDBC types are modeled on the SQL-92 and SQL-99 types. The JDBC driver adheres to the JDBC
specification and is designed to provide the right balance between predictability and flexibility.
The topics in this section describe how to use the basic and advanced data types, and how data types can be
converted into other data types.

In this section
TO P IC DESC RIP T IO N

Using basic data types Describes the JDBC basic data types. Includes examples of
how to work with the data types by using result sets,
parameterized queries, and stored procedures.

Configuring how java.sql.Time values are sent to the server Describes how the JDBC Driver generates dates.

Using advanced data types Describes the JDBC advanced data types.

Understanding data type differences Describes differences between the various JDBC driver data
types.

Understanding data type conversions Describes how data type conversion is handled when using
getter and setter methods.

National character set support Describes the support for the national character set types.

Supporting XML data Describes the SQLXML interface. Also describes how to read
and write an XML data from and to the relational database
with the SQLXML Java data type.

Wrappers and interfaces Discusses the interfaces that have the Microsoft JDBC Driver
for SQL Server specific methods and constants that allow an
application server to create a proxy of the class, Also
discusses supports for the java.sql.Wrapper interface.

See also
Overview of the JDBC driver
Using statements with the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server can be used to work with data in a SQL Server database in a variety
of ways. The JDBC driver can be used to run SQL statements against the database, or it can be used to call stored
procedures in the database, using both input and output parameters. The JDBC driver also supports using SQL
escape sequences, update counts, automatically generated keys, and performing updates within a batch
operation.
The JDBC driver provides three classes for retrieving data from a SQL Server database:
1. SQLServerStatement - used for running SQL statements without parameters.
2. SQLServerPreparedStatement - (inherited from SQLServerStatement), used for running compiled SQL
statements that might contain IN parameters.
3. SQLServerCallableStatement - (inherited from SQLServerPreparedStatement), used for running stored
procedures that might contain IN parameters, OUT parameters, or both.
The topics in this section discuss how you can use each of the three statement classes to work with data in a SQL
Server database.

In this section
TO P IC DESC RIP T IO N

Using statements with SQL Describes how to use SQL statements with the JDBC driver
to work with data in a SQL Server database.

Using statements with stored procedures Describes how to use stored procedures with the JDBC
driver to work with data in a SQL Server database.

Using multiple result sets Describes how to use the JDBC driver to retrieve data from
multiple result sets.

Using SQL escape sequences Describes how to use SQL escape sequences, such as date
and time literals and functions.

Using auto generated keys Describes how to use automatically generated keys.

Performing batch operations Describes how to use the JDBC driver to perform batch
operations.

Handling complex statements Describes how to use the JDBC driver to run complex
statements that perform a variety of tasks and might return
different types of data.

See also
Overview of the JDBC driver
Managing result sets with the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The result set is an object that represents a set of data returned from a data source, usually as the result of a
query. The result set contains rows and columns to hold the requested data elements, and it is navigated with a
cursor. A result set can be updatable, meaning that it can be modified and have those modifications pushed to
the original data source. A result set can also have various levels of sensitivity to changes in the underlying data
source.
The type of result set is determined when a statement is created, which is when a call to the createStatement
method of the SQLServerConnection class is made. The fundamental role of a result set is to provide Java
applications with a usable representation of the database data. This task is typically done with the typed getter
and setter methods on the result set data elements.
In the following example, which is based on the sample database, a result set is created by calling the
executeQuery method of the SQLServerStatement class. Data from the result set is then displayed by using the
getString method of the SQLServerResultSet class.

public static void executeStatement(Connection con){


try(Statement stmt = con.createStatement();) {
String SQL = "SELECT TOP 10 * FROM Person.Contact";
ResultSet rs = stmt.executeQuery(SQL);

while (rs.next()) {
System.out.println(rs.getString("FirstName") + " " + rs.getString("LastName"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

The articles in this section describe various aspects of result set usage, including cursor types, concurrency, and
row locking.

In this section
A RT IC L E DESC RIP T IO N

Understanding cursor types Describes the different cursor types that the Microsoft JDBC
Driver for SQL Server supports.

Understanding concurrency control Describes how the JDBC driver supports concurrency
control.

Understanding row locking Describes how the JDBC driver supports row locking.

See also
Overview of the JDBC driver
Performing transactions with the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Transaction processing is a mandatory requirement of all applications that must guarantee consistency of their
persistent data. With the Microsoft JDBC Driver for SQL Server, transaction processing can either be performed
locally or distributed. Transactions are atomic, consistent, isolated, and durable (ACID) modules of execution.
The articles in this section describe how the JDBC driver supports transactions including isolation levels,
transaction savepoints, and result set holdability.

In this section
A RT IC L E DESC RIP T IO N

Understanding transactions Provides an overview of how transactions are used with the
JDBC driver.

Understanding XA transactions Provides an overview of how XA transactions are used with


the JDBC driver.

Understanding isolation levels Describes the various isolation levels that are supported by
the JDBC driver.

Using savepoints Describes how to use the JDBC driver with transaction
savepoints.

Using holdability Describes how to use the JDBC driver with result set
holdability.

See also
Overview of the JDBC driver
Handling metadata with the JDBC driver
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server can be used to work with metadata in a SQL Server database in
various ways. The JDBC driver can be used to get metadata about the database, a result set, or parameters.
The JDBC driver provides three classes for retrieving metadata from a SQL Server database:
SQLServerDatabaseMetaData: Used to return information about the database that is currently connected.
SQLServerResultSetMetaData: Used to return information about a result set.
SQLServerParameterMetaData: Used to return information about the parameters of prepared and callable
statements.
The articles in this section describe how you can use each of the three metadata classes to work with metadata
in a SQL Server database.

NOTE
The metadata methods discussed in this section are generally expensive in terms of application performance, so care
should be taken with their usage.

In this section
A RT IC L E DESC RIP T IO N

Using database metadata Describes how to retrieve metadata information about the
currently connected database.

Using result set metadata Describes how to retrieve metadata information about the
current result set.

Using parameter metadata Describes how to retrieve metadata information about the
parameters of prepared and callable statements.

See also
Overview of the JDBC driver
Use Always Encrypted with the JDBC driver
4/27/2022 • 40 minutes to read • Edit Online

Download JDBC Driver


This page provides information on how to develop Java applications to use Always Encrypted with the Microsoft
JDBC Driver 6.0 (or higher) for SQL Server.
Always Encrypted allows clients to encrypt sensitive data and never reveal the data or the encryption keys to
SQL Server or Azure SQL Database. An Always Encrypted enabled driver, such as the Microsoft JDBC Driver 6.0
(or higher) for SQL Server, achieves this behavior by transparently encrypting and decrypting sensitive data in
the client application. The driver figures out which query parameters correspond to Always Encrypted database
columns, and encrypts the values of those parameters before it sends them to the database. Similarly, the driver
transparently decrypts data retrieved from encrypted database columns in query results. For more information,
see Always Encrypted (Database Engine) and Always Encrypted API reference for the JDBC driver.

Prerequisites
Make sure Microsoft JDBC Driver 6.0 (or higher) for SQL Server is installed on your development machine.
Download and install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files. Be
sure to read the Readme included in the zip file for installation instructions, and relevant details on possible
export or import issues.
For mssql-jdbc-X.X.X.jre7.jar or sqljdbc41.jar, the policy files can be downloaded from Java
Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7 Download
For mssql-jdbc-X.X.X.jre8.jar or sqljdbc42.jar, the policy files can be downloaded from Java
Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 8 Download
For mssql-jdbc-X.X.X.jre9.jar, no policy file needs to be downloaded. The jurisdiction policy in Java 9
defaults to unlimited strength encryption.

Work with column master key stores


To encrypt or decrypt data for encrypted columns, SQL Server maintains column encryption keys. Column
encryption keys are stored in encrypted form in the database metadata. Each column encryption key has a
corresponding column master key that is used to encrypt the column encryption key.
The database metadata doesn't contain the column master keys. Those keys are only held by the client. However
the database metadata does contain information about where the column master keys are stored relative to the
client. For example, the database metadata might say the keystore that holds a column master key is the
Windows Certificate Store, and the specific certificate that's used to encrypt and decrypt is located at a specific
path within the Windows Certificate Store.
If the client has access to that certificate in the Windows Certificate Store, it can obtain the certificate. The
certificate can then be used to decrypt the column encryption key. Then that encryption key can be used to
decrypt or encrypt data for encrypted columns that use that column encryption key.
The Microsoft JDBC Driver for SQL Server communicates with a keystore that uses a column master key store
provider, which is an instance of a class that's derived from SQLServerColumnEncryptionKeyStoreProvider .
Use built-in column master key store providers
The Microsoft JDBC Driver for SQL Server comes with the following built-in column master key store providers.
Some of these providers are pre-registered with the specific provider names (used to look up the provider) and
some require either extra credentials or explicit registration.

P RO VIDER ( LO O K UP )
C L A SS DESC RIP T IO N NAME IS P RE- REGIST ERED? P L AT F O RM

A provider for a AZURE_KEY_VAULT


SQLServerColumnEncryptionAzureKeyVaultProvider No before JDBC Windows, Linux,
keystore for the driver version 7.4.1, macOS
Azure Key Vault. but yes as of JDBC
driver version 7.4.1.

A provider for the MSSQL_CERTIFICATE


SQLServerColumnEncryptionCertificateStoreProvider Yes Windows
Windows Certificate _STORE
Store.

A provider for the


SQLServerColumnEncryptionJavaKeyStoreProviderMSSQL_JAVA_KEYST Yes Windows, Linux,
Java keystore. ORE macOS

For the pre-registered keystore providers, you don't need any application code changes to use these providers
but note the following items:
You must make sure the provider name that's configured in the column master key metadata is correct and
the column master key path follows the key path format that is valid for a given provider. It's recommended
that you configure the keys with tools such as SQL Server Management Studio, which automatically
generates the valid provider names and key paths to issue the CREATE COLUMN MASTER KEY (Transact-SQL)
statement.
Ensure your application can access the key in the keystore. This task might involve granting your application
access to the key and/or the keystore. Depending on the keystore, this might involve other keystore-specific
configuration steps. For example, to use the SQLServerColumnEncryptionJavaKeyStoreProvider , you must
provide the location and the password of the keystore in the connection properties.
All of these keystore providers are described in more detail in the sections that follow. You only need to
implement one keystore provider to use Always Encrypted.
Use Azure Key Vault provider
Azure Key Vault is a convenient option to store and manage column master keys for Always Encrypted
(especially if your application is hosted in Azure). The Microsoft JDBC Driver for SQL Server includes a built-in
provider, SQLServerColumnEncryptionAzureKeyVaultProvider , for applications that have keys stored in Azure Key
Vault. The name of this provider is AZURE_KEY_VAULT.

NOTE
The Azure Key Vault provider built in to the JDBC driver supports both Vaults and Managed HSMs in Azure Key Vault.

To use the Azure Key Vault store provider, an application developer must create the vault and the keys in Azure
Key Vault and create an App registration in Azure Active Directory. The registered application must be granted
Get, Decrypt, Encrypt, Unwrap Key, Wrap Key, and Verify permissions in the Access policies defined for the key
vault created for use with Always Encrypted. For more information on how to set up the key vault and create a
column master key, see Azure Key Vault—Step by Step and Creating Column Master Keys in Azure Key Vault.
For Azure Key Vault provider, the JDBC driver validates the column master key path against the list of trusted
endpoints. As of version 8.2.2, this list is configurable: create a mssql-jdbc.properties file in the working
directory of the application, set the AKVTrustedEndpoints property to a semicolon-delimited list. If the value
begins with a semicolon, it extends the default list. Otherwise, it replaces the default list.
The default, trusted endpoints are:
*vault.azure.net
*vault.azure.cn
*vault.usgovcloudapi.net
*vault.microsoftazure.de
*managedhsm.azure.net (v9.2+)
*managedhsm.azure.cn (v9.2+)
*managedhsm.usgovcloudapi.net (v9.2+)
*managedhsm.microsoftazure.de (v9.2+)

For the examples on this page, if you've created an Azure Key Vault based column master key and column
encryption key with SQL Server Management Studio, the T-SQL script to re-create them might look similar to
this example with its own specific KEY_PATH and ENCRYPTED_VALUE :

CREATE COLUMN MASTER KEY [MyCMK]


WITH
(
KEY_STORE_PROVIDER_NAME = N'AZURE_KEY_VAULT',
KEY_PATH = N'https://<MyKeyVaultName>.vault.azure.net:443/keys/Always-Encrypted-
Auto1/c61f01860f37302457fa512bb7e7f4e8'
);

CREATE COLUMN ENCRYPTION KEY [MyCEK]


WITH VALUES
(
COLUMN_MASTER_KEY = [MyCMK],
ALGORITHM = 'RSA_OAEP',
ENCRYPTED_VALUE = 0x01BA000001680074507400700073003A002F002F006400610076006...
);

An application that uses the JDBC driver can use the Azure Key Vault. The syntax or statements for this use of
Azure Key Vault changed as of with JDBC driver version 7.4.1.
JDBC driver 7.4.1 or later
This section involves JDBC driver version 7.4.1 or later.
A client application that uses the JDBC driver can configure to use Azure Key Vault by mentioning
keyVaultProviderClientId=<ClientId>;keyVaultProviderClientKey=<ClientKey> in JDBC connection string.

Here's an example that provides this configuration information in a JDBC connection string.

String connectionUrl = "jdbc:sqlserver://<server>:<port>;user=<user>;password=


<password>;columnEncryptionSetting=Enabled;keyVaultProviderClientId=<ClientId>;keyVaultProviderClientKey=
<ClientKey>";

The JDBC driver automatically instantiates a SQLServerColumnEncryptionAzureKeyVaultProvider object when these


credentials are present among the connection properties.

IMPORTANT
The connection properties keyVaultProviderClientId and keyVaultProviderClientKey have been deprecated as of
v8.4.1. Users are encouraged to use keyStoreAuthentication , KeyStorePrincipalId , and KeyStoreSecret instead.

JDBC driver versions before 7.4.1


This section involves JDBC driver versions before 7.4.1.
A client application that uses the JDBC driver must instantiate a SQLServerColumnEncryptionAzureKeyVaultProvider
object, and then register the object with the driver.

SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider = new


SQLServerColumnEncryptionAzureKeyVaultProvider(clientID, clientKey);

clientID is the Application ID of an App registration in an Azure Active Directory instance. clientKey is a Key
Password registered under that Application, which provides API access to the Azure Key Vault.
After the application creates an instance of SQLServerColumnEncryptionAzureKeyVaultProvider , the application
must register the instance with the driver with the
SQLServerConnection.registerColumnEncryptionKeyStoreProviders() method. It's highly recommended that the
instance is registered using the default lookup name, AZURE_KEY_VAULT, which can be obtained by the
SQLServerColumnEncryptionAzureKeyVaultProvider.getName() API. The default name allows you to use tools such as
SQL Server Management Studio or PowerShell to provision and manage Always Encrypted keys (the tools use
the default name to generate the metadata object to column master key). The following example shows
registering the Azure Key Vault provider. For more information on the
SQLServerConnection.registerColumnEncryptionKeyStoreProviders() method, see Always Encrypted API Reference
for the JDBC Driver.

Map<String, SQLServerColumnEncryptionKeyStoreProvider> keyStoreMap = new HashMap<String,


SQLServerColumnEncryptionKeyStoreProvider>();
keyStoreMap.put(akvProvider.getName(), akvProvider);
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(keyStoreMap);

IMPORTANT
If you use the Azure Key Vault keystore provider, the Azure Key Vault implementation of the JDBC driver has
dependencies on these libraries (from GitHub) which must be included with your application:
azure-sdk-for-java
microsoft-authentication-library-for-java libraries
For an example of how to include these dependencies in a Maven project, see Download MSAL4J And AKV Dependencies
with Apache Maven

Use Azure Key Vault authentication with Managed Identities


As of JDBC Driver 8.4.1 , the driver added support to authenticate to Azure Key Vaults with Managed Identities.
You can use Managed Identities to authenticate to the Azure Key Vault if the application is hosted in Azure. This
eliminates the need to provide and expose any credentials in the code.
Connection properties for Key Vault authentication with Managed Identities
For JDBC Driver 8.4.1 and later, the driver introduced the following connection properties:

C O N N EC T IO N P RO P ERT Y P O SSIB L E VA L UE PA IRIN G 1 P O SSIB L E VA L UE PA IRIN G 2 P O SSIB L E VA L UE PA IRIN G 3

keyStoreAuthentication KeyVaultClientSecret KeyVaultManagedIdentity JavaKeyStorePassword

keyStorePrincipalId <Azure AD Application <Azure AD Application n/a


Client ID> object ID> (optional)

keyStoreSecret <Azure AD Application n/a <secret/password for the


Client Secret> Java Key Store>
The following examples show how the connection properties are used in a connection string.
Use Managed Identity to authenticate to AKV

"jdbc:sqlserver://<server>:
<port>;columnEncryptionSetting=Enabled;keyStoreAuthentication=KeyVaultManagedIdentity;"

Use Managed Identity and the principal ID to authenticate to AKV

"jdbc:sqlserver://<server>:
<port>;columnEncryptionSetting=Enabled;keyStoreAuthentication=KeyVaultManagedIdentity;keyStorePrincipal=
<principalId>"

Use clientId and clientSecret to authentication to AKV

"jdbc:sqlserver://<server>:
<port>;columnEncryptionSetting=Enabled;keyStoreAuthentication=KeyVaultClientSecret;keyStorePrincipalId=
<clientId>;keyStoreSecret=<clientSecret>"

Users are encouraged to use these connection properties to specify the type of authentication used for the Key
Stores instead of the SQLServerColumnEncryptionAzureKeyVaultProvider API.
Previously added connection properties keyVaultProviderClientId and keyVaultProviderClientKey are
deprecated and replaced by the connection properties described above.
For information on how to configure Managed Identities, see Configure managed identities for Azure resources
on a VM using the Azure portal.
Use Windows Certificate Store provider
The SQLServerColumnEncryptionCertificateStoreProvider can be used to store column master keys in the
Windows Certificate Store. Use the SQL Server Management Studio (SSMS) Always Encrypted wizard or other
supported tools to create the column master key and column encryption key definitions in the database. The
same wizard can be used to generate a self-signed certificate in the Windows Certificate Store that can be used
as a column master key for the Always Encrypted data. For more information on column master key and column
encryption key T-SQL syntax, see CREATE COLUMN MASTER KEY and CREATE COLUMN ENCRYPTION KEY
respectively.
The name of the SQLServerColumnEncryptionCertificateStoreProvider is MSSQL_CERTIFICATE_STORE and can be
queried by the getName() API of the provider object. It's automatically registered by the driver and can be used
seamlessly without any application change.
For the examples on this page, if you've created a Windows Certificate Store based column master key and
column encryption key with SQL Server Management Studio, the T-SQL script to re-create them might look
similar to this example with its own specific KEY_PATH and ENCRYPTED_VALUE :
CREATE COLUMN MASTER KEY [MyCMK]
WITH
(
KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE',
KEY_PATH = N'CurrentUser/My/A2A91F59C461B559E4D962DA9D2BC6131B32CB91'
);

CREATE COLUMN ENCRYPTION KEY [MyCEK]


WITH VALUES
(
COLUMN_MASTER_KEY = [MyCMK],
ALGORITHM = 'RSA_OAEP',
ENCRYPTED_VALUE = 0x016E000001630075007200720065006E0074007500730065007200...
);

IMPORTANT
While the other keystore providers in this article are available on all platforms supported by the driver, the
SQLServerColumnEncryptionCertificateStoreProvider implementation of the JDBC driver is available on Windows
operating systems only. It has a dependency on the mssql-jdbc_auth-<version>-<arch>.dll that is available in the
driver package. To use this provider, copy the mssql-jdbc_auth-<version>-<arch>.dll file to a directory on the
Windows system path on the computer where the JDBC driver is installed. Alternatively you can set the java.library.path
system property to specify the directory of the mssql-jdbc_auth-<version>-<arch>.dll . If you are running a 32-bit
Java Virtual Machine (JVM), use the mssql-jdbc_auth-<version>-x86.dll file in the x86 folder, even if the operating
system is the x64 version. If you are running a 64-bit JVM on a x64 processor, use the
mssql-jdbc_auth-<version>-x64.dll file in the x64 folder. For example, if you use the 32-bit JVM and the JDBC driver
is installed in the default directory, you can specify the location of the DLL with the following virtual machine (VM)
argument when the Java application is started:
-Djava.library.path=C:\Microsoft JDBC Driver <version> for SQL Server\sqljdbc_<version>\enu\auth\x86

Use Java Key Store provider


The JDBC driver comes with a built-in keystore provider implementation for the Java Key Store. If the
keyStoreAuthentication connection string property is present in the connection string and it's set to
JavaKeyStorePassword , the driver automatically instantiates and registers the provider for Java Key Store. The
name of the Java Key Store provider is MSSQL_JAVA_KEYSTORE. This name can also be queried by the
SQLServerColumnEncryptionJavaKeyStoreProvider.getName() API.

There are three connection string properties that allow a client application to specify the credentials the driver
needs to authenticate to the Java Key Store. The driver initializes the provider based on the values of these three
properties in the connection string.
keyStoreAuthentication : Identifies the Java Key Store to use. With Microsoft JDBC Driver 6.0 and higher for SQL
Server, you can authenticate to the Java Key Store only through this property. For the Java Key Store, the value
for this property must be JavaKeyStorePassword .
keyStoreLocation : The path to the Java Key Store file that stores the column master key. The path includes the
keystore filename.
keyStoreSecret : The secret/password to use for the keystore and the key. To use the Java Key Store, the keystore
and the key password must be the same.
Here's an example of providing these credentials in the connection string:
String connectionUrl = "jdbc:sqlserver://<server>:<port>;user=<user>;password=
<password>;columnEncryptionSetting=Enabled;keyStoreAuthentication=JavaKeyStorePassword;keyStoreLocation=
<path_to_the_keystore_file>;keyStoreSecret=<keystore_key_password>";

You can also get or set these settings with the SQLServerDataSource object. For more information, see Always
Encrypted API Reference for the JDBC Driver.
The JDBC driver automatically instantiates the SQLServerColumnEncryptionJavaKeyStoreProvider when these
credentials are present in connection properties.
Creating a column master key for the Java Key Store
The SQLServerColumnEncryptionJavaKeyStoreProvider can be used with JKS or PKCS12 keystore types. To create or
import a key to use with this provider use the Java keytool utility. The key must have the same password as the
keystore itself. Here's an example of how to create a public key and its associated private key with the keytool
utility:

keytool -genkeypair -keyalg RSA -alias AlwaysEncryptedKey -keystore keystore.jks -storepass mypassword -
validity 360 -keysize 2048 -storetype jks

This command creates a public key and wraps it in an X.509 self-signed certificate, which is stored in the
keystore keystore.jks along with its associated private key. This entry in the keystore is identified by the alias
AlwaysEncryptedKey .

Here's an example of the same with a PKCS12 store type:

keytool -genkeypair -keyalg RSA -alias AlwaysEncryptedKey -keystore keystore.pfx -storepass mypassword -
validity 360 -keysize 2048 -storetype pkcs12 -keypass mypassword

If the keystore is of type PKCS12, the keytool utility doesn't prompt for a key password and the key password
needs to be provided with -keypass option as the SQLServerColumnEncryptionJavaKeyStoreProvider requires that
the keystore and the key have the same password.
You can also export a certificate from the Windows Certificate store in .pfx format and use that with the
SQLServerColumnEncryptionJavaKeyStoreProvider . The exported certificate can also be imported to the Java Key
Store as a JKS keystore type.
After you create the keytool entry, create the column master key metadata in the database, which needs the
keystore provider name and the key path. For more information on how to create column master key meta data,
see CREATE COLUMN MASTER KEY. For SQLServerColumnEncryptionJavaKeyStoreProvider , the key path is just the
alias of the key and the name of the SQLServerColumnEncryptionJavaKeyStoreProvider is MSSQL_JAVA_KEYSTORE . You
can also query this name with the getName() public API of the SQLServerColumnEncryptionJavaKeyStoreProvider
class.
The T-SQL syntax to create the column master key is:

CREATE COLUMN MASTER KEY [<CMK_name>]


WITH
(
KEY_STORE_PROVIDER_NAME = N'MSSQL_JAVA_KEYSTORE',
KEY_PATH = N'<key_alias>'
);

For the 'AlwaysEncryptedKey' created above, the column master key definition would be:
CREATE COLUMN MASTER KEY [MyCMK]
WITH
(
KEY_STORE_PROVIDER_NAME = N'MSSQL_JAVA_KEYSTORE',
KEY_PATH = N'AlwaysEncryptedKey'
);

NOTE
The built-in SQL Server management Studio functionality cannot create column master key definitions for the Java Key
Store. T-SQL commands must be used programmatically.

Create a column encryption key for the Java Key Store


The SQL Server Management Studio or any other tool can't be used to create column encryption keys using
column master keys in the Java Key Store. The client application must create the column encryption key
programmatically with the SQLServerColumnEncryptionJavaKeyStoreProvider class. For more information, see Use
column master key store providers for programmatic key provisioning.
Implementing a custom column master key store provider
If you want to store column master keys in a keystore that isn't supported by an existing provider, you can
implement a custom provider by extending the SQLServerColumnEncryptionKeyStoreProvider Class and
registering the provider with one of the following methods:
SQLServerConnection.registerColumnEncryptionKeyStoreProviders
SQLServerConnection.registerColumnEncryptionKeyStoreProvidersOnConnection (Added in JDBC version 10.2)
SQLServerStatement.registerColumnEncryptionKeyStoreProvidersOnStatement (Added in JDBC version 10.2)

public class MyCustomKeyStore extends SQLServerColumnEncryptionKeyStoreProvider{


private String name = "MY_CUSTOM_KEYSTORE";

public void setName(String name)


{
this.name = name;
}

public String getName()


{
return name;
}

public byte[] encryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, byte[]


plainTextColumnEncryptionKey)
{
// Logic for encrypting the column encryption key
}

public byte[] decryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, byte[]


encryptedColumnEncryptionKey)
{
// Logic for decrypting the column encryption key
}
}

Register the provider with SQLServerConnection.registerColumnEncryptionKeyStoreProviders :


SQLServerColumnEncryptionKeyStoreProvider storeProvider = new MyCustomKeyStore();
Map<String, SQLServerColumnEncryptionKeyStoreProvider> keyStoreMap = new HashMap<String,
SQLServerColumnEncryptionKeyStoreProvider>();
keyStoreMap.put(storeProvider.getName(), storeProvider);
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(keyStoreMap);

Column encryption key cache precedence


This section applies to JDBC driver version 10.2 and higher.
The column encryption keys (CEK) decrypted by custom key store providers registered on a connection or
statement instance won't be cached by the Microsoft JDBC Driver for SQL Ser ver . Custom key store
providers should implement their own CEK caching mechanism.
As of version 10.2, the SQLServerColumnEncryptionAzureKeyVaultProvider has its own CEK caching
implementation. When registered on a connection or statement instance, CEKs decrypted by an instance of
SQLServerColumnEncryptionAzureKeyVaultProvider will be cleared when that instance goes out of scope:

try (SQLServerConnection conn = getConnection(); SQLServerStatement stmt = (SQLServerStatement)


conn.createStatement()) {

Map<String, SQLServerColumnEncryptionKeyStoreProvider> customKeyStoreProviders = new HashMap<>();


SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider = new
SQLServerColumnEncryptionAzureKeyVaultProvider(clientID, clientKey);
customKeyStoreProviders.put(akvProvider.getName(), akvProvider);
stmt.registerColumnEncryptionKeyStoreProvidersOnStatement(customKeyStoreProviders);
// Perform database operation with Azure Key Vault Provider
// Any decrypted column encryption keys will be cached
} // Column encryption key cache of "akvProvider" is cleared when "akvProvider" goes out of scope

NOTE
CEK caching implemented by custom key store providers will be disabled by the driver if the key store provider instance is
registered in the driver globally with the SQLServerConnection.registerColumnEncryptionKeyStoreProviders method.
Any CEK caching implementation should reference the value of time-to-live duration before caching a CEK and not cache
it if the value is zero. This will avoid duplicate caching and possible user confusion when they are trying to configure key
caching. The time-to-live value for the cache can be set with the
SQLServerColumnEncryptionKeyStoreProvider.setColumnEncryptionCacheTtl method.

Register a custom column master key store provider


This section applies to JDBC driver version 10.2 and higher.
Custom master key store providers can be registered with the driver at three different layers. The precedence of
the three registrations is as follows:
The per-statement registration is checked if it isn't empty.
If the per-statement registration is empty, the per-connection registration is checked if it isn't empty.
If the per-connection registration is empty, the global registration is checked.
Once any key store provider is found at a registration level, the driver will NOT fall back to the other
registrations to search for a provider. If providers are registered but the proper provider isn't found at a level, an
exception is thrown that contains only the registered providers in the registration that was checked.
The built-in column master key store provider that is available for the Windows Certificate Store is pre-
registered. The Microsoft Java Keystore provider and Azure Key Vault Keystore provider can be implicitly pre-
registered with a connection instance if credentials are provided in advance.
The three registration levels support different scenarios when querying encrypted data. The appropriate method
can be used to ensure that a user of an application can access the plaintext data. Access to the unencrypted data
only happens if they can provide the required column master key, by authenticating against the key store
containing the column master key.
Applications that share a SQLServerConnection instance between multiple users might want to use
SQLServerStatement.registerColumnEncryptionKeyStoreProvidersOnStatement . Each user must register a key store
provider on a SQLServerStatement instance before executing a query to access an encrypted column. If the key
store provider is able to access the required column master key in the key store that uses the user's given
credentials, the query will succeed.
Applications that create a instance for each user might want to use
SQLServerConnection
SQLServerConnection.registerColumnEncryptionKeyStoreProvidersOnConnection . Key store providers registered with
this method can be used by the connection for any query accessing encrypted data.
Key store providers registered with SQLServerConnection.registerColumnEncryptionKeyStoreProviders will use the
identity given by the application when authenticating against the key store.
The following example shows the precedence of custom column master key store providers registered on a
connection instance:

Map<String, SQLServerColumnEncryptionKeyStoreProvider> customKeyStoreProviders = new HashMap<>();


MyCustomKeyStore myProvider = new MyCustomKeyStore();
customKeyStoreProviders.put(myProvider.getName(), myProvider);
// Registers the provider globally
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(customKeyStoreProviders);

try (SQLServerConnection conn = getConnection()) {


customKeyStoreProviders.clear();
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider = new
SQLServerColumnEncryptionAzureKeyVaultProvider(clientID, clientKey);
customKeyStoreProviders.put(akvProvider.getName(), akvProvider);

// Registers the provider on the connection


// These providers will take precedence over globally registered providers
conn.registerColumnEncryptionKeyStoreProvidersOnConnection(customKeyStoreProviders);
}

The following example shows the precedence of custom column master key store providers registered on a
statement instance:
Map<String, SQLServerColumnEncryptionKeyStoreProvider> customKeyStoreProviders = new HashMap<>();
MyCustomKeyStore firstProvider = new MyCustomKeyStore();
customKeyStoreProviders.put("FIRST_CUSTOM_STORE", firstProvider);
// Registers the provider globally
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(customKeyStoreProviders);

try (SQLServerConnection conn = getConnection()) {


customKeyStoreProviders.clear();
MyCustomKeyStore secondProvider = new MyCustomKeyStore();
customKeyStoreProviders.put("SECOND_CUSTOM_STORE", secondProvider);
// Registers the provider on the connection
conn.registerColumnEncryptionKeyStoreProvidersOnConnection(customKeyStoreProviders);

try (SQLServerStatement stmt = (SQLServerStatement) conn.createStatement()) {


customKeyStoreProviders.clear();
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider = new
SQLServerColumnEncryptionAzureKeyVaultProvider(clientID, clientKey);
customKeyStoreProviders.put(akvProvider.getName(), akvProvider);

// Registers the provider on the statement


// These providers will take precedence over connection-level providers and globally registered
providers
stmt.registerColumnEncryptionKeyStoreProvidersOnStatement(customKeyStoreProviders);
}
}

Use column master key store providers for programmatic key


provisioning
To access encrypted columns, the Microsoft JDBC Driver for SQL Server transparently finds and calls the right
column master key store provider to decrypt column encryption keys. Typically, your normal application code
doesn't directly call column master key store providers. You may, however, instantiate and call a provider
programmatically to provision and manage Always Encrypted keys. This step may be done to generate an
encrypted column encryption key and decrypt a column encryption key as part column master key rotation, for
example. For more information, see Overview of Key Management for Always Encrypted.
If you use a custom keystore provider, implementing your own key management tools may be required. To use
keys stored in Windows Certificate Store or in Azure Key Vault, you can use existing tools, such as SQL Server
Management Studio or PowerShell, to manage and provision keys. To use keys stored in the Java Key Store, you
need to provision keys programmatically. The following example illustrates how to use the
SQLServerColumnEncryptionJavaKeyStoreProvider class to encrypt the key with a key stored in the Java Key Store.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionJavaKeyStoreProvider;
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider;
import com.microsoft.sqlserver.jdbc.SQLServerException;

/**
* This program demonstrates how to create a column encryption key programmatically for the Java Key Store.
*/
public class AlwaysEncrypted {
// Alias of the key stored in the keystore.
private static String keyAlias = "<provide key alias>";

// Name by which the column master key will be known in the database.
private static String columnMasterKeyName = "MyCMK";

// Name by which the column encryption key will be known in the database.
// Name by which the column encryption key will be known in the database.
private static String columnEncryptionKey = "MyCEK";

// The location of the keystore.


private static String keyStoreLocation = "C:\\Dev\\Always Encrypted\\keystore.jks";

// The password of the keystore and the key.


private static char[] keyStoreSecret = "********".toCharArray();

/**
* Name of the encryption algorithm used to encrypt the value of the column encryption key. The
algorithm for the system providers must be
* RSA_OAEP.
*/
private static String algorithm = "RSA_OAEP";

public static void main(String[] args) {


String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<databaseName>;user=
<user>;password=<password>;columnEncryptionSetting=Enabled;";

try (Connection connection = DriverManager.getConnection(connectionUrl);


Statement statement = connection.createStatement();) {

// Instantiate the Java Key Store provider.


SQLServerColumnEncryptionKeyStoreProvider storeProvider = new
SQLServerColumnEncryptionJavaKeyStoreProvider(keyStoreLocation,
keyStoreSecret);

byte[] encryptedCEK = getEncryptedCEK(storeProvider);

/**
* Create column encryption key For more details on the syntax, see:
* https://docs.microsoft.com/sql/t-sql/statements/create-column-encryption-key-transact-sql
Encrypted column encryption key first needs
* to be converted into varbinary_literal from bytes, for which byteArrayToHex() is used.
*/
String createCEKSQL = "CREATE COLUMN ENCRYPTION KEY "
+ columnEncryptionKey
+ " WITH VALUES ( "
+ " COLUMN_MASTER_KEY = "
+ columnMasterKeyName
+ " , ALGORITHM = '"
+ algorithm
+ "' , ENCRYPTED_VALUE = 0x"
+ byteArrayToHex(encryptedCEK)
+ " ) ";
statement.executeUpdate(createCEKSQL);
System.out.println("Column encryption key created with name : " + columnEncryptionKey);
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

private static byte[] getEncryptedCEK(SQLServerColumnEncryptionKeyStoreProvider storeProvider) throws


SQLServerException {
String plainTextKey = "You need to give your plain text";

// plainTextKey has to be 32 bytes with current algorithm supported


byte[] plainCEK = plainTextKey.getBytes();

// This will give us encrypted column encryption key in bytes


byte[] encryptedCEK = storeProvider.encryptColumnEncryptionKey(keyAlias, algorithm, plainCEK);

return encryptedCEK;
}

public static String byteArrayToHex(byte[] a) {


StringBuilder sb = new StringBuilder(a.length * 2);
for (byte b : a)
sb.append(String.format("%02x", b).toUpperCase());
return sb.toString();
}
}

Enabling Always Encrypted for application queries


The easiest way to enable the encryption of parameters and the decryption of query results of encrypted
columns is by setting the value of the columnEncryptionSetting connection string keyword to Enabled .
The following connection string is an example of enabling Always Encrypted in the JDBC driver:

String connectionUrl = "jdbc:sqlserver://<server>:<port>;user=<user>;password=<password>;databaseName=


<database>;columnEncryptionSetting=Enabled;";
SQLServerConnection connection = (SQLServerConnection) DriverManager.getConnection(connectionUrl);

The following code is an equivalent example to use the SQLServerDataSource object:

SQLServerDataSource ds = new SQLServerDataSource();


ds.setServerName("<server>");
ds.setPortNumber(<port>);
ds.setUser("<user>");
ds.setPassword("<password>");
ds.setDatabaseName("<database>");
ds.setColumnEncryptionSetting("Enabled");
SQLServerConnection con = (SQLServerConnection) ds.getConnection();

Always Encrypted can also be enabled for individual queries. For more information, see Controlling the
performance impact of Always Encrypted. Enabling Always Encrypted isn't sufficient for encryption or
decryption to succeed. You also need to make sure:
The application has the VIEW ANY COLUMN MASTER KEY DEFINITION and
VIEW ANY COLUMN ENCRYPTION KEY DEFINITION database permissions, required to access the metadata about
Always Encrypted keys in the database. For details, see Permissions in Always Encrypted (Database Engine).
The application can access the column master key that protects the column encryption keys, which encrypt
the queried database columns. To use the Java Key Store provider, you need to provide extra credentials in
the connection string. For more information, see Use Java Key Store provider.
Configuring how java.sql.Time values are sent to the server
The sendTimeAsDatetime connection property is used to configure how the java.sql.Time value is sent to the
server. When set to false, the time value is sent as a SQL Server time type. When set to true, the time value is
sent as a datetime type. If a time column is encrypted, the sendTimeAsDatetime property must be false, as
encrypted columns don't support the conversion from time to datetime. Also note that this property is by
default true, so to use encrypted time columns set it to false. Otherwise, the driver will throw an exception.
Starting with version 6.0 of the driver, the SQLServerConnection class has two methods to configure the value of
this property programmatically:
public void setSendTimeAsDatetime(boolean sendTimeAsDateTimeValue)
public boolean getSendTimeAsDatetime()
For more information on this property, see Configuring How java.sql.Time Values are Sent to the Server.
Configuring how String values are sent to the server
The sendStringParametersAsUnicode connection property is used to configure how String values are sent to SQL
Server. If set to true, String parameters are sent to the server in Unicode format. If set to false, String parameters
are sent in non-Unicode format, such as ASCII or MBCS, instead of Unicode. The default value for this property is
true. When Always Encrypted is enabled and a char / varchar / varchar(max) column is encrypted, the value of
sendStringParametersAsUnicode must be set to false. If this property is set to true, the driver will throw an
exception when decrypting data from an encrypted char / varchar / varchar(max) column that has Unicode
characters. For more information on this property, see Setting the Connection Properties.

IMPORTANT
If sendStringParametersAsUnicode is set to true and unicode data is inserted into a char / varchar column
encrypted with Always Encrypted, data loss may occur without an error being reported. The data loss may only be
detected when trying to decrypt the data after reading it back from the server. An error like
Decryption failed. The last 10 bytes of the encrypted column encryption key are: 'C3-D9-10-4E-C1-45-8B-
94-A2-43'. The first 10 bytes of ciphertext are: '01-9B-9D-A6-3E-40-22-53-15-9B'.
might be the result.
It is important to use correct column data types and specify the correct data type for parameters when inserting
encrypted data. If unicode data is expected, use nchar / nvarchar columns and setNString() methods. The server
can't perform implicit data conversions and has limited ability to detect data errors when Always Encrypted is enabled.

Retrieving and modifying data in encrypted columns


Once you enable Always Encrypted for application queries, you can use standard JDBC APIs to retrieve or
modify data in encrypted database columns. If your application has the required database permissions and can
access the column master key, the driver will encrypt any query parameters that target encrypted columns, and
decrypt data that's retrieved from encrypted columns.
If Always Encrypted isn't enabled, queries with parameters that target encrypted columns will fail. Queries can
still retrieve data from encrypted columns as long as the query has no parameters targeting encrypted columns.
However, the driver won't attempt to decrypt any values that are retrieved from encrypted columns and the
application will receive binary encrypted data (as byte arrays).
The following table summarizes the behavior of queries depending on whether Always Encrypted is enabled or
not:

A L WAY S EN C RY P T ED IS A L WAY S EN C RY P T ED IS
EN A B L ED A N D EN A B L ED A N D
A P P L IC AT IO N C A N A C C ESS A P P L IC AT IO N C A N 'T
T H E K EY S A N D K EY A C C ESS T H E K EY S O R K EY A L WAY S EN C RY P T ED IS
Q UERY C H A RA C T ERIST IC M ETA DATA M ETA DATA DISA B L ED

Queries with parameters Parameter values are Error Error


targeting encrypted transparently encrypted.
columns.

Queries retrieving data Results from encrypted Error Results from encrypted
from encrypted columns columns are transparently columns aren't decrypted.
without parameters decrypted. The application The application receives
targeting encrypted receives plaintext values of encrypted values as byte
columns. the JDBC datatypes arrays (byte[]).
corresponding to the SQL
Server types configured for
the encrypted columns.

Inserting and retrieving encrypted data examples


The following examples illustrate retrieving and modifying data in encrypted columns. The examples assume the
target table with the following schema and encrypted SSN and BirthDate columns. If you've configured a
Column Master Key named "MyCMK" and a Column Encryption Key named "MyCEK" (as described in the
preceding keystore providers sections), you can create the table with this script:

CREATE TABLE [dbo].[Patients]([PatientId] [int] IDENTITY(1,1),


[SSN] [char](11) COLLATE Latin1_General_BIN2
ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC,
ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256',
COLUMN_ENCRYPTION_KEY = MyCEK) NOT NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[BirthDate] [date]
ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED,
ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256',
COLUMN_ENCRYPTION_KEY = MyCEK) NOT NULL
PRIMARY KEY CLUSTERED ([PatientId] ASC) ON [PRIMARY]);
GO

For each Java code example, you'll need to insert keystore-specific code in the location noted.
To use an Azure Key Vault keystore provider:

String clientID = "<Azure Application ID>";


String clientKey = "<Azure Application API Key Password>";
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider = new
SQLServerColumnEncryptionAzureKeyVaultProvider(clientID, clientKey);
Map<String, SQLServerColumnEncryptionKeyStoreProvider> keyStoreMap = new HashMap<String,
SQLServerColumnEncryptionKeyStoreProvider>();
keyStoreMap.put(akvProvider.getName(), akvProvider);
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(keyStoreMap);
String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<databaseName>;user=
<user>;password=<password>;columnEncryptionSetting=Enabled;";

To use a Windows Certificate Store keystore provider:

String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<databaseName>;user=


<user>;password=<password>;columnEncryptionSetting=Enabled;";

To use a Java Key Store keystore provider:

String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<databaseName>;user=


<user>;password=
<password>;columnEncryptionSetting=Enabled;keyStoreAuthentication=JavaKeyStorePassword;keyStoreLocation=
<path to jks or pfx file>;keyStoreSecret=<keystore secret/password>";

Inserting data example


This example inserts a row into the Patients table. Note the following items:
There's nothing specific to encryption in the sample code. The Microsoft JDBC Driver for SQL Server
automatically detects and encrypts the parameters that target encrypted columns. This behavior makes
encryption transparent to the application.
The values inserted into database columns, including the encrypted columns, are passed as parameters with
SQLServerPreparedStatement . While parameters are optional when sending values to non-encrypted columns
(although, it's highly recommended because it helps prevent SQL injection), it's required for values that
target encrypted columns. If the values inserted into the encrypted columns were passed as literals
embedded in the query statement, the query would fail because the driver wouldn't be able to determine the
values in the target encrypted columns and it wouldn't encrypt the values. As a result, the server would reject
them as incompatible with the encrypted columns.
All values printed by the program will be in plaintext, as the Microsoft JDBC Driver for SQL Server will
transparently decrypt the data retrieved from the encrypted columns.
If you're doing a lookup with a WHERE clause, the value that's used in the WHERE clause needs to be passed
as a parameter so that the driver can transparently encrypt it before sending it to the database. In the
following example, the SSN is passed as a parameter but the LastName is passed as a literal as LastName
isn't encrypted.
The setter method used for the parameter targeting the SSN column is setString() , which maps to the
char / varchar SQL Server data type. If for this parameter, the setter method used was setNString() , which
maps to nchar / nvarchar , the query would fail, as Always Encrypted doesn't support conversions from
encrypted nchar / nvarchar values to encrypted char / varchar values.

// <Insert keystore-specific code here>


try (Connection sourceConnection = DriverManager.getConnection(connectionUrl);
PreparedStatement insertStatement = sourceConnection.prepareStatement("INSERT INTO [dbo].[Patients]
VALUES (?, ?, ?, ?)")) {
insertStatement.setString(1, "795-73-9838");
insertStatement.setString(2, "Catherine");
insertStatement.setString(3, "Abel");
insertStatement.setDate(4, Date.valueOf("1996-09-10"));
insertStatement.executeUpdate();
System.out.println("1 record inserted.\n");
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}

Retrieving plaintext data example


The following example demonstrates filtering data based on encrypted values and retrieving plaintext data from
encrypted columns. Note the following items:
The value that's used in the WHERE clause to filter on the SSN column needs to be passed as a parameter so
that the Microsoft JDBC Driver for SQL Server can transparently encrypt it before sending it to the database.
All values printed by the program will be in plaintext, as the Microsoft JDBC Driver for SQL Server will
transparently decrypt the data retrieved from the SSN and BirthDate columns.

NOTE
if columns are encrypted with deterministic encryption, queries can perform equality comparisons on them. For more
information, see Selecting Deterministic or Randomized encryption in Always Encrypted (Database Engine).
// <Insert keystore-specific code here>
try (Connection connection = DriverManager.getConnection(connectionUrl);
PreparedStatement selectStatement = connection
.prepareStatement("\"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].
[Patients] WHERE SSN = ?;\"");) {
selectStatement.setString(1, "795-73-9838");
ResultSet rs = selectStatement.executeQuery();
while (rs.next()) {
System.out.println("SSN: " + rs.getString("SSN") + ", FirstName: " + rs.getString("FirstName") + ",
LastName:"
+ rs.getString("LastName") + ", Date of Birth: " + rs.getString("BirthDate"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}

Retrieving encrypted data example


If Always Encrypted isn't enabled, a query can still retrieve data from encrypted columns, as long as the query
has no parameters targeting encrypted columns.
The following example illustrates retrieving binary encrypted data from encrypted columns. Note the following
items:
Since Always Encrypted isn't enabled in the connection string, the query will return encrypted values of SSN
and BirthDate as byte arrays (the program converts the values to strings).
A query retrieving data from encrypted columns with Always Encrypted disabled can have parameters, as
long as none of the parameters target an encrypted column. The following query filters by LastName, which
isn't encrypted in the database. If the query filtered by SSN or BirthDate, the query would fail.

try (Connection sourceConnection = DriverManager.getConnection(connectionUrl);


PreparedStatement selectStatement = sourceConnection
.prepareStatement("SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients]
WHERE LastName = ?;");) {

selectStatement.setString(1, "Abel");
ResultSet rs = selectStatement.executeQuery();
while (rs.next()) {
System.out.println("SSN: " + rs.getString("SSN") + ", FirstName: " + rs.getString("FirstName") + ",
LastName:"
+ rs.getString("LastName") + ", Date of Birth: " + rs.getString("BirthDate"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}

Avoiding common problems when querying encrypted columns


This section describes common categories of errors when querying encrypted columns from Java applications
and a few guidelines on how to avoid them.
Unsupported data type conversion errors
Always Encrypted supports few conversions for encrypted data types. See Always Encrypted (Database Engine)
for the detailed list of supported type conversions. Here's what you can do to avoid data type conversion errors.
Make sure that:
you use the proper setter methods when passing values for parameters that target encrypted columns.
Ensure that the SQL Server data type of the parameter is exactly the same as the type of the target column or
a conversion of the SQL Server data type of the parameter to the target type of the column is supported. API
methods have been added to the SQLServerPreparedStatement , SQLServerCallableStatement , and
SQLServerResultSet classes to pass parameters corresponding to specific SQL Server data types. For a
complete list of new APIs, see Always Encrypted API Reference for the JDBC Driver. The following are some
examples of adjustments that may be needed when using Always Encrypted:
You can use the setTimestamp() method to pass a parameter to a non-encrypted datetime2 or
datetime column. But when a column is encrypted you have to use the exact method representing the
type of the column in the database. Use setTimestamp() to pass values to an encrypted datetime2
column and use setDateTime() to pass values to an encrypted datetime column.
You can use the setBinary() method to pass a parameter to a non-encrypted varbinary(max) or
binary column. The driver defaults to the BINARY data type for setBinary() parameters and the
server can implicitly convert the data to insert into a varbinary(max) column. But when a
varbinary(max) column is encrypted you have to specify a more exact type for the parameter data.
Example: preparedStatement.setObject(1, binaryData, java.sql.JDBCType.LONGVARBINARY)
the precision and scale of parameters targeting columns of the decimal and numeric SQL Server data types
is the same as the precision and scale configured for the target column. API methods have been added to the
SQLServerPreparedStatement , SQLServerCallableStatement , and SQLServerResultSet classes to accept
precision and scale along with data values for parameters/columns representing decimal and numeric data
types. See Always Encrypted API Reference for the JDBC Driver for a complete list of new/overloaded APIs.
the fractional seconds precision/scale of parameters targeting columns of datetime2 , datetimeoffset , or
time SQL Server data types isn't greater than the fractional seconds precision/scale for the target column in
queries that modify values of the target column. API methods have been added to the
SQLServerPreparedStatement , SQLServerCallableStatement , and SQLServerResultSet classes to accept
fractional seconds precision/scale along with data values for parameters representing these data types. For a
complete list of new/overloaded APIs, see Always Encrypted API Reference for the JDBC Driver.
Errors due to incorrect connection properties
This section describes how to configure connection settings properly to use Always Encrypted data. Since
encrypted data types support limited conversions, the sendTimeAsDatetime and sendStringParametersAsUnicode
connection settings need proper configuration to use encrypted columns. Make sure that:
sendTimeAsDatetime connection setting is set to false when inserting data into encrypted time columns. For
more information, see Configuring how java.sql.Time Values are sent to the server.
sendStringParametersAsUnicode connection setting is set to true (or is left as the default) when inserting
data into encrypted char/varchar/varchar(max) columns.
Errors due to passing plaintext instead of encrypted values
Any value that targets an encrypted column needs to be encrypted inside the application. An attempt to
insert/modify or to filter by a plaintext value on an encrypted column will result in an error similar to this one:

com.microsoft.sqlserver.jdbc.SQLServerException: Operand type clash: varchar is incompatible with


varchar(8000) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name =
'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'MyCEK', column_encryption_key_database_name =
'ae') collation_name = 'SQL_Latin1_General_CP1_CI_AS'

To prevent such errors, make sure:


Always Encrypted is enabled for application queries targeting encrypted columns (for the connection string
or for a specific query).
you use prepared statements and parameters to send data targeting encrypted columns. The following
example shows a query that incorrectly filters by a literal/constant on an encrypted column (SSN), instead of
passing the literal inside as a parameter. This query will fail:

ResultSet rs = connection.createStatement().executeQuery("SELECT * FROM Customers WHERE SSN='795-73-9838'");

Force encryption on input parameters


The Force Encryption feature enforces encryption of a parameter with Always Encrypted. If force encryption is
used and SQL Server informs the driver that the parameter doesn't need to be encrypted, the query that uses
the parameter will fail. This property provides added protection against security attacks that involve a
compromised SQL Server providing incorrect encryption metadata to the client, which may lead to data
disclosure. The set* methods in the SQLServerPreparedStatement and SQLServerCallableStatement classes and the
update* methods in the SQLServerResultSet class are overloaded to accept a boolean argument to specify the
force encryption setting. If the value of this argument is false, the driver won't force encryption on parameters. If
force encryption is set to true, the query parameter is only sent if the destination column is encrypted and
Always Encrypted is enabled on the connection or on the statement. This property gives an extra layer of
security, ensuring that the driver doesn't mistakenly send data to SQL Server as plaintext when it's expected to
be encrypted.
For more information on the SQLServerPreparedStatement and SQLServerCallableStatement methods that are
overloaded with the force encryption setting, see Always Encrypted API Reference for the JDBC Driver

Controlling the performance impact of Always Encrypted


Because Always Encrypted is a client-side encryption technology, most of the performance overhead is observed
on the client side, not in the database. Apart from the cost of encryption and decryption operations, other
sources of performance overheads on the client side are:
Added round trips to the database to retrieve metadata for query parameters.
Calls to a column master key store to access a column master key.
This section describes the built-in performance optimizations in the Microsoft JDBC Driver for SQL Server and
how you can control the impact of the above two factors on performance.
Controlling round trips to retrieve metadata for query parameters
If Always Encrypted is enabled for a connection, by default the driver will call
sys.sp_describe_parameter_encryption for each parameterized query, passing the query statement (without any
parameter values) to the database. sys.sp_describe_parameter_encryption analyzes the query statement to find
out if any parameters need to be encrypted, and if so, for each one it returns the encryption-related information
that allows the driver to encrypt parameter values. This behavior ensures a high level of transparency to the
client application. As long as the application uses parameters to pass values that target encrypted columns to
the driver, the application (and the application developer) doesn't need to know which queries access encrypted
columns.
Setting Always Encrypted at the query level
To control the performance impact of retrieving encryption metadata for parameterized queries, you can enable
Always Encrypted for individual queries instead of setting it up for the connection. This way you can ensure that
sys.sp_describe_parameter_encryption is invoked only for queries that you know have parameters targeting
encrypted columns. Note, however, that by doing so you reduce the transparency of encryption: if you change
encryption properties of your database columns, you may need to change the code of your application to align
it with the schema changes.
To control the Always Encrypted behavior of individual queries, you need to configure individual statement
objects by passing an Enum, SQLServerStatementColumnEncryptionSetting, which specifies how data will be
sent and received when reading and writing encrypted columns for that specific statement. Here are some
useful guidelines:
If most queries a client application sends over a database connection access encrypted columns, use
these guidelines:
Set the columnEncryptionSetting connection string keyword to Enabled .
Set SQLServerStatementColumnEncryptionSetting.Disabled for individual queries that don't access any
encrypted columns. This setting will disable both calling sys.sp_describe_parameter_encryption and
decrypting any values in the result set.
Set SQLServerStatementColumnEncryptionSetting.ResultSet for individual queries that don't have any
parameters requiring encryption but retrieve data from encrypted columns. This setting will disable
calling sys.sp_describe_parameter_encryption and parameter encryption. The query will decrypt the
results from encryption columns.
If most queries a client application sends over a database connection don't access encrypted columns, use
these guidelines:
Set the columnEncryptionSetting connection string keyword to Disabled .
Set SQLServerStatementColumnEncryptionSetting.Enabled for individual queries that have any
parameters that need to be encrypted. This setting will enable both calling
sys.sp_describe_parameter_encryption and decrypting of any query results retrieved from encrypted
columns.
Set SQLServerStatementColumnEncryptionSetting.ResultSet for queries that don't have any parameters
requiring encryption but retrieve data from encrypted columns. This setting will disable calling
sys.sp_describe_parameter_encryption and parameter encryption. The query will decrypt the results
from encryption columns.
The SQLServerStatementColumnEncryptionSetting settings can't be used to bypass encryption and gain access to
plaintext data. For more information on how to configure column encryption on a statement, see Always
Encrypted API Reference for the JDBC Driver.
In the following example, Always Encrypted is disabled for the database connection. The query the application
issues has a parameter that targets the LastName column that isn't encrypted. The query retrieves data from the
SSN and BirthDate columns that are both encrypted. In such a case, calling
sys.sp_describe_parameter_encryption to retrieve encryption metadata isn't required. However, the decryption of
the query results needs to be enabled so that the application can receive plaintext values from the two
encrypted columns. The SQLServerStatementColumnEncryptionSetting.ResultSet setting is used to ensure that.
// Assumes the same table definition as in Section "Retrieving and modifying data in encrypted columns"
// where only SSN and BirthDate columns are encrypted in the database.
String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<database>;user=<user>;password=
<password>;"
+ "keyStoreAuthentication=JavaKeyStorePassword;"
+ "keyStoreLocation=<keyStoreLocation>"
+ "keyStoreSecret=<keyStoreSecret>;";

String filterRecord = "SELECT FirstName, LastName, SSN, BirthDate FROM " + tableName + " WHERE LastName =
?";

try (SQLServerConnection connection = (SQLServerConnection) DriverManager.getConnection(connectionUrl);


PreparedStatement selectStatement = connection.prepareStatement(filterRecord,
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
connection.getHoldability(), SQLServerStatementColumnEncryptionSetting.ResultSetOnly);) {

selectStatement.setString(1, "Abel");
ResultSet rs = selectStatement.executeQuery();
while (rs.next()) {
System.out.println("First name: " + rs.getString("FirstName"));
System.out.println("Last name: " + rs.getString("LastName"));
System.out.println("SSN: " + rs.getString("SSN"));
System.out.println("Date of Birth: " + rs.getDate("BirthDate"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}

Column encryption key caching


To reduce the number of calls to a column master key store to decrypt column encryption keys, the Microsoft
JDBC Driver for SQL Server caches the plaintext column encryption keys in memory. After the driver receives
the encrypted column encryption key value from the database metadata, the driver first tries to find the
plaintext column encryption key corresponding to the encrypted key value. The driver calls the keystore
containing the column master key only if it can't find the encrypted column encryption key value in the cache.
You can configure a time-to-live value for the column encryption key entries in the cache with the API,
setColumnEncryptionKeyCacheTtl() , in the SQLServerConnection class. The default time-to-live value for the
column encryption key entries in the cache is two hours. To turn off caching, use a value of 0. To set any time-to-
live value, use the following API:

SQLServerConnection.setColumnEncryptionKeyCacheTtl (int columnEncryptionKeyCacheTTL, TimeUnit unit)

For example, to set a time-to-live value of 10 minutes, use:

SQLServerConnection.setColumnEncryptionKeyCacheTtl (10, TimeUnit.MINUTES)

Only DAYS, HOURS, MINUTES, or SECONDS are supported as the time unit.

Copying encrypted data with SQLServerBulkCopy


With SQLServerBulkCopy , you can copy data that is already encrypted and stored in one table to another table
without decrypting the data. To do that:
Make sure the encryption configuration of the target table is identical to the configuration of the source
table. In particular, both tables must have the same columns encrypted and the columns must be encrypted
using the same encryption types and the same encryption keys. If any target column is encrypted differently
than its corresponding source column, you won't be able to decrypt the data in the target table after the copy
operation. The data will be corrupted.
Configure both database connections to the source table and to the target table without Always Encrypted
enabled.
Set the allowEncryptedValueModifications option. For more information, see Using bulk copy with the JDBC
driver.

NOTE
Use caution when specifying AllowEncryptedValueModifications as this option may lead to corrupting the database
because the Microsoft JDBC Driver for SQL Server does not check if the data is indeed encrypted or if it is correctly
encrypted with the same encryption type, algorithm, and key as the target column.

See also
Always Encrypted (Database Engine)
Using Always Encrypted with secure enclaves with
the JDBC driver
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


This page provides information on how to develop Java applications using Always Encrypted with secure
enclaves and the Microsoft JDBC Driver 8.2 (or higher) for SQL Server.
The secure enclaves feature is an addition to the existing Always Encrypted feature. The purpose of secure
enclaves is to address limitations when working with Always Encrypted data. Previously, users could only do
equality comparisons on Always Encrypted data, and had to retrieve and decrypt the data to do other
operations. Secure enclaves address this limitation by allowing computations on plaintext data inside a secure
enclave on the server side. A secure enclave is a protected region of memory within the SQL Server process. It
acts as a trusted execution environment for processing sensitive data inside the SQL Server engine. A secure
enclave appears as a black box to the rest of the SQL Server and other processes on the hosting machine.
There's no way to view any data or code inside the enclave from the outside, even with a debugger.

Prerequisites
Make sure Microsoft JDBC Driver 8.2 (or higher) for SQL Server is installed on your development machine.
Verify environment dependencies such as DLLs, KeyStores, and so on, are in the correct paths. Always
Encrypted with secure enclaves is an add-on to the existing Always Encrypted feature and share similar
prerequisites.

NOTE
If you are using an older version of JDK 8, you may need to download and install the Java Cryptography Extension (JCE)
Unlimited Strength Jurisdiction Policy Files. Be sure to read the Readme included in the zip file for installation instructions
and relevant details on possible export/import issues.
The policy files can be downloaded from Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 8
Download

Setting up secure enclaves


Follow Tutorial: Getting started with Always Encrypted with secure enclaves in SQL Server or Tutorial: Getting
started with Always Encrypted with secure enclaves in Azure SQL Database to get started with secure enclaves.
For more in-depth information, refer to Always encrypted with secure enclaves.

Connection String properties


To enable enclave computations for a database connection, you need to set the following connection string
keywords, in addition to enabling Always Encrypted.
enclaveAttestationProtocol - specifies an attestation protocol.
If you're using SQL Server and Host Guardian Service (HGS), the value of this keyword should be HGS
.
If you're using Azure SQL Database and Microsoft Azure Attestation, the value of this keyword should
be AAS .
enclaveAttestationUrl: - specifies an attestation URL (an attestation service endpoint). You need to
obtain an attestation URL for your environment from your attestation service administrator.
If you're using SQL Server and Host Guardian Service (HGS), see Determine and share the HGS
attestation URL.
If you're using Azure SQL Database and Microsoft Azure Attestation, see Determine the attestation
URL for your attestation policy.
Users must enable columnEncr yptionSetting and correctly set both of the above connection string
properties to enable Always Encrypted with secure enclaves from the Microsoft JDBC Driver for SQL Server.

Working with secure enclaves


When the enclave connection properties are set properly, the feature will work transparently. The driver will
determine whether the query requires the use of a secure enclave automatically. The following are examples of
queries that trigger enclave computations. You can find the database and table setup in Tutorial: Getting started
with Always Encrypted with secure enclaves in SQL Server or Tutorial: Getting started with Always Encrypted
with secure enclaves in Azure SQL Database.
Rich queries will trigger enclave computations:

private static final String URL = "jdbc:sqlserver://<server>:<port>;user=<username>;password=


<password>;databaseName=ContosoHR;columnEncryptionSetting=enabled;enclaveAttestationUrl=<attestation-
url>;enclaveAttestationProtocol=<attestation-protocol>;";
try (Connection c = DriverManager.getConnection(URL)) {
try (PreparedStatement p = c.prepareStatement("SELECT * FROM Employees WHERE SSN LIKE ?")) {
p.setString(1, "%6818");
try (ResultSet rs = p.executeQuery()) {
while (rs.next()) {
// Do work with data
}
}
}

try (PreparedStatement p = c.prepareStatement("SELECT * FROM Employees WHERE SALARY > ?")) {


((SQLServerPreparedStatement) p).setMoney(1, new BigDecimal(0));
try (ResultSet rs = p.executeQuery()) {
while (rs.next()) {
// Do work with data
}
}
}
}

Toggling encryption on a column will also trigger enclave computations:

private static final String URL = "jdbc:sqlserver://<server>:<port>;user=<username>;password=


<password>;databaseName=ContosoHR;columnEncryptionSetting=enabled;enclaveAttestationUrl=<attestation-
url>;enclaveAttestationProtocol=<attestation-protocol>;";
try (Connection c = DriverManager.getConnection(URL);Statement s = c.createStatement()) {
s.executeUpdate("ALTER TABLE Employees ALTER COLUMN SSN CHAR(11) NULL WITH (ONLINE = ON)");
}

Java 8 users
This feature requires the RSASSA-PSA signature algorithm. This algorithm was added in JDK 11, but not back-
ported to JDK 8. Users who wish to use this feature with the JDK 8 version of the Microsoft JDBC Driver for SQL
Server must either load their own provider, which supports the RSASSA-PSA signature algorithm, or include the
BouncyCastleProvider optional dependency. The dependency will be removed at a later date if JDK 8 back ports
the signature algorithm or if the support lifecycle of JDK 8 ends.

See also
Using Always Encrypted with the JDBC driver
Setting the data source properties
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Data sources are the preferred mechanism by which to create JDBC connections in a Java Platform, Enterprise
Edition (Java EE) environment. Data sources provide connections, pooled connections, and distributed
connections without hard-coding connection properties into Java code. All Microsoft JDBC Driver for SQL
Server data sources can set or get the value of any property by using the appropriate setter and getter methods,
respectively.
Java EE products, such as application servers and servlet/JSP engines, typically let you configure data sources
for database access. Any property listed in the Setting the Connection Properties topic can be specified
wherever the configuration lets you enter a property as a property=value pair.
For more information about SQL Server data sources, see the SQLServerDataSource class. For an example of
how to use the SQLServerDataSource class to make a connection to a SQL Server database, see Data source
sample.

See also
Connecting to SQL Server with the JDBC driver
Setting the connection properties
4/27/2022 • 25 minutes to read • Edit Online

Download JDBC Driver


The connection string properties can be specified in various ways:
As name=value properties in the connection URL when you connect by using the DriverManager class.
For connection string syntax, see Building the connection URL.
As name=value properties in the Properties parameter of the Connect method in the DriverManager
class.
As values in the appropriate setter method of the data source of the driver. For example:

datasource.setServerName(value)
datasource.setDatabaseName(value)

Remarks
Property names are case-insensitive, and duplicate property names are resolved in the following order:
1. API arguments (such as user and password)
2. Property collection
3. Last instance in the connection string
Unknown values are allowed for the property names, and aren't validated by the JDBC driver for case sensitivity.
Synonyms are allowed and are resolved in order, just as duplicate property names.

Properties
The following table lists all the currently available connection string properties for the JDBC driver.

P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

accessToken (Version 6.0+) Use this property to connect to a database


using an access token. accessToken can't be set using the
String connection URL.

null

applicationIntent (Version 6.0+) Declares the application workload type to


connect to a server.
String
Possible values are ReadOnly and ReadWrite .
ReadWrite
For more information about disaster recovery, see JDBC
driver support for High Availability, disaster recovery.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

applicationName The application name, or "Microsoft JDBC Driver for SQL


Server" if no name is provided.
String
[<=128 char] Used to identify the specific application in various SQL
Server profiling and logging tools.
null
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

authentication (Version 6.0+) This optional property indicates which


authentication method to use for connection. Possible values
String are ActiveDirector yIntegrated ,
ActiveDirector yPassword , ActiveDirector yMSI (version
NotSpecified 7.2+), ActiveDirector yInteractive (version 9.2+),
ActiveDirector ySer vicePrincipal (version 9.2+),
SqlPassword , and the default NotSpecified .

Use ActiveDirector yIntegrated (version 6.0+) to connect


to an SQL database using integrated Windows
authentication.

Use ActiveDirector yPassword (version 6.0+) to connect


to an SQL database using an Azure AD principal name and
password.

Use ActiveDirector yMSI (version 7.2+) to connect to an


SQL database from inside an Azure Resource. For example,
an Azure Virtual Machine, App Service or Function App
using Managed Identity (MSI) authentication.

The two types of Managed Identities supported by the


driver when using ActiveDirector yMSI authentication
mode are:
1. System-Assigned Managed Identity: Used to acquire
accessToken by default.
2. User-Assigned Managed Identity: Used to acquire
accessToken if the Client ID of a Managed Identity (MSI) is
specified with the msiClientId connection property.

Use ActiveDirector yInteractive to connect to an SQL


database using an interactive authentication flow.

Use ActiveDirector ySer vicePrincipal (version 9.2+) to


connect to an SQL database using the client ID and secret of
a service principal identity. Specify client ID in the userName
property and secret in the password property (10.2+).

Use SqlPassword to connect to an SQL database using


userName /user and password properties.

Use NotSpecified if none of these authentication methods


are needed.

Impor tant: If authentication is set to


ActiveDirectoryIntegrated, the following two libraries must
be installed: mssql-jdbc_auth-<version>-<arch>.dll
(available in the JDBC driver package) and Microsoft
Authentication Library for SQL Server (ADAL.DLL ).
Microsoft Authentication Library can be installed from
Microsoft ODBC Driver for SQL Server or Microsoft OLE DB
Driver for SQL Server. The JDBC driver only supports version
1.0.2028.318 and higher for ADAL.DLL.

Note: When the authentication property is set to any value


other than NotSpecified , the driver by default uses
Transport Layer Security (TLS), previously known as Secure
Sockets Layer (SSL), encryption.

For information on how to configure Azure Active Directory


authentication, see Connecting to SQL Database By Using
P RO P ERT Y
TYPE Azure Active Directory Authentication.
DEFA ULT DESC RIP T IO N
authenticationScheme Indicates which kind of integrated security you want your
application to use. Possible values are JavaKerberos , NTLM
String (version 7.4+), and the default NativeAuthentication .

NativeAuthentication NativeAuthentication causes the driver to load


mssql-jdbc_auth-<version>-<arch>.dll (for example,
mssql-jdbc_auth-8.2.2.x64.dll ) on Windows, which is
used to obtain integrated authentication information.

(The native authentication library loaded is named


sqljdbc_auth.dll when using driver versions 6.0 through
7.4.)

When using authenticationScheme=JavaKerberos , you


must specify the fully qualified domain name (FQDN) in the
ser verName or ser verSpn property. Otherwise, an error
occurs (Server not found in Kerberos database).

For more information about using


authenticationScheme=JavaKerberos , see Using
Kerberos integrated authentication to connect to SQL
Server.

When using authenticationScheme=NTLM , you must


specify the Windows domain by using the domain or
domainName property, the Windows credentials in the
user or userName property, and the password property.
Otherwise, an error occurs (connection properties must be
specified).

cancelQueryTimeout (Version 6.4+) This property can be used to cancel a


quer yTimeout set on the connection. Query execution
int hangs and doesn't throw an exception if the TCP connection
to the server is silently dropped. This property is only
-1 applicable if 'queryTimeout' is also set on the connection.

The driver waits the total amount of cancelQuer yTimeout


+ quer yTimeout seconds, to drop the connection and
close the channel.

The default value for this property is -1 and behavior is to


wait indefinitely.

clientCertificate (Version 8.4+) Specifies the location of the certificate to be


used for client certificate authentication. The JDBC driver
String supports PFX, PEM, DER, and CER file extensions.

null For details, see Client Certificate Authentication for


Loopback Scenarios.

clientKey (Version 8.4+) Specifies the location of the private key for
PEM, DER, and CER certificates specified by the
String clientCertificate attribute.

null For details, see Client Certificate Authentication for


Loopback Scenarios.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

clientKeyPassword (Version 8.4+) Specifies the optional password string for


accessing the clientKey file's private key.
String
For details, see Client Certificate Authentication for
null Loopback Scenarios.

columnEncryptionSetting (Version 6.0+) Set to "Enabled" to use the Always Encrypted


(AE) feature. When AE is enabled, the JDBC driver
String transparently encrypts and decrypts sensitive data stored in
["Enabled" | "Disabled"] encrypted database columns on the server.

Disabled For more information about Always Encrypted, see Using


Always Encrypted with the JDBC driver.

Note: Always Encrypted is available with SQL Server 2016


or later and Azure SQL Database.

connectRetryCount (Version 9.4+) The number of reconnection attempts if


there's a connection failure.
int
[0..255]

connectRetryInterval (Version 9.4+) The number of seconds between each


connection retry attempt.
int
[1..60]

10

databaseName, The name of the database to connect to.


database
If not stated, a connection is made to the default database.
String
[<=128 char]

null

delayLoadingLobs Flag to indicate whether to stream or not stream all the LOB
objects being retrieved from the ResultSet. Setting this
boolean property to "false" loads the entire LOB object into memory
["true" | "false"] without streaming.

true

domainName, (Version 7.4+) The Windows domain to authenticate to


domain when using NTLM authentication.

String
null
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

disableStatementPooling Flag indicates if statement pooling should be used.

boolean
["true" | "false"]

true

enablePrepareOnFirst... Set to "true" to enable prepared statement handle creation


PreparedStatementCall by calling sp_prepexec with the first execution of a
prepared statement.
boolean
["true" | "false"] Set to "false" to change the first execution of a prepared
statement to call sp_executesql and not prepare a
false statement. If a second execution happens, it calls
sp_prepexec to set up a prepared statement handle.

enclaveAttestationUrl (Version 8.2+) This optional property indicates the


attestation service endpoint URL to use for Always
String Encrypted with secure enclaves.

null For more information about Always Encrypted with secure


enclaves, see Always Encrypted with secure enclaves.

enclaveAttestationProtocol (Version 8.2+) This optional property indicates the


attestation protocol to use for Always Encrypted with secure
String enclaves. Currently, the only supported value for this field is
HGS.
null
For more information about Always Encrypted with secure
enclaves, see Always Encrypted with secure enclaves.

encrypt Set to "true" to specify that the SQL Server uses TLS
encryption for all the data sent between the client and the
boolean server if the server has a certificate installed. The default
["true" | "false"] value is "true" in version 10.2 and up and "false" in 9.4 and
below.
true
In version 6.0 and up, there is a new connection setting
'authentication' that uses TLS encryption by default.

For more information about this property, see the


'authentication' property.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

failoverPartner The name of the failover server used in a database mirroring


configuration. This property is used for an initial connection
String failure to the principal server. After you make the initial
connection, this property is ignored. Must be used with the
null databaseName property.

Note: The driver doesn't support the server instance port


number for the failover partner instance as part of the
failoverPartner property in the connection string. However,
specifying the serverName, instanceName, and portNumber
properties of the principal server instance and
failoverPartner property of the failover partner instance in
the same connection string is supported.

If you specify a Virtual Network Name in the Ser ver


connection property, you can't use database mirroring. For
more information about disaster recovery, see JDBC driver
support for High Availability, disaster recovery

fips For FIPS enabled Java Virtual Machine (JVM) this property
should be true .
boolean
["true" | "false"]

"false"

fipsProvider FIPS provider configured in JVM. For example, BCFIPS or


SunPKCS11-NSS. Removed in version 6.4.0 -- see the details
String Here.

null

gsscredential (Version 6.2+) User credentials to be used for Kerberos


Constrained Delegation can be passed in this property.
org.ietf.jgss.GSSCredential
This should be used with integratedSecurity as true and
null JavaKerberos as authenticationScheme .

hostNameInCertificate The host name to be used to validate the SQL Server


TLS/SSL certificate.
String
If the hostNameInCertificate property is unspecified or set to
null null, the Microsoft JDBC Driver for SQL Server uses the
ser verName property value on the connection URL as the
host name to validate the SQL Server TLS/SSL certificate.

Note: This property is used in combination with the


encr ypt /authentication properties and the
trustSer verCer tificate property. This property affects the
certificate validation, if the connection uses TLS encryption
and the trustSer verCer tificate is set to "false". Make sure
the value passed to hostNameInCer tificate matches the
Common Name (CN) or DNS name in the Subject Alternate
Name (SAN) in the server certificate for a TLS connection to
succeed. For more information about encryption support,
see Understanding encryption support.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

instanceName The database instance name to connect to. When it isn't


specified, a connection is made to the default instance. For
String the case where both the instanceName and port are
[<=128 char] specified, see the notes for port.

null If you specify a Virtual Network Name in the Ser ver


connection property, you can't use the instanceName
connection property. For more information about disaster
recovery, see JDBC Driver Support for High Availability,
Disaster Recovery.

integratedSecurity Set to "true" to indicate that Windows credentials are used


by SQL Server on Windows operating systems. If "true", the
boolean JDBC driver searches the local computer credential cache for
["true"|"false"] credentials that were provided when a user signed in to the
computer or network.
false
Set to "true" (with
authenticationscheme=JavaKerberos ), to indicate that
Kerberos credentials are used by SQL Server. For more
information about Kerberos authentication, see Using
Kerberos integrated authentication to connect to SQL
Server.

Set to "true" (with authenticationscheme=NTLM ), to


indicate that NTLM credentials are used by SQL Server.

If "false", the username and password must be supplied.

jaasConfigurationName (Version 6.2+) Each connection to SQL Server can have its
own JAAS Login Configuration file to establish a Kerberos
String connection. The name of the JAAS Login Configuration file
can be passed through this property.
SQLJDBCDriver By default, the driver sets useDefaultCcache = true for
IBM JVMs, and useTicketCache = true for other JVMs.

keyStoreAuthentication (Version 6.0+) This property identifies which key store to use
with Always Encrypted and determines an authentication
String mechanism used to authenticate to the key store. The driver
supports setting up of the Java Key Store seamlessly when
null you set
"keyStoreAuthentication=JavaKeyStorePassword ". To
use this property, you also must set the keyStoreLocation
and keyStoreSecret properties for the Java Key Store.

For more information about Always Encrypted, see Using


Always Encrypted with the JDBC driver.

Beginning with Microsoft JDBC Driver 8.4, you can set


"keyStoreAuthentication=KeyVaultManagedIdentity "
or "keyStoreAuthentication=KeyVaultClientSecret " to
authenticate to Azure Key Vault using Managed Identities.

For more information about Always Encrypted, see Using


Always Encrypted with the JDBC driver.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

keyStoreLocation (Version 6.0+) When


keyStoreAuthentication=JavaKeyStorePassword , the
String keyStoreLocation property identifies the path to the Java
keystore file that stores the Column Master Key to be used
null with Always Encrypted data. The path must include the
keystore filename.

For more information about Always Encrypted, see Using


Always Encrypted with the JDBC driver.

keyStorePrincipalId (Version 8.4+) When


keyStoreAuthentication=KeyVaultManagedIdentity ,
String the keyStorePrincipalId property specifies a valid Azure
Active Directory application client ID.
null
For more information about Always Encrypted, see Using
Always Encrypted with the JDBC driver.

keyStoreSecret (Version 6.0+) When


keyStoreAuthentication=JavaKeyStorePassword , the
String keyStoreSecret property identifies the password to use for
the keystore and the key. For using the Java Key Store, the
null keystore and the key password must be the same.

For more information about Always Encrypted, see Using


Always Encrypted with the JDBC driver.

lastUpdateCount A "true" value only returns the last update count from an
SQL statement passed to the server, and it can be used on
boolean single SELECT, INSERT, or DELETE statements to ignore other
["true" | "false"] update count caused by server triggers. Setting this
property to "false" causes all update counts to be returned,
true including this update counts returned by server triggers.

Note: This property only applies when it's used with the
executeUpdate methods. All other execute methods return
all results and update counts. This property only affects
update counts returned by server triggers. It doesn't affect
result sets or errors that result as part of trigger execution.

lockTimeout The number of milliseconds to wait before the database


reports a lock time-out. The default behavior is to wait
int indefinitely. If it's specified, this value is the default for all
statements on the connection.
-1 Statement.setQuer yTimeout() can be used to set the
time-out for specific statements. The value can be 0, which
specifies no wait.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

loginTimeout The number of seconds the driver should wait before timing
out a failed connection. A zero value indicates that the
int timeout is the default system timeout, which is specified as
[0..65535] 15 seconds by default. A non-zero value is the number of
seconds the driver should wait before timing out a failed
15 connection.

If you specify a Virtual Network Name in the Ser ver


connection property, you should specify a timeout value of
three minutes or more to allow sufficient time for a failover
connection to succeed. For more information about disaster
recovery, see JDBC driver support for High Availability,
disaster recovery.

maxResultBuffer (Version 9.2+) maxResultBuffer can be used to set the


maximum bytes to read when reading a result set. If not
String specified, then the entire result set is read. Size can be
specified in two styles:
null 1. as size of bytes (for example, 100, 150M, 300K, 400G)
2. as a percent of maximum heap memory (for example, 10p,
15pct, 20percent).

msiClientId (Version 7.2+) The Client ID of the Managed Identity (MSI)


used to acquire an accessToken to establish a connection
String with the ActiveDirector yMSI authentication mode.

null

multiSubnetFailover Always specify multiSubnetFailover=true to connect to


the availability group listener of a SQL Server availability
Boolean group or an SQL Server Failover Cluster Instance.
multiSubnetFailover=true configures the driver to
false provide faster detection of and connection to the (currently)
active server. Possible values are true and false. For more
information about disaster recovery, see JDBC Driver
Support for High Availability, Disaster Recovery.

You can programmatically access the multiSubnetFailover


connection property with getPropertyInfo,
getMultiSubnetFailover, and setMultiSubnetFailover.

Note: Beginning with Microsoft JDBC Driver 6.0 for SQL


Server, it's no longer required to set multiSubnetFailover
to "true" to connect to an availability group listener. A new
property, transparentNetworkIPResolution , which is
enabled by default, provides the detection of and connection
to the (currently) active server.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

packetSize The network packet size used to communicate with the


server, specified in bytes. A value of -1 indicates to use the
int server's default packet size. A value of 0 indicates to use the
[-1 | 0 | 512..32767] maximum value of 32767. If this property is set to a value
outside the acceptable range, an exception occurs.
8000
Impor tant: Using the packetSize property when the
encryption is enabled (encrypt=true) is not recommended.
Otherwise, the driver might raise a connection error. For
more information about this property, see the setPacketSize
method of the SQLServerDataSource class.

password The database password, if connection with SQL user and


password.
String For Kerberos connection with principal name and password,
[<=128 char] this property is set to the Kerberos Principal password.

null (Version 10.2+) When


authentication=ActiveDirector ySer vicePrincipal, the
password property identifies the password to use for the
Active Directory principal.

portNumber, The port where the server is listening. If the port number is
port specified in the connection string, no request to SQLbrowser
is made. When the port and instanceName are both
int specified, the connection is made to the specified port.
[0..65535] However, the instanceName is validated and an error is
thrown if it doesn't match the port.
1433
Impor tant: It is recommended that the port number is
always specified, as it's more secure than using SQLbrowser.

queryTimeout The number of seconds to wait before a timeout has


occurred on a query. The default value is -1, which means
int infinite timeout. Set this value to 0 also implies to wait
indefinitely.
-1

realm (Version 9.4+) The realm for Kerberos authentication. Set


this value to override the Kerberos authentication realm the
String driver autodetects from the server's realm.

null

replication (Version 9.4+) This setting tells the server if the connection
is used for replication. When enabled, triggers with the
boolean NOT FOR REPLICATION option won't fire on the connection.
["true" | "false"]

false
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

responseBuffering If this property is set to "adaptive", the minimum possible


data is buffered when necessary. The default mode is
String "adaptive."
["full" | "adaptive"]
If this property is set to "full", the entire result set is read
adaptive from the server when a statement is executed.

Note: After upgrading the JDBC driver from version 1.2, the
default buffering behavior will be "adaptive." If you want to
keep the version 1.2 default behavior in your application,
you must set the responseBufferring property to "full" either
in the connection properties, or use the
setResponseBuffering method of the SQLServerStatement
object.

selectMethod If this property is set to "cursor," a database cursor is created


for each query created on the connection for
String TYPE_FORWARD_ONLY and CONCUR_READ_ONLY
["direct" | "cursor"] cursors. This property is typically required only if the
application generates large result sets that can't be fully
direct contained in client memory. If this property is set to "cursor,"
only a limited number of result set rows are kept in client
memory.

The default behavior is that all result set rows are kept in
client memory. This behavior provides the fastest
performance when the application is processing all rows.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

sendStringParameters... If the sendStringParametersAsUnicode property is set to


AsUnicode "true", String parameters are sent to the server in Unicode
format.
boolean
["true" | "false"] If the sendStringParametersAsUnicode property is set to
"false", String parameters are sent to the server in non-
true Unicode format such as ASCII/MBCS instead of Unicode.

The default value for the


sendStringParametersAsUnicode property is "true".

Note: The sendStringParametersAsUnicode property is


only checked to send a parameter value with CHAR,
VARCHAR, or LONGVARCHAR JDBC types. The new JDBC
4.0 national character methods, such as the setNString,
setNCharacterStream, and setNClob methods of
SQLServerPreparedStatement and
SQLServerCallableStatement classes, always send their
parameter values to the server in Unicode whatever the
setting of this property.

For optimal performance with the CHAR, VARCHAR, and


LONGVARCHAR JDBC data types, an application should set
the sendStringParametersAsUnicode property to "false"
and use the setString, setCharacterStream, and setClob non-
national character methods of the
SQLServerPreparedStatement and
SQLServerCallableStatement classes.

When the application sets the


sendStringParametersAsUnicode property to "false" and
uses a non-national character method to access Unicode
data types on the server side (such as nchar , nvarchar and
ntext ), some data might be lost if the database collation
doesn't support the characters in the String parameters
passed by the non-national character method.

An application should use the setNString,


setNCharacterStream, and setNClob national character
methods of the SQLServerPreparedStatement and
SQLServerCallableStatement classes for the NCHAR,
NVARCHAR, and LONGNVARCHAR JDBC data types.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

sendTemporalDataTypesAsStringForBulkCopy (Version 8.4+) This connection property, when set to "false",


sends DATE , DATETIME , DATIMETIME2 ,
boolean DATETIMEOFFSET , SMALLDATETIME , and TIME
["true" | "false"] datatypes as their respective types instead of sending them
as String.
true
With this connection property set to "false", the driver will
only accept the default string literal format of each temporal
datatype, for example:

DATE: YYYY-MM-DD
DATETIME: YYYY-MM-DD hh:mm:ss[.nnn]
DATETIME2: YYYY-MM-DD hh:mm:ss[.nnnnnnn]
DATETIMEOFFSET:
YYYY-MM-DD hh:mm:ss[.nnnnnnn] [{+/-}hh:mm]
SMALLDATETIME: YYYY-MM-DD hh:mm:ss
TIME: hh:mm:ss[.nnnnnnn]

sendTimeAsDatetime This property was added in SQL Server JDBC Driver 3.0.

boolean Set to "true" to send java.sql.Time values to the server as


["true" | "false"] SQL Server datetime values.
Set to "false" to send java.sql.Time values to the server as
true SQL Server time values.

The default value for this property is currently "true" and


might change in a future release.

For more information about how the Microsoft JDBC Driver


for SQL Server configures java.sql.Time values before it sends
them to the server, see Configuring How java.sql.Time Values
are Sent to the Server.

serverName, The computer running SQL Server or an Azure SQL


server database.

String You can also specify the Virtual Network Name of an Always
On Availability Groups availability group. For more
null information about disaster recovery, see JDBC driver
support for High Availability, disaster recovery.

serverNameAsACE (Version 6.0+) Set to "true" to indicate that the driver should
translate the Unicode server name to ASCII compatible
boolean encoding (Punycode) for the connection. If this setting is
["true" | "false"] false, the driver uses the server name as provided to
connect.
false
For more information about international features, see
International features of the JDBC driver.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

serverPreparedStatement... (Version 6.2+) This property can be used to control how


DiscardThreshold many outstanding prepared statement discard actions (
sp_unprepare ) can be outstanding per connection before a
Integer call to clean up the outstanding handles on the server is
executed.
10
If this property is set to <= 1, unprepare actions are
executed immediately on prepared statement close. If it's set
to >1, these calls are batched together to avoid overhead of
calling sp_unprepare too often.

serverSpn (Version 4.2+) This optional property can be used to specify


the Service Principal Name (SPN) for a Java Kerberos
String connection. It's used with authenticationScheme .

null To specify the SPN, it can be in the form of:


"MSSQLSvc/fqdn:port@REALM" where fqdn is the fully
qualified domain name, port is the port number, and REALM
is the Kerberos realm of the SQL Server in upper-case letters.

Note: the @REALM is optional if the default realm of the


client (as specified in the Kerberos configuration) is the same
as the Kerberos realm for the SQL Server.

For more information about using ser verSpn with Java


Kerberos, see Using Kerberos integrated authentication to
connect to SQL Server.

socketFactoryClass (Version 8.4+) Specifies the class name for a custom socket
factory to be used instead of the default socket factory.
String

null

socketTimeout The number of milliseconds to wait before a timeout is


occurred on a socket read or accept. The default value is 0,
int which means infinite timeout.

statementPooling... (Version 6.4+) This property can be used to enable prepared


CacheSize statement handle caching in the driver.

int This property defines the size of the cache for statement
pooling.
0
This property can only be used with the
disableStatementPooling connection property, which
should be set to "false". Setting disableStatementPooling
to "true" or statementPoolingCacheSize to 0 disables
prepared statement handle caching.
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

sslProtocol (Version 6.4+) This property can be used to specify the TLS
protocol to be considered during secure connection.
String Possible values are: TLS, TLSv1 , TLSv1.1 , and TLSv1.2 .

TLS For more information about the Secure Sockets Layer


protocol, see SSLProtocol.

transparentNetwork... (Version 6.0+) This property provides faster detection of and


IPResolution connection to the (currently) active server. Possible values
are "true" and "false" where "true" is the default value.
boolean
["true" | "false"] Before Microsoft JDBC Driver 6.0 for SQL Server, an
application had to set the connection string to include
true "multiSubnetFailover=true" to indicate that it was connecting
to an AlwaysOn Availability Group. Without setting the
multiSubnetFailover connection keyword to "true", an
application might experience a timeout while connecting to
an AlwaysOn Availability Group. With version 6.0 and up, an
application isn't required to set multiSubnetFailover to true
anymore.

Note: When transparentNetworkIPResolution=true, the first


connection attempt uses 500 ms as the timeout. Any later
attempts use the same timeout logic as used by the
multiSubnetFailover property.

trustManagerClass (Version 6.4+) The fully qualified class name of a custom


javax.net.ssl.TrustManager implementation.
String

null

trustManager... (Version 6.4+) An optional argument to pass to the


ConstructorArg constructor of the TrustManager. If trustManagerClass is
specified and an encrypted connection is requested, the
String custom TrustManager is used instead of the default system
JVM keystore-based TrustManager.
null
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

trustServerCertificate Set to "true" to specify that the driver doesn't validate the
server TLS/SSL certificate.
boolean
["true" | "false"] If "true", the server TLS/SSL certificate is automatically
trusted when the communication layer is encrypted using
false TLS.

If "false", the driver validates the server TLS/SSL certificate. If


the server certificate validation fails, the driver raises an error
and closes the connection. The default value is "false". Make
sure the value passed to ser verName exactly matches the
Common Name (CN) or DNS name in the Subject Alternate
Name in the server certificate for a TLS/SSL connection to
succeed. For more information about encryption support,
see Understanding encryption support.

Note: This property is used in combination with the


encr ypt /authentication properties. This property only
affects server TLS/SSL certificate validation if the connection
uses TLS encryption.

trustStore The path (including filename) to the certificate trustStore file.


The trustStore file contains the list of certificates that the
String client trusts.

null When this property is unspecified or set to null, the driver


relies on the trust manager factory's lookup rules to
determine which certificate store to use.

The default SunX509 TrustManagerFactor y tries to


locate the trusted material in the following search
order :

A file specified by the "javax.net.ssl.trustStore" JVM system


property.

"<java-home>/lib/security/jssecacerts" file.

"<java-home>/lib/security/cacerts" file.

For more information about the SUNX509 TrustManager


Interface, see the SUNX509 TrustManager Interface
documentation on the Sun Microsystems Web site.

Note: This property only affects the certificate trustStore


lookup, if the connection uses TLS encryption and the
trustSer verCer tificate property is set to "false".
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

trustStorePassword The password used to check the integrity of the trustStore


data.
String
If the trustStore property is set but the trustStorePassword
null property isn't set, the integrity of the trustStore isn't
checked.

When both trustStore and trustStorePassword properties are


unspecified, the driver uses the JVM system properties,
"javax.net.ssl.trustStore" and
"javax.net.ssl.trustStorePassword". If the
"javax.net.ssl.trustStorePassword" system property isn't
specified, the integrity of the trustStore isn't checked.

If the trustStore property isn't set but the


trustStorePassword property is set, the JDBC driver uses the
file that is specified by the "javax.net.ssl.trustStore" as a trust
store and the integrity of the trust store is checked by using
the specified trustStorePassword. This setting is needed
when the client application doesn't want to store the
password in the JVM system property.

Note: The trustStorePassword property only affects the


certificate trustStore lookup, if the connection uses TLS
connection and the trustSer verCer tificate property is set
to "false".

trustStoreType Set this property to specify trust store type to be used for
FIPS mode.
String
Possible values are either PKCS12 or type defined by FIPS
JKS provider.

useBulkCopyFor... (Version 9.2+) This connection property can be enabled to


BatchInsert transparently use the Bulk Copy API when doing batch
insert operations using java.sql.PreparedStatement . This
boolean feature potentially provides much higher performance when
["true" | "false"] enabled.

false This feature is disabled by default. Set this property to "true"


to enable this feature.

Impor tant Note: This feature only supports fully


parameterized INSERT queries. If the INSERT queries are
combined by other SQL queries, or contain data in values,
execution falls back to the basic batch insert operation.

For more information about how to use this property, see


Using bulk copy API for batch insert operation
P RO P ERT Y
TYPE
DEFA ULT DESC RIP T IO N

useFmtOnly (Version 7.4+) Provides an alternative way to query


Parameter Metadata from the server. Set this property to
boolean "true" to specify that the driver should use SET FMTONLY
["true" | "false"] logic when querying Parameter Metadata. This feature is off
by default, and it isn't recommended to use this property as
false SET FMTONLY is marked for deprecation. useFmtOnly is
made available to use only as a workaround for known
issues and limitations in
sp_describe_undeclared_parameters .

This feature currently only supports single


SELECT/INSERT/UPDATE/DELETE queries. Attempting to use
this feature with unsupported/multiple queries will cause the
driver to attempt to parse the query(s), but will most likely
result in an exception.

For more information about this property, see Retrieving


ParameterMetaData via useFmtOnly.

userName, The database user, if connection with SQL user and


user password.

String For Kerberos connection with principal name and password,


[<=128 char] this property is set to Kerberos Principal name.

null (Version 10.2+) When


authentication=ActiveDirector ySer vicePrincipal, the
userName property specifies a valid Azure Active Directory
secure client ID.

workstationID The workstation ID. Used to identify the specific workstation


in various profiling and logging tools.
String
[<=128 char] If none is specified, the <empty string> is used.

<empty string>

xopenStates Set to "true" to specify that the driver returns XOPEN-


compliant state codes in exceptions.
boolean
["true" | "false"] The default is to return SQL 99 state codes.

false

NOTE
The Microsoft JDBC Driver for SQL Server takes the server default values for connection properties except for
ANSI_DEFAULTS and IMPLICIT_TRANSACTIONS. The Microsoft JDBC Driver for SQL Server automatically sets
ANSI_DEFAULTS to ON and IMPLICIT_TRANSACTIONS to OFF.
IMPORTANT
If authentication is set to ActiveDirectoryPassword, the following library needs to be included in the classpath: microsoft-
authentication-library-for-java. It can be found on Maven Repository. The simplest way to download the library and its
dependencies is by using Maven:
1. Install Maven on your system
2. Go to the GitHub page of the driver
3. Download the pom.xml file
4. Run the following Maven command to download the library and its dependencies:
mvn dependency:copy-dependencies

See also
Connecting to SQL Server with the JDBC driver
FIPS mode
Working with a connection
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The following sections provide examples of the different ways to connect to a SQL Server database by using the
SQLServerConnection class of the Microsoft JDBC Driver for SQL Server.

NOTE
If you have problems connecting to SQL Server using the JDBC driver, see Troubleshooting Connectivity for suggestions
on how to correct it.

Creating a connection by using the DriverManager class


The simplest approach to creating a connection to a SQL Server database is to load the JDBC driver and call the
getConnection method of the DriverManager class, as in the following:

Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String connectionUrl = "jdbc:sqlserver://localhost;database=AdventureWorks;integratedSecurity=true;"
Connection con = DriverManager.getConnection(connectionUrl);

This technique will create a database connection using the first available driver in the list of drivers that can
successfully connect with the given URL.

NOTE
When using the sqljdbc4.jar class library, applications do not need to explicitly register or load the driver by using the
Class.forName method. When the getConnection method of the DriverManager class is called, an appropriate driver is
located from the set of registered JDBC drivers. For more information, see Using the JDBC Driver.

Creating a connection by using the SQLServerDriver class


If you have to specify a particular driver in the list of drivers for DriverManager, you can create a database
connection by using the connect method of the SQLServerDriver class, as in the following:

Driver d = (Driver) Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();


String connectionUrl = "jdbc:sqlserver://localhost;database=AdventureWorks;integratedSecurity=true;"
Connection con = d.connect(connectionUrl, new Properties());

Creating a connection by using the SQLServerDataSource class


If you have to create a connection by using the SQLServerDataSource class, you can use various setter methods
of the class before you call the getConnection method, as in the following:
SQLServerDataSource ds = new SQLServerDataSource();
ds.setUser("MyUserName");
ds.setPassword("*****");
ds.setServerName("localhost");
ds.setPortNumber(1433);
ds.setDatabaseName("AdventureWorks");
Connection con = ds.getConnection();

Creating a connection that targets a specific data source


If you have to make a database connection that targets a specific data source, there are a number of approaches
that you can take. Each approach depends on the properties that you set by using the connection URL.
To connect to the default instance on a remote server, use the following example:

String url = "jdbc:sqlserver://MyServer;integratedSecurity=true;"

To connect to a specific port on a server, use the following example:

String url = "jdbc:sqlserver://MyServer:1533;integratedSecurity=true;"

To connect to a named instance on a server, use the following example:

String url = "jdbc:sqlserver://209.196.43.19;instanceName=INSTANCE1;integratedSecurity=true;"

To connect to a specific database on a server, use the following example:

String url = "jdbc:sqlserver://172.31.255.255;database=AdventureWorks;integratedSecurity=true;"

For more connection URL examples, see Building the connection URL.

Creating a connection with a custom login timeout


If you have to adjust for server load or network traffic, you can create a connection that has a specific login
timeout value described in seconds, as in the following example:

String url = "jdbc:sqlserver://MyServer;loginTimeout=90;integratedSecurity=true;"

Create a connection with application-level identity


If you have to use logging and profiling, you will have to identify your connection as originating from a specific
application, as in the following example:

String url = "jdbc:sqlserver://MyServer;applicationName=MYAPP.EXE;integratedSecurity=true;"

Closing a connection
You can explicitly close a database connection by calling the close method of the SQLServerConnection class, as
in the following:
con.close();

This will release the database resources that the SQLServerConnection object is using, or return the connection
to the connection pool in pooled scenarios.

NOTE
Calling the close method will also roll back any pending transactions.

See also
Connecting to SQL Server with the JDBC driver
Connect to an Azure SQL database
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


This article discusses issues when you use the Microsoft JDBC Driver for SQL Server to connect to an Azure SQL
Database. For more information to connect to an Azure SQL Database, see:
Azure SQL Database
How to: Connect to Azure SQL Using JDBC
Connect using Azure Active Directory Authentication

Details
To connect to an Azure SQL Database, you should connect to the master database to call
SQLSer verDatabaseMetaData.getCatalogs .
Azure SQL Database doesn't support returning the entire set of catalogs from a user database.
SQLSer verDatabaseMetaData.getCatalogs use the sys.databases view to get the catalogs. Refer to the
discussion of permissions in sys.databases (Transact-SQL) to understand
SQLSer verDatabaseMetaData.getCatalogs behavior on an Azure SQL Database.

Connections dropped
When you connect to an Azure SQL Database, idle connections may be terminated by a network component
(such as a firewall) after a period of inactivity. There are two types of idle connections, in this context:
Idle at the TCP layer, where connections can be dropped by any number of network devices.
Idle by the Azure SQL Gateway, where TCP keepalive messages might be occurring (which makes the
connection not idle from a TCP perspective), but not had an active query in 30 minutes. In this scenario,
the Gateway will determine that the TDS connection is idle at 30 minutes and terminates the connection.
To address the second point and avoid the Gateway terminating idle connections, you can:
Use the Redirect connection policy to configure your Azure SQL data source.
Keep connections active via lightweight activity. This method isn’t recommended and should only be used
if there are no other possible options.
To address the first point and avoid dropping idle connections by a network component, set the following
registry settings or their non-Windows equivalents on the operating system where the driver is loaded:

REGIST RY SET T IN G REC O M M EN DED VA L UE

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ 30000


Services \ Tcpip \ Parameters \ KeepAliveTime

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ 1000


Services \ Tcpip \ Parameters \ KeepAliveInterval
REGIST RY SET T IN G REC O M M EN DED VA L UE

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ 10


Services \ Tcpip \ Parameters \ TcpMaxDataRetransmissions

Restart the computer for the registry settings to take effect.


The KeepAliveTime and KeepAliveInterval values are in milliseconds. These settings cause an unresponsive
connection to disconnect within 10 to 40 seconds. If no response is received after a keep alive packet is sent, it
will be retried every second up to 10 times. If no response is received during that time, the client-side socket is
disconnected. Depending on your environment, you might want to increase the KeepAliveInterval to
accommodate known disruptions (for example, virtual machine migrations), that might cause a server to be
unresponsive for longer than 10 seconds.

NOTE
TcpMaxDataRetransmissions isn't controllable on Windows Vista or Windows 2008 and higher.

To configure this in an Azure VM, create a startup task to add the registry keys. For example, add the following
Startup task to the service definition file:

<Startup>
<Task commandLine="AddKeepAlive.cmd" executionContext="elevated" taskType="simple">
</Task>
</Startup>

Then add a AddKeepAlive.cmd file to your project. Set the "Copy to Output Directory" setting to Copy always.
The following script is a sample AddKeepAlive.cmd file:

if exist keepalive.txt goto done


time /t > keepalive.txt
REM Workaround for JDBC keep alive on Azure SQL
REG ADD HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters /v KeepAliveTime /t REG_DWORD
/d 30000 >> keepalive.txt
REG ADD HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters /v KeepAliveInterval /t
REG_DWORD /d 1000 >> keepalive.txt
REG ADD HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters /v TcpMaxDataRetransmissions
/t REG_DWORD /d 10 >> keepalive.txt
shutdown /r /t 1
:done

Append the server name to the userId in the connection string


Prior to the 4.0 version of the Microsoft JDBC Driver for SQL Server, to connect to an Azure SQL Database, you
were required to append the server name to the UserId in the connection string. For example,
user@servername. Beginning in version 4.0 of the Microsoft JDBC Driver for SQL Server, it's no longer
necessary to append @servername to the UserId in the connection string.

Using encryption requires setting hostNameInCertificate


Prior to the 7.2 version of the Microsoft JDBC Driver for SQL Server, to connect to an Azure SQL Database, you
should specify hostNameInCer tificate if you specify encr ypt=true (If the server name in the connection
string is shortName.domainName, set the hostNameInCer tificate property to *.domainName.). This property
is optional as of version 7.2 of the driver.
For example:

jdbc:sqlserver://abcd.int.mscds.com;databaseName=myDatabase;user=myName;password=myPassword;encrypt=true;hos
tNameInCertificate=*.int.mscds.com;

See also
Connecting to SQL Server with the JDBC driver
Connection resiliency (JDBC)
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Connection resiliency allows a broken idle connection to be reestablished, within limitations. If an initial
connection fails, connection resiliency also allows the driver to automatically try to reconnect. Only SQL Server
2014 and later and Azure SQL Database support reconnecting a broken idle connection. This feature is available
starting with Microsoft JDBC Driver 10.2.0 for SQL Server.
There are two aspects to connection resiliency. The first is the ability to transparently retry an initial database
connection. The second is the ability to transparently restore an existing, idle connection. A typical idle
connection might be a connection sitting in a connection pool. An "idle" connection is generally one that has
been idle for at least 30 seconds. These connections often can be closed by the server or by network devices
between the client and server.
The JDBC driver has two connection options that control connection resiliency behavior. These options can be
added to the connection string or set via data source properties.

K EY W O RD VA L UES DEFA ULT DESC RIP T IO N

connectRetryCount Integer between 0 and 255 1 The maximum number of


(inclusive) attempts to establish or
reestablish a connection
before giving up. By default,
a single retry attempt is
made. A value of 0 means
that a retry won't be
attempted.

connectRetryInterval Integer between 1 and 60 10 The time, in seconds,


(inclusive) between connection retry
attempts. The driver will
attempt to reconnect
immediately upon detecting
a broken idle connection,
and will then wait
connectRetryInterval
seconds before trying
again. This keyword is
ignored if
connectRetryCount is 0.

If the product of connectRetryCount multiplied by connectRetryInterval is larger than loginTimeout , then the
driver will stop attempting to connect once loginTimeout is reached. Otherwise, it will continue to try to
reconnect until connectRetryCount is reached.
To detect broken idle connections, the driver relies on TCP keepalive packets at the socket level. On Linux and
Java 11+, the driver automatically enables keepalive packets at a 30-second interval ( KeepAliveTime ) with a 1-
second delay between retries when a failure occurs ( KeepAliveInterval ).
IMPORTANT
On Windows and macOS or on Java 8, keepalives must be manually configured in the operating system in order to take
advantage of restoring broken idle connections. For information on how to configure keepalives, see Connection to Azure
SQL database.

Limitations
Broken idle connections can't be restored when:
There's an open result set that hasn't been completely parsed or buffered
Switching databases against Azure SQL
There's an open transaction

See also
Connecting to an Azure SQL database
Technical Article - Idle Connection Resiliency
Overview of the JDBC driver
Building the connection URL
4/27/2022 • 4 minutes to read • Edit Online

Download JDBC Driver


The general form of the connection URL is
jdbc:sqlserver://[serverName[\instanceName][:portNumber]][;property=value[;property=value]]

where:
jdbc:sqlser ver :// (Required) is known as the subprotocol and is constant.
ser verName (Optional) is the address of the server to connect to. This address can be a DNS or IP
address, or it can be localhost or 127.0.0.1 for the local computer. If not specified in the connection URL,
the server name must be specified in the properties collection.
instanceName (Optional) is the instance to connect to on serverName. If not specified, a connection to
the default instance is made.
por tNumber (Optional) is the port to connect to on serverName. The default is 1433. If you're using the
default, you don't have to specify the port, nor its preceding ':', in the URL.

NOTE
For optimal connection performance, you should set the portNumber when you connect to a named instance.
This will avoid a round trip to the server to determine the port number. If both a portNumber and instanceName
are used, the portNumber will take precedence and the instanceName will be ignored.

proper ty (Optional) is one or more option connection properties. For more information, see Setting the
connection properties. Any property from the list can be specified. Properties can only be delimited by
using the semicolon (';'), and they can't be duplicated.
Cau t i on

For security purposes, you should avoid building the connection URLs based on user input. You should only
specify the server name and driver in the URL. For user name and password values, use the connection property
collections. For more information about security in your JDBC applications, see Securing JDBC driver
applications.

Connection properties
For a detailed list of properties that can be set in the connection string, see Setting the connection properties.

Connection examples
Connect to the default database on the local computer by using a user name and password:
jdbc:sqlserver://localhost;user=MyUserName;password=*****;
NOTE
Although the previous example uses a username and password in the connection string, you should use integrated
security as it is more secure. For more information, see the Connecting with Integrated Authentication section later in this
topic.

The following connection string shows an example of how to connect to a SQL Server database using integrated
authentication and Kerberos from an application running on any operating system supported by the Microsoft
JDBC Driver for SQL Server:

jdbc:sqlserver://;servername=server_name;integratedSecurity=true;authenticationScheme=JavaKerberos

Connect to the default database on the local computer by using integrated authentication:
jdbc:sqlserver://localhost;integratedSecurity=true;

Connect to a named database on a remote server:


jdbc:sqlserver://localhost;databaseName=AdventureWorks;integratedSecurity=true;

Connect on the default port to the remote server:


jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks;integratedSecurity=true;

Connect by specifying a customized application name:


jdbc:sqlserver://localhost;databaseName=AdventureWorks;integratedSecurity=true;applicationName=MyApp;

Named and multiple SQL Server instances


SQL Server allows for the installation of multiple database instances per server. Each instance is identified by a
specific name. To connect to a named instance of SQL Server, you can either specify the port number of the
named instance (preferred), or you can specify the instance name as a JDBC URL property or a datasource
property. If no instance name or port number property is specified, a connection to the default instance is
created. See the following examples:
To specify a port number, use the following format:
jdbc:sqlserver://localhost:1433;integratedSecurity=true;<more properties as required>;

To use a JDBC URL property, use the following format:


jdbc:sqlserver://localhost;instanceName=instance1;integratedSecurity=true;<more properties as required>;

Escaping values in the connection URL


You might have to escape certain parts of the connection URL values if the values include special characters like
spaces, semicolons, and quotation marks. The JDBC driver supports escaping these characters by enclosing
them in braces. For example, {;} escapes a semicolon.
Before version 8.4, escaped values can contain special characters (especially '=', ';', '[]', and space) but can't
contain braces. Values that must be escaped and contain braces should be added to a properties collection.
In version 8.4 and above, escaped values can contain special characters, including braces. However, closing
braces must be escaped. For example, with a password of pass";{}word , a connection string would need to
escape the password as follows:
jdbc:sqlserver://localhost;username=MyUsername;password={pass";{}}word};

NOTE
White space inside the braces is literal and not trimmed.

Connecting with integrated authentication On Windows


The JDBC driver supports the use of Type 2 integrated authentication on Windows operating systems by using
the integratedSecurity connection string property. To use integrated authentication, copy the mssql-jdbc_auth-
<version>-<arch>.dll file to a directory on the Windows system path on the computer where the JDBC driver is
installed.
The mssql-jdbc_auth-<version>-<arch>.dll files are installed in the following location:
<installation directory>\sqljdbc_<version>\<language>\auth\
For any operating system supported by the Microsoft JDBC Driver for SQL Server, see Using Kerberos
Integrated Authentication to Connect to SQL Server for a description of a feature added in Microsoft JDBC
Driver 4.0 for SQL Server that allows an application to connect to a database using integrated authentication
with Type 4 Kerberos.

NOTE
If you are running a 32-bit Java Virtual Machine (JVM), use the mssql-jdbc_auth-<version>-<arch>.dll file in the x86
folder, even if the operating system is the x64 version. If you are running a 64-bit JVM on a x64 processor, use the mssql-
jdbc_auth-<version>-<arch>.dll file in the x64 folder.

Alternatively you can set the java.library.path system property to specify the directory of the mssql-jdbc_auth-
<version>-<arch>.dll. For example, if the JDBC driver is installed in the default directory, you can specify the
location of the DLL by using the following virtual machine (VM) argument when the Java application is started:
-Djava.library.path=C:\Microsoft JDBC Driver 6.4 for SQL Server\sqljdbc_<version>\enu\auth\x86

Connecting with IPv6 addresses


The JDBC driver supports the use of IPv6 addresses with the connection properties collection, and with the
serverName connection string property. The initial serverName value, such as jdbc:sqlserver://serverName, isn't
supported for IPv6 addresses in connection strings. Using a name for serverName instead of a raw IPv6 address
will work in every case in the connection. The following examples provide more information.
To use the ser verName proper ty:
jdbc:sqlserver://;serverName=3ffe:8311:eeee:f70f:0:5eae:10.203.31.9\\instance1;integratedSecurity=true;

To use the proper ties collection:


Properties pro = new Properties();

pro.setProperty("serverName", "serverName=3ffe:8311:eeee:f70f:0:5eae:10.203.31.9\\instance1");

Connection con = DriverManager.getConnection("jdbc:sqlserver://;integratedSecurity=true;", pro);

See also
Connecting to SQL Server with the JDBC driver
Using connection pooling
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server provides support for Java Platform, Enterprise Edition (Java EE)
connection pooling. The JDBC driver implements the JDBC 3.0 required interfaces to enable the driver to
participate in any connection-pooling implementation that is provided by middleware vendors and is JDBC 3.0-
compliant. Middleware such as Java EE application servers frequently provides compliant connection-pooling
facilities. The JDBC driver will participate in pooled connections in these environments.

NOTE
Although the JDBC driver supports Java EE connection pooling, it does not provide its own pooling implementation. The
driver relies on third-party Java Application Servers to manage the connections.

Remarks
The classes for the connection pooling implementation are as follows.

C L A SS IM P L EM EN T S DESC RIP T IO N

com.microsoft.sqlserver.jdbc. javax.sql.ConnectionPoolDataSource We recommend that you use the


SQLServerXADataSource and javax.sql.XADataSource SQLServerXADataSource class for all
your Java EE server needs, because it
implements all the JDBC 3.0 pooling
and XA interfaces.

com.microsoft.sqlserver.jdbc. javax.sql.ConnectionPoolDataSource This class is a connection factory that


SQLServerConnectionPoolDataSource enables the Java EE application server
to populate its connection pool with
physical connections. If the
configuration of your Java EE vendor
requires a class that implements
javax.sql.ConnectionPoolDataSource,
specify the class name as
SQLServerConnectionPoolDataSource.
We generally recommend that you use
the SQLServerXADataSource class
instead, because it implements both
pooling and XA interfaces, and has
been verified in more Java EE server
configurations.

JDBC application code should always close connections explicitly to derive the most benefit from pooling. When
the application explicitly closes a connection, the pooling implementation can reuse the connection immediately.
If the connection is not closed, other applications cannot reuse it. Applications can use the finally construct to
make sure that pooled connections are closed even if an exception occurs.
NOTE
The JDBC driver does not currently call the sp_reset_connection stored procedure when it returns the connection to the
pool. Instead, the driver relies on third-party Java Application Servers to return the connections back to their original
states.

See also
Connecting to SQL Server with the JDBC driver
Using Kerberos integrated authentication to connect
to SQL Server
4/27/2022 • 7 minutes to read • Edit Online

Download JDBC Driver


Beginning in Microsoft JDBC Driver 4.0 for SQL Server, an application can use the authenticationScheme
connection property to indicate that it wants to connect to a database using type 4 Kerberos integrated
authentication. See Setting the Connection Properties for more information on connection properties. For more
information on Kerberos, see Microsoft Kerberos.
When using integrated authentication with the Java Krb5LoginModule , you can configure the module using
Class Krb5LoginModule.
The Microsoft JDBC Driver for SQL Server sets the following properties for IBM Java VMs:
useDefaultCcache = true
moduleBanner = false
The Microsoft JDBC Driver for SQL Server sets the following properties for all other Java VMs:
useTicketCache = true
doNotPrompt = true

Remarks
Prior to Microsoft JDBC Driver 4.0 for SQL Server, applications could specify integrated authentication (using
Kerberos or NTLM, depending on which is available) by using the integratedSecurity connection property and
by referencing mssql-jdbc_auth-<version>-<arch>.dll , as described in Building the connection URL.
Beginning in Microsoft JDBC Driver 4.0 for SQL Server, an application can use the authenticationScheme
connection property to indicate that it wants to connect to a database using Kerberos integrated authentication
using the pure Java Kerberos implementation:
If you want integrated authentication using Krb5LoginModule , you must still specify the
integratedSecurity=true connection property. You would then also specify the
authenticationScheme=JavaKerberos connection property.
To continue using integrated authentication with mssql-jdbc_auth-<version>-<arch>.dll , just specify
integratedSecurity=true connection property (and optionally
authenticationScheme=NativeAuthentication ).
If you specify authenticationScheme=JavaKerberos but do not also specify
integratedSecurity=true , the driver will ignore the authenticationScheme connection property and
it will expect to find user name and password credentials in the connection string.
When using a datasource to create connections, you can programmatically set the authentication scheme using
setAuthenticationScheme and (optionally) set the SPN for Kerberos connections using setSer verSpn .
A new logger has been added to support Kerberos authentication:
com.microsoft.sqlserver.jdbc.internals.KerbAuthentication. For more information, see Tracing driver operation.
The following guidelines will help you to configure Kerberos:
1. Set AllowTgtSessionKey to 1 in the registry for Windows. For more information, see Kerberos protocol
registry entries and KDC configuration keys in Windows Server 2003.
2. Make sure that the Kerberos configuration (krb5.conf in UNIX environments), points to the correct realm and
KDC for your environment.
3. Initialize the TGT cache by using kinit or logging into the domain.
4. When an application that uses authenticationScheme=JavaKerberos runs on the Windows Vista or
Windows 7 operating systems, you should use a standard user account. However if you run the application
under an administrator's account, the application must run with administrator privileges.

NOTE
The serverSpn connection attribute is only supported by Microsoft JDBC Drivers 4.2 and higher.

Service principal names


A service principal name (SPN) is the name by which a client uniquely identifies an instance of a service.
You can specify the SPN using the ser verSpn connection property, or simply let the driver build it for you (the
default). This property is in the form of: "MSSQLSvc/fqdn:port@REALM" where fqdn is the fully-qualified
domain name, port is the port number, and REALM is the Kerberos realm of the SQL Server in upper-case
letters. The realm portion of this property is optional if your Kerberos configuration's default realm is the same
realm as that of the Server and is not included by default. If you wish to support a cross-realm authentication
scenario where the default realm in the Kerberos configuration is different than the realm of the Server, then
you must set the SPN with the serverSpn property.
For example, your SPN might look like: "MSSQLSvc/some-
server.zzz.corp.contoso.com:[email protected]"
For more information about service principal names (SPNs), see:
Register a Service Principal Name for Kerberos Connections
Using Kerberos with SQL Server

NOTE
Before 6.2 release of JDBC driver, for proper use of Cross Realm Kerberos, you would need to explicitly set the ser verSpn .
As of the 6.2 release, the driver will be able to build the ser verSpn by default, even when using Cross Realm Kerberos.
Although one can use ser verSpn explicitly too.

Creating a login module configuration file


You can optionally specify a Kerberos configuration file. If a configuration file is not specified, the following
settings are in effect:
Sun JVM
com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true;
IBM JVM
com.ibm.security.auth.module.Krb5LoginModule required useDefaultCcache = true;
If you decide to create a login module configuration file, the file must follow this format:
<name> {
<LoginModule> <flag> <LoginModule options>;
<optional_additional_LoginModules, flags_and_options>;
};

A login configuration file consists of one or more entries, each specifying which underlying authentication
technology should be used for a particular application or applications. For example,

SQLJDBCDriver {
com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true;
};

So, each login module configuration file entry consists of a name followed by one or more LoginModule-
specific entries, where each LoginModule-specific entry is terminated by a semicolon and the entire group of
LoginModule-specific entries is enclosed in braces. Each configuration file entry is terminated by a semicolon.
In addition to allowing the driver to acquire Kerberos credentials using the settings specified in the login module
configuration file, the driver can use existing credentials. This can be useful when your application needs to
create connections using more than one user's credentials.
The driver will attempt to use existing credentials if they are available, before attempting to login using the
specified login module. Thus, when using the Subject.doAs method for executing code under a specific context,
a connection will be created with the credentials passed to the Subject.doAs call.
For more information, see JAAS Login Configuration File and Class Krb5LoginModule.
Beginning in Microsoft JDBC Driver 6.2, name of login module configuration file can optionally be passed using
connection property jaasConfigurationName , this allows each connection to have its own login configuration.

Creating a Kerberos configuration file


For more information about Kerberos configuration files, see Kerberos Requirements.
This is a sample domain configuration file, where YYYY and ZZZZ are the domain names.

[libdefaults]
default_realm = YYYY.CORP.CONTOSO.COM
dns_lookup_realm = false
dns_lookup_kdc = true
ticket_lifetime = 24h
forwardable = yes

[domain_realm]
.yyyy.corp.contoso.com = YYYY.CORP.CONTOSO.COM
.zzzz.corp.contoso.com = ZZZZ.CORP.CONTOSO.COM

[realms]
YYYY.CORP.CONTOSO.COM = {
kdc = krbtgt/YYYY.CORP. CONTOSO.COM @ YYYY.CORP. CONTOSO.COM
default_domain = YYYY.CORP. CONTOSO.COM
}

ZZZZ.CORP. CONTOSO.COM = {
kdc = krbtgt/ZZZZ.CORP. CONTOSO.COM @ ZZZZ.CORP. CONTOSO.COM
default_domain = ZZZZ.CORP. CONTOSO.COM
}
Enabling the domain configuration file and the login module
configuration file
You can enable a domain configuration file with -Djava.security.krb5.conf. You can enable a login module
configuration file with -Djava.security.auth.login.config .
For example, the following command can be used to start the application:

Java.exe -Djava.security.auth.login.config=SQLJDBCDriver.conf -Djava.security.krb5.conf=krb5.ini


<APPLICATION_NAME>

Verifying that SQL Server can be accessed via Kerberos


Run the following query in SQL Server Management Studio:

select auth_scheme from sys.dm_exec_connections where session_id=\@\@spid

Make sure that you have the necessary permission to run this query.

Constrained delegation
Beginning in Microsoft JDBC Driver 6.2, the driver supports Kerberos Constrained Delegation. The delegated
credential can be passed in as org.ietf.jgss.GSSCredential object, these credentials are used by driver to establish
connection.

Properties driverProperties = new Properties();


GSSCredential impersonatedUserCredential = [userCredential]
driverProperties.setProperty("integratedSecurity", "true");
driverProperties.setProperty("authenticationScheme", "JavaKerberos");
driverProperties.put("gsscredential", impersonatedUserCredential);
Connection conn = DriverManager.getConnection(CONNECTION_URI, driverProperties);

Kerberos connection using principal name, password, and realm


Beginning in Microsoft JDBC Driver 6.2, the driver can establish a Kerberos connection using the Principal Name
and Password passed in the connection string.

jdbc:sqlserver://servername=server_name;integratedSecurity=true;authenticationScheme=JavaKerberos;userName=u
ser@REALM;password=****

The username property does not require a REALM if the user belongs to the default_realm set in krb5.conf file.
When userName and password are set along with integratedSecurity=true; and the
authenticationScheme=JavaKerberos; property, the connection is established with a value of userName as the
Kerberos Principal along with the password supplied.
Beginning in Microsoft JDBC Driver 9.4, the user can specify the realm for Kerberos authentication in the
connection string.

jdbc:sqlserver://servername=server_name;integratedSecurity=true;authenticationScheme=JavaKerberos;userName=u
ser;password=****;realm=REALM
Using Kerberos authentication from Unix Machines on the same
domain
This guide assumes a working Kerberos setup already exists. Run the following code on a Windows machine
with working Kerberos authentication to verify if the aforementioned is true. The code will print "Authentication
Scheme: KERBEROS" to the console if successful. No additional run-time flags, dependencies, or driver settings
are required outside of the ones provided. The same block of code can be run on Linux to verify successful
connections.

SQLServerDataSource ds = new SQLServerDataSource();


ds.setServerName("<server>");
ds.setPortNumber(1433); // change if necessary
ds.setIntegratedSecurity(true);
ds.setAuthenticationScheme("JavaKerberos");
ds.setDatabaseName("<database>");

try (Connection c = ds.getConnection(); Statement s = c.createStatement();


ResultSet rs = s.executeQuery("select auth_scheme from sys.dm_exec_connections where
session_id=@@spid")) {
while (rs.next()) {
System.out.println("Authentication Scheme: " + rs.getString(1));
}
}

1. Domain join the client machine to the same domain as the server.
2. (Optional) Set the default Kerberos ticket location. This is most conveniently done by setting the KRB5CCNAME
environment variable.
3. Get the Kerberos ticket, either by generating a new one or placing an existing one in the default Kerberos
ticket location. To generate a ticket, simply use a terminal and initialize the ticket via kinit [email protected]
where "USER" and "DOMAIN.AD" is the principal and domain respectively. E.g:
kinit [email protected] . The ticket will be generated in the default ticket location or in the
KRB5CCNAME path if set.
4. The terminal will prompt for a password, enter the password.
5. Verify the credentials in the ticket via klist and confirm the credentials are the ones you intend to use for
authentication.
6. Run the above sample code and confirm that Kerberos Authentication was successful.

See also
Connecting to SQL Server with the JDBC driver
Connect using Azure Active Directory
authentication
4/27/2022 • 18 minutes to read • Edit Online

Download JDBC Driver


This article provides information on how to develop Java applications that use the Azure Active Directory
authentication feature with the Microsoft JDBC Driver for SQL Server.
You can use Azure Active Directory (Azure AD) authentication, which is a mechanism to connect to Azure SQL
Database using identities in Azure Active Directory. Use Azure Active Directory authentication to centrally
manage identities of database users and as an alternative to SQL Server authentication. The JDBC driver allows
you to specify your Azure Active Directory credentials in the JDBC connection string to connect to Azure SQL
Database. For information on how to configure Azure Active Directory authentication visit Connecting to SQL
Database By Using Azure Active Directory Authentication.
Connection properties to support Azure Active Directory authentication in the Microsoft JDBC Driver for SQL
Server are:
authentication : Use this property to indicate which SQL authentication method to use for the connection.
Possible values are:
ActiveDirector yMSI
Since driver version v8.3.1 , authentication=ActiveDirectoryMSI can be used to connect to an
Azure SQL Database/Synapse Analytics from an Azure Resource with "Identity" support
enabled. Optionally, msiClientId can be specified in the Connection/DataSource properties
along with this authentication mode. msiClientId must contain the Client ID of a Managed
Identity to be used to acquire the accessToken for establishing the connection.
ActiveDirector yIntegrated
Since driver version v6.0 , authentication=ActiveDirectoryIntegrated can be used to connect to
an Azure SQL Database/Synapse Analytics via integrated authentication. To use this
authentication mode, you must federate the on-premise Active Directory Federation Services
(ADFS) with Azure Active Directory in the cloud. Once it's set up, you can connect by either
adding the native library 'mssql-jdbc_auth-<version>-<arch>.dll' to the application class path
on Windows, or by setting up a Kerberos ticket for cross-platform authentication support.
You're able to access Azure SQL Database/Azure Synapse Analytics without prompted for
credentials when you're logged in to a domain joined machine.
ActiveDirector yPassword
Since driver version v6.0 , authentication=ActiveDirectoryPassword can be used to connect to
an Azure SQL Database/Synapse Analytics with Azure AD user name and password.
ActiveDirector yInteractive
Since driver version v9.2 , authentication=ActiveDirectoryInteractive can be used to connect
to an Azure SQL Database/Synapse Analytics via interactive authentication flow (multi-factor
authentication).
ActiveDirector ySer vicePrincipal
Since driver version v9.2 , authentication=ActiveDirectoryServicePrincipal can be used to
connect to an Azure SQL Database/Synapse Analytics by specifying the application/client ID in
the userName property and secret of a service principal identity in the password property.
SqlPassword
Use authentication=SqlPassword to connect to a SQL Server using userName/user and
password properties.
NotSpecified
Use authentication=NotSpecified or leave it as the default when none of these authentication
methods are needed.
accessToken : Use this connection property to connect to a SQL Database with access token.
accessToken can only be set using the Properties parameter of the getConnection() method in the
DriverManager class. It can't be used in the connection URL.
For more information, see the authentication property on the Setting the Connection Properties page.

Client setup requirements


For ActiveDirector yMSI authentication, the below components must be installed on the client machine:
Java 8 or above
Microsoft JDBC Driver 7.2 (or higher) for SQL Server
Client Environment must be an Azure Resource and must have "Identity" feature support enabled. Azure
Virtual Machine, Azure App Service, and Azure Function App environments are supported by the JDBC driver.
A contained database user that represents your Azure Resource's System Assigned Managed Identity or User
Assigned Managed Identity, or one of the groups your Managed Identity belongs to, must exist in the target
database, and must have the CONNECT permission.
For other authentication modes, the below components must be installed on the client machine:
Java 8 or above
Microsoft JDBC Driver 6.0 (or higher) for SQL Server
If you're using the access token-based authentication mode, you need either Microsoft Authentication Library
(MSAL) for Java and its dependencies for JDBC Driver 9.1 and above, or Microsoft Azure Active Directory
Authentication Library (ADAL) for Java and its dependencies for driver versions before JDBC Driver 9.1, to
run the examples from this article. For more information, see the Connect using access token section.
If you're using the ActiveDirector yPassword authentication mode, you need either Microsoft
Authentication Library (MSAL) for Java and its dependencies for JDBC Driver 9.1 and above, or Microsoft
Azure Active Directory Authentication Library (ADAL) for Java and its dependencies for driver versions
before JDBC Driver 9.1. For more information, see the Connect using ActiveDirectoryPassword authentication
mode section.
If you're using the ActiveDirector yIntegrated mode, you need either Microsoft Authentication Library
(MSAL) for Java and its dependencies for JDBC Driver 9.1 and above, or Microsoft Azure Active Directory
Authentication Library (ADAL) for Java and its dependencies for driver versions before JDBC Driver 9.1. For
more information, see the Connect using ActiveDirectoryIntegrated authentication mode section.
If you're using the ActiveDirector yInteractive mode, you need either Microsoft Authentication Library
(MSAL) for Java and its dependencies for JDBC Driver 9.1 and above, or Microsoft Azure Active Directory
Authentication Library (ADAL) for Java and its dependencies for driver versions before JDBC Driver 9.1. For
more information, see the Connect using ActiveDirectoryInteractive authentication mode section.
If you're using the ActiveDirector ySer vicePrincipal mode, you need either Microsoft Authentication
Library (MSAL) for Java and its dependencies for JDBC Driver 9.1 and above, or Microsoft Azure Active
Directory Authentication Library (ADAL) for Java and its dependencies. For more information, see the
Connect using ActiveDirectoryServicePrincipal authentication mode section.

Connect using ActiveDirectoryMSI authentication mode


The following example shows how to use authentication=ActiveDirectoryMSI mode. Run this example from
inside an Azure Resource, e,g an Azure Virtual Machine, App Service, or a Function App that is federated with
Azure Active Directory.
Replace the server/database name with your server/database name in the following lines to run the example:

ds.setServerName("aad-managed-demo.database.windows.net"); // replace 'aad-managed-demo' with your server


name
ds.setDatabaseName("demo"); // replace with your database name
//Optional
ds.setMSIClientId("94de34e9-8e8c-470a-96df-08110924b814"); // Replace with Client ID of User-Assigned
Managed Identity to be used

The example to use ActiveDirectoryMSI authentication mode:

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerDataSource;

public class AAD_MSI {


public static void main(String[] args) throws Exception {

SQLServerDataSource ds = new SQLServerDataSource();


ds.setServerName("aad-managed-demo.database.windows.net"); // Replace with your server name
ds.setDatabaseName("demo"); // Replace with your database name
ds.setAuthentication("ActiveDirectoryMSI");
// Optional
ds.setMSIClientId("94de34e9-8e8c-470a-96df-08110924b814"); // Replace with Client ID of User-
Assigned Managed Identity to be used

try (Connection connection = ds.getConnection();


Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT SUSER_SNAME()")) {
if (rs.next()) {
System.out.println("You have successfully logged on as: " + rs.getString(1));
}
}
}
}

This example on an Azure Virtual Machine fetches an access token from System Assigned Managed Identity or
User Assigned Managed Identity (if msiClientId is specified) and establishes a connection using the fetched
access token. If a connection is established, you should see the following message:

You have successfully logged on as: <your Managed Identity username>

Connect using ActiveDirectoryIntegrated authentication mode


There are two ways to use ActiveDirectoryIntegrated authentication in the Microsoft JDBC Driver for SQL
Server:
On Windows, mssql-jdbc_auth-<version>-<arch>.dll from the downloaded package can be copied to a
location in the system path.
If you can't use the DLL, starting with version 6.4, you can configure a Kerberos ticket. This method is
supported on multiple platforms (Windows, Linux, and macOS). For more information, see Set Kerberos
ticket on Windows, Linux And macOS.
NOTE
If you are using an older version of the driver, check this link for the respective dependencies that are required to use this
authentication mode.

The following example shows how to use authentication=ActiveDirectoryIntegrated mode. Run this example on
a domain joined machine that is federated with Azure Active Directory. A contained database user that
represents your Azure AD user, or one of the groups you belong to, must exist in the database, and must have
the CONNECT permission.
To build and run the example, on the client machine where you run the example, download the Microsoft
Authentication Library (MSAL) for Java and its dependencies for JDBC Driver 9.1 and above, or Microsoft Azure
Active Directory Authentication Library (ADAL) for Java and its dependencies for driver versions before JDBC
Driver 9.1, and include them in the Java build path.
Replace the server/database name with your server/database name in the following lines before executing the
example:

ds.setServerName("aad-managed-demo.database.windows.net"); // replace 'aad-managed-demo' with your server


name
ds.setDatabaseName("demo"); // replace with your database name

The example to use ActiveDirectoryIntegrated authentication mode:

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerDataSource;

public class AADIntegrated {


public static void main(String[] args) throws Exception {

SQLServerDataSource ds = new SQLServerDataSource();


ds.setServerName("aad-managed-demo.database.windows.net"); // Replace with your server name
ds.setDatabaseName("demo"); // Replace with your database name
ds.setAuthentication("ActiveDirectoryIntegrated");

try (Connection connection = ds.getConnection();


Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT SUSER_SNAME()")) {
if (rs.next()) {
System.out.println("You have successfully logged on as: " + rs.getString(1));
}
}
}
}

Running this example on a client machine automatically uses your Kerberos ticket and no password is required.
If a connection is established, you should see the following message:

You have successfully logged on as: <your domain user name>

Set Kerberos ticket on Windows, Linux And macOS


You must up a Kerberos ticket to link your current user to a Windows domain account. A summary of key steps
is included below.
Windows

NOTE
On Windows, mssql-jdbc_auth-<version>-<arch>.dll from the downloaded package can be used instead of these
Kerberos configuration steps. These steps are only required if you can't use the DLL.

JDK comes with kinit , which you can use to get a TGT from Key Distribution Center (KDC) on a domain joined
machine that is federated with Azure Active Directory.
St e p 1 : T i c k e t g r a n t i n g t i c k e t r e t r i e v a l

Run on : Windows
Action :
Use the command kinit [email protected] to get a TGT from KDC, then it prompts you for
your domain password.
Use klist to see the available tickets. If the kinit was successful, you should see a ticket from
krbtgt/DOMAIN.COMPANY.COM@ DOMAIN.COMPANY.COM.

NOTE
You might have to specify a .ini file with -Djava.security.krb5.conf for your application to locate KDC.

Linux and macOS


Requ i r em en t s

Access to a Windows domain-joined machine to query your Kerberos Domain Controller.


St e p 1 : F i n d K e r b e r o s K D C

Run on : Windows command line


Action : nltest /dsgetdc:DOMAIN.COMPANY.COM (where "DOMAIN.COMPANY.COM" maps to your domain's
name)
Sample Output

DC: \\co1-red-dc-33.domain.company.com
Address: \\2111:4444:2111:33:1111:ecff:ffff:3333
...
The command completed successfully

Information to extract The DC name, in this case co1-red-dc-33.domain.company.com

St e p 2 : C o n fi g u r i n g K D C i n k r b 5 .c o n f

Run on : Linux/macOS
Action : Edit the /etc/krb5.conf in an editor of your choice. Configure the following keys

[libdefaults]
default_realm = DOMAIN.COMPANY.COM

[realms]
DOMAIN.COMPANY.COM = {
kdc = co1-red-dc-28.domain.company.com
}

Then save the krb5.conf file and exit


NOTE
Domain must be in ALL CAPS.

St e p 3 : Te st t h e t i c k e t g r a n t i n g t i c k e t r e t r i e v a l

Run on : Linux/macOS
Action :
Use the command kinit [email protected] to get a TGT from KDC, then it prompts you for
your domain password.
Use klist to see the available tickets. If the kinit was successful, you should see a ticket from
krbtgt/DOMAIN.COMPANY.COM@ DOMAIN.COMPANY.COM.

Connect using ActiveDirectoryPassword authentication mode


The following example shows how to use authentication=ActiveDirectoryPassword mode.
To build and run the example:
1. On the client machine where you run the example, download the Microsoft Authentication Library
(MSAL) for Java and its dependencies for JDBC Driver 9.1 and above, or Microsoft Azure Active Directory
Authentication Library (ADAL) for Java and its dependencies for driver versions before JDBC Driver 9.1,
and include them in the Java build path.
2. Locate the following lines of code and replace the server/database name with your server/database
name.

ds.setServerName("aad-managed-demo.database.windows.net"); // replace 'aad-managed-demo' with your


server name
ds.setDatabaseName("demo"); // replace with your database name

3. Locate the following lines of code. Replace user name with the name of the Azure AD user that you want
to connect as.

ds.setUser("[email protected]"); // replace with your user name


ds.setPassword("password"); // replace with your password

The example to use ActiveDirectoryPassword authentication mode:


import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerDataSource;

public class AADUserPassword {

public static void main(String[] args) throws Exception{

SQLServerDataSource ds = new SQLServerDataSource();


ds.setServerName("aad-managed-demo.database.windows.net"); // Replace with your server name
ds.setDatabaseName("demo"); // Replace with your database
ds.setUser("[email protected]"); // Replace with your user name
ds.setPassword("password"); // Replace with your password
ds.setAuthentication("ActiveDirectoryPassword");

try (Connection connection = ds.getConnection();


Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT SUSER_SNAME()")) {
if (rs.next()) {
System.out.println("You have successfully logged on as: " + rs.getString(1));
}
}
}
}

If connection is established, you should see the following message as output:

You have successfully logged on as: <your user name>

NOTE
A contained user database must exist and a contained database user that represents the specified Azure AD user or one
of the groups, the specified Azure AD user belongs to, must exist in the database, and must have the CONNECT
permission (except for Azure Active Directory server admin or group)

Connect using ActiveDirectoryInteractive authentication mode


The following example shows how to use authentication=ActiveDirectoryInteractive mode.
To build and run the example:
1. On the client machine where you run the example, download the Microsoft Authentication Library
(MSAL) for Java and its dependencies for JDBC Driver 9.1 and above, or Microsoft Azure Active Directory
Authentication Library (ADAL) for Java and its dependencies for driver versions before JDBC Driver 9.1,
and include them in the Java build path
2. Locate the following lines of code and replace the server/database name with your server/database
name.

ds.setServerName("aad-managed-demo.database.windows.net"); // replace 'aad-managed-demo' with your


server name
ds.setDatabaseName("demo"); // replace with your database name

3. Locate the following lines of code. Replace user name with the name of the Azure AD user that you want
to connect as.
ds.setUser("[email protected]"); // replace with your user name

The example to use ActiveDirectoryInteractive authentication mode:

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerDataSource;

public class AADInteractive {


public static void main(String[] args) throws Exception{

SQLServerDataSource ds = new SQLServerDataSource();


ds.setServerName("aad-managed-demo.database.windows.net"); // Replace with your server name
ds.setDatabaseName("demo"); // Replace with your database
ds.setAuthentication("ActiveDirectoryInteractive");

// Optional login hint


ds.setUser("[email protected]"); // Replace with your user name

try (Connection connection = ds.getConnection();


Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT SUSER_SNAME()")) {
if (rs.next()) {
System.out.println("You have successfully logged on as: " + rs.getString(1));
}
}
}
}

When you run the program, a browser is displayed to authenticate the user. Exactly what you see depends on
how your Azure AD has been configured. It might or might not include multi-factor authentication prompts for
username, password, PIN, or second device authentication via a phone. If multiple interactive authentication
requests are done in the same program, later requests might not even prompt you if the authentication library
can reuse a previously cached authentication token.
For information about how to configure Azure AD to require Multi-Factor Authentication, see Getting started
with Azure AD Multi-Factor Authentication in the cloud.
For screenshots of these dialog boxes, see Configure multi-factor authentication for SQL Server Management
Studio and Azure AD.
If user authentication is completed successfully, you should see the following message in the browser:

Authentication complete. You can close the browser and return to the application.

This message only indicates that user authentication was successful but not necessarily a successful connection
to the server. Upon return to the application, if a connection is established to the server, you should see the
following message as output:

You have successfully logged on as: <your user name>


NOTE
A contained user database must exist and a contained database user that represents the specified Azure AD user or one
of the groups the specified Azure AD user belongs to, must exist in the database and must have the CONNECT
permission (except for an Azure Active Directory server admin or group)

Connect using ActiveDirectoryServicePrincipal authentication mode


The following example shows how to use authentication=ActiveDirectoryServicePrincipal mode.
To build and run the example:
1. On the client machine where you run the example, download the Microsoft Authentication Library
(MSAL) for Java and its dependencies for JDBC Driver 9.1 and above, or Microsoft Azure Active Directory
Authentication Library (ADAL) for Java and its dependencies for driver versions before JDBC Driver 9.1,
and include them in the Java build path
2. Locate the following lines of code and replace the server/database name with your server/database
name.

ds.setServerName("aad-managed-demo.database.windows.net"); // replace 'aad-managed-demo' with your


server name
ds.setDatabaseName("demo"); // replace with your database name

3. Locate the following lines of code. Replace the value of principalId with the Application ID / Client ID of
the Azure AD service principal that you want to connect as. Replace the value of principalSecret with the
secret.

String principalId = "1846943b-ad04-4808-aa13-4702d908b5c1"; // Replace with your AAD service


principal ID.
String principalSecret = "..."; // Replace with your AAD principal secret.

4. Set the principalId and principal Secret using setUser and setPassword in version 10.2 and up, and
setAADSecurePrincipalId and setAADSecurePrincipalSecret in version 9.4 and below.

The example to use ActiveDirectoryInteractive authentication mode:


import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerDataSource;

public class AADServicePrincipal {


public static void main(String[] args) throws Exception{
String principalId = "1846943b-ad04-4808-aa13-4702d908b5c1"; // Replace with your AAD service
principal ID.
String principalSecret = "..."; // Replace with your AAD principal secret.

SQLServerDataSource ds = new SQLServerDataSource();


ds.setServerName("aad-managed-demo.database.windows.net"); // Replace with your server name
ds.setDatabaseName("demo"); // Replace with your database
ds.setAuthentication("ActiveDirectoryServicePrincipal");
ds.setUser(principalId); // setAADSecurePrincipalId for JDBC Driver 9.4 and below
ds.setPassword(principalSecret); // setAADSecurePrincipalSecret for JDBC Driver 9.4 and below

try (Connection connection = ds.getConnection();


Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT SUSER_SNAME()")) {
if (rs.next()) {
System.out.println("You have successfully logged on as: " + rs.getString(1));
}
}
}
}

If a connection is established, you should see the following message as output:

You have successfully logged on as: <your app/client ID>

NOTE
A contained user database must exist and a contained database user that represents the specified Azure AD principal or
one of the groups the specified Azure AD principal belongs to, must exist in the database and must have the CONNECT
permission (except for an Azure Active Directory server admin or group)

Connect using access token


Applications/services can retrieve an access token from the Azure Active Directory and use that to connect to
Azure SQL Database/Synapse Analytics.

NOTE
accessToken can only be set using the Properties parameter of the getConnection() method in the DriverManager class.
It can't be used in the connection string.

The following example contains a simple Java application that connects to Azure SQL Database/Synapse
Analytics using access token-based authentication.
To build and run the example:
1. Create an application account in Azure Active Directory for your service.
a. Sign in to the Azure portal.
b. Select Azure Active Directory in the left-hand navigation.
c. Select the "App registrations" tab.
d. In the drawer, select "New application registration".
e. Enter mytokentest as a friendly name for the application, select "Web App/API".
f. Don't need SIGN-ON URL, provide anything: "https://mytokentest".
g. Select "Create" at the bottom.
h. While still in the Azure portal, select the "Settings" tab of your application, and open the "Properties"
tab.
i. Find the "Application ID" (also known as Client ID) value and copy it. You need this value later to
configure your application (for example, 1846943b-ad04-4808-aa13-4702d908b5c1).
j. Under section "Keys", create a key to fill in the name field, select the duration of the key, and save the
configuration (leave the value field empty). After you save, the value field should be filled
automatically. Copy the generated value. This value is the client Secret.
k. Select Azure Active Directory on the left side panel. Under "App Registrations", find the "End points"
tab. Copy the URL under "OATH 2.0 TOKEN ENDPOINT", this URL is your STS URL.

2. Sign in to your Azure SQL Server user database as an Azure Active Directory admin and use a T-SQL
command, provision a contained database user for your application principal. For more information on
how to create an Azure Active Directory admin and a contained database user, see the Connecting to SQL
Database or Azure Synapse Analytics By Using Azure Active Directory authentication.

CREATE USER [mytokentest] FROM EXTERNAL PROVIDER

3. On the client machine where you run the example, download the Microsoft Authentication Library
(MSAL) for Java library and its dependencies for JDBC Driver 9.1 and above, or Microsoft Azure Active
Directory Authentication Library (ADAL) for Java and its dependencies for driver versions before JDBC
Driver 9.1, and include them in the Java build path. The microsoft-authentication-library-for-java is only
required to run this specific example. The example uses the APIs from this library to retrieve the access
token from Azure AD. If you already have an access token, you can skip this step and remove the section
in the example that retrieves an access token.
In the following example, replace the STS URL, Client ID, Client Secret, server and database name with your
values.

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;

// The azure-activedirectory-library-for-java is needed to retrieve the access token from the AD.
import com.microsoft.aad.msal4j.ClientCredentialFactory;
import com.microsoft.aad.msal4j.ClientCredentialParameters;
import com.microsoft.aad.msal4j.ConfidentialClientApplication;
import com.microsoft.aad.msal4j.IAuthenticationResult;
import com.microsoft.aad.msal4j.IClientCredential;

public class AADTokenBased {

public static void main(String[] args) throws Exception {

// Retrieve the access token from the AD.


String spn = "https://database.windows.net/";
String stsurl = "https://login.microsoftonline.com/..."; // Replace with your STS URL.
String clientId = "1846943b-ad04-4808-aa13-4702d908b5c1"; // Replace with your client ID.
String clientSecret = "..."; // Replace with your client secret.

String scope = spn + "/.default";


Set<String> scopes = new HashSet<>();
scopes.add(scope);

ExecutorService executorService = Executors.newSingleThreadExecutor();


IClientCredential credential = ClientCredentialFactory.createFromSecret(clientSecret);
ConfidentialClientApplication clientApplication = ConfidentialClientApplication
.builder(clientId, credential).executorService(executorService).authority(stsurl).build();
CompletableFuture<IAuthenticationResult> future = clientApplication
.acquireToken(ClientCredentialParameters.builder(scopes).build());

IAuthenticationResult authenticationResult = future.get();


String accessToken = authenticationResult.accessToken();

System.out.println("Access Token: " + accessToken);

// Connect with the access token.


SQLServerDataSource ds = new SQLServerDataSource();

ds.setServerName("aad-managed-demo.database.windows.net"); // Replace with your server name.


ds.setDatabaseName("demo"); // Replace with your database name.
ds.setAccessToken(accessToken);

try (Connection connection = ds.getConnection();


Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT SUSER_SNAME()")) {
if (rs.next()) {
System.out.println("You have successfully logged on as: " + rs.getString(1));
}
}
}
}

If the connection is successful, you should see the following message as output:

Access Token: <your access token>


You have successfully logged on as: <your client ID>
Next steps
Learn more about related concepts in the following articles:
Connecting to SQL Database By Using Azure Active Directory Authentication
Microsoft Authentication Library (MSAL) for Java
Microsoft Azure Active Directory Authentication Library (ADAL) for Java
Connecting to SQL Database or Azure Synapse Analytics By Using Azure Active Directory authentication
Troubleshoot connection issues to Azure SQL Database
Using NTLM Authentication to connect to SQL
Server
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server allows an application to use the authenticationScheme connection
property to indicate that it wants to connect to a database using NTLM v2 Authentication.
The following properties are also used for NTLM Authentication:
domain = domainName (optional)
user = userName
password = password
integratedSecurity = true
Other than domain , the other properties are mandatory, the driver will throw an error if any are missing when
the NTLM authenticationScheme property is used.
For more information on connection properties, see Setting the connection properties. For more information on
the Microsoft NTLM authentication protocol, see Microsoft NTLM.

Remarks
See Network security: LAN Manager authentication level for description of the SQL server settings, which
control the behavior of NTLM authentication.

Logging
A new logger has been added to support NTLM authentication:
com.microsoft.sqlserver.jdbc.internals.NTLMAuthentication. For more information, see Tracing Driver Operation.

DataSource
When using a datasource to create connections, the NTLM properties can be programmatically set using
setAuthenticationScheme , setDomain , and (optionally) setSer verSpn .
SQLServerDataSource ds = new SQLServerDataSource();
ds.setServerName("<server>");
ds.setPortNumber(1433); // change if necessary
ds.setIntegratedSecurity(true);
ds.setAuthenticationScheme("NTLM");
ds.setDomain("<domainName>");
ds.setUser("<userName>");
ds.setPassword("<password>");
ds.setDatabaseName("<database>");
ds.setServerSpn("<serverSpn");

try (Connection c = ds.getConnection(); Statement s = c.createStatement();


ResultSet rs = s.executeQuery("select auth_scheme from sys.dm_exec_connections where
session_id=@@spid")) {
while (rs.next()) {
System.out.println("Authentication Scheme: " + rs.getString(1));
}
}

Service principal names


A service principal name (SPN) is the name by which a client uniquely identifies an instance of a service.
You can specify the SPN using the ser verSpn connection property, or let the driver build it for you (the default).
This property is in the form of: "MSSQLSvc/fqdn:port@REALM" where fqdn is the fully qualified domain name,
port is the port number, and REALM is the realm of the SQL Server in upper-case letters. The realm portion of
this property is optional since the default realm is the same as the realm of the Server.
For example, your SPN might look like: "MSSQLSvc/some-server.zzz.corp.contoso.com:1433"
For more information about service principal names (SPNs), see:
Service Principal Name (SPN) Support in Client Connections

NOTE
The serverSpn connection attribute is only supported by Microsoft JDBC Drivers 4.2 and higher.

Before 6.2 release of JDBC driver, you would need to explicitly set the ser verSpn . As of the 6.2 release, the
driver will be able to build the ser verSpn by default, although one can use ser verSpn explicitly too.

Security risks
The NTLM protocol is an old authentication protocol with various vulnerabilities, which pose a security risk. It's
based on a weak cryptographic scheme and is vulnerable to attacks. NTLM has been replaced by Kerberos,
which much more secure and recommended. NTLM authentication should only be used in a secure trusted
environment, or when Kerberos can't be used.
The Microsoft JDBC Driver for SQL Server only supports NTLM v2, which has some security improvements over
the original v1 protocol. It's also recommended to enable Extended Protection, or use TLS Encryption for
increased security.
For more information on how to enable Extended Protection and, see:
Connect to the Database Engine Using Extended Protection
For more information on connecting with encryption, see:
Connecting with encryption

NOTE
For the 7.4 release, enabling both Extended Protection and Encryption is not supported.

See also
Connecting to SQL Server with the JDBC driver
Client Certificate Authentication for Loopback
Scenarios
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


A new stored procedure called sp_execute_external_script (SPEES) was added in SQL Server 2016. This stored
procedure allows SQL Server to launch and execute an external script outside of the SQL Server, as part of an
extensibility effort. With it came the support for R and Python scripts, both of which has libraries that can use a
JDBC driver to connect to the SQL Server. While SQL Servers on Windows box can use Windows Integrated
Authentication to authenticate these loopback connections with the same credentials as the user who started the
query, Linux SQL Server cannot do the same. Therefore, client certificate authentication is being added to allow
users to authenticate with a certificate and key.

Connecting using Client Certificate Authentication


The JDBC driver adds three connection properties for this feature:
clientCertificate – specifies the certificate to be used for authentication. The JDBC driver will support PFX,
PEM, DER, and CER file extensions.
Format

clientCertificate=<file_location>

The driver uses a certificate file. For certificates in PEM, DER, and CER formats clientKey attribute is required. File
location can be either relative or absolute.
clientKey – specifies a file location of the private key for PEM, DER, and CER certificates specified by the
clientCertificate attribute.
Format

clientKey=<file_location>

Specifies location of the private key file. In case if private key file is password protected then password keyword
is required. File location can be either relative or absolute.
clientKeyPassword – optional password string provided to access the clientKey file's private key.
This feature is only officially supported for loopback authentication scenarios against Linux SQL Server
2019 and up.

See also
Connecting to SQL Server with the JDBC driver
sp_execute_external_script (Transact-SQL)
Using basic data types
4/27/2022 • 5 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server uses the JDBC basic data types to convert the SQL Server data types
to a format that can be understood by the Java programming language, and vice versa. The JDBC driver
provides support for the JDBC 4.0 API, which includes the SQLXML data type, and National (Unicode) data
types, such as NCHAR , NVARCHAR , LONGNVARCHAR , and NCLOB .

Data type mappings


The following table lists the default mappings between the basic SQL Server, JDBC, and Java programming
language data types:

SQ L SERVER T Y P ES JDB C T Y P ES ( JAVA . SQ L . T Y P ES) JAVA L A N GUA GE T Y P ES

bigint BIGINT long

binary BINARY byte[]

bit BIT boolean

char CHAR String

date DATE java.sql.Date

datetime3 TIMESTAMP java.sql.Timestamp

datetime2 TIMESTAMP java.sql.Timestamp

datetimeoffset2 microsoft.sql.Types.DATETIMEOFFSET microsoft.sql.DateTimeOffset

decimal DECIMAL java.math.BigDecimal

float DOUBLE double

image LONGVARBINARY byte[]

int INTEGER int

money DECIMAL java.math.BigDecimal

nchar CHAR String

NCHAR (Java SE 6.0)

ntext LONGVARCHAR String

LONGNVARCHAR (Java SE 6.0)


SQ L SERVER T Y P ES JDB C T Y P ES ( JAVA . SQ L . T Y P ES) JAVA L A N GUA GE T Y P ES

numeric NUMERIC java.math.BigDecimal

nvarchar VARCHAR String

NVARCHAR (Java SE 6.0)

nvarchar(max) VARCHAR String

NVARCHAR (Java SE 6.0)

real REAL float

smalldatetime TIMESTAMP java.sql.Timestamp

smallint SMALLINT short

smallmoney DECIMAL java.math.BigDecimal

text LONGVARCHAR String

time TIME1 java.sql.Time1

timestamp BINARY byte[]

tinyint TINYINT short

udt VARBINARY byte[]

uniqueidentifier CHAR String

varbinary VARBINARY byte[]

varbinary(max) VARBINARY byte[]

varchar VARCHAR String

varchar(max) VARCHAR String

xml LONGVARCHAR String

LONGNVARCHAR (Java SE 6.0) SQLXML

sqlvariant microsoft.sql.Types.SQL_VARIANT Object

geometry VARBINARY byte[]

geography VARBINARY byte[]

1 To use java.sql.Time with the time SQL Server type, you must set the sendTimeAsDatetime connection
property to false.
2 You can programmatically access values of datetimeoffset with DateTimeOffset Class.
3
3 Note that java.sql.Timestamp values can no longer be used to compare values from a datetime column starting
from SQL Server 2016. This limitation is due to a server-side change that converts datetime to datetime2
differently, resulting in non-equitable values. The workaround to this issue is to either change datetime columns
to datetime2(3), use String instead of java.sql.Timestamp, or change database compatibility level to 120 or
below.
The following sections provide examples of how you can use the JDBC Driver and the basic data types. For a
more detailed example of how to use the basic data types in a Java application, see Basic Data Types Sample.

Retrieving data as a string


If you have to retrieve data from a data source that maps to any of the JDBC basic data types for viewing as a
string, or if strongly typed data is not required, you can use the getString method of the SQLServerResultSet
class, as in the following:

try(Statement stmt = con.createStatement();) {


ResultSet rs = stmt.executeQuery("SELECT lname, job_id FROM employee WHERE (lname = 'Brown')");
rs.next();
short empJobID = rs.getString("job_id");
}

Retrieving data by data type


If you have to retrieve data from a data source, and you know the type of data that is being retrieved, use one of
the get<Type> methods of the SQLServerResultSet class, also known as the getter methods. You can use either
a column name or a column index with the get<Type> methods, as in the following:

try(Statement stmt = con.createStatement();) {


ResultSet rs = stmt.executeQuery("SELECT lname, job_id FROM employee WHERE (lname = 'Brown')");
rs.next();
short empJobID = rs.getShort("job_id");
}

NOTE
The getUnicodeStream and getBigDecimal with scale methods are deprecated and are not supported by the JDBC driver.

Updating data by data type


If you have to update the value of a field in a data source, use one of the update<Type> methods of the
SQLServerResultSet class. In the following example, the updateInt method is used in conjunction with the
updateRow method to update the data in the data source:

try (Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);) {


ResultSet rs = stmt.executeQuery("SELECT lname, job_id FROM employee WHERE (lname = 'Brown')");
rs.next();
int empJobID = rs.getInt(2);
empJobID++;
rs.first();
rs.updateInt(2, empJobID);
rs.updateRow();
}
NOTE
The JDBC driver cannot update a SQL Server column with a column name that is more than 127 characters long. If an
update to a column whose name is more than 127 characters is attempted, an exception is thrown.

Updating data by parameterized query


If you have to update data in a data source by using a parameterized query, you can set the data type of the
parameters by using one of the set<Type> methods of the SQLServerPreparedStatement class, also known as
the setter methods. In the following example, the prepareStatement method is used to pre-compile the
parameterized query, and then the setString method is used to set the string value of the parameter before the
executeUpdate method is called.

try(PreparedStatement pstmt = con.prepareStatement("UPDATE employee SET fname = ? WHERE (lname =


'Brown')");) {
String name = "Bob";
pstmt.setString(1, name);
int rowCount = pstmt.executeUpdate();
}

For more information about parameterized queries, see Using an SQL statement with parameters.

Passing parameters to a stored procedure


If you have to pass typed parameters into a stored procedure, you can set the parameters by index or name by
using one of the set<Type> methods of the SQLServerCallableStatement class. In the following example, the
prepareCall method is used to set up the call to the stored procedure, and then the setString method is used to
set the parameter for the call before the executeQuery method is called.

try(CallableStatement cstmt = con.prepareCall("{call employee_jobid(?)}");) {


String lname = "Brown";
cstmt.setString(1, lname);
ResultSet rs = cstmt.executeQuery();
}

NOTE
In this example, a result set is returned with the results of running the stored procedure.

For more information about using the JDBC driver with stored procedures and input parameters, see Using a
stored procedure with input parameters.

Retrieving parameters from a stored procedure


If you have to retrieve parameters back from a stored procedure, you must first register an out parameter by
name or index by using the registerOutParameter method of the SQLServerCallableStatement class, and then
assign the returned out parameter to an appropriate variable after you run the call to the stored procedure. In
the following example, the prepareCall method is used to set up the call to the stored procedure, the
registerOutParameter method is used to set up the out parameter, and then the setString method is used to set
the parameter for the call before executeQuery method is called. The value that is returned by the out parameter
of the stored procedure is retrieved by using the getShort method.
try(CallableStatement cstmt = con.prepareCall("{call employee_jobid (?, ?)}");) {
cstmt.registerOutParameter(2, java.sql.Types.SMALLINT);
String lname = "Brown";
cstmt.setString(1, lname);
ResultSet rs = cstmt.executeQuery();
short empJobID = cstmt.getShort(2);
}

NOTE
In addition to the returned out parameter, a result set might also be returned with the results of running the stored
procedure.

For more information about how to use the JDBC driver with stored procedures and output parameters, see
Using a stored procedure with output parameters.

See also
Understanding the JDBC driver data types
Understanding data type differences
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


There are a number of differences between the Java programming language data types and SQL Server data
types. The Microsoft JDBC Driver for SQL Server helps to facilitate those differences through various types of
conversions.

Character types
The JDBC character string data types are CHAR , VARCHAR , and LONGVARCHAR . The JDBC driver provides
support for the JDBC 4.0 API. In the JDBC 4.0, the JDBC character string data types can also be NCHAR ,
NVARCHAR , and LONGNVARCHAR . These new character string types maintain Java native character types in
Unicode format and remove the need to perform any ANSI-to-Unicode or Unicode-to-ANSI conversion.

TYPE DESC RIP T IO N

Fixed-length The SQL Server char and nchar data types map directly to
the JDBC CHAR and NCHAR types. These are fixed-length
types with padding provided by the server in the case where
the column has SET ANSI_PADDING ON . Padding is always
turned on for nchar , but for char , in the case where the
server char columns are not padded, the JDBC driver adds
the padding.

Variable-length The SQL Server varchar and nvarchar types map directly
to the JDBC VARCHAR and NVARCHAR types, respectively.

Long The SQL Server text and ntext types map to the JDBC
LONGVARCHAR and LONGNVARCHAR type, respectively.
These are deprecated types beginning in SQL Server 2005
(9.x), so you should use large value types, varchar(max) or
nvarchar(max) , instead.

Using the update<Numeric Type> and updateObject (int,


java.lang.Object) methods will fail against text and ntext
server columns. However, using the setObject method with a
specified character conversion type is supported against
text and ntext server columns.

Binary string types


The JDBC binary-string types are BINARY , VARBINARY , and LONGVARBINARY .

TYPE DESC RIP T IO N


TYPE DESC RIP T IO N

Fixed-length The SQL Server binar y type maps directly to the JDBC
BINARY type. This is a fixed-length type with padding
provided by the server in the case where the column has SET
ANSI_PADDING ON. When the server char columns are not
padded, the JDBC driver adds the padding.

The SQL Server timestamp type is a JDBC BINARY type


with the fixed length of 8 bytes.

Variable-length The SQL Server varbinar y type maps to the JDBC


VARBINARY type.

The udt type in SQL Server maps to JDBC as a VARBINARY


type.

Long The SQL Server image type maps to the JDBC


LONGVARBINARY type. This type is deprecated beginning
in SQL Server 2005 (9.x), so you should use a large value
type, varbinar y(max) instead.

Exact numeric types


The JDBC exact numeric types map directly to their corresponding SQL Server types.

TYPE DESC RIP T IO N

BIT The JDBC BIT type represents a single bit that can be 0 or 1.
This maps to a SQL Server bit type.

TINYINT The JDBC TINYINT type represents a single byte. This maps
to a SQL Server tinyint type.

SMALLINT The JDBC SMALLINT type represents a signed 16-bit


integer. This maps to a SQL Server smallint type.

INTEGER The JDBC INTEGER type represents a signed 32-bit integer.


This maps to a SQL Server int type.

BIGINT The JDBC BIGINT type represents a signed 64-bit integer.


This maps to a SQL Server bigint type.

NUMERIC The JDBC NUMERIC type represents a fixed-precision


decimal value that holds values of identical precision. The
NUMERIC type maps to the SQL Server numeric type.

DECIMAL The JDBC DECIMAL type represents a fixed-precision


decimal value that holds values of at least the specified
precision. The DECIMAL type maps to the SQL Server
decimal type.

The JDBC DECIMAL type also maps to the SQL Server


money and smallmoney types, which are specific fixed-
precision decimal types that are stored in 8 and 4 bytes,
respectively.
Approximate numeric types
The JDBC approximate numeric types are REAL , DOUBLE , and FLOAT .

TYPE DESC RIP T IO N

REAL The JDBC REAL type has seven digits of precision (single
precision) and maps directly to the SQL Server real type.

DOUBLE The JDBC DOUBLE type has 15 digits of precision (double


precision) and maps to the SQL Server float type. The JDBC
FLOAT type is a synonym of DOUBLE . Because there can
be confusion between FLOAT and DOUBLE , DOUBLE is
preferred.

Datetime Types
The JDBC TIMESTAMP type maps to the SQL Server datetime and smalldatetime types. The datetime type
is stored in two 4-byte integers. The smalldatetime type holds the same information (date and time), but with
less accuracy, in two 2-byte small integers.

NOTE
The SQL Server timestamp type is a fixed-length binary-string type. It does not map to any of the JDBC time types:
DATE , TIME , or TIMESTAMP .

Custom type mapping


The custom type mapping feature of JDBC that uses the SQLData interfaces for the JDBC advanced types (UDTs,
Struct, and so on). is not implemented in the JDBC driver.

See also
Understanding the JDBC driver data types
Understanding data type conversions
4/27/2022 • 7 minutes to read • Edit Online

Download JDBC Driver


To facilitate the conversion of Java programming language data types to SQL Server data types, the Microsoft
JDBC Driver for SQL Server provides data type conversions as required by the JDBC specification. For added
flexibility, all types are convertible to and from Object , String , and byte[] data types.

Getter method conversions


Based on the SQL Server data types, the following chart contains the JDBC driver's conversion map for the
get<Type>() methods of the SQLServerResultSet class, and the supported conversions for the get<Type>
methods of the SQLServerCallableStatement class.

There are three categories of conversions that are supported by the JDBC driver's getter methods:
Non-Lossy (x) : Conversions for cases where the getter type is the same or smaller than the underlying
server type. For example, when calling getBigDecimal on an underlying server decimal column, no
conversion is necessary.
Conver ted (y) : Conversions from numeric server types to Java language types where the conversion is
regular and follows Java language conversion rules. For these conversions, precision is always truncated-
never rounded-and overflow is handled as modulo of the destination type, which is smaller. For example,
calling getInt on an underlying decimal column that contains "1.9999" will return "1", or if the
underlying decimal value is "3000000000" then the int value overflows to "-1294967296".
Data Dependent (z) : Conversions from underlying character types to numeric types require that the
character types contain values that can be converted into that type. No other conversions are performed.
If the value is too large for the getter type, the value isn't valid. For example, if getInt is called on a
varchar(50) column that contains "53", the value is returned as an int ; but if the underlying value is "xyz"
or "3000000000", an error is thrown.
If getString is called on a binar y , varbinar y , varbinar y(max) , or image column data type, the value is
returned as a hexadecimal string value.

Updater method conversions


For the Java typed data passed to the update<Type>() methods of the SQLServerResultSet class, the following
conversions apply.

There are three categories of conversions supported by the JDBC driver's updater methods:
Non-Lossy (x) : Conversions for cases where the updater type is the same or smaller than the underlying
server type. For example, when calling updateBigDecimal on an underlying server decimal column, no
conversion is necessary.
Conver ted (y) : Conversions from numeric server types to Java language types where the conversion is
regular and follows Java language conversion rules. For these conversions, precision is always truncated
(never rounded) and overflow is handled as modulo of the destination (the smaller) type. For example,
calling updateDecimal on an underlying int column that contains "1.9999" will return "1", or if the
underlying decimal value is "3000000000" then the int value overflows to "-1294967296".
Data Dependent (z) : Conversions from underlying source data types to destination data types require
that the contained values can be converted into the destination types. No other conversions are
performed. If the value is too large for the getter type, the value isn't valid. For example, if updateString is
called on an int column that contains "53", the update succeeds; but if the underlying String value is "foo"
or "3000000000", an error is thrown.
When updateString is called on a binar y , varbinar y , varbinar y(max) , or image column data type, it handles
the String value as a hexadecimal string value.
When the SQL Server column data type is XML , the data value must be a valid XML . When calling updateBytes,
updateBinaryStream, or updateBlob methods, the data value should be the hexadecimal string representation of
the XML characters. For example:

<hello>world</hello> = 0x3C68656C6C6F3E776F726C643C2F68656C6C6F3E

Note that a byte-order mark (BOM) is required if the XML characters are in specific character encodings.

Setter method conversions


For the Java typed data passed to the set<Type>() methods of the SQLServerPreparedStatement class and the
SQLServerCallableStatement class, the following conversions apply.

The server tries any conversions and returns errors on failure.


In the case of the String data type, if the value exceeds the length of VARCHAR , it maps to LONGVARCHAR .
Similarly, NVARCHAR maps to LONGNVARCHAR if the value exceeds the supported length of NVARCHAR .
The same is true for byte[] . Values longer than VARBINARY become LONGVARBINARY .
There are two categories of conversions that are supported by the JDBC driver's setter methods:
Non-Lossy (x) : Conversions for numeric cases where the setter type is the same or smaller than the
underlying server type. For example, when calling setBigDecimal on an underlying server decimal
column, no conversion is necessary. For numeric to character cases, the Java numeric data type is
converted to a String . For example, calling setDouble with a value of "53" on a varchar(50) column
produces a character value "53" in that destination column.
Conver ted (y) : Conversions from a Java numeric type to an underlying server numeric type that is
smaller. This conversion is regular and follows SQL Server conversion conventions. Precision is always
truncated (never rounded) and overflow throws an unsupported conversion error. For example, using
updateDecimal with a value of "1.9999" on an underlying integer column results in a "1" in the
destination column; but if "3000000000" is passed, the driver throws an error.
Data Dependent (z) : Conversions from a Java String type to the underlying SQL Server data type
depends on the following conditions: The driver sends the String value to SQL Server and SQL Server
performs conversions, if necessary. If the sendStringParametersAsUnicode is set to true and the
underlying SQL Server data type is image , SQL Server doesn't allow converting nvarchar to image and
throws an SQLServerException. If the sendStringParametersAsUnicode is set to false and the underlying
SQL Server data type is image , SQL Server allows converting varchar to image and doesn't throw an
exception.
SQL Server performs the conversions and passes errors back to the JDBC driver when there are problems.
When the SQL Server column data type is XML , the data value must be a valid XML . When calling updateBytes,
updateBinaryStream, or updateBlob methods, the data value should be the hexadecimal string representation of
the XML characters. For example:

<hello>world</hello> = 0x3C68656C6C6F3E776F726C643C2F68656C6C6F3E

Note that a byte-order mark (BOM) is required if the XML characters are in specific character encodings.

Conversions on setObject
NOTE
Microsoft JDBC Drivers 4.2 (and higher) for SQL Server supports JDBC 4.1 and 4.2. For more detail on 4.1 and 4.2
datatype mappings and conversions see JDBC 4.1 compliance for the JDBC Driver and JDBC 4.2 compliance for the JDBC
Driver, in addition to the information below.

For the Java typed data passed to the setObject(<Type>) methods of the SQLServerPreparedStatement class,
the following conversions apply.
The setObject method with no specified target type uses the default mapping. In the case of the String data
type, if the value exceeds the length of VARCHAR , it maps to LONGVARCHAR . Similarly, NVARCHAR maps to
LONGNVARCHAR if the value exceeds the supported length of NVARCHAR . The same is true for byte[] .
Values longer than VARBINARY become LONGVARBINARY .
There are three categories of conversions that are supported by the JDBC driver's setObject methods:
Non-Lossy (x) : Conversions for numeric cases where the setter type is the same or smaller than the
underlying server type. For example, when calling setBigDecimal on an underlying server decimal
column, no conversion is necessary. For numeric to character cases, the Java numeric data type is
converted to a String . For example, calling setDouble with a value of "53" on a varchar(50) column will
produce a character value "53" in that destination column.
Conver ted (y) : Conversions from a Java numeric type to an underlying server numeric type that is
smaller. This conversion is regular and follows SQL Server conversion conventions. Precision is always
truncated-never rounded-and overflow throws an unsupported conversion error. For example, using
updateDecimal with a value of "1.9999" on an underlying integer column results in a "1" in the
destination column; but if "3000000000" is passed, the driver throws an error.
Data Dependent (z) : Conversions from a Java String type to the underlying SQL Server data type
depends on the following conditions: The driver sends the String value to SQL Server and SQL Server
performs conversions, if necessary. If the sendStringParametersAsUnicode connection property is set to
true and the underlying SQL Server data type is image , SQL Server doesn't allow converting nvarchar
to image and throws an SQLServerException. If the sendStringParametersAsUnicode is set to false and
the underlying SQL Server data type is image , SQL Server allows converting varchar to image and
doesn't throw an exception.
SQL Server performs the bulk of the set conversions and passes errors back to the JDBC driver when there are
problems. Client-side conversions are the exception and are performed only in the case of date , time ,
timestamp , Boolean , and String values.
When the SQL Server column data type is XML , the data value must be a valid XML . When calling
setObject(byte[], SQLXML), setObject(inputStream, SQLXML), or setObject(Blob, SQLXML) methods, the data
value should be the hexadecimal string representation of the XML characters. For example:

<hello>world</hello> = 0x3C68656C6C6F3E776F726C643C2F68656C6C6F3E

Note that a byte-order mark (BOM) is required if the XML characters are in specific character encodings.

See also
Understanding the JDBC driver data types
Using advanced data types
4/27/2022 • 6 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server uses the JDBC advanced data types to convert the SQL Server data
types to a format that can be understood by the Java programming language.

Remarks
The following table lists the default mappings between the advanced SQL Server, JDBC, and Java programming
language data types.

SQ L SERVER T Y P ES JDB C T Y P ES ( JAVA . SQ L . T Y P ES) JAVA L A N GUA GE T Y P ES

varbinary(max) LONGVARBINARY byte[] (default), Blob, InputStream,


String
image

text LONGVARCHAR String (default), Clob, InputStream

varchar(max)

ntext LONGVARCHAR String (default), Clob, NClob

nvarchar(max) LONGNVARCHAR (Java SE 6.0)

xml LONGVARCHAR String (default), InputStream, Clob,


byte[], Blob, SQLXML
SQLXML

Udt1 VARBINARY String (default), byte[], InputStream

sqlvariant SQLVARIANT Object

geometry VARBINARY byte[]

geography

1 The Microsoft JDBC Driverfor SQL Server supports sending and retrieving CLR UDTs as binary data but
doesn't support manipulation of the CLR metadata.
The following sections provide examples of how you can use the JDBC driver and the advanced data types.

BLOB and CLOB and NCLOB data types


The JDBC driver implements all the methods of the java.sql.Blob, java.sql.Clob, and java.sql.NClob interfaces.
NOTE
CLOB values can be used with SQL Server 2005 (9.x) (or later) large-value data types. Specifically, CLOB types can be used
with the varchar(max) and nvarchar(max) data types, BLOB types can be used with varbinar y(max) and image data
types, and NCLOB types can be used with ntext and nvarchar(max) .

Large value data types


In earlier versions of SQL Server, working with large-value data types required special handling. Large-value
data types are those that exceed the maximum row size of 8 KB. SQL Server introduces a max specifier for
varchar , nvarchar , and varbinar y data types to allow storage of values as large as 2^31 bytes. Table columns
and Transact-SQL variables can specify varchar(max) , nvarchar(max) , or varbinar y(max) data types.
The primary scenarios for working with large-value types involve retrieving them from a database, or adding
them to a database. The following sections describe different approaches to accomplish these tasks.
Retrieving large -value types from a database
When you retrieve a non-binary large-value data type-such as the varchar(max) data type-from a database,
one approach is to read that data as a character stream. In the following example, the executeQuery method of
the SQLServerStatement class is used to retrieve data from the database and return it as a result set. Then the
getCharacterStream method of the SQLServerResultSet class is used to read the large-value data from the result
set.

ResultSet rs = stmt.executeQuery("SELECT TOP 1 * FROM Test1");


rs.next();
Reader reader = rs.getCharacterStream(2);

NOTE
This same approach can also be used for the text , ntext , and nvarchar(max) data types.

When you retrieve a binary large-value data type-such as the varbinar y(max) data type-from a database, there
are several approaches that you can take. The most efficient approach is to read the data as a binary stream, as
in the following:

ResultSet rs = stmt.executeQuery("SELECT photo FROM mypics");


rs.next();
InputStream is = rs.getBinaryStream(2);

You can also use the getBytes method to read the data as a byte array, as in the following:

ResultSet rs = stmt.executeQuery("SELECT photo FROM mypics");


rs.next();
byte [] b = rs.getBytes(2);

NOTE
You can also read the data as a BLOB. However, this is less efficient than the two methods shown previously.

Adding large -value types to a database


Uploading large data with the JDBC driver works well for the memory-sized cases, and in the larger-than-
memory cases, streaming is the primary option. However, the most efficient way to upload large data is through
the stream interfaces.
Using a String or bytes is also an option, as in the following:

PreparedStatement pstmt = con.prepareStatement("INSERT INTO test1 (c1_id, c2_vcmax) VALUES (?, ?)");
pstmt.setInt(1, 1);
pstmt.setString(2, htmlStr);
pstmt.executeUpdate();

NOTE
This approach can also be used for values that are stored in text , ntext , and nvarchar(max) columns.

If you have an image library on the server and must upload entire binary image files to a varbinar y(max)
column, the most efficient method with the JDBC driver is to use streams directly, as in the following:

try (PreparedStatement pstmt = con.prepareStatement("INSERT INTO test1 (Col1, Col2) VALUES(?,?)")) {


File inputFile = new File("CLOBFile20mb.jpg");
try (FileInputStream inStream = new FileInputStream(inputFile)) {
int id = 1;
pstmt.setInt(1,id);
pstmt.setBinaryStream(2, inStream);
pstmt.executeUpdate();
}
}

NOTE
Using either the CLOB or BLOB method is not an efficient way to upload large data.

Modifying large -value types in a database


In most cases, the recommended method for updating or modifying large values on the database is to pass
parameters through the SQLServerPreparedStatement and SQLServerCallableStatement classes by using
Transact-SQL commands like UPDATE , WRITE , and SUBSTRING .
If you have to replace the instance of a word in a large text file, such as an archived HTML file, you can use a
Clob object, as in the following:

String SQL = "SELECT * FROM test1;";


try (Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)
ResultSet rs = stmt.executeQuery(SQL)) {
rs.next();

Clob clob = rs.getClob(2);


long pos = clob.position("dog", 1);
clob.setString(pos, "cat");
rs.updateClob(2, clob);
rs.updateRow();
}

Additionally, you could do all the work on the server and just pass parameters to a prepared UPDATE statement.
For more information about large-value types, see "Using Large-Value Types" in SQL Server Books Online.
XML data type
SQL Server provides an xml data type that lets you store XML documents and fragments in a SQL Server
database. The xml data type is a built-in data type in SQL Server, and is in some ways similar to other built-in
types, such as int and varchar . As with other built-in types, you can use the xml data type as a column type
when you create a table; as a variable type, a parameter type, or a function-return type; or in Transact-SQL CAST
and CONVERT functions.
In the JDBC driver, the xml data type can be mapped as a String, byte array, stream, CLOB, BLOB, or SQLXML
object. String is the default. Starting with the JDBC Driver version 2.0, the JDBC driver provides support for the
JDBC 4.0 API, which introduces the SQLXML interface. The SQLXML interface defines methods to interact and
manipulate XML data. The SQLXML data type maps to the SQL Serverxml data type. For more information
about how to read and write XML data from and to the relational database with the SQLXML Java data type, see
Supporting XML data.
The implementation of the xml data type in the JDBC driver provides support for the following:
Access to the XML as a standard Java UTF-16 string for most common programming scenarios
Input of UTF-8 and other 8-bit encoded XML
Access to the XML as a byte array with a leading BOM when encoded in UTF-16 for interchange with
other XML processors and disk files
SQL Server requires a leading BOM for UTF-16-encoded XML. The application must provide this when XML
parameter values are supplied as byte arrays. SQL Server always outputs XML values as UTF-16 strings with no
BOM or embedded encoding declaration. When XML values are retrieved as byte[], BinaryStream or Blob, a UTF-
16 BOM is pre-pended to the value.
For more information about the xml data type, see "xml Data Type" in SQL Server Books Online.

User-defined data type


The introduction of user-defined types (UDTs) in SQL Server 2005 (9.x) extends the SQL type system by letting
you store objects and custom data structures in a SQL Server database. UDTs can contain multiple data types
and can have behaviors, differentiating them from the traditional alias data types that consist of a single SQL
Server system data type. UDTs are defined by using any of the languages supported by the Microsoft .NET
common language runtime (CLR) that produce verifiable code. This includes Microsoft Visual C# and Visual
Basic .NET. The data is exposed as fields and properties of a .NET Framework-based class or structure, and
behaviors are defined by methods of the class or structure.
In SQL Server, a UDT can be used as the column definition of a table, as a variable in a Transact-SQL batch, or as
an argument of a Transact-SQL function or stored procedure.
For more information about user-defined data types, see "Using and Modifying Instances of User-defined Types"
in SQL Server Books Online.

Sql_variant data type


For information about sql_variant data type, see Using Sql_variant data type.

Spatial data types


For information about spatial data types, see Using Spatial Datatypes.

See also
Understanding the JDBC driver data types
Using Sql_variant data type
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Starting with version 6.3.0, the JDBC driver supports the sql_variant datatype. Sql_variant is also supported
when using features such as Table-Valued Parameters and BulkCopy, with some limitations. Not all data types
can be stored in the sql_variant data type. For a list of supported data types with sql_variant, see sql_variant
(Transact-SQL).

Populating and retrieving a table


Assuming one has a table with a sql_variant column as:

CREATE TABLE sampleTable (col1 sql_variant)

A sample script to insert values using statement:

try (Statement stmt = connection.createStatement()){


stmt.execute("insert into sampleTable values (1)");
}

Inserting value using prepared statement:

try (PreparedStatement preparedStatement = con.prepareStatement("insert into sampleTable values (?)")) {


preparedStatement.setObject(1, 1);
preparedStatement.execute();
}

If the underlying type of the data being passed is known, the respective setter can be used. For instance,
preparedStatement.setInt() can be used when inserting an integer value.

try (PreparedStatement preparedStatement = con.prepareStatement("insert into table values (?)")) {


preparedStatement.setInt (1, 1);
preparedStatement.execute();
}

For reading values from the table, the respective getters can be used. For example, getInt() or getString()
methods can be used if the values coming from the server are known:

try (SQLServerResultSet resultSet = (SQLServerResultSet) stmt.executeQuery("select * from sampleTable ")) {


resultSet.next();
resultSet.getInt(1); //or rs.getString(1); or rs.getObject(1);
}

Using stored procedures with sql_variant


Having a stored procedure such as:
String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT AS SELECT TOP 1 @p0=col1 FROM
sampleTable ";

Output parameters must be registered:

try (CallableStatement callableStatement = con.prepareCall(" {call " + inputProc + " (?) }")) {
callableStatement.registerOutParameter(1, microsoft.sql.Types.SQL_VARIANT);
callableStatement.execute();
}

Limitations of sql_variant
When using TVP to populate a table with a datetime / smalldatetime / date value stored in a sql_variant,
calling getDateTime() / getSmallDateTime() / getDate() on a ResultSet doesn't work and throws the
following exception:
Java.lang.String cannot be cast to java.sql.Timestamp

Workaround: use getString() or getObject() instead.


Using TVP to populate a table and send a null value in a sql_variant isn't supported. Trying to do that
results in an exception:
Inserting null value with column type sql_variant in TVP is not supported.

See also
Understanding the JDBC driver data types
Using spatial data types
4/27/2022 • 6 minutes to read • Edit Online

Download JDBC Driver


Spatial data types (Geometry and Geography) are supported starting JDBC Driver preview release 6.5.0. Spatial
data types are currently not supported with stored procedures, Table Valued Parameters (TVP), BulkCopy, and
Always Encrypted. This page shows various use cases of Geometry and Geography data types with the JDBC
Driver. For an overview on spatial data types, check Spatial Data Types Overview page.

Creating a geometry / geography object


There are two main ways to create a Geometry / Geography object - either convert from a Well-Known Text
(WKT) or an internal SQL Server format (CLR).
Creating from WKT

String geoWKT = "LINESTRING(1 0, 0 1, -1 0)";


Geometry geomWKT = Geometry.STGeomFromText(geoWKT, 0);
Geography geogWKT = Geography.STGeomFromText(geoWKT, 4326);

This code will create a LINESTRING Geometry object with Spatial Reference System Identifier (SRID) 0, and a
Geography object with SRID 4326.
Creating from CLR

byte[] geomCLR =
Hex.decodeHex("00000000010403000000000000000000F03F00000000000000000000000000000000000000000000F03F000000000
000F0BF000000000000000001000000010000000001000000FFFFFFFF0000000002".toCharArray());
byte[] geogCLR =
Hex.decodeHex("E61000000104030000000000000000000000000000000000F03F000000000000F03F0000000000000000000000000
0000000000000000000F0BF01000000010000000001000000FFFFFFFF0000000002".toCharArray());

Geometry geomWKT = Geometry.deserialize(geomCLR);


Geography geogWKT = Geography.deserialize(geogCLR);

This code will create a Geometry and Geography object that is equivalent to the ones created from the WKT
previously.

Working with a Geometry / Geography object


Assuming the user has a table on SQL Server like below:

CREATE TABLE sampleTable (c1 geometry)

A sample script to insert a Geometry value would be:


String geoWKT = "LINESTRING(1 0, 0 1, -1 0)";
Geometry geomWKT = Geometry.STGeomFromText(geoWKT, 0);
SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement("insert into
sampleTable values (?)");
pstmt.setGeometry(1, geomWKT);
pstmt.execute();

The same can be done for the Geography counterpart, using a Geography column and setGeography()
method.
To read a Geometry / Geography column:

try(SQLServerResultSet rs = (SQLServerResultSet)stmt.executeQuery("select * from geomTable")) {


while(rs.next()){
rs.getGeometry(1);
}
}

The same can be done for the Geography counterpart, using a Geography column and getGeography()
method.

Newly introduced APIs


These methods are the new public APIs that have been introduced with this addition, in the classes
SQLSer verPreparedStatement , SQLSer verResultSet , Geometr y , and Geography .
SQLServerPreparedStatement
M ET H O D DESC RIP T IO N

void setGeometry(int n, Geometry x) Sets the designated parameter to the given


microsoft.sql.Geometry Class object.

void setGeography(int n, Geography x) Sets the designated parameter to the given


microsoft.sql.Geography Class object.

SQLServerResultSet
M ET H O D DESC RIP T IO N

Geometry getGeometry(int colunIndex) Returns the value of the designated column in the current
row of this ResultSet object as a
com.microsoft.sqlserver.jdbc.Geometry object in the Java
programming language.

Geometry getGeometry(String columnName) Returns the value of the designated column in the current
row of this ResultSet object as a
com.microsoft.sqlserver.jdbc.Geometry object in the Java
programming language.

Geography getGeography(int colunIndex) Returns the value of the designated column in the current
row of this ResultSet object as a
com.microsoft.sqlserver.jdbc.Geography object in the Java
programming language.
M ET H O D DESC RIP T IO N

Geography getGeography(String columnName) Returns the value of the designated column in the current
row of this ResultSet object as a
com.microsoft.sqlserver.jdbc.Geography object in the Java
programming language.

Geometry
M ET H O D DESC RIP T IO N

Geometry STGeomFromText(String wkt , int SRID ) Constructor for a Geometry instance from an Open
Geospatial Consortium (OGC) Well-Known Text (WKT)
representation augmented with any Z (elevation) and M
(measure) values carried by the instance.

Geometry STGeomFromWKB(byte[] wkb ) Constructor for a Geometry instance from an Open


Geospatial Consortium (OGC) Well-Known Binary (WKB)
representation. Note: This method currently uses internal
SQL Server format (CLR) to create a Geometry instance,
which is a known issue in the driver and is planned to be
changed to accept WKB data instead. For existing users who
are already using this method, consider switching to
deserialize(byte) instead.

Geometries deserialize(byte[] clr) Constructor for a Geometry instance from an internal SQL
Server format for spatial data.

Geometry parse(String wkt) Constructor for a Geometry instance from an Open


Geospatial Consortium (OGC) Well-Known Text (WKT)
representation. Spatial Reference Identifier is defaulted to 0.

Geometry point(double x, double y, int SRID) Constructor for a Geometry instance that represents a Point
instance from its X and Y values and a Spatial Reference
Identifier.

String STAsText() Returns the Open Geospatial Consortium (OGC) Well-


Known Text (WKT) representation of a Geometry instance.
This text won't contain any Z (elevation) or M (measure)
values carried by the instance.

byte[] STAsBinary() Returns the internal SQL Server format (CLR) representation
of a Geometry instance. This value won't contain any Z or M
values carried by the instance.

byte[] serialize() Returns the bytes that represent an internal SQL Server
format of Geometry type.

boolean hasM() Returns if the object contains an M (measure) value.

boolean hasZ() Returns if the object contains a Z (elevation) value.

Double getX() Returns the X coordinate value.

Double getY() Returns the Y coordinate value.

Double getM() Returns the M (measure) value of the object.


M ET H O D DESC RIP T IO N

Double getZ() Returns the Z (elevation) value of the object.

int getSrid() Returns the Spatial Reference Identifier (SRID) value.

boolean isNull() Returns if the Geometry object is null.

int STNumPoints() Returns the number of points in the Geometry object.

String STGeometryType() Returns the Open Geospatial Consortium (OGC) type name
represented by a geometry instance.

String asTextZM() Returns the Well-Known Text (WKT) representation of the


Geometry object.

String toString() Returns the String representation of the Geometry object.

Geography
M ET H O D DESC RIP T IO N

Geography STGeomFromText(String wkt, int SRID) Constructor for a Geography instance from an Open
Geospatial Consortium (OGC) Well-Known Text (WKT)
representation augmented with any Z (elevation) and M
(measure) values carried by the instance.

Geography STGeomFromWKB(byte[] wkb ) Constructor for a Geography instance from an Open


Geospatial Consortium (OGC) Well-Known Binary (WKB)
representation. Note: This method currently uses internal
SQL Server format (CLR) to create a Geometry instance, but
in the future this method will be changed to accept WKB
data instead, as the SQL Server counterpart of this method
(STGeomFromWKB) uses WKB. For existing users who are
already using this method, consider switching to
deserialize(byte) instead.

Geography deserialize(byte[] clr) Constructor for a Geography instance from an internal SQL
Server format for spatial data.

Geography parse(String wkt) Constructor for a Geography instance from an Open


Geospatial Consortium (OGC) Well-Known Text (WKT)
representation. Spatial Reference Identifier is defaulted to 0.

Geography point(double lon, double lat, int SRID) Constructor for a Geography instance that represents a
Point instance from its longitude and latitude and a Spatial
Reference Identifier.

String STAsText() Returns the Open Geospatial Consortium (OGC) Well-


Known Text (WKT) representation of a Geography instance.
This text won't contain any Z (elevation) or M (measure)
values carried by the instance.

byte[] STAsBinary()) Returns the internal SQL Server format (CLR) representation
of a Geography instance. This value won't contain any Z or
M values carried by the instance.
M ET H O D DESC RIP T IO N

byte[] serialize() Returns the bytes that represent an internal SQL Server
format of Geography type.

boolean hasM() Returns if the object contains an M (measure) value.

boolean hasZ() Returns if the object contains a Z (elevation) value.

Double getLatitude() Returns the latitude value.

Double getLongitude() Returns the longitude value.

Double getM() Returns the M (measure) value of the object.

Double getZ() Returns the Z (elevation) value of the object.

int getSrid() Returns the Spatial Reference Identifier (SRID) value.

boolean isNull() Returns if the Geography object is null.

int STNumPoints() Returns the number of points in the Geography object.

String STGeographyType() Returns the Open Geospatial Consortium (OGC) type name
represented by a geography instance.

String asTextZM() Returns the Well-Known Text (WKT) representation of the


Geography object.

String toString() Returns the String representation of the Geography object.

Limitations of spatial data types


1. The spatial sub data types CircularString , CompoundCur ve , Cur vePolygon , and FullGlobe are only
supported starting from SQL Server 2012 and above.
2. Always Encrypted can't be used with spatial data types.
3. Stored procedures, TVP, and BulkCopy operations are currently not supported with spatial data types.

See also
Spatial data types sample (JDBC)
User defined types
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


User-defined types (UDTs) were introduced in SQL Server 2005 (9.x) to allow a developer to extend the server's
scalar type system by storing common language runtime (CLR) objects in a SQL Server database. UDTs can
contain multiple elements and can have behaviors, unlike the traditional alias data types, that consist of a single
SQL Server system data type. Previously, UDTs were restricted to a maximum size of 8 kilobytes. In SQL Server
2008, support was added for UDTs larger than 64 kilobytes. Beginning in version 3.0, the JDBC Driver also
supports UDTs larger than 64 kilobytes when you specify the UserDefined format.
There is no behavior change for UDTs that are less than or equal to 8,000 bytes, but larger UDTs are supported
and report their size as "unlimited".

See also
Understanding the JDBC driver data types
Configuring how java.sql.Time values are sent
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


If you use a java.sql.Time object or the java.sql.Types.TIME JDBC type to set a parameter, you can configure how
the java.sql.Time value is sent to the server; either as a SQL Server time type or as a datetime type.
This scenario applies when using one of the following methods:
SQLServerCallableStatement.registerOutParameter(int, int)
SQLServerCallableStatement.registerOutParameter(int, int, int)
SQLServerCallableStatement.setTime
SQLServerPreparedStatement.setTime
SQLServerCallableStatement.setObject
SQLServerPreparedStatement.setObject

SendTimeAsDatetime
You can configure how the java.sql.Time value is sent by using the sendTimeAsDatetime connection property.
For more information, see Setting the Connection Properties.
You can programmatically modify the value of the sendTimeAsDatetime connection property with
SQLServerDataSource.setSendTimeAsDatetime.
Versions of SQL Server earlier than SQL Server 2008 don't support the time data type, so applications using
java.sql.Time typically store java.sql.Time values either as datetime or smalldatetime SQL Server data types.
If you want to use the datetime and smalldatetime SQL Server data types when working with java.sql.Time
values, you should set the sendTimeAsDatetime connection property to true . If you want to use the time SQL
Server data type when working with java.sql.Time values, you should set the sendTimeAsDatetime connection
property to false .
Sending java.sql.Time values into a parameter whose data type can also store the date, that default dates are
different depending on whether the java.sql.Time value is sent as a datetime (1/1/1970) or time (1/1/1900)
value. For more information about data conversions when sending data to a SQL Server, see Using Date and
Time Data.
In SQL Server JDBC Driver 3.0, sendTimeAsDatetime is true by default. In a future release, the
sendTimeAsDatetime connection property may be set to false by default.
To ensure that your application continues to work as expected regardless of the default value of the
sendTimeAsDatetime connection property, you can:
Use java.sql.Time when working with the time SQL Server data type.
Use java.sql.Timestamp when working with the datetime , smalldatetime , and datetime2 SQL Server data
types.
SendTimeAsDatetime must be false for encrypted columns as encrypted columns don't support the conversion
from time to datetime. Beginning with Microsoft JDBC Driver 6.0 for SQL Server, the SQLServerConnection class
has the following two methods to set/get the value of the sendTimeAsDatetime property.
public boolean getSendTimeAsDatetime()
public void setSendTimeAsDatetime(boolean sendTimeAsDateTimeValue)

See also
Understanding the JDBC driver data types
Programming with SQLXML
4/27/2022 • 5 minutes to read • Edit Online

Download JDBC Driver


This section describes how to use the Microsoft JDBC Driver for SQL Server API methods to store and retrieve
an XML document in and from a relational database with SQLXML objects.
This section also contains information about the types of SQLXML objects and provides a list of important
guidelines and limitations when using SQLXML objects.

Reading and writing XML data with SQLXML objects


The following list describes how to use the Microsoft JDBC Driver for SQL Server API methods to read and write
XML data with SQLXML objects:
To create a SQLXML object, use the createSQLXML method of the SQLServerConnection class. Note that
this method creates a SQLXML object without any data. To add xml data to SQLXML object, call one of the
following methods that are specified in the SQLXML interface: setResult, setCharacterStream,
setBinaryStream, or setString.
To retrieve the SQLXML object itself, use the getSQLXML methods of the SQLServerResultSet class or the
SQLServerCallableStatement class.
To retrieve the xml data from a SQLXML object, use one of the following methods that are specified in the
SQLXML interface: getSource, getCharacterStream, getBinaryStream, or getString.
To update the xml data in a SQLXML object, use the updateSQLXML method of the SQLServerResultSet
class.
To store a SQLXML object in a database table column of type xml , use the setSQLXML methods of the
SQLServerPreparedStatement class or the SQLServerCallableStatement class.
The example code in SQLXML data type sample demonstrates how to perform these common API tasks.

Readable and writable SQLXML objects


The following table lists which types of SQLXML objects are supported by the setter, getter, and updater
methods provided by the JDBC API. The columns in the table refer to the following:
The Method Name column lists the supported getter, setter, and updater methods in the JDBC API.
The Getter SQLXML Object column represents a SQLXML object, which is created by either the
getSQLXML method of the SQLServerCallableStatement class or the getSQLXML method of the
SQLServerResultSet class.
The Setter SQLXML Object column represents a SQLXML object, which is created by the
createSQLXML method of the SQLServerConnection class. Note that the setter methods below accept
only a SQLXML object created by the createSQLXML method.
GET T ER SQ L XM L O B JEC T SET T ER SQ L XM L O B JEC T

M ET H O D N A M E ( REA DA B L E) ( W RITA B L E)

CallableStatement.setSQLXML() Not Supported Supported

CallableStatement.setObject() Not Supported Supported

PreparedStatement.setSQLXML() Not Supported Supported

PreparedStatement.setObject() Not Supported Supported

ResultSet.updateSQLXML() Not Supported Supported

ResultSet.updateObject() Not Supported Supported

ResultSet.getSQLXML() Supported Not Supported

CallableStatement.getSQLXML() Supported Not Supported

As shown in the table above, the setter SQLXML methods will not work with the readable SQLXML objects;
similarly, the getter methods will not work with the writable SQLXML objects.
If the application invokes the setObject method by specifying a scale or a length parameter with a SQLXML
object, the scale or length parameter is ignored.

Guidelines and limitations when using SQLXML objects


Applications can use SQLXML objects to read and write the XML data from and to the database. The following
list provides information about specific limitations and guidance when using SQLXML objects:
A SQLXML object can be valid only for the duration of the transaction in which it was created.
A SQLXML object received from a getter method can only be used to read data.
A SQLXML object created by the connection object can only be used to write data.
The application can invoke only one getter method on a readable SQLXML object to read data. After the
getter method is invoked, all other getter or setter methods on the same SQLXML object fail.
The application can invoke only the free method on the SQLXML object after it is read or written to.
However, it is still possible to process the returned stream or source as long as the underlying column or
parameter is active. If the underlying column or parameter becomes inactive, the stream or source
associated with the SQLXML object will be closed. If the underlying column or parameter is no longer
valid, the underlying data will not be available for the Stream, Simple API for XML (SAX), and Streaming
API for XML (StAX) getters.
The application can invoke only one setter method on a writable SQLXML object. After the setter method
is invoked, all other setter or getter methods on the same SQLXML object fail.
To set data on the SQLXML object, the application must use the appropriate setter method and the
functions in the returned object.
The getSQLXML methods of the SQLServerCallableStatement class and the SQLServerResultSet class
returns null data if the underlying column is null .
The setter objects can be valid through the connection they are created within.
Applications are not allowed to set a null value by using the setter methods provided by the SQLXML
interface. The applications can set an empty string ("") by using the setter methods provided in the
SQLXML interface. To set a null value, the applications should call one of the following:
The setNull methods of the SQLServerCallableStatement class and SQLServerPreparedStatement
class.
The setObject methods of the SQLServerCallableStatement class and
SQLServerPreparedStatement class.
The setSQLXML methods of the SQLServerCallableStatement class and
SQLServerPreparedStatement class with a null parameter value.
When working with XML documents, we recommend using Simple API for XML (SAX) and Streaming API
for XML (StAX) parsers instead of Document Object Model (DOM) parsers for performance reasons.
XML parsers cannot handle empty values. However, SQL Server allows applications to retrieve and store empty
values from and to database columns of the XML data type. That means that when parsing the XML data, if the
underlying value is empty, an exception is thrown by the parser. For DOM outputs, the JDBC driver catches that
exception and throws an error. For SAX and Stax outputs, the error comes from the parser directly.

Adaptive buffering and SQLXML support


The binary and character streams returned by the SQLXML object obey the adaptive or full buffering modes. On
the other hand, if the XML parsers are not streams, they will not obey the adaptive or full settings. For more
information about adaptive buffering, see Using Adaptive Buffering.

See also
Supporting XML data
Supporting XML data
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


SQL Server provides an xml data type that lets you store XML documents and fragments in a SQL Server
database. The xml data type is a built-in data type in SQL Server, and is in some ways similar to other built-in
types, such as int and varchar . Like other built-in types, you can use the xml data type as: a variable type, a
parameter type, a function-return type, or a column type when you create a table; or in Transact-SQL CAST and
CONVERT functions. In the JDBC driver, the xml data type can be mapped as a String, byte array, stream, CLOB,
BLOB, or SQLXML object. String is the default mapping.
The JDBC driver provides support for the JDBC 4.0 API, which introduces the SQLXML interface. The SQLXML
interface defines methods to interact with and manipulate XML data. The SQLXML is a JDBC 4.0 data type and it
maps to the SQL Serverxml data type. Therefore, in order to use the SQLXML data type in your applications, you
must set the classpath to include the sqljdbc4.jar file. If the application tries to use the sqljdbc3.jar when
accessing the SQLXML object and its methods, an exception is thrown.

IMPORTANT
SQL Server always validates the XML data before storing it in the database column. Applications can use SQLXML data
type, because the JDBC driver maps it to the xml data type automatically. The SQLXML support is available in
sqljdbc4.jar. See System Requirements for the JDBC driver for the list of JRE versions supported by the Microsoft JDBC
Driver for SQL Server.

The articles in this section describe the SQLXML interface and how to program against the SQLXML data type
by using the JDBC API methods.

In this section
A RT IC L E DESC RIP T IO N

SQLXML interface Describes the SQLXML interface and its methods.

Programming with SQLXML Describes how to use the Microsoft JDBC Driver for SQL
Server API methods to store and retrieve an XML data in
and from a relational database with the SQLXML Java data
type. Also contains information about the types of SQLXML
objects and provides a list of important guidelines and
limitations when using SQLXML objects.

See also
Understanding the JDBC driver data types
SQLXML interface
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The JDBC driver provides support for the JDBC 4.0 API, which introduces the java.sql.SQLXML interface. The
SQLXML interface defines methods to interact and manipulate XML data. The SQLXML data type maps to the
SQL Serverxml data type.
The SQLXML interface provides methods for accessing the XML value as a String , a Reader or Writer , or as a
Stream . The XML value may also be accessed through a Source or set as a Result , which are used with XML
Parser APIs such as Document Object Model (DOM), Simple API for XML (SAX), and Streaming API for XML
(StAX), as well as with XSLT transforms and XPath.

Remarks
The following table describes the methods defined in the SQLXML interface:

M ET H O D SY N TA X M ET H O D DESC RIP T IO N

void free() This method frees the SQLXML object and releases the
resources that it holds.

InputStream getBinaryStream() Returns an input stream to read data from the SQLXML.

Reader getCharacterStream() Returns the XML data as a java.io.Reader object or as a


stream of characters.

T extends Source T getSource(Class<T> sourceClass) Returns a Source for reading the XML value specified by
this SQLXML object.

Note: The getSource method supports the following


sources: javax.xml.transform.dom.DOMSource,
javax.xml.transform.sax.SAXSource,
javax.xml.transform.stax.StAXSource, and java.io.InputStream.

String getString() Returns a string representation of the XML value designated


by this SQLXML object.

OutputStream setBinaryStream() Retrieves a stream that can be used to write the XML value
that this SQLXML object represents.

Writer setCharacterStream() Returns a stream to be used to write the XML value that
this SQLXML object represents.

T extends Result T setResult(Class<T> resultClass) Returns a Result for setting the XML value specified by this
SQLXML object.

Note: The setResult method supports the following sources:


javax.xml.transform.dom.DOMResult,
javax.xml.transform.sax.SAXResult,
javax.xml.transform.stax.StaxResult, and java.io.OutputStream.
M ET H O D SY N TA X M ET H O D DESC RIP T IO N

void setString(String value) Sets the XML value designated by this SQLXML object to the
specified String representation.

The applications can read and write XML values to or from an SQLXML object only once.
When the free() method is called, a SQLXML object becomes invalid and is neither readable nor writeable. If the
application tries to invoke a method on that SQLXML object other than the free() method, an exception is
thrown.
The SQLXML object becomes neither readable nor writable when the application calls any of the following getter
methods: getSource, getCharacterStream, getBinaryStream, and getString.
The SQLXML object becomes neither writeable nor readable when the application calls any of the following
setter methods: setResult, setCharacterStream, setBinaryStream, and setString.

See also
Supporting XML data
Using statements with SQL
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you work with data in a SQL Server database by using the Microsoft JDBC Driver for SQL Server and
inline SQL statements, there are different classes that you can use. Which class you use depends on the type of
SQL statement that you want to run.
If your SQL statement contains no IN parameters, use the SQLServerStatement class, but if it does contain IN
parameters, use the SQLServerPreparedStatement class.

NOTE
If you need to use SQL statements that contain both IN and OUT parameters, you must implement them as stored
procedures and call them by using the SQLServerCallableStatement class. For more information about using stored
procedures, see Using statements with stored procedures.

The following sections describe the different scenarios for working with data in a SQL Server database by using
SQL statements.

In This Section
TO P IC DESC RIP T IO N

Using an SQL statement with no parameters Describes how to use SQL statements that contain no
parameters.

Using an SQL statement with parameters Describes how to use SQL statements that contain
parameters.

Using an SQL statement to modify database objects Describes how to use SQL statements to modify database
objects.

Using an SQL statement to modify data Describes how to use SQL statements to modify data in a
database.

See also
Using Statements with the JDBC driver
Using an SQL statement with no parameters
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


To work with data in a SQL Server database by using an SQL statement that contains no parameters, you can
use the executeQuery method of the SQLServerStatement class to return a SQLServerResultSet that will contain
the requested data. First create a SQLServerStatement object by using the createStatement method of the
SQLServerConnection class.
In the following example, an open connection to the sample database is passed in to the executeStatement
function. From there, a SQL statement is constructed and run. Finally, the results are read from the result set.

public static void executeStatement(Connection con) {


try(Statement stmt = con.createStatement();) {
String SQL = "SELECT LastName, FirstName FROM Person.Contact ORDER BY LastName";
ResultSet rs = stmt.executeQuery(SQL);

while (rs.next()) {
System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

For more information about using result sets, see Managing result sets with the JDBC driver.

See also
Using statements with SQL
Using an SQL statement with parameters
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


To work with data in a SQL Server database by using an SQL statement that contains IN parameters, you can use
the executeQuery method of the SQLServerPreparedStatement class to return a SQLServerResultSet that will
contain the requested data. To do this, you must first create a SQLServerPreparedStatement object by using the
prepareStatement method of the SQLServerConnection class.
When you construct your SQL statement, the IN parameters are specified by using the ? (question mark)
character, which acts as a placeholder for the parameter values that will later be passed into the SQL statement.
To specify a value for a parameter, you can use one of the setter methods of the SQLServerPreparedStatement
class. The setter method that you use is determined by the data type of the value that you want to pass into the
SQL statement.
When you pass a value to the setter method, you must specify not only the actual value to be used in the SQL
statement, but also the parameter's ordinal placement in the SQL statement. For example, if your SQL statement
contains a single parameter, its ordinal value will be 1. If the statement contains two parameters, the first ordinal
value will be 1, while the second ordinal value will be 2.
In the following example, an open connection to the sample database is passed in to the function, an SQL
prepared statement is constructed and run with a single String parameter value, and then the results are read
from the result set.

public static void executeStatement(Connection con) {


try(PreparedStatement pstmt = con.prepareStatement("SELECT LastName, FirstName FROM Person.Contact WHERE
LastName = ?");) {
pstmt.setString(1, "Smith");
ResultSet rs = pstmt.executeQuery();

while (rs.next()) {
System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

See also
Using statements with SQL
Using an SQL statement to modify database objects
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


To modify SQL Server database objects by using an SQL statement, you can use the executeUpdate method of
the SQLServerStatement class. The executeUpdate method will pass the SQL statement to the database for
processing, and then return a value of 0 because no rows were affected.
To do this, you must first create a SQLServerStatement object by using the createStatement method of the
SQLServerConnection class.

NOTE
SQL statements that modify objects within a database are called Data Definition Language (DDL) statements. These
include statements such as CREATE TABLE , DROP TABLE , CREATE INDEX , and DROP INDEX . For more information
about the types of DDL statements that are supported by SQL Server, see SQL Server Books Online.

In the following example, an open connection to the sample database is passed in to the function, an SQL
statement is constructed that will create the simple TestTable in the database, and then the statement is run and
the return value is displayed.

public static void executeUpdateStatement(Connection con) {


try(Statement stmt = con.createStatement();) {
String SQL = "CREATE TABLE TestTable (Col1 int IDENTITY, Col2 varchar(50), Col3 int)";
int count = stmt.executeUpdate(SQL);
System.out.println("ROWS AFFECTED: " + count);
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

See also
Using statements with SQL
Using an SQL statement to modify data
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


To modify the data that is contained in a SQL Server database by using an SQL statement, you can use the
executeUpdate method of the SQLServerStatement class. The executeUpdate method will pass the SQL
statement to the database for processing, and then return a value that indicates the number of rows that were
affected.
To do this, you must first create a SQLServerStatement object by using the createStatement method of the
SQLServerConnection class.
In the following example, an open connection to the sample database is passed in to the function, an SQL
statement is constructed that adds new data to the table, and then the statement is run and the return value is
displayed.

public static void executeUpdateStatement(Connection con) {


try(Statement stmt = con.createStatement();) {
String SQL = "INSERT INTO TestTable (Col2, Col3) VALUES ('a', 10)";
int count = stmt.executeUpdate(SQL);
System.out.println("ROWS AFFECTED: " + count);
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

NOTE
If you must use an SQL statement that contains parameters to modify the data in a SQL Server database, you should use
the executeUpdate method of the SQLServerPreparedStatement class.
If the column that you are trying to insert data into contains special characters such as spaces, you must provide the
values to be inserted, even if they are default values. If you do not, the insert operation will fail.
If you want the JDBC driver to return all update counts, including update counts returned by any triggers that may have
fired, set the lastUpdateCount connection string property to "false". For more information about the lastUpdateCount
property, see Setting the connection properties.

See also
Using statements with SQL
Using statements with stored procedures
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


A stored procedure is a database procedure, similar to a procedure in other programming languages, which is
contained within the database itself. In SQL Server, stored procedures can be created by using Transact-SQL, or
by using the common language runtime (CLR) and one of the Visual Studio programming languages such as
Visual Basic or C#. Generally, SQL Server stored procedures can do the following:
Accept input parameters and return multiple values in the form of output parameters to the calling
procedure or batch.
Contain programming statements that perform operations in the database, including calling other
procedures.
Return a status value to a calling procedure or batch to indicate success or failure (and the reason for
failure).

NOTE
For more information about SQL Server stored procedures, see "Understanding Stored Procedures" in SQL Server Books
Online.

To work with data in a SQL Server database by using a stored procedure, the Microsoft JDBC Driver for SQL
Server provides the SQLServerStatement, SQLServerPreparedStatement, and SQLServerCallableStatement
classes. Which class you use depends on whether IN (input) or OUT (output) parameters are required by the
stored procedure. If the stored procedure requires no IN or OUT parameters, you can use the
SQLServerStatement class; if the stored procedure will be called multiple times, or requires only IN parameters,
you can use the SQLServerPreparedStatement class. If the stored procedure requires both IN and OUT
parameters, you should use the SQLServerCallableStatement class. It is only when the stored procedure requires
OUT parameters that you will need the overhead of using the SQLServerCallableStatement class.

NOTE
Stored procedures can also return update counts and multiple result sets. For more information, see Using a stored
procedure with an update count and Using multiple result sets.

When you use the JDBC driver to call a stored procedure with parameters, you must use the call SQL escape
sequence together with the prepareCall method of the SQLServerConnection class. The complete syntax for the
call escape sequence is as follows:

{[?=]call procedure-name[([parameter][,[parameter]]...)]}

NOTE
For more information about the call and other SQL escape sequences, see Using SQL escape sequences.

The topics in this section describe the ways that you can call SQL Server stored procedures by using the JDBC
driver and the call SQL escape sequence.
In this section
TO P IC DESC RIP T IO N

Using a stored procedure with no parameters Describes how to use the JDBC driver to run stored
procedures that contain no input or output parameters.

Using a stored procedure with input parameters Describes how to use the JDBC driver to run stored
procedures that contain input parameters.

Using a stored procedure with output parameters Describes how to use the JDBC driver to run stored
procedures that contain output parameters.

Using a stored procedure with a return status Describes how to use the JDBC driver to run stored
procedures that contain return status values.

Using a stored procedure with an update count Describes how to use the JDBC driver to run stored
procedures that return update counts.

See also
Using statements with the JDBC driver
Using a stored procedure with no parameters
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The simplest kind of SQL Server stored procedure that you can call is one that contains no parameters and
returns a single result set. The Microsoft JDBC Driver for SQL Server provides the SQLServerStatement class,
which you can use to call this kind of stored procedure and process the data that it returns.
When you use the JDBC driver to call a stored procedure without parameters, you must use the call SQL
escape sequence. The syntax for the call escape sequence with no parameters is as follows:
{call procedure-name}

NOTE
For more information about the SQL escape sequences, see Using SQL escape sequences.

As an example, create the following stored procedure in the sample database:

CREATE PROCEDURE GetContactFormalNames


AS
BEGIN
SELECT TOP 10 Title + ' ' + FirstName + ' ' + LastName AS FormalName
FROM Person.Contact
END

This stored procedure returns a single result set that contains one column of data, which is a combination of the
title, first name, and last name of the top 10 contacts that are in the Person.Contact table.
In the following example, an open connection to the sample database is passed in to the function, and the
executeQuery method is used to call the GetContactFormalNames stored procedure.

public static void executeSprocNoParams(Connection con) throws SQLException {


try(Statement stmt = con.createStatement();) {

ResultSet rs = stmt.executeQuery("{call dbo.GetContactFormalNames}");


while (rs.next()) {
System.out.println(rs.getString("FormalName"));
}
}
}

See also
Using statements with stored procedures
Using a stored procedure with input parameters
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


A SQL Server stored procedure that you can call is one that contains one or more IN parameters, which are
parameters that can be used to pass data into the stored procedure. The Microsoft JDBC Driver for SQL Server
provides the SQLServerPreparedStatement class, which you can use to call this kind of stored procedure and to
process the data that it returns.
When you use the JDBC driver to call a stored procedure with IN parameters, you must use the call SQL
escape sequence together with the prepareCall method of the SQLServerConnection class. The syntax for the
call escape sequence with IN parameters is as follows:

{call procedure-name[([parameter][,[parameter]]...)]}

NOTE
For more information about the SQL escape sequences, see Using SQL escape sequences.

When you construct the call escape sequence, specify the IN parameters by using the ? (question mark)
character. This character acts as a placeholder for the parameter values that will be passed into the stored
procedure. To specify a value for a parameter, you can use one of the setter methods of the
SQLServerPreparedStatement class. The setter method that you can use is determined by the data type of the IN
parameter.
When you pass a value to the setter method, you must specify not only the actual value that will be used in the
parameter, but also the ordinal placement of the parameter in the stored procedure. For example, if your stored
procedure contains a single IN parameter, its ordinal value will be 1. If the stored procedure contains two
parameters, the first ordinal value will be 1, and the second ordinal value will be 2.
As an example of how to call a stored procedure that contains an IN parameter, use the
uspGetEmployeeManagers stored procedure in the sample database. This stored procedure accepts a single
input parameter named EmployeeID, which is an integer value, and it returns a recursive list of employees and
their managers based on the specified EmployeeID. The Java code for calling this stored procedure is as follows:

public static void executeSprocInParams(Connection con) throws SQLException {


try(PreparedStatement pstmt = con.prepareStatement("{call dbo.uspGetEmployeeManagers(?)}"); ) {

pstmt.setInt(1, 50);
ResultSet rs = pstmt.executeQuery();

while (rs.next()) {
System.out.println("EMPLOYEE:");
System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));
System.out.println("MANAGER:");
System.out.println(rs.getString("ManagerLastName") + ", " + rs.getString("ManagerFirstName"));
System.out.println();
}
}
}
See also
Using statements with stored procedures
Using a stored procedure with output parameters
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


A SQL Server stored procedure that you can call is one that returns one or more OUT parameters, which are
parameters that the stored procedure uses to return data back to the calling application. The Microsoft JDBC
Driver for SQL Server provides the SQLServerCallableStatement class, which you can use to call this kind of
stored procedure and process the data that it returns.
When you call this kind of stored procedure by using the JDBC driver, you must use the call SQL escape
sequence together with the prepareCall method of the SQLServerConnection class. The syntax for the call
escape sequence with OUT parameters is the following:
{call procedure-name[([parameter][,[parameter]]...)]}

NOTE
For more information about the SQL escape sequences, see Using SQL escape sequences.

When you construct the call escape sequence, specify the OUT parameters by using the ? (question mark)
character. This character acts as a placeholder for the parameter values that will be returned from the stored
procedure. To specify a value for an OUT parameter, you must specify the data type of each parameter by using
the registerOutParameter method of the SQLServerCallableStatement class before you run the stored
procedure.
The value that you specify for the OUT parameter in the registerOutParameter method must be one of the JDBC
data types contained in java.sql.Types, which in turn maps to one of the native SQL Server data types. For more
information about the JDBC and SQL Server data types, see Understanding the JDBC Driver data types.
When you pass a value to the registerOutParameter method for an OUT parameter, you must specify not only
the data type to be used for the parameter, but also the parameter's ordinal placement or the parameter's name
in the stored procedure. For example, if your stored procedure contains a single OUT parameter, its ordinal value
will be 1; if the stored procedure contains two parameters, the first ordinal value will be 1, and the second
ordinal value will be 2.

NOTE
The JDBC driver does not support the use of CURSOR, SQLVARIANT, TABLE, and TIMESTAMP SQL Server data types as
OUT parameters.

As an example, create the following stored procedure in the sample database:


CREATE PROCEDURE GetImmediateManager
@employeeID INT,
@managerID INT OUTPUT
AS
BEGIN
SELECT @managerID = ManagerID
FROM HumanResources.Employee
WHERE EmployeeID = @employeeID
END

This stored procedure returns a single OUT parameter (managerID), which is an integer, based on the specified
IN parameter (employeeID), which is also an integer. The value that is returned in the OUT parameter is the
ManagerID based on the EmployeeID that is contained in the HumanResources.Employee table.
In the following example, an open connection to the sample database is passed in to the function, and the
execute method is used to call the GetImmediateManager stored procedure:

public static void executeStoredProcedure(Connection con) throws SQLException {


try(CallableStatement cstmt = con.prepareCall("{call dbo.GetImmediateManager(?, ?)}");) {
cstmt.setInt(1, 5);
cstmt.registerOutParameter(2, java.sql.Types.INTEGER);
cstmt.execute();
System.out.println("MANAGER ID: " + cstmt.getInt(2));
}
}

This example uses the ordinal positions to identify the parameters. Alternatively, you can identify a parameter by
using its name instead of its ordinal position. The following code example modifies the previous example to
demonstrate how to use named parameters in a Java application. Note that parameter names correspond to the
parameter names in the stored procedure's definition:

public static void executeStoredProcedure(Connection con) throws SQLException {


try(CallableStatement cstmt = con.prepareCall("{call dbo.GetImmediateManager(?, ?)}"); ) {
cstmt.setInt("employeeID", 5);
cstmt.registerOutParameter("managerID", java.sql.Types.INTEGER);
cstmt.execute();
System.out.println("MANAGER ID: " + cstmt.getInt("managerID"));
}
}

NOTE
These examples use the execute method of the SQLServerCallableStatement class to run the stored procedure. This is
used because the stored procedure did not also return a result set. If it did, the executeQuery method would be used.

Stored procedures can return update counts and multiple result sets. The Microsoft JDBC Driver for SQL Server
follows the JDBC 3.0 specification, which states that multiple result sets and update counts should be retrieved
before the OUT parameters are retrieved. That is, the application should retrieve all of the ResultSet objects and
update counts before retrieving the OUT parameters by using the CallableStatement.getter methods. Otherwise,
the ResultSet objects and update counts that haven't already been retrieved will be lost when the OUT
parameters are retrieved. For more information about update counts and multiple result sets, see Using a stored
procedure with an update count and Using Multiple Result Sets.

See also
Using statements with stored procedures
Using a stored procedure with a return status
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


A SQL Server stored procedure that you can call is one that returns a status or a result parameter. This status is
typically used to indicate the success or failure of the stored procedure. The Microsoft JDBC Driver for SQL
Server provides the SQLServerCallableStatement class, which you can use to call this kind of stored procedure
and to process the data that it returns.
When you call this kind of stored procedure by using the JDBC driver, you have to use the call SQL escape
sequence in conjunction with the prepareCall method of the SQLServerConnection class. The syntax for the
call escape sequence with a return status parameter is the following:

{[?=]call procedure-name[([parameter][,[parameter]]...)]}

NOTE
For more information about the SQL escape sequences, see Using SQL escape sequences.

When you construct the call escape sequence, specify the return status parameter by using the ? (question
mark) character. This character acts as a placeholder for the parameter value that will be returned from the
stored procedure. To specify a value for a return status parameter, you must specify the data type of the
parameter by using the registerOutParameter method of the SQLServerCallableStatement class, before
executing the stored procedure.

NOTE
When using the JDBC driver with a SQL Server database, the value that you specify for the return status parameter in the
registerOutParameter method will always be an integer, which you can specify by using the java.sql.Types.INTEGER data
type.

In addition, when you pass a value to the registerOutParameter method for a return status parameter, you must
specify not only the data type to be used for the parameter, but also the parameter's ordinal placement in the
stored procedure call. In the case of the return status parameter, its ordinal position will always be 1 because it is
always the first parameter in the call to the stored procedure. Although the SQLServerCallableStatement class
provides support for using the parameter's name to indicate the specific parameter, you can use only a
parameter's ordinal position number for return status parameters.
As an example, create the following stored procedure in the sample database:
CREATE PROCEDURE CheckContactCity
(@cityName CHAR(50))
AS
BEGIN
IF ((SELECT COUNT(*)
FROM Person.Address
WHERE City = @cityName) > 1)
RETURN 1
ELSE
RETURN 0
END

This stored procedure returns a status value of 1 or 0, depending on whether the city that is specified in the
cityName parameter is found in the Person.Address table.
In the following example, an open connection to the sample database is passed in to the function, and the
execute method is used to call the CheckContactCity stored procedure:

public static void executeStoredProcedure(Connection con) {


try(CallableStatement cstmt = con.prepareCall("{? = call dbo.CheckContactCity(?)}");) {
cstmt.registerOutParameter(1, java.sql.Types.INTEGER);
cstmt.setString(2, "Atlanta");
cstmt.execute();
System.out.println("RETURN STATUS: " + cstmt.getInt(1));
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

See also
Using statements with stored procedures
Using a stored procedure with an update count
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


To modify data in a SQL Server database by using a stored procedure, the Microsoft JDBC Driver for SQL Server
provides the SQLServerCallableStatement class. By using the SQLServerCallableStatement class, you can call
stored procedures that modify data that is in the database and return a count of the number of rows affected,
also referred to as the update count.
After you have set up the call to the stored procedure by using the SQLServerCallableStatement class, you can
then call the stored procedure by using either the execute or the executeUpdate method. The executeUpdate
method will return an int value that contains the number of rows affected by the stored procedure, but the
execute method doesn't. If you use the execute method and want to get the count of the number of rows
affected, you can call the getUpdateCount method after you run the stored procedure.

NOTE
If you want the JDBC driver to return all update counts, including update counts returned by any triggers that may have
fired, set the lastUpdateCount connection string property to "false". For more information about the lastUpdateCount
property, see Setting the connection properties.

As an example, create the following table and stored procedure, and also insert sample data in the sample
database:

CREATE TABLE TestTable


(Col1 int IDENTITY,
Col2 varchar(50),
Col3 int);

CREATE PROCEDURE UpdateTestTable


@Col2 varchar(50),
@Col3 int
AS
BEGIN
UPDATE TestTable
SET Col2 = @Col2, Col3 = @Col3
END;
INSERT INTO dbo.TestTable (Col2, Col3) VALUES ('b', 10);

In the following example, an open connection to the sample database is passed in to the function, the execute
method is used to call the UpdateTestTable stored procedure, and then the getUpdateCount method is used to
return a count of the rows that are affected by the stored procedure.
public static void executeUpdateStoredProcedure(Connection con) {
try(CallableStatement cstmt = con.prepareCall("{call dbo.UpdateTestTable(?, ?)}");) {
cstmt.setString(1, "A");
cstmt.setInt(2, 100);
cstmt.execute();
int count = cstmt.getUpdateCount();
System.out.println("ROWS AFFECTED: " + count);
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

See also
Using statements with stored procedures
Using table-valued parameters
4/27/2022 • 13 minutes to read • Edit Online

Download JDBC Driver


Table-valued parameters provide an easy way to marshal multiple rows of data from a client application to SQL
Server without requiring multiple round trips or special server-side logic for processing the data. You can use
table-valued parameters to encapsulate rows of data in a client application and send the data to the server in a
single parameterized command. The incoming data rows are stored in a table variable that can then be operated
on by using Transact-SQL.
Column values in table-valued parameters can be accessed using standard Transact-SQL SELECT statements.
Table-valued parameters are strongly typed and their structure is automatically validated. The size of table-
valued parameters is limited only by server memory.

NOTE
Support for Table-Valued Parameters is available starting with Microsoft JDBC Driver 6.0 for SQL Server.
You can't return data in a table-valued parameter. Table-valued parameters are input-only; the OUTPUT keyword is not
supported.

For more information about table-valued parameters, see the following resources.

RESO URC E DESC RIP T IO N

Table-Valued Parameters (Database Engine) in SQL Server Describes how to create and use table-valued parameters
Books Online

User-Defined Table Types in SQL Server Books Online Describes user-defined table types that are used to declare
table-valued parameters

Passing multiple rows in previous versions of SQL Server


Before table-valued parameters were introduced to SQL Server 2008, the options for passing multiple rows of
data to a stored procedure or a parameterized SQL command were limited. A developer could choose from the
following options for passing multiple rows to the server:
Use a series of individual parameters to represent the values in multiple columns and rows of data. The
amount of data that can be passed by using this method is limited by the number of parameters allowed.
SQL Server procedures can have, at most, 2100 parameters. Server-side logic is required to assemble
these individual values into a table variable or a temporary table for processing.
Bundle multiple data values into delimited strings or XML documents and then pass those text values to a
procedure or statement. This requires the procedure or statement to include the logic necessary for
validating the data structures and unbundling the values.
Create a series of individual SQL statements for data modifications that affect multiple rows. Changes can
be submitted to the server individually or batched into groups. However, even when submitted in batches
that contain multiple statements, each statement is executed separately on the server.
Use the bcp utility program or SQLServerBulkCopy to load many rows of data into a table. Although this
technique is efficient, it doesn't support server-side processing unless the data is loaded into a temporary
table or table variable.

Creating table-valued parameter types


Table-valued parameters are based on strongly typed table structures that are defined by using Transact-SQL
CREATE TYPE statements. You have to create a table type and define the structure in SQL Server before you can
use table-valued parameters in your client applications. For more information about creating table types, see
User-Defined Table Types in SQL Server Books Online.

CREATE TYPE dbo.CategoryTableType AS TABLE


( CategoryID int, CategoryName nvarchar(50) )

After creating a table type, you can declare table-valued parameters based on that type. The following Transact-
SQL fragment demonstrates how to declare a table-valued parameter in a stored procedure definition. The
READONLY keyword is required for declaring a table-valued parameter.

CREATE PROCEDURE usp_UpdateCategories


(@tvpNewCategories dbo.CategoryTableType READONLY)

Modifying data with table-valued parameters (Transact-SQL)


Table-valued parameters can be used in set-based data modifications that affect multiple rows by executing a
single statement. For example, you can select all the rows in a table-valued parameter and insert them into a
database table, or you can create an update statement by joining a table-valued parameter to the table you want
to update.
The following Transact-SQL UPDATE statement demonstrates how to use a table-valued parameter by joining it
to the Categories table. When you use a table-valued parameter with a JOIN in a FROM clause, you must also
alias it, as shown here, where the table-valued parameter is aliased as "ec":

UPDATE dbo.Categories
SET Categories.CategoryName = ec.CategoryName
FROM dbo.Categories INNER JOIN @tvpEditedCategories AS ec
ON dbo.Categories.CategoryID = ec.CategoryID;

This Transact-SQL example demonstrates how to select rows from a table-valued parameter to perform an
INSERT in a single set-based operation.

INSERT INTO dbo.Categories (CategoryID, CategoryName)


SELECT nc.CategoryID, nc.CategoryName FROM @tvpNewCategories AS nc;

Limitations of table-valued parameters


There are several limitations to table-valued parameters:
You can't pass table-valued parameters to user defined functions.
Table-valued parameters can only be indexed to support UNIQUE or PRIMARY KEY constraints. SQL
Server doesn't maintain statistics on table-valued parameters.
Table-valued parameters are read-only in Transact-SQL code. You can't update the column values in the
rows of a table-valued parameter and you can't insert or delete rows. To modify the data that is passed to
a stored procedure or parameterized statement in table-valued parameter, you must insert the data into a
temporary table or into a table variable.
You can't use ALTER TABLE statements to modify the design of table-valued parameters.
You can stream large objects in a table-valued parameter.

Configuring a table-valued parameter


Beginning with Microsoft JDBC Driver 6.0 for SQL Server, table-valued parameters are supported with a
parameterized statement or a parameterized stored procedure. Table-valued parameters can be populated from
a SQLServerDataTable, from a ResultSet or from a user provided implementation of the ISQLServerDataRecord
interface. When setting a table-valued parameter for a prepared query, you must specify a type name, which
must match the name of a compatible type previously created on the server.
The following two code fragments demonstrate how to configure a table-valued parameter with a
SQLServerPreparedStatement and with a SQLServerCallableStatement to insert data. Here sourceTVPObject can
be a SQLServerDataTable, or a ResultSet or an ISQLServerDataRecord object. The examples assume connection
is an active Connection object.

// Using table-valued parameter with a SQLServerPreparedStatement.


SQLServerPreparedStatement pStmt =
(SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO dbo.Categories SELECT * FROM ?");
pStmt.setStructured(1, "dbo.CategoryTableType", sourceTVPObject);
pStmt.execute();

// Using table-valued parameter with a SQLServerCallableStatement.


SQLServerCallableStatement pStmt =
(SQLServerCallableStatement) connection.prepareCall("exec usp_InsertCategories ?");
pStmt.setStructured(1, "dbo.CategoryTableType", sourceTVPObject);;
pStmt.execute();

NOTE
See Section Table-Valued Parameter API for the JDBC Driver below for a complete list of APIs available for setting
the table-valued parameter.

Passing a table-valued parameter as a SQLServerDataTable object


Beginning with Microsoft JDBC Driver 6.0 for SQL Server, the SQLServerDataTable class represents an in-
memory table of relational data. This example demonstrates how to construct a table-valued parameter from in-
memory data using the SQLServerDataTable object. First, the code creates a SQLServerDataTable object, defines
its schema, and populates the table with data. The code then configures a SQLServerPreparedStatement that
passes this data table as a table-valued parameter to SQL Server.
/* Assumes connection is an active Connection object. */

// Create an in-memory data table.


SQLServerDataTable sourceDataTable = new SQLServerDataTable();

// Define metadata for the data table.


sourceDataTable.addColumnMetadata("CategoryID" ,java.sql.Types.INTEGER);
sourceDataTable.addColumnMetadata("CategoryName" ,java.sql.Types.NVARCHAR);

// Populate the data table.


sourceDataTable.addRow(1, "CategoryNameValue1");
sourceDataTable.addRow(2, "CategoryNameValue2");

// Pass the data table as a table-valued parameter using a prepared statement.


SQLServerPreparedStatement pStmt =
(SQLServerPreparedStatement) connection.prepareStatement(
"INSERT INTO dbo.Categories SELECT * FROM ?;");
pStmt.setStructured(1, "dbo.CategoryTableType", sourceDataTable);
pStmt.execute();

This example is similar to the previous one. The only difference is that it sets the TVP Name on the
SQLServerDataTable instead of relying on casting PreparedStatement to a SQLServerPreparedStatement to use the
setStructured method.

/* Assumes connection is an active Connection object. */

// Create an in-memory data table.


SQLServerDataTable sourceDataTable = new SQLServerDataTable();
sourceDataTable.setTvpName("dbo.CategoryTableType");

// Define metadata for the data table.


sourceDataTable.addColumnMetadata("CategoryID" ,java.sql.Types.INTEGER);
sourceDataTable.addColumnMetadata("CategoryName" ,java.sql.Types.NVARCHAR);

// Populate the data table.


sourceDataTable.addRow(1, "CategoryNameValue1");
sourceDataTable.addRow(2, "CategoryNameValue2");

// Pass the data table as a table-valued parameter using a prepared statement.


PreparedStatement pStmt =
connection.prepareStatement(
"INSERT INTO dbo.Categories SELECT * FROM ?;");
pStmt.setObject(1, sourceDataTable);
pStmt.execute();

NOTE
See Section Table-Valued Parameter API for the JDBC Driver below for a complete list of APIs available for setting
the table-valued parameter.

Passing a table-valued parameter as a ResultSet object


This example demonstrates how to stream rows of data from a ResultSet to a table-valued parameter. First, the
code retrieves data from a source table in a SQLServerDataTable object, defines its schema, and populates the
table with data. The code then configures a SQLServerPreparedStatement that passes this data table as a table-
valued parameter to SQL Server.
/* Assumes connection is an active Connection object. */

// Create the source ResultSet object. Here SourceCategories is a table defined with the same schema as
Categories table.
ResultSet sourceResultSet = connection.createStatement().executeQuery("SELECT * FROM SourceCategories");

// Pass the source result set as a table-valued parameter using a prepared statement.
SQLServerPreparedStatement pStmt =
(SQLServerPreparedStatement) connection.prepareStatement(
"INSERT INTO dbo.Categories SELECT * FROM ?;");
pStmt.setStructured(1, "dbo.CategoryTableType", sourceResultSet);
pStmt.execute();

NOTE
See Section Table-Valued Parameter API for the JDBC Driver below for a complete list of APIs available for setting
the table-valued parameter.

Passing a table-valued parameter as an ISQLServerDataRecord object


Beginning with Microsoft JDBC Driver 6.0 for SQL Server, a new interface ISQLServerDataRecord is available for
streaming data (depending on how the user provides the implementation for it) using a table-valued parameter.
The following example demonstrates how to implement the ISQLServerDataRecord interface and how to pass it
as a table-valued parameter. For simplicity, the following example passes just one row with hardcoded values to
the table-valued parameter. Ideally, the user would implement this interface to stream rows from any source, for
example from text files.
class MyRecords implements ISQLServerDataRecord
{
int currentRow = 0;
Object[] row = new Object[2];

MyRecords(){
// Constructor. This implementation has just one row.
row[0] = new Integer(1);
row[1] = "categoryName1";
}

public int getColumnCount(){


// Return the total number of columns, for this example it is 2.
return 2;
}

public SQLServerMetaData getColumnMetaData(int columnIndex) {


// Return the column metadata.
if (1 == columnIndex)
return new SQLServerMetaData("CategoryID", java.sql.Types.INTEGER);
else
return new SQLServerMetaData("CategoryName", java.sql.Types.NVARCHAR);
}

public Object[] getRowData(){


// Return the columns in the current row as an array of objects. This implementation has just one
row.
return row;
}

public boolean next(){


// Move to the next row. This implementation has just one row, after processing the first row,
return false.
currentRow++;
if (1 == currentRow)
return true;
else
return false;
}
}

// Following code demonstrates how to pass MyRecords object as a table-valued parameter.


MyRecords sourceRecords = new MyRecords();
SQLServerPreparedStatement pStmt =
(SQLServerPreparedStatement) connection.prepareStatement(
"INSERT INTO dbo.Categories SELECT * FROM ?;");
pStmt.setStructured(1, "dbo.CategoryTableType", sourceRecords);
pStmt.execute();

NOTE
See Section Table-valued parameter API for the JDBC driver below for a complete list of APIs available for setting
the table-valued parameter.

Table-valued parameter API for the JDBC driver


SQLServerMetaData
This class represents metadata for a column. It's used in the ISQLServerDataRecord interface to pass column
metadata to the table-valued parameter. The methods in this class are:
NAME DESC RIP T IO N

public SQLServerMetaData(String columnName, int sqlType, Initializes a new instance of SQLServerMetaData with the
int precision, int scale, boolean useServerDefault, boolean specified column name, sql type, precision, scale and server
isUniqueKey, SQLServerSortOrder sortOrder, int sortOrdinal) default. This form of the constructor supports table-valued
parameters by allowing you to specify if the column is
unique in the table-valued parameter, the sort order for the
column, and the ordinal of the sort column.

useServerDefault - specifies if this column should use the


default server value; Default value is false.
isUniqueKey - indicates if the column in the table-valued
parameter is unique; Default value is false.
sortOrder - indicates the sort order for a column; Default
value is SQLServerSortOrder.Unspecified.
sortOrdinal - specifies ordinal of the sort column;
sortOrdinal starts from 0; Default value is -1.

public SQLServerMetaData(String columnName, int sqlType) Initializes a new instance of SQLServerMetaData using the
column name and the sql type.

public SQLServerMetaData(String columnName, int sqlType, Initializes a new instance of SQLServerMetaData using the
int length) column name, the sql type and the length (for String data).
The length is used to differentiate large strings from strings
with length less than 4000 characters. Introduced in the
version 7.2 of the JDBC driver.

public SQLServerMetaData(String columnName, int sqlType, Initializes a new instance of SQLServerMetaData using the
int precision, int scale) column name, sql type, precision and scale.

Public SQLServerMetaData(SQLServerMetaData Initializes a new instance of SQLServerMetaData from


sqlServerMetaData) another SQLServerMetaData object.

public String getColumName() Retrieves the column name.

public int getSqlType() Retrieves the java sql Type.

public int getPrecision() Retrieves the precision of the type passed to the column.

public int getScale() Retrieves the scale of the type passed to the column.

public SQLServerSortOrder getSortOrder() Retrieves the sort order.

public int getSortOrdinal() Retrieves the sort ordinal.

public boolean isUniqueKey() Returns whether the column is unique.

public boolean useServerDefault() Returns whether the column uses the default server value.

SQLServerSortOrder
An Enum that defines the sort order. Possible values are Ascending, Descending and Unspecified.
SQLServerDataTable
This class represents an in-memory data table to be used with table-valued parameters. The methods in this
class are:
NAME DESC RIP T IO N

Public SQLServerDataTable() Initializes a new instance of SQLServerDataTable.

public Iterator<Entry<Integer, Object[]>> getIterator() Retrieves an iterator on the rows of the data table.

public void addColumnMetadata(String columnName, int Adds metadata for the specified column.
sqlType)

public void addColumnMetadata(SQLServerDataColumn Adds metadata for the specified column.


column)

public void addRow(Object... values) Adds one row of data to the data table.

public Map<Integer, SQLServerDataColumn> Retrieves column meta data of this data table.
getColumnMetadata()

public void clear() Clears this data table.

SQLServerDataColumn
This class represents a column of the in-memory data table represented by SQLServerDataTable. The methods
in this class are:

NAME DESC RIP T IO N

public SQLServerDataColumn(String columnName, int Initializes a new instance of SQLServerDataColumn with the
sqlType) column name and type.

public String getColumnName() Retrieves the column name.

public int getColumnType() Retrieves the column type.

ISQLServerDataRecord
This class represents an interface that users can implement to stream data to a table-valued parameter. The
methods in this interface are:

NAME DESC RIP T IO N

public SQLServerMetaData getColumnMetaData(int Retrieves the column meta data of the given column index.
column);

public int getColumnCount(); Retrieves the total number of columns.

public Object[] getRowData(); Retrieves the data for the current row as an array of Objects.

public boolean next(); Moves to the next row. Returns True if the move is successful
and there's a next row, false otherwise.

SQLServerPreparedStatement
The following methods have been added to this class to support passing of table-valued parameters.
NAME DESC RIP T IO N

public final void setStructured(int parameterIndex, String Populates a table-valued parameter with a data table.
tvpName, SQLServerDataTable tvpDataTable) parameterIndex is the parameter index, tvpName is the
name of the table-valued parameter, and tvpDataTable is the
source data table object.

public final void setStructured(int parameterIndex, String Populates a table-valued parameter with a ResultSet
tvpName, ResultSet tvpResultSet) retrieved from another table. parameterIndex is the
parameter index, tvpName is the name of the table-valued
parameter, and tvpResultSet is the source result set object.

public final void setStructured(int parameterIndex, String Populates a table-valued parameter with an
tvpName, ISQLServerDataRecord tvpDataRecord) ISQLServerDataRecord object. ISQLServerDataRecord is used
for streaming data and the user decides how to use it.
parameterIndex is the parameter index, tvpName is the
name of the table-valued parameter, and tvpDataRecord is
an ISQLServerDataRecord object.

SQLServerCallableStatement
The following methods have been added to this class to support passing of table-valued parameters.

NAME DESC RIP T IO N

public final void setStructured(String paratemeterName, Populates a table-valued parameter passed to a stored
String tvpName, SQLServerDataTable tvpDataTable) procedure with a data table. paratemeterName is the name
of the parameter, tvpName is the name of the type TVP, and
tvpDataTable is the data table object.

public final void setStructured(String paratemeterName, Populates a table-valued parameter passed to a stored
String tvpName, ResultSet tvpResultSet) procedure with a ResultSet retrieved from another table.
paratemeterName is the name of the parameter, tvpName is
the name of the type TVP, and tvpResultSet is the source
result set object.

public final void setStructured(String paratemeterName, Populates a table-valued parameter passed to a stored
String tvpName, ISQLServerDataRecord tvpDataRecord) procedure with an ISQLServerDataRecord object.
ISQLServerDataRecord is used for streaming data and the
user decides how to use it. paratemeterName is the name of
the parameter, tvpName is the name of the type TVP, and
tvpDataRecord is an ISQLServerDataRecord object.

See also
Overview of the JDBC driver
Handling complex statements
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When you use the Microsoft JDBC Driver for SQL Server, you might have to handle complex statements,
including statements that are dynamically generated at runtime. Complex statements often perform different
kinds of tasks, including updates, inserts, and deletes. These types of statements may also return multiple result
sets and output parameters. In these situations, the Java code that runs the statements might not know in
advance the types and number of objects and data returned.
To process complex statements, the JDBC driver provides many methods to query the objects and data that's
returned so your application can correctly process them. The key to processing complex statements is the
execute method of the SQLServerStatement class. This method returns a boolean value. When the value is true,
the first result returned from the statements is a result set. If the value is false, the first result returned is an
update count.
When you know the type of object or data that's returned, you can use either the getResultSet or the
getUpdateCount method to process that data. To continue to the next object or data that's returned from the
complex statement, you can call the getMoreResults method.
In the following example, an open connection to the sample database is passed in to the function, a complex
statement is constructed that combines a stored procedure call with a SQL statement, the statements are run,
and then a do loop is used to process all the result sets and updated counts that are returned.

public static void executeComplexStatement(Connection con) {


try (Statement stmt = con.createStatement();) {
String sqlStringWithUnknownResults = "{call dbo.uspGetEmployeeManagers(50)}; SELECT TOP 10 * FROM
Person.Contact";
boolean results = stmt.execute(sqlStringWithUnknownResults);
int count = 0;
do {
if (results) {
ResultSet rs = stmt.getResultSet();
System.out.println("Result set data displayed here.");
}
else {
count = stmt.getUpdateCount();
if (count >= 0) {
System.out.println("DDL or update data displayed here.");
}
else {
System.out.println("No more results to process.");
}
}
results = stmt.getMoreResults();
}
while (results || count != -1);
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}
See also
Using statements with the JDBC driver
Using multiple result sets
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


When working with inline SQL or SQL Server stored procedures that return more than one result set, the
Microsoft JDBC Driver for SQL Server provides the getResultSet method in the SQLServerStatement class for
retrieving each set of data returned. In addition, when running a statement that returns more than one result set,
you can use the execute method of the SQLServerStatement class, because it will return a boolean value that
indicates if the value returned is a result set or an update count.
If the execute method returns true , the statement that was run has returned one or more result sets. You can
access the first result set by calling the getResultSet method. To determine if more result sets are available, you
can call the getMoreResults method, which returns a boolean value of true if more result sets are available. If
more result sets are available, you can call the getResultSet method again to access them, continuing the
process until all result sets have been processed. If the getMoreResults method returns false , there are no more
result sets to process.
If the execute method returns false , the statement that was run has returned an update count value, which you
can retrieve by calling the getUpdateCount method.

NOTE
For more information about update counts, see Using a stored procedure with an update count.

In the following example, an open connection to the sample database is passed in to the function, and an SQL
statement is constructed that, when run, returns two result sets:
public static void executeStatement(Connection con) {
try (Statement stmt = con.createStatement();) {
String SQL = "SELECT TOP 10 * FROM Person.Contact; SELECT TOP 20 * FROM Person.Contact";

boolean results = stmt.execute(SQL);


int rsCount = 0;

// Loop through the available result sets.


do {
if (results) {
ResultSet rs = stmt.getResultSet();
rsCount++;

// Show data from the result set.


System.out.println("RESULT SET #" + rsCount);
while (rs.next()) {
System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));
}
}
System.out.println();
results = stmt.getMoreResults();
} while (results);
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

In this case, the number of result sets returned is known to be two. However, the code is written so that if an
unknown number of result sets were returned, such as when calling a stored procedure, they would all be
processed. To see an example of calling a stored procedure that returns multiple result sets along with update
values, see Handling complex statements.

NOTE
When you make the call to the getMoreResults method of the SQLServerStatement class, the previously returned result
set is implicitly closed.

See also
Using statements with the JDBC driver
Using parameter metadata
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


To query a SQLServerPreparedStatement or a SQLServerCallableStatement object about the parameters that
they contain, the Microsoft JDBC Driver for SQL Server implements the SQLServerParameterMetaData class.
This class contains numerous fields and methods that return information in the form of a single value.
To create a SQLServerParameterMetaData object, you can use the getParameterMetaData methods of the
SQLServerPreparedStatement and SQLServerCallableStatement classes.
In the following example, an open connection to the sample database is passed in to the function, the
getParameterMetaData method of the SQLServerCallableStatement class is used to return a
SQLServerParameterMetaData object, and then various methods of the SQLServerParameterMetaData object
are used to display information about the type and mode of the parameters that are contained within the
HumanResources.uspUpdateEmployeeHireInfo stored procedure.

public static void getParameterMetaData(Connection con) {


try(CallableStatement cstmt = con.prepareCall("{call HumanResources.uspUpdateEmployeeHireInfo(?, ?, ?,
?, ?)}");) {
ParameterMetaData pmd = cstmt.getParameterMetaData();
int count = pmd.getParameterCount();
for (int i = 1; i <= count; i++) {
System.out.println("TYPE: " + pmd.getParameterTypeName(i) + " MODE: " +
pmd.getParameterMode(i));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

NOTE
There are some limitations when using the SQLServerParameterMetaData class with prepared statements.
With Microsoft JDBC Driver 6.0 (or higher) for SQL Ser ver : When using SQL Server 2008 or 2008 R2, the JDBC
driver supports SELECT, DELETE, INSERT, and UPDATE statements as long as these statements does not contain
subqueries and/or joins.

MERGE queries are also not supported for SQLServerParameterMetaData class when using SQL Server 2008 or
2008 R2. For SQL Server 2012 and higher versions parameter metadata with complex queries are supported.
Retrieval of parameter metadata for encrypted columns are not supported. With Microsoft JDBC Driver 4.1
or 4.2 for SQL Ser ver : The JDBC driver supports SELECT, DELETE, INSERT, and UPDATE statements as long as
these statements does not contain subqueries and/or joins. MERGE queries are also not supported for
SQLServerParameterMetaData class.
Using result set metadata
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


To query a result set for information about the columns that it contains, the Microsoft JDBC Driver for SQL
Server implements the SQLServerResultSetMetaData class. This class contains numerous methods that return
information in the form of a single value.
To create a SQLServerResultSetMetaData object, you can use the getMetaData method of the
SQLServerResultSet class.
In the following example, an open connection to the sample database is passed in to the function, the
getMetaData method of the SQLServerResultSet class is used to return a SQLServerResultSetMetaData object,
and then various methods of the SQLServerResultSetMetaData object are used to display information about the
name and data type of the columns contained within the result set.

public static void getResultSetMetaData(Connection con) {


try(Statement stmt = con.createStatement();) {
String SQL = "SELECT TOP 10 * FROM Person.Contact";

ResultSet rs = stmt.executeQuery(SQL);
ResultSetMetaData rsmd = rs.getMetaData();

// Display the column name and type.


int cols = rsmd.getColumnCount();
for (int i = 1; i <= cols; i++) {
System.out.println("NAME: " + rsmd.getColumnName(i) + " " + "TYPE: " +
rsmd.getColumnTypeName(i));
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

See also
Handling metadata with the JDBC driver
Understanding transactions
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Transactions are groups of operations that are combined into logical units of work. They are used to control and
maintain the consistency and integrity of each action in a transaction, despite errors that might occur in the
system.
With the Microsoft JDBC Driver for SQL Server, transactions can be either local or distributed. Transactions can
also use isolation levels. For more information about the isolation levels supported by the JDBC driver, see
Understanding Isolation Levels.
Applications should control transactions by either using Transact-SQL statements or the methods provided by
the JDBC driver, but not both. Using both Transact-SQL statements and JDBC API methods on the same
transaction might lead to problems, such as a transaction cannot be committed when expected, a transaction is
committed or rolled back and a new one starts unexpectedly, or "Failed to resume the transaction" exceptions.

Using local transactions


A transaction is considered to be local when it is a single-phase transaction, and it is handled by the database
directly. The JDBC driver supports local transactions by using various methods of the SQLServerConnection
class, including setAutoCommit, commit, and rollback. Local transactions are typically managed explicitly by the
application or automatically by the Java Platform, Enterprise Edition (Java EE) application server.
The following example performs a local transaction that consists of two separate statements in the try block.
The statements are run against the Production.ScrapReason table in the sample database, and they are
committed if no exceptions are thrown. The code in the catch block rolls back the transaction if an exception is
thrown.

public static void executeTransaction(Connection con) {


try {
//Switch to manual transaction mode by setting
//autocommit to false. Note that this starts the first
//manual transaction.
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.executeUpdate("INSERT INTO Production.ScrapReason(Name) VALUES('Wrong size')");
stmt.executeUpdate("INSERT INTO Production.ScrapReason(Name) VALUES('Wrong color')");
con.commit(); //This commits the transaction and starts a new one.
stmt.close(); //This turns off the transaction.
System.out.println("Transaction succeeded. Both records were written to the database.");
}
catch (SQLException ex) {
ex.printStackTrace();
try {
System.out.println("Transaction failed.");
con.rollback();
}
catch (SQLException se) {
se.printStackTrace();
}
}
}
Using distributed transactions
A distributed transaction updates data on two or more networked databases while retaining the important
atomic, consistent, isolated, and durable (ACID) properties of transaction processing. Distributed transaction
support was added to the JDBC API in the JDBC 2.0 Optional API specification. The management of distributed
transactions is typically performed automatically by the Java Transaction Service (JTS) transaction manager in a
Java EE application server environment. However, the Microsoft JDBC Driver for SQL Server supports
distributed transactions under any Java Transaction API (JTA) compliant transaction manager.
The JDBC driver seamlessly integrates with Microsoft Distributed Transaction Coordinator (MS DTC) to provide
true distributed transaction support with SQL Server. MS DTC is a distributed transaction facility provided by
Microsoft for Microsoft Windows systems. MS DTC uses proven transaction processing technology from
Microsoft to support XA features such as the complete two-phase distributed commit protocol and the recovery
of distributed transactions.
For more information about how to use distributed transactions, see Understanding XA transactions.

See also
Performing transactions with the JDBC driver
Understanding XA transactions
4/27/2022 • 11 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server provides support for Java Platform, Enterprise Edition/JDBC 2.0
optional distributed transactions. JDBC connections obtained from the SQLServerXADataSource class can
participate in standard distributed transaction processing environments such as Java Platform, Enterprise
Edition (Java EE) application servers.
In this article, XA stands for extended architecture.

WARNING
Microsoft JDBC Driver 4.2 (and higher) for SQL includes new timeout options for the existing feature for automatic
rollback of unprepared transactions. See Configuring server-side timeout settings for automatic rollback of unprepared
transactions later in this topic for more detail.

Remarks
The classes for the distributed transaction implementation are as follows:

C L A SS IM P L EM EN T S DESC RIP T IO N

com.microsoft.sqlserver.jdbc.SQLServer javax.sql.XADataSource The class factory for distributed


XADataSource connections.

com.microsoft.sqlserver.jdbc.SQLServer javax.transaction.xa.XAResource The resource adaptor for the


XAResource transaction manager.

NOTE
XA distributed transaction connections default to the Read Committed isolation level.

Guidelines and limitations when using XA transactions


The following additional guidelines apply to tightly coupled transactions:
When you use XA transactions together with Microsoft Distributed Transaction Coordinator (MS DTC),
you may notice that the current version of MS DTC doesn't support tightly coupled XA branch behavior.
For example, MS DTC has a one-to-one mapping between an XA branch transaction ID (XID) and an MS
DTC transaction ID and the work that is performed by loosely coupled XA branches is isolated from one
another.
MS DTC also supports tightly coupled XA branches where multiple XA branches with same global
transaction ID (GTRID) are mapped to a single MS DTC transaction ID. This support enables multiple
tightly coupled XA branches to see each other's changes in the resource manager, such as SQL Server.
A SSTRANSTIGHTLYCPLD flag allows applications to use tightly coupled XA transactions, which have
different XA branch transaction IDs (BQUAL) but have the same global transaction ID (GTRID) and format
ID (FormatID). In order to use that feature, you must set the SSTRANSTIGHTLYCPLD on the flags
parameter of the XAResource.start method:

xaRes.start(xid, SQLServerXAResource.SSTRANSTIGHTLYCPLD);

Configuration instructions
The following steps are required if you want to use XA data sources together with Microsoft Distributed
Transaction Coordinator (MS DTC) for handling distributed transactions.

NOTE
The JDBC distributed transaction components are included in the xa directory of the JDBC driver installation. These
components include the xa_install.sql and sqljdbc_xa.dll files. If you have different versions of the JDBC driver on different
clients, it is recommended to use the newest sqljdbc_xa.dll on the server.

NOTE
The JDBC XA distributed transaction components are included in the SQL Server engine in SQL Server 2017 starting with
cumulative update 16 and in SQL Server 2019, and can be enabled or disabled with a system stored procedure. The
sqjdbc_xa.dll from the driver is not required and it is recommended to enable the server components instead for these
server versions. To enable the required components to perform XA distributed transactions using the JDBC driver, execute
the following stored procedure.
EXEC sp_sqljdbc_xa_install
To disable the previously installed components, execute the following stored procedure.
EXEC sp_sqljdbc_xa_uninstall

Running the MS DTC service


The MS DTC service should be marked Automatic in Service Manager to make sure that it is running when the
SQL Server service is started. To enable MS DTC for XA transactions, you must follow these steps:
On Windows Vista and later:
1. Click the Star t button, type dcomcnfg in the Start Search box, and then press ENTER to open
Component Ser vices . You can also type %windir%\system32\comexp.msc in the Star tSearch box to
open Component Ser vices .
2. Expand Component Services, Computers, My Computer, and then Distributed Transaction Coordinator.
3. Right-click Local DTC and then select Proper ties .
4. Click the Security tab on the Local DTC Proper ties dialog box.
5. Select the Enable XA Transactions check box, and then click OK . This action will cause an MS DTC
service restart.
6. Click OK again to close the Proper ties dialog box, and then close Component Ser vices .
7. Stop and then restart SQL Server to make sure that it syncs with the MS DTC changes. (This step is
optional for SQL Server 2019 and SQL Server 2017 CU 16 and higher.)
Configuring the JDBC distributed transaction components
You can configure the JDBC driver distributed transaction components by following these steps:
1. Copy the new sqljdbc_xa.dll from the JDBC driver installation directory to the Binn directory of every SQL
Server computer that will participate in distributed transactions.

NOTE
If you are using XA transactions with a 32-bit SQL Server, use the sqljdbc_xa.dll file in the x86 folder, even if the
SQL Server is installed on a x64 processor. If you are using XA transactions with a 64-bit SQL Server on the x64
processor, use the sqljdbc_xa.dll file in the x64 folder.

2. Execute the database script xa_install.sql on every SQL Server instance that will participate in distributed
transactions. This script installs the extended stored procedures that are called by sqljdbc_xa.dll. These
extended stored procedures implement distributed transaction and XA support for the Microsoft JDBC
Driver for SQL Server. You'll need to run this script as an administrator of the SQL Server instance.
3. To grant permissions to a specific user to participate in distributed transactions with the JDBC driver, add
the user to the SqlJDBCXAUser role.
You can configure only one version of the sqljdbc_xa.dll assembly on each SQL Server instance at a time.
Applications may need to use different versions of the JDBC driver to connect to the same SQL Server instance
by using the XA connection. In that case, sqljdbc_xa.dll, which comes with the newest JDBC driver, must be
installed on the SQL Server instance.
There are three ways to verify the version of sqljdbc_xa.dll currently installed on the SQL Server instance:
1. Open the LOG directory of SQL Server computer that will participate in distributed transactions. Select
and open the SQL Server "ERRORLOG" file. Search for "Using 'SQLJDBC_XA.dll' version ..." phrase in the
"ERRORLOG" file.
2. Open the Binn directory of SQL Server computer that will participate in distributed transactions. Select
the sqljdbc_xa.dll assembly.
On Windows Vista or later: Right-click sqljdbc_xa.dll and then select Properties. Then click the Details
tab. The File Version field shows the version of sqljdbc_xa.dll that is currently installed on the SQL
Server instance.
3. Set the logging functionality as shown in the code example in the next section. Search for "Server XA DLL
version:..." phrase in the output log file.
Configuring server-side timeout settings for automatic rollback of unprepared transactions

WARNING
This server-side option is new with Microsoft JDBC Driver 4.2 (and higher) for SQL Server. To get the updated behavior,
make sure the sqljdbc_xa.dll on the server is updated. For more information on setting client side timeouts, see
XAResource.setTransactionTimeout().

There are two registry settings (DWORD values) to control the timeout behavior of distributed transactions:
XADefaultTimeout (in seconds): The default timeout value to be used when the user does not specify
any timeout. The default is 0.
XAMaxTimeout (in seconds): The maximum value of the timeout that a user can set. The default is 0.
These settings are SQL Server instance specific and should be created under the following registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL<version>.<instance_name>\XATimeout


NOTE
For 32-bit SQL Server running in 64-bit machines, the registry settings should be created under the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server\MSSQL<version>.
<instance_name>\XATimeout

A timeout value is set for each transaction when it's started and the transaction is rolled back by the SQL Server
if the timeout expires. The timeout is determined depending on these registry settings and depending on what
the user has specified through XAResource.setTransactionTimeout(). A few examples on how these timeout
values are interpreted as follows:
XADefaultTimeout = 0 , XAMaxTimeout = 0

Means no default timeout will be used, and no maximum timeout will be enforced on clients. In this case,
the transactions will have a timeout only if the client sets a timeout using
XAResource.setTransactionTimeout.
XADefaultTimeout = 60 , XAMaxTimeout = 0

Means all transactions will have a 60-second timeout if the client doesn't specify any timeout. If the client
specifies a timeout, then that timeout value will be used. No maximum value for timeout is enforced.
XADefaultTimeout = 30 , XAMaxTimeout = 60

Means all transactions will have a 30-second timeout if the client doesn't specify any timeout. If client
specifies any timeout, then the client's timeout will be used as long as it is less than 60 seconds (the max
value).
XADefaultTimeout = 0 , XAMaxTimeout = 30

Means all transactions will have a 30-second timeout (the max value) if the client does not specify any
timeout. If the client specifies any timeout, then the client's timeout will be used as long as it is less than
30 seconds (the max value).
Upgrading sqljdbc_xa.dll
When you install a new version of the JDBC driver, you should also use sqljdbc_xa.dll from the new version to
upgrade sqljdbc_xa.dll on the server.

IMPORTANT
You should upgrade sqljdbc_xa.dll during a maintenance window or when there are no MS DTC transactions in progress.

1. Unload sqljdbc_xa.dll using the Transact-SQL command DBCC sqljdbc_xa (FREE) .


2. Copy the new sqljdbc_xa.dll from the JDBC driver installation directory to the Binn directory of every SQL
Server computer that will participate in distributed transactions.
The new DLL will be loaded when an extended procedure in sqljdbc_xa.dll is called. You don't need to
restart SQL Server to load the new definitions.
Configuring the user-defined roles
To grant permissions to a specific user to participate in distributed transactions with the JDBC driver, add the
user to the SqlJDBCXAUser role. For example, use the following Transact-SQL code to add a user named 'shelly'
(SQL standard login user named 'shelly') to the SqlJDBCXAUser role:
USE master
GO
EXEC sp_grantdbaccess 'shelly', 'shelly'
GO
EXEC sp_addrolemember [SqlJDBCXAUser], 'shelly'

SQL user-defined roles are defined per database. To create your own role for security purposes, you'll have to
define the role in each database, and add users in a per database manner. The SqlJDBCXAUser role is strictly
defined in the master database because it's used to grant access to the SQL JDBC extended stored procedures
that reside in master. You'll have to first grant individual users access to master, and then grant them access to
the SqlJDBCXAUser role while you're logged into the master database.

Example
import java.net.Inet4Address;
import java.sql.*;
import java.util.Random;
import javax.sql.XAConnection;
import javax.transaction.xa.*;
import com.microsoft.sqlserver.jdbc.*;

public class testXA {

public static void main(String[] args) throws Exception {

// Create variables for the connection string.


String prefix = "jdbc:sqlserver://";
String serverName = "localhost";
int portNumber = 1433;
String databaseName = "AdventureWorks";
String user = "UserName";
String password = "*****";

String connectionUrl = prefix + serverName + ":" + portNumber + ";databaseName=" + databaseName +


";user="
+ user + ";password=" + password;

Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt =


con.createStatement()) {
stmt.executeUpdate("CREATE TABLE XAMin (f1 int, f2 varchar(max))");

}
// Create the XA data source and XA ready connection.
SQLServerXADataSource ds = new SQLServerXADataSource();
ds.setUser(user);
ds.setPassword(password);
ds.setServerName(serverName);
ds.setPortNumber(portNumber);
ds.setDatabaseName(databaseName);

XAConnection xaCon = ds.getXAConnection();


try (Connection con = xaCon.getConnection()) {

// Get a unique Xid object for testing.


XAResource xaRes = null;
Xid xid = null;
xid = XidImpl.getUniqueXid(1);

// Get the XAResource object and set the timeout value.


xaRes = xaCon.getXAResource();
xaRes.setTransactionTimeout(0);
xaRes.setTransactionTimeout(0);

// Perform the XA transaction.


System.out.println("Write -> xid = " + xid.toString());
xaRes.start(xid, XAResource.TMNOFLAGS);
PreparedStatement pstmt = con.prepareStatement("INSERT INTO XAMin (f1,f2) VALUES (?, ?)");
pstmt.setInt(1, 1);
pstmt.setString(2, xid.toString());
pstmt.executeUpdate();

// Commit the transaction.


xaRes.end(xid, XAResource.TMSUCCESS);
xaRes.commit(xid, true);
}
xaCon.close();

// Open a new connection and read back the record to verify that it worked.
try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt =
con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM XAMin")) {
rs.next();
System.out.println("Read -> xid = " + rs.getString(2));
stmt.executeUpdate("DROP TABLE XAMin");
}
}
}

class XidImpl implements Xid {

public int formatId;


public byte[] gtrid;
public byte[] bqual;

public byte[] getGlobalTransactionId() {


return gtrid;
}

public byte[] getBranchQualifier() {


return bqual;
}

public int getFormatId() {


return formatId;
}

XidImpl(int formatId, byte[] gtrid, byte[] bqual) {


this.formatId = formatId;
this.gtrid = gtrid;
this.bqual = bqual;
}

public String toString() {


int hexVal;
StringBuffer sb = new StringBuffer(512);
sb.append("formatId=" + formatId);
sb.append(" gtrid(" + gtrid.length + ")={0x");
for (int i = 0; i < gtrid.length; i++) {
hexVal = gtrid[i] & 0xFF;
if (hexVal < 0x10)
sb.append("0" + Integer.toHexString(gtrid[i] & 0xFF));
else
sb.append(Integer.toHexString(gtrid[i] & 0xFF));
}
sb.append("} bqual(" + bqual.length + ")={0x");
for (int i = 0; i < bqual.length; i++) {
hexVal = bqual[i] & 0xFF;
if (hexVal < 0x10)
sb.append("0" + Integer.toHexString(bqual[i] & 0xFF));
else
else
sb.append(Integer.toHexString(bqual[i] & 0xFF));
}
sb.append("}");
return sb.toString();
}

// Returns a globally unique transaction id.


static byte[] localIP = null;
static int txnUniqueID = 0;

static Xid getUniqueXid(int tid) {

Random rnd = new Random(System.currentTimeMillis());


txnUniqueID++;
int txnUID = txnUniqueID;
int tidID = tid;
int randID = rnd.nextInt();
byte[] gtrid = new byte[64];
byte[] bqual = new byte[64];
if (null == localIP) {
try {
localIP = Inet4Address.getLocalHost().getAddress();
} catch (Exception ex) {
localIP = new byte[] {0x01, 0x02, 0x03, 0x04};
}
}
System.arraycopy(localIP, 0, gtrid, 0, 4);
System.arraycopy(localIP, 0, bqual, 0, 4);

// Bytes 4 -> 7 - unique transaction id.


// Bytes 8 ->11 - thread id.
// Bytes 12->15 - random number generated by using seed from current time in milliseconds.
for (int i = 0; i <= 3; i++) {
gtrid[i + 4] = (byte) (txnUID % 0x100);
bqual[i + 4] = (byte) (txnUID % 0x100);
txnUID >>= 8;
gtrid[i + 8] = (byte) (tidID % 0x100);
bqual[i + 8] = (byte) (tidID % 0x100);
tidID >>= 8;
gtrid[i + 12] = (byte) (randID % 0x100);
bqual[i + 12] = (byte) (randID % 0x100);
randID >>= 8;
}
return new XidImpl(0x1234, gtrid, bqual);
}
}

See also
Performing transactions with the JDBC driver
Using holdability
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


By default, a result set created within a transaction is kept open after the transaction is committed to the
database, or when it is rolled back. However, it is sometimes useful for the result set to be closed, after the
transaction has been committed. To do this, the Microsoft JDBC Driver for SQL Server supports the use of result
set holdability.
Result set holdability can be set by using the setHoldability method of the SQLServerConnection class. When
setting the holdability by using the setHoldability method, the result set holdability constants of
ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT can be used.

The JDBC driver also supports setting holdability when creating one of the Statement objects. When creating the
Statement objects that have overloads with result set holdability parameters, the holdability of statement object
must match the connection's holdability. When they don't match, an exception is thrown. It's because SQL Server
supports the holdability only at the connection level.
The holdability of a result set is the holdability of the SQLServerConnection object that is associated with the
result set at the time when the result set is created for server-side cursors only. It does not apply to client-side
cursors. All result sets with client-side cursors will always have the holdability value of
ResultSet.HOLD_CURSORS_OVER_COMMIT .

For server cursors, when connected to SQL Server 2005 or later, setting the holdability affects only the
holdability of new result sets that are yet to be created on that connection. It means that setting holdability has
no impact on the holdability of any result sets that were previously created and are already open on that
connection.
In the following example, the result set holdability is set while performing a local transaction consisting of two
separate statements in the try block. The statements are run against the Production.ScrapReason table in the
sample database. First, the example switches to manual transaction mode by setting the auto-commit to false .
Once auto-commit mode is disabled, no SQL Statements will be committed until the application calls the
commit method explicitly. The code in the catch block rolls back the transaction if an exception is thrown.
public static void executeTransaction(Connection con) {
try (Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);) {
con.setAutoCommit(false);
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);

stmt.executeUpdate("INSERT INTO Production.ScrapReason(Name) VALUES('Bad part')");


ResultSet rs = stmt.executeQuery("SELECT * FROM Production.ScrapReason");
con.commit();
System.out.println("Transaction succeeded.");

// Display results.
while (rs.next()) {
System.out.println(rs.getString(2));
}
}
catch (SQLException ex) {
ex.printStackTrace();
try {
System.out.println("Transaction failed.");
con.rollback();
}
catch (SQLException se) {
se.printStackTrace();
}
}
}

See also
Performing transactions with the JDBC driver
Using savepoints
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Savepoints offer a mechanism to roll back portions of transactions. Within SQL Server, you can create a
savepoint by using the SAVE TRANSACTION savepoint_name statement. Later, you run a ROLLBACK
TRANSACTION savepoint_name statement to roll back to the savepoint instead of rolling back to the start of the
transaction.
Savepoints are useful in situations where errors are unlikely to occur. The use of a savepoint to roll back part of
a transaction in the case of an infrequent error can be more efficient than having each transaction test to see if
an update is valid before making the update. Updates and rollbacks are expensive operations, so savepoints are
effective only if the probability of encountering the error is low and the cost of checking the validity of an update
beforehand is relatively high.
The Microsoft JDBC Driver for SQL Server supports the use of savepoints through the setSavepoint method of
the SQLServerConnection class. By using the setSavepoint method, you can create a named or unnamed
savepoint within the current transaction, and the method will return a SQLServerSavepoint object. Multiple
savepoints can be created within a transaction. To roll back a transaction to a given savepoint, you can pass the
SQLServerSavepoint object to the rollback ( java.sql.Savepoint) method.
In the following example, a savepoint is used while performing a local transaction consisting of two separate
statements in the try block. The statements are run against the Production.ScrapReason table in the sample
database, and a savepoint is used to roll back the second statement. This results in only the first statement being
committed to the database.

public static void executeTransaction(Connection con) {


try(Statement stmt = con.createStatement();) {
con.setAutoCommit(false);
stmt.executeUpdate("INSERT INTO Production.ScrapReason(Name) VALUES('Correct width')");
Savepoint save = con.setSavepoint();
stmt.executeUpdate("INSERT INTO Production.ScrapReason(Name) VALUES('Wrong width')");
con.rollback(save);
con.commit();
System.out.println("Transaction succeeded.");
}
catch (SQLException ex) {
ex.printStackTrace();
try {
System.out.println("Transaction failed.");
con.rollback();
}
catch (SQLException se) {
se.printStackTrace();
}
}
}

See also
Performing transactions with the JDBC driver
Understanding row locking
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server uses SQL Server row locks. These implement concurrency controls
among multiple users who are performing modifications in a database at the same time. By default, transactions
and locks are managed on a per-connection basis. For example, if an application opens two JDBC connections,
locks that are acquired by one connection cannot be shared with the other connection. Neither connection can
acquire locks that would conflict with locks held by the other connection.

NOTE
If row locking is used, all rows in the fetch buffer are locked, so a very large setting for the fetch size can affect
concurrency.

Locking is used to assure transactional integrity and database consistency. Locking prevents users from reading
data that is being changed by other users, and prevents multiple users from changing the same data at the same
time. If locking is not used, data within the database might become logically incorrect, and queries run against
that data might produce unexpected results.

NOTE
For more information about row locking in SQL Server, see Locking in the Database Engine.

See also
Managing result sets with the JDBC driver
Understanding concurrency control
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Concurrency control refers to the various techniques that are used to preserve the integrity of the database
when multiple users are updating rows at the same time. Incorrect concurrency can lead to problems such as
dirty reads, phantom reads, and non-repeatable reads. The Microsoft JDBC Driver for SQL Server provides
interfaces to all the concurrency techniques used by SQL Server to resolve these issues.

NOTE
For more information about SQL Server concurrency, see "Managing Concurrent Data Access".

Remarks
The JDBC driver supports the following concurrency types:

C O N C URREN C Y T Y P E C H A RA C T ERIST IC S RO W LO C K S DESC RIP T IO N

CONCUR_READ_ONLY Read Only No Updates through the cursor


are not allowed, and no
locks are held on the rows
that make up the result set.

CONCUR_UPDATABLE Optimistic Read Write No Database assumes row


contention is unlikely, but
possible. Row integrity is
checked with a timestamp
comparison.

CONCUR_SS_SCROLL_LOCK Pessimistic Read Write Yes Database assumes row


S contention is likely. Row
integrity is ensured with
row locking.
C O N C URREN C Y T Y P E C H A RA C T ERIST IC S RO W LO C K S DESC RIP T IO N

CONCUR_SS_OPTIMISTIC_C Optimistic Read Write No Database assumes row


C contention is unlikely, but
possible. Row integrity is
verified with a timestamp
comparison.

For SQL Server 2005 (9.x)


and later, the server will
change this to
CONCUR_SS_OPTIMISTIC_C
CVAL if the table does not
contain a timestamp
column.

For SQL Server 2000 (8.x), if


the underlying table has a
timestamp column,
OPTIMISTIC WITH ROW
VERSIONING is used even if
OPTIMISTIC WITH VALUES
is specified. If OPTIMISTIC
WITH ROW VERSIONING is
specified and the table does
not have timestamps,
OPTIMISTIC WITH VALUES
is used.

CONCUR_SS_OPTIMISTIC_C Optimistic Read Write No Database assumes row


CVAL contention is unlikely, but
possible. Row integrity is
checked with a row data
comparison.

Result sets that are not updateable


An updatable result set is a result set in which rows can be inserted, updated, and deleted. In the following cases,
SQL Server cannot create an updatable cursor. The exception generated is, "Result set is not updatable."

C A USE DESC RIP T IO N REM EDY

Statement is not created by using JDBC 2.0 introduced new methods to Specify result set type and concurrency
JDBC 2.0 (or later) syntax create statements. If JDBC 1.0 syntax is when creating the statement.
used, the result set defaults to read-
only.

Statement is created by using SQL Server creates a static snapshot Use TYPE_SCROLL_SENSITIVE,
TYPE_SCROLL_INSENSITIVE cursor. This is disconnected from the TYPE_SS_SCROLL_KEYSET,
underlying table rows to help protect TYPE_SS_SCROLL_DYNAMIC, or
the cursor from row updates by other TYPE_FORWARD_ONLY with
users. CONCUR_UPDATABLE to avoid
creating a static cursor.

Table design precludes a KEYSET or The underlying table does not have Add unique keys to the table to
DYNAMIC cursor unique keys to enable SQL Server to provide unique identification of each
uniquely identify a row. row.

See also
Managing result sets with the JDBC driver
International features of the JDBC driver
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


The internationalization features of the Microsoft JDBC Driver for SQL Server include the following items:
Support for a fully localized experience in the same languages as SQL Server
Support for the Java language conversions for locale sensitive SQL Server data
Support for international languages, regardless of operating system
Support for international domain names (starting with Microsoft JDBC Driver 6.0 for SQL Server)

Handling of character data


Character data in Java is handled as Unicode by default; the Java String object represents Unicode character
data. In the JDBC driver, the only exception to this rule is the ASCII stream getter and setter methods, which are
special cases because they use byte streams with the implicit assumption of single well-known code pages
(ASCII).
Also, the JDBC driver provides the sendStringParametersAsUnicode connection string property. This
property can be used to specify that prepared parameters for character data are sent as ASCII or Multi-byte
Character Set (MBCS) instead of Unicode. For more information about the sendStringParametersAsUnicode
connection string property, see Setting the Connection Properties.
Driver incoming conversions
Unicode text data coming from the server doesn't have to be converted. It's passed directly as Unicode. Non-
Unicode data coming from the server is converted from the code page for the data, at the database or column
level, to Unicode. The JDBC driver uses the Java Virtual Machine (JVM) conversion routines to do these
conversions. These conversions are done on all typed String and Character stream getter methods.
If the JVM doesn't have the proper code page support for the data from the database, the JDBC driver throws an
"XXX codepage not supported by the Java environment" exception. To solve this problem, you should install the
full international character support required for that JVM.
Driver outgoing conversions
Character data going from the driver to the server can be ASCII or Unicode. For example, the new JDBC 4.0
national character methods, such as setNString, setNCharacterStream, and setNClob methods of
SQLServerPreparedStatement and SQLServerCallableStatement classes, always send their parameter values to
the server in Unicode.
On the other hand, the non-national character API methods, such as setString, setCharacterStream, and setClob
methods of SQLServerPreparedStatement and SQLServerCallableStatement classes send their values to the
server in Unicode only when the sendStringParametersAsUnicode property is set to "true", which is the
default value.

Non-unicode parameters
For optimal performance with CHAR , VARCHAR or LONGVARCHAR type of non-Unicode parameters, set the
sendStringParametersAsUnicode connection string property to "false" and use the non-national character
methods.
Formatting issues
For date, time, and currencies, all formatting with localized data is done at the Java language level using the
Locale object; and the various formatting methods for Date , Calendar , and Number data types. In the rare
case where the JDBC driver must pass along locale sensitive data in a localized format, the proper formatter is
used with the default JVM locale.

Collation support
The JDBC Driver 3.0 supports all the collations supported by SQL Server 2000 (8.x), SQL Server 2005 (9.x), and
the new collations or new versions of Windows collation names introduced in SQL Server 2008.
For more information on the collations, see Collation and Unicode Support and Windows Collation Name
(Transact-SQL).

Using International domain names (IDN)


The JDBC Driver 6.0 for SQL Server supports the use of Internationalized Domain Names (IDNs) and can
convert a Unicode serverName to ASCII compatible encoding (Punycode) when required during a connection. If
the IDNs are stored in the Domain Name System (DNS) as ASCII strings in the Punycode format (specified by
RFC 3490), enable the conversion of the Unicode server name by setting the serverNameAsACE property to
true. Otherwise, if the DNS service is configured to allow the use of Unicode characters, set the
serverNameAsACE property as false (the default). For older versions of the JDBC driver, it's also possible to
convert the serverName to Punycode using Java's IDN.toASCII methods before setting that property for a
connection.

NOTE
Most resolver software written for non-Windows platforms is based on the Internet DSN standards and is therefore most
likely to use the Punycode format for IDNs, while a Windows-based DNS Server on a private network can be configured
to allow the use of UTF-8 characters on a per-server basis. For more information, see Unicode character support.

See also
Overview of the JDBC driver
National character set support
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The JDBC driver provides support for the JDBC 4.0 API, which includes new national character set conversion
API methods. This support includes new setter, getter, and updater methods for NCHAR , NVARCHAR ,
LONGNVARCHAR , and NCLOB JDBC types.
The following list shows new getter, setter, and updater methods to support the national character set
conversion:
SQLServerPreparedStatement: setNString, setNCharacterStream, setNClob.
SQLServerCallableStatement: getNClob, getNString, getNCharacterStream, setNString,
setNCharacterStream, setNClob.
SQLServerResultSet: getNClob, getNString, getNCharacterStream, updateNClob, updateNString,
updateNCharacterStream.

NOTE
You must set the classpath to include the sqljdbc4.jar file to use these methods in your application.

To send String parameters to the server in Unicode format, the applications should either use the new JDBC 4.0
national character methods; or set the sendStringParametersAsUnicode connection property to "true " when
using the non-national character methods. The recommended way is to use the new JDBC 4.0 national character
methods where possible. For more information about the sendStringParametersAsUnicode connection
property, see Setting the Connection Properties.

See also
Understanding the JDBC driver data types
Using database metadata
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


To query a database for information about what it supports, the Microsoft JDBC Driver for SQL Server
implements the SQLServerDatabaseMetaData class. This class contains many methods that return information
in the form of a single value, or as a result set.
To create a SQLServerDatabaseMetaData object, you can use the getMetaData method of the
SQLServerConnection class to get information about the database that it's connected to.
In the following example, an open connection to the sample database is passed in to the function. Then the
getMetaData method of the SQLServerConnection class is used to return a SQLServerDatabaseMetadata object.
Finally, various SQLServerDatabaseMetaData methods are used to display information about the driver, driver
version, database name, and database version.

public static void getDatabaseMetaData(Connection con) {


try {
DatabaseMetaData dbmd = con.getMetaData();
System.out.println("dbmd:driver version = " + dbmd.getDriverVersion());
System.out.println("dbmd:driver name = " + dbmd.getDriverName());
System.out.println("db name = " + dbmd.getDatabaseProductName());
System.out.println("db ver = " + dbmd.getDatabaseProductVersion());
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

See also
Handling metadata with the JDBC driver
Always Encrypted API reference for the JDBC driver
4/27/2022 • 16 minutes to read • Edit Online

Download JDBC Driver


Always Encrypted allows clients to encrypt sensitive data inside client applications and never reveal the
encryption keys to the server. An Always Encrypted enabled driver installed on the client computer achieves this
functionality by automatically encrypting and decrypting sensitive data in the client application.
The driver encrypts the data in sensitive columns before passing the data to SQL Server, and automatically
rewrites queries to preserve the semantics to the application. Similarly, the driver transparently decrypts data
stored in encrypted database columns that are in query results. For more information, see Always Encrypted
(Database Engine) and Using Always Encrypted with the JDBC Driver.

NOTE
Always Encrypted is supported only by Microsoft JDBC Driver 6.0 or higher for SQL Server with Azure SQL Database and
SQL Server 2016 and higher.

Always Encrypted API references


There are several new additions and modifications to the JDBC driver API for use in client applications that use
Always Encrypted.
SQLServerConnection class
NAME DESC RIP T IO N

New connection string keyword: columnEncryptionSetting=Enabled enables Always


Encrypted functionality for the connection and
columnEncryptionSetting columnEncryptionSetting=Disabled disables it. Accepted
values are Enabled/Disabled. The default is Disabled.

New connection string keyword:(MS JDBC 7.4 onwards) keyVaultProviderClientId=


<ClientID>;keyVaultProviderClientKey=<ClientKey>
keyVaultProviderClientId
Registers
keyVaultProviderClientKey SQLServerColumnEncryptionAzureKeyVaultProvider and
uses ClientID and ClientKey values to retrieve Column
Master Key from Azure Key Vault

New methods: Allows you to set/update/remove a list of trusted key paths


for a database server. If while processing an application
public static void query the driver receives a key path that's not on the list,
setColumnEncryptionTrustedMasterKeyPaths(Map<String, the query will fail. This property provides extra protection
List\<String>> trustedKeyPaths)
against security attacks that involve a compromised server
sending fake key paths, which may lead to leaking key store
public static void
updateColumnEncryptionTrustedMasterKeyPaths(String credentials.
server, List\<String> trustedKeyPaths)

public static void


removeColumnEncryptionTrustedMasterKeyPaths(String
server)
NAME DESC RIP T IO N

New method: Returns a list of trusted key paths for a database server.

public static Map<String, List\<String>>


getColumnEncryptionTrustedMasterKeyPaths()

New method: Allows you to register custom key store providers. It's a
dictionary that maps key store provider names to key store
public static void provider implementations.
registerColumnEncryptionKeyStoreProviders (Map\
<String, SQLServerColumnEncryptionKeyStoreProvider>
clientKeyStoreProviders) To use the JVM key store, you need to instantiate a
SQLServerColumnEncryptionJVMKeyStoreProvider object
with JVM keystore credentials and register it with the driver.
The name for this provider must be
'MSSQL_JVM_KEYSTORE'.

To use the Azure Key Vault store, you need to instantiate a


SQLServerColumnEncryptionAzureKeyStoreProvider object
and register it with the driver. The name for this provider
must be 'AZURE_KEY_VAULT'.

New method: Allows you to unregister all the custom key store providers
by clearing the dictionary that maps key store provider
public static void names to key store provider implementations.
unregisterColumnEncryptionKeyStoreProviders (Map\
<String, SQLServerColumnEncryptionKeyStoreProvider>
clientKeyStoreProviders)

public final boolean getSendTimeAsDatetime() Returns the setting of the sendTimeAsDatetime connection
property.

public void setSendTimeAsDatetime(boolean Modifies the setting of the sendTimeAsDatetime connection


sendTimeAsDateTimeValue) property.

SQLServerConnectionPoolProxy class
NAME DESC RIP T IO N

public final boolean getSendTimeAsDatetime() Returns the setting of the sendTimeAsDatetime connection
property.

public void setSendTimeAsDatetime(boolean Modifies the setting of the sendTimeAsDatetime connection


sendTimeAsDateTimeValue) property.

SQLServerDataSource class
NAME DESC RIP T IO N

public void setColumnEncryptionSetting(String Enables/disables Always Encrypted functionality for the data
columnEncryptionSetting) source object.

The default is Disabled.

public String getColumnEncryptionSetting() Retrieves the Always Encrypted functionality setting for the
data source object.
NAME DESC RIP T IO N

public void setKeyStoreAuthentication(String Sets the name that identifies a key store. Only value
keyStoreAuthentication) supported is the JavaKeyStorePassword for identifying
the Java Key Store.

The default is null.

public String getKeyStoreAuthentication() Gets the value of the keyStoreAuthentication setting for the
data source object.

public void setKeyStoreSecret(String Sets the password for the Java keystore. The password for
keyStoreSecret) the keystore and the key must be the same.
keyStoreAuthentication must be set with
JavaKeyStorePassword .

public void setKeyStoreLocation(String Sets the location including the file name for the Java
keyStoreLocation) keystore. keyStoreAuthentication must be set with
JavaKeyStorePassword .

public String getKeyStoreLocation() Retrieves the keyStoreLocation for the Java Key Store.

SQLServerColumnEncryptionJavaKeyStoreProvider class
The implementation of the key store provider for Java Key Store. This class enables using certificates stored in
the Java keystore as column master keys.
Constructors:

NAME DESC RIP T IO N

public Key store provider for the Java Key Store.


SQLServerColumnEncryptionJavaKeyStoreProvider
(String keyStoreLocation, char[] keyStoreSecret)

Methods:

NAME DESC RIP T IO N

public byte[] decryptColumnEncryptionKey (String Decrypts the specified encrypted value of a column
masterKeyPath, String encryptionAlgorithm, byte[] encryption key. The encrypted value is expected to be
encryptedColumnEncryptionKey)
encrypted using the certificate with the specified key path
and using the specified algorithm.

The key path should be in one of the following


formats:

Thumbprint:<certificate_thumbprint>

Alias:<certificate_alias>

(Overrides SQLServerColumnEncryptionKeyStoreProvider .
decryptColumnEncryptionKey(String, String, Byte[]).)
NAME DESC RIP T IO N

public byte[] encryptColumnEncryptionKey (String Encrypts a column encryption key using the certificate with
masterKeyPath, String encryptionAlgorithm, byte[] the specified key path and using the specified algorithm.
plainTextColumnEncryptionKey)

The key path should be in one of the following


formats:

Thumbprint:<certificate_thumbprint>

Alias:<certificate_alias>

(Overrides SQLServerColumnEncryptionKeyStoreProvider .
encryptColumnEncryptionKey(String, String, Byte[]).)

public boolean verifyColumnEncryptionKey (String Verifies the signature of the column encryption key using
masterKeyPath, boolean allowEnclaveComputations, the certificate.
byte[] signature)

The key path should be in one of the following


formats:

Thumbprint:<certificate_thumbprint>

Alias:<certificate_alias>

(Overrides SQLServerColumnEncryptionKeyStoreProvider .
verifyColumnEncryptionKey(String, boolean, Byte[]).)

public void setName (String name) Sets the name of this key store provider.

public String getName () Gets the name of this key store provider.

SQLServerColumnEncryptionAzureKeyVaultProvider class
The implementation of the key store provider for Azure Key Vault. This class enables using keys stored in the
Azure Key Vault as column master keys.
Constructors:

NAME DESC RIP T IO N

public Constructs a
SQLServerColumnEncryptionAzureKeyVaultProvider () SQLServerColumnEncryptionAzureKeyVaultProvider to
authenticate to Azure Key Vault.

public Constructs a
SQLServerColumnEncryptionAzureKeyVaultProvider SQLServerColumnEncryptionAzureKeyVaultProvider to
(String clientId)
authenticate to Azure Key Vault using the identifier of the
client requesting the token.

public Constructs a
SQLServerColumnEncryptionAzureKeyVaultProvider SQLServerColumnEncryptionAzureKeyVaultProvider to
(String clientId, String clientKey)
authenticate to Azure Key Vault using the identifier and the
key of the client requesting the token.

public Constructs a
SQLServerColumnEncryptionAzureKeyVaultProvider SQLServerColumnEncryptionAzureKeyVaultProvider to
(TokenCredential tokenCredential)
authenticate to Azure Key Vault using provided
TokenCredential.
Methods:

NAME DESC RIP T IO N

public byte[] decryptColumnEncryptionKey (String Decrypts an encrypted column encryption key (CEK). This
masterKeyPath, String encryptionAlgorithm, byte[] decryption is accomplished with an RSA encryption
encryptedColumnEncryptionKey)
algorithm that uses the asymmetric key specified by the
master key path.
(Overrides SQLServerColumnEncryptionKeyStoreProvider .
decryptColumnEncryptionKey(String, String, Byte[]).)

public byte[] encryptColumnEncryptionKey (String Encrypts a column encryption key, by giving the specified
masterKeyPath, String encryptionAlgorithm, byte[] column master key to the specified algorithm.
columnEncryptionKey)
(Overrides SQLServerColumnEncryptionKeyStoreProvider .
encryptColumnEncryptionKey(String, String, Byte[]).)

public void setName (String name) Sets the name of this key store provider.

public String getName () Gets the name of this key store provider.

SQLServerKeyVaultAuthenticationCallback interface
This interface contains one method for Azure Key Vault authentication, which is to be implemented by user.
Methods:

NAME DESC RIP T IO N

public String getAccessToken(String authority, The method must be overridden. The method is used to get
String resource, String scope); an access token to Azure Key Vault.

SQLServerColumnEncryptionKeyStoreProvider class
Extend this class to implement a custom key store provider.

NAME DESC RIP T IO N

SQLServerColumnEncryptionKeyStoreProvider Base class for all key store providers. A custom provider
must derive from this class and override its member
functions and then register it using SQLServerConnection.
registerColumnEncryptionKeyStoreProviders().

Methods:

NAME DESC RIP T IO N

public abstract byte[] decryptColumnEncryptionKey Base class method for decrypting the specified encrypted
(String masterKeyPath, String encryptionAlgorithm, value of a column encryption key. The encrypted value is
byte [] encryptedColumnEncryptionKey)
expected to be encrypted using the column master key with
the specified key path and the specified algorithm.

public abstract byte[] encryptColumnEncryptionKey Base class method for encrypting a column encryption key
(String masterKeyPath, String encryptionAlgorithm, using the column master key with the specified key path and
byte[] columnEncryptionKey)
using the specified algorithm.

public abstract void setName(String name) Sets the name of this key store provider.
NAME DESC RIP T IO N

public abstract String getName() Gets the name of this key store provider.

New or overloaded methods in SQLServerPreparedStatement class


NAME DESC RIP T IO N

public void setBigDecimal(int parameterIndex, These methods are overloaded with a precision or a scale
BigDecimal x, int precision, int scale) argument or both to support Always Encrypted for specific
data types that require precision and scale information.
public void setObject(int parameterIndex, Object x,
int targetSqlType, Integer precision, int scale)

public void setObject(int parameterIndex, Object x,


SQLType targetSqlType, Integer precision, Integer
scale)

public void setTime(int parameterIndex,


java.sql.Time x, int scale)

public void setTimestamp(int parameterIndex,


java.sql.Timestamp x, int scale)
public void setDateTimeOffset(int parameterIndex,
microsoft.sql.DateTimeOffset x, int scale)

public void setMoney(int parameterIndex, BigDecimal These methods add support for Always Encrypted for the
x) data types money, smallmoney, uniqueidentifier, datetime
and smalldatetime.
public void setSmallMoney(int parameterIndex,
BigDecimal x)
The existing setTimestamp() method is used for sending
parameter values to the encrypted datetime2 column. For
public void setUniqueIdentifier(int parameterIndex,
String guid) encrypted datetime and smalldatetime columns, use the new
methods setDateTime() and setSmallDateTime()
public void setDateTime(int parameterIndex, respectively.
java.sql.Timestamp x)

public void setSmallDateTime(int parameterIndex,


java.sql.Timestamp x)

public final void setBigDecimal(int parameterIndex, Sets the named parameter to the given java value.
BigDecimal x, int precision, int scale, boolean
forceEncrypt)
If the boolean forceEncrypt is set to true, the query
parameter will only be set if the designated column is
public final void setMoney(int parameterIndex,
BigDecimal x, boolean forceEncrypt) encrypted and Always Encrypted is enabled on the
connection or on the statement.
public final void setSmallMoney(int parameterIndex,
BigDecimal x, boolean forceEncrypt) If the boolean forceEncrypt is set to false, the driver won't
force encryption on parameters.
public final void setBoolean(int parameterIndex,
boolean x, boolean forceEncrypt)

public final void setByte(int parameterIndex, byte


x, boolean forceEncrypt)

public final void setBytes(int parameterIndex, byte


x[], boolean forceEncrypt)

public final void setUniqueIdentifier(int


parameterIndex, String guid, boolean forceEncrypt)

public final void setDouble(int parameterIndex,


double x, boolean forceEncrypt)
NAME DESC RIP T IO N
public final void setFloat(int parameterIndex,
float x, boolean forceEncrypt)

public final void setInt(int parameterIndex, int


value, boolean forceEncrypt)

public final void setLong(int parameterIndex, long


x, boolean forceEncrypt)

public final setObject(int parameterIndex, Object


x, int targetSqlType, Integer precision, int scale,
boolean forceEncrypt)

public final void setObject(int parameterIndex,


Object x, SQLType targetSqlType, Integer precision,
Integer scale, boolean forceEncrypt)

public final void setShort(int parameterIndex,


short x, boolean forceEncrypt)

public final void setString(int parameterIndex,


String str, boolean forceEncrypt)

public final void setNString(int parameterIndex,


String value, boolean forceEncrypt)

public final void setTime(int parameterIndex,


java.sql.Time x, int scale, boolean forceEncrypt)

public final void setTimestamp(int parameterIndex,


java.sql.Timestamp x, int scale, boolean
forceEncrypt)

public final void setDateTimeOffset(int


parameterIndex, microsoft.sql.DateTimeOffset x, int
scale, boolean forceEncrypt)

public final void setDateTime(int parameterIndex,


java.sql.Timestamp x, boolean forceEncrypt)

public final void setSmallDateTime(int


parameterIndex, java.sql.Timestamp x, boolean
forceEncrypt)

public final void setDate(int parameterIndex,


java.sql.Date x, java.util.Calendar cal, boolean
forceEncrypt)

public final void setTime(int parameterIndex,


java.sql.Time x, java.util.Calendar cal, boolean
forceEncrypt)

public final void setTimestamp(int parameterIndex,


java.sql.Timestamp x, java.util.Calendar cal,
boolean forceEncrypt)

New or overloaded methods in SQLServerCallableStatement class


NAME DESC RIP T IO N

public void registerOutParameter(int These methods are overloaded with a precision or a scale
parameterIndex, int sqlType, int precision, int argument or both to support Always Encrypted for specific
scale)
data types that require precision and scale information.
public void registerOutParameter(int
parameterIndex, SQLType sqlType, int precision, int
scale)

public void registerOutParameter(String


parameterName, int sqlType, int precision, int
scale)

public void registerOutParameter(String


parameterName, SQLType sqlType, int precision, int
scale)
public void setBigDecimal(String parameterName,
BigDecimal bd, int precision, int scale)

public void setTime(String parameterName,


java.sql.Time t, int scale)

public void setTimestamp(String parameterName,


java.sql.Timestamp t, int scale)

public void setDateTimeOffset(String parameterName,


microsoft.sql.DateTimeOffset t, int scale)

public final void setObject(String sCol, Object x,


int targetSqlType, Integer precision, int scale)
NAME DESC RIP T IO N

public void setDateTime(String parameterName, These methods add support for Always Encrypted for the
java.sql.Timestamp x) data types money, smallmoney, uniqueidentifier, datetime
and smalldatetime.
public void setSmallDateTime(String parameterName,
java.sql.Timestamp x)
The existing setTimestamp() method is used for sending
parameter values to the encrypted datetime2 column. For
public void setUniqueIdentifier(String
parameterName, String guid) encrypted datetime and smalldatetime columns, use the new
methods setDateTime() and setSmallDateTime()
public void setMoney(String parameterName,
respectively.
BigDecimal bd)

public void setSmallMoney(String parameterName,


BigDecimal bd)

public Timestamp getDateTime(int index)

public Timestamp getDateTime(String sCol)

public Timestamp getDateTime(int index, Calendar


cal)

public Timestamp getSmallDateTime(int index)

public Timestamp getSmallDateTime(String sCol)

public Timestamp getSmallDateTime(int index,


Calendar cal)

public Timestamp getSmallDateTime(String name,


Calendar cal)

public BigDecimal getMoney(int index)

public BigDecimal getMoney(String sCol)

public BigDecimal getSmallMoney(int index)

public BigDecimal getSmallMoney(String sCol)

public void setObject(String parameterName, Object Sets the named parameter to the given java value.
o, int n, int m, boolean forceEncrypt)
If the boolean forceEncrypt is set to true, the query
public void setObject(String parameterName, Object parameter will only be set if the designated column is
obj, SQLType jdbcType, int scale, boolean
forceEncrypt) encrypted and Always Encrypted is enabled on the
connection or on the statement.
public void setDate(String parameterName,
java.sql.Date x, Calendar c, boolean forceEncrypt) If the boolean forceEncrypt is set to false, the driver won't
force encryption on parameters.
public void setTime(String parameterName,
java.sql.Time t, int scale, boolean forceEncrypt)

public void setTime(String parameterName,


java.sql.Time x, Calendar c, boolean forceEncrypt)

public void setDateTime(String parameterName,


java.sql.Timestamp x, boolean forceEncrypt)

public void setDateTimeOffset(String parameterName,


microsoft.sql.DateTimeOffset t, int scale, boolean
forceEncrypt)
public void setSmallDateTime(String parameterName,
Njava.sql.Timestamp
AME x, boolean forceEncrypt) DESC RIP T IO N

public void setTimestamp(String parameterName,


java.sql.Timestamp t, int scale, boolean
forceEncrypt)

public void setTimestamp(String parameterName,


java.sql.Timestamp x, boolean forceEncrypt)

public void setUniqueIdentifier(String


parameterName, String guid, boolean forceEncrypt)

public void setBytes(String parameterName, byte[]


b, boolean forceEncrypt)

public void setByte(String parameterName, byte b,


boolean forceEncrypt)

public void setString(String parameterName, String


s, boolean forceEncrypt)

public final void setNString(String parameterName,


String value, boolean forceEncrypt)<br /><br />
public void setMoney(String parameterName,
BigDecimal bd, boolean forceEncrypt)

public void setSmallMoney(String parameterName,


BigDecimal bd, boolean forceEncrypt)

public void setBigDecimal(String parameterName,


BigDecimal bd, int precision, int scale, boolean
forceEncrypt)

public void setDouble(String parameterName, double


d, boolean forceEncrypt)

public void setFloat(String parameterName, float f,


boolean forceEncrypt)

public void setInt(String parameterName, int i,


boolean forceEncrypt)

public void setLong(String parameterName, long l,


boolean forceEncrypt)

public void setShort(String parameterName, short s,


boolean forceEncrypt)

public void setBoolean(String parameterNames,


boolean b, boolean forceEncrypt)

public void setTimeStamp(String sCol,


java.sql.Timestamp x, Calendar c, Boolean
forceEncrypt)

New or overloaded methods in SQLServerResultSet class


NAME DESC RIP T IO N

public String getUniqueIdentifier(int columnIndex) These methods add support for Always Encrypted for the
data types money, smallmoney, uniqueidentifier, datetime,
public String getUniqueIdentifier(String and smalldatetime.
columnLabel)
The existing updateTimestamp() method is used for
public java.sql.Timestamp getDateTime(int updating encrypted datetime2 columns. For encrypted
columnIndex)
datetime and smalldatetime columns, use the new methods
updateDateTime() and updateSmallDateTime()
public java.sql.Timestamp getDateTime(String
columnName) respectively.

public java.sql.Timestamp getDateTime(int


columnIndex, Calendar cal)

public java.sql.Timestamp getDateTime(String


colName, Calendar cal)

public java.sql.Timestamp getSmallDateTime(int


columnIndex)

public java.sql.Timestamp getSmallDateTime(String


columnName)

public java.sql.Timestamp getSmallDateTime(int


columnIndex, Calendar cal)

public java.sql.Timestamp getSmallDateTime(String


colName, Calendar cal)

public BigDecimal getMoney(int columnIndex)

public BigDecimal getMoney(String columnName)

public BigDecimal getSmallMoney(int columnIndex)

public BigDecimal getSmallMoney(String columnName)

public void updateMoney(String columnName,


BigDecimal x)

public void updateSmallMoney(String columnName,


BigDecimal x)

public void updateDateTime(int index,


java.sql.Timestamp x)

public void updateSmallDateTime(int index,


java.sql.Timestamp x)

public void updateBoolean(int index, boolean x, Updates the named column to the given java value.
boolean forceEncrypt)
If the boolean forceEncrypt is set to true, the column will
public void updateByte(int index, byte x, boolean only be set if it's encrypted and Always Encrypted is enabled
forceEncrypt)
on the connection or on the statement.
public void updateShort(int index, short x, boolean
forceEncrypt) If the boolean forceEncrypt is set to false, the driver won't
force encryption on parameters.
public void updateInt(int index, int x, boolean
forceEncrypt)

public void updateLong(int index, long x, boolean


forceEncrypt)
public void updateFloat(int index, float x, boolean
NforceEncrypt)
AME DESC RIP T IO N

public void updateDouble(int index, double x,


boolean forceEncrypt)

public void updateMoney(int index, BigDecimal x,


boolean forceEncrypt)

public void updateMoney(String columnName,


BigDecimal x, boolean forceEncrypt)

public void updateSmallMoney(int index, BigDecimal


x, boolean forceEncrypt)

public void updateSmallMoney(String columnName,


BigDecimal x, boolean forceEncrypt)

public void updateBigDecimal(int index, BigDecimal


x, Integer precision, Integer scale, boolean
forceEncrypt)

public void updateString(int columnIndex, String


stringValue, boolean forceEncrypt)

public void updateNString(int columnIndex, String


nString, boolean forceEncrypt)

public void updateNString(String columnLabel,


String nString, boolean forceEncrypt)

public void updateBytes(int index, byte x[],


boolean forceEncrypt) <br/><br/> public void
updateDate(int index, java.sql.Date x, boolean
forceEncrypt)

public void updateTime(int index, java.sql.Time x,


Integer scale, boolean forceEncrypt)

public void updateTimestamp(int index,


java.sql.Timestamp x, int scale, boolean
forceEncrypt)

public void updateDateTime(int index,


java.sql.Timestamp x, Integer scale, boolean
forceEncrypt)

public void updateSmallDateTime(int index,


java.sql.Timestamp x, Integer scale, boolean
forceEncrypt)

public void updateDateTimeOffset(int index,


microsoft.sql.DateTimeOffset x, Integer scale,
boolean forceEncrypt)

public void updateUniqueIdentifier(int index,


String x, boolean forceEncrypt)

public void updateObject(int index, Object x, int


precision, int scale, boolean forceEncrypt)

public void updateObject(int index, Object obj,


SQLType targetSqlType, int scale, boolean
forceEncrypt)

public void updateBoolean(String columnName,


boolean x, boolean forceEncrypt)

public void updateByte(String columnName, byte x,


boolean forceEncrypt)
NAME DESC RIP T IO N
public void updateShort(String columnName, short x,
boolean forceEncrypt)

public void updateInt(String columnName, int x,


boolean forceEncrypt)

public void updateLong(String columnName, long x,


boolean forceEncrypt)

public void updateFloat(String columnName, float x,


boolean forceEncrypt)

public void updateDouble(String columnName, double


x, boolean forceEncrypt) <br/><br/> public void
updateBigDecimal(String columnName, BigDecimal x,
boolean forceEncrypt)

public void updateBigDecimal(String columnName,


BigDecimal x, Integer precision, Integer scale,
boolean forceEncrypt)

public void updateString(String columnName, String


x, boolean forceEncrypt)

public void updateBytes(String columnName, byte


x[], boolean forceEncrypt)

public void updateDate(String columnName,


java.sql.Date x, boolean forceEncrypt)

public void updateTime(String columnName,


java.sql.Time x, int scale, boolean forceEncrypt)

public void updateTimestamp(String columnName,


java.sql.Timestamp x, int scale, boolean
forceEncrypt)

public void updateDateTime(String columnName,


java.sql.Timestamp x, int scale, boolean
forceEncrypt)

public void updateSmallDateTime(String columnName,


java.sql.Timestamp x, int scale, boolean
forceEncrypt)

public void updateDateTimeOffset(String columnName,


microsoft.sql.DateTimeOffset x, int scale, boolean
forceEncrypt)

public void updateUniqueIdentifier(String


columnName, String x, boolean forceEncrypt)

public void updateObject(String columnName, Object


x, int precision, int scale, boolean forceEncrypt)

public void updateObject(String columnName, Object


obj, SQLType targetSqlType, int scale, boolean
forceEncrypt)

New types in microsoft.sql.Types class


NAME DESC RIP T IO N

DATETIME, SMALLDATETIME, MONEY, SMALLMONEY, GUID Use these types as the target SQL types when sending
parameter values to encr ypted datetime, smalldatetime,
money, smallmoney, uniqueidentifier columns using
setObject()/updateObject() API methods.
SQLServerStatementColumnEncryptionSetting Enum
Specifies how data will be sent and received when reading and writing encrypted columns. Depending on your
specific query, performance impact may be reduced by bypassing the Always Encrypted driver's processing
when non-encrypted columns are being used. These settings can't be used to bypass encryption and gain access
to plaintext data.
Syntax:

Public enum SQLServerStatementColumnEncryptionSetting

Members:

NAME DESC RIP T IO N

UseConnectionSetting Specifies that the command should default to the Always


Encrypted setting in the connection string.

Enabled Enables Always Encrypted for the query.

ResultSetOnly Specifies that only the results of the command should be


processed by the Always Encrypted routine in the driver. Use
this value when the command has no parameters that
require encryption.

Disabled Disables Always Encrypted for the query.

The statement level setting for AE is added to the SQLServerConnection class and to the
SQLServerConnectionPoolProxy class. The following methods in these classes are overloaded with the new
setting.

NAME DESC RIP T IO N

public Statement createStatement(int nType, int Creates a Statement object that will generate ResultSet
nConcur, int statementHoldability, objects with the given type, concurrency, holdability, and
SQLServerStatementColumnEncryptionSetting
stmtColEncSetting) column encryption setting.

public CallableStatement prepareCall(String sql, Creates a CallableStatement object with the given column
int nType, int nConcur, int statementHoldability, encryption setting that will generate ResultSet objects with
SQLServerStatementColumnEncryptionSetting
stmtColEncSetiing) the given type, concurrency, and holdability.

public PreparedStatement prepareStatement(String Creates a PreparedStatement object with the given column
sql, int autogeneratedKeys, encryption setting that has the capability to retrieve
SQLServerStatementColumnEncryptionSetting
stmtColEncSetting) autogenerated keys.

public PreparedStatement prepareStatement(String Creates a PreparedStatement object with the given column
sql, String[] columnNames, encryption setting that will generate ResultSet objects with
SQLServerStatementColumnEncryptionSetting
stmtColEncSetting) the given column names.

public PreparedStatement prepareStatement(String Creates a PreparedStatement object with the given column
sql, int[] columnIndexes, encryption setting that will generate ResultSet objects with
SQLServerStatementColumnEncryptionSetting
stmtColEncSetting the given column indexes.
NAME DESC RIP T IO N

public PreparedStatement prepareStatement(String Creates a PreparedStatement object with the given column
sql, int nType, int nConcur, int nHold, encryption setting that will generate ResultSet objects with
SQLServerStatementColumnEncryptionSetting
stmtColEncSetting) the given type, concurrency, and holdability.

NOTE
If Always Encrypted is disabled for a query and the query has parameters that need to be encrypted (parameters that
correspond to encrypted columns), the query will fail.
If Always Encrypted is disabled for a query and the query returns results from encrypted columns, the query will return
encrypted values. The encrypted values will have the varbinary datatype.

See also
Using Always Encrypted with the JDBC driver
JDBC driver support for High Availability, disaster
recovery
4/27/2022 • 8 minutes to read • Edit Online

Download JDBC Driver


This article discusses Microsoft JDBC Driver for SQL Server support for high-availability, disaster recovery:
Always On Availability Groups. For more information about Always On Availability Groups, see SQL Server
2012 (11.x) Books Online.
Beginning in version 4.0 of the Microsoft JDBC Driver for SQL Server, you can specify the availability group
listener of a (high-availability, disaster-recovery) availability group (AG) in the connection property. If a
Microsoft JDBC Driver for SQL Server application is connected to an AlwaysOn database that fails over, the
original connection is broken, and the application must open a new connection to continue work after the
failover. The following connection properties were added in Microsoft JDBC Driver 4.0 for SQL Server:
multiSubnetFailover
applicationIntent
Specify multiSubnetFailover=true when connecting to the availability group listener of an availability group or a
Failover Cluster Instance.

NOTE
multiSubnetFailover is false by default. Use applicationIntent to declare the application workload type. For more
details, see the sections below.

Beginning in version 6.0 of the Microsoft JDBC Driver for SQL Server, a new connection property
transparentNetworkIPResolution (TNIR) is added for transparent connection to Always On availability
groups or to a server that has multiple IP addresses associated. When transparentNetworkIPResolution is
true, the driver attempts to connect to the first IP address available. If the first attempt fails, the driver tries to
connect to all IP addresses in parallel until the timeout expires, discarding any pending connection attempts
when one of them succeeds.
Note:
transparentNetworkIPResolution is true by default
transparentNetworkIPResolution is ignored if multiSubnetFailover is true
transparentNetworkIPResolution is ignored if database mirroring is used
transparentNetworkIPResolution is ignored if there are more than 64 IP addresses
When transparentNetworkIPResolution is true, the first connection attempt uses a timeout value of 500 ms.
Rest of the connection attempts follow the same logic as in the multiSubnetFailover feature.
NOTE
If you are using Microsoft JDBC Driver 4.2 (or lower) for SQL Server and if multiSubnetFailover is false, the Microsoft
JDBC Driver for SQL Server attempts to connect to the first IP address. If the Microsoft JDBC Driver for SQL Server
cannot establish a connection with first IP address, the connection fails. The Microsoft JDBC Driver for SQL Server will not
attempt to connect to any subsequent IP address associated with the server.

NOTE
Increasing connection timeout and implementing connection retry logic will increase the probability that an application
will connect to an availability group. Also, because a connection can fail because of an availability group failover, you
should implement connection retry logic, retrying a failed connection until it reconnects.

Connecting with multiSubnetFailover


Always specify multiSubnetFailover=true when connecting to the availability group listener of a SQL Server
2012 (11.x) availability group or a SQL Server 2012 (11.x) Failover Cluster Instance. multiSubnetFailover
enables faster failover for all Availability Groups and failover cluster instances in SQL Server 2012 (11.x) and will
significantly reduce failover time for single and multi-subnet AlwaysOn topologies. During a multi-subnet
failover, the client will attempt connections in parallel. During a subnet failover, the Microsoft JDBC Driver for
SQL Server will aggressively retry the TCP connection.
The multiSubnetFailover connection property indicates that the application is being deployed in an
availability group or Failover Cluster Instance and that the Microsoft JDBC Driver for SQL Server will try to
connect to the database on the primary SQL Server instance by trying to connect to all the IP addresses. When
MultiSubnetFailover=true is specified for a connection, the client retries TCP connection attempts faster than
the operating system's default TCP retransmit intervals. This behavior enables faster reconnection after failover
of either an AlwaysOn Availability Group or an AlwaysOn Failover Cluster Instance, and applies to both single-
and multi-subnet Availability Groups and Failover Cluster Instances.
For more information about connection string keywords in the Microsoft JDBC Driver for SQL Server, see
Setting the Connection Properties.
Specifying multiSubnetFailover=true when connecting to something other than an availability group listener
or Failover Cluster Instance may result in a negative performance impact, and isn't supported.
If the security manager isn't installed, the Java Virtual Machine caches virtual IP addresses (VIPs) for a finite
period of time, by default, defined by your JDK implementation and the Java properties networkaddress.cache.ttl
and networkaddress.cache.negative.ttl. If the JDK security manager is installed, the Java Virtual Machine will
cache VIPs, and won't refresh the cache by default. You should set "time-to-live" (networkaddress.cache.ttl) to
one day for the Java Virtual Machine cache. If you don't change the default value to one day (or so), the old
value won't be purged from the Java Virtual Machine cache when a VIP is added or updated. For more
information about networkaddress.cache.ttl and networkaddress.cache.negative.ttl, see
https://download.oracle.com/javase/6/docs/technotes/guides/net/properties.html.
Use the following guidelines to connect to a server in an availability group or Failover Cluster Instance:
The driver will generate an error if the instanceName connection property is used in the same
connection string as the multiSubnetFailover connection property. This error reflects the fact that SQL
Browser isn't used in an availability group. However, if the por tNumber connection property is also
specified, the driver will ignore instanceName and use por tNumber .
Use the multiSubnetFailover connection property when connecting to a single subnet or multi-subnet,
it will improve performance for both.
To connect to an availability group, specify the availability group listener of the availability group as the
server in your connection string. For example, jdbc:sqlserver://VNN1.
Connecting to a SQL Server instance configured with more than 64 IP addresses will cause a connection
failure.
Behavior of an application that uses the multiSubnetFailover connection property isn't affected based
on the type of authentication: SQL Server Authentication, Kerberos Authentication, or Windows
Authentication.
Increase the value of loginTimeout to accommodate for failover time and reduce application connection
retry attempts.
If read-only routing isn't in effect, connecting to a secondary replica location in an availability group will fail in
the following situations:
If the secondary replica location isn't configured to accept connections.
If an application uses applicationIntent=ReadWrite (discussed below) and the secondary replica
location is configured for read-only access.
A connection will fail if a primary replica is configured to reject read-only workloads and the connection string
contains ApplicationIntent=ReadOnly .

Upgrading to Use multi-subnet clusters from database mirroring


If you upgrade a Microsoft JDBC Driver for SQL Server application that currently uses database mirroring to a
multi-subnet scenario, you should remove the failoverPar tner connection property and replace it with
multiSubnetFailover set to true and replace the server name in the connection string with an availability
group listener. If a connection string uses failoverPar tner and multiSubnetFailover=true , the driver will
generate an error. However, if a connection string uses failoverPar tner and multiSubnetFailover=false (or
ApplicationIntent=ReadWrite ), the application will use database mirroring.
The driver will return an error if database mirroring is used on the primary database in the AG, and if
multiSubnetFailover=true is used in the connection string that connects to a primary database instead of to
an availability group listener.

Specify application intent


You can specify the keyword ApplicationIntent in your connection string. The assignable values are ReadWrite
(the default) or ReadOnly .
When you set ApplicationIntent=ReadOnly , the client requests a read workload when connecting. The server
enforces the intent at connection time, and during a USE database statement.
The ApplicationIntent keyword doesn't work with legacy read-only databases.
Targets of ReadOnly
When a connection chooses ReadOnly , the connection is assigned to any of the following special configurations
that might exist for the database:
Always On. A database can allow or disallow read workloads on the targeted availability group database.
This choice is controlled by using the ALLOW_CONNECTIONS clause of the PRIMARY_ROLE and SECONDARY_ROLE
Transact-SQL statements.
Geo-replication
Read scale-out
If none of those special targets are available, the regular database is read from.
The ApplicationIntent keyword enables read-only routing.

Read-only routing
Read-only routing is a feature that can ensure the availability of a read-only replica of a database. To enable
read-only routing, all of the following apply:
You must connect to an Always On availability group listener.
The ApplicationIntent connection string keyword must be set to ReadOnly .
The database administrator must configure the availability group to enable read-only routing.
Multiple connections that each use read-only routing might not all connect to the same read-only replica.
Changes in database synchronization or changes in the server's routing configuration can result in client
connections to different read-only replicas.
You can ensure that all read-only requests connect to the same read-only replica by not passing an availability
group listener to the Server connection string keyword. Instead, specify the name of the read-only instance.
Read-only routing might take longer than connecting to the primary. This is because read-only routing first
connects to the primary, and then looks for the best available readable secondary. Due to these multiple steps,
you should increase your login timeout to at least 30 seconds.

Connection pooling
When using the Microsoft JDBC Driver for SQL Server in combination with a connection pooling library, you
should consider the following points:
If you have read-only routing configured and a pool of read-only servers that you want to distribute load
over, connection pooling will reduce the number of opportunities for new connections to spread over the
target servers.
To avoid a higher load on any single server in a pool, choose pool options that encourage an even
distribution of connections across the pool.
Make sure your connection pool is configured with a connection lifetime. In the event a read-only replica is
unavailable when a read-only connection is made, the configuration should ensure that connection is
eventually closed and re-established to a read-only replica when one becomes available again.

New methods supporting multiSubnetFailover and applicationIntent


The following methods give you programmatic access to the multiSubnetFailover , applicationIntent , and
transparentNetworkIPResolution connection string keywords:
SQLServerDataSource.getApplicationIntent
SQLServerDataSource.setApplicationIntent
SQLServerDataSource.getMultiSubnetFailover
SQLServerDataSource.setMultiSubnetFailover
SQLServerDriver.getPropertyInfo
SQLServerDataSource.setTransparentNetworkIPResolution
SQLServerDataSource.getTransparentNetworkIPResolution
The getMultiSubnetFailover , setMultiSubnetFailover , getApplicationIntent , setApplicationIntent ,
getTransparentNetworkIPResolution , and setTransparentNetworkIPResolution methods are also added
to SQLServerDataSource Class, SQLServerConnectionPoolDataSource Class, and SQLServerXADataSource
Class.

TLS/SSL certificate validation


An availability group consists of multiple physical servers. Microsoft JDBC Driver 4.0 for SQL Server added
support for Subject Alternate Name in TLS/SSL certificates so multiple hosts can be associated with the same
certificate. For more information on TLS, see Understanding encryption support.

See also
Connecting to SQL Server with the JDBC driver
Setting the connection properties
Using auto-generated keys
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server supports the optional JDBC 3.0 APIs to retrieve automatically
generated row identifiers. The main value of this feature is to provide a way to make IDENTITY values available
to an application that is updating a database table without a requiring a query and a second round trip to the
server.
Because SQL Server doesn't support pseudo columns for identifiers, updates that have to use the autogenerated
key feature must operate against a table that contains an IDENTITY column. SQL Server allows only a single
IDENTITY column per table. The result set that is returned by getGeneratedKeys method of the
SQLServerStatement class will have only one column, with the returned column name of GENERATED_KEYS. If
generated keys are requested on a table that has no IDENTITY column, the JDBC driver will return a null result
set.
As an example, create the following table in the sample database:

CREATE TABLE TestTable


(Col1 int IDENTITY,
Col2 varchar(50),
Col3 int);

In the following example, an open connection to the sample database is passed in to the function, an SQL
statement is constructed that will add data to the table, and then the statement is run and the IDENTITY column
value is displayed.

public static void executeInsertWithKeys(Connection con) {


try(Statement stmt = con.createStatement();) {
String SQL = "INSERT INTO TestTable (Col2, Col3) VALUES ('S', 50)";
int count = stmt.executeUpdate(SQL, Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();

ResultSetMetaData rsmd = rs.getMetaData();


int columnCount = rsmd.getColumnCount();
if (rs.next()) {
do {
for (int i=1; i<=columnCount; i++) {
String key = rs.getString(i);
System.out.println("KEY " + i + " = " + key);
}
} while(rs.next());
}
else {
System.out.println("NO KEYS WERE GENERATED.");
}
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}
See also
Using statements with the JDBC driver
Using database mirroring (JDBC)
4/27/2022 • 5 minutes to read • Edit Online

Download JDBC Driver


Database mirroring is primarily a software solution for increasing database availability and data redundancy.
The Microsoft JDBC Driver for SQL Server provides implicit support for database mirroring, so that the
developer doesn't need to write any code or take any other action when it has been configured for the database.
Database mirroring, which is implemented on a per-database basis, keeps a copy of a SQL Server production
database on a standby server. This server is either a hot or warm standby server, depending on the
configuration and state of the database mirroring session. A hot standby server supports rapid failover without
a loss of committed transactions. A warm standby server supports forcing service (with possible data loss).
The production database is called the principal database, and the standby copy is called the mirror database. The
principal database and mirror database must be on separate instances of SQL Server (server instances). They
should reside on separate computers, if possible.
The production server instance (the principal server) communicates with the standby server instance (the mirror
server). The principal and mirror servers act as partners within a database mirroring session. If the principal
server fails, the mirror server can make its database the principal database through a process called failover. For
example, Partner_A and Partner_B are two partner servers, with the principal database initially on Partner_A as
principal server, and the mirror database residing on Partner_B as the mirror server. If Partner_A goes offline, the
database on Partner_B can fail over to become the current principal database. When Partner_A rejoins the
mirroring session, it becomes the mirror server and its database becomes the mirror database.
If Partner_A server is irreparably damaged, a Partner_C server can be brought online to act as the mirror server
for Partner_B, which is now the principal server. However, in this scenario, the client application must include
programming logic to ensure that the connection string properties are updated with the new server names used
in the database mirroring configuration. Otherwise, the connection to the servers may fail.
Alternative database mirroring configurations offer different levels of performance and data safety, and support
different forms of failover. For more information, see "Overview of Database Mirroring" in SQL Server Books
Online.

Programming considerations
When the principal database server fails, the client application receives errors in response to API calls, which
indicate that the connection to the database has been lost. When these errors occur, any uncommitted changes
to the database are lost and the current transaction is rolled back. In this scenario, the application should close
the connection (or release the data source object) and try to reopen it. On connection, the new connection is
transparently redirected to the mirror database, which now acts as the principal server, without the client having
to modify the connection string or data source object.
When a connection is initially established, the principal server sends the identity of its failover partner to the
client that will be used when failover occurs. When an application tries to establish an initial connection with a
failed principal server, the client doesn't know the identity of the failover partner. To allow clients the opportunity
to cope with this scenario, the failoverPartner connection string property, and optionally the setFailoverPartner
data source method, allows the client to specify the identity of the failover partner on its own. The client
property is used only in this scenario; if the principal server is available, it isn't used.
NOTE
When a failoverPartner is specified in either the connection string or with a data source object, the databaseName
property must also be set or else an exception will be thrown. If the failoverPartner and databaseName are not specified
explicitly, the application will not attempt to failover when the principal database server fails. In other words, the
transparent redirection only works for connections that explicitly specify the failoverPartner and databaseName. For more
information about failoverPartner and other connection string properties, see Setting the connection properties.

If the failover partner server supplied by the client doesn't refer to a server acting as a failover partner for the
specified database, and if the server/database referred to is in a mirrored arrangement, the connection is
refused by the server. Although the SQLServerDataSource class provides the getFailoverPartner method, this
method only returns the name of the failover partner specified in the connection string or the setFailoverPartner
method. To retrieve the name of the actual failover partner that is currently being used, use the following
Transact-SQL statement:

SELECT m.mirroring_role_DESC, m.mirroring_state_DESC,


m.mirroring_partner_instance FROM sys.databases as db,
sys.database_mirroring AS m WHERE db.name = 'MirroringDBName'
AND db.database_id = m.database_id

NOTE
You will need to change this statement to use the name of your mirroring database.

Consider caching the partner information to update the connection string or devise a retry strategy in case the
first attempt at making a connection fails.

Example
In the following example, an attempt is first made to connect to the principle server. If that fails and an exception
is thrown, an attempt is made to connect to the mirror server, which may have been promoted to the new
principle server. Note the use of the failoverPartner property in the connection string.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class ClientFailover {


public static void main(String[] args) {

String connectionUrl = "jdbc:sqlserver://serverA:1433;"


+ "databaseName=AdventureWorks;integratedSecurity=true;"
+ "failoverPartner=serverB";

// Establish the connection to the principal server.


try (Connection con = DriverManager.getConnection(connectionUrl);
Statement stmt = con.createStatement();) {
System.out.println("Connected to the principal server.");

// Note that if a failover of serverA occurs here, then an


// exception will be thrown and the failover partner will
// be used in the first catch block below.

// Execute a SQL statement that inserts some data.

// Note that the following statement assumes that the


// TestTable table has been created in the AdventureWorks
// sample database.
stmt.executeUpdate("INSERT INTO TestTable (Col2, Col3) VALUES ('a', 10)");
}
catch (SQLException se) {
System.out.println("Connection to principal server failed, " + "trying the mirror server.");
// The connection to the principal server failed,
// try the mirror server which may now be the new
// principal server.
try (Connection con = DriverManager.getConnection(connectionUrl);
Statement stmt = con.createStatement();) {
System.out.println("Connected to the new principal server.");
stmt.executeUpdate("INSERT INTO TestTable (Col2, Col3) VALUES ('a', 10)");
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}
}
}

See also
Connecting to SQL Server with the JDBC driver
Understanding cursor types
4/27/2022 • 12 minutes to read • Edit Online

Download JDBC Driver


Operations in a relational database act on a complete set of rows. The set of rows returned by a SELECT
statement consists of all the rows that satisfy the conditions in the WHERE clause of the statement. This
complete set of rows returned by the statement is known as the result set. Applications can't always work
effectively with the entire result set as a unit. These applications need a way to work with one row or a small
block of rows at a time. Cursors are an extension to result sets that provide that mechanism.
Cursors extend result set processing by doing the following items:
Allowing positioning at specific rows of the result set.
Retrieving one row or block of rows from the current position in the result set.
Supporting data modifications to the row at the current position in the result set.
Supporting different levels of visibility to changes made to the database data by other users that is presented
in the result set.

NOTE
For a full description of the SQL Server cursor types, see Type of Cursors.

The JDBC specification provides support for forward-only and scrollable cursors that are sensitive or insensitive
to changes made by other jobs, and can be read-only or updatable. This functionality is provided by the
Microsoft JDBC Driver for SQL ServerSQLServerResultSet class.

Remarks
The JDBC driver supports the following result set and cursor types along with the specified behavior options.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_FORWARD_ON N/A Forward-only, read- direct full


LY only
(CONCUR_READ_ON
LY)

The application has to make a single (forward) pass through the result set. This pass is the default behavior and
behaves the same as a TYPE_SS_DIRECT_FORWARD_ONLY cursor. The driver reads the entire result set from the
server into a memory during the statement execution time.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_FORWARD_ON N/A Forward-only, read- direct full


LY only
(CONCUR_READ_ON
LY)

The application has to make a single (forward) pass through the result set. This pass is the default behavior and
behaves the same as a TYPE_SS_DIRECT_FORWARD_ONLY cursor. The driver reads the entire result set from the
server into a memory during the statement execution time.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_FORWARD_ON N/A Forward-only, read- direct adaptive


LY only
(CONCUR_READ_ON
LY)

The application has to make a single (forward) pass through the result set. It behaves the same as a
TYPE_SS_DIRECT_FORWARD_ONLY cursor. The driver reads rows from the server as the application requests
them and minimizes client-side memory usage.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_FORWARD_ON Fast Forward Forward-only, read- cursor N/A


LY only
(CONCUR_READ_ON
LY)

The application has to make a single (forward) pass through the result set by using a server cursor. It behaves
the same as a TYPE_SS_SERVER_CURSOR_FORWARD_ONLY cursor.
Rows are retrieved from the server in blocks that are specified by the fetch size.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_FORWARD_ON Dynamic (Forward- Forward-only, N/A N/A


LY only) updatable
(CONCUR_UPDATAB
LE)

The application has to make a single (forward) pass through the result set to update one or more rows.
Rows are retrieved from the server in blocks that are specified by the fetch size.
By default, the fetch size is fixed when the application calls the setFetchSize method of the SQLServerResultSet
object.

NOTE
The JDBC driver provides an adaptive buffering feature that allows you to retrieve statement execution results from the
SQL Server as the application needs them, rather than all at once. For example, if the application should retrieve a large
data that is too large to fit entirely in application memory, adaptive buffering allows the client application to retrieve such
a value as a stream. The default behavior of the driver is "adaptive ". However, in order to get the adaptive buffering for
the forward-only updatable result sets, the application has to explicitly call the setResponseBuffering method of the
SQLServerStatement object by providing a String value "adaptive". For an example code, see Updating large data
sample.
RESULT SET SQ L SERVER C URSO R RESP O N SE
( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SCROLL_INSEN Static Scrollable, not N/A N/A


SITIVE updateable.

External row updates,


inserts, and deletes
aren't visible.

The application requires a database snapshot. The result set isn't updatable. Only CONCUR_READ_ONLY is
supported. All other concurrency types will cause an exception when used with this cursor type.
Rows are retrieved from the server in blocks that are specified by the fetch size.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SCROLL_SENSI Keyset Scrollable, read-only. N/A N/A


TIVE External row updates
(CONCUR_READ_ON are visible, and
LY) deletes appear as
missing data.

External row inserts


aren't visible.

The application has to see changed data for existing rows only.
Rows are retrieved from the server in blocks that are specified by the fetch size.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SCROLL_SENSI Keyset Scrollable, updatable. N/A N/A


TIVE
(CONCUR_UPDATAB External and internal
LE, row updates are
CONCUR_SS_SCROLL visible, and deletes
_LOCKS, appear as missing
CONCUR_SS_OPTIMI data; inserts aren't
STIC_CC, visible.
CONCUR_SS_OPTIMI
STIC_CCVAL)

The application may change data in the existing rows by using the ResultSet object. The application must also be
able to see the changes to rows made by others from outside the ResultSet object.
Rows are retrieved from the server in blocks that are specified by the fetch size.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SS_DIRECT_FO N/A Forward-only, read- N/A full or adaptive


RWARD_ONLY only

Integer value = 2003. Provides a read-only client-side cursor that is fully buffered. No server cursor is created.
Only CONCUR_READ_ONLY concurrency type is supported. All other concurrency types cause an exception
when used with this cursor type.
RESULT SET SQ L SERVER C URSO R RESP O N SE
( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SS_SERVER_CU Fast Forward Forward-only N/A N/A


RSOR_FORWARD_ON
LY

Integer value = 2004. Fast and accesses all data using a server cursor. It's updatable when used with
CONCUR_UPDATABLE concurrency type.
Rows are retrieved from the server in blocks that are specified by the fetch size.
To get adaptive buffering for this case, the application has to explicitly call the setResponseBuffering method of
the SQLServerStatement object by providing a String value "adaptive" . For an example code, see Updating
large data sample.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SS_SCROLL_ST Static Other users' updates N/A N/A


ATIC aren't reflected.

Integer value = 1004. Application requires a database snapshot. This option is the SQL Server-specific synonym
for the JDBC TYPE_SCROLL_INSENSITIVE and has the same concurrency setting behavior.
Rows are retrieved from the server in blocks that are specified by the fetch size.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SS_SCROLL_KE Keyset Scrollable, read-only. N/A N/A


YSET External row updates
(CONCUR_READ_ON are visible, and
LY) deletes appear as
missing data.

External row inserts


aren't visible.

Integer value = 1005. Application has to see changed data for existing rows only. This option is the SQL Server-
specific synonym for the JDBC TYPE_SCROLL_SENSITIVE and has the same concurrency setting behavior.
Rows are retrieved from the server in blocks that are specified by the fetch size.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SS_SCROLL_KE Keyset Scrollable, updatable. N/A N/A


YSET
(CONCUR_UPDATAB External and internal
LE, row updates are
CONCUR_SS_SCROLL visible, and deletes
_LOCKS, appear as missing
CONCUR_SS_OPTIMI data; inserts aren't
STIC_CC, visible.
CONCUR_SS_OPTIMI
STIC_CCVAL)

Integer value = 1005. Application has to change data or see changed data for existing rows. This option is the
SQL Server-specific synonym for the JDBC TYPE_SCROLL_SENSITIVE and has the same concurrency setting
behavior.
Rows are retrieved from the server in blocks that are specified by the fetch size.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SS_SCROLL_DY Dynamic Scrollable, read-only. N/A N/A


NAMIC
(CONCUR_READ_ON External row updates
LY) and inserts are
visible, and deletes
appear as transient
missing data in the
current fetch buffer.

Integer value = 1006. Application must see changed data for existing rows, and see inserted and deleted rows
during the lifetime of the cursor.
Rows are retrieved from the server in blocks that are specified by the fetch size.

RESULT SET SQ L SERVER C URSO R RESP O N SE


( C URSO R) T Y P E TYPE C H A RA C T ERIST IC S SEL EC T M ET H O D B UF F ERIN G

TYPE_SS_SCROLL_DY Dynamic Scrollable, updatable. N/A N/A


NAMIC
(CONCUR_UPDATAB External and internal
LE, row updates and
CONCUR_SS_SCROLL inserts are visible,
_LOCKS, and deletes appear
CONCUR_SS_OPTIMI as transient missing
STIC_CC, data in the current
CONCUR_SS_OPTIMI fetch buffer.
STIC_CCVAL)

Integer value = 1006. The application may change data for existing rows, or insert or delete rows by using the
ResultSet object. The application must also be able to see changes, inserts, and deletes made by others from
outside the ResultSet object.
Rows are retrieved from the server in blocks that are specified by the fetch size.

Cursor positioning
The TYPE_FORWARD_ONLY, TYPE_SS_DIRECT_FORWARD_ONLY, and
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY cursors support only the next positioning method.
The TYPE_SS_SCROLL_DYNAMIC cursor doesn't support the absolute and getRow methods. The absolute
method can be approximated by a combination of calls to the first and relative methods for dynamic cursors.
The getRow method is supported by TYPE_FORWARD_ONLY, TYPE_SS_DIRECT_FORWARD_ONLY,
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY, TYPE_SS_SCROLL_KEYSET, and TYPE_SS_SCROLL_STATIC cursors
only. The getRow method with all forward-only cursor types returns the number of rows read so far through the
cursor.
NOTE
When an application makes an unsupported cursor positioning call, or an unsupported call to the getRow method, an
exception is thrown with the message, "The requested operation is not supported with this cursor type."

Only the TYPE_SS_SCROLL_KEYSET and the equivalent TYPE_SCROLL_SENSITIVE cursors expose deleted rows. If
the cursor is positioned on a deleted row, column values are unavailable, and the rowDeleted method returns
"true". Calls to get<Type> methods throw an exception with the message, "Cannot get value from a deleted
row". Deleted rows cannot be updated. If you try to call an update<Type> method on a deleted row, an
exception is thrown with the message, "A deleted row cannot be updated". The TYPE_SS_SCROLL_DYNAMIC
cursor has the same behavior until the cursor is moved out of the current fetch buffer.
Forward and dynamic cursors expose deleted rows in a similar way, but only while the cursors remain accessible
in the fetch buffer. For forward cursors, this behavior is fairly straightforward. For dynamic cursors, it more
complex when the fetch size is greater than 1. An application can move the cursor forward and backward within
the window that is defined by the fetch buffer, but the deleted row will disappear when the original fetch buffer
in which it was updated is left. If an application doesn't want to see transient deleted rows by using dynamic
cursors, a fetch relative (0) should be used.
If the key values of a TYPE_SS_SCROLL_KEYSET or TYPE_SCROLL_SENSITIVE cursor row are updated with the
cursor, the row keeps its original position in the result set, regardless of whether the updated row meets the
cursor's selection criteria. If the row was updated outside the cursor, a deleted row will appear at the row's
original position, but the row will appear in the cursor only if another row with the new key values was present
in the cursor, but has since been deleted.
For dynamic cursors, updated rows will keep their position within the fetch buffer until the window that is
defined by the fetch buffer is left. Updated rows might later reappear at different positions within the result set,
or might disappear completely. Applications that have to avoid transient inconsistencies in the result set should
use a fetch size of 1 (the default is 8 rows with CONCUR_SS_SCROLL_LOCKS concurrency and 128 rows with
other concurrencies).

Cursor conversion
SQL Server can sometimes choose to implement a cursor type other than the one requested, which is referred
to as an implicit cursor conversion (or cursor degradation).
With SQL Server 2000 (8.x), when you update the data through the ResultSet.TYPE_SCROLL_SENSITIVE and
ResultSet.CONCUR_UPDATABLE result set, an exception is thrown with a message "The cursor is READ ONLY".
This exception occurs because the SQL Server 2000 (8.x) has done an implicit cursor conversion for that result
set and didn't return the updatable cursor that has been requested.
To work around this problem, you can do one of the following solutions:
Ensure that the underlying table has a primary key
Use SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC instead of ResultSet.TYPE_SCROLL_SENSITIVE while
creating a statement.

Cursor updating
In-place updates are supported for cursors where the cursor type and concurrency support updates. If the
cursor isn't positioned on an updatable row in the result set (no get<Type> method call succeeded), a call to an
update<Type> method will throw an exception with the message, "The result set has no current row." The JDBC
specification states that an exception arises when an update method is called for a column of a cursor that is
CONCUR_READ_ONLY. In situations where the row is not updatable, such as because of an optimistic
concurrency conflict such as a competing update or deletion, the exception might not arise until insertRow,
updateRow, or deleteRow is called.
After a call to update<Type>, the affected column cannot be accessed by get<Type> until updateRow or
cancelRowUpdates has been called. This behavior avoids problems where a column is updated by using a
different type from the type returned by the server, and subsequent getter calls could invoke client-side type
conversions that give inaccurate results. Calls to get<Type> will throw an exception with the message, "Updated
columns cannot be accessed until updateRow() or cancelRowUpdates() has been called."

NOTE
If the updateRow method is called when no columns have been updated, the JDBC driver will throw an exception with the
message, "updateRow() called when no columns have been updated."

After moveToInsertRow has been called, an exception will be thrown if any method other than get<Type>,
update<Type>, insertRow, and cursor positioning methods (including moveToCurrentRow) are called on the
result set. The moveToInsertRow method effectively places the result set into insert mode, and cursor
positioning methods terminate insert mode. Relative cursor positioning calls move the cursor relative to the
position it was at before moveToInsertRow was called. After cursor positioning calls, the eventual destination
cursor position becomes the new cursor position.
If the cursor positioning call made while in insert mode doesn't succeed, the cursor position after the failed call
is the original cursor position before moveToInsetRow was called. If insertRow fails, the cursor remains on the
insert row and the cursor remains in insert mode.
Columns in the insert row are initially in an uninitialized state. Calls to the update<Type> method set the
column state to initialized. A call to the get<Type> method for an uninitialized column throws an exception. A
call to the insertRow method returns all the columns in the insert row to an uninitialized state.
If any columns are uninitialized when the insertRow method is called, the default value for the column is
inserted. If there's no default value but the column is nullable, then NULL is inserted. If there's no default value
and the column is not nullable, the server will return an error and an exception will be thrown.

NOTE
Calls to the getRow method returns 0 when in insert mode.
The JDBC driver does not support positioned updates or deletes. According to the JDBC specification, the setCursorName
method has no effect and the getCursorName method will throw an exception if called.
Read-only and static cursors are never updatable.
SQL Server restricts server cursors to a single result set. If a batch or stored procedure contains multiple statements, then
a forward-only read-only client cursor must be used.

See also
Managing result sets with the JDBC driver
Understanding isolation levels
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


Transactions specify an isolation level that defines how one transaction is isolated from other transactions.
Isolation is the separation of resource or data modifications made by different transactions. Isolation levels are
described for which concurrency side effects are allowed, such as dirty reads or phantom reads.
Transaction isolation levels control the following effects:
Whether locks are taken when data is read, and what type of locks are requested.
How long the read locks are held.
Whether read operations referencing rows modified by another transaction:
Block until the exclusive lock on the row is freed.
Retrieve the committed version of the row that existed at the time the statement or transaction
started.
Read the uncommitted data modification.

Choosing an isolation level


Choosing a transaction isolation level doesn't affect the locks that are acquired to protect data modifications. A
transaction always gets an exclusive lock on any data it modifies. It holds that lock until the transaction
completes, whatever the isolation level set for that transaction. For read operations, transaction isolation levels
mainly define how the operation is protected from the effects of other transactions.
A lower isolation level increases the ability of many users to access data at the same time. But it increases the
number of concurrency effects, such as dirty reads or lost updates, that users might see. Conversely, a higher
isolation level reduces the types of concurrency effects that users might see. But it requires more system
resources and increases the chances that one transaction will block another. Choosing the appropriate isolation
level depends on balancing the data integrity requirements of the application against the overhead of each
isolation level.
The highest isolation level, serializable, guarantees that a transaction will retrieve exactly the same data every
time it repeats a read operation. But it uses a level of locking that is likely to impact other users in multi-user
systems. The lowest isolation level, read uncommitted, can retrieve data that has been modified but not
committed by other transactions. All concurrency side effects can happen in read uncommitted, however there's
no read locking or versioning, so overhead is minimized.

Remarks
The following table shows the concurrency side effects allowed by the different isolation levels.

ISO L AT IO N L EVEL DIRT Y REA D N O N - REP EATA B L E REA D P H A N TO M

Read uncommitted Yes Yes Yes

Read committed No Yes Yes


ISO L AT IO N L EVEL DIRT Y REA D N O N - REP EATA B L E REA D P H A N TO M

Repeatable read No No Yes

Snapshot No No No

Serializable No No No

Transactions must be run at an isolation level of at least repeatable read to prevent lost updates that can occur
when two transactions each retrieve the same row. The transaction then later updates the row based on the
originally retrieved values. If the two transactions update rows using a single UPDATE statement and don't base
the update on the previously retrieved values, lost updates can't occur at the default isolation level of read
committed.
To set the isolation level for a transaction, you can use the setTransactionIsolation method of the
SQLServerConnection class. This method accepts an int value as its argument, which is based on one of the
connection constants as in the following:

con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

To use the new snapshot isolation level of SQL Server, you can use one of the SQLServerConnection constants:

con.setTransactionIsolation(SQLServerConnection.TRANSACTION_SNAPSHOT);

or you can use:

con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED + 4094);

For more information about SQL Server isolation levels, see "Isolation Levels in the Database Engine" in SQL
Server Books Online.

See also
Performing transactions with the JDBC driver
SET TRANSACTION ISOLATION LEVEL (Transact-SQL)
Wrappers and interfaces
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server supports interfaces that allow you create a proxy of a class, and
wrappers that let you access extensions to the JDBC API that are specific to the Microsoft JDBC Driver for SQL
Server through a proxy interface.

Wrappers
The Microsoft JDBC Driver for SQL Server supports the java.sql.Wrapper interface. This interface provides a
mechanism to access extensions to the JDBC API that are specific to the Microsoft JDBC Driver for SQL Server
through a proxy interface.
The java.sql.Wrapper interface defines two methods: isWrapperFor and unwrap . The isWrapperFor method
checks whether the specified input object implements this interface. The unwrap method returns an object that
implements this interface to allow access to the Microsoft JDBC Driver for SQL Server specific methods.
isWrapperFor and unwrap methods are exposed as follows:
isWrapperFor Method (SQLServerCallableStatement)
unwrap Method (SQLServerCallableStatement)
isWrapperFor Method (SQLServerConnectionPoolDataSource)
unwrap Method (SQLServerConnectionPoolDataSource)
isWrapperFor Method (SQLServerDataSource)
unwrap Method (SQLServerDataSource)
isWrapperFor Method (SQLServerPreparedStatement)
unwrap Method (SQLServerPreparedStatement)
isWrapperFor Method (SQLServerStatement)
unwrap Method (SQLServerStatement)
isWrapperFor Method (SQLServerXADataSource)
unwrap Method (SQLServerXADataSource)

Interfaces
Beginning in SQL Server JDBC Driver 3.0, interfaces are available for an application server to access a driver-
specific method from the associated class. The application server can wrap the class by creating a proxy,
exposing the Microsoft JDBC Driver for SQL Server-specific functionality from an interface. The Microsoft JDBC
Driver for SQL Server supports interfaces that have the Microsoft JDBC Driver for SQL Server specific methods
and constants so an application server can create a proxy of the class.
The interfaces derive from standard Java interfaces so you can use the same object once it is unwrapped to
access driver-specific functionality or generic Microsoft JDBC Driver for SQL Server functionality.
The following interfaces are added:
ISQLServerCallableStatement
ISQLServerConnection
ISQLServerDataSource
ISQLServerPreparedStatement
ISQLServerResultSet
ISQLServerStatement

Example
Description
This sample demonstrates how to access to a Microsoft JDBC Driver for SQL Server-specific function from a
DataSource object. This DataSource class may have been wrapped by an application server. To access the JDBC
driver-specific function or constant, you can unwrap the datasource to an ISQLServerDataSource interface and
use the functions declared in this interface.
Code

import javax.sql.*;
import java.sql.*;
import com.microsoft.sqlserver.jdbc.*;

public class UnWrapTest {


public static void main(String[] args) {
// This is a test. This DataSource object could be something from an appserver
// which has wrapped the real SQLServerDataSource with its own wrapper
SQLServerDataSource ds = new SQLServerDataSource();
checkSendStringParametersAsUnicode(ds);
}

// Unwrap to the ISQLServerDataSource interface to access the getSendStringParametersAsUnicode function


static void checkSendStringParametersAsUnicode(DataSource ds) {
try {
final ISQLServerDataSource sqlServerDataSource = ds.unwrap(ISQLServerDataSource.class);
boolean sendStringParametersAsUnicode = sqlServerDataSource.getSendStringParametersAsUnicode();

System.out.println("Send string as parameter value is:-" + sendStringParametersAsUnicode);

} catch (SQLException sqlE) {


System.out.println("Exception:-" + sqlE);
}
}
}

See also
Understanding the JDBC driver data types
Using bulk copy with the JDBC driver
4/27/2022 • 31 minutes to read • Edit Online

Download JDBC Driver


Microsoft SQL Server includes a popular command-line utility named bcp for quickly bulk copying large files
into tables or views in SQL Server databases. The SQLServerBulkCopy class allows you to write code solutions in
Java that provide similar functionality. There are other ways to load data into a SQL Server table (INSERT
statements, for example) but SQLServerBulkCopy offers a significant performance advantage over them.
The SQLServerBulkCopy class can be used to write data only to SQL Server tables. But the data source isn't
limited to SQL Server; any data source can be used, as long as the data can be read with a ResultSet , RowSet ,
or ISQLServerBulkRecord implementation.
Using the SQLServerBulkCopy class, you can perform:
A single bulk copy operation
Multiple bulk copy operations
A bulk copy operation with a transaction

NOTE
When using the Microsoft JDBC Driver 4.1 for SQL Server or earlier (which does not support the SQLServerBulkCopy
class), you can execute the SQL Server Transact-SQL BULK INSERT statement instead.

Bulk copy example setup


The SQLServerBulkCopy class can be used to write data only to SQL Server tables. The code samples shown in
this article use the SQL Server sample database, AdventureWorks. To avoid altering the existing tables in the
code samples, write data to tables that you create first.
The BulkCopyDemoMatchingColumns and BulkCopyDemoDifferentColumns tables are both based on the
AdventureWorks Production.Products table. In code samples that use these tables, data is added from the
Production.Products table to one of these sample tables. The BulkCopyDemoDifferentColumns table is used when
the sample illustrates how to map columns from the source data to the destination table;
BulkCopyDemoMatchingColumns is used for most other samples.

A few of the code samples demonstrate how to use one SQLServerBulkCopy class to write to multiple tables. For
these samples, the BulkCopyDemoOrderHeader and BulkCopyDemoOrderDetail tables are used as the destination
tables. These tables are based on the Sales.SalesOrderHeader and Sales.SalesOrderDetail tables in
AdventureWorks.

NOTE
The SQLServerBulkCopy code samples are provided to demonstrate the syntax for using SQLServerBulkCopy only. If
the source and destination tables are located in the same SQL Server instance, it is easier and faster to use a Transact-SQL
INSERT ... SELECT statement to copy the data.

Table setup
To create the tables necessary for the code samples to run correctly, you must run the following Transact-SQL
statements in a SQL Server database.

USE AdventureWorks

IF EXISTS (SELECT * FROM dbo.sysobjects


WHERE id = object_id(N'[dbo].[BulkCopyDemoMatchingColumns]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE [dbo].[BulkCopyDemoMatchingColumns]

CREATE TABLE [dbo].[BulkCopyDemoMatchingColumns]([ProductID] [int] IDENTITY(1,1) NOT NULL,


[Name] [nvarchar](50) NOT NULL,
[ProductNumber] [nvarchar](25) NOT NULL,
CONSTRAINT [PK_ProductID] PRIMARY KEY CLUSTERED
(
[ProductID] ASC
) ON [PRIMARY]) ON [PRIMARY]

IF EXISTS (SELECT * FROM dbo.sysobjects


WHERE id = object_id(N'[dbo].[BulkCopyDemoDifferentColumns]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE [dbo].[BulkCopyDemoDifferentColumns]

CREATE TABLE [dbo].[BulkCopyDemoDifferentColumns]([ProdID] [int] IDENTITY(1,1) NOT NULL,


[ProdNum] [nvarchar](25) NOT NULL,
[ProdName] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_ProdID] PRIMARY KEY CLUSTERED
(
[ProdID] ASC
) ON [PRIMARY]) ON [PRIMARY]

IF EXISTS (SELECT * FROM dbo.sysobjects


WHERE id = object_id(N'[dbo].[BulkCopyDemoOrderHeader]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE [dbo].[BulkCopyDemoOrderHeader]

CREATE TABLE [dbo].[BulkCopyDemoOrderHeader]([SalesOrderID] [int] IDENTITY(1,1) NOT NULL,


[OrderDate] [datetime] NOT NULL,
[AccountNumber] [nvarchar](15) NULL,
CONSTRAINT [PK_SalesOrderID] PRIMARY KEY CLUSTERED
(
[SalesOrderID] ASC
) ON [PRIMARY]) ON [PRIMARY]

IF EXISTS (SELECT * FROM dbo.sysobjects


WHERE id = object_id(N'[dbo].[BulkCopyDemoOrderDetail]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
DROP TABLE [dbo].[BulkCopyDemoOrderDetail]

CREATE TABLE [dbo].[BulkCopyDemoOrderDetail]([SalesOrderID] [int] NOT NULL,


[SalesOrderDetailID] [int] NOT NULL,
[OrderQty] [smallint] NOT NULL,
[ProductID] [int] NOT NULL,
[UnitPrice] [money] NOT NULL,
CONSTRAINT [PK_LineNumber] PRIMARY KEY CLUSTERED
(
[SalesOrderID] ASC,
[SalesOrderDetailID] ASC
) ON [PRIMARY]) ON [PRIMARY]

Single bulk copy operations


The simplest approach to performing a SQL Server bulk copy operation is to perform a single operation against
a database. By default, a bulk copy operation is performed as an isolated operation: the copy operation occurs in
a non-transacted way, with no opportunity for rolling it back.

NOTE
If you need to roll back all or part of the bulk copy when an error occurs, you can either use a SQLServerBulkCopy -
managed transaction, or perform the bulk copy operation within an existing transaction.
For more information, see Transaction and bulk copy operations

The general steps to perform a bulk copy operation are:


1. Connect to the source server and obtain the data to be copied. Data can also come from other sources, if
it can be retrieved from a ResultSet object or an ISQLServerBulkRecord implementation.
2. Connect to the destination server (unless you want SQLServerBulkCopy to establish a connection for you).
3. Create a SQLServerBulkCopy object, setting any necessary properties via setBulkCopyOptions .
4. Call the setDestinationTableName method to indicate the target table for the bulk insert operation.
5. Call one of the writeToServer methods.
6. Optionally, update properties via setBulkCopyOptions and call writeToServer again as necessary.
7. Call close , or wrap the bulk copy operations within a try-with-resources statement.
Cau t i on

We recommend that the source and target column data types match. If the data types do not match,
SQLServerBulkCopy attempts to convert each source value to the target data type. Conversions can affect
performance, and also can result in unexpected errors. For example, a double data type can be converted to a
decimal data type most of the time, but not always.
Example
The following application demonstrates how to load data using the SQLServerBulkCopy class. In this example, a
ResultSet is used to copy data from the Production.Product table in the SQL Server AdventureWorks database
to a similar table in the same database.

IMPORTANT
This sample will not run unless you have created the work tables as described in Table setup. This code is provided to
demonstrate the syntax for using SQLServerBulkCopy only. If the source and destination tables are located in the same
SQL Server instance, it is easier and faster to use a Transact-SQL INSERT ... SELECT statement to copy the data.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;

public class BulkCopySingle {


public static void main(String[] args) {
String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";
String destinationTable = "dbo.BulkCopyDemoMatchingColumns";
int countBefore, countAfter;
ResultSet rsSourceData;

try (Connection sourceConnection = DriverManager.getConnection(connectionUrl);


Connection destinationConnection = DriverManager.getConnection(connectionUrl);
Statement stmt = sourceConnection.createStatement();
SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(destinationConnection)) {

// Empty the destination table.


stmt.executeUpdate("DELETE FROM " + destinationTable);

// Perform an initial count on the destination table.


countBefore = getRowCount(stmt, destinationTable);

// Get data from the source table as a ResultSet.


rsSourceData = stmt.executeQuery("SELECT ProductID, Name, ProductNumber FROM
Production.Product");

// In real world applications you would


// not use SQLServerBulkCopy to move data from one table to the other
// in the same database. This is for demonstration purposes only.

// Set up the bulk copy object.


// Note that the column positions in the source
// table match the column positions in
// the destination table so there is no need to
// map columns.
bulkCopy.setDestinationTableName(destinationTable);

// Write from the source to the destination.


bulkCopy.writeToServer(rsSourceData);

// Perform a final count on the destination


// table to see how many rows were added.
countAfter = getRowCount(stmt, destinationTable);
System.out.println((countAfter - countBefore) + " rows were added.");
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

private static int getRowCount(Statement stmt,


String tableName) throws SQLException {
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
rs.next();
int count = rs.getInt(1);
rs.close();
return count;
}
}
Performing a bulk copy operation using Transact-SQL
The following example illustrates how to use the executeUpdate method to execute the BULK INSERT statement.

NOTE
The file path for the data source is relative to the server. The server process must have access to that path in order for the
bulk copy operation to succeed.

try (Connection con = DriverManager.getConnection(connectionUrl);


Statement stmt = con.createStatement()) {
// Perform the BULK INSERT
stmt.executeUpdate(
"BULK INSERT Northwind.dbo.[Order Details] " + "FROM 'f:\\mydata\\data.tbl' " + "WITH (
FORMATFILE='f:\\mydata\\data.fmt' )");
}

Multiple bulk copy operations


You can perform multiple bulk copy operations using a single instance of a SQLServerBulkCopy class. If the
operation parameters change between copies (for example, the name of the destination table), you must update
them prior to any subsequent calls to any of the writeToServer methods, as demonstrated in the following
example. Unless explicitly changed, all property values remain the same as they were on the previous bulk copy
operation for a given instance.

NOTE
Performing multiple bulk copy operations using the same instance of SQLServerBulkCopy is usually more efficient than
using a separate instance for each operation.

If you perform several bulk copy operations using the same SQLServerBulkCopy object, there are no restrictions
on whether source or target information is equal or different in each operation. However, you must ensure that
column association information is properly set each time you write to the server.

IMPORTANT
This sample will not run unless you have created the work tables as described in Table setup. This code is provided to
demonstrate the syntax for using SQLServerBulkCopy only. If the source and destination tables are located in the same
SQL Server instance, it is easier and faster to use a Transact-SQL INSERT ... SELECT statement to copy the data.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions;

public class BulkCopyMultiple {


public static void main(String[] args) {
String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";
String destinationHeaderTable = "dbo.BulkCopyDemoOrderHeader";
String destinationDetailTable = "dbo.BulkCopyDemoOrderDetail";
int countHeaderBefore, countDetailBefore, countHeaderAfter, countDetailAfter;
int countHeaderBefore, countDetailBefore, countHeaderAfter, countDetailAfter;
ResultSet rsHeader, rsDetail;

try (Connection sourceConnection1 = DriverManager.getConnection(connectionUrl);


Connection sourceConnection2 = DriverManager.getConnection(connectionUrl);
Statement stmt = sourceConnection1.createStatement();
PreparedStatement preparedStmt1 = sourceConnection1.prepareStatement(
"SELECT [SalesOrderID], [OrderDate], [AccountNumber] FROM [Sales].[SalesOrderHeader]
WHERE [AccountNumber] = ?;");
PreparedStatement preparedStmt2 = sourceConnection2.prepareStatement(
"SELECT [Sales].[SalesOrderDetail].[SalesOrderID], [SalesOrderDetailID], [OrderQty],
[ProductID], [UnitPrice] FROM "
+ "[Sales].[SalesOrderDetail] INNER JOIN [Sales].[SalesOrderHeader] ON "
+ "[Sales].[SalesOrderDetail].[SalesOrderID] = [Sales].[SalesOrderHeader].
[SalesOrderID] WHERE [AccountNumber] = ?;");
SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connectionUrl);) {

// Empty the destination tables.


stmt.executeUpdate("DELETE FROM " + destinationHeaderTable);
stmt.executeUpdate("DELETE FROM " + destinationDetailTable);

// Perform an initial count on the destination


// table with matching columns.
countHeaderBefore = getRowCount(stmt, destinationHeaderTable);

// Perform an initial count on the destination


// table with different column positions.
countDetailBefore = getRowCount(stmt, destinationDetailTable);

// Get data from the source table as a ResultSet.


// The Sales.SalesOrderHeader and Sales.SalesOrderDetail
// tables are quite large and could easily cause a timeout
// if all data from the tables is added to the destination.
// To keep the example simple and quick, a parameter is
// used to select only orders for a particular account
// as the source for the bulk insert.
preparedStmt1.setString(1, "10-4020-000034");
rsHeader = preparedStmt1.executeQuery();

// Get the Detail data in a separate connection.


preparedStmt2.setString(1, "10-4020-000034");
rsDetail = preparedStmt2.executeQuery();

// Create the SQLServerBulkCopySQLServerBulkCopy object.


SQLServerBulkCopyOptions copyOptions = new SQLServerBulkCopyOptions();
copyOptions.setBulkCopyTimeout(100);
bulkCopy.setBulkCopyOptions(copyOptions);
bulkCopy.setDestinationTableName(destinationHeaderTable);

// Guarantee that columns are mapped correctly by


// defining the column mappings for the order.
bulkCopy.addColumnMapping("SalesOrderID", "SalesOrderID");
bulkCopy.addColumnMapping("OrderDate", "OrderDate");
bulkCopy.addColumnMapping("AccountNumber", "AccountNumber");

// Write rsHeader to the destination.


bulkCopy.writeToServer(rsHeader);

// Set up the order details destination.


bulkCopy.setDestinationTableName(destinationDetailTable);

// Clear the existing column mappings


bulkCopy.clearColumnMappings();

// Add order detail column mappings.


bulkCopy.addColumnMapping("SalesOrderID", "SalesOrderID");
bulkCopy.addColumnMapping("SalesOrderDetailID", "SalesOrderDetailID");
bulkCopy.addColumnMapping("OrderQty", "OrderQty");
bulkCopy.addColumnMapping("ProductID", "ProductID");
bulkCopy.addColumnMapping("UnitPrice", "UnitPrice");

// Write rsDetail to the destination.


bulkCopy.writeToServer(rsDetail);

// Perform a final count on the destination


// tables to see how many rows were added.
countHeaderAfter = getRowCount(stmt, destinationHeaderTable);
countDetailAfter = getRowCount(stmt, destinationDetailTable);

System.out.println((countHeaderAfter - countHeaderBefore) + " rows were added to the Header


table.");
System.out.println((countDetailAfter - countDetailBefore) + " rows were added to the Detail
table.");
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

private static int getRowCount(Statement stmt,


String tableName) throws SQLException {
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
rs.next();
int count = rs.getInt(1);
rs.close();
return count;
}
}

Transaction and bulk copy operations


Bulk copy operations can be performed as isolated operations or as part of a multiple step transaction. This
latter option enables you to perform more than one bulk copy operation within the same transaction, as well as
perform other database operations (such as inserts, updates, and deletes) while still being able to commit or roll
back the entire transaction.
By default, a bulk copy operation is performed as an isolated operation. The bulk copy operation occurs in a
non-transacted way, with no opportunity for rolling it back. If you need to roll back all or part of the bulk copy
when an error occurs, you can use a SQLServerBulkCopy -managed transaction or perform the bulk copy
operation within an existing transaction.

Extended Bulk Copy for Azure Data Warehouse


Driver version v8.4.1 adds a new connection property, sendTemporalDataTypesAsStringForBulkCopy . This boolean
property is true by default.
This connection property, when set to false , will send DATE , DATETIME , DATIMETIME2 , DATETIMEOFFSET ,
SMALLDATETIME , and TIME datatypes as their respective types instead of sending them as String.
Sending the temporal datatypes as their respective types allows the user to send data into those columns for
Azure Synapse Analytics, which was not possible before due to the driver converting the data into String.
Sending String data into temporal columns works for SQL Server because SQL Server would perform implicit
conversion for us, but it is not the same with Azure Synapse Analytics.
Additionally, even without setting this connection string to 'false', from v8.4.1 and onward, MONEY and
SMALLMONEY datatypes will be sent as MONEY / SMALLMONEY datatypes instead of DECIMAL , which
also allows those datatypes to be bulk copied into Azure Synapse Analytics.
Extended Bulk Copy for Azure Data Warehouse limitations
There are currently two limitations:
1. With this connection property set to false , the driver will only accept the default string literal format of
each temporal datatype, for example:
DATE: YYYY-MM-DD

DATETIME: YYYY-MM-DD hh:mm:ss[.nnn]

DATETIME2: YYYY-MM-DD hh:mm:ss[.nnnnnnn]

DATETIMEOFFSET: YYYY-MM-DD hh:mm:ss[.nnnnnnn] [{+/-}hh:mm]

SMALLDATETIME:YYYY-MM-DD hh:mm:ss

TIME: hh:mm:ss[.nnnnnnn]

2. With this connection property set to false , the column type specified for bulk copy has to respect the
data type mapping chart from here. For example, previously users could specify
java.sql.Types.TIMESTAMP to bulk copy data into a DATE column, but with this feature enabled, they must
specify java.sql.Types.DATE to perform the same.
Performing a non-transacted bulk copy operation
The following application shows what happens when a non-transacted bulk copy operation encounters an error
partway through the operation.
In the example, the source table and destination table each include an Identity column named ProductID . The
code first prepares the destination table by deleting all rows and then inserting a single row whose ProductID is
known to exist in the source table. By default, a new value for the Identity column is generated in the destination
table for each row added. In this example, an option is set when the connection is opened that forces the bulk-
load process to use the Identity values from the source table instead.
The bulk copy operation is executed with the BatchSize property set to 10. When the operation encounters the
invalid row, an exception is thrown. In this first example, the bulk copy operation is non-transacted. All batches
copied up to the point of the error are committed; the batch containing the duplicate key is rolled back, and the
bulk copy operation is halted before processing any other batches.

NOTE
This sample will not run unless you have created the work tables as described in Table setup. This code is provided to
demonstrate the syntax for using SQLServerBulkCopy only. If the source and destination tables are located in the same
SQL Server instance, it is easier and faster to use a Transact-SQL INSERT ... SELECT statement to copy the data.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions;

public class BulkCopyNonTransacted {


public static void main(String[] args) {
String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";
String destinationTable = "dbo.BulkCopyDemoMatchingColumns";
int countBefore, countAfter;
ResultSet rsSourceData;
try (Connection sourceConnection = DriverManager.getConnection(connectionUrl);
Statement stmt = sourceConnection.createStatement();
SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connectionUrl)) {

// Empty the destination table.


stmt.executeUpdate("DELETE FROM " + destinationTable);

// Add a single row that will result in duplicate key


// when all rows from source are bulk copied.
// Note that this technique will only be successful in
// illustrating the point if a row with ProductID = 446
// exists in the AdventureWorks Production.Products table.
// If you have made changes to the data in this table, change
// the SQL statement in the code to add a ProductID that
// does exist in your version of the Production.Products
// table. Choose any ProductID in the middle of the table
// (not first or last row) to best illustrate the result.
stmt.executeUpdate("SET IDENTITY_INSERT " + destinationTable + " ON;" + "INSERT INTO " +
destinationTable
+ "([ProductID], [Name] ,[ProductNumber]) VALUES(446, 'Lock Nut 23','LN-3416'); SET
IDENTITY_INSERT " + destinationTable
+ " OFF");

// Perform an initial count on the destination table.


countBefore = getRowCount(stmt, destinationTable);

// Get data from the source table as a ResultSet.


rsSourceData = stmt.executeQuery("SELECT ProductID, Name, ProductNumber FROM
Production.Product");

// Set up the bulk copy object using the KeepIdentity option and BatchSize = 10.
SQLServerBulkCopyOptions copyOptions = new SQLServerBulkCopyOptions();
copyOptions.setKeepIdentity(true);
copyOptions.setBatchSize(10);

bulkCopy.setBulkCopyOptions(copyOptions);
bulkCopy.setDestinationTableName(destinationTable);

// Write from the source to the destination.


// This should fail with a duplicate key error
// after some of the batches have been copied.
try {
bulkCopy.writeToServer(rsSourceData);
}
catch (SQLException e) {
e.printStackTrace();
}

// Perform a final count on the destination


// table to see how many rows were added.
countAfter = getRowCount(stmt, destinationTable);
System.out.println((countAfter - countBefore) + " rows were added.");
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

private static int getRowCount(Statement stmt,


String tableName) throws SQLException {
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
rs.next();
int count = rs.getInt(1);
rs.close();
return count;
}
}
Performing a dedicated bulk copy operation in a transaction
By default, a bulk copy operation does not create transactions itself. When you want to perform a dedicated bulk
copy operation, create a new instance of SQLServerBulkCopy with a connection string. In this scenario, each batch
of the bulk copy operation is implicitly committed by the database. You can set the UseInternalTransaction
option to true in SQLServerBulkCopyOptions to make the bulk copy operation create transactions, performing a
commit after each batch of the bulk copy operation.

SQLServerBulkCopyOptions copyOptions = new SQLServerBulkCopyOptions();


copyOptions.setKeepIdentity(true);
copyOptions.setBatchSize(10);
copyOptions.setUseInternalTransaction(true);

Using existing transactions


You can pass a Connection object that has transactions enabled as a parameter in a SQLServerBulkCopy
constructor. In this situation, the bulk copy operation is performed in an existing transaction, and no change is
made to the transaction state (that is, it's not committed or aborted). This allows an application to include the
bulk copy operation in a transaction with other database operations. If you need to roll back the entire bulk copy
operation because an error occurs, or if the bulk copy should execute as part of a larger process that can be
rolled back, you can perform the rollback on the Connection object at any point after the bulk copy operation.
The following application is similar to BulkCopyNonTransacted , with one exception: in this example, the bulk copy
operation is included in a larger, external transaction. When the primary key violation error occurs, the entire
transaction is rolled back and no rows are added to the destination table.

NOTE
This sample will not run unless you have created the work tables as described in Table setup. This code is provided to
demonstrate the syntax for using SQLServerBulkCopy only. If the source and destination tables are located in the same
SQL Server instance, it is easier and faster to use a Transact-SQL INSERT ... SELECT statement to copy the data.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions;

public class BulkCopyExistingTransactions {


public static void main(String[] args) {
String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";
String destinationTable = "dbo.BulkCopyDemoMatchingColumns";
int countBefore, countAfter;
ResultSet rsSourceData;
SQLServerBulkCopyOptions copyOptions;

try (Connection sourceConnection = DriverManager.getConnection(connectionUrl);


Connection destinationConnection = DriverManager.getConnection(connectionUrl);
Statement stmt = sourceConnection.createStatement();
SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(destinationConnection);) {

// Empty the destination table.


stmt.executeUpdate("DELETE FROM " + destinationTable);

// Add a single row that will result in duplicate key


// when all rows from source are bulk copied.
// Note that this technique will only be successful in
// illustrating the point if a row with ProductID = 446
// exists in the AdventureWorks Production.Products table.
// If you have made changes to the data in this table, change
// the SQL statement in the code to add a ProductID that
// does exist in your version of the Production.Products
// table. Choose any ProductID in the middle of the table
// (not first or last row) to best illustrate the result.
stmt.executeUpdate("SET IDENTITY_INSERT " + destinationTable + " ON;" + "INSERT INTO " +
destinationTable
+ "([ProductID], [Name] ,[ProductNumber]) VALUES(446, 'Lock Nut 23','LN-3416'); SET
IDENTITY_INSERT " + destinationTable
+ " OFF");

// Perform an initial count on the destination table.


countBefore = getRowCount(stmt, destinationTable);

// Get data from the source table as a ResultSet.


rsSourceData = stmt.executeQuery("SELECT ProductID, Name, ProductNumber FROM
Production.Product");

// Set up the bulk copy object inside the transaction.


destinationConnection.setAutoCommit(false);

copyOptions = new SQLServerBulkCopyOptions();


copyOptions.setKeepIdentity(true);
copyOptions.setBatchSize(10);

bulkCopy.setBulkCopyOptions(copyOptions);
bulkCopy.setDestinationTableName(destinationTable);

// Write from the source to the destination.


// This should fail with a duplicate key error.
try {
bulkCopy.writeToServer(rsSourceData);
destinationConnection.commit();
}
catch (SQLException e) {
e.printStackTrace();
destinationConnection.rollback();
}

// Perform a final count on the destination


// table to see how many rows were added.
countAfter = getRowCount(stmt, destinationTable);
System.out.println((countAfter - countBefore) + " rows were added.");
}
catch (Exception e) {
// Handle any errors that may have occurred.
e.printStackTrace();
}
}

private static int getRowCount(Statement stmt,


String tableName) throws SQLException {
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
rs.next();
int count = rs.getInt(1);
rs.close();
return count;
}
}

Bulk copy from a CSV file


The following application demonstrates how to load data using the SQLServerBulkCopy class. In this example, a
CSV file is used to copy data exported from the Production.Product table in the SQL Server AdventureWorks
database to a similar table in the database.

IMPORTANT
This sample will not run unless you have created the work tables as described in Table setup to get it.

1. Open SQL Ser ver Management Studio and connect to the SQL Server with the AdventureWorks
database.
2. Expand the databases, right-click the AdventureWorks database, select Tasks and Expor t Data ...
3. For the Data Source, select the Data source that allows you to connect to your SQL Server (for example,
SQL Server Native Client 11.0), check the configuration and then Next
4. For the Destination, Select the Flat File Destination and enter a File Name with a destination such as
C:\Test\TestBulkCSVExample.csv . Check that the Format is Delimited, the Text qualifier is none, and
enable Column names in the first data row , and then select Next
5. Select Write a quer y to specify the data to transfer and Next . Enter your SQL Statement
SELECT ProductID, Name, ProductNumber FROM Production.Product , and Next

6. Check the configuration: You can leave the Row delimiter as {CR}{LF} and Column Delimiter as Comma
{,} . Select Edit Mappings ... and check that the data Type is correct for each column (for example,
integer for ProductID and Unicode string for the others).
7. Skip ahead to Finish and run the export.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerBulkCSVFileRecord;
import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy;

public class BulkCopyCSV {


public static void main(String[] args) {
String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=AdventureWorks;user=
<user>;password=<password>";
String destinationTable = "dbo.BulkCopyDemoMatchingColumns";
int countBefore, countAfter;

// Get data from the source file by loading it into a class that implements ISQLServerBulkRecord.
// Here we are using the SQLServerBulkCSVFileRecord implementation to import the example CSV file.
try (Connection destinationConnection = DriverManager.getConnection(connectionUrl);
Statement stmt = destinationConnection.createStatement();
SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(destinationConnection);
SQLServerBulkCSVFileRecord fileRecord = new
SQLServerBulkCSVFileRecord("C:\\Test\\TestBulkCSVExample.csv", true);) {

// Set the metadata for each column to be copied.


fileRecord.addColumnMetadata(1, null, java.sql.Types.INTEGER, 0, 0);
fileRecord.addColumnMetadata(2, null, java.sql.Types.NVARCHAR, 50, 0);
fileRecord.addColumnMetadata(3, null, java.sql.Types.NVARCHAR, 25, 0);

// Empty the destination table.


stmt.executeUpdate("DELETE FROM " + destinationTable);

// Perform an initial count on the destination table.


countBefore = getRowCount(stmt, destinationTable);

// Set up the bulk copy object.


// Note that the column positions in the source
// data reader match the column positions in
// the destination table so there is no need to
// map columns.
bulkCopy.setDestinationTableName(destinationTable);

// Write from the source to the destination.


bulkCopy.writeToServer(fileRecord);

// Perform a final count on the destination


// table to see how many rows were added.
countAfter = getRowCount(stmt, destinationTable);
System.out.println((countAfter - countBefore) + " rows were added.");
}
// Handle any errors that may have occurred.
catch (SQLException e) {
e.printStackTrace();
}
}

private static int getRowCount(Statement stmt,


String tableName) throws SQLException {
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tableName);
rs.next();
int count = rs.getInt(1);
rs.close();
return count;
}
}
Using a regex character as a delimiter

NOTE
When setting a custom delimiter, escape it if it's a regex character such as '|'.

SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(CSVFilePath, null, "\\|", true);

Bulk copy with delimiters as data in CSV file


Driver version 8.4.1 adds a new API SQLServerBulkCSVFileRecord.setEscapeColumnDelimitersCSV(boolean) . When
set to true, the following rules will apply:
Each field may or may not be enclosed in double quotes.
If fields are not enclosed with double quotes, then double quotes may not appear inside the fields.
Fields containing double quotes, and delimiters should be enclosed in double quotes.
If double-quotes are used to enclose fields, then a double-quote appearing inside a field must be escaped by
preceding it with another double quote.
Bulk copy with Always Encrypted columns
Beginning with Microsoft JDBC Driver 6.0 for SQL Server, bulk copy is supported with Always Encrypted
columns.
Depending on the bulk copy options, and the encryption type of the source and destination tables the JDBC
driver may transparently decrypt and then encrypt the data or it may send the encrypted data as is. For
example, when bulk copying data from an encrypted column to an unencrypted column, the driver
transparently decrypts data before sending to SQL Server. Similarly when bulk copying data from an
unencrypted column (or from a CSV file) to an encrypted column, the driver transparently encrypts data before
sending to SQL Server. If both source and destination is encrypted, then depending on the
allowEncryptedValueModifications bulk copy option, the driver would send data as is or would decrypt the data
and encrypt it again before sending to SQL Server.
For more information, see the allowEncryptedValueModifications bulk copy option below, and Using Always
Encrypted with the JDBC Driver.

IMPORTANT
Limitation of the Microsoft JDBC Driver 6.0 for SQL Server, when bulk copying data from a CSV file to encrypted columns:
Only the Transact-SQL default string literal format is supported for the date and time types
DATETIME and SMALLDATETIME data types are not supported

Bulk copy API for JDBC driver


SQLServerBulkCopy
Lets you efficiently bulk-load a SQL Server table with data from another source.
Microsoft SQL Server includes a popular command-prompt utility named bcp for moving data from one table to
another, whether on a single server or between servers. The SQLServerBulkCopy class lets you write code
solutions in Java that provide similar functionality. There are other ways to load data into a SQL Server table
(INSERT statements, for example), but SQLServerBulkCopy offers a significant performance advantage over them.
The SQLServerBulkCopy class can be used to write data only to SQL Server tables. However, the data source isn't
limited to SQL Server; any data source can be used, as long as the data can be read with a ResultSet instance
or ISQLServerBulkRecord implementation.

C O N ST RUC TO R DESC RIP T IO N

SQLServerBulkCopy(Connection connection) Initializes a new instance of the SQLServerBulkCopy class


using the specified open instance of SQLServerConnection .
If the Connection has transactions enabled, the copy
operations will be performed within that transaction.

SQLServerBulkCopy(String connectionURL) Initializes and opens a new instance of


SQLServerConnection based on the supplied
connectionURL . The constructor uses the
SQLServerConnection to initialize a new instance of the
SQLServerBulkCopy class.

P RO P ERT Y DESC RIP T IO N

String DestinationTableName Name of the destination table on the server.

If DestinationTableName hasn't been set when


writeToServer is called, a SQLServerException is
thrown.

DestinationTableName is a three-part name (


<database>.<owningschema>.<name> ). You can qualify the
table name with its database and owning schema if you
choose. However, if the table name uses an underscore ("_")
or any other special characters, you must escape the name
using surrounding brackets. For more information, see
Database Identifiers.

ColumnMappings Column mappings define the relationships between columns


in the data source and columns in the destination.

If mappings aren't defined, the columns are mapped


implicitly based on ordinal position. For this to work, source
and target schemas must match. If they don't, an Exception
will be thrown.

If the mappings isn't empty, not every column present in the


data source has to be specified. Those not mapped are
ignored.

You can refer to source and target columns by either name


or ordinal.

M ET H O D DESC RIP T IO N

void addColumnMapping(int sourceColumn, int Adds a new column-mapping, using ordinals to specify both
destinationColumn) source and destination columns.

void addColumnMapping (int sourceColumn, String Adds a new column-mapping, using an ordinal for the
destinationColumn) source column and a column name for the destination
column.
M ET H O D DESC RIP T IO N

void addColumnMapping (String sourceColumn, int Adds a new column-mapping, using a column name to
destinationColumn) describe the source column and an ordinal to specify the
destination column.

void addColumnMapping (String sourceColumn, String Adds a new column-mapping, using column names to
destinationColumn) specify both source and destination columns.

void clearColumnMappings() Clears the contents of the column mappings.

void close() Closes the SQLServerBulkCopy instance.

SQLServerBulkCopyOptions getBulkCopyOptions() Retrieves the current set of SQLServerBulkCopyOptions .

String getDestinationTableName() Retrieve the current destination table name.

void setBulkCopyOptions(SQLServerBulkCopyOptions Updates the behavior of the SQLServerBulkCopy instance


copyOptions) according to the options supplied.

void setDestinationTableName(String tableName) Sets the name of the destination table.

void writeToServer(ResultSet sourceData) Copies all rows in the supplied ResultSet to a destination
table specified by the DestinationTableName property of
the SQLServerBulkCopy object.

void writeToServer(RowSet sourceData) Copies all rows in the supplied RowSet to a destination
table specified by the DestinationTableName property of
the SQLServerBulkCopy object.

void writeToServer(ISQLServerBulkRecord sourceData) Copies all rows in the supplied ISQLServerBulkRecord


implementation to a destination table specified by the
DestinationTableName property of the
SQLServerBulkCopy object.

SQLServerBulkCopyOptions
A collection of settings that control how the writeToServer methods behave in an instance of
SQLServerBulkCopy .

C O N ST RUC TO R DESC RIP T IO N

SQLServerBulkCopyOptions() Initializes a new instance of the


SQLServerBulkCopyOptions class using defaults for all of
the settings.

Getters and setters exist for the following options:

O P T IO N DESC RIP T IO N DEFA ULT

boolean CheckConstraints Check constraints while data is being False - constraints aren't checked
inserted.
O P T IO N DESC RIP T IO N DEFA ULT

boolean FireTriggers Cause the server to fire the insert False - no triggers are fired
triggers for the rows being inserted
into the database.

boolean KeepIdentity Preserve source identity values. False - identity values are assigned by
the destination

boolean KeepNulls Preserve null values in the destination False - null values are replaced by
table regardless of the settings for default values where applicable.
default values.

boolean TableLock Obtain a bulk update lock for the False - row locks are used.
duration of the bulk copy operation.

boolean UseInternalTransaction When set to true , each batch of the False - no transaction
bulk-copy operation will occur within a
transaction. If SQLServerBulkCopy is
using an existing connection (as
specified by the constructor), a
SQLServerException will occur. If
SQLServerBulkCopy created a
dedicated connection, a transaction will
be created and committed for each
batch.

int BatchSize Number of rows in each batch. At the 0 - indicates that each
end of each batch, the rows in the writeToServer operation is a single
batch are sent to the server. batch

A batch is complete when BatchSize


rows have been processed or there are
no more rows to send to the
destination data source. If the
SQLServerBulkCopy instance has
been declared with the
UseInternalTransaction option set
to false , rows are sent to the server
BatchSize rows at a time, but no
transaction-related action is taken. If
UseInternalTransaction is set to
true , each batch of rows is
performed within an explicit
transaction.

int BulkCopyTimeout Number of seconds for the operation 60 seconds.


to complete before it times out. A
value of 0 indicates no limit; the bulk
copy will wait indefinitely.
O P T IO N DESC RIP T IO N DEFA ULT

boolean This option is available with Microsoft


allowEncryptedValueModifications JDBC Driver 6.0 (or higher) for SQL
Server.

When set to true ,


allowEncryptedValueModifications
enables bulk copying of encrypted
data between tables or databases,
without decrypting the data. Typically,
an application would select data from
encrypted columns from one table
without decrypting the data (the app
would connect to the database with
the column encryption setting
keyword set to disabled) and then
would use this option to bulk insert
the data, which is still encrypted. For
more information, see Using Always
Encrypted with the JDBC Driver.

Use caution when setting


allowEncryptedValueModifications
to true as this may lead to
corrupting the database because the
driver doesn't check if the data is
indeed encrypted, or if it is correctly
encrypted using the same encryption
type, algorithm and key as the target
column.

Getters and setters:

M ET H O DS DESC RIP T IO N

boolean isCheckConstraints() Indicates whether constraints are to be checked while data is


being inserted or not.

void setCheckConstraints(boolean checkConstraints) Sets whether constraints are to be checked while data is
being inserted or not.

boolean isFireTriggers() Indicates if the server should fire the insert triggers for the
rows being inserted into the database.

void setFireTriggers(boolean fireTriggers) Sets whether the server should be set to fire triggers for the
rows being inserted into the database.

boolean isKeepIdentity() Indicates whether or not to preserve any source identity


values.

void setKeepIdentity(boolean keepIdentity) Sets whether or not to preserve identity values.

boolean isKeepNulls() Indicates whether to preserve null values in the destination


table regardless of the settings for default values, or if they
should be replaced by the default values (where applicable).
M ET H O DS DESC RIP T IO N

void setKeepNulls(boolean keepNulls) Sets whether to preserve null values in the destination table
regardless of the settings for default values, or if they should
be replaced by the default values (where applicable).

boolean isTableLock() Indicates whether SQLServerBulkCopy should obtain a bulk


update lock for the duration of the bulk copy operation.

void setTableLock(boolean tableLock) Sets whether SQLServerBulkCopy should obtain a bulk


update lock for the duration of the bulk copy operation.

boolean isUseInternalTransaction() Indicates whether each batch of the bulk-copy operation will
occur within a transaction.

void setUseInternalTranscation(boolean Sets whether each batch of the bulk-copy operations will
useInternalTransaction) occur within a transaction or not.

int getBatchSize() Gets the number of rows in each batch. At the end of each
batch, the rows in the batch are sent to the server.

void setBatchSize(int batchSize) Sets the number of rows in each batch. At the end of each
batch, the rows in the batch are sent to the server.

int getBulkCopyTimeout() Gets the number of seconds for the operation to complete
before it times out.

void setBulkCopyTimeout(int timeout) Sets the number of seconds for the operation to complete
before it times out.

boolean isAllowEncryptedValueModifications() Indicates whether allowEncryptedValueModifications


setting is enabled or disabled.

void setAllowEncryptedValueModifications(boolean Configures the allowEncryptedValueModifications


allowEncryptedValueModifications) setting that is used for bulk copy with Always Encrypted
columns.

ISQLServerBulkRecord
The ISQLServerBulkRecord interface can be used to create classes that read in data from any source (such as a
file) and allow a SQLServerBulkCopy instance to bulk load a SQL Server table with that data.

IN T ERFA C E M ET H O DS DESC RIP T IO N

set<Integer> getColumnOrdinals() Get the ordinals for each of the columns represented in this
data record.

String getColumnName(int column) Get the name of the given column.

int getColumnType(int column) Get the JDBC data type of the given column.

int getPrecision(int column) Get the precision for the given column.
IN T ERFA C E M ET H O DS DESC RIP T IO N

object[] getRowData() Gets the data for the current row as an array of Objects.

Each Object must match the Java language Type that is used
to represent the indicated JDBC data type for the given
column. For more information, see Understanding the JDBC
Driver Data Types for the appropriate mappings.

int getScale(int column) Get the scale for the given column.

boolean isAutoIncrement(int column) Indicates whether the column represents an identity column.

boolean next() Advances to the next data row.

SQLServerBulkCSVFileRecord
A simple implementation of the ISQLServerBulkRecord interface that can be used to read in the basic Java data
types from a delimited file where each line represents a row of data.
Implementation Notes and Limitations:
1. The maximum amount of data allowed in any given row is limited by the available memory because the
data is read one line at a time.
2. Streaming of large data types such as varchar(max) , varbinary(max) , nvarchar(max) , sqlxml , and
ntext isn't supported.

3. The delimiter specified for the CSV file shouldn't appear anywhere in the data and should be escaped
properly if it is a restricted character in Java regular expressions.
4. In the CSV file implementation, double quotes are treated as part of the data. For example, the line
hello,"world","hello,world" would be treated as having four columns with the values hello , "world" ,
"hello and world" if the delimiter is a comma.

5. New line characters are used as row terminators and aren't allowed anywhere in the data.

C O N ST RUC TO R DESC RIP T IO N

SQLServerBulkCSVFileRecord(String fileToParse, Initializes a new instance of the


String encoding, String delimiter, boolean SQLServerBulkCSVFileRecord class that will parse each line
firstLineIsColumnNames)
in the fileToParse with the provided delimiter and
encoding. If firstLineIsColumnNames is set to True, the
first line in the file will be parsed as column names. If
encoding is NULL, the default encoding will be used.

SQLServerBulkCSVFileRecord(String fileToParse, Initializes a new instance of the


String encoding, boolean firstLineIsColumnNames) SQLServerBulkCSVFileRecord class that will parse each line
in the fileToParse with a comma as the delimiter and
provided encoding. If firstLineIsColumnNames is set to
True, the first line in the file will be parsed as column names.
If encoding is NULL, the default encoding will be used.
C O N ST RUC TO R DESC RIP T IO N

SQLServerBulkCSVFileRecord(String fileToParse, Initializes a new instance of the


boolean firstLineIsColumnNames SQLServerBulkCSVFileRecord class that will parse each line
in the fileToParse with a comma as the delimiter and
default encoding. If firstLineIsColumnNames is set to True,
the first line in the file will be parsed as column names.

M ET H O D DESC RIP T IO N

void addColumnMetadata(int positionInFile, String Adds metadata for the given column in the file.
columnName, int jdbcType, int precision, int scale)

void close() Releases any resources associated with the file reader.

void Sets the format for parsing Timestamp data from the file as
setTimestampWithTimezoneFormat(DateTimeFormatter java.sql.Types.TIMESTAMP_WITH_TIMEZONE .
dateTimeFormatter)

void setTimestampWithTimezoneFormat(String Sets the format for parsing Time data from the file as
dateTimeFormat) java.sql.Types.TIME_WITH_TIMEZONE .

void setTimeWithTimezoneFormat(DateTimeFormatter Sets the format for parsing Time data from the file as
dateTimeFormatter) java.sql.Types.TIME_WITH_TIMEZONE .

void setTimeWithTimezoneFormat(String timeFormat) Sets the format for parsing Time data from the file as
java.sql.Types.TIME_WITH_TIMEZONE .

See also
Overview of the JDBC driver
Using bulk copy API for batch insert operation
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


Microsoft JDBC Driver for SQL Server version 9.2 and above supports using the Bulk Copy API for batch insert
operations. This feature allows users to enable the driver to do Bulk Copy operations underneath when
executing batch insert operations. The driver aims to achieve improvement in performance while inserting the
same data as the driver would have with regular batch insert operation. The driver parses the user's SQL Query,
using the Bulk Copy API instead of the usual batch insert operation. Below are various ways to enable the Bulk
Copy API for batch insert feature and lists its limitations. This page also contains a small sample code that
demonstrates a usage and the performance increase as well.
This feature is only applicable to PreparedStatement and CallableStatement's executeBatch() &
executeLargeBatch() APIs.

Prerequisites
Prerequisite to enable Bulk Copy API for batch insert.
The query must be an insert query (the query may contain comments, but the query must start with the
INSERT keyword for this feature to come into effect).

Enabling bulk copy API for batch insert


There are three ways to enable Bulk Copy API for batch insert.
1. Enabling with connection property
Adding useBulkCopyForBatchInser t=true; to the connection string enables this feature.

Connection connection = DriverManager.getConnection("jdbc:sqlserver://<server>:<port>;userName=


<user>;password=<password>;database=<database>;useBulkCopyForBatchInsert=true;");

2. Enabling with setUseBulkCopyForBatchInsert() method from SQLServerConnection object


Calling SQLSer verConnection.setUseBulkCopyForBatchInser t(true) enables this feature.
SQLSer verConnection.getUseBulkCopyForBatchInser t() retrieves the current value for
useBulkCopyForBatchInser t connection property.
The value for useBulkCopyForBatchInser t stays constant for each PreparedStatement at the time of its
initialization. Any subsequent calls to SQLSer verConnection.setUseBulkCopyForBatchInser t() won't affect
the already created PreparedStatement's value.
3. Enabling with setUseBulkCopyForBatchInsert() method from SQLServerDataSource object
Similar to above, but using SQLServerDataSource to create a SQLServerConnection object. Both methods
achieve the same result.

Known limitations
There are currently these limitations that apply to this feature.
Insert queries that contain non-parameterized values (for example, INSERT INTO TABLE VALUES (?, 2 )), isn't
supported. Wildcards (?) are the only supported parameters for this function.
Insert queries that contain INSERT-SELECT expressions (for example, INSERT INTO TABLE SELECT * FROM TABLE2
), isn't supported.
Insert queries that contain multiple VALUE expressions (for example, INSERT INTO TABLE VALUES (1, 2) (3, 4)
), isn't supported.
Insert queries that are followed by the OPTION clause, joined with multiple tables, or followed by another
query, isn't supported.
Because of the limitations of Bulk Copy API, MONEY , SMALLMONEY , DATE , DATETIME , DATETIMEOFFSET ,
SMALLDATETIME , TIME , GEOMETRY , and GEOGRAPHY data types, are currently not supported for this feature.

If the query fails because of non "SQL server" related errors, the driver will log the error message and fallback to
the original logic for batch insert.

Example
This is an example that demonstrates the use case for a batch insert operation of a thousand rows, for both
regular vs Bulk Copy API scenarios.
public static void main(String[] args) throws Exception
{
String tableName = "batchTest";
String tableNameBulkCopyAPI = "batchTestBulk";

String connectionUrl = "jdbc:sqlserver://<server>:<port>;databaseName=<database>;user=


<user>;password=<password>";

try (Connection con = DriverManager.getConnection(connectionUrl);


Statement stmt = con.createStatement();
PreparedStatement pstmt = con.prepareStatement("insert into " + tableName + " values (?,
?)");) {

String dropSql = "if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[" +


tableName + "]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE [" + tableName + "]";
stmt.execute(dropSql);

String createSql = "create table " + tableName + " (c1 int, c2 varchar(20))";
stmt.execute(createSql);

System.out.println("Starting batch operation using regular batch insert operation.");


long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
pstmt.setInt(1, i);
pstmt.setString(2, "test" + i);
pstmt.addBatch();
}
pstmt.executeBatch();

long end = System.currentTimeMillis();

System.out.println("Finished. Time taken : " + (end - start) + " milliseconds.");


}

try (Connection con = DriverManager.getConnection(connectionUrl +


";useBulkCopyForBatchInsert=true");
Statement stmt = con.createStatement();
PreparedStatement pstmt = con.prepareStatement("insert into " + tableNameBulkCopyAPI + "
values (?, ?)");) {

String dropSql = "if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[" +


tableNameBulkCopyAPI + "]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE [" + tableNameBulkCopyAPI
+ "]";
stmt.execute(dropSql);

String createSql = "create table " + tableNameBulkCopyAPI + " (c1 int, c2 varchar(20))";
stmt.execute(createSql);

System.out.println("Starting batch operation using Bulk Copy API.");


long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
pstmt.setInt(1, i);
pstmt.setString(2, "test" + i);
pstmt.addBatch();
}
pstmt.executeBatch();

long end = System.currentTimeMillis();

System.out.println("Finished. Time taken : " + (end - start) + " milliseconds.");


}
}

Result:
Starting batch operation using regular batch insert operation.
Finished. Time taken : 104132 milliseconds.
Starting batch operation using Bulk Copy API.
Finished. Time taken : 1058 milliseconds.

See also
Improving performance and reliability with the JDBC driver
Performing batch operations
4/27/2022 • 2 minutes to read • Edit Online

Download JDBC Driver


To improve performance when multiple updates to a SQL Server database are occurring, the Microsoft JDBC
Driver for SQL Server provides the ability to submit multiple updates as a single unit of work, also referred to as
a batch.
The SQLServerStatement, SQLServerPreparedStatement, and SQLServerCallableStatement classes can all be
used to submit batch updates. The addBatch method is used to add a command. The clearBatch method is used
to clear the list of commands. The executeBatch method is used to submit all commands for processing. Only
Data Definition Language (DDL) and Data Manipulation Language (DML) statements that return a simple update
count can be run as part of a batch.
The executeBatch method returns an array of int values that correspond to the update count of each command.
If one of the commands fails, a BatchUpdateException is thrown, and you should use the getUpdateCounts
method of the BatchUpdateException class to retrieve the update count array. If a command fails, the driver
continues processing the remaining commands. However, if a command has a syntax error, the statements in the
batch fail.

NOTE
If you do not have to use update counts, you can first issue a SET NOCOUNT ON statement to SQL Server. This will
reduce network traffic and additionally enhance the performance of your application.

As an example, create the following table in the sample database:

CREATE TABLE TestTable


(Col1 int IDENTITY,
Col2 varchar(50),
Col3 int);

In the following example, an open connection to the sample database is passed in to the function, the addBatch
method is used to create the statements to be executed, and the executeBatch method is called to submit the
batch to the database.

public static void executeBatchUpdate(Connection con) {


try {
Statement stmt = con.createStatement();
stmt.addBatch("INSERT INTO TestTable (Col2, Col3) VALUES ('X', 100)");
stmt.addBatch("INSERT INTO TestTable (Col2, Col3) VALUES ('Y', 200)");
stmt.addBatch("INSERT INTO TestTable (Col2, Col3) VALUES ('Z', 300)");
int[] updateCounts = stmt.executeBatch();
stmt.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
See also
Using statements with the JDBC driver
Using SQL escape sequences
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver


The Microsoft JDBC Driver for SQL Server supports the use of SQL escape sequences, as defined by the JDBC
API. Escape sequences are used within an SQL statement to tell the driver that the escaped part of the SQL string
should be handled differently. When the JDBC driver processes the escaped part of an SQL string, it translates
that part of the string into SQL code that SQL Server understands.
There are five types of escape sequences that the JDBC API requires, and all are supported by the JDBC driver:
LIKE wildcard literals
Function handling
Date and time literals
Stored procedure calls
Outer joins
Limit escape syntax
The escape sequence syntax used by the JDBC driver is the following:
{keyword ...parameters...}

NOTE
SQL escape processing is always turned on for the JDBC driver.

The following sections describe the five types of escape sequences and how they are supported by the JDBC
driver.

LIKE wildcard literals


The JDBC driver supports the {escape 'escape character'} syntax for using LIKE clause wildcards as literals. For
example, the following code will return values for col3, where the value of col2 literally begins with an
underscore (and not its wildcard usage).

ResultSet rst = stmt.executeQuery("SELECT col3 FROM test1 WHERE col2


LIKE '\\_%' {escape '\\'}");

NOTE
The escape sequence must be at the end of the SQL statement. For multiple SQL statements in a command string, the
escape sequence needs to be at the end of each relevant SQL statement.

Function handling
The JDBC driver supports function escape sequences in SQL statements with the following syntax:
{fn functionName}

where functionName is a function supported by the JDBC driver. For example:

SELECT {fn UCASE(Name)} FROM Employee

The following table lists the various functions that are supported by the JDBC driver when using a function
escape sequence:

ST RIN G F UN C T IO N S N UM ERIC F UN C T IO N S DAT ET IM E F UN C T IO N S SY ST EM F UN C T IO N S

ASCII ABS CURDATE DATABASE

CHAR ACOS CURTIME IFNULL

CONCAT ASIN DAYNAME USER

DIFFERENCE ATAN DAYOFMONTH

INSERT ATAN2 DAYOFWEEK

LCASE CEILING DAYOFYEAR

LEFT COS EXTRACT

LENGTH COT HOUR

LOCATE DEGREES MINUTE

LTRIM EXP MONTH

REPEAT FLOOR MONTHNAME

REPLACE LOG NOW

RIGHT LOG10 QUARTER

RTRIM MOD SECOND

SOUNDEX PI TIMESTAMPADD

SPACE POWER TIMESTAMPDIFF

SUBSTRING RADIANS WEEK

UCASE RAND YEAR

ROUND

SIGN

SIN

SQRT

TAN

TRUNCATE
NOTE
If you try to use a function that the database does not support, an error will occur.

Date and time literals


The escape syntax for date, time, and timestamp literals is the following:

{literal-type 'value'}

where literal-type is one of the following:

L IT ERA L T Y P E DESC RIP T IO N VA L UE F O RM AT

d Date yyyy-mm-dd

t Time hh:mm:ss [1]

ts TimeStamp yyyy-mm-dd hh:mm:ss[.f...]

For example:

UPDATE Orders SET OpenDate={d '2005-01-31'}


WHERE OrderID=1025

Stored procedure calls


The JDBC driver supports the {? = call proc_name(?,...)} and {call proc_name(?,...)} escape syntax for
stored procedure calls, depending on whether you need to process a return parameter.
A procedure is an executable object stored in the database. Generally, it is one or more SQL statements that have
been precompiled. The escape sequence syntax for calling a stored procedure is the following:

{[?=]call procedure-name[([parameter][,[parameter]]...)]}

where procedure-name specifies the name of a stored procedure and parameter specifies a stored procedure
parameter.
For more information about using the call escape sequence with stored procedures, see Using Statements
with Stored Procedures.

Outer joins
The JDBC driver supports the SQL92 left, right, and full outer join syntax. The escape sequence for outer joins is
the following:

{oj outer-join}

where outer-join is:


table-reference {LEFT | RIGHT | FULL} OUTER JOIN
{table-reference | outer-join} ON search-condition

where table-reference is a table name and search-condition is the join condition you want to use for the
tables.
For example:

SELECT Customers.CustID, Customers.Name, Orders.OrderID, Orders.Status


FROM {oj Customers LEFT OUTER JOIN
Orders ON Customers.CustID=Orders.CustID}
WHERE Orders.Status='OPEN'

The following outer join escape sequences are supported by the JDBC driver:
Left outer joins
Right outer joins
Full outer joins
Nested outer joins

Limit escape syntax


NOTE
The LIMIT escape syntax is only supported by Microsoft JDBC Driver 4.2 (or higher) for SQL Server when using JDBC 4.1
or higher.

The escape syntax for LIMIT is as follows:

LIMIT <rows> [OFFSET <row offset>]

The escape syntax has two parts: <rows> is mandatory and specifies the number of rows to return. OFFSET and
<row offset> are optional and specify the number of rows to skip before beginning to return rows. The JDBC
driver supports only the mandatory part by transforming the query to use TOP instead of LIMIT. SQL Server
does not support the LIMIT clause. The JDBC driver does not suppor t the optional <row offset> and
the driver will throw an exception if it is used .

See also
Using statements with the JDBC driver
Azure Key Vault sample version 9.2
4/27/2022 • 4 minutes to read • Edit Online

Download JDBC Driver

Sample application using Azure Key Vault


This application is runnable using JDBC Driver 9.2 and above, Azure-Security-Keyvault (version 4.2.8), Azure-
Identity (version 1.3.3), and their dependencies. To resolve the underlying dependencies, add these libraries to
the Project Object Model (POM) file of the project. For more information on feature dependencies, see Feature
dependencies of the Microsoft JDBC Driver for SQL Server.

import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import com.microsoft.aad.msal4j.IAuthenticationResult;
import com.microsoft.aad.msal4j.PublicClientApplication;
import com.microsoft.aad.msal4j.UserNamePasswordParameters;

import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionAzureKeyVaultProvider;
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider;
import com.microsoft.sqlserver.jdbc.SQLServerConnection;
import com.microsoft.sqlserver.jdbc.SQLServerException;
import com.microsoft.sqlserver.jdbc.SQLServerKeyVaultAuthenticationCallback;

public class AKV {

static String connectionUrl =


"jdbc:sqlserver://localhost;integratedSecurity=true;database=test;columnEncryptionSetting=enabled";
static String applicationClientID = "Your Client ID";
static String applicationKey = "Your Application Key";
static String keyID = "Your Key ID";
static String cmkName = "AKV_CMK_JDBC";
static String cekName = "AKV_CEK_JDBC";
static String akvTable = "akvTable";

static String createTableSQL = "create table " + akvTable + " ("


+ "PlainNvarcharMax nvarchar(max) null,"
+ "RandomizedNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ cekName + ") NULL,"
+ "DeterministicNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ cekName + ") NULL" + ");";

public static void main(String[] args)


throws ClassNotFoundException, Exception {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
try (Connection connection = DriverManager.getConnection(connectionUrl);
Statement statement = connection.createStatement()) {
statement.execute("DBCC FREEPROCCACHE");

statement.execute("DBCC FREEPROCCACHE");
System.out.println("Create SQLServerColumnEncryptionAzureKeyVaultProvider with
'authenticationCallback'");
/* Constructor added in 7.0.0 driver version [Supports SQLServerKeyVaultAuthenticationCallback
in 7.0 for backwards compatibility]
* This constructor is recommended to replace the above deprecated constructor */
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider2 = new
SQLServerColumnEncryptionAzureKeyVaultProvider(
tryAuthenticationCallback());
setupKeyStoreProviders(akvProvider2.getName(), akvProvider2);
testAKV(akvProvider2.getName(), akvProvider2, connection, statement);

statement.execute("DBCC FREEPROCCACHE");
System.out.println("Create SQLServerColumnEncryptionAzureKeyVaultProvider with 'clientId' and
'clientKey'");
/* Constructor added in 6.2.2 driver version [Continued Support] */
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider3 = new
SQLServerColumnEncryptionAzureKeyVaultProvider(
applicationClientID, applicationKey);
setupKeyStoreProviders(akvProvider3.getName(), akvProvider3);
testAKV(akvProvider3.getName(), akvProvider3, connection, statement);

statement.execute("DBCC FREEPROCCACHE");
System.out.println("Create SQLServerColumnEncryptionAzureKeyVaultProvider with 'token
credential'");
/* see Azure Identity client library for Java
* https://docs.microsoft.com/java/api/overview/azure/identity-readme?view=azure-java-stable */
ClientSecretCredential tokenCredential = new ClientSecretCredentialBuilder().tenantId(tenantID)
.clientId(applicationClientID).clientSecret(applicationKey).build();
/* Constructor added in 9.2.0 driver version */
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider4 = new
SQLServerColumnEncryptionAzureKeyVaultProvider(
tokenCredential);
setupKeyStoreProviders(akvProvider4.getName(), akvProvider4);
testAKV(akvProvider4.getName(), akvProvider4, connection, statement);

System.exit(0);
}
}

private static SQLServerKeyVaultAuthenticationCallback tryAuthenticationCallback()


throws URISyntaxException, SQLServerException {
SQLServerKeyVaultAuthenticationCallback authenticationCallback = new
SQLServerKeyVaultAuthenticationCallback() {

@Override
public String getAccessToken(String authority, String resource, String scope) {
try {
IClientCredential credential = ClientCredentialFactory.createFromSecret(applicationKey);
ConfidentialClientApplication confidentialClientApplication =
ConfidentialClientApplication
.builder(applicationClientID, credential).authority(authority).build();
Set<String> scopes = new HashSet<>();
scopes.add(scope);
return
confidentialClientApplication.acquireToken(ClientCredentialParameters.builder(scopes).build()).get().accessT
oken();
} catch (Exception e) {
fail(TestResource.getResource("R_unexpectedException") + e.getMessage());
}
return null;
}
};

return authenticationCallback;

}
}

private static void testAKV(String CUSTOM_AKV_PROVIDER_NAME,


SQLServerColumnEncryptionKeyStoreProvider akvProvider,
Connection connection, Statement statement)
throws SQLException, InterruptedException {

dropTable(statement);
dropKeys(statement);

System.out.println("createCMK");
createCMK(CUSTOM_AKV_PROVIDER_NAME, statement);

System.out.println("createCEK");
createCEK(akvProvider, statement);

System.out.println("create Table");
statement.execute(createTableSQL);

System.out.println("populate");
populateCharNormalCase(connection);

System.out.println("run the test");


testChar(statement);
}

private static void setupKeyStoreProviders(String CUSTOM_AKV_PROVIDER_NAME,


SQLServerColumnEncryptionKeyStoreProvider akvProvider)
throws SQLServerException {
/* unregister all previously registered providers if any */
SQLServerConnection.unregisterColumnEncryptionKeyStoreProviders();
Map<String, SQLServerColumnEncryptionKeyStoreProvider> map1 = new HashMap<String,
SQLServerColumnEncryptionKeyStoreProvider>();
map1.put(CUSTOM_AKV_PROVIDER_NAME, akvProvider);
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(map1);
}

private static void dropTable(Statement statement) throws SQLException {


statement.executeUpdate("if object_id('" + akvTable
+ "','U') is not null" + " drop table " + akvTable);
}

private static void dropKeys(Statement statement) throws SQLException {


statement.executeUpdate(
"if exists (SELECT name from sys.column_encryption_keys where name='"
+ cekName + "')" + " begin"
+ " drop column encryption key " + cekName + " end");
statement.executeUpdate(
"if exists (SELECT name from sys.column_master_keys where name='"
+ cmkName + "')" + " begin" + " drop column master key "
+ cmkName + " end");
}

private static void createCMK(String CUSTOM_AKV_PROVIDER_NAME,


Statement statement) throws SQLException {
String _createColumnMasterKeyTemplate = String.format(
"CREATE COLUMN MASTER KEY [%s] WITH ( KEY_STORE_PROVIDER_NAME = '%s', KEY_PATH = '%s');",
cmkName, CUSTOM_AKV_PROVIDER_NAME, keyID);
statement.execute(_createColumnMasterKeyTemplate);
}

private static void createCEK(


SQLServerColumnEncryptionKeyStoreProvider storeProvider,
Statement statement) throws SQLServerException, SQLException {
String letters = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] valuesDefault = letters.getBytes();
byte[] key = storeProvider.encryptColumnEncryptionKey(keyID, "RSA_OAEP",
valuesDefault);
String cekSql = "CREATE COLUMN ENCRYPTION KEY " + cekName
+ " WITH VALUES " + "(COLUMN_MASTER_KEY = " + cmkName
+ " WITH VALUES " + "(COLUMN_MASTER_KEY = " + cmkName
+ ", ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x"
+ bytesToHexString(key, key.length) + ")" + ";";
statement.execute(cekSql);
}

final static char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F'};

private static String bytesToHexString(byte[] b, int length) {


StringBuilder sb = new StringBuilder(length * 2);
for (int i = 0; i < length; i++) {
int hexVal = b[i] & 0xFF;
sb.append(hexChars[(hexVal & 0xF0) >> 4]);
sb.append(hexChars[(hexVal & 0x0F)]);
}
return sb.toString();
}

private static void populateCharNormalCase(Connection connection)


throws SQLException {
String sql = "insert into " + akvTable + " values(?,?,?)";
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
for (int i = 1; i <= 5; i++) { //Insert 5 rows
for (int j = 1; j <= 3; j++) {
pstmt.setNString(j, "Row " + i + " Column " + j);
}
pstmt.execute();
}
}
}

/**
* Rerieves the table
*
* @throws SQLException
*/
private static void testChar(Statement statement) throws SQLException {
try (ResultSet rs = statement
.executeQuery("select * from " + akvTable);) {
int numberOfColumns = rs.getMetaData().getColumnCount();
while (rs.next()) {
for (int i = 1; i <= numberOfColumns; i++) {
System.out.println(rs.getString(i));
}
}
}
}
}

See also
Azure Key vault sample version 7.0
Azure Key vault sample version 6.2.2
Azure Key vault sample version 6.0.0
Azure Key Vault sample versions 7.0, 8.0
4/27/2022 • 4 minutes to read • Edit Online

Download JDBC Driver

Sample application using Azure Key Vault


This application is runnable using JDBC Driver 7.0, 8.0, Azure-Keyvault (version 1.0.0), Adal4j (version 1.6.0), and
their dependencies. The underlying dependencies can be resolved by adding these libraries to the Project Object
Model (POM) file of the project. For more information on feature dependencies, see Feature dependencies of the
Microsoft JDBC Driver for SQL Server.

import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionAzureKeyVaultProvider;
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider;
import com.microsoft.sqlserver.jdbc.SQLServerConnection;
import com.microsoft.sqlserver.jdbc.SQLServerException;
import com.microsoft.sqlserver.jdbc.SQLServerKeyVaultAuthenticationCallback;

public class AKV {

static String connectionUrl =


"jdbc:sqlserver://localhost;integratedSecurity=true;database=test;columnEncryptionSetting=enabled";
static String applicationClientID = "Your Client ID";
static String applicationKey = "Your Application Key";
static String keyID = "Your Key ID";
static String cmkName = "AKV_CMK_JDBC";
static String cekName = "AKV_CEK_JDBC";
static String akvTable = "akvTable";

static String createTableSQL = "create table " + akvTable + " ("


+ "PlainNvarcharMax nvarchar(max) null,"
+ "RandomizedNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ cekName + ") NULL,"
+ "DeterministicNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ cekName + ") NULL" + ");";

public static void main(String[] args)


throws ClassNotFoundException, Exception {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
try (Connection connection = DriverManager.getConnection(connectionUrl);
Statement statement = connection.createStatement()) {
statement.execute("DBCC FREEPROCCACHE");
System.out.println("Create SQLServerColumnEncryptionAzureKeyVaultProvider with
'authenticationCallback' and 'executorService(null)'");
/* Constructor added in 6.0.0 driver version and removed in 6.2.2 driver, now added back in
7.0.0 driver
* [Supports SQLServerKeyVaultAuthenticationCallback in 7.0 for backwards compatibility]
* This constructor is marked @deprecated since it no longer uses 'ExecutorService' parameter
passed. */
@SuppressWarnings("deprecation")
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider1 = new
SQLServerColumnEncryptionAzureKeyVaultProvider(
tryAuthenticationCallback(), null);
setupKeyStoreProviders(akvProvider1.getName(), akvProvider1);
testAKV(akvProvider1.getName(), akvProvider1, connection, statement);

statement.execute("DBCC FREEPROCCACHE");
System.out.println("Create SQLServerColumnEncryptionAzureKeyVaultProvider with
'authenticationCallback'");
/* Constructor added in 7.0.0 driver version [Supports SQLServerKeyVaultAuthenticationCallback
in 7.0 for backwards compatibility]
* This constructor is recommended to replace the above deprecated constructor */
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider2 = new
SQLServerColumnEncryptionAzureKeyVaultProvider(
tryAuthenticationCallback());
testAKV(akvProvider2.getName(), akvProvider2, connection, statement);

statement.execute("DBCC FREEPROCCACHE");
System.out.println("Create SQLServerColumnEncryptionAzureKeyVaultProvider with 'clientId' and
'clientKey'");
/* Constructor added in 6.2.2 driver version [Continued Support] */
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider3 = new
SQLServerColumnEncryptionAzureKeyVaultProvider(
applicationClientID, applicationKey);
testAKV(akvProvider3.getName(), akvProvider3, connection, statement);
System.exit(0);
}
}

private static SQLServerKeyVaultAuthenticationCallback tryAuthenticationCallback()


throws URISyntaxException, SQLServerException {
SQLServerKeyVaultAuthenticationCallback authenticationCallback = new
SQLServerKeyVaultAuthenticationCallback() {

@Override
public String getAccessToken(String authority, String resource,
String scope) {
AuthenticationResult result = null;
try {
ExecutorService service = Executors.newFixedThreadPool(1);
AuthenticationContext context = new AuthenticationContext(
authority, false, service);
ClientCredential cred = new ClientCredential(
applicationClientID, applicationKey);
Future<AuthenticationResult> future = context
.acquireToken(resource, cred, null);
result = future.get();
service.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
return result.getAccessToken();
}
};

return authenticationCallback;

private static void testAKV(String CUSTOM_AKV_PROVIDER_NAME,


private static void testAKV(String CUSTOM_AKV_PROVIDER_NAME,
SQLServerColumnEncryptionKeyStoreProvider akvProvider,
Connection connection, Statement statement)
throws SQLException, InterruptedException {

dropTable(statement);
dropKeys(statement);

System.out.println("createCMK");
createCMK(CUSTOM_AKV_PROVIDER_NAME, statement);

System.out.println("createCEK");
createCEK(akvProvider, statement);

System.out.println("create Table");
statement.execute(createTableSQL);

System.out.println("populate");
populateCharNormalCase(connection);

System.out.println("run the test");


testChar(statement);
}

private static void setupKeyStoreProviders(String CUSTOM_AKV_PROVIDER_NAME,


SQLServerColumnEncryptionKeyStoreProvider akvProvider)
throws SQLServerException {
Map<String, SQLServerColumnEncryptionKeyStoreProvider> map1 = new HashMap<String,
SQLServerColumnEncryptionKeyStoreProvider>();
map1.put(CUSTOM_AKV_PROVIDER_NAME, akvProvider);
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(map1);
}

private static void dropTable(Statement statement) throws SQLException {


statement.executeUpdate("if object_id('" + akvTable
+ "','U') is not null" + " drop table " + akvTable);
}

private static void dropKeys(Statement statement) throws SQLException {


statement.executeUpdate(
"if exists (SELECT name from sys.column_encryption_keys where name='"
+ cekName + "')" + " begin"
+ " drop column encryption key " + cekName + " end");
statement.executeUpdate(
"if exists (SELECT name from sys.column_master_keys where name='"
+ cmkName + "')" + " begin" + " drop column master key "
+ cmkName + " end");
}

private static void createCMK(String CUSTOM_AKV_PROVIDER_NAME,


Statement statement) throws SQLException {
String _createColumnMasterKeyTemplate = String.format(
"CREATE COLUMN MASTER KEY [%s] WITH ( KEY_STORE_PROVIDER_NAME = '%s', KEY_PATH = '%s');",
cmkName, CUSTOM_AKV_PROVIDER_NAME, keyID);
statement.execute(_createColumnMasterKeyTemplate);
}

private static void createCEK(


SQLServerColumnEncryptionKeyStoreProvider storeProvider,
Statement statement) throws SQLServerException, SQLException {
String letters = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] valuesDefault = letters.getBytes();
byte[] key = storeProvider.encryptColumnEncryptionKey(keyID, "RSA_OAEP",
valuesDefault);
String cekSql = "CREATE COLUMN ENCRYPTION KEY " + cekName
+ " WITH VALUES " + "(COLUMN_MASTER_KEY = " + cmkName
+ ", ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x"
+ bytesToHexString(key, key.length) + ")" + ";";
statement.execute(cekSql);
}
}

final static char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F'};

private static String bytesToHexString(byte[] b, int length) {


StringBuilder sb = new StringBuilder(length * 2);
for (int i = 0; i < length; i++) {
int hexVal = b[i] & 0xFF;
sb.append(hexChars[(hexVal & 0xF0) >> 4]);
sb.append(hexChars[(hexVal & 0x0F)]);
}
return sb.toString();
}

private static void populateCharNormalCase(Connection connection)


throws SQLException {
String sql = "insert into " + akvTable + " values(?,?,?)";
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
for (int i = 1; i <= 5; i++) { //Insert 5 rows
for (int j = 1; j <= 3; j++) {
pstmt.setNString(j, "Row " + i + " Column " + j);
}
pstmt.execute();
}
}
}

/**
* Rerieves the table
*
* @throws SQLException
*/
private static void testChar(Statement statement) throws SQLException {
try (ResultSet rs = statement
.executeQuery("select * from " + akvTable);) {
int numberOfColumns = rs.getMetaData().getColumnCount();
while (rs.next()) {
for (int i = 1; i <= numberOfColumns; i++) {
System.out.println(rs.getString(i));
}
}
}
}
}

See also
Azure Key vault sample version 9.2
Azure Key vault sample version 6.2.2
Azure Key vault sample version 6.0.0
Azure Key Vault sample version 6.2.2
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver

Sample application using Azure Key Vault


This application is runnable using JDBC Driver 6.2.2 and 6.4.0, Azure-Keyvault (version 1.0.0), Adal4j (version
1.4.0), and their dependencies. The underlying dependencies can be resolved by adding these libraries to the
pom file of the project as described in the Feature dependencies of the Microsoft JDBC Driver for SQL Server:

import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionAzureKeyVaultProvider;
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider;
import com.microsoft.sqlserver.jdbc.SQLServerConnection;
import com.microsoft.sqlserver.jdbc.SQLServerException;

public class AKV_6_2_2 {

static String connectionUrl =


"jdbc:sqlserver://localhost;integratedSecurity=true;database=test;columnEncryptionSetting=enabled";
static String applicationClientID = "Your Client ID";
static String applicationKey = "Your Application Key";
static String keyID = "Your Key ID";
static String cmkName = "AKV_CMK_JDBC";
static String cekName = "AKV_CEK_JDBC";
static String akvTable = "akvTable";

static String createTableSQL = "create table " + akvTable + " ("


+ "PlainNvarcharMax nvarchar(max) null,"
+ "RandomizedNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ cekName + ") NULL,"
+ "DeterministicNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ cekName + ") NULL" + ");";

public static void main(String[] args)


throws ClassNotFoundException, Exception {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
try (Connection connection = DriverManager.getConnection(connectionUrl);
Statement statement = connection.createStatement()) {
statement.execute("DBCC FREEPROCCACHE");
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider = new
SQLServerColumnEncryptionAzureKeyVaultProvider(
applicationClientID, applicationKey);
setupKeyStoreProviders(akvProvider.getName(), akvProvider);
testAKV(akvProvider.getName(), akvProvider, connection, statement);
}
}

private static void testAKV(String CUSTOM_AKV_PROVIDER_NAME,


SQLServerColumnEncryptionKeyStoreProvider akvProvider,
SQLServerColumnEncryptionKeyStoreProvider akvProvider,
Connection connection, Statement statement)
throws SQLException, SQLServerException, InterruptedException {

dropTable(statement);
dropKeys(statement);

System.out.println("createCMK");
createCMK(CUSTOM_AKV_PROVIDER_NAME, statement);

System.out.println("createCEK");
createCEK(akvProvider, statement);

System.out.println("create Table");
statement.execute(createTableSQL);

System.out.println("populate");
populateCharNormalCase(connection);

System.out.println("run the test");


testChar(statement);
}

private static void setupKeyStoreProviders(String CUSTOM_AKV_PROVIDER_NAME,


SQLServerColumnEncryptionKeyStoreProvider akvProvider)
throws SQLServerException {
Map<String, SQLServerColumnEncryptionKeyStoreProvider> map1 = new HashMap<String,
SQLServerColumnEncryptionKeyStoreProvider>();
map1.put(CUSTOM_AKV_PROVIDER_NAME, akvProvider);
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(map1);
}

private static void dropTable(Statement statement) throws SQLException {


statement.executeUpdate("if object_id('" + akvTable
+ "','U') is not null" + " drop table " + akvTable);
}

private static void dropKeys(Statement statement) throws SQLException {


statement.executeUpdate(
"if exists (SELECT name from sys.column_encryption_keys where name='"
+ cekName + "')" + " begin"
+ " drop column encryption key " + cekName + " end");
statement.executeUpdate(
"if exists (SELECT name from sys.column_master_keys where name='"
+ cmkName + "')" + " begin" + " drop column master key "
+ cmkName + " end");
}

private static void createCMK(String CUSTOM_AKV_PROVIDER_NAME,


Statement statement) throws SQLException {
String _createColumnMasterKeyTemplate = String.format(
"CREATE COLUMN MASTER KEY [%s] WITH ( KEY_STORE_PROVIDER_NAME = '%s', KEY_PATH = '%s');",
cmkName, CUSTOM_AKV_PROVIDER_NAME, keyID);
statement.execute(_createColumnMasterKeyTemplate);
}

private static void createCEK(


SQLServerColumnEncryptionKeyStoreProvider storeProvider,
Statement statement) throws SQLServerException, SQLException {
String letters = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] valuesDefault = letters.getBytes();
byte[] key = storeProvider.encryptColumnEncryptionKey(keyID, "RSA_OAEP",
valuesDefault);
String cekSql = "CREATE COLUMN ENCRYPTION KEY " + cekName
+ " WITH VALUES " + "(COLUMN_MASTER_KEY = " + cmkName
+ ", ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x"
+ bytesToHexString(key, key.length) + ")" + ";";
statement.execute(cekSql);
}
final static char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F'};

private static String bytesToHexString(byte[] b, int length) {


StringBuilder sb = new StringBuilder(length * 2);
for (int i = 0; i < length; i++) {
int hexVal = b[i] & 0xFF;
sb.append(hexChars[(hexVal & 0xF0) >> 4]);
sb.append(hexChars[(hexVal & 0x0F)]);
}
return sb.toString();
}

private static void populateCharNormalCase(Connection connection)


throws SQLException {
String sql = "insert into " + akvTable + " values(?,?,?)";
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
for (int i = 1; i <= 3; i++) {
pstmt.setNString(i, "hello world");
}
pstmt.execute();
}
}

private static void testChar(Statement statement) throws SQLException {


try (ResultSet rs = statement
.executeQuery("select * from " + akvTable);) {
int numberOfColumns = rs.getMetaData().getColumnCount();
while (rs.next()) {
testGetString(rs, numberOfColumns);
}
}
}

private static void testGetString(ResultSet rs, int numberOfColumns)


throws SQLException {
for (int i = 1; i <= numberOfColumns; i = i + 3) {
String stringValue1 = "" + rs.getString(i);
String stringValue2 = "" + rs.getString(i + 1);
String stringValue3 = "" + rs.getString(i + 2);
System.out.println(stringValue1);
System.out.println(stringValue2);
System.out.println(stringValue3);
}
}
}

See also
Azure Key vault sample version 9.2
Azure Key Vault sample version 7.0.0
Azure Key Vault sample version 6.0.0
Azure Key Vault sample version 6.0.0
4/27/2022 • 3 minutes to read • Edit Online

Download JDBC Driver

Sample application using Azure Key Vault


This application is runnable using JDBC Driver 6.0.0, Azure-Keyvault (version 0.9.7), Adal4j (version 1.3.0), and
their dependencies. The underlying dependencies can be resolved by adding these libraries to the Project Object
Model (POM) file of the project. For more information on feature dependencies, see Feature dependencies of the
Microsoft JDBC Driver for SQL Server.

import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;

import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionAzureKeyVaultProvider;
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider;
import com.microsoft.sqlserver.jdbc.SQLServerConnection;
import com.microsoft.sqlserver.jdbc.SQLServerException;
import com.microsoft.sqlserver.jdbc.SQLServerKeyVaultAuthenticationCallback;

public class AKV_600 {

static String connectionUrl =


"jdbc:sqlserver://localhost;integratedSecurity=true;database=test;columnEncryptionSetting=enabled";
static String applicationClientID = "Your Client ID";
static String applicationKey = "Your Application Key";
static String keyID = "Your Key ID";
static String cmkName = "AKV_CMK_JDBC";
static String cekName = "AKV_CEK_JDBC";
static String akvTable = "akvTable";

static String createTableSQL = "create table " + akvTable + " ("


+ "PlainNvarcharMax nvarchar(max) null,"
+ "RandomizedNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ cekName + ") NULL,"
+ "DeterministicNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH
(ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ cekName + ") NULL" + ");";

static ExecutorService service = Executors.newFixedThreadPool(2);

private static SQLServerColumnEncryptionAzureKeyVaultProvider tryAuthenticationCallback()


throws URISyntaxException, SQLServerException {
SQLServerKeyVaultAuthenticationCallback authenticationCallback = new
SQLServerKeyVaultAuthenticationCallback() {

@Override
public String getAccessToken(String authority, String resource,
String scope) {
AuthenticationResult result = null;
try {
AuthenticationContext context = new AuthenticationContext(
authority, false, service);
ClientCredential cred = new ClientCredential(
applicationClientID, applicationKey);
Future<AuthenticationResult> future = context
.acquireToken(resource, cred, null);
result = future.get();
} catch (Exception e) {
e.printStackTrace();
}
return result.getAccessToken();
}
};

SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider = new


SQLServerColumnEncryptionAzureKeyVaultProvider(
authenticationCallback, service);
return akvProvider;
}

public static void main(String[] args)


throws ClassNotFoundException, Exception {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
try (Connection connection = DriverManager.getConnection(connectionUrl);
Statement statement = connection.createStatement()) {
statement.execute("DBCC FREEPROCCACHE");
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider = tryAuthenticationCallback();
setupKeyStoreProviders(akvProvider.getName(), akvProvider);
testAKV(akvProvider.getName(), akvProvider, connection, statement);
}
}

private static void testAKV(String CUSTOM_AKV_PROVIDER_NAME,


SQLServerColumnEncryptionKeyStoreProvider akvProvider,
Connection connection, Statement statement)
throws SQLException, SQLServerException, InterruptedException {

dropTable(statement);
dropKeys(statement);

System.out.println("createCMK");
createCMK(CUSTOM_AKV_PROVIDER_NAME, statement);

System.out.println("createCEK");
createCEK(akvProvider, statement);

System.out.println("create Table");
statement.execute(createTableSQL);

System.out.println("populate");
populateCharNormalCase(connection);

System.out.println("run the test");


testChar(statement);
}

private static void setupKeyStoreProviders(String CUSTOM_AKV_PROVIDER_NAME,


SQLServerColumnEncryptionKeyStoreProvider akvProvider)
throws SQLServerException {
Map<String, SQLServerColumnEncryptionKeyStoreProvider> map1 = new HashMap<String,
SQLServerColumnEncryptionKeyStoreProvider>();
map1.put(CUSTOM_AKV_PROVIDER_NAME, akvProvider);
map1.put(CUSTOM_AKV_PROVIDER_NAME, akvProvider);
SQLServerConnection.registerColumnEncryptionKeyStoreProviders(map1);
}

private static void dropTable(Statement statement) throws SQLException {


statement.executeUpdate("if object_id('" + akvTable
+ "','U') is not null" + " drop table " + akvTable);
}

private static void dropKeys(Statement statement) throws SQLException {


statement.executeUpdate(
"if exists (SELECT name from sys.column_encryption_keys where name='"
+ cekName + "')" + " begin"
+ " drop column encryption key " + cekName + " end");
statement.executeUpdate(
"if exists (SELECT name from sys.column_master_keys where name='"
+ cmkName + "')" + " begin" + " drop column master key "
+ cmkName + " end");
}

private static void createCMK(String CUSTOM_AKV_PROVIDER_NAME,


Statement statement) throws SQLException {
String _createColumnMasterKeyTemplate = String.format(
"CREATE COLUMN MASTER KEY [%s] WITH ( KEY_STORE_PROVIDER_NAME = '%s', KEY_PATH = '%s');",
cmkName, CUSTOM_AKV_PROVIDER_NAME, keyID);
statement.execute(_createColumnMasterKeyTemplate);
}

private static void createCEK(


SQLServerColumnEncryptionKeyStoreProvider storeProvider,
Statement statement) throws SQLServerException, SQLException {
String letters = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] valuesDefault = letters.getBytes();
byte[] key = storeProvider.encryptColumnEncryptionKey(keyID, "RSA_OAEP",
valuesDefault);
String cekSql = "CREATE COLUMN ENCRYPTION KEY " + cekName
+ " WITH VALUES " + "(COLUMN_MASTER_KEY = " + cmkName
+ ", ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x"
+ bytesToHexString(key, key.length) + ")" + ";";
statement.execute(cekSql);
}

final static char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F'};

private static String bytesToHexString(byte[] b, int length) {


StringBuilder sb = new StringBuilder(length * 2);
for (int i = 0; i < length; i++) {
int hexVal = b[i] & 0xFF;
sb.append(hexChars[(hexVal & 0xF0) >> 4]);
sb.append(hexChars[(hexVal & 0x0F)]);
}
return sb.toString();
}

private static void populateCharNormalCase(Connection connection)


throws SQLException {
String sql = "insert into " + akvTable + " values(?,?,?)";
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
for (int i = 1; i <= 3; i++) {
pstmt.setNString(i, "hello world");
}
pstmt.execute();
}
}

private static void testChar(Statement statement) throws SQLException {


try (ResultSet rs = statement
.executeQuery("select * from " + akvTable);) {
int numberOfColumns = rs.getMetaData().getColumnCount();
int numberOfColumns = rs.getMetaData().getColumnCount();
while (rs.next()) {
testGetString(rs, numberOfColumns);
}
}
}

private static void testGetString(ResultSet rs, int numberOfColumns)


throws SQLException {
for (int i = 1; i <= numberOfColumns; i = i + 3) {
String stringValue1 = "" + rs.getString(i);
String stringValue2 = "" + rs.getString(i + 1);
String stringValue3 = "" + rs.getString(i + 2);
System.out.println(stringValue1);
System.out.println(stringValue2);
System.out.println(stringValue3);
}
}
}

See also
Azure Key vault sample version 9.2
Azure Key Vault sample version 7.0
Azure Key Vault sample version 6.2.2
Node.js Driver for SQL Server
4/27/2022 • 2 minutes to read • Edit Online

To download Node.js SQL driver


The tedious module is a JavaScript implementation of the TDS protocol, which is supported by all modern
versions of SQL Server. The driver is an open-source project, available on GitHub.
You can connect to a SQL Database using Node.js on Windows, Linux, or macOS.

Get started
Step 1: Configure development environment for Node.js development
Step 2: Create a SQL database for Node.js development
Step 3: Proof of concept connecting to SQL using Node.js

Documentation
Tedious module documentation on GitHub

Support
Tedious for Node.js is community-supported software. Microsoft contributes to the tedious open-source
community and is an active participant in the repository at https://github.com/tediousjs/tedious. However, this
software doesn't come with Microsoft support.
To get help, file an issue in the tedious GitHub repository or visit other Node.js community resources.

Community resources
Azure Node.js Developer Center
Get Involved at nodejs.org

Code examples
Getting Started with Node.js on Windows
Getting Started with Node.js on macOS
Getting Started with Node.js on Ubuntu
Getting Started with Node.js on Red Hat Enterprise Linux (RHEL)
Getting Started with Node.js on SUSE Linux Enterprise Server (SLES)
Step 1: Configure development environment for
Node.js development
4/27/2022 • 2 minutes to read • Edit Online

You will need to configure your development environment with the prerequisites in order to develop an
application using the Node.js Driver for SQL Server. The most common method is to use the node package
manager (npm) to install the tedious module, but you can download the tedious module directly at GitHub if
you prefer.
The Node.js Driver uses the TDS protocol, which is enabled by default in SQL Server and Azure SQL Database.
No additional configuration is required.

Windows
1. Install Node.js runtime and npm package manager.
a. Go to Node.js
b. Click on the appropriate Windows installer msi link.
c. Once downloaded, run the msi to install Node.js
2. Open cmd.exe
3. Create a project director y and navigate to it.

> mkdir HelloWorld


> cd HelloWorld

4. Create a Node project. To retain the defaults during your project creation, press enter until the project is
created. At the end of this step, you should see a package.json file in your project directory.

> npm init

5. Install tedious module in your project. Tedious is the implementation of the TDS protocol, which is used
to communicate to SQL Server.

> npm install tedious

Ubuntu Linux
1. Open terminal
2. Install Node.js runtime.

>sudo apt-get install node

3. Install npm (node package manager).


> sudo apt-get install npm

4. Create a project director y and navigate to it.

> mkdir HelloWorld


> cd HelloWorld

5. Create a Node project. To retain the defaults during your project creation, press enter until the project is
created. At the end of this step, you should see a package.json file in your project directory.

> sudo npm init

6. Install tedious module in your project. Tedious is the implementation of the TDS protocol, which is used
to communicate to SQL Server.

> sudo npm install tedious

macOS
1. Install Node.js runtime and npm package manager.
a. Go to Node.js
b. Click on the appropriate macOS installer link.
c. Once downloaded, run 'dmg' to install Node.js
2. Open terminal
3. Create a project director y and navigate to it.

> mkdir HelloWorld


> cd HelloWorld

4. Create a Node project. To retain the defaults during your project creation, press enter until the project is
created. At the end of this step, you should see a package.json file in your project directory.

> npm init

5. Install tedious module in your project. This is the implementation of the TDS protocol which the driver
uses to communicate to SQL Server.

> npm install tedious


Step 2: Create a SQL database for Node.js
development
4/27/2022 • 2 minutes to read • Edit Online

The samples in this section only work with the AdventureWorks schema, on either Microsoft SQL Server or
Azure SQL Database.

Azure SQL Database


Create a SQL database in minutes using the Azure portal

Microsoft SQL Server


Microsoft SQL Server Samples on GitHub
Step 3: Proof of concept connecting to SQL using
Node.js
4/27/2022 • 2 minutes to read • Edit Online

To download Node.js SQL driver


This example should be considered a proof of concept only. The sample code is simplified for clarity, and does
not necessarily represent best practices recommended by Microsoft. Other examples, which use the same crucial
functions are available on GitHub:
https://github.com/tediousjs/tedious/blob/master/examples/

Step 1: Connect
The new Connection function is used to connect to SQL Database.

var Connection = require('tedious').Connection;


var config = {
server: 'your_server.database.windows.net', //update me
authentication: {
type: 'default',
options: {
userName: 'your_username', //update me
password: 'your_password' //update me
}
},
options: {
// If you are on Microsoft Azure, you need encryption:
encrypt: true,
database: 'your_database' //update me
}
};
var connection = new Connection(config);
connection.on('connect', function(err) {
// If no error, then good to proceed.
console.log("Connected");
});

connection.connect();

Step 2: Execute a query


All SQL statements are executed using the new Request() function. If the statement returns rows, such as a
select statement, you can retrieve them using the request.on() function. If there are no rows, the request.on()
function returns empty lists.
var Connection = require('tedious').Connection;
var config = {
server: 'your_server.database.windows.net', //update me
authentication: {
type: 'default',
options: {
userName: 'your_username', //update me
password: 'your_password' //update me
}
},
options: {
// If you are on Microsoft Azure, you need encryption:
encrypt: true,
database: 'your_database' //update me
}
};
var connection = new Connection(config);
connection.on('connect', function(err) {
// If no error, then good to proceed.
console.log("Connected");
executeStatement();
});

connection.connect();

var Request = require('tedious').Request;


var TYPES = require('tedious').TYPES;

function executeStatement() {
request = new Request("SELECT c.CustomerID, c.CompanyName,COUNT(soh.SalesOrderID) AS OrderCount FROM
SalesLT.Customer AS c LEFT OUTER JOIN SalesLT.SalesOrderHeader AS soh ON c.CustomerID = soh.CustomerID GROUP
BY c.CustomerID, c.CompanyName ORDER BY OrderCount DESC;", function(err) {
if (err) {
console.log(err);}
});
var result = "";
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
result+= column.value + " ";
}
});
console.log(result);
result ="";
});

request.on('done', function(rowCount, more) {


console.log(rowCount + ' rows returned');
});

// Close the connection after the final event emitted by the request, after the callback passes
request.on("requestCompleted", function (rowCount, more) {
connection.close();
});
connection.execSql(request);
}

Step 3: Insert a row


In this example you will see how to execute an INSERT statement safely, passing parameters, which protect your
application from SQL injection values.
var Connection = require('tedious').Connection;
var config = {
server: 'your_server.database.windows.net', //update me
authentication: {
type: 'default',
options: {
userName: 'your_username', //update me
password: 'your_password' //update me
}
},
options: {
// If you are on Microsoft Azure, you need encryption:
encrypt: true,
database: 'your_database' //update me
}
};
var connection = new Connection(config);
connection.on('connect', function(err) {
// If no error, then good to proceed.
console.log("Connected");
executeStatement1();
});

connection.connect();

var Request = require('tedious').Request


var TYPES = require('tedious').TYPES;

function executeStatement1() {
request = new Request("INSERT SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice,
SellStartDate) OUTPUT INSERTED.ProductID VALUES (@Name, @Number, @Cost, @Price, CURRENT_TIMESTAMP);",
function(err) {
if (err) {
console.log(err);}
});
request.addParameter('Name', TYPES.NVarChar,'SQL Server Express 2014');
request.addParameter('Number', TYPES.NVarChar , 'SQLEXPRESS2014');
request.addParameter('Cost', TYPES.Int, 11);
request.addParameter('Price', TYPES.Int,11);
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log("Product id of inserted item is " + column.value);
}
});
});

// Close the connection after the final event emitted by the request, after the callback passes
request.on("requestCompleted", function (rowCount, more) {
connection.close();
});
connection.execSql(request);
}
Microsoft ODBC Driver for SQL Server
4/27/2022 • 2 minutes to read • Edit Online

Version: 18.0.1.1
Date: February 15th 2022

Download ODBC Driver


ODBC is the primary native data access API for applications written in C and C++ for SQL Server. There's an
ODBC driver for most data sources. Other languages that can use ODBC include COBOL, Perl, PHP, and Python.
ODBC is widely used in data integration scenarios.
The ODBC driver comes with tools such as sqlcmd and bcp . The sqlcmd utility lets you run Transact-SQL
statements, system procedures, and SQL scripts. The bcp utility bulk copies data between an instance of
Microsoft SQL Server and a data file in a format you choose. You can use bcp to import many new rows into
SQL Server tables or to export data out of tables into data files.

Code example in C++


The following sample demonstrates how to use the ODBC APIs to connect to and access a database:
C++ code example, using ODBC

Download
To download ODBC driver

Documentation
Features
Connection Resiliency
Custom Keystore Providers
Data Classification
DSN and Connection String Keywords and Attributes
SQL Server Native Client (the features available also apply, without OLEDB, to the ODBC Driver for SQL
Server)
Using Always Encrypted
Using Azure Active Directory
Using Transparent Network IP Resolution
Using XA Transactions
Linux and macOS
Installing the driver on Linux
Installing the driver on macOS
Connecting to SQL Server
Connecting with bcp
Connecting with sqlcmd
Data Access Tracing
Frequently Asked Questions
Installing the Driver Manager
Known Issues
Programming Guidelines
Release Notes
Release Notes (mssql-tools)
Support for High Availability and Disaster Recovery
Using Integrated Authentication (Kerberos)
Windows
Asynchronous Execution (Notification Method) Sample
Driver-Aware Connection Pooling
Features and Behavior Changes
Release Notes for ODBC to SQL Server on Windows
System Requirements, Installation, and Driver Files

Community
SQL Server Drivers blog
SQL Server Data Access Forum
Download ODBC Driver for SQL Server
4/27/2022 • 3 minutes to read • Edit Online

Applies to: SQL Server (all supported versions) Azure SQL Database Azure SQL Managed Instance
Azure Synapse Analytics Analytics Platform System (PDW)
Microsoft ODBC Driver for SQL Server is a single dynamic-link library (DLL) containing run-time support for
applications using native-code APIs to connect to SQL Server. Use Microsoft ODBC Driver 18 for SQL Server to
create new applications or enhance existing applications that need to take advantage of newer SQL Server
features.

Download for Windows


The redistributable installer for Microsoft ODBC Driver 18 for SQL Server installs the client components, which
are required during run time to take advantage of newer SQL Server features. It optionally installs the header
files needed to develop an application that uses the ODBC API. Starting with version 17.4.2, the installer also
includes and installs the Microsoft Active Directory Authentication Library (ADAL.dll).
Version 18.0.1.1 is the latest general availability (GA) version. The Microsoft ODBC Driver 18 for SQL Server will
install side by side with Microsoft ODBC Driver 17 for SQL Server.

Download Microsoft ODBC Driver 18 for SQL Ser ver (x64)


Download Microsoft ODBC Driver 18 for SQL Ser ver (x86)
Version information
Release number: 18.0.1.1
Released: February 15, 2022

NOTE
If you are accessing this page from a non-English language version, and want to see the most up-to-date content, please
select Read in English at the top of this page. You can download different languages from the US-English version site by
selecting available languages.

Available languages
This release of Microsoft ODBC Driver for SQL Server can be installed in the following languages:
Microsoft ODBC Driver 18.0.1.1 for SQL Server (x64):
Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian | Japanese |
Korean | Portuguese (Brazil) | Russian | Spanish
Microsoft ODBC Driver 18.0.1.1 for SQL Server (x86):
Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian | Japanese |
Korean | Portuguese (Brazil) | Russian | Spanish
Version 17.9.1 is the latest general availability (GA) version of the 17.x driver. If you have a previous version of
Microsoft ODBC Driver 17 for SQL Server installed, installing 17.9.1 upgrades it to 17.9.1.

Download Microsoft ODBC Driver 17 for SQL Ser ver (x64)


Download Microsoft ODBC Driver 17 for SQL Ser ver (x86)
Release number: 17.9.1.1
Released: February 17, 2022
This release of Microsoft ODBC Driver for SQL Server can be installed in the following languages:
Microsoft ODBC Driver 17.9.1.1 for SQL Server (x64):
Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian | Japanese |
Korean | Portuguese (Brazil) | Russian | Spanish
Microsoft ODBC Driver 17.9.1.1 for SQL Server (x86):
Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian | Japanese |
Korean | Portuguese (Brazil) | Russian | Spanish
Release notes for Windows
For details about this release on Windows, see the Windows release notes.
Previous releases for Windows
To download previous releases for Windows, see previous Microsoft ODBC Driver for SQL Server releases.

Download for Linux and macOS


The Microsoft ODBC Driver for SQL Server can be downloaded and installed using package managers for Linux
and macOS using the relevant installation instructions:
Install ODBC for SQL Server (Linux)
Install ODBC for SQL Server (macOS)
If you need to download the packages for offline installation, all versions are available via the below links.

NOTE
Packages named msodbcsql18-* are the latest version. Packages named msodbcsql-* are version 13 of the driver.

Alpine
18.0.1.1 Alpine package (PGP Signature)
17.9.1.1 Alpine package (PGP Signature)
17.8.1.1 Alpine package (PGP Signature)
17.7.2.1 Alpine package (PGP Signature)
17.7.1.1 Alpine package (PGP Signature)
17.6.1.1 Alpine package (PGP Signature)
17.5.2.2 Alpine package (PGP Signature)
17.5.2.1 Alpine package (PGP Signature)
17.5.1.1 Alpine package (PGP Signature)
Debian
Debian 11 .deb packages: v17 v18
Debian 10 .deb packages: v17 v18
Debian 9 .deb packages: v17 v18
Debian 8 .deb packages: v13 v17
Red Hat
Red Hat 8 .rpm packages
Red Hat 7 .rpm packages
Red Hat 6 .rpm packages
Suse
SuSE 15 .rpm packages
SuSE 12 .rpm packages
SuSE 11 .rpm packages
Ubuntu
Ubuntu 21.10 .deb packages: v17 v18
Ubuntu 20.04 .deb packages: v17 v18
Ubuntu 18.04 .deb packages: v17 v18
Ubuntu 16.04 .deb packages: v13 v17
Ubuntu 14.04 .deb packages: v13 v17
See also Installing the Linux driver.
macOS
See the Homebrew formulae for details.
See also Installing the macOS driver.
Older Linux releases
Red Hat Enterprise Linux 5 and 6 (64-bit) - Download Microsoft ODBC Driver 11 for SQL Server - Red
Hat Linux
SUSE Linux Enterprise 11 Ser vice Pack 2 (64-bit) - Download Microsoft ODBC Driver 11 Preview for
SQL Server - SUSE Linux
Release notes for Linux and macOS
For details about releases for Linux and macOS, see the Linux and macOS release notes.
System Requirements (Linux and macOS)
4/27/2022 • 3 minutes to read • Edit Online

Download ODBC Driver


This topic lists the requirements to use the Microsoft ODBC Driver for SQL Server on Linux and macOS.

SQL version compatibility


The Linux and macOS drivers SQL version compatibility is the same as the Windows drivers SQL version
compatibility.

Operating system support


Versions 18, 17, 13.1, and 13 of the Linux and macOS drivers are supported on the x64 architecture of the
following operating systems. The ARM64 architecture on macOS is supported starting with version 17.8.

DRIV
ER
VER
SIO
N→

OPE
RAT I
NG
SY S
T EM 18. 0 17. 9 17. 8 17. 7 17. 6 17. 5 17. 4 17. 3 17. 2 17. 1 17. 0 13. 1 13

Appl Yes Yes Yes Yes Yes Yes Yes


e OS
X
10.1
1 (El
Capi
tan)

Appl Yes Yes Yes Yes Yes Yes Yes


e
mac
OS
10.1
2
(Sier
ra)

Appl Yes Yes Yes Yes Yes Yes Yes Yes Yes
e
mac
OS
10.1
3
(Hig
h
Sierr
a)
DRIV
ER
VER
SIO
N→

OPE
RAT I
NG
SY S
T EM 18. 0 17. 9 17. 8 17. 7 17. 6 17. 5 17. 4 17. 3 17. 2 17. 1 17. 0 13. 1 13

Appl Yes Yes Yes Yes Yes Yes


e
mac
OS
10.1
4
(Moj
ave)

Appl Yes Yes Yes Yes Yes Yes


e
mac
OS
10.1
5
(Cat
alina
)

Appl Yes Yes Yes Yes


e
mac
OS
11.0
(Big
Sur)

Appl Yes Yes


e
mac
OS
12.0
(Mo
nter
ey)

Alpi Yes Yes Yes Yes


ne
Linu
x
3.11

Alpi Yes Yes Yes Yes


ne
Linu
x
3.12
DRIV
ER
VER
SIO
N→

OPE
RAT I
NG
SY S
T EM 18. 0 17. 9 17. 8 17. 7 17. 6 17. 5 17. 4 17. 3 17. 2 17. 1 17. 0 13. 1 13

Alpi Yes Yes Yes Yes


ne
Linu
x
3.13

Alpi Yes Yes Yes Yes


ne
Linu
x
3.14

Alpi Yes Yes Yes Yes


ne
Linu
x
3.15

Debi Yes Yes Yes Yes Yes Yes Yes Yes Yes
an
Linu
x8

Debi Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
an
Linu
x9

Debi Yes Yes Yes Yes Yes Yes Yes


an
Linu
x 10

Debi Yes Yes


an
Linu
x 11

Orac Yes Yes Yes Yes


le
Linu
x7

Orac Yes Yes Yes Yes Yes Yes


le
Linu
x8
DRIV
ER
VER
SIO
N→

OPE
RAT I
NG
SY S
T EM 18. 0 17. 9 17. 8 17. 7 17. 6 17. 5 17. 4 17. 3 17. 2 17. 1 17. 0 13. 1 13

Red Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
Hat
Ente
rpris
e
Linu
x6

Red Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
Hat
Ente
rpris
e
Linu
x7

Red Yes Yes Yes Yes Yes Yes Yes


Hat
Ente
rpris
e
Linu
x8

SUS Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
E
Linu
x
Ente
rpris
e
Serv
er
111

SUS Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
E
Linu
x
Ente
rpris
e
Serv
er
12
DRIV
ER
VER
SIO
N→

OPE
RAT I
NG
SY S
T EM 18. 0 17. 9 17. 8 17. 7 17. 6 17. 5 17. 4 17. 3 17. 2 17. 1 17. 0 13. 1 13

SUS Yes Yes Yes Yes Yes Yes Yes Yes


E
Linu
x
Ente
rpris
e
Serv
er
15

Ubu Yes Yes Yes Yes Yes Yes Yes


ntu
Linu
x
14.0
4

Ubu Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
ntu
Linu
x
16.0
4

Ubu Yes Yes Yes Yes Yes Yes Yes Yes Yes
ntu
Linu
x
18.0
4

Ubu Yes Yes Yes Yes Yes


ntu
Linu
x
20.0
4

Ubu Yes Yes Yes Yes Yes


ntu
Linu
x
21.0
4
DRIV
ER
VER
SIO
N→

OPE
RAT I
NG
SY S
T EM 18. 0 17. 9 17. 8 17. 7 17. 6 17. 5 17. 4 17. 3 17. 2 17. 1 17. 0 13. 1 13

Ubu Yes Yes


ntu
Linu
x
21.1
0

1 ODBC Driver 17 supports SUSE Linux Enterprise Server 11 SP4 only


The installation packages for the Microsoft ODBC Driver 13, 13.1, and 17 for SQL Server on Linux and macOS
resolve the driver's dependencies automatically when installed using the package management system of your
distribution, as described in Install the ODBC Driver (Linux) and Install the ODBC Driver (macOS).

Microsoft ODBC Driver 11 for SQL Server


64-bit UnixODBC 2.3.0 Driver Manager, built for 64-bit SQLLEN/SQLULEN. Later versions of the 64-bit
UnixODBC Driver Manager are not supported with the ODBC driver on Linux. See Installing the Driver
Manager for more information.
ODBC driver for Red Hat Enterprise Linux 5 (64-bit) requires the following packages, and can be
downloaded here: Microsoft ODBC Driver 11 for SQL Server - Red Hat Linux
glibc
libgcc
libstdc++
e2fsprogs-libs
krb5-libs
openssl
ODBC driver for Red Hat Enterprise Linux 6 (64-bit) requires the following packages, and can be
downloaded here: Microsoft ODBC Driver 11 for SQL Server - Red Hat Linux
glibc
libgcc
libstdc++
libuuid
krb5-libs
openssl
ODBC driver for SUSE Linux Enterprise 11 Ser vice Pack 2 (64-bit) requires the following packages,
and can be downloaded here: Microsoft ODBC Driver 11 Preview for SQL Server - SUSE Linux
glibc
libstdc++46
libgcc46
libuuid1
krb5
libopenssl0_9_8

See Also
Installing the Driver Manager
Known Issues in this Version of the Driver
Release Notes
Installing the Driver Manager
4/27/2022 • 3 minutes to read • Edit Online

Download ODBC Driver


This article contains instructions to install the unixODBC Driver Manager for use with all the versions of
Microsoft ODBC Driver for SQL Server on Linux and macOS.

IMPORTANT
Delete any driver manager packages installed on your computer before you install the unixODBC Driver Manager.
Installing the unixODBC Driver Manager could cause a failure of an existing Driver Manager.

Installing the Driver Manager for Microsoft ODBC Driver 13, 13.1, 17,
and 18
The driver manager dependency is resolved automatically by the package management system when you install
the Microsoft ODBC Driver 13, 13.1, 17, or 18 for SQL Server on Linux or macOS by following the instructions in
the following articles:
Installing the Microsoft ODBC Driver for SQL Server on Linux
Installing the Microsoft ODBC Driver for SQL Server on macOS

Installing the Driver Manager for Microsoft ODBC Driver 11 for SQL
Server
(SUSE and Red Hat Linux only.)
Using the Installation Script

IMPORTANT
These instructions refer to msodbcsql-11.0.2270.0.tar.gz , which is the installation file for Red Hat Linux. If you are
installing the Preview for SUSE Linux, the file name is msodbcsql-11.0.2260.0.tar.gz .

To install the driver manager:


1. Make sure that you have root permission.
2. Go to the directory where the MicrosoftSQL Server ODBC Driver download placed the file called
msodbcsql-11.0.2270.0.tar.gz . Make sure that you have the *.tar.gz file that matches your version of
Linux. To extract the files, execute the following command: tar xvzf msodbcsql-11.0.2270.0.tar.gz .
3. Change to the msodbcsql-11.0.2270.0 directory and there you should see a file called build_dm.sh . You
can run build_dm.sh to install the unixODBC Driver Manager.
4. To see a list of the available options, execute the following command: ./build_dm.sh --help .
5. When you are ready to install, and if your computer can access an external site via FTP, execute the
following command: ./build_dm.sh .
If your computer cannot access an external site via FTP, get unixODBC-2.3.0.tar.gz . You can get
unixODBC-2.3.0.tar.gz from http://www.unixodbc.org. Click the Download link on the left side of the page to
go to the download page. Then click the appropriate link to download unixODBC-2.3.0 (not unixODBC-2.3.1).
unixODBC-2.3.1 is not supported with this release of the Microsoft ODBC Driver 11 for SQL Server. Execute the
following command to begin the unixODBC Driver Manager installation: ./build_dm.sh --download-
url=file://unixODBC-2.3.0.tar.gz .
6. Type YES to proceed with unpacking the files. This part of the process can take up to five minutes to
complete.
7. After the script stops running, follow the instructions on the screen to install the unixODBC Driver
Manager.
You are now ready to install the driver. For more information, see the ODBC driver installation instructions for
Linux or macOS.
Manual Installation
If the installation script is unable to complete, configure and build the proper driver manager yourself.
1. Remove any older installed version of unixODBC (for example, unixODBC 2.2.11). On Red Hat Enterprise
Linux 5 or 6, execute the following command: yum remove unixODBC . On SUSE Linux Enterprise,
zypper remove unixODBC .
2. Go to http://www.unixodbc.org. Click the Download link on the left side of the page to go to the
download page. Then click the appropriate link to save the file unixODBC-2.3.0.tar.gz to your computer.
UnixODBC-2.3.1 is not supported with this release of the Microsoft ODBC Driver 11 for SQL Server.
3. On your Linux computer, execute the command: tar xvzf unixODBC-2.3.0.tar.gz .
4. Change to the unixODBC-2.3.0 directory.
5. At a command prompt, execute the command: CPPFL AGS="-DSIZEOF_LONG_INT=8" .
6. At a command prompt, execute the command: expor t CPPFL AGS .
7. At a command prompt, execute the command: "./configure --prefix=/usr --libdir=/usr/lib64 --
sysconfdir=/etc --enable-gui=no --enable-drivers=no --enable-iconv --with-iconv-char-
enc=UTF8 --with-iconv-ucode-enc=UTF16LE" .
8. At a command prompt (logged in as root), execute the command: make .
9. At a command prompt (logged in as root), execute the command: make install .
You are now ready to install the driver. For more information, see the ODBC driver installation instructions for
Linux or macOS.

See Also
Installing the Microsoft ODBC Driver for SQL Server on Linux
Installing the Microsoft ODBC Driver for SQL Server on macOS
Release Notes
Install the Microsoft ODBC driver for SQL Server
(Linux)
4/27/2022 • 14 minutes to read • Edit Online

This article explains how to install the Microsoft ODBC Driver for SQL Server on Linux. It also includes
instructions for the optional command-line tools for SQL Server ( bcp and sqlcmd ) and the unixODBC
development headers.
This article provides commands for installing the ODBC driver from the bash shell. If you want to download the
packages directly, see Download ODBC Driver for SQL Server.

Microsoft ODBC 18
The following sections explain how to install the Microsoft ODBC driver 18 from the bash shell for different
Linux distributions.
Alpine Linux
Debian
Red Hat Enterprise Linux and Oracle
SUSE Linux Enterprise Server
Ubuntu
Alpine Linux

#Download the desired package(s)


curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-
da08869c6486/msodbcsql18_18.0.1.1-1_amd64.apk
curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486/mssql-
tools18_18.0.1.1-1_amd64.apk

#(Optional) Verify signature, if 'gpg' is missing install it using 'apk add gnupg':
curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-
da08869c6486/msodbcsql18_18.0.1.1-1_amd64.sig
curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486/mssql-
tools18_18.0.1.1-1_amd64.sig

curl https://packages.microsoft.com/keys/microsoft.asc | gpg --import -


gpg --verify msodbcsql18_18.0.1.1-1_amd64.sig msodbcsql18_18.0.1.1-1_amd64.apk
gpg --verify mssql-tools18_18.0.1.1-1_amd64.sig mssql-tools18_18.0.1.1-1_amd64.apk

#Install the package(s)


sudo apk add --allow-untrusted msodbcsql18_18.0.1.1-1_amd64.apk
sudo apk add --allow-untrusted mssql-tools18_18.0.1.1-1_amd64.apk

NOTE
Driver version 17.5 or higher is required for Alpine support.

Debian
sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -

#Download appropriate package for the OS version


#Choose only ONE of the following, corresponding to your OS version

#Debian 9
curl https://packages.microsoft.com/config/debian/9/prod.list > /etc/apt/sources.list.d/mssql-release.list

#Debian 10
curl https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list

#Debian 11
curl https://packages.microsoft.com/config/debian/11/prod.list > /etc/apt/sources.list.d/mssql-release.list

exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools18
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo apt-get install -y unixodbc-dev
# optional: kerberos library for debian-slim distributions
sudo apt-get install -y libgssapi-krb5-2

NOTE
You can substitute setting the environment variable 'ACCEPT_EULA' with setting the debconf variable
'msodbcsql/ACCEPT_EULA' instead:
echo msodbcsql18 msodbcsql/ACCEPT_EULA boolean true | sudo debconf-set-selections

Red Hat Enterprise Server and Oracle Linux

sudo su

#Download appropriate package for the OS version


#Choose only ONE of the following, corresponding to your OS version

#Red Hat Enterprise Server 7 and Oracle Linux 7


curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo

#Red Hat Enterprise Server 8 and Oracle Linux 8


curl https://packages.microsoft.com/config/rhel/8/prod.repo > /etc/yum.repos.d/mssql-release.repo

exit
sudo yum remove unixODBC-utf16 unixODBC-utf16-devel #to avoid conflicts
sudo ACCEPT_EULA=Y yum install -y msodbcsql18
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y yum install -y mssql-tools18
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo yum install -y unixODBC-devel

SUSE Linux Enterprise Server


sudo su
curl -O https://packages.microsoft.com/keys/microsoft.asc
rpm --import microsoft.asc

#Download appropriate package for the OS version


#Choose only ONE of the following, corresponding to your OS version

#SUSE Linux Enterprise Server 11 SP4


#Ensure SUSE Linux Enterprise 11 Security Module has been installed
zypper ar https://packages.microsoft.com/config/sles/11/prod.repo

#SUSE Linux Enterprise Server 12


zypper ar https://packages.microsoft.com/config/sles/12/prod.repo

#SUSE Linux Enterprise Server 15


zypper ar https://packages.microsoft.com/config/sles/15/prod.repo
#(Only for driver 17.3 and below)
SUSEConnect -p sle-module-legacy/15/x86_64

exit
sudo ACCEPT_EULA=Y zypper install -y msodbcsql18
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y zypper install -y mssql-tools18
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo zypper install -y unixODBC-devel

Ubuntu

if ! [[ "18.04 20.04 21.04" == *"$(lsb_release -rs)"* ]];


then
echo "Ubuntu $(lsb_release -rs) is not currently supported.";
exit;
fi

sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -

curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list >


/etc/apt/sources.list.d/mssql-release.list

exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools18
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo apt-get install -y unixodbc-dev

NOTE
You can substitute setting the environment variable 'ACCEPT_EULA' with setting the debconf variable
'msodbcsql/ACCEPT_EULA' instead:
echo msodbcsql18 msodbcsql/ACCEPT_EULA boolean true | sudo debconf-set-selections

Previous versions
The following sections provide instructions for installing previous versions of the Microsoft ODBC driver on
Linux. The following driver versions are covered:
Microsoft ODBC driver 17 for SQL Server
Microsoft ODBC driver 13.1 for SQL Server
Microsoft ODBC driver 13 for SQL Server
Microsoft ODBC driver 11 for SQL Server

Microsoft ODBC 17
The following sections explain how to install the Microsoft ODBC driver 17 from the bash shell for different
Linux distributions.
Alpine Linux
Debian
Red Hat Enterprise Linux and Oracle
SUSE Linux Enterprise Server
Ubuntu

IMPORTANT
If you installed the v17 msodbcsql package that was briefly available, you should remove it before installing the
msodbcsql17 package. This will avoid conflicts. The msodbcsql17 package can be installed side by side with the
msodbcsql v13 package.

Alpine Linux

#Download the desired package(s)


curl -O https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-
8d28ddafb39b/msodbcsql17_17.9.1.1-1_amd64.apk
curl -O https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/mssql-
tools_17.9.1.1-1_amd64.apk

#(Optional) Verify signature, if 'gpg' is missing install it using 'apk add gnupg':
curl -O https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-
8d28ddafb39b/msodbcsql17_17.9.1.1-1_amd64.sig
curl -O https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/mssql-
tools_17.9.1.1-1_amd64.sig

curl https://packages.microsoft.com/keys/microsoft.asc | gpg --import -


gpg --verify msodbcsql17_17.9.1.1-1_amd64.sig msodbcsql17_17.9.1.1-1_amd64.apk
gpg --verify mssql-tools_17.9.1.1-1_amd64.sig mssql-tools_17.9.1.1-1_amd64.apk

#Install the package(s)


sudo apk add --allow-untrusted msodbcsql17_17.9.1.1-1_amd64.apk
sudo apk add --allow-untrusted mssql-tools_17.9.1.1-1_amd64.apk

NOTE
Driver version 17.5 or higher is required for Alpine support.

Debian
sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -

#Download appropriate package for the OS version


#Choose only ONE of the following, corresponding to your OS version

#Debian 8 (only supported up to driver version 17.6)


curl https://packages.microsoft.com/config/debian/8/prod.list > /etc/apt/sources.list.d/mssql-release.list

#Debian 9
curl https://packages.microsoft.com/config/debian/9/prod.list > /etc/apt/sources.list.d/mssql-release.list

#Debian 10
curl https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list

#Debian 11
curl https://packages.microsoft.com/config/debian/11/prod.list > /etc/apt/sources.list.d/mssql-release.list

exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql17
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo apt-get install -y unixodbc-dev
# optional: kerberos library for debian-slim distributions
sudo apt-get install -y libgssapi-krb5-2

NOTE
You can substitute setting the environment variable 'ACCEPT_EULA' with setting the debconf variable
'msodbcsql/ACCEPT_EULA' instead:
echo msodbcsql17 msodbcsql/ACCEPT_EULA boolean true | sudo debconf-set-selections

Red Hat Enterprise Server and Oracle Linux

sudo su

#Download appropriate package for the OS version


#Choose only ONE of the following, corresponding to your OS version

#Red Hat Enterprise Server 6 (only supported up to driver version 17.7)


curl https://packages.microsoft.com/config/rhel/6/prod.repo > /etc/yum.repos.d/mssql-release.repo

#Red Hat Enterprise Server 7 and Oracle Linux 7


curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo

#Red Hat Enterprise Server 8 and Oracle Linux 8


curl https://packages.microsoft.com/config/rhel/8/prod.repo > /etc/yum.repos.d/mssql-release.repo

exit
sudo yum remove unixODBC-utf16 unixODBC-utf16-devel #to avoid conflicts
sudo ACCEPT_EULA=Y yum install -y msodbcsql17
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y yum install -y mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo yum install -y unixODBC-devel
SUSE Linux Enterprise Server

sudo su
curl -O https://packages.microsoft.com/keys/microsoft.asc
rpm --import microsoft.asc

#Download appropriate package for the OS version


#Choose only ONE of the following, corresponding to your OS version

#SUSE Linux Enterprise Server 11 SP4


#Ensure SUSE Linux Enterprise 11 Security Module has been installed
zypper ar https://packages.microsoft.com/config/sles/11/prod.repo

#SUSE Linux Enterprise Server 12


zypper ar https://packages.microsoft.com/config/sles/12/prod.repo

#SUSE Linux Enterprise Server 15


zypper ar https://packages.microsoft.com/config/sles/15/prod.repo
#(Only for driver 17.3 and below)
SUSEConnect -p sle-module-legacy/15/x86_64

exit
sudo ACCEPT_EULA=Y zypper install -y msodbcsql17
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y zypper install -y mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo zypper install -y unixODBC-devel

Ubuntu

if ! [[ "16.04 18.04 20.04 21.04 21.10" == *"$(lsb_release -rs)"* ]];


then
echo "Ubuntu $(lsb_release -rs) is not currently supported.";
exit;
fi

sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -

curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list >


/etc/apt/sources.list.d/mssql-release.list

exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql17
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo apt-get install -y unixodbc-dev

NOTE
You can substitute setting the environment variable 'ACCEPT_EULA' with setting the debconf variable
'msodbcsql/ACCEPT_EULA' instead:
echo msodbcsql17 msodbcsql/ACCEPT_EULA boolean true | sudo debconf-set-selections

ODBC 13.1
The following sections explain how to install the Microsoft ODBC driver 13.1 from the bash shell for different
Linux distributions.
Debian 8

sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/debian/8/prod.list > /etc/apt/sources.list.d/mssql-release.list
exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y apt-get install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo apt-get install unixodbc-dev

Red Hat Enterprise Server 6

sudo su
curl https://packages.microsoft.com/config/rhel/6/prod.repo > /etc/yum.repos.d/mssql-release.repo
exit
sudo yum remove unixODBC-utf16 unixODBC-utf16-devel #to avoid conflicts
sudo ACCEPT_EULA=Y yum install msodbcsql
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y yum install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo yum install unixODBC-devel

Red Hat Enterprise Server 7

sudo su
curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo
exit
sudo yum remove unixODBC-utf16 unixODBC-utf16-devel #to avoid conflicts
sudo ACCEPT_EULA=Y yum install msodbcsql
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y yum install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo yum install unixODBC-devel

SUSE Linux Enterprise Server 11

sudo su
zypper ar https://packages.microsoft.com/config/sles/11/prod.repo
exit
sudo ACCEPT_EULA=Y zypper install msodbcsql
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y zypper install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo zypper install unixODBC-devel

SUSE Linux Enterprise Server 12


sudo su
zypper ar https://packages.microsoft.com/config/sles/12/prod.repo
exit
sudo ACCEPT_EULA=Y zypper install msodbcsql
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y zypper install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo zypper install unixODBC-devel

Ubuntu 15.10

sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/15.10/prod.list > /etc/apt/sources.list.d/mssql-
release.list
exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y apt-get install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo apt-get install unixodbc-dev

Ubuntu 16.04

sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-
release.list
exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y apt-get install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo apt-get install unixodbc-dev

Ubuntu 16.10

sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/16.10/prod.list > /etc/apt/sources.list.d/mssql-
release.list
exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql
# optional: for bcp and sqlcmd
sudo ACCEPT_EULA=Y apt-get install mssql-tools
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
# optional: for unixODBC development headers
sudo apt-get install unixodbc-dev

ODBC 13
The following sections explain how to install the Microsoft ODBC driver 13 from the bash shell for different
Linux distributions.
Red Hat Enterprise Server 6 (ODBC 13)

sudo su
curl https://packages.microsoft.com/config/rhel/6/prod.repo > /etc/yum.repos.d/mssql-release.repo
exit
sudo yum update
sudo yum remove unixODBC #to avoid conflicts
sudo ACCEPT_EULA=Y yum install msodbcsql-13.0.1.0-1 mssql-tools-14.0.2.0-1
sudo yum install unixODBC-utf16-devel #this step is optional but recommended*
#Create symlinks for tools
ln -sfn /opt/mssql-tools/bin/sqlcmd-13.0.1.0 /usr/bin/sqlcmd
ln -sfn /opt/mssql-tools/bin/bcp-13.0.1.0 /usr/bin/bcp

Red Hat Enterprise Server 7 (ODBC 13)

sudo su
curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo
exit
sudo yum update
sudo yum remove unixODBC #to avoid conflicts
sudo ACCEPT_EULA=Y yum install msodbcsql-13.0.1.0-1 mssql-tools-14.0.2.0-1
sudo yum install unixODBC-utf16-devel #this step is optional but recommended*
#Create symlinks for tools
ln -sfn /opt/mssql-tools/bin/sqlcmd-13.0.1.0 /usr/bin/sqlcmd
ln -sfn /opt/mssql-tools/bin/bcp-13.0.1.0 /usr/bin/bcp

Ubuntu 15.10 (ODBC 13)

sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/15.10/prod.list > /etc/apt/sources.list.d/mssql-
release.list
exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql=13.0.1.0-1 mssql-tools=14.0.2.0-1
sudo apt-get install unixodbc-dev-utf16 #this step is optional but recommended*
#Create symlinks for tools
ln -sfn /opt/mssql-tools/bin/sqlcmd-13.0.1.0 /usr/bin/sqlcmd
ln -sfn /opt/mssql-tools/bin/bcp-13.0.1.0 /usr/bin/bcp

Ubuntu 16.04 (ODBC 13)

sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-
release.list
exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql=13.0.1.0-1 mssql-tools=14.0.2.0-1
sudo apt-get install unixodbc-dev-utf16 #this step is optional but recommended*
#Create symlinks for tools
ln -sfn /opt/mssql-tools/bin/sqlcmd-13.0.1.0 /usr/bin/sqlcmd
ln -sfn /opt/mssql-tools/bin/bcp-13.0.1.0 /usr/bin/bcp

SUSE Linux Enterprise Server 12 (ODBC 13)


sudo su
zypper ar https://packages.microsoft.com/config/sles/12/prod.repo
zypper update
sudo ACCEPT_EULA=Y zypper install msodbcsql-13.0.1.0-1 mssql-tools-14.0.2.0-1
zypper install unixODBC-utf16-devel
#Create symlinks for tools
ln -sfn /opt/mssql-tools/bin/sqlcmd-13.0.1.0 /usr/bin/sqlcmd
ln -sfn /opt/mssql-tools/bin/bcp-13.0.1.0 /usr/bin/bcp

Offline installation
If you prefer/require the Microsoft ODBC Driver 13 to be installed on a computer with no internet connection,
you'll need to resolve package dependencies manually. The Microsoft ODBC Driver 13 has the following direct
dependencies:
Ubuntu: libc6 (>= 2.21), libstdc++6 (>= 4.9), libkrb5-3, libcurl3, openssl, debconf (>= 0.5), unixodbc (>=
2.3.1-1)
Red Hat: glibc, e2fsprogs, krb5-libs, openssl, unixODBC
SUSE: glibc, libuuid1, krb5, openssl, unixODBC

Each of these packages in turn has their own dependencies, which may or may not be present on the system.
For a general solution to this issue, refer to your distribution's package manager documentation: Red Hat,
Ubuntu, and SUSE
It's also common to manually download all the dependent packages and place them together on the installation
computer, then manually install each package in turn, finishing with the Microsoft ODBC Driver 13 package.
Red Hat Linux Enterprise Server 7
Download the latest msodbcsql .rpm from https://packages.microsoft.com/rhel/7/prod/.
Install dependencies and the driver.

yum install glibc e2fsprogs krb5-libs openssl unixODBC unixODBC-devel #install dependencies
sudo rpm -i msodbcsql-13.1.X.X-X.x86_64.rpm #install the Driver

Ubuntu 16.04 (ODBC 13 offline)


Download the latest msodbcsql .deb from
https://packages.microsoft.com/ubuntu/16.04/prod/pool/main/m/msodbcsql/.
Install dependencies and the driver.

sudo apt-get install libc6 libstdc++6 libkrb5-3 libcurl3 openssl debconf unixodbc unixodbc-dev #install
dependencies
sudo dpkg -i msodbcsql_13.1.X.X-X_amd64.deb #install the Driver

SUSE Linux Enterprise Server 12 (ODBC 13 offline)


Download the latest msodbcsql .rpm from https://packages.microsoft.com/sles/12/prod/.
Install the dependencies and the driver.

zypper install glibc, libuuid1, krb5, openssl, unixODBC unixODBC-devel #install dependencies
sudo rpm -i msodbcsql-13.1.X.X-X.x86_64.rpm #install the Driver

After you've completed the package installation, you can verify that the Microsoft ODBC Driver 13 can find all its
dependencies by running ldd and inspecting its output for missing libraries:
ldd /opt/microsoft/msodbcsql/lib64/libmsodbcsql-*

ODBC 11
The following sections explain how to install the Microsoft ODBC driver 11 on Linux. Before you can use the
driver, install the unixODBC driver manager. For more information, see Installing the Driver Manager.
Installation Steps

IMPORTANT
These instructions refer to msodbcsql-11.0.2270.0.tar.gz , which is installation file for Red Hat Linux. If you are
installing the Preview for SUSE Linux, the file name is msodbcsql-11.0.2260.0.tar.gz .

To install the driver:


1. Make sure that you have root permission.
2. Change to the directory where the download placed the file msodbcsql-11.0.2270.0.tar.gz . Make sure
that you have the *.tar.gz file that matches your version of Linux. To extract the files, execute the following
command, tar xvzf msodbcsql-11.0.2270.0.tar.gz .
3. Change to the msodbcsql-11.0.2270.0 directory and there you should see a file called install.sh .
4. To see a list of the available installation options, execute the following command: ./install.sh .
5. Make a backup of odbcinst.ini . The driver installation updates odbcinst.ini . odbcinst.ini contains the list
of drivers that are registered with the unixODBC Driver Manager. To discover the location of odbcinst.ini
on your computer, execute the following command: odbc_config --odbcinstini .
6. Before you install the driver, execute the following command: ./install.sh verify . The output of
./install.sh verify reports if your computer has the required software to support the ODBC driver on
Linux.
7. When you're ready to install the ODBC driver on Linux, execute the command: ./install.sh install . If
you need to specify an install command ( bin-dir or lib-dir ), specify the command after the install
option.
8. After reviewing the license agreement, type YES to continue with the installation.
Installation puts the driver in /opt/microsoft/msodbcsql/11.0.2270.0 . The driver and its support files must be in
/opt/microsoft/msodbcsql/11.0.2270.0 .
To verify that the Microsoft ODBC driver on Linux was registered successfully, execute the following command:
odbcinst -q -d -n "ODBC Driver 11 for SQL Server" .

Uninstall
You can uninstall the ODBC driver 11 on Linux by executing the following commands:
1. rm -f /usr/bin/sqlcmd

2. rm -f /usr/bin/bcp

3. rm -rf /opt/microsoft/msodbcsql

4. odbcinst -u -d -n "ODBC Driver 11 for SQL Server"


Driver files
The ODBC driver on Linux consists of the following components:

C O M P O N EN T DESC RIP T IO N

libmsodbcsql-17.X.so.X.X or libmsodbcsql-13.X.so.X.X The shared object ( so ) dynamic library file that contains all
of the driver's functionality. This file is installed in
/opt/microsoft/msodbcsql17/lib64/ for the Driver 17
and in /opt/microsoft/msodbcsql/lib64/ for Driver 13.

msodbcsqlr17.rll or msodbcsqlr13.rll The accompanying resource file for the driver library. This file
is installed in
[driver .so directory]../share/resources/en_US/

msodbcsql.h The header file that contains all of the new definitions
needed to use the driver.

Note: You can't reference msodbcsql.h and odbcss.h in the


same program.

msodbcsql.h is installed in
/opt/microsoft/msodbcsql17/include/ for Driver 17 and
in /opt/microsoft/msodbcsql/include/ for Driver 13.

LICENSE.txt The text file that contains the terms of the End-User License
Agreement. This file is placed in
/usr/share/doc/msodbcsql17/ for Driver 17 and in
/usr/share/doc/msodbcsql/ for Driver 13.

RELEASE_NOTES The text file that contains release notes. This file is placed in
/usr/share/doc/msodbcsql17/ for Driver 17 and in
/usr/share/doc/msodbcsql/ for Driver 13.

Resource file loading


The driver needs to load the resource file to function. This file is called msodbcsqlr17.rll or msodbcsqlr13.rll
depending on the driver version. The location of the .rll file is relative to the location of the driver itself ( so
or dylib ), as noted in the table above. As of version 17.1 the driver will also attempt to load the .rll from the
default directory if loading from the relative path fails. The default resource file path on Linux is
/opt/microsoft/msodbcsql17/share/resources/en_US/ .

Troubleshooting
If you're unable to make a connection to SQL Server using the ODBC driver, see the known issues article on
troubleshooting connection problems.

Next steps
After installing the driver, you can try the C++ ODBC example application. For more information about
developing ODBC applications, see Developing Applications.
For more information, see the ODBC driver release notes and system requirements.
Install the Microsoft ODBC driver for SQL Server
(macOS)
4/27/2022 • 3 minutes to read • Edit Online

This article explains how to install the Microsoft ODBC Driver for SQL Server on macOS. It also includes
instructions for the optional command-line tools for SQL Server ( bcp and sqlcmd ) and the unixODBC
development headers.
This article provides commands for installing the ODBC driver from the bash shell. If you want to download the
packages directly, see Download ODBC Driver for SQL Server.

NOTE
The Microsoft ODBC driver for SQL Server on macOS is only supported on the x64 architecture through version 17.7.
Apple M1 (ARM64) support was added starting with version 17.8. The architecture will be detected and the correct
package will be automatically installed by the Homebrew formula. If your command prompt is running in x64 emulation
mode on the M1, the x64 package will be installed. If you're not running in emulation mode in your command prompt,
the ARM64 package will be installed.

Microsoft ODBC 18
To install Microsoft ODBC driver 18 for SQL Server on macOS, run the following commands:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"


brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew update
HOMEBREW_NO_ENV_FILTERING=1 ACCEPT_EULA=Y brew install msodbcsql18 mssql-tools18

Previous versions
The following sections provide instructions for installing previous versions of the Microsoft ODBC driver on
macOS.

Microsoft ODBC 17
To install Microsoft ODBC driver 17 for SQL Server on macOS, run the following commands:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"


brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew update
HOMEBREW_NO_ENV_FILTERING=1 ACCEPT_EULA=Y brew install msodbcsql17 mssql-tools

IMPORTANT
If you installed the v17 msodbcsql package that was briefly available, you should remove it before installing the
msodbcsql17 package. This will avoid conflicts. The msodbcsql17 package can be installed side by side with the
msodbcsql v13 package.
ODBC 13.1
Use the following commands to install the Microsoft ODBC driver 13.1 for SQL Server on OS X 10.11 (El
Capitan) and macOS 10.12 (Sierra):

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"


brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew update
brew install [email protected] [email protected]

Driver files
The ODBC driver on macOS consists of the following components:

C O M P O N EN T DESC RIP T IO N

libmsodbcsql.17.dylib or libmsodbcsql.13.dylib The dynamic library ( dylib ) file that contains all of the
driver's functionality. This file is installed in
/usr/local/lib/ .

msodbcsqlr17.rll or msodbcsqlr13.rll The accompanying resource file for the driver library. This file
is installed in
[driver .dylib
directory]../share/msodbcsql17/resources/en_US/
for Driver 17 and in
[driver .dylib
directory]../share/msodbcsql/resources/en_US/
for Driver 13.

msodbcsql.h The header file that contains all of the new definitions
needed to use the driver.

Note: You can't reference msodbcsql.h and odbcss.h in the


same program.

msodbcsql.h is installed in
/usr/local/include/msodbcsql17/ for Driver 17 and in
/usr/local/include/msodbcsql/ for Driver 13.

LICENSE.txt The text file that contains the terms of the End-User License
Agreement. This file is placed in
/usr/local/share/doc/msodbcsql17/ for Driver 17 and in
/usr/local/share/doc/msodbcsql/ for Driver 13.

RELEASE_NOTES The text file that contains release notes. This file is placed in
/usr/local/share/doc/msodbcsql17/ for Driver 17 and in
/usr/local/share/doc/msodbcsql/ for Driver 13.

Resource file loading


The driver needs to load the resource file in order to function. This file is called msodbcsqlr17.rll or
msodbcsqlr13.rll depending on the driver version. The location of the .rll file is relative to the location of the
driver itself ( so or dylib ), as noted in the component table. As of version 17.1 the driver will also attempt to
load the .rll from the default directory if loading from the relative path fails. The default resource file path on
macOS is /usr/local/share/msodbcsql17/resources/en_US/
Troubleshooting
Some users encounter an issue when trying to connect after installing the ODBC driver and receive an error like:
"[01000] [unixODBC][Driver Manager]Can't open lib 'ODBC Driver 17 for SQL Server' : file not found (0)
(SQLDriverConnect)"
. It may be the case that unixODBC isn't configured correctly to find registered drivers. In these cases, creating
symbolic links can resolve the issue.

sudo ln -s /usr/local/etc/odbcinst.ini /etc/odbcinst.ini


sudo ln -s /usr/local/etc/odbc.ini /etc/odbc.ini

For additional cases where you're unable to make a connection to SQL Server using the ODBC driver, see the
known issues article on troubleshooting connection problems.
If brew is having trouble finding the formulas, make sure you didn't skip the install step:
brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release

Next steps
After installing the driver, you can try the C++ ODBC example application. For more information about
developing ODBC applications, see Developing Applications.
For more information, see the ODBC driver release notes and system requirements.
Connecting from Linux or macOS
4/27/2022 • 6 minutes to read • Edit Online

Download ODBC Driver


This article discusses how you can create a connection to a SQL Server database.

Connection Properties
See DSN and Connection String Keywords and Attributes for all the connection string keywords and attributes
supported on Linux and macOS.

IMPORTANT
When connecting to a database that uses database mirroring (has a failover partner), do not specify the database name in
the connection string. Instead, send a use database_name command to connect to the database before executing your
queries.

The value passed to the Driver keyword can be one of the following:
The name you used when you installed the driver.
The path to the driver library, which was specified in the template .ini file used to install the driver.
DSNs are optional. You can use a DSN to define connection string keywords under a DSN name that you can
then reference in the connection string. To create a DSN, create (if necessary) and edit the file ~/.odbc.ini (
.odbc.ini in your home directory) for a User DSN only accessible to the current user, or /etc/odbc.ini for a
System DSN (administrative privileges required.) The following odbc.ini is a sample that shows the minimal
required entries for a DSN:

# [DSN name]
[MSSQLTest]
Driver = ODBC Driver 17 for SQL Server
# Server = [protocol:]server[,port]
Server = tcp:localhost,1433
#
# Note:
# Port isn't a valid keyword in the odbc.ini file
# for the Microsoft ODBC driver on Linux or macOS
#

To connect using the above DSN in a connection string, you would specify the DSN keyword like:
DSN=MSSQLTest;UID=my_username;PWD=my_password
The above connection string would be the equivalent of specifying a connection string without the DSN
keyword like: Driver=ODBC Driver 17 for SQL Server;Server=tcp:localhost,1433;UID=my_username;PWD=my_password
You can optionally specify the protocol and port to connect to the server. For example,
Ser ver=tcp:servername,12345 . The only protocol supported by the Linux and macOS drivers is tcp .
To connect to a named instance on a static port, use Ser ver= servername,por t_number . Connecting to a
dynamic port isn't supported before version 17.4.
Alternatively, you can add the DSN information to a template file, and execute the following command to add it
to ~/.odbc.ini :

odbcinst -i -s -f <template_file>

For complete documentation on ini files and odbcinst , see the unixODBC documentation. For entries in the
odbc.ini file specific to the ODBC Driver for SQL Server, see DSN and Connection String Keywords and
Attributes for ones supported on Linux and macOS.
You can verify that your driver is working by using isql to test the connection, or you can use this command:

bcp master.INFORMATION_SCHEMA.TABLES out OutFile.dat -S <server> -U <name> -P <password>

Using TLS/SSL
You can use Transport Layer Security (TLS), previously known as Secure Sockets Layer (SSL), to encrypt
connections to SQL Server. TLS protects SQL Server user names and passwords over the network. TLS also
verifies the identity of the server to protect against man-in-the-middle (MITM) attacks.
Enabling encryption increases security at the expense of performance.
For more information, see Encrypting Connections to SQL Server and Using Encryption Without Validation.
Regardless of the settings for Encr ypt and TrustSer verCer tificate , the server login credentials (user name
and password) are always encrypted. The following tables show the effect of the Encr ypt and
TrustSer verCer tificate settings.
ODBC Driver 18 and newer
SERVER F O RC E
EN C RY P T SET T IN G T RUST SERVER C ERT IF IC AT E EN C RY P T IO N RESULT

No No No Server certificate isn't


checked.
Data sent between client
and server isn't encrypted.

No Yes No Server certificate isn't


checked.
Data sent between client
and server isn't encrypted.

Yes No No Server certificate is checked.


Data sent between client
and server is encrypted.

Yes Yes No Server certificate isn't


checked.
Data sent between client
and server is encrypted.

No No Yes Server certificate is checked.


Data sent between client
and server is encrypted.
SERVER F O RC E
EN C RY P T SET T IN G T RUST SERVER C ERT IF IC AT E EN C RY P T IO N RESULT

No Yes Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.

Yes No Yes Server certificate is checked.


Data sent between client
and server is encrypted.

Yes Yes Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.

Strict - - TrustServerCertificate is
ignored. Server certificate is
checked.
Data sent between client
and server is encrypted.

NOTE
Strict is only available against servers that support TDS 8.0 connections.

ODBC Driver 17 and older


SERVER F O RC E
EN C RY P T SET T IN G T RUST SERVER C ERT IF IC AT E EN C RY P T IO N RESULT

No No No Server certificate isn't


checked.
Data sent between client
and server isn't encrypted.

No Yes No Server certificate isn't


checked.
Data sent between client
and server isn't encrypted.

Yes No No Server certificate is checked.


Data sent between client
and server is encrypted.

Yes Yes No Server certificate isn't


checked.
Data sent between client
and server is encrypted.

No No Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.
SERVER F O RC E
EN C RY P T SET T IN G T RUST SERVER C ERT IF IC AT E EN C RY P T IO N RESULT

No Yes Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.

Yes No Yes Server certificate is checked.


Data sent between client
and server is encrypted.

Yes Yes Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.

When using connection encryption, the name (or IP address) in a Subject Common Name (CN) or Subject
Alternative Name (SAN) in a SQL Server TLS/SSL certificate should exactly match the server name (or IP
address) specified in the connection string.
By default, encrypted connections always verify the server's certificate. However, if you connect to a server that
has a self-signed certificate, and aren't using strict encryption mode, you can add the TrustServerCertificate
option to bypass checking the certificate against the list of trusted certificate authorities:

Driver={ODBC Driver 17 for SQL Server};Server=ServerNameHere;Encrypt=YES;TrustServerCertificate=YES

In strict encryption mode, the certificate is always verified.

TLS on Linux and macOS uses the OpenSSL library. The following table shows the minimum supported versions
of OpenSSL and the default Certificate Trust Store locations for each platform:

DEFA ULT C ERT IF IC AT E T RUST STO RE


P L AT F O RM M IN IM UM O P EN SSL VERSIO N LO C AT IO N

Debian 10 1.1.1 /etc/ssl/certs

Debian 9 1.1.0 /etc/ssl/certs

Debian 8.71 1.0.1 /etc/ssl/certs

OS X 10.11, macOS 1.0.2 /usr/local/etc/openssl/certs

Red Hat Enterprise Linux 8 1.1.1 /etc/pki/tls/cert.pem

Red Hat Enterprise Linux 7 1.0.1 /etc/pki/tls/cert.pem

Red Hat Enterprise Linux 6 1.0.0-10 /etc/pki/tls/cert.pem

SUSE Linux Enterprise 15 1.1.0 /etc/ssl/certs

SUSE Linux Enterprise 11, 12 1.0.1 /etc/ssl/certs

Ubuntu 20.04, 21.04, 21.10 1.1.1 /etc/ssl/certs


DEFA ULT C ERT IF IC AT E T RUST STO RE
P L AT F O RM M IN IM UM O P EN SSL VERSIO N LO C AT IO N

Ubuntu 18.04 1.1.0 /etc/ssl/certs

Ubuntu 16.04, 16.10, 17.10 1.0.2 /etc/ssl/certs

Ubuntu 14.04 1.0.1 /etc/ssl/certs

You can also specify encryption in the connection string using the Encrypt option when using
SQLDriverConnect to connect.

Adjusting the TCP Keep-Alive Settings


Starting with ODBC Driver 17.4, how often the driver sends keep-alive packets and retransmits them when a
response isn't received is configurable. To configure, add the following settings to either the driver's section in
odbcinst.ini , or the DSN's section in odbc.ini . When connecting with a DSN, the driver will use the settings in
the DSN's section if present; otherwise, or if connecting with a connection string only, it will use the settings in
the driver's section in odbcinst.ini . If the setting isn't present in either location, the driver uses the default
value. Beginning with ODBC Driver 17.8, KeepAlive and KeepAliveInterval keywords can be specified in the
connection string.
KeepAlive=<integer> controls how often TCP attempts to verify that an idle connection is still intact by
sending a keep-alive packet. The default is 30 seconds.
KeepAliveInterval=<integer> determines the interval separating keep-alive retransmissions until a
response is received. The default is 1 second.

See Also
Installing the Microsoft ODBC Driver for SQL Server on Linux
Installing the Microsoft ODBC Driver for SQL Server on macOS
Programming Guidelines
Data access tracing on Linux and macOS
4/27/2022 • 2 minutes to read • Edit Online

Download ODBC Driver


The unixODBC Driver Manager on macOS and Linux supports tracing of ODBC API call entry and exit of the
ODBC Driver for SQL Server.
To trace your application's ODBC behavior, edit the [ODBC] section of the odbcinst.ini file. Set the values
Trace=Yes and TraceFile to the path of the file that will contain the trace output. For example:

[ODBC]
Trace=Yes
TraceFile=/home/myappuser/odbctrace.log

You can also use /dev/stdout or any other device name to send trace output there, instead of to a persistent file.
With the preceding settings, every time an application loads the unixODBC Driver Manager, it records all ODBC
API calls made, into the output file.
After you finish tracing your application, remove Trace=Yes from the odbcinst.ini file to avoid the
performance penalty of tracing, and ensure that any unnecessary trace files are removed.
Tracing applies to all applications that use the driver in odbcinst.ini . To not trace all applications (for example,
to avoid disclosing sensitive per-user information), you can trace an individual application instance. Provide the
instance the location of a private odbcinst.ini , by using the ODBCSYSINI environment variable. For example:

$ ODBCSYSINI=/home/myappuser myapp

In this case, you can add Trace=Yes to the [ODBC Driver 17 for SQL Server] section of
/home/myappuser/odbcinst.ini .

Determine which file the driver is using


The Linux and macOS ODBC drivers don't know which odbc.ini file is in use, or the path to the odbc.ini file.
Information about which odbc.ini file is in use is available from the unixODBC tools odbc_config and
odbcinst . You can also get this information from the unixODBC Driver Manager documentation.

For example, the following command prints the location of system and user odbc.ini files that contain,
respectively, system and user data source names (DSNs):

$ odbcinst -j
unixODBC 2.3.1
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /home/odbcuser/.odbc.ini`
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8

User DSNs are only available to a specific user. User DSNs are stored in a file in the user's home directory, or a
subdirectory. System DSNs are available for every user on the system, but can only be added, modified, and
removed by a system administrator. If a user has a user DSN with the same name as a system DSN, the user
DSN will be used upon connections by that user. For more information, see the unixODBC documentation.

See also
Programming guidelines
High availability and disaster recovery on Linux and
macOS
4/27/2022 • 5 minutes to read • Edit Online

Download ODBC Driver


The ODBC drivers for Linux and macOS support Always On availability groups. For more information about
Always On availability groups, see:
Availability group listeners, client connectivity, and application failover (SQL Server)
Creation and configuration of availability groups (SQL Server)
Failover clustering and Always On availability groups (SQL Server)
Active secondaries: Readable secondary replicas (Always On availability groups)
You can specify the availability group listener of a particular availability group in the connection string. If an
ODBC application on Linux or macOS is connected to a database in an availability group that fails over, the
original connection is broken. The application must open a new connection to continue work after the failover.
The ODBC drivers on Linux and macOS iterate sequentially through all IP addresses associated with a DNS
hostname, if you aren't connecting to an availability group listener. If the DNS server's first returned IP address
isn't connectable, these iterations can be time consuming.
When you're connecting to an availability group listener, the driver attempts to establish connections to all IP
addresses in parallel. If a connection attempt succeeds, the driver discards any pending connection attempts.

NOTE
Because a connection can fail due to an availability group failover, you should implement connection retry logic. Retry a
failed connection until it reconnects. Increasing the connection timeout and implementing connection retry logic increases
the chance of connecting to an availability group.

Connect with MultiSubnetFailover


Always specify MultiSubnetFailover=Yes when you're connecting to a SQL Server 2012 (11.x) availability group
listener or SQL Server 2012 (11.x) failover cluster instance. MultiSubnetFailover enables faster failover for all
availability groups and failover cluster instances in SQL Server 2012 (11.x).
This connection property also significantly reduces failover time for single and multi-subnet Always On
topologies. During a multi-subnet failover, the client attempts connections in parallel. During a subnet failover,
the driver aggressively retries the TCP connection.
The MultiSubnetFailover connection property indicates that the application is being deployed in an availability
group or failover cluster instance. The driver tries to connect to the database on the primary SQL Server
instance by trying to connect to all the IP addresses.
When you connect with MultiSubnetFailover=Yes , the client retries TCP connection attempts faster than the
operating system's default TCP retransmit intervals. MultiSubnetFailover=Yes enables faster reconnection after
failover of either an Always On availability group, or an Always On failover cluster instance.
MultiSubnetFailover=Yes applies to both single- and multi-subnet availability groups and failover cluster
instances.
Use MultiSubnetFailover=Yes when you're connecting to an availability group listener or failover cluster
instance. Otherwise, your application's performance can be negatively affected.
Recommendations
When you're connecting to a server in an availability group or failover cluster instance:
Specify MultiSubnetFailover=Yes to improve performance when you're connecting to a single subnet or
multi-subnet availability group.
Specify the availability group listener of the availability group as the server in your connection string.
You can't connect to a SQL Server instance configured with more than 64 IP addresses.
Both SQL Server Authentication or Kerberos Authentication can be used with MultiSubnetFailover=Yes ,
without affecting the behavior of the application.
You can increase the value of loginTimeout to accommodate for failover time and reduce the
application's connection retry attempts.
Distributed transactions aren't supported.
If read-only routing isn't in effect, connecting to a secondary replica location in an availability group fails in the
following situations:
If the secondary replica location isn't configured to accept connections.
If an application uses ApplicationIntent=ReadWrite and the secondary replica location is configured for
read-only access.
A connection fails if a primary replica is configured to reject read-only workloads, and the connection string
contains ApplicationIntent=ReadOnly .

Specify application intent


You can specify the keyword ApplicationIntent in your connection string. The assignable values are ReadWrite
(the default) or ReadOnly .
When you set ApplicationIntent=ReadOnly , the client requests a read workload when connecting. The server
enforces the intent at connection time, and during a USE database statement.
The ApplicationIntent keyword doesn't work with legacy read-only databases.
Targets of ReadOnly
When a connection chooses ReadOnly , the connection is assigned to any of the following special configurations
that might exist for the database:
Always On. A database can allow or disallow read workloads on the targeted availability group database.
This choice is controlled by using the ALLOW_CONNECTIONS clause of the PRIMARY_ROLE and SECONDARY_ROLE
Transact-SQL statements.
Geo-replication
Read scale-out
If none of those special targets are available, the regular database is read from.
The ApplicationIntent keyword enables read-only routing.
Read-only routing
Read-only routing is a feature that can ensure the availability of a read-only replica of a database. To enable
read-only routing, all of the following apply:
You must connect to an Always On availability group listener.
The ApplicationIntent connection string keyword must be set to ReadOnly .
The database administrator must configure the availability group to enable read-only routing.
Multiple connections that each use read-only routing might not all connect to the same read-only replica.
Changes in database synchronization or changes in the server's routing configuration can result in client
connections to different read-only replicas.
You can ensure that all read-only requests connect to the same read-only replica by not passing an availability
group listener to the Server connection string keyword. Instead, specify the name of the read-only instance.
Read-only routing might take longer than connecting to the primary. This is because read-only routing first
connects to the primary, and then looks for the best available readable secondary. Due to these multiple steps,
you should increase your login timeout to at least 30 seconds.

ODBC syntax
Two ODBC connection string keywords support Always On availability groups:
ApplicationIntent

MultiSubnetFailover

For more information about ODBC connection string keywords, see Using connection string keywords with SQL
Server Native Client.
The equivalent connection attributes are:
SQL_COPT_SS_APPLICATION_INTENT

SQL_COPT_SS_MULTISUBNET_FAILOVER

For more information about ODBC connection attributes, see SQLSetConnectAttr.


An ODBC application that uses Always On availability groups can use one of two functions to make the
connection:

F UN C T IO N DESC RIP T IO N

SQLConnect Function SQLConnect supports both ApplicationIntent and


MultiSubnetFailover via a data source name (DSN) or
connection attribute.

SQLDriverConnect Function SQLDriverConnect supports ApplicationIntent and


MultiSubnetFailover via DSN, connection string keyword,
or connection attribute.

See also
Connection string keywords and data source names (DSNs)
Programming guidelines
Release notes
Programming Guidelines
4/27/2022 • 7 minutes to read • Edit Online

Download ODBC Driver


The programming features of the Microsoft ODBC Driver for SQL Server on macOS and Linux are based on
ODBC in SQL Server Native Client (SQL Server Native Client (ODBC)). SQL Server Native Client is based on
ODBC in Windows Data Access Components (ODBC Programmer's Reference).
An ODBC application can use Multiple Active Result Sets (MARS) and other SQL Server specific features by
including /usr/local/include/msodbcsql.h after including the unixODBC headers ( sql.h , sqlext.h , sqltypes.h
, and sqlucode.h ). Then use the same symbolic names for SQL Server-specific items that you would use in your
Windows ODBC applications.

Available Features
The following sections from the SQL Server Native Client documentation for ODBC (SQL Server Native Client
(ODBC)) are valid when using the ODBC driver on macOS and Linux:
Communicating with SQL Server (ODBC)
Connection and query timeout support
Cursors
Date/Time Improvements (ODBC)
Executing Queries (ODBC)
Handling Errors and Messages
Kerberos authentication
Large CLR User-Defined Types (ODBC)
Performing Transactions (ODBC) (except distributed transactions)
Processing Results (ODBC)
Running Stored Procedures
Sparse Columns Support (ODBC)
Using Encryption Without Validation
Table Valued Parameters
UTF-8 and UTF-16 for command and data API
Using Catalog Functions

Unsupported Features
The following features haven't been verified to work correctly in the ODBC driver on macOS and Linux:
Failover Cluster Connection
Transparent Network IP Resolution (before ODBC Driver 17)
Linux and macOS ODBC Driver BID Tracing (before ODBC Driver 17.3)
The following features aren't available in the ODBC driver on macOS and Linux:
Distributed Transactions (SQL_ATTR_ENLIST_IN_DTC attribute isn't supported)
Database Mirroring
FILESTREAM
Profiling ODBC driver performance, discussed in SQLSetConnectAttr, and the following performance-related
connection attributes:
SQL_COPT_SS_PERF_DATA
SQL_COPT_SS_PERF_DATA_LOG
SQL_COPT_SS_PERF_DATA_LOG_NOW
SQL_COPT_SS_PERF_QUERY
SQL_COPT_SS_PERF_QUERY_INTERVAL
SQL_COPT_SS_PERF_QUERY_LOG
SQLBrowseConnect (before version 17.2)
C interval types such as SQL_C_INTERVAL_YEAR_TO_MONTH (documented in Data Type Identifiers and
Descriptors)
The SQL_CUR_USE_ODBC value of the SQL_ATTR_ODBC_CURSORS attribute of the SQLSetConnectAttr
function.

Character Set Support


For ODBC Driver 13 and 13.1, SQLCHAR data must be UTF-8. No other encodings are supported.
For ODBC Driver 17, SQLCHAR data in one of the following character sets/encodings is supported:

NOTE
Due to iconv differences in musl and glibc many of these locales are not supported on Alpine Linux.
For more information, see Functional differences from glibc

NAME DESC RIP T IO N

UTF-8 Unicode

CP437 MS-DOS Latin US

CP850 MS-DOS Latin 1

CP874 Latin/Thai

CP932 Japanese, Shift-JIS

CP936 Simplified Chinese, GBK

CP949 Korean, EUC-KR

CP950 Traditional Chinese, Big5

CP1251 Cyrillic

CP1253 Greek

CP1256 Arabic

CP1257 Baltic
NAME DESC RIP T IO N

CP1258 Vietnamese

ISO-8859-1 / CP1252 Latin-1

ISO-8859-2 / CP1250 Latin-2

ISO-8859-3 Latin-3

ISO-8859-4 Latin-4

ISO-8859-5 Latin/Cyrillic

ISO-8859-6 Latin/Arabic

ISO-8859-7 Latin/Greek

ISO-8859-8 / CP1255 Hebrew

ISO-8859-9 / CP1254 Turkish

ISO-8859-13 Latin-7

ISO-8859-15 Latin-9

Upon connection, the driver detects the current locale of the process it's loaded in. If it uses one of the encodings
above, the driver uses that encoding for SQLCHAR (narrow-character) data; otherwise, it defaults to UTF-8. Since
all processes start in the "C" locale by default (and cause the driver to default to UTF-8), if an application needs
to use one of the encodings above, it should use the setlocale function to set the locale appropriately before
connecting; either by specifying the locale explicitly, or using an empty string for example
setlocale(LC_ALL, "") to use the locale settings of the environment.

Therefore, in a typical Linux or macOS environment where the encoding is UTF-8, users of ODBC Driver 17
upgrading from 13 or 13.1 won't observe any differences. However, applications that use a non-UTF-8 encoding
in the above list via setlocale() need to use that encoding for data to/from the driver instead of UTF-8.
SQLWCHAR data must be UTF-16LE (Little Endian).
When binding input parameters with SQLBindParameter, if a narrow character SQL type such as SQL_VARCHAR
is specified, the driver converts the supplied data from the client encoding to the default (typically codepage
1252) SQL Server encoding. For output parameters, the driver converts from the encoding specified in the
collation information associated with the data to the client encoding. However, data loss is possible ---
characters in the source encoding not representable in the target encoding will convert to a question mark ('?').
To avoid this data loss when binding input parameters, specify a Unicode SQL character type such as
SQL_NVARCHAR. In this case, the driver converts from the client encoding to UTF-16, which can represent all
Unicode characters. Furthermore, the target column or parameter on the server must also be either a Unicode
type (nchar , nvarchar , ntext ) or one with a collation/encoding, which can represent all the characters of the
original source data. For avoiding data loss with output parameters, specify a Unicode SQL type, and either a
Unicode C type (SQL_C_WCHAR), causing the driver to return data as UTF-16, or a narrow C type, and ensure
that the client encoding can represent all the characters of the source data (this representation is always possible
with UTF-8.)
For more information about collations and encodings, see Collation and Unicode Support.
There are some encoding conversion differences between Windows and several versions of the iconv library on
Linux and macOS. Text data in codepage 1255 (Hebrew) has one code point (0xCA) that behaves differently
upon conversion to Unicode. On Windows, this character converts to the UTF-16 code point of 0x05BA. On
macOS and Linux with libiconv versions earlier than 1.15, it converts to 0x00CA. On Linux with iconv libraries
that don't support the 2003 revision of Big5/CP950 (named BIG5-2003 ), characters added with that revision
won't convert correctly. In codepage 932 (Japanese, Shift-JIS), the result of decoding of characters not originally
defined in the encoding standard also differs. For example, the byte 0x80 converts to U+0080 on Windows but
may become U+30FB on Linux and macOS, depending on iconv version.
In ODBC Driver 13 and 13.1, when UTF-8 multibyte characters or UTF-16 surrogates are split across SQLPutData
buffers, it results in data corruption. Use buffers for streaming SQLPutData that don't end in partial character
encodings. This limitation has been removed with ODBC Driver 17.

OpenSSL
Starting with version 17.4, the driver loads OpenSSL dynamically, which allows it to run on systems that have
either version 1.0 or 1.1 without a need for separate driver files. Starting with version 17.9, the driver supports
OpenSSL 3.0 in addition to the previous versions. When multiple versions of OpenSSL are present, the driver
will attempt to load the latest one.

DRIVER VERSIO N SUP P O RT ED O P EN SSL VERSIO N S

17.4+ 1.0, 1.1

17.9, 18.0+ 1.0, 1.1, 3.0

NOTE
A potential conflict may occur if the application that uses the driver (or one of its components) is linked with or
dynamically loads a different version of OpenSSL. If several versions of OpenSSL are present on the system and the
application uses it, it is highly recommended that one be extra careful in making sure that the version loaded by the
application and the driver do not mismatch, as the errors could corrupt memory and thus will not necessarily manifest in
obvious or consistent ways.

Alpine Linux
At the time of this writing the default stack size in MUSL is 128K, which is enough for basic ODBC driver
functionality, however depending on what the application does it isn't difficult to exceed this limit, especially
when calling the driver from multiple threads. It's recommended that an ODBC application on Alpine Linux is
compiled with -Wl,-z,stack-size=<VALUE IN BYTES> to increase the stack size. For reference, the default stack size
on most GLIBC systems is 2MB.

Additional Notes
You can make a dedicated administrator connection (DAC) using SQL Server authentication and
host,por t . A member of the Sysadmin role first needs to discover the DAC port. See Diagnostic
Connection for Database Administrators to discover how. For example, if the DAC port were 33000, you
could connect to it with sqlcmd as follows:

sqlcmd -U <user> -P <pwd> -S <host>,33000


NOTE
DAC connections must use SQL Server Authentication.

The UnixODBC driver manager returns "invalid attribute/option identifier" for all statement attributes
when they're passed through SQLSetConnectAttr. On Windows, when SQLSetConnectAttr receives a
statement attribute value, it causes the driver to set that value on all active statements, which are children
of the connection handle.
When using the driver with highly multithreaded applications, unixODBC's handle validation may become
a performance bottleneck. In such scenarios, higher performance may be obtained by compiling
unixODBC with the --enable-fastvalidate option. However, beware that this option may cause
applications that pass invalid handles to ODBC APIs to crash instead of returning SQL_INVALID_HANDLE
errors.

See Also
Frequently Asked Questions
Known Issues in this Version of the Driver
Release Notes
Connecting with bcp
4/27/2022 • 5 minutes to read • Edit Online

Download ODBC Driver


The bcp utility is available with the Microsoft ODBC Driver for SQL Server on Linux and macOS. This page
documents the differences from the Windows version of bcp.
The field terminator is a tab ("\t").
The line terminator is a newline ("\n").
Character mode is the preferred format for bcp format files and data files that don't contain extended
characters.

NOTE
A backslash '\' on a command-line argument must either be quoted or escaped. For example, to specify a newline as a
custom row terminator, you must use one of the following mechanisms:
-r\\n
-r"\n"
-r'\n'

The following example is a command invocation of bcp to copy table rows to a text file:

bcp AdventureWorks2008R2.Person.Address out test.dat -Usa -Pxxxx -Sxxx.xxx.xxx.xxx

Available options
In the current release, the following syntax and options are available:
[database.]schema.table in data_file | out data_file
-a packet_size
Specifies the number of bytes, per network packet, sent to and from the server.
-b batch_size
Specifies the number of rows per batch of imported data.
-c
Uses a character data type.
-d database_name
Specifies the database to connect to.
-D
Causes the value passed to the bcp -S option to be interpreted as a data source name (DSN). For more
information, see "DSN Support in sqlcmd and bcp" in Connecting with sqlcmd.
-e error_file
Specifies the full path of an error file used to store any rows that the bcp utility can't transfer from the file to
the database.
-E
Uses an identity value or values in the imported data file for the identity column.
-f format_file
Specifies the full path of a format file.
-F first_row
Specifies the number of the first row to export from a table or import from a data file.
-G
This switch is used by the client when connecting to Azure SQL Database or Azure Synapse Analytics to specify
that the user be authenticated using Azure Active Directory authentication. It can be combined with just the -P
option to use access token authentication (v17.8+). The -G switch requires at least bcp version 17.6. To
determine your version, execute bcp -v.

IMPORTANT
The -G option only applies to Azure SQL Database and Azure Synapse Analytics. AAD Interactive Authentication is not
currently supported on Linux or macOS. AAD Integrated Authentication requires Microsoft ODBC Driver 17 for SQL
Server version 17.6.1 or higher and a properly configured Kerberos environment.

-k
Specifies that empty columns should keep a null value during the operation, rather than have any default values
for the columns inserted.
-l
Specifies a login timeout. The -l option specifies the number of seconds before a login to SQL Server times out
when you try to connect to a server. The default login timeout is 15 seconds. The login timeout must be a
number between 0 and 65534. If the value supplied isn't numeric or doesn't fall into that range, bcp generates
an error message. A value of 0 specifies an infinite timeout.
-L last_row
Specifies the number of the last row to export from a table or import from a data file.
-m max_errors
Specifies the maximum number of syntax errors that can occur before the bcp operation is canceled.
-n
Uses the native (database) data types of the data to do the bulk-copy operation.
-P password
Specifies the password for the login ID. When used with the -G option without -U, specifies a file that contains an
access token (v17.8+). The token file should be in UTF-16LE (no BOM) format.
Access tokens can be obtained via various methods. It's important to ensure the access token is correct byte-for-
byte, as it will be sent as-is. Below is an example command that obtains an access token. The command uses the
Azure CLI and Linux commands and saves it to a file in the proper format. If your system or terminal's default
encoding isn't ASCII or UTF-8, you may need to adjust the iconv options. Be sure to carefully secure the
resulting file and delete it when it's no longer required.

az account get-access-token --resource https://database.windows.net --output tsv | cut -f 1 | tr -d '\n' |


iconv -f ascii -t UTF-16LE > /tmp/tokenFile

-q
Executes the SET QUOTED_IDENTIFIERS ON statement in the connection between the bcp utility and an
instance of SQL Server.
-r row_terminator
Specifies the row terminator.
-R
Specifies that currency, date, and time data is bulk copied into SQL Server using the regional format defined for
the locale setting of the client computer.
-S server
Specifies the name of the SQL Server instance to connect to, or if -D is used, a DSN.
-t field_terminator
Specifies the field terminator.
-T
Specifies that the bcp utility connect to SQL Server with a trusted connection (integrated security).
-u
Trust server certificate. (available since bcp version 18)
-U login_id
Specifies the login ID used to connect to SQL Server.
-v
Reports the bcp utility version number and copyright.
-w
Uses Unicode characters to do the bulk copy operation.
In this release, Latin-1 and UTF-16 characters are supported.
-Y [s|m|o]
Specifies the connection encryption mode. The options are Strict, Mandatory, and Optional. Using -Y without any
parameters uses the Mandatory encryption mode, and is equivalent to -Ym. (available since bcp version 18)

Unavailable options
In the current release, the following syntax and options aren't available:
-C
Specifies the code page of the data in the data file.
-h hint
Specifies the hint or hints used during a bulk import of data into a table or view.
-i input_file
Specifies the name of a response file.
-N
Uses the native (database) data types of the data for noncharacter data, and Unicode characters for character
data.
-o output_file
Specifies the name of a file that receives output redirected from the command prompt.
-V (80 | 90 | 100)
Uses data types from an earlier version of SQL Server.
-x
Used with the format and -f format_file options, generates an XML-based format file instead of the default non-
XML format file.

See also
Connecting with sqlcmd
Release notes
Connecting with sqlcmd
4/27/2022 • 7 minutes to read • Edit Online

Download ODBC Driver


The sqlcmd utility is available with the Microsoft ODBC Driver for SQL Server on Linux and macOS.
The following commands show how to use Windows Authentication (Kerberos) and SQL Server Authentication,
respectively:

sqlcmd -E -Sxxx.xxx.xxx.xxx
sqlcmd -Sxxx.xxx.xxx.xxx -Uxxx -Pxxx

Available options
The following options are available in sqlcmd on Linux and macOS:
-?
Display sqlcmd usage.
-a
Request a packet size.
-b
Terminate batch job if there's an error.
-c batch_terminator
Specify the batch terminator.
-C
Trust server certificate.
-d database_name
Issue a USE database_name statement when you start sqlcmd .
-D
Causes the value passed to the sqlcmd -S option to be interpreted as a data source name (DSN). For more
information, see "DSN Support in sqlcmd and bcp " at the end of this article.
-e
Write input scripts to the standard output device (stdout).
-E
Use trusted connection (integrated authentication.) For more information about making trusted connections that
use integrated authentication from a Linux or macOS client, see Using Integrated Authentication.
-f codepage | i:codepage[,o:codepage] | o:codepage[,i:codepage]
Specifies the input and output code pages. The codepage number is a numeric value that specifies an installed
Linux code page. (available since 17.5.1.1)
-G
This switch is used by the client when connecting to SQL Database or Azure Synapse Analytics to specify that the
user be authenticated using Azure Active Directory authentication. It can be combined with just the -P option to
use access token authentication (v17.8+). This option sets the sqlcmd scripting variable SQLCMDUSEAAD = true.
The -G switch requires at least sqlcmd version 17.6. To determine your version, execute sqlcmd -? .

IMPORTANT
The -G option only applies to Azure SQL Database and Azure Synapse Analytics. AAD Interactive Authentication isn't
currently supported on Linux or macOS. AAD Integrated Authentication requires Microsoft ODBC Driver 17 for SQL
Server version 17.6.1 or higher and a properly configured Kerberos environment.

-h number_of_rows
Specify the number of rows to print between the column headings.
-H
Specify a workstation name.
-i input_file[,input_file[,...]]
Identify the file that contains a batch of SQL statements or stored procedures.
-I
Set the SET QUOTED_IDENTIFIER connection option to ON.
-k
Remove or replace control characters.
-K application_intent
Declares the application workload type when connecting to a server. The only currently supported value is
ReadOnly . If -K isn't specified, sqlcmd doesn't support connectivity to a secondary replica in an AlwaysOn
availability group. For more information, see ODBC Driver on Linux and macOS - High Availability and Disaster
Recovery.

NOTE
-K isn't supported in the CTP for SUSE Linux. You can, however, specify the ApplicationIntent=ReadOnly keyword in a
DSN file passed to sqlcmd . For more information, see "DSN Support in sqlcmd and bcp " at the end of this article.

-l timeout
Specify the number of seconds before a sqlcmd login times out when you try to connect to a server.
-m error_level
Control which error messages are sent to stdout.
-M multisubnet_failover
Always specify -M when connecting to the availability group listener of a SQL Server 2012 (11.x) availability
group or a SQL Server 2012 (11.x) Failover Cluster Instance. -M provides for faster detection of failovers and
connection to the (currently) active server. If -M isn't specified, -M is off. For more information about Always On
Availability Groups, see ODBC Driver on Linux and macOS - High Availability and Disaster Recovery.

NOTE
-M isn't supported in the CTP for SUSE Linux. You can, however, specify the MultiSubnetFailover=Yes keyword in a
DSN file passed to sqlcmd . For more information, see "DSN Support in sqlcmd and bcp " at the end of this article.

-N [s|m|o]
Set the connection encryption mode to be Strict, Mandatory, or Optional respectively. Defaults to mandatory if
not specified. ( [s|m|o] added in ODBC 18.0)
-o output_file
Identify the file that receives output from sqlcmd .
-p
Print performance statistics for every result set.
-P
Specify a user password. When used with the -G option without -U, specifies a file that contains an access token
(v17.8+). The token file should be in UTF-16LE (no BOM) format.
Access tokens can be obtained via various methods. It's important to ensure the access token is correct byte-for-
byte, as it will be sent as-is. Below is an example command that obtains an access token. The command uses the
Azure CLI and Linux commands and saves it to a file in the proper format. If your system or terminal's default
encoding isn't ASCII or UTF-8, you may need to adjust the iconv options. Be sure to carefully secure the
resulting file and delete it when it's no longer required.

az account get-access-token --resource https://database.windows.net --output tsv | cut -f 1 | tr -d '\n' |


iconv -f ascii -t UTF-16LE > /tmp/tokenFile

-q commandline_query
Execute a query when sqlcmd starts, but doesn't exit when the query has finished running.
-Q commandline_query
Execute a query when sqlcmd starts. sqlcmd will exit when the query finishes.
-r
Redirects error messages to stderr.
-R
Causes the driver to use client regional settings to convert currency and date and time data to character data.
Currently only uses en_US (US English) formatting.
-s column_separator_char
Specify the column-separator character.
-S [protocol:] server[,port]
Specify the instance of SQL Server to connect to, or if -D is used, a DSN. The ODBC driver on Linux and macOS
requires -S. The only valid protocol value is tcp .
-t query_timeout
Specify the number of seconds before a command (or SQL statement) times out.
-u
Specify that output_file is stored in Unicode format, whatever the format of input_file.
-U
login_id Specify a user login ID.
-V error_severity_level
Control the severity level that is used to set the ERRORLEVEL variable.
-w column_width
Specify the screen width for output.
-W
Remove trailing spaces from a column.
-x
Disable variable substitution.
-X
Disable commands, startup script, and environment variables.
-y variable_length_type_display_width
Set the sqlcmd scripting variable SQLCMDMAXFIXEDTYPEWIDTH .
-Y fixed_length_type_display_width
Set the sqlcmd scripting variable SQLCMDMAXVARTYPEWIDTH .
-z password
Change password.
-Z password
Change password and exit.

Available commands
In the current release, the following commands are available:
[:]!!
:Connect
:Error
[:]EXIT
GO [ count ]
:Help
:List
:Listvar
:On Error
:Out
:Perftrace
[:]QUIT
:r
:RESET
:setvar

Unavailable options
In the current release, the following options aren't available:
-A
Log in to SQL Server with a Dedicated Administrator Connection (DAC). For information on how to make a
dedicated administrator connection (DAC), see Programming Guidelines.
-L
List the locally configured server computers, and the names of the server computers that are broadcasting on
the network.
-v
Create a sqlcmd scripting variable that can be used in a sqlcmd script.
You can use the following alternative method: Put the parameters inside one file, which you can then append to
another file. This method will help you use a parameter file to replace the values. For example, create a file called
a.sql (the parameter file) with the following content:

:setvar ColumnName object_id


:setvar TableName sys.objects

Then create a file called b.sql , with the parameters for replacement:

select $(ColumnName) from $(TableName)

At the command line, combine a.sql and b.sql into c.sql using the following commands:

cat a.sql > c.sql

cat b.sql >> c.sql

Run sqlcmd and use c.sql as input file:

sqlcmd -S<...> -P<..> -U<..> -I c.sql

Unavailable commands
In the current release, the following commands aren't available:
:ED
:Ser verList
:XML

DSN support in sqlcmd and bcp


You can specify a data source name (DSN) instead of a server name in the sqlcmd or bcp -S option (or
sqlcmd :Connect command) if you specify -D . -D causes sqlcmd or bcp to connect to the server specified in
the DSN by the -S option.
System DSNs are stored in the odbc.ini file in the ODBC SysConfigDir directory ( /etc/odbc.ini on standard
installations). User DSNs are stored in .odbc.ini in a user's home directory ( ~/.odbc.ini ).
On Windows systems, System and User DSNs are stored in the registry and managed via odbcad32.exe. File
DSNs aren't supported by bcp and sqlcmd.
See DSN and Connection String Keywords and Attributes for the list of entries that the driver supports.
In a DSN, only the DRIVER entry is required, but to connect to a remote server, sqlcmd or bcp needs a value in
the SERVER element. If the SERVER element is empty or not present in the DSN, sqlcmd and bcp will attempt
to connect to the default instance on the local system.
When using bcp on Windows systems, SQL Server 2017 (14.x) and earlier require the SQL Native Client 11
driver (sqlncli11.dll) while SQL Server 2019 (15.x) and higher require the Microsoft ODBC Driver 17 for SQL
Server driver (msodbcsql17.dll).
If the same option is specified in both the DSN and the sqlcmd or bcp command line, the command line option
overrides the value used in the DSN. For example, if the DSN has a DATABASE entry and the sqlcmd command
line includes -d , the value passed to -d is used. If Trusted_Connection=yes is specified in the DSN, Kerberos
authentication is used and user name (-U ) and password (-P ), if provided, are ignored.
Existing scripts that invoke isql can be modified to use sqlcmd by defining the following alias:
alias isql="sqlcmd -D" .

See also
Connecting with bcp
Release notes
Using Integrated Authentication
4/27/2022 • 5 minutes to read • Edit Online

Download ODBC Driver


The Microsoft ODBC Driver for SQL Server on Linux and macOS supports connections that use Kerberos
integrated authentication. It supports the MIT Kerberos Key Distribution Center (KDC), and works with Generic
Security Services Application Program Interface (GSSAPI) and Kerberos v5 libraries.
As of version 17.6, the driver also supports integrated authentication with Azure Active Directory using a
federated account, system library limitations notwithstanding. See Using Azure Active Directory for more
information.

Using Integrated Authentication to Connect to SQL Server from an


ODBC Application
You can enable Kerberos integrated authentication by specifying Trusted_Connection=yes in the connection
string of SQLDriverConnect or SQLConnect . For example:

Driver='ODBC Driver 17 for SQL Server';Server=your_server;Trusted_Connection=yes

When connecting with a DSN, you can also add Trusted_Connection=yes to the DSN entry in odbc.ini .
The -E option of sqlcmd and the -T option of bcp can also be used to specify integrated authentication; see
Connecting with sqlcmd and Connecting with bcp for more information.
Ensure that the client principal which is going to connect to SQL Server is already authenticated with the
Kerberos KDC.
Ser verSPN and FailoverPar tnerSPN are not supported.

Deploying a Linux or macOS ODBC Driver Application Designed to


Run as a Service
A system administrator can deploy an application to run as a service that uses Kerberos Authentication to
connect to SQL Server.
You first need to configure Kerberos on the client and then ensure that the application can use the Kerberos
credential of the default principal.
Ensure that you use kinit or PAM (Pluggable Authentication Module) to obtain and cache the TGT for the
principal that the connection uses, via one of the following methods:
Run kinit , passing in a principal name and password.
Run kinit , passing in a principal name and a location of a keytab file that contains the principal's key
created by ktutil .
Ensure that the login to the system was done using the Kerberos PAM (Pluggable Authentication Module).
When an application runs as a service, because Kerberos credentials expire by design, renew the credentials to
ensure continued service availability. The ODBC driver does not renew credentials itself; ensure that there is a
cron job or script that periodically runs to renew the credentials before their expiration. To avoid requiring the
password for each renewal, you can use a keytab file.
Kerberos Configuration and Use provides details on ways to Kerberize services on Linux.

Tracking Access to a Database


A database administrator can create an audit trail of access to a database when using system accounts to access
SQL Server using Integrated Authentication.
Logging in to SQL Server uses the system account and there is no functionality on Linux to impersonate security
context. Therefore, more is required to determine the user.
To audit activities in SQL Server on behalf of users other than the system account, the application must use
Transact-SQL EXECUTE AS .
To improve application performance, an application can use connection pooling with Integrated Authentication
and auditing. However, combining connection pooling, Integrated Authentication, and auditing creates a security
risk because the unixODBC driver manager permits different users to reuse pooled connections. For more
information, see ODBC Connection Pooling.
Before reuse, an application must reset pooled connections by executing sp_reset_connection .

Using Active Directory to Manage User Identities


An application system administrator does not have to manage separate sets of login credentials for SQL Server.
It is possible to configure Active Directory as a key distribution center (KDC) for Integrated Authentication. See
Microsoft Kerberos for more information.

Using Linked Server and Distributed Queries


Developers can deploy an application that uses a linked server or distributed queries without a database
administrator who maintains separate sets of SQL credentials. In this situation, a developer must configure an
application to use integrated authentication:
User logs in to a client machine and authenticates to the application server.
The application server authenticates as a different database and connects to SQL Server.
SQL Server authenticates as a database user to another database (SQL Server.
After integrated authentication is configured, credentials will be passed to the linked server.

Integrated Authentication and sqlcmd


To access SQL Server using integrated authentication, use the -E option of sqlcmd . Ensure that the account
which runs sqlcmd is associated with the default Kerberos client principal.

Integrated Authentication and bcp


To access SQL Server using integrated authentication, use the -T option of bcp . Ensure that the account which
runs bcp is associated with the default Kerberos client principal.
It is an error to use -T with the -U or -P option.

Supported Syntax for an SPN Registered by SQL Server


The syntax that SPNs use in the connection string or connection attributes is as follows:

SY N TA X DESC RIP T IO N

MSSQLSvc/fqdn:port The provider-generated, default SPN when TCP is used. port


is a TCP port number. fqdn is a fully qualified domain name.

Authenticating a Linux or macOS Computer with Active Directory


To configure Kerberos, enter data into the krb5.conf file. krb5.conf is in /etc/ but you can refer to another
file using the syntax e.g. export KRB5_CONFIG=/home/dbapp/etc/krb5.conf . The following is an example krb5.conf
file:

[libdefaults]
default_realm = YYYY.CORP.CONTOSO.COM
dns_lookup_realm = false
dns_lookup_kdc = true
ticket_lifetime = 24h
forwardable = yes

[domain_realm]
.yyyy.corp.contoso.com = YYYY.CORP.CONTOSO.COM
.zzzz.corp.contoso.com = ZZZZ.CORP.CONTOSO.COM

If your Linux or macOS computer is configured to use the Dynamic Host Configuration Protocol (DHCP) with a
Windows DHCP server providing the DNS servers to use, you can use dns_lookup_kdc=true . Now, you can
use Kerberos to sign in to your domain by issuing the command kinit [email protected] . Parameters
passed to kinit are case-sensitive and the SQL Server computer configured to be in the domain must have
that user [email protected] added for login. Now, you can use trusted connections
(Trusted_Connection=YES in a connection string, bcp -T , or sqlcmd -E ).
The time on the Linux or macOS computer and the time on the Kerberos Key Distribution Center (KDC) must be
close. Ensure that your system time is set correctly, e.g. by using the Network Time Protocol (NTP).
If Kerberos authentication fails, the ODBC driver on Linux or macOS does not use NTLM authentication.
For more information about authenticating Linux or macOS computers with Active Directory, see Authenticate
Linux Clients with Active Directory. For more information about configuring Kerberos, see the MIT Kerberos
Documentation.

See Also
Programming Guidelines
Release Notes
Using Azure Active Directory
Release Notes for the Microsoft ODBC Driver for
SQL Server on Linux and macOS
4/27/2022 • 7 minutes to read • Edit Online

Download ODBC Driver


This article lists and describes what's new in the versioned releases of the Microsoft ODBC driver for SQL Server
on Linux and macOS.

18.0, February 2022


N EW IT EM DETA IL S

New distributions supported. Debian 11, Ubuntu 21.10, macOS 12

Added compatibility with OpenSSL 3.0 See Connection String Keywords and Data Source Names.

Ability to send long types as max types See DSN and Connection String Attributes and Keywords.

Support for TDS 8.0 See Features of the Microsoft ODBC Driver for SQL Server
on Windows.

Compatibility extensions for SQLGetData See Features of the Microsoft ODBC Driver for SQL Server
on Windows.

Bug fixes. Bug fixes.

17.9, February 2022


N EW IT EM DETA IL S

New distributions supported. Debian 11, Ubuntu 21.10, macOS 12

Added compatibility with OpenSSL 3.0 See Connection String Keywords and Data Source Names.

Bug fixes. Bug fixes.

17.8.1.2, October 2021


N EW IT EM DETA IL S

Package update Updated RPM packages for Red Hat 7, Red Hat 8, SUSE 12,
and SUSE 15 to use SHA256 RPM signing.
N EW IT EM DETA IL S

17.8, July 2021


N EW IT EM DETA IL S

New distributions supported. Ubuntu 21.04, Alpine 3.13

Support for Apple M1 ARM64 hardware See Install the ODBC driver (macOS).

Replication option added to the connection string See DSN and Connection String Attributes and Keywords.

KeepAlive and KeepAliveInterval options added to the See DSN and Connection String Attributes and Keywords.
connection string

Bug fixes. Bug fixes.

17.7.2, March 2021


N EW IT EM DETA IL S

Bug fixes. Bug fixes.

17.7, January 2021


N EW IT EM DETA IL S

New distributions supported. Ubuntu 20.10, macOS Big Sur (11.0), Oracle Linux 7

Service Principal Authentication See DSN and Connection String Attributes and Keywords.

Ability to insert into encrypted money and smallmoney See Using Always Encrypted.
columns

Bug fixes. Bug fixes.

17.6, July 2020


N EW IT EM DETA IL S

New distributions supported. Ubuntu 20.04


N EW IT EM DETA IL S

Support for Federated Authentication See Using Azure Active Directory.

Metadata caching for prepared statements See Using Always Encrypted.

SQL_COPT_SS_AUTOBEGINTXN connection attribute to See DSN and Connection String Attributes and Keywords.
control whether automatic BEGIN TRANSACTION happens
after ROLLBACK or COMMIT

Bug fixes. Bug fixes.

17.5.2.2, April 2020 (Alpine Linux only)


F EAT URE A DDED DETA IL S

Bug fixed. See Bug fixes.

17.5.2, March 2020


F EAT URE A DDED DETA IL S

Support authentication with Managed Identity for Azure Key See Using Always Encrypted with the ODBC Driver.
Vault

Support for more Azure Key Vault endpoints See Using Always Encrypted with the ODBC Driver.

Bug fixes. See Bug fixes.

17.5, January 2020


F EAT URE A DDED DETA IL S

SQL_COPT_SS_SPID connection attribute to retrieve SPID See DSN and Connection String Attributes and Keywords.
without round trip to server

Support for indicating EULA acceptance via debconf on See Installing the Driver.
Debian and Ubuntu

New distributions supported. • Alpine Linux (3.10, 3.11)


• Oracle Linux 8
• Ubuntu 19.10
• macOS 10.15

Bug fixes. See Bug fixes.


F EAT URE A DDED DETA IL S

17.4.2, October 2019


F EAT URE A DDED DETA IL S

Support for more Azure Key Vault endpoints See Using Always Encrypted with the ODBC Driver.

Support for setting data classification version See Data Classification.

Bug fixes. See Bug fixes.

Known Issue:
When using Always Encrypted with secure enclaves and Azure Key Vault, odd key path lengths may result in
CMK signature verification errors. If you encounter this issue, try changing the length of the key path by one
character by renaming the AKV key.

17.4, August 2019


F EAT URE A DDED DETA IL S

Always Encrypted with secure enclaves. See Using Always Encrypted with the ODBC Driver.

Dynamic loading of OpenSSL See Programming Guidelines.

Configurable TCP Keep Alive settings. See Connecting to SQL Server.

Bug fixes. See Bug fixes.

17.3, February 2019


N EW IT EM DETA IL S

New distributions supported. • SUSE 15


• Ubuntu 18.10
• macOS 10.14

Azure Active Directory Managed Identity (system and user- See Using Azure Active Directory with the ODBC Driver.
assigned) authentication mode.

Ability to stream input parameters against Always Encrypted For more information, see Limitations of the ODBC driver
columns. when using Always Encrypted.
N EW IT EM DETA IL S

XA distributed transactions. See Using XA Transactions.

XA is an initialism for eXtended Architecture, which is a


standard for the execution of a global transaction that
accesses more than one server-side data storage system.

17.2, July 2018


N EW IT EM DETA IL S

New distributions supported. • Ubuntu 18.04

Data Classification for Azure SQL Database and SQL Server. See Data Classification.

Support UTF-8 server encoding.

SQLBrowseConnect

Dynamic dependency on libcurl . Starting with this version, the libcurl package isn't an
explicit dependency.
The libcurl package for OpenSSL or NSS is required when
using Azure Key Vault or Azure Active Directory
authentication.
If you encounter an error regarding libcurl , ensure it's
installed.

Idle Connection Resiliency with ConnectRetryCount and • Use SQL_COPT_SS_CONNECT_RETRY_COUNT (read only) to
ConnectRetryInterval keywords in connection string. retrieve the number of connection retry attempts.

• Use SQL_COPT_SS_CONNECT_RETRY_INTERVAL (read only)


to retrieve the length of the connection retry interval.

See Connection Resiliency.

Bug fixes. Bug fixes.

17.1, March 2018


N EW IT EM DETA IL S
N EW IT EM DETA IL S

Support for SQL_COPT_SS_CEKCACHETTL and • SQL_COPT_SS_CEKCACHETTL allows controlling the time


SQL_COPT_SS_TRUSTEDCMKPATHS connection attributes. that the local cache of Column Encryption Keys exists, and
flushing it.

• SQL_COPT_SS_TRUSTEDCMKPATHS allows the application


to restrict Always Encrypted operations to use only the
specified list of Column Master Keys.

See Using Always Encrypted with the ODBC Driver for SQL
Server).

Support for loading the .rll from default location. See 'Resource File Loading' section in the Installation
document.

Bug fixes. Bug fixes.

17
New distributions suppor ted : macOS High Sierra and Ubuntu 17.10
Performance Improvements : Greater than 10 times performance improvement when driver converts to/from
UTF-8/16.
Features Added :
Always Encrypted support for BCP API
New connection string attribute UseFMTOnly causes driver to use legacy metadata in special cases requiring
temp tables.
Support for Azure SQL Managed Instance.

NOTE
There are a number of differences when using Managed Instance:
FILESTREAM is not supported
Local filesystem access is not supported, but required for things like tracefiles
Create UDT from local path is not supported
Windows Integrated Authentication is not supported
DTC is not supported
'sa' account is not present (default account is called 'cloudSA')
TDS token ERROR (0xAA) returns incorrect server name
Special characters in database name are not supported
ALTER DATABASE [dbname1] MODIFY NAME = [dbname2] is not supported
The error messages are always shown in English, regardless of language settings (same as Azure)

13.1, for SQL Server on Linux and macOS, May 2017


ODBC Driver 13.1 for SQL Server adds support for Always Encrypted and Azure Active Directory when used
with Microsoft SQL Server 2016.
New distributions suppor ted : OS X 10.11 and macOS 10.12 are supported in the first release of the ODBC
Driver on macOS. Ubuntu 16.10 is now also supported, along with Red Hat 6, 7, and SUSE 12. Each platform has
a platform-relevant package (RPM or DEB) to ease installation and configuration. For more information, see the
ODBC driver installation instructions for Linux and macOS.
unixODBC Driver Manager 2.3.1 Suppor t Changes : The ODBC driver no longer depends on custom
packaging for the unixODBC driver manager (except on Red Hat 6), and instead relies on the distribution
package manager to resolve the UnixODBC dependency from the distribution's repositories.
BCP API Suppor t : The Linux and macOS ODBC driver now supports the use of the BCP API functions
(bcp_init , etc.)

13.0, for SQL Server on Linux


With Microsoft ODBC Driver 13.0 for SQL Server, SQL Server 2014 and SQL Server 2016 are now also
supported.
New distributions suppor ted :
Ubuntu is now supported, along with Red Hat and SUSE. Each platform has a platform-relevant package (RPM
or DEB) to ease installation and configuration. See Installing the Driver for installation instructions.
unixODBC Driver Manager 2.3.1 Suppor t : In addition to a newer driver manager, there's also a package for
installing this dependency that eases installation and configuration.
Transparent Network IP Resolution : Transparent Network IP Resolution is a revision of the existing Multi-
Subnet Failover feature that affects the connection sequence of the driver in the case where the first resolved IP
of the hostname doesn't respond and there are multiple IPs associated with the hostname.
TLS 1.2 Suppor t : The Microsoft ODBC Driver 13.0 for SQL Server on Linux now supports TLS 1.2 when secure
communications with SQL Server are used.

11, for SQL Server on Linux


The ODBC driver on SUSE Linux (Preview) supports 64-bit SUSE Linux Enterprise 11 Service Pack 2. For more
information, see System Requirements.
The ODBC driver on Linux supports Always On Availability Groups. For more information, see ODBC Driver on
Linux Support for High Availability, Disaster Recovery.
The ODBC driver on Linux supports connections to Azure SQL Database.
The -l option (login timeout) has been added to bcp . For more information, see Connecting with bcp .
Release notes for the Microsoft SQL Server tools on
Linux and macOS
4/27/2022 • 2 minutes to read • Edit Online

Download ODBC Driver


This article lists and describes what's new in the versioned releases of the Microsoft SQL Server Tools on Linux
and macOS.

18.0.1.1, February 2022


N EW IT EM DETA IL S

Sqlcmd Bugfix Fixed extraneous trailing bytes after encoding conversion.

TDS 8.0 Add support for TDS 8.0 strict encryption

17.9.1.1, February 2022


N EW IT EM DETA IL S

Sqlcmd Bugfix Fixed extraneous trailing bytes after encoding conversion.

17.8.1.2, October 2021


N EW IT EM DETA IL S

Package update Updated RPM packages for Red Hat 7, Red Hat 8, SUSE 12,
and SUSE 15 to use SHA256 RPM signing.

17.8.1.1, July 2021


F EAT URE A DDED DETA IL S

Sqlcmd Token Authentication Now supported. See Connecting with sqlcmd

BCP Token Authentication Now supported. See Connecting with bcp


17.7.1.1, January 2021
F EAT URE A DDED DETA IL S

Sqlcmd Bugfix Fixed input redirection bug and empty lines leading to
repeated execution.

Sqlcmd Bugfix Fixed mistaken error reporting for r, p, X and k options


under certain formatting.

Sqlcmd -z/-Z "Password" Option Now supported.

17.6.1.1, July 2020


F EAT URE A DDED DETA IL S

Sqlcmd Command Line Parser Updated Fixed bugs where unexpected behavior occurred when using
certain options in different orders.

Sqlcmd Error Messages Updated Fixed various inconsistencies in how errors in sqlcmd were
returned.

Sqlcmd -Y Option Fixed Fixed issue where -Y option was ineffective

Sqlcmd Column Name Truncation Fixed Fixed issue where column names would be truncated
incorrectly

Sqlcmd Linux Exit Codes Fixed issue where process exit code was missing on Linux

Next steps
Learn more about connecting with BCP and SQLCMD!
Known issues for the ODBC driver on Linux and
macOS
4/27/2022 • 4 minutes to read • Edit Online

Download ODBC Driver


This article contains a list of known issues with the Microsoft ODBC Driver 13, 13.1, 17, and 18 for SQL Server
on Linux and macOS. It also contains steps for troubleshooting connectivity issues.

Known issues
Additional issues will be posted on the SQL Server Drivers blog.
Due to system library limitations, Alpine Linux supports fewer character encodings and locales. For
example, en_US.UTF-8 isn't available. For more information, see musl libc - functional differences from
glibc .

Windows, Linux, and macOS convert characters from the Private Use Area (PUA) or End User-Defined
Characters (EUDC) differently. Conversions performed on the server within Transact-SQL use the
Windows conversion library. Conversions in the driver use the Windows, Linux, or macOS conversion
libraries. Each library may produce different results when performing these conversions. For more
information, see End-User-Defined and Private Use Area Characters.
If the client encoding is UTF-8, the driver manager doesn't always correctly convert from UTF-8 to UTF-
16. Currently, data corruption occurs when one or more characters in the string aren't valid UTF-8
characters. ASCII characters are mapped correctly. The driver manager attempts this conversion when
calling the SQLCHAR versions of the ODBC API (for example, SQLDriverConnectA). The driver manager
won't attempt this conversion when calling the SQLWCHAR versions of the ODBC API (for example,
SQLDriverConnectW).
The ColumnSize parameter of SQLBindParameter refers to the number of characters in the SQL type,
while BufferLength is the number of bytes in the application's buffer. However, if the SQL data type is
varchar(n) or char(n) , the application binds the parameter as SQL_C_CHAR for the C type, and
SQL_CHAR or SQL_VARCHAR for the SQL type, and the character encoding of the client is UTF-8, you
may get a "String data, right truncation" error from the driver even if the value of ColumnSize is aligned
with the size of the data type on the server. This error occurs since conversions between character
encodings may change the length of the data. For example, a right apostrophe character (U+2019) is
encoded in CP-1252 as the single-byte 0x92, but in UTF-8 as the 3-byte sequence 0xe2 0x80 0x99.
For example, if your encoding is UTF-8 and you specify 1 for both BufferLength and ColumnSize in
SQLBindParameter for an out-parameter, and then attempt to retrieve the preceding character stored in a
char(1) column on the server (using CP-1252), the driver attempts to convert it to the 3-byte UTF-8 encoding,
but can't fit the result into a 1-byte buffer. In the other direction, it compares ColumnSize with the BufferLength
in SQLBindParameter before doing the conversion between the different code pages on the client and server.
Because a ColumnSize of 1 is less than a BufferLength of (for example) 3, the driver generates an error. To avoid
this error, ensure that the length of the data after conversion fits into the specified buffer or column. Note that
ColumnSize can't be greater than 8000 for the varchar(n) type.

Troubleshooting connection problems


If you're unable to make a connection to SQL Server using the ODBC driver, use the following information to
identify the problem.
The most common connection problem is to have two copies of the UnixODBC driver manager installed. Search
/usr for libodbc*.so*. If you see more than one version of the file, you (possibly) have more than one driver
manager installed. Your application might use the wrong version.
Enable the connection log by editing your /etc/odbcinst.ini file to contain the following section with these
items:

[ODBC]
Trace = Yes
TraceFile = (path to log file, or /dev/stdout to output directly to the terminal)

If you get another connection failure and don't see a log file, there (possibly) are two copies of the driver
manager on your computer. Otherwise, the log output should be similar to:

[ODBC][28783][1321576347.077780][SQLDriverConnectW.c][290]
Entry:
Connection = 0x17c858e0
Window Hdl = (nil)
Str In = [DRIVER={ODBC Driver 17 for SQL Server};SERVER={contoso.com};Trusted_Connection=
{YES};WSID={mydb.contoso.com};AP...][length = 139 (SQL_NTS)]
Str Out = (nil)
Str Out Max = 0
Str Out Ptr = (nil)
Completion = 0
UNICODE Using encoding ASCII 'UTF8' and UNICODE 'UTF16LE'

If the ASCII character encoding isn't UTF-8, for example:

UNICODE Using encoding ASCII 'ISO8859-1' and UNICODE 'UCS-2LE'

There's more than one driver manager installed and your application is using the wrong one, or the driver
manager wasn't built correctly.
Some macOS users encounter the following error with driver version 17.8 or older:
(This error has been resolved in driver version 17.9+)

[08001][Microsoft][ODBC Driver 17 for SQL Server]SSL Provider: [OpenSSL library could not be loaded, make
sure OpenSSL 1.0 or 1.1 is installed]
[08001][Microsoft][ODBC Driver 17 for SQL Server]Client unable to establish connection (0)
(SQLDriverConnect)

The error can happen when OpenSSL 3.0 is installed. OpenSSL typically is installed through Brew, and it contains
the openssl, [email protected], and openssl@3 binaries.
To resolve this error, change the symlink of the openssl binary to [email protected]:

rm -rf $(brew --prefix)/opt/openssl


version=$(ls $(brew --prefix)/Cellar/[email protected] | grep "1.1")
ln -s $(brew --prefix)/Cellar/[email protected]/$version $(brew --prefix)/opt/openssl

For more information about resolving connection failures, see:


Steps to troubleshoot SQL connectivity issues
SQL Server 2005 Connectivity Issue Troubleshoot - Part I
Connectivity troubleshooting in SQL Server 2008 with the Connectivity Ring Buffer
SQL Server Authentication Troubleshooter

Next steps
For ODBC driver installation instructions, see the following articles:
Installing the Microsoft ODBC Driver for SQL Server on Linux
Installing the Microsoft ODBC Driver for SQL Server on macOS
For more information, see the Programming guidelines and the Release notes.
Microsoft ODBC Driver for SQL Server on Windows
4/27/2022 • 2 minutes to read • Edit Online

Download ODBC Driver


The Microsoft ODBC Drivers for SQL Server are stand-alone ODBC drivers which provide an application
programming interface (API) implementing the standard ODBC interfaces to Microsoft SQL Server.
The Microsoft ODBC Driver for SQL Server can be used to create new applications. You can also upgrade your
older applications which currently use an older ODBC driver. The ODBC Driver for SQL Server supports
connections to Azure SQL Database, Azure Synapse Analytics, and SQL Server.

Summary
VERSIO N F EAT URES SUP P O RT ED

Microsoft ODBC Driver 18 for SQL Server Support for TDS 8.0
Extensions to SQLGetData
Option to send SQL_LONG_* types as (max) -types

Microsoft ODBC Driver 17 for SQL Server Always Encrypted support for BCP API
New connection string attribute UseFMTONLY causes
driver to use legacy metadata in special cases
requiring temp tables

Microsoft ODBC Driver 13.1 for SQL Server Always Encrypted


Azure AD Authentication
AlwaysOn Availability Groups (AG)

Microsoft ODBC Driver 13 for SQL Server Internationalized Domain Name (IDN)

Microsoft ODBC Driver 11 for SQL Server Driver-Aware Connection Pooling


Connection Resiliency
Asynchronous execution (Polling Method)

Documentation
This documentation for the Microsoft ODBC Driver for SQL Server includes:
Release Notes for ODBC to SQL Server on Windows
Features of the Microsoft ODBC Driver for SQL Server on Windows
System Requirements, Installation, and Driver Files
Driver-Aware Connection Pooling in the ODBC Driver for SQL Server
Asynchronous Execution (Notification Method) Sample
Connection Resiliency in the Windows ODBC Driver
Using Always Encrypted with the ODBC Driver
Using Azure Active Directory with the ODBC Driver
Using Transparent Network IP Resolution

Community
SQL Server Drivers blog
SQL Server Data Access Forum

See Also
Building Applications with SQL Server Native Client
SQL Server Native Client FAQ
ODBC Programmer's Reference
SQL Server Native Client (ODBC)
Features of the Microsoft ODBC Driver for SQL
Server on Windows
4/27/2022 • 4 minutes to read • Edit Online

Download ODBC Driver

Microsoft ODBC Driver 18.0 for SQL Server on Windows


The ODBC Driver 18.0 allows users to send long data types as max data types using the keyword LongAsMax to
toggle the setting on or off. When enabled, the SQL types SQL_LONGVARCHAR, SQL_LONGVARBINARY, and
SQL_LONGWVARCHAR will be sent as varchar(max), varbinary(max), and nvarchar(max) instead of text, image,
and ntext respectively.
The connection encryption defaults have changed. The default value of Encrypt is now Yes, and the new
keywords Optional and Mandatory have been introduced as synonyms for No and Yes, respectively. For
connecting using the TDS 8.0 protocol, the Strict mode ( Encrypt=Strict ) has been added. In this mode, the
server certificate is always verified ( TrustServerCertificate is ignored). A new keyword, HostnameInCertificate ,
can be used to specify the expected hostname found in the certificate if it differs from the specified server.
HostnameInCertificate is usable in all encryption modes and is also applicable if the server-side
Force Encryption option is enabled, which will cause the driver to verify the certificate in Optional or
Mandatory modes unless disabled using TrustServerCertificate .
The ODBC Driver 18 includes SQLGetData extensions. When enabled, SQLGetData can be used to retrieve
column data in any order within a row, including going backwards. The feature is provided for compatibility
purposes and will significantly degrade performance and increase memory usage. It is highly recommended
that application always access the columns in ascending order. To enable SQLGetData extensions one can either
use the GetDataExtensions connection string attribute, or use the SQLSetConnectAttr function to set
SQL_COPT_SS_GETDATA_EXTENSIONS to SQL_EN_ON .

Microsoft ODBC Driver 17.4 for SQL Server on Windows


The ODBC Driver 17.4 includes the ability to adjust TCP Keep-Alive settings. They can be modified by adding
values to the Driver or DSN registry keys. The keys are located in HKEY_LOCAL_MACHINE\Software\ODBC\ for system
data sources, and in HKEY_CURRENT_USER\Software\ODBC\ for user data sources. For DSN, the values need to be
added to ...\Software\ODBC\ODBC.INI\<DSN Name> and for the Driver to
...\Software\ODBC\ODBCINST.INI\ODBC Driver 17 for SQL Server .

For more information, see Registry Entries for ODBC Components.


The values are REG_SZ and are as follows:
KeepAlive controls how often TCP attempts to verify that an idle connection is still intact by sending a
keep-alive packet. The default is 30 seconds.
KeepAliveInterval determines the interval separating keep-alive retransmissions until a response is
received. The default is 1 second.

Microsoft ODBC Driver 13.1 for SQL Server on Windows


The ODBC Driver 13.1 for SQL Server contains all the functionality of the previous version (11). It also adds
support for Always Encrypted and Azure Active Directory authentication.
Always Encrypted allows clients to encrypt sensitive data inside client applications and never reveal the
encryption keys to SQL Server. An Always Encrypted enabled driver installed on the client computer achieves
this security by automatically encrypting and decrypting sensitive data in the SQL Server client application. The
driver encrypts the data in sensitive columns before passing the data to SQL Server. It also automatically
rewrites queries so that the semantics to the application are preserved. Similarly, the driver transparently
decrypts data stored in encrypted database columns that are contained in query results. For more information,
see Using Always Encrypted with the ODBC Driver.
Azure Active Directory allows users, DBAs, and application programmers to use Azure Active Directory
authentication. For more information, see Using Azure Active Directory with the ODBC Driver, and Connecting
to SQL Database or Azure Synapse Analytics By Using Azure Active Directory Authentication.

Microsoft ODBC Driver 11 for SQL Server on Windows


The ODBC Driver for SQL Server contains all the functionality of the SQL Server Native Client ODBC driver that
shipped in SQL Server 2012 (11.x). For more information about SQL Server Native Client, see SQL Server
Native Client Programming. The SQL Server Native Client ODBC driver is based on the ODBC driver that ships
in the Windows operating system. For more information about that driver, see Windows Data Access
Components SDK.
This release of the ODBC Driver for SQL Server contains the following new features:
bcp.exe -l option for specifying a login timeout
The -l option specifies the number of seconds before a bcp.exe login to SQL Server times out when you try to
connect to a server. The default login timeout is 15 seconds. The login timeout must be a number between 0 and
65534. If the value supplied isn't numeric or doesn't fall into that range, bcp.exe generates an error message. A
value of 0 specifies an infinite timeout. A login timeout of less than (approximately) 10 seconds isn't reliable.
Driver-aware connection pooling
The ODBC Driver for SQL Server supports Driver-Aware Connection Pooling. For more information, see Driver-
Aware Connection Pooling in the ODBC Driver for SQL Server.
Asynchronous execution (notification method)
The ODBC Driver for SQL Server supports Asynchronous Execution (Notification Method). For a usage sample,
see Asynchronous Execution (Notification Method) Sample.
Connection resiliency
To ensure that applications remain connected to a Microsoft Azure SQL Database, the ODBC driver on Windows
can restore idle connections. For more information, see Connection Resiliency in the Windows ODBC Driver.

Behavior changes
In SQL Server Native Client, the -y0 option for sqlcmd.exe caused output to be truncated at 1 MB if the display
width was 0.
Beginning in the ODBC Driver 11 for SQL Server, there's no limit on the amount of data that can be retrieved in a
single column when -y0 is specified. sqlcmd.exe now streams columns as large as 2 GB (SQL Server data type
maximum).
Another difference is that specifying both -h and -y0 now produces an error reporting that the options are
incompatible. -h , which specifies the number of rows to print between the column headings and has never
been compatible with -y0 , was ignored although no headers were printed.
-y0 can cause performance issues on both the server and the network, depending on the size of the data
returned.

See also
Microsoft ODBC Driver for SQL Server on Windows
Release Notes for Microsoft ODBC Driver for SQL
Server on Windows
4/27/2022 • 13 minutes to read • Edit Online

This release notes article describes what's new for the Microsoft ODBC driver for SQL Server on Windows.

18.0
Download x64 installer
Download x86 installer
Version number: 18.0.1.1
Released: February 15, 2022
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish

F EAT URE A DDED DETA IL S

Added compatibility with OpenSSL 3.0 See Connection String Keywords and Data Source Names.

Ability to send long types as max types See DSN and Connection String Attributes and Keywords.

Secure by default BREAKING CHANGE


Default Encrypt to Yes/Mandatory. Changed certificate
validation behavior to validate when encryption is
negotiated from either the client or the server side, not just
the client side. For more information, see the ODBC Driver
18.0 release announcement.

Support for TDS 8.0 See Features of the Microsoft ODBC Driver for SQL Server
on Windows.

Compatibility extensions for SQLGetData See Features of the Microsoft ODBC Driver for SQL Server
on Windows.

Bug fixes. Bug fixes.

17.9
Download x64 installer
Download x86 installer
Version number: 17.9.1.1
Released: February 17, 2022
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish

F EAT URE A DDED DETA IL S

Added compatibility with OpenSSL 3.0 See Connection String Keywords and Data Source Names.

Previous Releases
17.8
Download x64 installer
Download x86 installer
Version number: 17.8.1.1
Released: July 30, 2021
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish

F EAT URE A DDED DETA IL S

Ability to modify KeyStoreAuthentication and See Using Always Encrypted.


KeyStorePrincipalId in DSN configuration UI

Replication option added to the connection string See DSN and Connection String Attributes and Keywords.

KeepAlive and KeepAliveInterval options added to the See DSN and Connection String Attributes and Keywords.
connection string

Bug fixes. Bug fixes.

17.7.2
Download x64 installer
Download x86 installer
Version number: 17.7.2.1
Released: March 10, 2021
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish

F EAT URE A DDED DETA IL S

Bug fixes. Bug fixes.

17.7
Download x64 installer
Download x86 installer
Version number: 17.7.1.1
Released: January 29, 2021
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish

F EAT URE A DDED DETA IL S

Azure Key Vault Interactive Authentication See Using Always Encrypted.

Service Principal Authentication See DSN and Connection String Attributes and Keywords.

Ability to insert into encrypted money and smallmoney See Using Always Encrypted.
columns

Bug fixes. Bug fixes.

17.6
Download x64 installer
Download x86 installer
Version number: 17.6.1.1
Released: July 31, 2020
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish

F EAT URE A DDED DETA IL S

Metadata caching for prepared statements See Using Always Encrypted.

SQL_COPT_SS_AUTOBEGINTXN connection attribute to See DSN and Connection String Attributes and Keywords.
control whether automatic BEGIN TRANSACTION happens
after ROLLBACK or COMMIT

Bug fixes. Bug fixes.

17.5.2
Download x64 installer
Download x86 installer
Version number: 17.5.2.1
Released: March 6, 2020
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Features added in 17.5.2
F EAT URE A DDED DETA IL S

Support authentication with Managed Identity for Azure Key See Using Always Encrypted with the ODBC Driver.
Vault

Support for more Azure Key Vault endpoints See Using Always Encrypted with the ODBC Driver.

Bug fixes. See Bug fixes.

Download previous ODBC Driver versions by clicking the download links in the following sections:

17.5
Download x64 installer
Download x86 installer
Version number: 17.5.1.1
Released: January 31, 2020
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Features added in 17.5
F EAT URE A DDED DETA IL S

SQL_COPT_SS_SPID connection attribute to retrieve SPID See DSN and Connection String Attributes and Keywords.
without round trip to server

Bug fixes. See Bug fixes.

17.4.2
Download x64 installer
Download x86 installer
Version number: 17.4.2.1
Released: October 2019
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Features added in 17.4.2
F EAT URE A DDED DETA IL S

Support for more Azure Key Vault endpoints See Using Always Encrypted with the ODBC Driver.

Support for setting data classification version See Data Classification.

Include Azure Active Directory Authentication Library Now included in the base driver installation, the ODBC
(adal.dll) in the installer installer will upgrade existing installations of the Microsoft
Active Directory Authentication Library for SQL Server,
removing it from the list of installed applications in Windows.

Bug fixes. See Bug fixes.

17.4
Download x64 installer
Download x86 installer
Version number: 17.4.1.1
Released: July 2019
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Features added in 17.4
F EAT URE A DDED DETA IL S

Always Encrypted with secure enclaves. See Using Always Encrypted with the ODBC Driver.

Configurable TCP Keep Alive settings. See Connecting to SQL Server.

Bug fixes. See Bug fixes.

17.3
Download x64 installer
Download x86 installer
Version number: 17.3.1.1
Released: February 2019
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Features added in 17.3
F EAT URE A DDED DETA IL S

Azure Active Directory Managed Identity (system and user- See Using Azure Active Directory with the ODBC Driver.
assigned) authentication mode.

Ability to stream input parameters against Always Encrypted See Limitations of the ODBC driver when using Always
columns. Encrypted.

XA distributed transactions. Using XA Transactions.

Updated Visual C++ Redistributable Upgraded the runtime dependency to the Visual C++ 2017
Redistributable (x64 Download, x86 Download)

Bug fixes. See Bug fixes.


17.2
Download x64 installer
Download x86 installer
Version number: 17.2.0.1
Released: July 2018
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Features added in 17.2
F EAT URE A DDED DETA IL S

Data Classification for Azure SQL Database and SQL Server. See Data Classification.

Support for UTF-8 server encoding.

Bug fixes. See Bug fixes.

17.1
Download x64 installer
Download x86 installer
Version number: 17.1.0.1
Released: March 2018
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Features added in 17.1
F EAT URE A DDED DETA IL S

Support for SQL_COPT_SS_CEKCACHETTL and • SQL_COPT_SS_CEKCACHETTL


SQL_COPT_SS_TRUSTEDCMKPATHS connection attributes. Allows controlling the time that the local cache of Column
Encryption Keys exists, and flushing it.

• SQL_COPT_SS_TRUSTEDCMKPATHS
Allows the application to restrict AE operations to only use
the specified list of Column Master Keys.

For more information, see Using Always Encrypted with the


ODBC Driver for SQL Server.
F EAT URE A DDED DETA IL S

Azure Active Directory Interactive Authentication Support

Bug fixes. See Bug fixes.

17.0
Download x64 installer
Download x86 installer
Version number: 17.0.1.1
Released: February 2018
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Features added in 17.0
F EAT URE A DDED DETA IL S

Always Encrypted support for BCP API.

New connection string attribute UseFMTOnly . Causes the driver to use legacy metadata in special cases
that require temporary tables.

Support for Azure SQL Managed Instance. See the following list of Differences when using Managed
Instance (ODBC version 17).

DEP EN DEN C Y C H A N GED DETA IL S

Removed Microsoft online service sign-in assistant The dependency has been removed.

Differences when using Managed Instance (ODBC version 17)


This version of ODBC contains support for Azure SQL Managed Instance. See the following noted list of
differences when using Managed Instance.
NOTE
There are a number of differences when using Managed Instance:
FILESTREAM is not supported.
Local filesystem access is not supported, but is required for things like trace files.
Create UDT from local path is not supported.
Windows Integrated Authentication is not supported.
DTC is not supported.
sa account is not present (default account is called cloudSA ).
TDS token ERROR (0xAA) returns incorrect server name.
Special characters in database name are not supported.
ALTER DATABASE [dbname1] MODIFY NAME = [dbname2] is not supported.
The error messages are always shown in English, regardless of language settings (same as Azure).

13.1
Download x64 installer
Download x86 installer
Version number: 13.1
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Download the Microsoft Command Line Utilities 13.1 for SQL Server
Features added in 13.1
F EAT URE A DDED DETA IL S

ODBC Driver 13.1 for SQL Server adds support for Always These added supports are available when connecting to
Encrypted and Azure Active Directory. Microsoft SQL Server 2016, or to a later version.

There are connection pooling keywords and attributes, that These keywords and attributes are described in Driver Aware
correspond to the supports for Always Encrypted and Azure Connection Pooling in the ODBC Driver for SQL Server.
Active Directory.

13
Download x64 installer
Download x86 installer
Version number: 13
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Download the Microsoft Command Line Utilities 13 for SQL Server
Features added in 13
F EAT URE A DDED DETA IL S

Adds support for Microsoft SQL Server 2016. Retains the functionality of ODBC driver version 11.

11
Download x64 installer
Download x86 installer
Version number: 11
If you need to download the installer in a language other than the one detected for you, you can use these direct
links.
For the x64 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
For the x86 driver: Chinese (Simplified) | Chinese (Traditional) | English (United States) | French | German | Italian
| Japanese | Korean | Portuguese (Brazil) | Russian | Spanish
Download the Microsoft Command Line Utilities 11 for SQL Server
Features added in 11
F EAT URE A DDED DETA IL S

Contains new features. See Features of the Microsoft ODBC Driver for SQL Server
on Windows.

Contains all the features that shipped with ODBC in SQL


Server 2012 Native Client.
System requirements, installation, and driver files
4/27/2022 • 5 minutes to read • Edit Online

Download ODBC Driver


This article discusses the ODBC drivers that connect to SQL Server.

SQL version compatibility


Compatibility indicates that a driver was tested for compatibility against existing releases of SQL at the time of
the driver's release. SQL Server releases generally try to maintain backwards compatibility with existing client
drivers. But new features in SQL Server releases may not be available with older client drivers.

DATA
B A SE
VERSI
ON → A Z UR A Z UR
↓ E E SQ L SQ L
DRIVE A Z UR SY N A MAN SQ L SQ L SQ L SQ L SQ L SERVE SQ L SQ L
R E SQ L P SE A GED SERVE SERVE SERVE SERVE SERVE R SERVE SERVE
VERSI DATA ANAL IN STA R R R R R 2008 R R
ON B A SE Y T IC S NCE 2019 2017 2016 2014 2012 R2 2008 2005

18.0 Yes Yes Yes Yes Yes Yes Yes Yes

17.9 Yes Yes Yes Yes Yes Yes Yes Yes

17.8 Yes Yes Yes Yes Yes Yes Yes Yes

17.7 Yes Yes Yes Yes Yes Yes Yes Yes

17.6 Yes Yes Yes Yes Yes Yes Yes Yes

17.5 Yes Yes Yes Yes Yes Yes Yes Yes

17.4 Yes Yes Yes Yes Yes Yes Yes Yes

17.3 Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes

17.2 Yes Yes Yes Yes Yes Yes Yes Yes Yes

17.1 Yes Yes Yes Yes Yes Yes Yes Yes Yes

17.0 Yes Yes Yes Yes Yes Yes Yes Yes Yes

13.1 Yes Yes Yes Yes Yes Yes

13 Yes Yes Yes Yes Yes

11 Yes Yes Yes Yes Yes


Connection string details
The driver name that you specify in a connection string is one of the following:
ODBC Driver 11 for SQL Server
ODBC Driver 13 for SQL Server (for both 13 and 13.1)
ODBC Driver 17 for SQL Server
ODBC Driver 18 for SQL Server

Supported operating systems


The following matrix indicates driver version support for Windows operating system versions:

O P ER
AT IN
G
SY ST E
M→ W IN D W IN D
↓ W IN D W IN D W IN D OWS W IN D OWS
DRIVE OWS OWS OWS SERVE OWS SERVE W IN D
R SERVE SERVE SERVE R SERVE R W IN D W IN D W IN D W IN D OWS
VERSI R R R 2012 R 2008 OWS OWS OWS OWS VISTA
ON 2022 2019 2016 R2 2012 R2 11 10 8. 1 7 SP 2

18.0 Yes Yes Yes Yes Yes Yes Yes Yes

17.9 Yes Yes Yes Yes Yes Yes Yes Yes

17.8 Yes Yes Yes Yes Yes Yes

17.7 Yes Yes Yes Yes Yes Yes

17.6 Yes Yes Yes Yes Yes Yes

17.5 Yes Yes Yes Yes Yes Yes

17.4 Yes Yes Yes Yes Yes Yes Yes Yes

17.3 Yes Yes Yes Yes Yes Yes Yes Yes

17.2 Yes Yes Yes Yes Yes Yes Yes

17.1 Yes Yes Yes Yes Yes Yes Yes

17.0 Yes Yes Yes Yes Yes Yes Yes

13.1 Yes Yes Yes Yes Yes Yes Yes

13 Yes Yes Yes Yes

11 Yes Yes Yes Yes

Installing Microsoft ODBC Driver for SQL Server


The driver is installed when you run msodbcsql.msi from one of the Downloads for Windows.
NOTE
For those who have Driver 17.1.0.1 or below installed, it is recommended that it be uninstalled manually prior to installing
the newer version of the Driver.

Side -by-side with Native Client


The driver can be installed side-by-side with SQL Server Native Client. Major versions of the driver (11, 13, 17,
18) can all be installed side-by-side with each other, as well.
When you invoke msodbcsql.msi , only the client components are installed by default. The client components are
files that support running an application that was developed using the driver. To install the SDK components,
specify ADDLOCAL=ALL on the command line. Here is an example.

msiexec /i msodbcsql.msi ADDLOCAL=ALL

End-user license
Specify IACCEPTMSODBCSQLLICENSETERMS=YES to accept the terms of the end-user license if you use the /passive ,
/qn , /qb , or /qr option to install. This option must be specified in all uppercase letters. Here is an example.

msiexec /quiet /passive /qn /i msodbcsql.msi IACCEPTMSODBCSQLLICENSETERMS=YES ADDLOCAL=ALL

Silent uninstall
The following example shows how to perform a silent uninstall.

msiexec /quiet /passive /qn /uninstall msodbcsql.msi

Indicate dependency
When an application uses the driver, the application should indicate that it depends on the driver through the
install option APPGUID . this indication enables the driver installer to report dependent applications before
uninstalling. To specify a dependency on the driver, set the APPGUID command-line parameter to your product
code when silently installing the driver. A product code must be created when using Microsoft Installer to bundle
your application setup program. Here is an example.

msiexec /i msodbcsql.msi APPGUID={ <Your dependent application's APPGUID> }

Command-line tools: sqlcmd.exe and bcp.exe


The bcp.exe and sqlcmd.exe tools for use with the driver can be downloaded at Microsoft Command Line
Utilities 11 for SQL Server, Microsoft Command Line Utilities 13 for SQL Server, or Microsoft Command Line
Utilities 13.1 for SQL Server. The driver is a prerequisite to install sqlcmd.exe and bcp.exe .
bcp.exe and sqlcmd.exe are installed in the 110\Tools subfolder of
%PROGRAMFILES%\Microsoft SQL Server\Client SDK\ODBC for version 11, and 130\Tools for 13 and 13.1.
An application that uses BCP functions must specify the driver from the same version which shipped with the
header file and library used to compile the application.
For example, when you compile an ODBC application with msodbcsql11.lib and msodbcsql.h , use "DRIVER=
{ODBC Driver 11 for SQL Server}" in the connection string.
Components of the Microsoft ODBC Driver for SQL Server on
Windows
The ODBC driver on Windows contains the following components:

C O M P O N EN T DESC RIP T IO N

msodbcsql18.dll or The dynamic-link library (DLL) file that contains all of the
msodbcsql17.dll or driver's functionality. This file is installed in
msodbcsql13.dll or %SYSTEMROOT%\System32.
msodbcsql11.dll

msodbcdiag18.dll or The dynamic-link library (DLL) file that contains the driver's
msodbcdiag17.dll or diagnostics (tracing) interface. This file is installed in
msodbcdiag13.dll or %SYSTEMROOT%\System32.
msodbcdiag11.dll

msodbcsqlr18.rll or The accompanying resource file for the driver library. This file
msodbcsqlr17.rll or is installed in %SYSTEMROOT%\System32\1033.
msodbcsqlr13.rll or
msodbcsqlr11.rll

s13ch_msodbcsql.chm or The Data Source Wizard help file that documents how to
s11ch_msodbcsql.chm create a data source for the driver. This file is installed in
%SYSTEMROOT%\System32\1033

NOTE: There is no chm file for ODBC Driver 17 and above.

msodbcsql.h The header file that contains all of the new definitions
needed to use the driver.

Note: You cannot reference msodbcsql.h and odbcss.h in


the same program.

msodbcsql.h for ODBC Driver 18 is installed in


%PROGRAMFILES%\Microsoft SQL Server\Client
SDK\ODBC\180\SDK.
msodbcsql.h for ODBC Driver 17 is installed in
%PROGRAMFILES%\Microsoft SQL Server\Client
SDK\ODBC\170\SDK.
msodbcsql.h for ODBC Driver 13 is installed in
%PROGRAMFILES%\Microsoft SQL Server\Client
SDK\ODBC\130\SDK.
msodbcsql.h for ODBC Driver 11 is installed in
%PROGRAMFILES%\Microsoft SQL Server\Client
SDK\ODBC\110\SDK.
C O M P O N EN T DESC RIP T IO N

msodbcsql18.lib or The library file needed to call the bcp utility functions that
msodbcsql17.lib or are part of the driver.
msodbcsql13.lib or
msodbcsql11.lib Note: If you do reference this library file in your program,
make sure that it is in your system path and in the system
path of those that use the application.

msodbcsql18.lib is installed in %PROGRAMFILES%\Microsoft


SQL Server\Client SDK\ODBC\180\SDK.
msodbcsql17.lib is installed in %PROGRAMFILES%\Microsoft
SQL Server\Client SDK\ODBC\170\SDK.
msodbcsql13.lib is installed in %PROGRAMFILES%\Microsoft
SQL Server\Client SDK\ODBC\130\SDK.
msodbcsql11.lib is installed in %PROGRAMFILES%\Microsoft
SQL Server\Client SDK\ODBC\110\SDK.

See also
Microsoft ODBC Driver for SQL Server on Windows
Driver-Aware Connection Pooling in the ODBC
Driver for SQL Server
4/27/2022 • 3 minutes to read • Edit Online

Download ODBC Driver


The ODBC Driver for SQL Server supports Driver-Aware Connection Pooling. This article describes the
enhancements made to driver-aware connection pooling in the Microsoft ODBC Driver for SQL Server on
Windows:
Whatever the connection properties, connections that use SQLDriverConnect go into a separate pool from
connections that use SQLConnect .
When using SQL Server Authentication and driver-aware connection pooling, the driver doesn't use the
Windows user's security context for the current thread to separate connections in the pool. That is, if
connections are equivalent in their parameters for Windows impersonation scenarios with SQL Server
Authentication, and they're using the same SQL Server Authentication credentials to connect to the backend,
different Windows users can potentially use the same pool of connections. When using Windows
Authentication and driver-aware connection pooling, the driver uses the current Windows user's security
context to separate connections in the pool. That is, for Windows impersonation scenarios, different Windows
users don't share connections even if the connections use the same parameters.
When using Azure Active Directory and driver-aware connection pooling, the driver also uses the
Authentication value to determine the membership in the connection pool.
Driver-aware connection pooling prevents a bad connection from being returned from the pool.
Driver-aware connection pooling recognizes driver-specific connection attributes. So, if a connection uses
SQL_COPT_SS_APPLICATION_INTENT set to read only, that connection gets its own connection pool.
Setting the SQL_COPT_SS_ACCESS_TOKEN attribute causes a connection to be pooled separately
If one of the following connection-attribute IDs or connection string keywords is different between your
connection string and the pooled connection string, the driver uses a pooled connection. However, performance
is better if all connection attribute IDs or connection string keywords match. (To match a connection in the pool,
the driver resets the attribute.) Performance degrades because resetting the following parameters requires an
extra network call.
If two or more of the following connection attributes or connection keywords differ, a pooled connection
isn't used.
Language
QuoteId
SQL_ATTR_TXN_ISOLATION
SQL_COPT_SS_QUOTED_IDENT
If there's a difference in any of the following connection keywords between your connection string and a
pooled connection string, a pooled connection isn't used.

K EY W O RD O DB C DRIVER 13+ O DB C DRIVER 11

Address Yes Yes

AnsiNPW Yes Yes


K EY W O RD O DB C DRIVER 13+ O DB C DRIVER 11

App Yes Yes

ApplicationIntent Yes Yes

Authentication Yes No

ColumnEncryption Yes No

Database Yes Yes

Encrypt Yes Yes

Failover_Partner Yes Yes

FailoverPartnerSPN Yes Yes

MARS_Connection Yes Yes

Network Yes Yes

PWD Yes Yes

Server Yes Yes

ServerSPN Yes Yes

TransparentNetworkIPResolution Yes Yes

Trusted_Connection Yes Yes

TrustServerCertificate Yes Yes

UID Yes Yes

WSID Yes Yes

If there's a difference in any of the following connection attributes between your connection string and a
pooled connection string, a pooled connection isn't used.

AT T RIB UT E O DB C DRIVER 13+ O DB C DRIVER 11

SQL_ATTR_CURRENT_CATALOG Yes Yes

SQL_ATTR_PACKET_SIZE Yes Yes

SQL_COPT_SS_ANSI_NPW Yes Yes

SQL_COPT_SS_ACCESS_TOKEN Yes No
AT T RIB UT E O DB C DRIVER 13+ O DB C DRIVER 11

SQL_COPT_SS_AUTHENTICATION Yes No

SQL_COPT_SS_ATTACHDBFILENAME Yes Yes

SQL_COPT_SS_BCP Yes Yes

SQL_COPT_SS_COLUMN_ENCRYPTION Yes No

SQL_COPT_SS_CONCAT_NULL Yes Yes

SQL_COPT_SS_ENCRYPT Yes Yes

SQL_COPT_SS_FAILOVER_PARTNER Yes Yes

SQL_COPT_SS_FAILOVER_PARTNER_SPN Yes Yes

SQL_COPT_SS_INTEGRATED_SECURITY Yes Yes

SQL_COPT_SS_MARS_ENABLED Yes Yes

SQL_COPT_SS_OLDPWD Yes Yes

SQL_COPT_SS_SERVER_SPN Yes Yes

SQL_COPT_SS_TRUST_SERVER_CERTIFICATEYes Yes

SSPROP_AUTH_REPL_SERVER_NAME Yes Yes

SQL_COPT_SS_TNIR Yes No

The driver can reset and adjust the following connection keywords and attributes without making an
extra network call. The driver resets these parameters to ensure that the connection doesn't contain
incorrect information.
These connection keywords aren't considered when the Driver Manager tries to match your connection
with a connection in the pool. (Even if you change one of these parameters, an existing connection can be
reused. The driver will reset the options, as needed.) These attributes can be reset in the client side
without making an extra network call.

K EY W O RD O DB C DRIVER 13+ O DB C DRIVER 11

AutoTranslate Yes Yes

Description Yes Yes

MultisubnetFailover Yes Yes

QueryLog_On Yes Yes


K EY W O RD O DB C DRIVER 13+ O DB C DRIVER 11

QueryLogFile Yes Yes

QueryLogTime Yes Yes

Regional Yes Yes

StatsLog_On Yes Yes

StatsLogFile Yes Yes

If you change one of the following connection attributes, an existing connection can be reused. The driver
will reset the value, as needed. The driver can reset these attributes in the client without making an extra
network call.

AT T RIB UT E O DB C DRIVER 13+ O DB C DRIVER 11

All statement attributes Yes Yes

SQL_ATTR_AUTOCOMMIT Yes Yes

SQL_ATTR_CONNECTION_TIMEOUT Yes Yes

SQL_ATTR_DISCONNECT_BEHAVIOR Yes Yes


SQL_ATTR_CONNECTION_TIMEOUT

SQL_ATTR_LOGIN_TIMEOUT Yes Yes

SQL_ATTR_ODBC_CURSORS Yes Yes

SQL_COPT_SS_PERF_DATA Yes Yes

SQL_COPT_SS_PERF_DATA_LOG Yes Yes

SQL_COPT_SS_PERF_DATA_LOG_NOW Yes Yes

SQL_COPT_SS_PERF_QUERY Yes Yes

SQL_COPT_SS_PERF_QUERY_INTERVAL Yes Yes

SQL_COPT_SS_PERF_QUERY_LOG Yes Yes

SQL_COPT_SS_PRESERVE_CURSORS Yes Yes

SQL_COPT_SS_TRANSLATE Yes Yes

SQL_COPT_SS_USER_DATA Yes Yes

SQL_COPT_SS_WARN_ON_CP_ERROR Yes Yes


See Also
Microsoft ODBC Driver for SQL Server on Windows
Asynchronous Execution (Notification Method)
Sample
4/27/2022 • 4 minutes to read • Edit Online

Download ODBC Driver


The code samples in this topic demonstrate how to use the Asynchronous Execution (Notification Method).
This function uses asynchronous notification to open five connections, and executes one query on a statement
of each connection.

#define NUMBER_OPERATIONS 5
int AsyncNotificationSample(void)
{
RETCODE rc;

SQLHENV hEnv = NULL;


SQLHDBC arhDbc[NUMBER_OPERATIONS] = {NULL};
SQLHSTMT arhStmt[NUMBER_OPERATIONS] = {NULL};

HANDLE arhDBCEvent[NUMBER_OPERATIONS] = {NULL};


RETCODE arrcDBC[NUMBER_OPERATIONS] = {0};
HANDLE arhSTMTEvent[NUMBER_OPERATIONS] = {NULL};
RETCODE arrcSTMT[NUMBER_OPERATIONS] = {0};

rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &hEnv);


if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;

rc = SQLSetEnvAttr(hEnv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3_80,
SQL_IS_INTEGER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;

// Connection operations begin here

// Alloc NUMBER_OPERATIONS connection handles


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &arhDbc[i]);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Enable DBC Async on all connection handles


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc= SQLSetConnectAttr(arhDbc[i], SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE,
(SQLPOINTER)SQL_ASYNC_DBC_ENABLE_ON, SQL_IS_INTEGER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Application must create event objects


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
arhDBCEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial state is not-signaled
if (!arhDBCEvent[i]) goto Cleanup;
}

// Enable notification on all connection handles


// Event
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc= SQLSetConnectAttr(arhDbc[i], SQL_ATTR_ASYNC_DBC_EVENT, arhDBCEvent[i], SQL_IS_POINTER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Initiate connect establishing


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLDriverConnect(arhDbc[i], NULL, (SQLTCHAR*)TEXT("Driver={ODBC Driver 11 for SQL
Server};SERVER=your_server;DATABASE=your_database;UID=sa;PWD=your_password;"), SQL_NTS, NULL, 0, NULL,
SQL_DRIVER_NOPROMPT);
}

// Can do some other staff before calling WaitForMultipleObjects


WaitForMultipleObjects(NUMBER_OPERATIONS, arhDBCEvent, TRUE, INFINITE); // Wait All

// Complete connect API calls


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLCompleteAsync(SQL_HANDLE_DBC, arhDbc[i], & arrcDBC[i]);
}

BOOL fFail = FALSE; // Whether some connection opening fails.

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
if ( !SQL_SUCCEEDED(arrcDBC[i]) )
fFail = TRUE;
}

// If some SQLDriverConnect() fail, clean up.


if (fFail)
{
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (SQL_SUCCEEDED(arrcDBC[i]) )
{
SQLDisconnect(arhDbc[i]); // This is also async
}
else
{
SetEvent(arhDBCEvent[i]); // Previous SQLDriverConnect() failed. No need to call
SQLDisconnect().
}
}
WaitForMultipleObjects(NUMBER_OPERATIONS, arhDBCEvent, TRUE, INFINITE);
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (SQL_SUCCEEDED(arrcDBC[i]) )
{
SQLCompleteAsync(SQL_HANDLE_DBC, arhDbc[i], &arrcDBC[i]);; // To Complete
}
}

goto Cleanup;
}

// Statement Operations begin here

// Alloc statement handle


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc = SQLAllocHandle(SQL_HANDLE_STMT, arhDbc[i], &arhStmt[i]);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Enable STMT Async on all statement handles


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc = SQLSetStmtAttr(arhStmt[i], SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_ON,
SQL_IS_INTEGER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Create event objects


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
arhSTMTEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial state is not-
signaled
if (!arhSTMTEvent[i]) goto Cleanup;
}

// Enable notification on all statement handles


// Event
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc= SQLSetStmtAttr(arhStmt[i], SQL_ATTR_ASYNC_STMT_EVENT, arhSTMTEvent[i], SQL_IS_POINTER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Initiate SQLExecDirect() calls


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLExecDirect(arhStmt[i], (SQLTCHAR*)TEXT("select au_lname, au_fname from authors"), SQL_NTS);
}

// Can do some other staff before calling WaitForMultipleObjects


WaitForMultipleObjects(NUMBER_OPERATIONS, arhSTMTEvent, TRUE, INFINITE); // Wait All

// Now, call SQLCompleteAsync to complete the operation and get return code
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLCompleteAsync(SQL_HANDLE_STMT, arhStmt[i], &arrcSTMT[i]);
}

// Check return values


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if ( !SQL_SUCCEEDED(arrcSTMT[i]) ) goto Cleanup;
}

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
//Do some binding jobs here, set SQL_ATTR_ROW_ARRAY_SIZE
}

// Now, initiate fetching


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLFetch(arhStmt[i]);
}

// Can do some other staff before calling WaitForMultipleObjects


WaitForMultipleObjects(NUMBER_OPERATIONS, arhSTMTEvent, TRUE, INFINITE);

// Now, to complete the operations and get return code


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLCompleteAsync(SQL_HANDLE_STMT, arhStmt[i], &arrcSTMT[i]);
}

// Check return code


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if ( !SQL_SUCCEEDED(arrcSTMT[i]) ) goto Cleanup;
}
}

// USE fetched data here!!

Cleanup:

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
if (arhStmt[NUMBER_OPERATIONS])
{
SQLFreeHandle(SQL_HANDLE_STMT, arhStmt[i]);
arhStmt[i] = NULL;
}
}

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
if (arhSTMTEvent[i])
{
CloseHandle(arhSTMTEvent[i]);
arhSTMTEvent[i] = NULL;
}
}

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
if (arhDbc[i])
{
SQLFreeHandle(SQL_HANDLE_DBC, arhDbc[i]);
arhDbc[i] = NULL;
}
}

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
if (arhDBCEvent[i])
{
CloseHandle(arhDBCEvent[i]);
arhDBCEvent[i] = NULL;
}
}

if (hEnv)
{
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
hEnv = NULL;
}

return 0;
}

This function shows a pattern to start multiple operations simultaneously and wait for them when asynchronous
notification is used:

#define ODBCVER 0x0380


#define _SQLNCLI_ODBC

// Global variables

const int g_nConnection = 700;


SQLHENV g_hEnv = NULL;
SQLHDBC g_hDbcs[g_nConnection];
HANDLE g_hevents[g_nConnection];

LONG volatile g_JobDoneNumber;

struct
{
{
char szOutConnectionString[500];
SQLSMALLINT iLen;
} g_connOut[g_nConnection];

void CALLBACK WaitCallBack(PTP_CALLBACK_INSTANCE Inst, PVOID Context, PTP_WAIT Wait, TP_WAIT_RESULT


WaitResult)
{
UINT_PTR i = reinterpret_cast<UINT_PTR>(Context);
SQLRETURN rc ;
SQLCompleteAsync(SQL_HANDLE_DBC, g_hDbcs[(int)i], &rc);
printf("Connection %d done: RC: %d, threadid:%u \n", (int)i, rc, GetCurrentThreadId());
InterlockedIncrement(&g_JobDoneNumber);
}

int _tmain(int argc, _TCHAR* argv[])


{
for(int i = 0; i< g_nConnection; i++)
g_hevents[i] = CreateEvent(NULL, FALSE, FALSE, NULL);

PTP_WAIT waits[g_nConnection];
for(int i = 0; i < g_nConnection; i++)
{
waits[i] = CreateThreadpoolWait(&WaitCallBack, reinterpret_cast<PVOID>((UINT_PTR)i), NULL);
SetThreadpoolWait(waits[i], g_hevents[i], NULL);
}

SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,&g_hEnv);
SQLSetEnvAttr(g_hEnv,SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3_80, SQL_IS_UINTEGER);
for(int i = 0; i < g_nConnection; i++)
{
SQLAllocHandle( SQL_HANDLE_DBC, g_hEnv , &g_hDbcs[i]);
SQLSetConnectAttr(
g_hDbcs[i],
SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE,
(SQLPOINTER)SQL_ASYNC_ENABLE_ON,
SQL_IS_INTEGER);
SQLSetConnectAttr(g_hDbcs[i], SQL_ATTR_ASYNC_DBC_EVENT, g_hevents[i], SQL_IS_POINTER);
}

// make connections
g_JobDoneNumber = 0;
for(int i = 0; i < g_nConnection; i++)
{
SQLDriverConnect(g_hDbcs[i],NULL,
(SQLCHAR*)"DRIVER={ODBC Driver 17 for SQL
Server};Server=your_server;database=your_database;uid=usr;pwd=your_password",
SQL_NTS, (SQLCHAR*)g_connOut[i].szOutConnectionString, 500, &g_connOut[i].iLen,
SQL_DRIVER_NOPROMPT);
}

printf("connect wait..\n");
while(g_JobDoneNumber < g_nConnection)
SleepEx(50, false);

// disconnect
for(int i = 0; i < g_nConnection; i++)
SetThreadpoolWait(waits[i], g_hevents[i], NULL);

printf("disconnect wait..\n");
g_JobDoneNumber = 0;
for(int i = 0; i < g_nConnection; i++)
SQLDisconnect(g_hDbcs[i]);

while(g_JobDoneNumber < g_nConnection)


SleepEx(50, false);

for(int i = 0; i < g_nConnection; i++)


CloseThreadpoolWait(waits[i]);
for(int i = 0; i < g_nConnection; i++)
{
CloseHandle(g_hevents[i]);
SQLFreeHandle(SQL_HANDLE_DBC, g_hDbcs[i]);
}
SQLFreeHandle(SQL_HANDLE_ENV, g_hEnv);
return 0;
}

See Also
Microsoft ODBC Driver for SQL Server on Windows
Data Source Wizard Screen 1
4/27/2022 • 2 minutes to read • Edit Online

Specify the name and description of the data source, and the name of the server running SQL Server to which
the data source will connect.

Options
Name
The data source name used by an ODBC application when it requests a connection to the data source. For
example, "Personnel." The data source name is displayed in the ODBC Data Source Administrator dialog box.
Description
(Optional) A description of the data source. For example, "Hire date, salary history, and current review of all
employees."
Select or enter a server name
The name of an instance of SQL Server on your network. You will need to specify a server in the next edit box.
In most cases, the ODBC driver can connect by using the default protocol order and the server name supplied in
this box. Use SQL Server Configuration Manager if you want to create an alias for the server or configure client
network libraries.
You can enter "(local)" in the server box when you are using the same computer as SQL Server. The user can
then connect to the local instance of SQL Server, even when running a non-networked version of SQL Server.
Multiple instances of SQL Server can run on the same computer. To specify a named instance of SQL Server, the
server name is specified as ServerName\InstanceName.
For more information about server names for different types of networks, see Logging In to SQL Server.
Finish
If the information specified on this screen is all that is needed to connect to SQL Server, you can select Finish .
Defaults are used for all attributes specified on other screens of the wizard.
Next
To proceed to the next screen of the wizard, select Next .

Next steps
Data Source Wizard Screen 2
Data Source Wizard Screen 2
4/27/2022 • 2 minutes to read • Edit Online

Specify the method of authentication, and set up Microsoft SQL Server advanced-client entries and the login
and password the ODBC driver for SQL Server will use to connect to SQL Server while configuring the data
source.

Options
With Integrated Windows Authentication
Specifies that the driver request a secure (or trusted) connection to a SQL Server. When selected, SQL Server
uses integrated login security to establish connections using this data source, regardless of the current login
security mode at the server. Any login ID or password supplied is ignored. The SQL Server system administrator
must have associated your Windows login with a SQL Server login ID (for example, by using SQL Server
Management Studio).
Optionally, you can specify a service principal name (SPN) for the server.
With Active Directory Integrated Authentication
Specifies that the driver authenticate to SQL Server using Azure Active Directory. When selected, SQL Server
uses Azure Active Directory integrated login security to establish a connection using this data source, regardless
of the current login security mode at the server.
With SQL Server authentication
Specifies that the driver authenticate to SQL Server using a login ID and password.
With Active Directory Password authentication
Specifies that the driver authenticate to SQL Server using an Azure Active Directory login ID and password.
With Active Directory Interactive authentication
Specifies that the driver authenticate to SQL Server using Azure Active Directory Interactive mode by providing
login ID. This option will trigger the Azure Authentication prompt dialog.
With Managed Identity authentication
Specifies that the driver authenticate to SQL Server using a Managed Identity.
With Active Directory Service Principal authentication
Specifies that the driver authenticate to SQL Server using an Azure Active Directory Service Principal.
Login ID
Specifies the login ID the driver uses when connecting to SQL Server if With SQL Ser ver Authentication
using a login ID and password entered by the user or With Active Director y Password
authentication using a login ID and password entered by the user or With Active Director y
Interactive authentication using a login ID entered by the user is selected. If With Managed Identity
authentication is selected, specify the object ID of the managed identity or leave blank to use the default
identity. This field only applies to the connection made to determine the server default settings; it does not apply
to subsequent connections made using the data source after it has been created except if using Managed
Identity authentication.
Password
Specifies the password the driver uses when connecting to SQL Server if With SQL Ser ver Authentication
using a login ID and password entered by the user or With Active Director y Password
authentication using a login ID and password entered by the user is selected. This field only applies to
the connection made to determine the server default settings; it does not apply to subsequent connections
made using the new data source.
Both the Login ID and Password boxes are disabled if With Integrated Windows authentication or With
Active Director y Integrated authentication is selected.
Next
Proceeds to the next screen of the wizard.
Back
Returns to the previous screen of the wizard.

Next steps
Data Source Wizard Screen 1
Data Source Wizard Screen 3
Data Source Wizard Screen 3
4/27/2022 • 3 minutes to read • Edit Online

Specify the default database, various ANSI options to be used by the driver, and the name of a mirror server.

Options
Change the default database to
Specifies the name of the default database for any connection made using this data source. When this box is
cleared, connections use the default database defined for the login ID on the server. When this box is selected,
the database named in the box overrides the default database defined for the login ID. If the Attach database
filename box has the name of a primary file, the database described by the primary file is attached as a
database using the database name specified in the Change the default database to box.
Using the default database for the login ID is more efficient than specifying a default database in the ODBC data
source.
Mirror server
Specifies the name of the failover partner of the database to be mirrored. If a database name is not shown in the
Change the default database to box, or the name shown is the default database, Mirror Ser ver is grayed
out.
Optionally, you can specify a server principal name (SPN) for the mirror server. The SPN for the mirror server is
used for mutual authentication between client and server.
Attach database filename
Specifies the name of the primary file for an attachable database. This database is attached and used as the
default database for the data source. Specify the full path and file name for the primary file. The database name
specified in the Change the default database to box is used as the name for the attached database.
Use ANSI quoted identifiers
Specifies that QUOTED_IDENTIFIERS is set to on when the ODBC driver for SQL Server connects. When this check
box is selected, SQL Server enforces ANSI rules regarding quote marks. Double quotes can only be used for
identifiers, such as column and table names. Character strings must be enclosed in single quotes:

SELECT "LastName"
FROM "Person.Contact"
WHERE "LastName" = 'O''Brien'

When this check box is cleared, applications that use quoted identifiers, such as the Microsoft Query utility that
comes with Microsoft Excel, encounter errors when they generate SQL statements with quoted identifiers.
Use ANSI nulls, paddings, and warnings
Specifies that the ANSI_NULLS, ANSI_WARNINGS, and ANSI_PADDINGS options be set on when the ODBC
Driver for SQL Server connects.
With ANSI_NULLS set on, the server enforces ANSI rules regarding comparing columns for NULL. The ANSI
syntax "IS NULL" or "IS NOT NULL" must be used for all NULL comparisons. The Transact-SQL syntax "= NULL"
is not supported.
With ANSI_WARNINGS set on, SQL Server issues warning messages for conditions that violate ANSI rules but
do not violate the rules of Transact-SQL. Examples of such errors are data truncation on execution of an INSERT
or UPDATE statement, or encountering a null value during an aggregate function.
With ANSI_PADDING set on, trailing blanks on varchar values and trailing zeroes on varbinar y values are not
automatically trimmed.
Application intent
Declares the application workload type when connecting to a server. Possible values are ReadOnly and
ReadWrite .
Multi-subnet failover
If your application is connecting to a high-availability, disaster recovery (AlwaysOn Availability Groups)
availability group (AG) on different subnets, enabling Multi-subnet failover. configures ODBC Driver for SQL
Server to provide faster detection of and connection to the (currently) active server.
Transparent Network IP Resolution
Alters the behavior of Multi-subnet failover to allow for faster reconnection during failover. For more
information, see Using Transparent Network IP Resolution.
Column Encryption
Enables automatic decryption and encryption of data transfers to and from columns encrypted with the Always
Encrypted feature available in SQL Server 2016 and later.
Use FMTONLY metadata discovery
Use the legacy SET FMTONLY metadata discovery method when connecting to SQL Server 2012 or newer.
Enable this option only when using queries not supported by sp_describe_first_result_set, such as those
containing temporary tables.
Next
Proceeds to the next screen of the wizard.
Back
Returns to the previous screen of the wizard.

Next steps
Data Source Wizard Screen 2
Data Source Wizard Screen 4
Data Source Wizard Screen 4
4/27/2022 • 4 minutes to read • Edit Online

Specify the language to be used for SQL Server messages, the character set translation, and whether the ODBC
driver for SQL Server should use regional settings. You can also control the logging of long-running queries and
driver statistics settings.

Options
Change the language of SQL Server system messages to
Each instance of SQL Server can have multiple sets of system messages, with each set in a different language
(for example, English, Spanish, French, and so on). If a data source is defined against a server that has multiple
sets of system messages, you can specify which language you want to use for system messages. In the list, select
the language. This option is unavailable if only one language is installed on the SQL Server.
Use strong encryption for data
When selected, data that is passed through connections that are made using this DSN will be encrypted. Logins
are encrypted by default, even if the check box is cleared. This option is available in ODBC Driver 17 and older.
Connection Encryption
Declares the connection encryption mode to be used when connections are made using this DSN. Selecting the
Optional or Mandator y option is equivalent to having Use strong encr yption for data unselected or
selected, respectively. When Strict is used, connections will be encrypted using TDS 8.0. This option is available
in ODBC Driver 18 and newer.
Trust server certificate
This option is applicable only when Use strong encr yption for data is enabled (ODBC Driver 17 and older),
or when Connection Encr yption is set to Optional or Mandator y (ODBC Driver 18 and newer). When
selected, the server's certificate won't be validated to have the correct hostname of the server and be issued by a
trusted certificate authority. The server's certificate will always be validated when using the Strict encryption
mode.
Hostname in certificate (optional)
Specifies the hostname to be used when validating the server's certificate. When left blank, the server name is
used as the hostname for validation. A hostname can only be specified when Trust ser ver cer tificate is
unselected. This option is available in ODBC Driver 18 and newer.
Perform translation for character data
When this check box is selected, the ODBC driver for SQL Server converts ANSI strings sent between the client
computer and SQL Server by using Unicode. The ODBC driver sometimes converts between the SQL Server
code page and Unicode on the client computer. This option requires that the code page used by SQL Server is
one of the code pages available on the client computer.
When this check box is cleared, no translation of extended characters in ANSI character strings is done when
they're sent between the client application and the server. If the client computer is using an ANSI code page
(ACP) different from the SQL Server code page, extended characters in ANSI character strings may be
misinterpreted. If the client computer is using the same code page for its ACP that SQL Server is using, the
extended characters are interpreted correctly.
Use regional settings when outputting currency, numbers, dates, and times
Specifies that the driver use the regional settings of the client computer for formatting currency, numbers, dates,
and times in character output strings. The driver uses the default regional setting for the Windows login account
of the user connecting through the data source. Select this option for applications that only display data, not for
applications that process data.
Save long running queries to the log file
Specifies that the driver log any query that takes longer than the Long quer y time value. Long-running
queries are logged to the specified file. To specify a log file, either type the full path and file name in the box, or
select Browse to select a log file by navigating through existing file directories.
Long query time (milliseconds)
Specifies a threshold value, in milliseconds, for long-running query logging. Any query that takes longer than
this number of milliseconds to run is logged.
Log ODBC driver statistics to the log file
Specifies that statistics be logged. Statistics are logged to the specified file. To specify a log file, either type the
full path and file name in the box or select Browse to select a log file by navigating through existing file
directories.
The statistics log is a tab-delimited file that can be analyzed in Microsoft Excel or any other application that
supports tab-delimited files.
Connect retry count
Specifies the number of times to retry an unsuccessful connection attempt.
Connect retry interval (seconds)
Specifies the number of seconds between each connection retry attempt. For more information on the operation
of this option and the Connect retr y count options, see Connection Resiliency.
Back
Select this button to go back to the previous page of the wizard.
Finish
If the information specified on this screen is complete, you can select Finish . The DSN is created using all
attributes specified on this and other screens of the wizard, and you're given an opportunity to test the newly
created DSN.

Next steps
Data Source Wizard Screen 3
SQL Server Login Dialog Box (ODBC)
4/27/2022 • 3 minutes to read • Edit Online

When you call an ODBC connection without specifying enough information for the driver to connect to a SQL
Server, the ODBC driver displays the SQL Ser ver Login dialog box.

Options
Server
The name of an instance of SQL Server on your network. Select a server\instance name from the list, or type the
server\instance name in the Ser ver box. Optionally, you can create a server alias on the client computer using
SQL Ser ver Configuration Manager , and type that name in the Ser ver box.
You can enter "(local)" when you are using the same computer as SQL Server. You can then connect to a local
instance of SQL Server, even when running a non-networked version of SQL Server.
For more information about server names for different types of networks, see the SQL Server installation
documentation in SQL Server Books Online.
Authentication Mode
Selects the authentication mode from one of the following:
SQL Ser ver with login ID and password
Windows Integrated authentication using the currently logged-in user's account
Active Director y Password with login ID and password
Active Director y Integrated authentication using the currently logged-in user's account
Active Director y Interactive authentication with login ID
Managed Ser vice Identity authentication with Managed Identity
Active Director y Ser vice Principal authentication with Azure Active Directory service principal
See Data Source Wizard Screen 2 for more information on the authentication modes.
Server SPN
If you use a trusted connection, you can specify a service principal name (SPN) for the server.
Login ID
Specifies the SQL Server or Azure Active Directory login ID to use for the connection if Authentication Mode
is set to SQL Ser ver , Active Director y Password , Active Director y Interactive , Managed Ser vice
Identity , or Active Director y Ser vice Principal . Otherwise, the Login ID box is disabled.
Password
Specifies the password for the SQL Server or Azure Active Directory login ID used for the connection if
Authentication Mode is set to SQL Ser ver or Active Director y Password . Otherwise, the Password box is
disabled.
Options
Displays or hides the Options group. The Options button is enabled if Ser ver has a value.
Change Password
When this box is selected, displays the New Password and Confirm New Password boxes.
New Password
Specifies the new password.
Confirm New Password
Specifies the new password a second time, for confirmation.
Database
Specifies the default database to use on the connection. This setting overrides the default database specified for
the login on the server. If no database is specified, the connection uses the default database specified for the
login on the server.
Mirror Server
Specifies the name of the failover partner of the database to be mirrored.
Mirror SPN
Optionally, you can specify an SPN for the mirror server. The SPN for the mirror server is used for mutual
authentication between client and server.
Language
Specifies the national language to use for SQL Server system messages. The computer running SQL Server
must have the language installed. This setting overrides the default language specified for the login on the
server. If no language is specified, the connection uses the default language specified for the login on the server.
Application Name
(Optional) Specifies the application name to be stored in the program_name column in the row for this
connection in sys.sysprocesses .
Workstation ID
(Optional) Specifies the workstation ID to be stored in the hostname column in the row for this connection in
sys.sysprocesses .
Use strong encryption for data
When selected, data that is passed through the connection will be encrypted. Logins are encrypted by default,
even if the check box is cleared. This option is available in ODBC Driver 17 and older.
Connection Encryption
Declares the connection encryption mode to be used. Selecting the Optional or Mandator y option is
equivalent to having Use strong encr yption for data unselected or selected, respectively. When Strict is
used, the connection will be encrypted using TDS 8.0. This option is available in ODBC Driver 18 and newer.
Hostname in certificate (optional)
Specifies the hostname to be used when validating the server's certificate. When left blank, the server name is
used as the hostname for validation. A hostname can only be specified when Trust ser ver cer tificate is
unselected. This option is available in ODBC Driver 18 and newer.
Trust server certificate
This option is applicable only when Use strong encr yption for data is enabled (ODBC Driver 17 and older),
or when Connection Encr yption is set to Optional or Mandator y (ODBC Driver 18 and newer). When
selected, the server's certificate won't be validated to have the correct hostname of the server and be issued by a
trusted certificate authority. The server's certificate will always be validated when using the Strict encryption
mode.

See Also
Microsoft ODBC Driver for SQL Server on Windows
Connection resiliency in the ODBC driver
4/27/2022 • 4 minutes to read • Edit Online

Download ODBC Driver


To ensure that applications remain connected to an Azure SQL Database, the ODBC driver on Windows can
restore idle connections.

IMPORTANT
The connection resiliency feature is supported on Microsoft Azure SQL Database and SQL Server 2014 (and later) server
versions.
The feature is available on Windows starting with Microsoft ODBC Driver 11 for SQL Server. It is available on Linux
starting in version 17.2 of Microsoft ODBC Driver 17 for SQL Server.

For more information about idle connection resiliency, see Technical Article - Idle Connection Resiliency.
To control reconnect behavior, the ODBC Driver for SQL Server on Windows has two options:
Connection retry count.
Connect retry count controls the number of reconnection attempts if there's a connection failure. Valid
values range from 0 to 255. Zero (0) means don't attempt to reconnect. The default value is one
reconnection attempt.
You can modify the number of connection retries when you:
Define or modify a data source that uses the ODBC Driver for SQL Server with the Connection
Retr y Count control.
Use the ConnectRetryCount connection string keyword.
To retrieve the number of connection retry attempts, use the SQL_COPT_SS_CONNECT_RETRY_COUNT
(read only) connection attribute. If an application connects to a server that doesn't support
connection resiliency, SQL_COPT_SS_CONNECT_RETRY_COUNT returns 0.
Connect retry interval.
The connect retry interval specifies the number of seconds between each connection retry attempt. Valid
values are 1-60. The total time to reconnect can't exceed the connection timeout
(SQL_ATTR_QUERY_TIMEOUT in SQLSetStmtAttr). The default value is 10 seconds.
You can modify the connection retry interval when you:
Define or modify a data source that uses the ODBC Driver for SQL Server with the Connect Retr y
Inter val control.
Use the ConnectRetryInterval connection string keyword.
To retrieve the length of the connection retry interval, use the SQL_COPT_SS_CONNECT_RETRY_INTERVAL
(read only) connection attribute.
If an application establishes a connection with SQL_DRIVER_COMPLETE_REQUIRED and later tries to execute a
statement over a broken connection, the ODBC driver won't display the dialog box again. Also, during recovery
in progress,
During recovery, any call to SQLGetConnectAttr(SQL_COPT_SS_CONNECTION_DEAD) , must return SQL_CD_FALSE .
If recovery fails, any call to SQLGetConnectAttr(SQL_COPT_SS_CONNECTION_DEAD) , must return SQL_CD_TRUE .
The following state codes are returned by any function that executes a command on the server:

STAT E M ESSA GE

IMC01 The connection is broken and recovery is not


possible. The client driver attempted to recover
the connection one or more times and all attempts
failed. Increase the value of ConnectRetryCount to
increase the number of recovery attempts.

IMC02 The server did not acknowledge a recovery attempt,


connection recovery is not possible.

IMC03 The server did not preserve the exact client TDS
version requested during a recovery attempt,
connection recovery is not possible.

IMC04 The server did not preserve the exact server major
version requested during a recovery attempt,
connection recovery is not possible.

IMC05 The connection is broken and recovery is not


possible. The connection is marked by the server as
unrecoverable. No attempt was made to restore the
connection.

IMC06 The connection is broken and recovery is not


possible. The connection is marked by the client
driver as unrecoverable. No attempt was made to
restore the connection.

Example
The following sample contains two functions. func1 shows how you can connect with a data source name
(DSN) that uses the ODBC Driver for SQL Server on Windows. The DSN uses SQL Server Authentication, and it
specifies the user ID. func1 then retrieves the number of connection retries with
SQL_COPT_SS_CONNECT_RETRY_COUNT .

func2 uses SQLDriverConnect , ConnectRetryCount connection string keyword, and connection attributes to
retrieve the setting for connection retries and retry interval.

// Connection_resiliency.cpp
// compile with: odbc32.lib
#include <windows.h>
#include <stdio.h>
#include <sqlext.h>
#include <msodbcsql.h>

void func1() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
SQLSMALLINT i = 21;

// Allocate environment handle


retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
// Set the ODBC version environment attribute
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

// Allocate connection handle


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

// Set login timeout to 5 seconds


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

// Connect to data source


retcode = SQLConnect(hdbc, (SQLCHAR*)"MyDSN", SQL_NTS, (SQLCHAR*)"userID", SQL_NTS,
(SQLCHAR*)"password_for_userID", SQL_NTS);
retcode = SQLGetConnectAttr(hdbc, SQL_COPT_SS_CONNECT_RETRY_COUNT, &i, SQL_IS_INTEGER,
NULL);

// Allocate statement handle


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

// Process data
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}

SQLDisconnect(hdbc);
}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
}

void func2() {
SQLHENV henv;
SQLHDBC hdbc1;
SQLHSTMT hstmt;
SQLRETURN retcode;
SQLSMALLINT i = 21;

#define MAXBUFLEN 255

SQLCHAR ConnStrIn[MAXBUFLEN] = "DRIVER={ODBC Driver 17 for SQL


Server};SERVER=server_that_supports_connection_resiliency;UID=userID;PWD=
password_for_userID;ConnectRetryCount=2";
SQLCHAR ConnStrOut[MAXBUFLEN];

SQLSMALLINT cbConnStrOut = 0;

// Allocate environment handle


retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

// Set the ODBC version environment attribute


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3_80, SQL_IS_INTEGER);

// Allocate connection handle


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);

// Set login timeout to 5 seconds


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
// SQLSetConnectAttr(hdbc1, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
retcode = SQLDriverConnect(hdbc1, NULL, ConnStrIn, SQL_NTS, NULL, 0, NULL,
SQL_DRIVER_NOPROMPT);
}
retcode = SQLGetConnectAttr(hdbc1, SQL_COPT_SS_CONNECT_RETRY_COUNT, &i, SQL_IS_INTEGER, NULL);
retcode = SQLGetConnectAttr(hdbc1, SQL_COPT_SS_CONNECT_RETRY_INTERVAL, &i, SQL_IS_INTEGER,
NULL);
}
}
}

int main() {
func1();
func2();
}

See also
Microsoft ODBC Driver for SQL Server
Custom Keystore Providers
4/27/2022 • 18 minutes to read • Edit Online

Download ODBC Driver

Overview
The column encryption feature of SQL Server 2016 requires that the Encrypted Column Encryption Keys
(ECEKs) stored on the server are retrieved by the client and then decrypted to Column Encryption Keys (CEKs) in
order to access the data stored in encrypted columns. ECEKs are encrypted by Column Master Keys (CMKs), and
the security of the CMK is important to the security of column encryption. Thus, the CMK should be stored in a
secure location; the purpose of a Column Encryption Keystore Provider is to provide an interface to allow the
ODBC driver to access these securely stored CMKs. For users with their own secure storage, the Custom
Keystore Provider Interface provides a framework for implementing access to secure storage of the CMK for the
ODBC driver, which can then be used to perform CEK encryption and decryption.
Each keystore provider contains and manages one or more CMKs, which are identified by key paths - strings of
a format defined by the provider. This CMK, along with the encryption algorithm, also a string defined by the
provider, can be used to perform the encryption of a CEK and the decryption of an ECEK. The algorithm, along
with the ECEK and the name of the provider, are stored in the database's encryption metadata. For more
information, see CREATE COLUMN MASTER KEY and CREATE COLUMN ENCRYPTION KEY. Thus, the two
fundamental operations of key management are:

CEK = DecryptViaCEKeystoreProvider(CEKeystoreProvider_name, Key_path, Key_algorithm, ECEK)

-and-

ECEK = EncryptViaCEKeystoreProvider(CEKeyStoreProvider_name, Key_path, Key_algorithm, CEK)

where the CEKeystoreProvider_name is used to identify the specific Column Encryption Keystore Provider
(CEKeystoreProvider), and the other arguments are used by the CEKeystoreProvider to encrypt/decrypt the
(E)CEK. The name and key path are provided by the CMK metadata, while the algorithm and ECEK value are
provided by the CEK metadata. Multiple keystore providers may be present alongside the default built-in
provider(s). Upon performing an operation that requires the CEK, the driver uses the CMK metadata to find the
appropriate keystore provider by name, and executes its decryption operation, which can be expressed as:

CEK = CEKeyStoreProvider_specific_decrypt(Key_path, Key_algorithm, ECEK)

Although the driver has no need to encrypt CEKs, a key management tool may need to do so in order to
implement operations such as CMK creation and rotation. These actions require performing the inverse
operation:

ECEK = CEKeyStoreProvider_specific_encrypt(Key_path, Key_algorithm, CEK)

CEKeyStoreProvider interface
This document describes in detail the CEKeyStoreProvider interface. A keystore provider that implements this
interface can be used by the Microsoft ODBC Driver for SQL Server. CEKeyStoreProvider implementers can use
this guide to develop custom keystore providers usable by the driver.
A keystore provider library ("provider library") is a dynamic-link library that can be loaded by the ODBC driver,
and contains one or more keystore providers. The symbol CEKeystoreProvider must be exported by a provider
library, and be the address of a null-terminated array of pointers to CEKeystoreProvider structures, one for each
keystore provider within the library.
A CEKeystoreProvider structure defines the entry points of a single keystore provider:

typedef struct CEKeystoreProvider {


wchar_t *Name;
int (*Init)(CEKEYSTORECONTEXT *ctx, errFunc *onError);
int (*Read)(CEKEYSTORECONTEXT *ctx, errFunc *onError, void *data, unsigned int *len);
int (*Write)(CEKEYSTORECONTEXT *ctx, errFunc *onError, void *data, unsigned int len);
int (*DecryptCEK)( CEKEYSTORECONTEXT *ctx,
errFunc *onError,
const wchar_t *keyPath,
const wchar_t *alg,
unsigned char *ecek,
unsigned short ecekLen,
unsigned char **cekOut,
unsigned short *cekLen);
int (*EncryptCEK)( CEKEYSTORECONTEXT *ctx,
errFunc *onError,
const wchar_t *keyPath,
const wchar_t *alg,
unsigned char *cek,
unsigned short cekLen,
unsigned char **ecekOut,
unsigned short *ecekLen);
void (*Free)();
} CEKEYSTOREPROVIDER;

F IEL D N A M E DESC RIP T IO N

Name The name of the keystore provider. It must not be the same
as any other keystore provider previously loaded by the
driver or present in this library. Null-terminated, wide-
character* string.

Init Initialization function. If an initialization function is not


required, this field may be null.

Read Provider read function. May be null if not required.

Write Provider write function. Required if Read is not null. May be


null if not required.

DecryptCEK ECEK decryption function. This function is the reason for


existence of a keystore provider, and must not be null.

EncryptCEK CEK encryption function. The driver does not call this
function, but it is provided to allow for programmatic access
to ECEK creation by key management tools. May be null if
not required.

Free Termination function. May be null if not required.

Except for Free, the functions in this interface all have a pair of parameters, ctx and onError . The former
identifies the context in which the function is called, while the latter is used for reporting errors. For more
information, see Contexts and Error Handling below.
int Init(CEKEYSTORECONTEXT *ctx, errFunc onError);

Placeholder name for a provider-defined initialization function. The driver calls this function once, after a
provider has been loaded, but before the first time it needs it to perform ECEK decryption or Read()/Write()
requests. Use this function to perform any initialization it needs.

A RGUM EN T DESC RIP T IO N

ctx [Input] Operation context.

onError [Input] Error-reporting function.

Return Value Return nonzero to indicate success, or zero to indicate


failure.

int Read(CEKEYSTORECONTEXT *ctx, errFunc onError, void *data, unsigned int *len);

Placeholder name for a provider-defined communication function. The driver calls this function when the
application requests to read data from a (previously written to) provider using the
SQL_COPT_SS_CEKEYSTOREDATA connection attribute, allowing the application to read arbitrary data from the
provider. For more information, see Communicating with Keystore Providers.

A RGUM EN T DESC RIP T IO N

ctx [Input] Operation context.

onError [Input] Error-reporting function.

data [Output] Pointer to a buffer in which the provider writes data


to be read by the application. This buffer corresponds to the
data field of the CEKEYSTOREDATA structure.

len [InOut] Pointer to a length value; upon input, this value is


the maximum length of the data buffer, and the provider
shall not write more than *len bytes to it. Upon return,
the provider should update *len with the number of bytes
written.

Return Value Return nonzero to indicate success, or zero to indicate


failure.

int Write(CEKEYSTORECONTEXT *ctx, errFunc onError, void *data, unsigned int len);

Placeholder name for a provider-defined communication function. The driver calls this function when the
application requests to write data to a provider using the SQL_COPT_SS_CEKEYSTOREDATA connection attribute,
allowing the application to write arbitrary data to the provider. For more information, see Communicating with
Keystore Providers.

A RGUM EN T DESC RIP T IO N

ctx [Input] Operation context.


A RGUM EN T DESC RIP T IO N

onError [Input] Error-reporting function.

data [Input] Pointer to a buffer containing the data for the


provider to read. This buffer corresponds to the data field of
the CEKEYSTOREDATA structure. The provider must not read
more than len bytes from this buffer.

len [Input] The number of bytes available in data. This value


corresponds to the dataSize field of the CEKEYSTOREDATA
structure.

Return Value Return nonzero to indicate success, or zero to indicate


failure.

int (*DecryptCEK)( CEKEYSTORECONTEXT *ctx, errFunc *onError, const wchar_t *keyPath, const wchar_t *alg,
unsigned char *ecek, unsigned short ecekLen, unsigned char **cekOut, unsigned short *cekLen);

Placeholder name for a provider-defined ECEK decryption function. The driver calls this function to decrypt an
ECEK encrypted by a CMK associated with this provider into a CEK.

A RGUM EN T DESC RIP T IO N

ctx [Input] Operation context.

onError [Input] Error-reporting function.

keyPath [Input] The value of the KEY_PATH metadata attribute for the
CMK referenced by the given ECEK. Null-terminated wide-
character* string. This value is intended to identify a CMK
handled by this provider.

alg [Input] The value of the ALGORITHM metadata attribute for


the given ECEK. Null-terminated wide-character* string. This
value is intended to identify the encryption algorithm used
to encrypt the given ECEK.

ecek [Input] Pointer to the ECEK to be decrypted.

ecekLen [Input] Length of the ECEK.

cekOut [Output] The provider shall allocate memory for the


decrypted ECEK and write its address to the pointer pointed
to by cekOut. It must be possible to free this block of
memory using the LocalFree (Windows) or free
(Linux/macOS) function. If no memory was allocated due to
an error or otherwise, the provider shall set *cekOut to a null
pointer.

cekLen [Output] The provider shall write to the address pointed to


by cekLen the length of the decrypted ECEK that it has
written to **cekOut.
A RGUM EN T DESC RIP T IO N

Return Value Return nonzero to indicate success, or zero to indicate


failure.

int (*EncryptCEK)( CEKEYSTORECONTEXT *ctx, errFunc *onError, const wchar_t *keyPath, const wchar_t *alg,
unsigned char *cek,unsigned short cekLen, unsigned char **ecekOut, unsigned short *ecekLen);

Placeholder name for a provider-defined CEK encryption function. The driver does not call this function nor
expose its functionality through the ODBC interface, but it is provided to allow for programmatic access to ECEK
creation by key management tools.

A RGUM EN T DESC RIP T IO N

ctx [Input] Operation context.

onError [Input] Error-reporting function.

keyPath [Input] The value of the KEY_PATH metadata attribute for the
CMK referenced by the given ECEK. Null-terminated wide-
character* string. This value is intended to identify a CMK
handled by this provider.

alg [Input] The value of the ALGORITHM metadata attribute for


the given ECEK. Null-terminated wide-character* string. This
value is intended to identify the encryption algorithm used
to encrypt the given ECEK.

cek [Input] Pointer to the CEK to be encrypted.

cekLen [Input] Length of the CEK.

ecekOut [Output] The provider shall allocate memory for the


encrypted CEK and write its address to the pointer pointed
to by ecekOut. It must be possible to free this block of
memory using the LocalFree (Windows) or free
(Linux/macOS) function. If no memory was allocated due to
an error or otherwise, the provider shall set *ecekOut to a
null pointer.

ecekLen [Output] The provider shall write to the address pointed to


by ecekLen the length of the encrypted CEK that it has
written to **ecekOut.

Return Value Return nonzero to indicate success, or zero to indicate


failure.

void (*Free)();

Placeholder name for a provider-defined termination function. The driver may call this function upon normal
termination of the process.
NOTE
Wide-character strings are 2-byte characters (UTF-16) due to how SQL Server stores them.

Error Handling
As errors may occur during a provider's processing, a mechanism is provided to allow it to report errors back to
the driver in more specific detail than a boolean success/failure. Many of the functions have a pair of
parameters, ctx and onError , which are used together for this purpose in addition to the success/failure return
value.
The ctx parameter identifies the context in which a provider operation occurs.
The onError parameter points to an error-reporting function, with the following prototype:
typedef void errFunc(CEKEYSTORECONTEXT *ctx, const wchar_t *msg, ...);

A RGUM EN T DESC RIP T IO N

ctx [Input] The context to report the error on.

msg [Input] The error message to report. Null-terminated wide-


character string. To allow parameterized information, this
string may contain insert-formatting sequences of the form
accepted by the FormatMessage function. Extended
functionality may be specified by this parameter as described
below.

... [Input] Extra variadic parameters to fit format specifiers in


msg, as appropriate.

To report when an error has occurred, the provider calls onError, supplying the context parameter passed into
the provider function by the driver and an error message with optional extra parameters to be formatted in it.
The provider may call this function multiple times to post multiple error messages consecutively within one
provider-function invocation. For example:

if (!doSomething(...))
{
onError(ctx, L"An error occurred in doSomething.");
onError(ctx, L"Additional error message with more details.");
return 0;
}

The msg parameter is ordinarily a wide-character string, but more extensions are available:
By using one of the special predefined values with the IDS_MSG macro, generic error messages already existing
and in a localized form in the driver may be utilized. For example, if a provider fails to allocate memory, the
IDS_S1_001 "Memory allocation failure" message can be used:

onError(ctx, IDS_MSG(IDS_S1_001));

For the error to be recognized by the driver, the provider function must return failure. When a failure happens in
the context of an ODBC operation, the posted errors will become accessible on the connection or statement
handle via the standard ODBC diagnostics mechanism ( SQLError , SQLGetDiagRec , and SQLGetDiagField ).
Context Association
The CEKEYSTORECONTEXT structure, in addition to providing context for the error callback, can also be used to
determine the ODBC context in which a provider operation is executed. This context allows a provider to
associate data to each of these contexts, for example, to implement per-connection configuration. For this
purpose, the structure contains three opaque pointers corresponding to the environment, connection, and
statement context:

typedef struct CEKeystoreContext


{
void *envCtx;
void *dbcCtx;
void *stmtCtx;
} CEKEYSTORECONTEXT;

F IEL D DESC RIP T IO N

envCtx Environment context.

dbcCtx Connection context.

stmtCtx Statement context.

Each of these contexts is an opaque value which, while not the same as the corresponding ODBC handle, can be
used as a unique identifier for the handle: if handle X is associated with context value Y, then no other
environment, connection, or statement handles that exist simultaneously at the same time as X will have a
context value of Y, and no other context values will be associated with handle X. If the provider operation being
accomplished lacks a particular handle context (for example, SQLSetConnectAttr calls to load and configure
providers, in which there is no statement handle), the corresponding context value in the structure is null.

Example
Keystore Provider
The following code is an example of a minimal keystore provider implementation.

/* Custom Keystore Provider Example

Windows: compile with cl MyKSP.c /LD /MD /link /out:MyKSP.dll


Linux/macOS: compile with gcc -fshort-wchar -fPIC -o MyKSP.so -shared MyKSP.c

*/

#ifdef _WIN32
#include <windows.h>
#else
#define __stdcall
#endif

#include <stdlib.h>
#include <sqltypes.h>
#include "msodbcsql.h"
#include <sql.h>
#include <sqlext.h>

int __stdcall KeystoreInit(CEKEYSTORECONTEXT *ctx, errFunc *onError) {


printf("KSP Init() function called\n");
return 1;
}

static unsigned char *g_encryptKey;


static unsigned int g_encryptKeyLen;
int __stdcall KeystoreWrite(CEKEYSTORECONTEXT *ctx, errFunc *onError, void *data, unsigned int len) {
printf("KSP Write() function called (%d bytes)\n", len);
if (len) {
if (g_encryptKey)
free(g_encryptKey);
g_encryptKey = malloc(len);
if (!g_encryptKey) {
onError(ctx, L"Memory Allocation Error");
return 0;
}
memcpy(g_encryptKey, data, len);
g_encryptKeyLen = len;
}
return 1;
}

// Very simple "encryption" scheme - rotating XOR with the key


int __stdcall KeystoreDecrypt(CEKEYSTORECONTEXT *ctx, errFunc *onError, const wchar_t *keyPath, const
wchar_t *alg,
unsigned char *ecek, unsigned short ecekLen, unsigned char **cekOut, unsigned short *cekLen) {
unsigned int i;
printf("KSP Decrypt() function called (keypath=%S alg=%S ecekLen=%u)\n", keyPath, alg, ecekLen);
if (wcscmp(keyPath, L"TheOneAndOnlyKey")) {
onError(ctx, L"Invalid key path");
return 0;
}
if (wcscmp(alg, L"none")) {
onError(ctx, L"Invalid algorithm");
return 0;
}
if (!g_encryptKey) {
onError(ctx, L"Keystore provider not initialized with key");
return 0;
}
#ifndef _WIN32
*cekOut = malloc(ecekLen);
#else
*cekOut = LocalAlloc(LMEM_FIXED, ecekLen);
#endif
if (!*cekOut) {
onError(ctx, L"Memory Allocation Error");
return 0;
}
*cekLen = ecekLen;
for (i = 0; i < ecekLen; i++)
(*cekOut)[i] = ecek[i] ^ g_encryptKey[i % g_encryptKeyLen];
return 1;
}

// Note that in the provider interface, this function would be referenced via the CEKEYSTOREPROVIDER
// structure. However, that does not preclude keystore providers from exporting their own functions,
// as illustrated by this example where the encryption is performed via a separate function (with a
// different prototype than the one in the KSP interface.)
#ifdef _WIN32
__declspec(dllexport)
#endif
int KeystoreEncrypt(CEKEYSTORECONTEXT *ctx, errFunc *onError,
unsigned char *cek, unsigned short cekLen,
unsigned char **ecekOut, unsigned short *ecekLen) {
unsigned int i;
printf("KSP Encrypt() function called (cekLen=%u)\n", cekLen);
if (!g_encryptKey) {
onError(ctx, L"Keystore provider not initialized with key");
return 0;
}
*ecekOut = malloc(cekLen);
if (!*ecekOut) {
onError(ctx, L"Memory Allocation Error");
return 0;
return 0;
}
*ecekLen = cekLen;
for (i = 0; i < cekLen; i++)
(*ecekOut)[i] = cek[i] ^ g_encryptKey[i % g_encryptKeyLen];
return 1;
}

CEKEYSTOREPROVIDER MyCustomKSPName_desc = {
L"MyCustomKSPName",
KeystoreInit,
0,
KeystoreWrite,
KeystoreDecrypt,
0
};

#ifdef _WIN32
__declspec(dllexport)
#endif
CEKEYSTOREPROVIDER *CEKeystoreProvider[] = {
&MyCustomKSPName_desc,
0
};

ODBC Application
The following code is a demo application that uses the keystore provider above. When running it, ensure that
the provider library is in the same directory as the application binary, and that the connection string specifies (or
specifies a DSN that contains) the ColumnEncryption=Enabled setting.

/*
Example application for demonstration of custom keystore provider usage

Windows: compile with cl /MD kspapp.c /link odbc32.lib


Linux/macOS: compile with gcc -o kspapp -fshort-wchar kspapp.c -lodbc -ldl

usage: kspapp connstr

*/

#define KSPNAME L"MyCustomKSPName"


#define PROV_ENCRYPT_KEY "JHKCWYT06N3RG98J0MBLG4E3"

#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
#else
#define __stdcall
#include <dlfcn.h>
#endif
#include <sql.h>
#include <sqlext.h>
#include "msodbcsql.h"

/* Convenience functions */

int checkRC(SQLRETURN rc, char *msg, int ret, SQLHANDLE h, SQLSMALLINT ht) {
if (rc == SQL_ERROR) {
fprintf(stderr, "Error occurred upon %s\n", msg);
if (h) {
SQLSMALLINT i = 0;
SQLSMALLINT outlen = 0;
char errmsg[1024];
while ((rc = SQLGetDiagField(
ht, h, ++i, SQL_DIAG_MESSAGE_TEXT, errmsg, sizeof(errmsg), &outlen)) == SQL_SUCCESS
|| rc == SQL_SUCCESS_WITH_INFO) {
|| rc == SQL_SUCCESS_WITH_INFO) {
fprintf(stderr, "Err#%d: %s\n", i, errmsg);
}
}
if (ret)
exit(ret);
return 0;
}
else if (rc == SQL_SUCCESS_WITH_INFO && h) {
SQLSMALLINT i = 0;
SQLSMALLINT outlen = 0;
char errmsg[1024];
printf("Success with info for %s:\n", msg);
while ((rc = SQLGetDiagField(
ht, h, ++i, SQL_DIAG_MESSAGE_TEXT, errmsg, sizeof(errmsg), &outlen)) == SQL_SUCCESS
|| rc == SQL_SUCCESS_WITH_INFO) {
fprintf(stderr, "Msg#%d: %s\n", i, errmsg);
}
}
return 1;
}

void postKspError(CEKEYSTORECONTEXT *ctx, const wchar_t *msg, ...) {


if (msg > (wchar_t*)65535)
wprintf(L"Provider emitted message: %s\n", msg);
else
wprintf(L"Provider emitted message ID %d\n", msg);
}

int main(int argc, char **argv) {


char sqlbuf[1024];
SQLHENV env;
SQLHDBC dbc;
SQLHSTMT stmt;
SQLRETURN rc;
unsigned char CEK[32];
unsigned char *ECEK;
unsigned short ECEKlen;
#ifdef _WIN32
HMODULE hProvLib;
#else
void *hProvLib;
#endif
CEKEYSTORECONTEXT ctx = {0};
CEKEYSTOREPROVIDER **ppKsp, *pKsp;
int(__stdcall *pEncryptCEK)(CEKEYSTORECONTEXT *, errFunc *, unsigned char *, unsigned short, unsigned
char **, unsigned short *);
int i;
if (argc < 2) {
fprintf(stderr, "usage: kspapp connstr\n");
return 1;
}

/* Load the provider library */


#ifdef _WIN32
if (!(hProvLib = LoadLibrary("MyKSP.dll"))) {
#else
if (!(hProvLib = dlopen("./MyKSP.so", RTLD_NOW))) {
#endif
fprintf(stderr, "Error loading KSP library\n");
return 2;
}
#ifdef _WIN32
if (!(ppKsp = (CEKEYSTOREPROVIDER**)GetProcAddress(hProvLib, "CEKeystoreProvider"))) {
#else
if (!(ppKsp = (CEKEYSTOREPROVIDER**)dlsym(hProvLib, "CEKeystoreProvider"))) {
#endif
fprintf(stderr, "The export CEKeystoreProvider was not found in the KSP library\n");
return 3;
}
}
while (pKsp = *ppKsp++) {
if (!memcmp(KSPNAME, pKsp->Name, sizeof(KSPNAME)))
goto FoundProv;
}
fprintf(stderr, "Could not find provider in the library\n");
return 4;
FoundProv:
if (pKsp->Init && !pKsp->Init(&ctx, postKspError)) {
fprintf(stderr, "Could not initialize provider\n");
return 5;
}
#ifdef _WIN32
if (!(pEncryptCEK = (LPVOID)GetProcAddress(hProvLib, "KeystoreEncrypt"))) {
#else
if (!(pEncryptCEK = dlsym(hProvLib, "KeystoreEncrypt"))) {
#endif
fprintf(stderr, "The export KeystoreEncrypt was not found in the KSP library\n");
return 6;
}
if (!pKsp->Write) {
fprintf(stderr, "Provider does not support configuration\n");
return 7;
}

/* Configure the provider with the key */


if (!pKsp->Write(&ctx, postKspError, PROV_ENCRYPT_KEY, strlen(PROV_ENCRYPT_KEY))) {
fprintf(stderr, "Error writing to KSP\n");
return 8;
}

/* Generate a CEK and encrypt it with the provider */


srand(time(0) ^ getpid());
for (i = 0; i < sizeof(CEK); i++)
CEK[i] = rand();

if (!pEncryptCEK(&ctx, postKspError, CEK, sizeof(CEK), &ECEK, &ECEKlen)) {


fprintf(stderr, "Error encrypting CEK\n");
return 9;
}

/* Connect to Server */
rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &env);
checkRC(rc, "allocating environment handle", 2, 0, 0);
rc = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
checkRC(rc, "setting ODBC version to 3.0", 3, env, SQL_HANDLE_ENV);
rc = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
checkRC(rc, "allocating connection handle", 4, env, SQL_HANDLE_ENV);
rc = SQLDriverConnect(dbc, 0, argv[1], strlen(argv[1]), NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
checkRC(rc, "connecting to data source", 5, dbc, SQL_HANDLE_DBC);
rc = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
checkRC(rc, "allocating statement handle", 6, dbc, SQL_HANDLE_DBC);

/* Create a CMK definition on the server */


{
static char cmkSql[] = "CREATE COLUMN MASTER KEY CustomCMK WITH ("
"KEY_STORE_PROVIDER_NAME = 'MyCustomKSPName',"
"KEY_PATH = 'TheOneAndOnlyKey')";
printf("Create CMK: %s\n", cmkSql);
SQLExecDirect(stmt, cmkSql, SQL_NTS);
}

/* Create a CEK definition on the server */


{
const char cekSqlBefore[] = "CREATE COLUMN ENCRYPTION KEY CustomCEK WITH VALUES ("
"COLUMN_MASTER_KEY = CustomCMK,"
"ALGORITHM = 'none',"
"ENCRYPTED_VALUE = 0x";
char *cekSql = malloc(sizeof(cekSqlBefore) + 2 * ECEKlen + 2); /* 1 for ')', 1 for null terminator
*/
strcpy(cekSql, cekSqlBefore);
for (i = 0; i < ECEKlen; i++)
sprintf(cekSql + sizeof(cekSqlBefore) - 1 + 2 * i, "%02x", ECEK[i]);
strcat(cekSql, ")");
printf("Create CEK: %s\n", cekSql);
SQLExecDirect(stmt, cekSql, SQL_NTS);
free(cekSql);
#ifdef _WIN32
LocalFree(ECEK);
#else
free(ECEK);
#endif
}

#ifdef _WIN32
FreeLibrary(hProvLib);
#else
dlclose(hProvLib);
#endif

/* Create a table with encrypted columns */


{
static char *tableSql = "CREATE TABLE CustomKSPTestTable ("
"c1 int,"
"c2 varchar(255) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK,
ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'))";
printf("Create table: %s\n", tableSql);
SQLExecDirect(stmt, tableSql, SQL_NTS);
}

/* Load provider into the ODBC Driver and configure it */


{
unsigned char ksd[sizeof(CEKEYSTOREDATA) + sizeof(PROV_ENCRYPT_KEY) - 1];
CEKEYSTOREDATA *pKsd = (CEKEYSTOREDATA*)ksd;
pKsd->name = L"MyCustomKSPName";
pKsd->dataSize = sizeof(PROV_ENCRYPT_KEY) - 1;
memcpy(pKsd->data, PROV_ENCRYPT_KEY, sizeof(PROV_ENCRYPT_KEY) - 1);
#ifdef _WIN32
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREPROVIDER, "MyKSP.dll", SQL_NTS);
#else
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREPROVIDER, "./MyKSP.so", SQL_NTS);
#endif
checkRC(rc, "Loading KSP into ODBC Driver", 7, dbc, SQL_HANDLE_DBC);
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREDATA, (SQLPOINTER)pKsd, SQL_IS_POINTER);
checkRC(rc, "Configuring the KSP", 7, dbc, SQL_HANDLE_DBC);
}

/* Insert some data */


{
int c1;
char c2[256];
rc = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &c1, 0, 0);
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
rc = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 255, 0, c2, 255, 0);
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
for (i = 0; i < 10; i++) {
c1 = i * 10 + i + 1;
sprintf(c2, "Sample data %d for column 2", i);
rc = SQLExecDirect(stmt, "INSERT INTO CustomKSPTestTable (c1, c2) values (?, ?)", SQL_NTS);
checkRC(rc, "Inserting rows query", 10, stmt, SQL_HANDLE_STMT);
}
printf("(Encrypted) data has been inserted into the [CustomKSPTestTable]. You may inspect the data
now.\n"
"Press Enter to continue...\n");
getchar();
}

/* Retrieve the data */


{
int c1;
char c2[256];
rc = SQLBindCol(stmt, 1, SQL_C_LONG, &c1, 0, 0);
checkRC(rc, "Binding columns for select", 11, stmt, SQL_HANDLE_STMT);
rc = SQLBindCol(stmt, 2, SQL_C_CHAR, c2, sizeof(c2), 0);
checkRC(rc, "Binding columns for select", 11, stmt, SQL_HANDLE_STMT);
rc = SQLExecDirect(stmt, "SELECT c1, c2 FROM CustomKSPTestTable", SQL_NTS);
checkRC(rc, "Retrieving rows query", 12, stmt, SQL_HANDLE_STMT);
while (SQL_SUCCESS == (rc = SQLFetch(stmt)))
printf("Retrieved data: c1=%d c2=%s\n", c1, c2);
SQLFreeStmt(stmt, SQL_CLOSE);
printf("Press Enter to clean up and exit...\n");
getchar();
}

/* Clean up */
{
SQLExecDirect(stmt, "DROP TABLE CustomKSPTestTable", SQL_NTS);
SQLExecDirect(stmt, "DROP COLUMN ENCRYPTION KEY CustomCEK", SQL_NTS);
SQLExecDirect(stmt, "DROP COLUMN MASTER KEY CustomCMK", SQL_NTS);
printf("Removed table, CEK, and CMK\n");
}
SQLDisconnect(dbc);
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
return 0;
}

See Also
Using Always Encrypted with the ODBC Driver
DSN and Connection String Keywords and
Attributes
4/27/2022 • 8 minutes to read • Edit Online

This page lists the keywords for connection strings and DSNs, and connection attributes for SQLSetConnectAttr
and SQLGetConnectAttr, available in the ODBC Driver for SQL Server.

Supported DSN/Connection String Keywords and Connection


Attributes
The following table lists the available keywords and the attributes for each platform (L: Linux; M: macOS; W:
Windows). Select the keyword or attribute for more details.

DSN / C O N N EC T IO N ST RIN G
K EY W O RD C O N N EC T IO N AT T RIB UT E P L AT F O RM

Addr LMW

Address LMW

AnsiNPW SQL_COPT_SS_ANSI_NPW LMW

APP LMW

ApplicationIntent SQL_COPT_SS_APPLICATION_INTENT LMW

AttachDBFileName SQL_COPT_SS_ATTACHDBFILENAME LMW

Authentication SQL_COPT_SS_AUTHENTICATION LMW

AutoTranslate SQL_COPT_SS_TRANSLATE LMW

ColumnEncryption SQL_COPT_SS_COLUMN_ENCRYPTIO LMW


N

ConnectRetryCount SQL_COPT_SS_CONNECT_RETRY_COU LMW


NT

ConnectRetryInterval SQL_COPT_SS_CONNECT_RETRY_INTE LMW


RVAL

Database SQL_ATTR_CURRENT_CATALOG LMW

Description LMW

Driver LMW

DSN LMW
DSN / C O N N EC T IO N ST RIN G
K EY W O RD C O N N EC T IO N AT T RIB UT E P L AT F O RM

Encrypt SQL_COPT_SS_ENCRYPT LMW

Failover_Partner SQL_COPT_SS_FAILOVER_PARTNER W

FailoverPartnerSPN SQL_COPT_SS_FAILOVER_PARTNER_SP W
N

FileDSN LMW

GetDataExtensions (v18.0+) SQL_COPT_SS_GETDATA_EXTENSIONS LMW

HostnameInCertificate (v18.0+) LMW

KeepAlive (v17.4+; DSN only prior to LMW


17.8)

KeepAliveInterval (v17.4+; DSN only LMW


prior to 17.8)

KeystoreAuthentication LMW

KeystorePrincipalId LMW

KeystoreSecret LMW

Language LMW

LongAsMax (v18.0+) SQL_COPT_SS_LONGASMAX LMW

MARS_Connection SQL_COPT_SS_MARS_ENABLED LMW

MultiSubnetFailover SQL_COPT_SS_MULTISUBNET_FAILOVE LMW


R

Net LMW

Network LMW

PWD LMW

QueryLog_On SQL_COPT_SS_PERF_QUERY W

QueryLogFile SQL_COPT_SS_PERF_QUERY_LOG W

QueryLogTIme SQL_COPT_SS_PERF_QUERY_INTERVAL W

QuotedId SQL_COPT_SS_QUOTED_IDENT LMW

Regional LMW
DSN / C O N N EC T IO N ST RIN G
K EY W O RD C O N N EC T IO N AT T RIB UT E P L AT F O RM

Replication LMW

SaveFile LMW

Server LMW

ServerSPN SQL_COPT_SS_SERVER_SPN LMW

StatsLog_On SQL_COPT_SS_PERF_DATA W

StatsLogFile SQL_COPT_SS_PERF_DATA_LOG W

TransparentNetworkIPResolution SQL_COPT_SS_TNIR LMW

Trusted_Connection SQL_COPT_SS_INTEGRATED_SECURITY LMW

TrustServerCertificate SQL_COPT_SS_TRUST_SERVER_CERTIFI LMW


CATE

UID LMW

UseFMTONLY LMW

WSID LMW

SQL_ATTR_ACCESS_MODE LMW
(SQL_ACCESS_MODE)

SQL_ATTR_ASYNC_DBC_EVENT W

SQL_ATTR_ASYNC_DBC_FUNCTIONS_E W
NABLE

SQL_ATTR_ASYNC_DBC_PCALLBACK W

SQL_ATTR_ASYNC_DBC_PCONTEXT W

SQL_ATTR_ASYNC_ENABLE W

SQL_ATTR_AUTO_IPD LMW

SQL_ATTR_AUTOCOMMIT LMW
(SQL_AUTOCOMMIT)

SQL_ATTR_CONNECTION_DEAD LMW

SQL_ATTR_CONNECTION_TIMEOUT LMW

SQL_ATTR_DBC_INFO_TOKEN LMW
DSN / C O N N EC T IO N ST RIN G
K EY W O RD C O N N EC T IO N AT T RIB UT E P L AT F O RM

SQL_ATTR_LOGIN_TIMEOUT LMW
(SQL_LOGIN_TIMEOUT)

SQL_ATTR_METADATA_ID LMW

SQL_ATTR_ODBC_CURSORS LMW
(SQL_ODBC_CURSORS)

SQL_ATTR_PACKET_SIZE LMW
(SQL_PACKET_SIZE)

SQL_ATTR_QUIET_MODE LMW
(SQL_QUIET_MODE)

SQL_ATTR_RESET_CONNECTION LMW
(SQL_COPT_SS_RESET_CONNECTION)

SQL_ATTR_TRACE LMW
(SQL_OPT_TRACE)

SQL_ATTR_TRACEFILE LMW
(SQL_OPT_TRACEFILE)

SQL_ATTR_TRANSLATE_LIB LMW
(SQL_TRANSLATE_DLL)

SQL_ATTR_TRANSLATE_OPTION LMW
(SQL_TRANSLATE_OPTION)

SQL_ATTR_TXN_ISOLATION LMW
(SQL_TXN_ISOLATION)

SQL_COPT_SS_ACCESS_TOKEN LMW

SQL_COPT_SS_ANSI_OEM W

SQL_COPT_SS_AUTOBEGINTXN LMW

SQL_COPT_SS_BCP LMW

SQL_COPT_SS_BROWSE_CACHE_DATA LMW

SQL_COPT_SS_BROWSE_CONNECT LMW

SQL_COPT_SS_BROWSE_SERVER LMW

SQL_COPT_SS_CEKEYSTOREDATA LMW

SQL_COPT_SS_CEKEYSTOREPROVIDER LMW
DSN / C O N N EC T IO N ST RIN G
K EY W O RD C O N N EC T IO N AT T RIB UT E P L AT F O RM

SQL_COPT_SS_CLIENT_CONNECTION_ LMW
ID

SQL_COPT_SS_CONCAT_NULL LMW

SQL_COPT_SS_CONNECTION_DEAD LMW

SQL_COPT_SS_ENLIST_IN_DTC W

SQL_COPT_SS_ENLIST_IN_XA LMW

SQL_COPT_SS_FALLBACK_CONNECT LMW

SQL_COPT_SS_INTEGRATED_AUTHENT LMW
ICATION_METHOD

SQL_COPT_SS_MUTUALLY_AUTHENTI LMW
CATED

SQL_COPT_SS_OLDPWD LMW

SQL_COPT_SS_PERF_DATA_LOG_NOW W

SQL_COPT_SS_PRESERVE_CURSORS LMW

SQL_COPT_SS_SPID (v17.5+) LMW

SQL_COPT_SS_TXN_ISOLATION LMW

SQL_COPT_SS_USER_DATA LMW

SQL_COPT_SS_WARN_ON_CP_ERROR LMW

ClientCertificate LMW

ClientKey LMW

Here are some connection string keywords and connection attributes, which aren't documented in Using
Connection String Keywords with SQL Server Native Client, SQLSetConnectAttr, and SQLSetConnectAttr
Function.
Description
Used to describe the data source.
SQL_COPT_SS_ANSI_OEM
Controls ANSI to OEM conversion of data.

AT T RIB UT E VA L UE DESC RIP T IO N

SQL_AO_OFF (Default) Translation isn't done.


AT T RIB UT E VA L UE DESC RIP T IO N

SQL_AO_ON Translation is done.

SQL_COPT_SS_AUTOBEGINTXN
Version 17.6+ While autocommit is off, controls automatic BEGIN TRANSACTION after ROLLBACK or COMMIT.

AT T RIB UT E VA L UE DESC RIP T IO N

SQL_AUTOBEGINTXN_ON (Default) Automatic BEGIN TRANSACTION after ROLLBACK


or COMMIT.

SQL_AUTOBEGINTXN_OFF No automatic BEGIN TRANSACTION after ROLLBACK or


COMMIT.

SQL_COPT_SS_FALLBACK_CONNECT
Controls the use of SQL Server Fallback Connections. This one is no longer supported.

AT T RIB UT E VA L UE DESC RIP T IO N

SQL_FB_OFF (Default) Fallback connections are disabled.

SQL_FB_ON Fallback connections are enabled.

New Connection String Keywords and Connection Attributes


Authentication - SQL_COPT_SS_AUTHENTICATION
Sets the authentication mode to use when connecting to SQL Server. For more information, see Using Azure
Active Directory.

K EY W O RD VA L UE AT T RIB UT E VA L UE DESC RIP T IO N

SQL_AU_NONE (Default) Not set. Combination of


other attributes determines
authentication mode.

SqlPassword SQL_AU_PASSWORD SQL Server authentication with


username and password.

ActiveDirectoryIntegrated SQL_AU_AD_INTEGRATED Azure Active Directory Integrated


authentication.

ActiveDirectoryPassword SQL_AU_AD_PASSWORD Azure Active Directory Password


authentication.

ActiveDirectoryInteractive SQL_AU_AD_INTERACTIVE Azure Active Directory Interactive


authentication.

ActiveDirectoryMsi SQL_AU_AD_MSI Azure Active Directory Managed


Identity authentication. For user-
assigned identity, UID is set to the
object ID of the user identity.
K EY W O RD VA L UE AT T RIB UT E VA L UE DESC RIP T IO N

ActiveDirectoryServicePrincipal SQL_AU_AD_SPA Azure Active Directory Service Principal


authentication. UID is set to the client
ID of the service principal. PWD is set
to the client secret.

SQL_AU_RESET Unset. Overrides any DSN or


connection string setting.

NOTE
When using Authentication keyword or attribute, explicitly specify Encrypt setting to the desired value in connection
string / DSN / connection attribute. Refer to Using Connection String Keywords with SQL Server Native Client for details.

ColumnEncryption - SQL_COPT_SS_COLUMN_ENCRYPTION
Controls transparent column encryption (Always Encrypted). For more information, see Using Always Encrypted
(ODBC).

K EY W O RD VA L UE AT T RIB UT E VA L UE DESC RIP T IO N

Enabled SQL_CE_ENABLED Enables Always Encrypted.

Disabled SQL_CE_DISABLED (Default) Disables Always Encrypted.

SQL_CE_RESULTSETONLY Enables decryption only (results and


return values).

Encrypt
Specifies whether connections use TLS encryption over the network. Possible values are yes / mandatory
(18.0+), no / optional (18.0+), and strict (18.0+). The default value is yes in version 18.0+ and no in
previous versions.
Regardless of the setting for Encrypt , the server login credentials (user name and password) are always
encrypted.
Encrypt , TrustServerCertificate , and server-side Force Encryption settings play a part in whether
connections are encrypted over the network. The following tables show the effect of these settings.
ODBC Driver 18 and newer

SERVER F O RC E
EN C RY P T SET T IN G T RUST SERVER C ERT IF IC AT E EN C RY P T IO N RESULT

No No No Server certificate isn't


checked.
Data sent between client
and server isn't encrypted.

No Yes No Server certificate isn't


checked.
Data sent between client
and server isn't encrypted.
SERVER F O RC E
EN C RY P T SET T IN G T RUST SERVER C ERT IF IC AT E EN C RY P T IO N RESULT

Yes No No Server certificate is checked.


Data sent between client
and server is encrypted.

Yes Yes No Server certificate isn't


checked.
Data sent between client
and server is encrypted.

No No Yes Server certificate is checked.


Data sent between client
and server is encrypted.

No Yes Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.

Yes No Yes Server certificate is checked.


Data sent between client
and server is encrypted.

Yes Yes Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.

Strict - - TrustServerCertificate is
ignored. Server certificate is
checked.
Data sent between client
and server is encrypted.

NOTE
Strict is only available against servers that support TDS 8.0 connections.

ODBC Driver 17 and older


SERVER F O RC E
EN C RY P T SET T IN G T RUST SERVER C ERT IF IC AT E EN C RY P T IO N RESULT

No No No Server certificate isn't


checked.
Data sent between client
and server isn't encrypted.

No Yes No Server certificate isn't


checked.
Data sent between client
and server isn't encrypted.
SERVER F O RC E
EN C RY P T SET T IN G T RUST SERVER C ERT IF IC AT E EN C RY P T IO N RESULT

Yes No No Server certificate is checked.


Data sent between client
and server is encrypted.

Yes Yes No Server certificate isn't


checked.
Data sent between client
and server is encrypted.

No No Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.

No Yes Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.

Yes No Yes Server certificate is checked.


Data sent between client
and server is encrypted.

Yes Yes Yes Server certificate isn't


checked.
Data sent between client
and server is encrypted.

TransparentNetworkIPResolution - SQL_COPT_SS_TNIR
Controls the Transparent Network IP Resolution feature, which interacts with MultiSubnetFailover to allow faster
reconnection attempts. For more information, see Using Transparent Network IP Resolution.

K EY W O RD VA L UE AT T RIB UT E VA L UE DESC RIP T IO N

Enabled SQL_IS_ON (Default) Enables Transparent Network


IP Resolution.

Disabled SQL_IS_OFF Disables Transparent Network IP


Resolution.

UseFMTONLY
Controls the use of SET FMTONLY for metadata when connecting to SQL Server 2012 and newer.

K EY W O RD VA L UE DESC RIP T IO N

No (Default) Use sp_describe_first_result_set for metadata if


available.

Yes Use SET FMTONLY for metadata.

Replication
Specifies the use of a replication login on ODBC Driver version 17.8 and newer.
K EY W O RD VA L UE DESC RIP T IO N

No (Default) Replication login won't be used.

Yes Triggers with the NOT FOR REPLICATION option won't fire
on the connection.

ClientCertificate
Specifies the certificate to be used for authentication. The options are:

O P T IO N VA L UE DESC RIP T IO N

sha1:<hash_value> The ODBC driver uses SHA1 hash to locate a certificate in


Windows Certificate Store

subject:<subject> The ODBC driver uses subject to locate a certificate in


Windows Certificate Store

file:<file_location>[,password:<password> ] The ODBC driver uses a certificate file.

In case if certificate is in PFX format and private key inside the PFX certificate is password protected, the
password keyword is required. For certificates in PEM and DER formats ClientKey attribute is required

ClientKey
Specifies a file location of the private key for PEM or DER certificates that are specified by the ClientCertificate
attribute. Format:

O P T IO N VA L UE DESC RIP T IO N

file:<file_location>[,password:<password> ] Specifies location of the private key file.

In case if private key file is password protected then password keyword is required. If the password contains any
" , " characters, an extra " , " character is added immediately after each one. For example, if the password is "
a,b,c ", the escaped password present in the connection string is " a,,b,,c ".

HostnameInCertificate
Specifies the hostname to be expected in the server's certificate when encryption is negotiated, if it's different
from the default value derived from Addr/Address/Server.
SQL_COPT_SS_ACCESS_TOKEN
Allows the use of an Azure Active Directory access token for authentication. For more information, see Using
Azure Active Directory.

AT T RIB UT E VA L UE DESC RIP T IO N

NULL (Default) No access token is supplied.

ACCESSTOKEN* Pointer to an access token.

SQL_COPT_SS_CEKEYSTOREDATA
Communicates with a loaded keystore provider library. See Controls transparent column encryption (Always
Encrypted). This attribute has no default value. For more information, see Custom Keystore Providers.

AT T RIB UT E VA L UE DESC RIP T IO N

CEKEYSTOREDATA * Communication data structure for keystore provider library

SQL_COPT_SS_CEKEYSTOREPROVIDER
Loads a keystore provider library for Always Encrypted, or retrieves the names of loaded keystore provider
libraries. For more information, see Custom Keystore Providers. This attribute has no default value.

AT T RIB UT E VA L UE DESC RIP T IO N

char * Path to a keystore provider library

SQL_COPT_SS_ENLIST_IN_XA
To enable XA transactions with an XA-compliant Transaction Processor (TP), the application needs to call
SQLSetConnectAttr with SQL_COPT_SS_ENLIST_IN_XA and a pointer to an XACALLPARAM object. This option is
supported on Windows (17.3 and above), Linux, and macOS.

SQLSetConnectAttr(hdbc, SQL_COPT_SS_ENLIST_IN_XA, param, SQL_IS_POINTER); // XACALLPARAM *param

To associate an XA transaction with an ODBC connection only, provide TRUE or FALSE with
SQL_COPT_SS_ENLIST_IN_XA instead of the pointer when calling SQLSetConnectAttr . This setting is only valid
on Windows and can't be used to specify XA operations through a client application.

SQLSetConnectAttr(hdbc, SQL_COPT_SS_ENLIST_IN_XA, (SQLPOINTER)TRUE, 0);

VA L UE DESC RIP T IO N P L AT F O RM S

XACALLPARAM object* The pointer to XACALLPARAM object. Windows, Linux, and macOS

TRUE Associates the XA transaction with the Windows


ODBC connection. All related database
activities will be performed under the
protection of the XA transaction.

FALSE Disassociates the transaction with the Windows


ODBC connection.

For more information about XA transactions, see Using XA Transactions.


SQL_COPT_SS_LONGASMAX
Allows long type data to be sent to servers as max type data.

AT T RIB UT E VA L UE DESC RIP T IO N

No (Default) Don't convert long types to max types when


sending.

Yes Converts data from long types to max types when sending.

SQL_COPT_SS_SPID
Retrieves the server process ID of the connection. This property is equivalent to the T-SQL @@SPID variable,
except that it doesn't incur an extra round trip to the server.

AT T RIB UT E VA L UE DESC RIP T IO N

DWORD SPID
Using Always Encrypted with the ODBC Driver for
SQL Server
4/27/2022 • 35 minutes to read • Edit Online

Download ODBC Driver

Applicable to
ODBC Driver 13.1+ for SQL Server

Introduction
This article provides information on how to develop ODBC applications using Always Encrypted (Database
Engine) or Always Encrypted with secure enclaves and the ODBC Driver for SQL Server.
Always Encrypted allows client applications to encrypt sensitive data and never reveal the data or the encryption
keys to SQL Server or Azure SQL Database. An Always Encrypted enabled driver, such as the ODBC Driver for
SQL Server, achieves this security by transparently encrypting and decrypting sensitive data in the client
application. The driver automatically determines which query parameters correspond to sensitive database
columns (protected using Always Encrypted), and encrypts the values of those parameters before passing the
data to SQL Server or Azure SQL Database. Similarly, the driver transparently decrypts data retrieved from
encrypted database columns in query results. Always Encrypted with secure enclaves extends this feature to
enable richer functionality on sensitive data while keeping the data confidential.
For more information, see Always Encrypted (Database Engine) and Always Encrypted with secure enclaves.
Prerequisites
Configure Always Encrypted in your database. This process involves provisioning Always Encrypted keys and
setting up encryption for selected database columns. If you don't already have a database with Always
Encrypted configured, follow the directions in Getting Started with Always Encrypted. In particular, your
database should contain the metadata definitions for a Column Master Key (CMK), a Column Encryption Key
(CEK), and a table containing one or more columns encrypted using that CEK.
If you're using Always Encrypted with secure enclaves, see Develop applications using Always Encrypted with
secure enclaves for more prerequisites.
Enabling Always Encrypted in an ODBC application
The easiest way to enable both parameter encryption and resultset encrypted column decryption is by setting
the value of the ColumnEncryption connection string keyword to Enabled . The following code is an example of a
connection string that enables Always Encrypted:

SQLWCHAR *connString = L"Driver={ODBC Driver 17 for SQL Server};Server=


{myServer};Trusted_Connection=yes;ColumnEncryption=Enabled;";

Always Encrypted may also be enabled in the DSN configuration, using the same key and value (which will be
overridden by the connection string setting, if present), or programmatically with the
SQL_COPT_SS_COLUMN_ENCRYPTION pre-connection attribute. Setting it this way overrides the value set in the
connection string or DSN:
SQLSetConnectAttr(hdbc, SQL_COPT_SS_COLUMN_ENCRYPTION, (SQLPOINTER)SQL_COLUMN_ENCRYPTION_ENABLE, 0);

Once enabled for the connection, the behavior of Always Encrypted may be adjusted for individual queries. For
more information, see Controlling the Performance Impact of Always Encrypted below.
Enabling Always Encrypted isn't sufficient for encryption or decryption to succeed; you also need to make sure
that:
The application has the VIEW ANY COLUMN MASTER KEY DEFINITION and VIEW ANY COLUMN
ENCRYPTION KEY DEFINITION database permissions, required to access the metadata about Always
Encrypted keys in the database. For details, see Database Permissions.
The application can access the CMK that protects the CEKs for the queried encrypted columns. This
behavior is dependent on the keystore provider that stores the CMK. For more information, see Working
with Column Master Key Stores.
Enabling Always Encrypted with secure enclaves

NOTE
On Linux and macOS, OpenSSL version 1.0.1 or later is required to use Always Encrypted with secure enclaves.

Beginning with version 17.4, the driver supports Always Encrypted with secure enclaves. To enable the use of
the enclave when connecting to a database, set the ColumnEncryption DSN key, connection string keyword, or
connection attribute to the following value: <attestation protocol>\<attestation URL> , where:
<attestation protocol> - specifies a protocol used for enclave attestation.
If you're using SQL Server and Host Guardian Service (HGS), <attestation protocol> should be
VBS-HGS .
If you're using Azure SQL Database and Microsoft Azure Attestation, <attestation protocol> should
be SGX-AAS .
<attestation URL> - specifies an attestation URL (an attestation service endpoint). You need to obtain an
attestation URL for your environment from your attestation service administrator.
If you're using SQL Server and Host Guardian Service (HGS), see Determine and share the HGS
attestation URL.
If you're using Azure SQL Database and Microsoft Azure Attestation, see Determine the attestation
URL for your attestation policy.
Examples of connection strings enabling enclave computations for a database connection:
SQL Server:

"Driver=ODBC Driver 17 for SQL


Server;Server=myServer.myDomain;Database=myDataBase;Trusted_Connection=Yes;ColumnEncryption=VBS-
HGS,http://myHGSServer.myDomain/Attestation"

Azure SQL Database:

"Driver=ODBC Driver 17 for SQL


Server;Server=myServer.database.windows.net;Database=myDataBase;Uid=myUsername;Pwd=myPassword;Encrypt
=yes;ColumnEncryption=SGX-AAS,https://myAttestationProvider.uks.attest.azure.net/attest/SgxEnclave"
If the server and attestation service are configured correctly along with enclave-enabled CMKs and CEKs for the
encrypted columns, you can execute queries that use the enclave such as in-place encryption and rich
computations, in addition to the existing functionality provided by Always Encrypted. For more information, see
Configure Always Encrypted with secure enclaves.
Retrieving and modifying data in encrypted columns
Once you enable Always Encrypted on a connection, you can use standard ODBC APIs. The ODBC APIs can
retrieve or modify data in encrypted database columns. The following documentation items might be helpful:
ODBC sample code
ODBC Programmer's Reference
Your application must have the required database permissions, and must be able to access the column master
key. Then the driver encrypts any query parameters that target encrypted columns. The driver also decrypts
data retrieved from encrypted columns. The driver does all this encrypting and decrypting without any
assistance from your source code. To your program, it's as if the columns aren't encrypted.
If Always Encrypted isn't enabled, queries with parameters that target encrypted columns will fail. Data can still
be retrieved from encrypted columns, as long as the query has no parameters targeting encrypted columns.
However, the driver won't attempt any decryption and the application will receive the binary encrypted data (as
byte arrays).
The table below summarizes the behavior of queries, depending on whether Always Encrypted is enabled or not:

A L WAY S EN C RY P T ED IS A L WAY S EN C RY P T ED IS
EN A B L ED A N D EN A B L ED A N D
A P P L IC AT IO N C A N A C C ESS A P P L IC AT IO N C A N 'T
T H E K EY S A N D K EY A C C ESS T H E K EY S O R K EY A L WAY S EN C RY P T ED IS
Q UERY C H A RA C T ERIST IC M ETA DATA M ETA DATA DISA B L ED

Parameters targeting Parameter values are Error Error


encrypted columns. transparently encrypted.

Retrieving data from Results from encrypted Error Results from encrypted
encrypted columns, without columns are transparently columns aren't decrypted.
parameters targeting decrypted. The application The application receives
encrypted columns. receives plaintext column encrypted values as byte
values. arrays.

The following examples illustrate retrieving and modifying data in encrypted columns. The examples assume a
table with the following schema. The SSN and BirthDate columns are encrypted.

CREATE TABLE [dbo].[Patients](


[PatientId] [int] IDENTITY(1,1),
[SSN] [char](11) COLLATE Latin1_General_BIN2
ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC,
ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256',
COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[BirthDate] [date]
ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED,
ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256',
COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL
PRIMARY KEY CLUSTERED ([PatientId] ASC) ON [PRIMARY] )
GO

Data insertion example


This example inserts a row into the Patients table. Note the following details:
There's nothing specific to encryption in the sample code. The driver automatically detects and encrypts
the values of the SSN and date parameters, which target encrypted columns. This behavior makes
encryption transparent to the application.
The values inserted into database columns, including the encrypted columns, are passed as bound
parameters (see SQLBindParameter Function). While using parameters is optional when sending values
to non-encrypted columns (although it's highly recommended because it helps prevent SQL injection), it's
required for values targeting encrypted columns. If the values inserted in the SSN or BirthDate columns
were passed as literals embedded in the query statement, the query would fail because the driver doesn't
attempt to encrypt or otherwise process literals in queries. As a result, the server would reject them as
incompatible with the encrypted columns.
The SQL type of the parameter inserted into the SSN column is set to SQL_CHAR, which maps to the
char SQL Server data type (
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 11, 0, (SQLPOINTER)SSN, 0,
&cbSSN);
). If the type of the parameter was set to SQL_WCHAR, which maps to nchar , the query would fail, as
Always Encrypted doesn't support server-side conversions from encrypted nchar values to encrypted
char values. See ODBC Programmer's Reference -- Appendix D: Data Types for information about the data
type mappings.

SQL_DATE_STRUCT date;
SQLLEN cbdate; // size of date structure

SQLCHAR SSN[12];
strcpy_s((char*)SSN, _countof(SSN), "795-73-9838");

SQLWCHAR* firstName = L"Catherine";


SQLWCHAR* lastName = L"Abel";
SQLINTEGER cbSSN = SQL_NTS, cbFirstName = SQL_NTS, cbLastName = SQL_NTS;

// Initialize the date structure


date.day = 10;
date.month = 9;
date.year = 1996;

// Size of structures
cbdate = sizeof(SQL_DATE_STRUCT);

SQLRETURN rc = 0;

string queryText = "INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES
(?, ?, ?, ?) ";

rc = SQLPrepare(hstmt, (SQLCHAR *)queryText.c_str(), SQL_NTS);

//SSN
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 11, 0, (SQLPOINTER)SSN, 0,
&cbSSN);
//FirstName
rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)firstName,
0, &cbFirstName);
//LastName
rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)lastName, 0,
&cbLastName);
//BirthDate
rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 10, 0,
(SQLPOINTER)&date, 0, &cbdate);

rc = SQLExecute(hstmt);

Plaintext data retrieval example


The following example demonstrates filtering data based on encrypted values, and retrieving plaintext data from
encrypted columns. Note the following details:
The value used in the WHERE clause to filter on the SSN column needs to be passed using
SQLBindParameter, so that the driver can transparently encrypt it before sending it to the server.
All values printed by the program will be in plaintext, since the driver will transparently decrypt the data
retrieved from the SSN and BirthDate columns.

NOTE
Queries can perform equality comparisons on encrypted columns only if the encryption is deterministic, or if the secure
enclave is enabled. For more information, see Selecting Deterministic or Randomized encryption.

SQLCHAR SSN[12];
strcpy_s((char*)SSN, _countof(SSN), "795-73-9838");

SQLWCHAR* firstName = L"Catherine";


SQLWCHAR* lastName = L"Abel";
SQLINTEGER cbSSN = SQL_NTS, cbFirstName = SQL_NTS, cbLastName = SQL_NTS;

SQLRETURN rc = 0;
string empty = "";
string queryText = "SELECT [SSN], [FirstName], [LastName], [BirthDate] " + empty +
"FROM [dbo].[Patients]" +
"WHERE " +
"[SSN] = ? ";

rc = SQLPrepare(hstmt, (SQLCHAR *)queryText.c_str(), SQL_NTS);

//SSN
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 11, 0, (SQLPOINTER)SSN, 0, &cbSSN);

rc = SQLExecute(hstmt);
HandleDiagnosticRecord(hstmt, SQL_HANDLE_STMT, rc);

SQL_DATE_STRUCT dateVal;
SQLWCHAR firstNameVal[50];
SQLWCHAR lastNameVal[50];
SQLCHAR SSNVal[12];
SQLLEN cbdate; // size of date structure

int rowcount = 0;
while (SQL_SUCCEEDED(SQLFetch(hstmt)))
{
rowcount++;
SQLGetData(hstmt, 1, SQL_C_CHAR, &SSNVal, 11, &cbSSN);
SQLGetData(hstmt, 2, SQL_C_WCHAR, &firstNameVal, 50, &cbFirstName);
SQLGetData(hstmt, 3, SQL_C_WCHAR, &lastNameVal, 50, &cbLastName);
SQLGetData(hstmt, 4, SQL_C_TYPE_DATE, &dateVal, 10, &cbdate);
}

Ciphertext data retrieval example


If Always Encrypted isn't enabled, a query can still retrieve data from encrypted columns, as long as the query
has no parameters targeting encrypted columns.
The following example illustrates retrieving binary encrypted data from encrypted columns. Note the following
details:
As Always Encrypted isn't enabled in the connection string, the query will return encrypted values of SSN
and BirthDate as byte arrays (the program converts the values to strings).
A query retrieving data from encrypted columns with Always Encrypted disabled can have parameters, as
long as none of the parameters target an encrypted column. The above query filters by LastName, which isn't
encrypted in the database. If the query filtered by SSN or BirthDate, the query would fail.

SQLCHAR SSN[12];
strcpy_s((char*)SSN, _countof(SSN), "795-73-9838");

SQLWCHAR* firstName = L"Catherine";


SQLWCHAR* lastName = L"Abel";
SQLINTEGER cbSSN = SQL_NTS, cbFirstName = SQL_NTS, cbLastName = SQL_NTS;

SQLRETURN rc = 0;
string empty = "";
string queryText = "SELECT [SSN], [FirstName], [LastName], [BirthDate] " + empty +
"FROM [dbo].[Patients]" +
"WHERE " +
"[LastName] = ?";

rc = SQLPrepare(hstmt, (SQLCHAR *)queryText.c_str(), SQL_NTS);

//LastName
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)lastName, 0,
&cbLastName);

rc = SQLExecute(hstmt);
HandleDiagnosticRecord(hstmt, SQL_HANDLE_STMT, rc);

SQL_DATE_STRUCT dateVal;
SQLWCHAR firstNameVal[50];
SQLWCHAR lastNameVal[50];
SQLCHAR SSNVal[12];
SQLLEN cbdate; // size of date structure

int rowcount = 0;
while (SQL_SUCCEEDED(SQLFetch(hstmt)))
{
rowcount++;
SQLGetData(hstmt, 1, SQL_C_CHAR, &SSNVal, 11, &cbSSN);
SQLGetData(hstmt, 2, SQL_C_WCHAR, &firstNameVal, 50, &cbFirstName);
SQLGetData(hstmt, 3, SQL_C_WCHAR, &lastNameVal, 50, &cbLastName);
SQLGetData(hstmt, 4, SQL_C_TYPE_DATE, &dateVal, 10, &cbdate);
}

Money/SmallMoney encryption
Starting with driver version 17.7 it's possible to use Always Encrypted with MONEY and SMALLMONEY.
However there are some extra steps to take. When inserting into encrypted MONEY or SMALLMONEY columns,
use one of the following C types:

SQL_C_CHAR
SQL_C_WCHAR
SQL_C_SHORT
SQL_C_LONG
SQL_C_FLOAT
SQL_C_DOUBLE
SQL_C_BIT
SQL_C_TINYINT
SQL_C_SBIGINT
SQL_C_NUMERIC

and a SQL type of either SQL_NUMERIC or SQL_DOUBLE (precision may be lost when using this type).
Bin din g t h e variable

Whenever binding a MONEY/SMALLMONEY variable in an encrypted column the following descriptor field(s)
must be set:

// n is the descriptor record of the MONEY/SMALLMONEY parameter


// the type is assumed to be SMALLMONEY if isSmallMoney is true and MONEY otherwise

SQLHANDLE ipd = 0;
SQLGetStmtAttr(hStmt, SQL_ATTR_IMP_PARAM_DESC, (SQLPOINTER)&ipd, SQL_IS_POINTER, NULL);
SQLSetDescField(ipd, n, SQL_CA_SS_SERVER_TYPE, isSmallMoney ? (SQLPOINTER)SQL_SS_TYPE_SMALLMONEY :
(SQLPOINTER)SQL_SS_TYPE_MONEY,
SQL_IS_INTEGER);

// If the variable is bound as SQL_NUMERIC, additional descriptor fields have to be set


// var is SQL_NUMERIC_STRUCT containing the value to be inserted

SQLHDESC hdesc = NULL;


SQLGetStmtAttr(hStmt, SQL_ATTR_APP_PARAM_DESC, &hdesc, 0, NULL);
SQLSetDescField(hdesc, n, SQL_DESC_PRECISION, (SQLPOINTER)(var.precision), 0);
SQLSetDescField(hdesc, n, SQL_DESC_SCALE, (SQLPOINTER)(var.scale), 0);
SQLSetDescField(hdesc, n, SQL_DESC_DATA_PTR, &var, 0);

Avoiding common problems when querying encrypted columns


This section describes common categories of errors when querying encrypted columns from ODBC applications
and a few guidelines on how to avoid them.
U n su p p o r t e d d a t a t y p e c o n v e r si o n e r r o r s

Always Encrypted supports few conversions for encrypted data types. See Always Encrypted (Database Engine)
for the detailed list of supported type conversions. To avoid data type conversion errors, make sure that you
observe the following points when using SQLBindParameter with parameters targeting encrypted columns:
The SQL type of the parameter is either exactly the same as the type of the targeted column, or the
conversion from the SQL type to the type of the column is supported.
The precision and scale of parameters targeting columns of the decimal and numeric SQL Server data
types is the same as the precision and scale configured for the target column.
The precision of parameters targeting columns of datetime2 , datetimeoffset , or time SQL Server data
types isn't greater than the precision for the target column, in queries that modify the target column.
Er r o r s d u e t o p a ssi n g p l a i n t e x t i n st e a d o f e n c r y p t e d v a l u e s

Any value that targets an encrypted column needs to be encrypted before being sent to the server. An attempt
to insert, modify, or filter by a plaintext value on an encrypted column will result in an error. To prevent such
errors, make sure that:
Always Encrypted is enabled (in the DSN, the connection string, before connecting by setting the
SQL_COPT_SS_COLUMN_ENCRYPTION connection attribute for a specific connection, or the
SQL_SOPT_SS_COLUMN_ENCRYPTION statement attribute for a specific statement).

You use SQLBindParameter to send data targeting encrypted columns. The example below shows a query
that incorrectly filters by a literal/constant on an encrypted column (SSN), instead of passing the literal as
an argument to SQLBindParameter.

string queryText = "SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE SSN='795-
73-9838'";

Precautions when using SQLSetPos and SQLMoreResults


SQLSetPos
The SQLSetPos API allows an application to update rows in a resultset using buffers that were bound with
SQLBindCol and into which row data was previously fetched. Because of the asymmetric padding behavior of
encrypted fixed-length types, it's possible to unexpectedly alter the data of these columns while performing
updates on other columns in the row. With AE, fixed-length character values will be padded if the value is
smaller than the buffer size.
To mitigate this behavior, use the SQL_COLUMN_IGNORE flag to ignore columns that won't be updated as part of
SQLBulkOperations and when using SQLSetPos for cursor-based updates. All columns that are not being directly
modified by the application should be ignored, both for performance and to avoid truncation of columns that
are bound to a buffer smaller than their actual (DB) size. For more information, see SQLSetPos Function
reference.
SQLMoreResults & SQLDescribeCol
Application programs may call SQLDescribeCol to return metadata about columns in prepared statements.
When Always Encrypted is enabled, calling SQLMoreResults before calling SQLDescribeCol causes
sp_describe_first_result_set to be called, which doesn't correctly return the plaintext metadata for encrypted
columns. To avoid this issue, call SQLDescribeCol on prepared statements before calling SQLMoreResults .

Controlling the performance impact of Always Encrypted


Because Always Encrypted is a client-side encryption technology, most of the performance overhead is observed
on the client side, not in the database. Apart from the cost of encryption and decryption operations, the other
sources of performance overhead on the client side are:
Extra round trips to the database to retrieve metadata for query parameters.
Calls to a column master key store to access a column master key.
This section describes the built-in performance optimizations in the ODBC Driver for SQL Server and how you
can control the impact of the above two factors on performance.
Controlling round-trips to retrieve metadata for query parameters
If Always Encrypted is enabled for a connection, the driver will, by default, call
sys.sp_describe_parameter_encryption for each parameterized query, passing the query statement (without any
parameter values) to SQL Server. This stored procedure analyzes the query statement to find out if any
parameters need to be encrypted, and if so, returns the encryption-related information for each parameter to
allow the driver to encrypt them. The above behavior ensures a high level of transparency to the client
application: The application (and the application developer) doesn't need to be aware of which queries access
encrypted columns, as long as the values targeting encrypted columns are passed to the driver in parameters.
Beginning in version 17.6, the driver also caches the encryption metadata for prepared statements, improving
performance by allowing future calls to SQLExecute to not require an extra round trip to retrieve the encryption
metadata.
Per-statement Always Encrypted behavior
To control the performance impact of retrieving encryption metadata for parameterized queries, you can alter
the Always Encrypted behavior for individual queries if it has been enabled on the connection. This way, you can
ensure that sys.sp_describe_parameter_encryption is invoked only for queries that you know have parameters
targeting encrypted columns. Note, however, that by doing so, you reduce transparency of encryption: if you
encrypt more columns in your database, you may need to change the code of your application to align it with
the schema changes.
To control the Always Encrypted behavior of a statement, call SQLSetStmtAttr to set the
SQL_SOPT_SS_COLUMN_ENCRYPTION statement attribute to one of the following values:

VA L UE DESC RIP T IO N

SQL_CE_DISABLED (0) Always Encrypted is disabled for the statement


VA L UE DESC RIP T IO N

SQL_CE_RESULTSETONLY (1) Decryption Only. Result sets and return values are
decrypted, and parameters aren't encrypted

SQL_CE_ENABLED (3) Always Encrypted is enabled and used for both parameters
and results

New statement handles created from a connection with Always Encrypted enabled default to SQL_CE_ENABLED.
Handles created from a connection with it disabled default to SQL_CE_DISABLED (and it isn't possible to enable
Always Encrypted on them.)
If most of the queries of a client application access encrypted columns, the following points are recommended:
Set the ColumnEncryption connection string keyword to Enabled .
Set the SQL_SOPT_SS_COLUMN_ENCRYPTION attribute to SQL_CE_DISABLED on statements that don't access any
encrypted columns. This setting will disable both calling sys.sp_describe_parameter_encryption and
attempts to decrypt any values in the result set.
Set the SQL_SOPT_SS_COLUMN_ENCRYPTION attribute to SQL_CE_RESULTSETONLY on statements that don't have
any parameters requiring encryption, but retrieve data from encrypted columns. This setting will disable
calling sys.sp_describe_parameter_encryption and parameter encryption. Results containing encrypted
columns will continue to be decrypted.
Use prepared statements for queries that will be executed more than once; prepare the query with
SQLPrepare and save the statement handle, reusing it with SQLExecute each time it's executed. This
method is the preferred approach for performance even when there are no encrypted columns, and
allows the driver to take advantage of cached metadata.

Always Encrypted security settings


Force column encryption
To enforce the encryption of a parameter, set the SQL_CA_SS_FORCE_ENCRYPT implementation parameter descriptor
(IPD) field through a call to the SQLSetDescField function. A non-zero value causes the driver to return an error
when no encryption metadata is returned for the associated parameter.

SQLHDESC ipd;
SQLGetStmtAttr(hStmt, SQL_ATTR_IMP_PARAM_DESC, &ipd, 0, 0);
SQLSetDescField(ipd, paramNum, SQL_CA_SS_FORCE_ENCRYPT, (SQLPOINTER)TRUE, SQL_IS_SMALLINT);

If SQL Server informs the driver that the parameter doesn't need to be encrypted, queries using that parameter
will fail. This behavior provides extra protection against security attacks that involve a compromised SQL Server
providing incorrect encryption metadata to the client, which may lead to data disclosure.
Column encryption key caching
To reduce the number of calls to a column master key store to decrypt column encryption keys, the driver
caches the plaintext CEKs in memory. The CEK cache is global to the driver and not associated with any one
connection. After receiving the ECEK from database metadata, the driver first tries to find the plaintext CEK
corresponding to the encrypted key value in the cache. The driver calls the key store containing the CMK only if
it can't find the corresponding plaintext CEK in the cache.
NOTE
In the ODBC Driver for SQL Server, the entries in the cache are evicted after a two hour timeout. This behavior means
that for a given ECEK, the driver contacts the key store only once during the lifetime of the application or every two
hours, whichever is less.

Starting with the ODBC Driver 17.1 for SQL Server, the CEK cache timeout can be adjusted using the
SQL_COPT_SS_CEKCACHETTL connection attribute, which specifies the number of seconds a CEK will remain in the
cache. Because of the global nature of the cache, this attribute can be adjusted from any connection handle valid
for the driver. When the cache TTL is lowered, existing CEKs that would exceed the new TTL are also evicted. If it's
0, no CEKs are cached.
Trusted key paths
Starting with the ODBC Driver 17.1 for SQL Server, the SQL_COPT_SS_TRUSTEDCMKPATHS connection attribute allows
an application to require that Always Encrypted operations only use a specified list of CMKs, identified by their
key paths. By default, this attribute is NULL, which means that the driver accepts any key path. To use this
feature, set SQL_COPT_SS_TRUSTEDCMKPATHS to point to a null-delimited, null-terminated wide-character string that
lists the allowed key path(s). The memory pointed to by this attribute must remain valid during encryption or
decryption operations using the connection handle on which it's set --- upon which the driver will check if the
CMK path as specified by the server metadata is case-insensitively in this list. If the CMK path isn't in the list, the
operation fails. The application can change the contents of memory this attribute points at, to change its list of
trusted CMKs, without setting the attribute again.

Working with column master key stores


To encrypt or decrypt data, the driver needs to obtain a CEK that is configured for the target column. CEKs are
stored in encrypted form (ECEKs) in the database metadata. Each CEK has a corresponding CMK that was used
to encrypt it. The database metadata doesn't store the CMK itself; it only contains the name of the keystore and
information that the keystore can use to locate the CMK.
To obtain the plaintext value of an ECEK, the driver first obtains the metadata about both the CEK and its
corresponding CMK, and then it uses this information to contact the keystore containing the CMK and requests
it to decrypt the ECEK. The driver communicates with a keystore using a keystore provider.
Built-in keystore providers
The ODBC Driver for SQL Server comes with the following built-in keystore providers:

P RO VIDER ( M ETA DATA )


NAME DESC RIP T IO N NAME AVA IL A B IL IT Y

Azure Key Vault Stores CMKs in an Azure AZURE_KEY_VAULT Windows, macOS, Linux
Key Vault

Windows Certificate Store Stores CMKs locally in the MSSQL_CERTIFICATE_STORE Windows


Windows keystore

You (or your DBA) need to make sure that the provider name, configured in the column master key
metadata, is correct and the column master key path complies with the key path format for the given
provider. It's recommended that you configure the keys using tools such as SQL Server Management
Studio, which automatically generates the valid provider names and key paths when issuing the CREATE
COLUMN MASTER KEY (Transact-SQL) statement.
Ensure your application can access the key in the keystore. This process may involve granting your
application access to the key and/or the keystore, depending on the keystore, or doing other keystore-
specific configuration steps. For example, to access an Azure Key Vault, you must provide the correct
credentials to the keystore.
Using the Azure Key Vault provider
Azure Key Vault (AKV) is a convenient option to store and manage column master keys for Always Encrypted
(especially if your applications are hosted in Azure). The ODBC Driver for SQL Server on Linux, macOS, and
Windows includes a built-in column master key store provider for Azure Key Vault. For more information on
configuring an Azure Key Vault for Always Encrypted, see Azure Key Vault - Step by Step, Getting Started with
Key Vault, and Creating Column Master Keys in Azure Key Vault.

NOTE
The ODBC Driver only supports AKV authentication directly against Azure Active Directory. If you are using Azure Active
Directory authentication to AKV and your Active Directory configuration requires authentication against an Active
Directory Federation Services endpoint, authentication may fail. On Linux and macOS, for driver version 17.2 and later,
libcurl is required to use this provider, but is not an explicit dependency since other operations with the driver do not
require it. If you encounter an error regarding libcurl , ensure it is installed.

The driver supports authenticating to Azure Key Vault using the following credential types:
Username/Password - with this method, the credentials are the name of an Azure Active Directory user
and its password.
Client ID/Secret - with this method, the credentials are an application client ID and an application secret.
Managed Identity (17.5.2+) - either system or user-assigned; for more information, see Managed
Identities for Azure resources.
Azure Key Vault Interactive (17.7+ Windows drivers) - with this method, the credentials are authenticated
through Azure Active Directory with Login ID.
To allow the driver to use CMKs stored in AKV for column encryption, use the following connection-string-only
keywords:

C REDEN T IA L T Y P E KEYSTOREAUTHENTICATION KEYSTOREPRINCIPALID KEYSTORESECRET

Username/password KeyVaultPassword User Principal Name Password

Client ID/secret KeyVaultClientSecret Client ID Secret

Managed Identity KeyVaultManagedIdentity Object ID (optional, for (not specified)


user-assigned only)

AKV Interactive KeyVaultInteractive (not set) (not set)

Starting in v17.8, the KeystoreAuthentication and KeystorePrincipalId can be edited using the DSN configuration
UI in the ODBC Datasource Administrator.
Example connection strings
The following connection strings show how to authenticate to Azure Key Vault with the two credential types:
C l i e n t I D / Se c r e t

"DRIVER=ODBC Driver 17 for SQL


Server;SERVER=myServer;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=
KeyVaultClientSecret;KeyStorePrincipalId=<clientId>;KeyStoreSecret=<secret>"
U se r n a m e / P a ssw o r d

"DRIVER=ODBC Driver 17 for SQL


Server;SERVER=myServer;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=
KeyVaultPassword;KeyStorePrincipalId=<username>;KeyStoreSecret=<password>"

M a n a g e d I d e n t i t y (sy st e m - a ssi g n e d )

"DRIVER=ODBC Driver 17 for SQL


Server;SERVER=myServer;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=
KeyVaultManagedIdentity"

M a n a g e d I d e n t i t y (u se r- a ssi g n e d )

"DRIVER=ODBC Driver 17 for SQL


Server;SERVER=myServer;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=
KeyVaultManagedIdentity;KeyStorePrincipalId=<objectID>"

A KV In t er ac t i ve

"DRIVER=ODBC Driver 17 for SQL


Server;SERVER=myServer;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=
KeyVaultInteractive;UID=<userID>;PWD=<password>"

No other ODBC application changes are required to use AKV for CMK storage.

NOTE
The driver contains a list of AKV endpoints which it trusts. Starting with driver version 17.5.2, this list is configurable: set
the AKVTrustedEndpoints property in the driver or DSN's ODBCINST.INI or ODBC.INI registry key (Windows) or
odbcinst.ini or odbc.ini file section (Linux/macOS) to a semicolon-delimited list. Setting it in the DSN takes
precedence over a setting in the driver. If the value begins with a semicolon, it extends the default list; otherwise, it
replaces the default list. The default list (as of 17.5) is
vault.azure.net;vault.azure.cn;vault.usgovcloudapi.net;vault.microsoftazure.de . Starting with 17.7, the list
also includes
managedhsm.azure.net;managedhsm.azure.cn;managedhsm.usgovcloudapi.net;managedhsm.microsoftazure.de .

NOTE
The Azure Key Vault provider built in to the ODBC driver supports both Vaults and Managed HSMs in Azure Key Vault.

Using the Windows Certificate Store provider


The ODBC Driver for SQL Server on Windows includes a built-in column master key store provider for the
Windows Certificate Store, named MSSQL_CERTIFICATE_STORE . (This provider isn't available on macOS or Linux.)
With this provider, the CMK is stored locally on the client machine and no extra configuration by the application
is necessary to use it with the driver. However, the application must have access to the certificate and its private
key in the store. For more information, see Create and Store Column Master Keys (Always Encrypted).
Using custom keystore providers
The ODBC Driver for SQL Server also supports custom third-party keystore providers using the
CEKeystoreProvider interface. This feature allows an application to load, query, and configure keystore providers
so that they can be used by the driver to access encrypted columns. Applications may also directly interact with
a keystore provider to encrypt CEKs for storage in SQL Server and perform tasks beyond accessing encrypted
columns with ODBC; for more information, see Custom Keystore Providers.
Two connection attributes are used to interact with custom keystore providers. They are:
SQL_COPT_SS_CEKEYSTOREPROVIDER

SQL_COPT_SS_CEKEYSTOREDATA

The former is used to load and enumerate loaded keystore providers, while the latter enables application-
provider communications. These connection attributes may be used at any time, before or after establishing a
connection, since application-provider interaction doesn't involve communication with SQL Server. However,
because the driver hasn't been loaded yet, setting and getting these attributes before connecting will cause them
to be processed by the Driver Manager, and may not yield the expected results.
Loading a keystore provider
Setting the SQL_COPT_SS_CEKEYSTOREPROVIDER connection attribute enables a client application to load a provider
library, making available for use the keystore providers contained there.

SQLRETURN SQLSetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER


StringLength);

A RGUM EN T DESC RIP T IO N

ConnectionHandle [Input] Connection handle. Must be a valid connection


handle, but providers loaded via one connection handle are
accessible from any other in the same process.

Attribute [Input] Attribute to set: the


SQL_COPT_SS_CEKEYSTOREPROVIDER constant.

ValuePtr [Input] Pointer to a null-terminated character string


specifying the filename of the provider library. For
SQLSetConnectAttrA, this value is an ANSI (multibyte) string.
For SQLSetConnectAttrW, this value is a Unicode (wchar_t)
string.

StringLength [Input] The length of the ValuePtr string, or SQL_NTS.

The driver attempts to load the library identified by the ValuePtr parameter using the platform-defined dynamic
library loading mechanism ( dlopen() on Linux and macOS, LoadLibrary() on Windows), and adds any
providers defined there to the list of providers known to the driver. The following errors may occur:

ERRO R DESC RIP T IO N

CE203 The dynamic library couldn't be loaded.

CE203 The "CEKeyStoreProvider" exported symbol wasn't found in


the library.

CE203 One or more providers in the library are already loaded.

SQLSetConnectAttr returns the usual error or success values, and more information is available for any errors
that occurred via the standard ODBC diagnostic mechanism.
NOTE
The application programmer must ensure that any custom providers are loaded before any query requiring them is sent
over any connection. Failure to do so results in the error:

ERRO R DESC RIP T IO N

CE200 Keystore provider %1 not found. Ensure that the appropriate


keystore provider library has been loaded.

NOTE
Keystore provider implementors should avoid the use of MSSQL in the name of their custom providers. This term is
reserved exclusively for Microsoft use and may cause conflicts with future built-in providers. Using this term in the name
of a custom provider may result in an ODBC warning.

Getting the list of loaded providers


Getting this connection attribute enables a client application to determine the keystore providers currently
loaded in the driver (including those providers built-in.) This process can only be performed after connecting.

SQLRETURN SQLGetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER


BufferLength, SQLINTEGER * StringLengthPtr);

A RGUM EN T DESC RIP T IO N

ConnectionHandle [Input] Connection handle. Must be a valid connection


handle, but providers loaded via one connection handle are
accessible from any other in the same process.

Attribute [Input] Attribute to retrieve: the


SQL_COPT_SS_CEKEYSTOREPROVIDER constant.

ValuePtr [Output] A pointer to memory in which to return the next


loaded provider name.

BufferLength [Input] The length of the buffer ValuePtr.

StringLengthPtr [Output] A pointer to a buffer in which to return the total


number of bytes (excluding the null-termination character)
available to return in *ValuePtr. If ValuePtr is a null pointer,
no length is returned. If the attribute value is a character
string and the number of bytes available to return is greater
than BufferLength minus the length of the null-termination
character, the data in *ValuePtr is truncated to BufferLength
minus the length of the null-termination character and is
null-terminated by the driver.

To allow retrieving the entire list, every Get operation returns the current provider's name, and increments an
internal counter to the next one. Once this counter reaches the end of the list, an empty string ("") is returned,
and the counter is reset; successive Get operations then continue again from the beginning of the list.
Communicating with keystore providers
The SQL_COPT_SS_CEKEYSTOREDATA connection attribute enables a client application to communicate with loaded
keystore providers for configuring more parameters, keying material, and so on. The communication between a
client application and a provider follows a simple request-response protocol, based on Get and Set requests
using this connection attribute. Communication is initiated only by the client application.

NOTE
Due to the nature of the ODBC calls CEKeyStoreProvider's respond to (SQLGet/SetConnectAttr), the ODBC interface only
supports setting data at the resolution of the connection context.

The application communicates with keystore providers through the driver via the CEKeystoreData structure:

typedef struct CEKeystoreData {


wchar_t *name;
unsigned int dataSize;
char data[];
} CEKEYSTOREDATA;

A RGUM EN T DESC RIP T IO N

name [Input] Upon Set, the name of the provider to which the
data is sent. Ignored upon Get. Null-terminated, wide-
character string.

dataSize [Input] The size of the data array following the structure.

data [InOut] Upon Set, the data to be sent to the provider. This
data may be arbitrary; the driver makes no attempt to
interpret it. Upon Get, the buffer to receive the data read
from the provider.

Writing data to a provider


A SQLSetConnectAttr call using the SQL_COPT_SS_CEKEYSTOREDATA attribute writes a "packet" of data to the
specified keystore provider.

SQLRETURN SQLSetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER


StringLength);

A RGUM EN T DESC RIP T IO N

ConnectionHandle [Input] Connection handle. Must be a valid connection


handle, but providers loaded via one connection handle are
accessible from any other in the same process.

Attribute [Input] Attribute to set: the SQL_COPT_SS_CEKEYSTOREDATA


constant.

ValuePtr [Input] Pointer to a CEKeystoreData structure. The name


field of the structure identifies the provider for which the
data is intended.

StringLength [Input] SQL_IS_POINTER constant

More detailed error information may be obtained via SQLGetDiacRec.


NOTE
The provider can use the connection handle to associate the written data to a specific connection, if it so desires. This
feature is useful for implementing per-connection configuration. It may also ignore the connection context and treat the
data identically regardless of the connection used to send the data. For more information, see Context Association.

Reading data from a provider


A call to SQLGetConnectAttr using the SQL_COPT_SS_CEKEYSTOREDATA attribute reads a "packet" of data from the
last-written-to provider. If there was none, a Function Sequence Error occurs. Keystore provider implementers
are encouraged to support "dummy writes" of 0 bytes as a way of selecting the provider for read operations
without causing other side-effects, if it makes sense to do so.

SQLRETURN SQLGetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER


BufferLength, SQLINTEGER * StringLengthPtr);

A RGUM EN T DESC RIP T IO N

ConnectionHandle [Input] Connection handle. Must be a valid connection


handle, but providers loaded via one connection handle are
accessible from any other in the same process.

Attribute [Input] Attribute to retrieve: the


SQL_COPT_SS_CEKEYSTOREDATA constant.

ValuePtr [Output] A pointer to a CEKeystoreData structure in which


the data read from the provider is placed.

BufferLength [Input] SQL_IS_POINTER constant

StringLengthPtr [Output] A pointer to a buffer in which to return


BufferLength. If *ValuePtr is a null pointer, no length is
returned.

The caller must ensure that a buffer of sufficient length following the CEKEYSTOREDATA structure is allocated for
the provider to write into. Upon return, its dataSize field is updated with the actual length of data read from the
provider. More detailed error information may be obtained via SQLGetDiacRec.
This interface places no extra requirements on the format of data transferred between an application and a
keystore provider. Each provider can define its own protocol/data format, depending on its needs.
For an example of implementing your own keystore provider, see Custom Keystore Providers

Limitations of the ODBC driver when using Always Encrypted


Asynchronous operations
While the ODBC driver will allow the use of asynchronous operations with Always Encrypted, there's a
performance impact on the operations when Always Encrypted is enabled. The call to
sys.sp_describe_parameter_encryption to determine encryption metadata for the statement is blocking and will
cause the driver to wait for the server to return the metadata before returning SQL_STILL_EXECUTING .
Retrieve data in parts with SQLGetData
Before ODBC Driver 17 for SQL Server, encrypted character and binary columns cannot be retrieved in parts
with SQLGetData. Only one call to SQLGetData can be made, with a buffer of sufficient length to contain the
entire column's data.
Send data in parts with SQLPutData
Before ODBC Driver 17.3 for SQL Server, data for insertion or comparison cannot be sent in parts with
SQLPutData. Only one call to SQLPutData can be made, with a buffer containing the entire data. For inserting
long data into encrypted columns, use the Bulk Copy API, described in the next section, with an input data file.
Encrypted money and smallmoney
Encrypted money or smallmoney columns cannot be targeted by parameters, since there's no specific ODBC
data type that maps to those types, resulting in Operand Type Clash errors.

Bulk copy of encrypted columns


Use of the SQL Bulk Copy functions and the bcp utility is supported with Always Encrypted since ODBC Driver
17 for SQL Server. Both plaintext (encrypted on insertion and decrypted on retrieval) and ciphertext (transferred
verbatim) can be inserted and retrieved using the Bulk Copy (bcp_*) APIs and the bcp utility.
To retrieve ciphertext in varbinary(max) form (for example, for bulk loading into a different database),
connect without the ColumnEncryption option (or set it to Disabled ) and perform a BCP OUT operation.
To insert and retrieve plaintext, and let the driver transparently perform encryption and decryption as
required, setting ColumnEncryption to Enabled is sufficient. The functionality of the BCP API is otherwise
unchanged.
To insert ciphertext in varbinary(max) form (for example, as retrieved above), set the BCPMODIFYENCRYPTED
option to TRUE and perform a BCP IN operation. In order for the resulting data to be decrypted, ensure
that the destination column's CEK is the same CEK as the one from which the ciphertext was originally
obtained.
When using the bcp utility: To control the ColumnEncryption setting, use the -D option and specify a DSN
containing the desired value. To insert ciphertext, ensure the ALLOW_ENCRYPTED_VALUE_MODIFICATIONS setting of the
user is enabled.
The following table provides a summary of the actions when operating on an encrypted column:

COLUMNENCRYPTION B C P DIREC T IO N DESC RIP T IO N

Disabled OUT (to client) Retrieves ciphertext. The observed


datatype is varbinar y(max) .

Enabled OUT (to client) Retrieves plaintext. The driver will


decrypt the column data.

Disabled IN (to server) Inserts ciphertext. This setting is


intended for opaquely moving
encrypted data without requiring it to
be decrypted. The operation will fail if
the
ALLOW_ENCRYPTED_VALUE_MODIFICATIONS
option isn't set on the user, or
BCPMODIFYENCRYPTED isn't set on
the connection handle. For more
information, see below.

Enabled IN (to server) Inserts plaintext. The driver will


encrypt the column data.
The BCPMODIFYENCRYPTED option
To prevent data corruption, the server normally doesn't allow inserting ciphertext directly into an encrypted
column, and thus attempts to do so will fail; however, for bulk loading of encrypted data using the BCP API,
setting the BCPMODIFYENCRYPTED bcp_control option to TRUE will allow ciphertext to be inserted directly, and
reduces the risk of corrupting encrypted data over setting the ALLOW_ENCRYPTED_VALUE_MODIFICATIONS option on
the user account. Nonetheless, the keys must match the data and it's a good idea to do some read-only checks
of the inserted data after the bulk insertion and before further use.
For more information, see Migrate Sensitive Data Protected by Always Encrypted.

Always Encrypted API summary


Connection string keywords
NAME DESC RIP T IO N

ColumnEncryption Accepted values are Enabled / Disabled .


Enabled - enables Always Encrypted functionality for the
connection.
Disabled - disable Always Encrypted functionality for the
connection.
attestation protocol, attestation URL - (version 17.4 and
later) enables Always Encrypted with secure enclave using
the specified attestation protocol and the attestation URL.

The default is Disabled .

KeyStoreAuthentication Valid Values: KeyVaultPassword , KeyVaultClientSecret ,


KeyVaultInteractive , KeyVaultManagedIdentity

KeyStorePrincipalId When KeyStoreAuthentication = KeyVaultPassword ,


set this value to a valid Azure Active Directory User Principal
Name.
When KeyStoreAuthetication = KeyVaultClientSecret
set this value to a valid Azure Active Directory Application
Client ID
When KeyStoreAuthetication =
KeyVaultManagedIdentity , set this value to the Object ID
of a user-assigned identity. Otherwise, the system-assigned
identity is used.

KeyStoreSecret When KeyStoreAuthentication = KeyVaultPassword set


this value to the password for the corresponding user name.
When KeyStoreAuthentication =
KeyVaultClientSecret set this value to the Application
Secret associated with a valid Azure Active Directory
Application Client ID

Connection attributes
NAME TYPE DESC RIP T IO N
NAME TYPE DESC RIP T IO N

SQL_COPT_SS_COLUMN_ENCRYPTION Pre-connect SQL_COLUMN_ENCRYPTION_DISABLE (0)


- Disable Always Encrypted
SQL_COLUMN_ENCRYPTION_ENABLE (1) -
Enable Always Encrypted
pointer to
*attestation
protocol*,*attestation URL*
string - (version 17.4 and later) enable
with secure enclave

SQL_COPT_SS_CEKEYSTOREPROVIDER Post-connect [Set] - Attempt to load


CEKeystoreProvider
[Get] - Return a CEKeystoreProvider
name

SQL_COPT_SS_CEKEYSTOREDATA Post-connect [Set] - Write data to


CEKeystoreProvider
[Get] - Read data from
CEKeystoreProvider

SQL_COPT_SS_CEKCACHETTL Post-connect [Set] - Set the CEK cache TTL


[Get] - Get the current CEK cache TTL

SQL_COPT_SS_TRUSTEDCMKPATHS Post-connect [Set] - Set the trusted CMK paths


pointer
[Get] - Get the current trusted CMK
paths pointer

Statement attributes
NAME DESC RIP T IO N

SQL_SOPT_SS_COLUMN_ENCRYPTION SQL_CE_DISABLED (0) - Always Encrypted is disabled for the


statement
SQL_CE_RESULTSETONLY (1) - Decryption Only. Result sets
and return values are decrypted, and parameters aren't
encrypted
SQL_CE_ENABLED (3) - Always Encrypted is enabled and
used for both parameters and results

Descriptor fields
IP D F IEL D SIZ E/ T Y P E DEFA ULT VA L UE DESC RIP T IO N
IP D F IEL D SIZ E/ T Y P E DEFA ULT VA L UE DESC RIP T IO N

SQL_CA_SS_FORCE_ENCRYPT WORD (2 bytes) 0 When 0 (default): decision


(1236) to encrypt this parameter is
determined by availability of
encryption metadata.

When nonzero: if
encryption metadata is
available for this parameter,
it's encrypted. Otherwise,
the request fails with error
[CE300] [Microsoft][ODBC
Driver 17 for SQL
Server]Mandatory
encryption was specified for
a parameter but no
encryption metadata was
provided by the server.

bcp_control options
O P T IO N N A M E DEFA ULT VA L UE DESC RIP T IO N

BCPMODIFYENCRYPTED (21) FALSE When TRUE, allows varbinary(max)


values to be inserted into an
encrypted column. When FALSE,
prevents insertion unless correct type
and encryption metadata is supplied.

Troubleshooting
When having difficulties using Always Encrypted, start by checking the following points:
The CEK that encrypts the desired column is present and accessible on the server.
The CMK that encrypts the CEK has accessible metadata on the server and is also accessible from the
client.
ColumnEncryption is enabled in the DSN, connection string, or connection attribute, and if using the
secure enclave, has the correct format.
Additionally, when using the secure enclave, attestation failures identify the step in the attestation process where
the failure occurred, according to the following table:

ST EP DESC RIP T IO N

0-99 Invalid attestation response, or signature verification error.

100-199 Error retrieving certificates from attestation URL. Ensure


<attestation URL>/v2.0/signingCertificates is valid
and accessible.

200-299 Unexpected or incorrect format of enclave's identity.

300-399 Error establishing secure channel with enclave.


See also
Always Encrypted (Database Engine)
Always Encrypted with secure enclaves
Using Azure Active Directory with the ODBC Driver
4/27/2022 • 13 minutes to read • Edit Online

Download ODBC Driver

Purpose
The Microsoft ODBC Driver for SQL Server version 13.1 or above allows ODBC applications to connect to an
instance of Azure SQL Database using a federated identity in Azure Active Directory. The identity can use a
username/password, an Azure Active Directory access token, an Azure Active Directory managed identity
(17.3+), or Windows-Integrated Authentication (17.6+ on Linux/macOS). For the ODBC Driver version 13.1, the
Azure Active Directory access token authentication is Windows only. The ODBC Driver version 17 and above
support this authentication across all platforms (Windows, Linux, and macOS). A new Azure Active Directory
interactive authentication with Login ID is introduced in ODBC Driver version 17.1 for Windows. A new Azure
Active Directory managed identity authentication method was added in ODBC Driver version 17.3.1.1 for both
system-assigned and user-assigned identities. All of these options are accomplished by using new DSN and
connection string keywords, and connection attributes.
To use Azure Active Directory authentication, you must configure your Azure SQL data source. For more
information, see Configure and manage Azure AD authentication with Azure SQL.

NOTE
The ODBC Driver on Linux and macOS before version 17.6 only supports Azure Active Directory authentication directly
against Azure Active Directory. If you are using Azure Active Directory username/password authentication from a Linux or
macOS client and your Active Directory configuration requires the client to authenticate against an Active Directory
Federation Services endpoint, authentication may fail. As of driver version 17.6, this limitation has been removed.

New and/or Modified DSN and Connection String Keywords


The Authentication keyword can be used when connecting with a DSN or connection string to control the
authentication mode. The value set in the connection string overrides that in the DSN, if provided. The pre-
attribute value of the Authentication setting is the value computed from the connection string and DSN values.

NAME VA L UES DEFA ULT DESC RIP T IO N

Authentication (not set), (empty string), (not set) Controls the authentication
SqlPassword , mode.
ActiveDirectoryPassword
, VA L U E D ESCR IP TIO
N
ActiveDirectoryIntegrated
, (not set) Authentica
ActiveDirectoryInteractive tion mode
, ActiveDirectoryMsi , determine
ActiveDirectoryServicePrincipal d by other
keywords
(existing
legacy
connectio
n options.)
NAME VA L UES DEFA ULT (empty
DESC RIP T IO N (Connectio
string) n string
only.)
Override
and unset
an
Authentication
value set
in the
DSN.

SqlPassword Directly
authentica
te to a
SQL
Server
instance
using a
username
and
password.

Authentica
ActiveDirectoryPassword
te with an
Azure
Active
Directory
identity
using a
username
and
password.

Windows,
ActiveDirectoryIntegrated
and
Linux/Mac
17.6+,
driver
only.
Authentica
te with an
Azure
Active
Directory
identity
using
integrated
authentica
tion.

Windows
ActiveDirectoryInteractive
driver
only.
Authentica
te with an
Azure
Active
Directory
identity
using
interactive
authentica
tion.
NAME VA L UES DEFA ULT DESC RIP T IO N Authentica
ActiveDirectoryMsi
te with
Azure
Active
Directory
identity
using
managed
identity
authentica
tion. For
user-
assigned
identity,
UID is set
to the
object ID
of the
user
identity.

(17.7+)
ActiveDirectoryServicePrincipal
Authentica
te with
Azure
Active
Directory
identity
using
service
principal
authentica
tion. UID
is set to
the client
ID of the
service
principal.
PWD is set
to the
client
secret.
NAME VA L UES DEFA ULT DESC RIP T IO N

Encrypt (not set), Yes / Mandatory (see description) Controls encryption for a
(18.0+), No / Optional connection. If the pre-
(18.0+), Strict (18.0+) attribute value of the
Authentication setting is
not none in the DSN or
connection string, the
default is Yes . The default
is also Yes in versions
18.0.1+. Otherwise, the
default is No . If the
attribute
SQL_COPT_SS_AUTHENTICATION
overrides the pre-attribute
value of Authentication ,
explicitly set the value of
Encryption in the DSN or
connection string or
connection attribute. The
pre-attribute value of
Encryption is Yes if the
value is set to Yes in
either the DSN or
connection string.

New and/or Modified Connection Attributes


The following pre-connect connection attributes have either been introduced or modified to support Azure
Active Directory authentication. When a connection attribute has a corresponding connection string or DSN
keyword and is set, the connection attribute takes precedence.

AT T RIB UT E TYPE VA L UES DEFA ULT DESC RIP T IO N

SQL_COPT_SS_AUTHENTICATION
SQL_IS_INTEGER SQL_AU_NONE , (not set) See description of
SQL_AU_PASSWORD , Authentication
SQL_AU_AD_INTEGRATED keyword above.
, SQL_AU_NONE is
SQL_AU_AD_PASSWORD provided to explicitly
, override a set
SQL_AU_AD_INTERACTIVE Authentication
, SQL_AU_AD_MSI , value in the DSN
SQL_AU_AD_SPA , and/or connection
SQL_AU_RESET
string, while
SQL_AU_RESET
unsets the attribute if
it was set, allowing
the DSN or
connection string
value to take
precedence.
AT T RIB UT E TYPE VA L UES DEFA ULT DESC RIP T IO N

SQL_COPT_SS_ACCESS_TOKEN
S QL_IS_POINTER Pointer to NULL If non-null, specifies
ACCESSTOKEN or the AzureAD Access
NULL Token to use. It's an
error to specify an
access token and also
UID , PWD ,
Trusted_Connection
, or
Authentication
connection string
keywords or their
equivalent attributes.
NOTE: ODBC Driver
version 13.1 only
supports this setting
on Windows.

SQL_COPT_SS_ENCRYPT SQL_IS_INTEGER SQL_EN_OFF , (see description) Controls encryption


SQL_EN_ON for a connection.
SQL_EN_OFF and
SQL_EN_ON disable
and enable
encryption,
respectively. If the
pre-attribute value of
the
Authentication
setting isn't none or
SQL_COPT_SS_ACCESS_TOKEN
is set, and Encrypt
wasn't specified in
either the DSN or
connection string,
the default is
SQL_EN_ON .
Otherwise, the
default is
SQL_EN_OFF . If the
connection attribute
SQL_COPT_SS_AUTHENTICATION
is set to not none ,
explicitly set
SQL_COPT_SS_ENCRYPT
to the desired value if
Encrypt wasn't
specified in the DSN
or connection string.
The effective value of
this attribute controls
whether encryption
will be used for the
connection.
AT T RIB UT E TYPE VA L UES DEFA ULT DESC RIP T IO N

SQL_COPT_SS_OLDPWD - - - Not supported with


Azure Active
Directory, since
password changes to
Azure AD principals
cannot be
accomplished
through an ODBC
connection.

Password expiration
for SQL Server
Authentication was
introduced in SQL
Server 2005. The
SQL_COPT_SS_OLDPWD
attribute was added
to allow the client to
provide both the old
and the new
password for the
connection. When
this property is set,
the provider won't
use the connection
pool for the first
connection or for
future connections,
since the connection
string will contain the
"old password",
which has now
changed.

SQL_COPT_SS_INTEGRATED_SECURITY
SQL_IS_INTEGER SQL_IS_OFF , SQL_IS_OFF Deprecated; use
SQL_IS_ON SQL_COPT_SS_AUTHENTICATION
set to
SQL_AU_AD_INTEGRATED
instead.

Forces use of
Windows
Authentication
(Kerberos on Linux
and macOS) for
access validation on
server login. When
Windows
Authentication is
used, the driver
ignores user identifier
and password values
provided as part of
SQLConnect ,
SQLDriverConnect ,
or
SQLBrowseConnect
processing.
UI Additions for Azure Active Directory (Windows driver only)
The DSN setup and connection UIs of the driver have been enhanced with the more options necessary for using
authentication with Azure AD.
Creating and editing DSNs in the UI
It's possible to use the new Azure AD authentication options when creating or editing an existing DSN using the
driver's setup UI:
Authentication=ActiveDirectoryIntegrated for Azure Active Directory Integrated authentication to Azure SQL
Database

Authentication=ActiveDirectoryPassword for Azure Active Directory username/password authentication to Azure


SQL Database
Authentication=ActiveDirectoryInteractive for Azure Active Directory interactive authentication to Azure SQL
Database

NOTE
As of driver version 17.9, the interactive authentication behavior has changed. Users will always be prompted for
credentials unless the driver has a valid access token cached. This change prevents users on Azure Active Directory joined
devices from skipping the prompt and automatically signing in with cached credentials when using
ActiveDirectoryInteractive authentication.

Authentication=SqlPassword for username/password authentication to SQL Server (Azure or otherwise)

Trusted_Connection=Yes for Windows legacy SSPI-integrated authentication


Authentication=ActiveDirectoryMsi for Azure Active Directory Managed Identity authentication

Authentication=ActiveDirectoryServicePrincipal for Azure Active Directory service principal authentication


The seven options correspond to Trusted_Connection=Yes (existing legacy Windows SSPI-only integrated
authentication) and Authentication= ActiveDirectoryIntegrated , SqlPassword , ActiveDirectoryPassword ,
ActiveDirectoryInteractive , ActiveDirectoryMsi , and ActiveDirectoryServicePrincipal respectively.

SQLDriverConnect Prompt (Windows driver only)


The prompt dialog displayed by SQLDriverConnect when it requests information required to complete the
connection contains four new options for Azure AD authentication:

These options correspond to the same six available in the DSN setup UI above.
Example connection strings
1. SQL Server Authentication - legacy syntax. Server certificate isn't validated, and encryption is used only if the
server enforces it. The username/password is passed in the connection string.
server=Server;database=Database;UID=UserName;PWD=Password;
2. SQL Authentication - new syntax. The client requests encryption (the default value of Encrypt is true ) and
the server certificate gets validated, whatever the encryption setting (unless TrustServerCertificate is set to
true ). The username/password is passed in the connection string.
server=Server;database=Database;UID=UserName;PWD=Password;Authentication=SqlPassword;
3. Integrated Windows Authentication (Kerberos on Linux and macOS) using SSPI (to SQL Server or SQL IaaS) -
current syntax. Server certificate isn't validated, unless encryption is used.
server=Server;database=Database;Trusted_Connection=yes;
4. (Windows driver only.) Integrated Windows Authentication using SSPI (if the target database is in SQL Server
or SQL IaaS) - new syntax. The client requests encryption (the default value of Encrypt is true ) and the
server certificate gets validated, whatever the encryption setting (unless TrustServerCertificate is set to
true ). server=Server;database=Database;Authentication=ActiveDirectoryIntegrated;
5. Azure Active Directory Username/Password Authentication (if the target database is in Azure SQL Database).
Server certificate gets validated, whatever the encryption setting (unless TrustServerCertificate is set to
true ). The username/password is passed in the connection string.
server=Server;database=Database;UID=UserName;PWD=Password;Authentication=ActiveDirectoryPassword;
6. (Windows, and Linux/macOS 17.6+, driver only.) Integrated Windows Authentication using ADAL or
Kerberos, which involves redeeming Windows account credentials for an Azure AD-issued access token,
assuming the target database is in Azure SQL Database. Server certificate gets validated, whatever the
encryption setting (unless TrustServerCertificate is set to true ). On Linux/macOS, a suitable Kerberos
ticket needs to be available. For more information, see the section below on Federated Accounts and Using
Integrated Authentication. server=Server;database=Database;Authentication=ActiveDirectoryIntegrated;
7. (Windows driver only.) Azure AD Interactive Authentication uses Azure Active Directory Multi-Factor
Authentication technology to set up connection. In this mode, by providing the login ID, an Azure
Authentication dialog is triggered and allows the user to input the password to complete the connection. The
username is passed in the connection string.
server=Server;database=Database;UID=UserName;Authentication=ActiveDirectoryInteractive;

8. Azure Active Directory Managed Identity Authentication uses system-assigned or user-assigned identity for
authentication to set up connection. For user-assigned identity, UID is set to the object ID of the user identity.
For system-assigned identity,
server=Server;database=Database;Authentication=ActiveDirectoryMsi;
For user-assigned identity with object ID equals to myObjectId,
server=Server;database=Database;UID=myObjectId;Authentication=ActiveDirectoryMsi;
9. Azure Active Directory Service Principal Authentication
server=Server;database=Database;UID=clientId;PWD=clientSecret;Authentication=ActiveDirectoryServicePrincipal;
NOTE
When using the Active Directory options with the Windows ODBC driver prior to version 17.4.2, ensure that the
Active Directory Authentication Library for SQL Server has been installed. When using the Linux and macOS drivers,
ensure that libcurl has been installed. For driver version 17.2 and later, this is not an explicit dependency since it is
not required for the other authentication methods or ODBC operations.
When Azure Active Directory configuration includes Conditional Access policies, and the client is Windows 10 or Server
2016 or later, authentication via Integrated or username/password may fail. Conditional Access policies require the use
of Web Account Manager (WAM), which is supported in driver version 17.6 or later for Windows. To use WAM, create
a new string or DWORD value named ADALuseWAM in
HKLM\Software\ODBC\ODBCINST.INI\ODBC Driver 17 for SQL Server ,
HKCU\Software\ODBC\ODBC.INI\<your-user-DSN-name> , or
HKLM\Software\ODBC\ODBC.INI\<your-system-DSN-name> for global, user DSN, or system DSN-scoped configuration
respectively, and set it to a value of 1. Note that authentication with WAM does not support running the application
as a different user with runas . Scenarios which require Condtitional Access policies are not supported for Linux or
macOS.
To connect using a SQL Server account username and password, you may now use the new SqlPassword option,
which is recommended especially for Azure SQL since this option enables more secure connection defaults.
To connect using an Azure Active Directory account username and password, specify
Authentication=ActiveDirectoryPassword in the connection string and the UID and PWD keywords with the
username and password, respectively.
To connect using Windows Integrated or Active Directory Integrated (Windows, and Linux/macOS 17.6+, driver only)
authentication, specify Authentication=ActiveDirectoryIntegrated in the connection string. The driver will choose
the correct authentication mode automatically. For driver versions 17.7 or earlier, UID and PWD must not be
specified. Beginning with driver version 17.8, UID and PWD are ignored.
To connect using Active Directory Interactive (Windows driver only) authentication, UID must be specified. For driver
versions 17.7 and earlier, PWD must not be specified. Beginning with driver version 17.8, PWD is ignored.

Authenticating with an Access Token


The SQL_COPT_SS_ACCESS_TOKEN pre-connection attribute allows the use of an access token obtained from Azure
AD for authentication instead of username and password, and also bypasses the negotiation and obtaining of an
access token by the driver. To use an access token, set the SQL_COPT_SS_ACCESS_TOKEN connection attribute to a
pointer to an ACCESSTOKEN structure:

typedef struct AccessToken


{
DWORD dataSize;
BYTE data[];
} ACCESSTOKEN;

The ACCESSTOKEN is a variable-length structure consisting of a 4-byte length followed by length bytes of opaque
data that form the access token. Because of how SQL Server handles access tokens, one obtained via an OAuth
2.0 JSON response must be expanded so that each byte is followed by a zero padding byte, similar to a UCS-2
string containing only ASCII characters. However, the token is an opaque value and the length specified, in bytes,
must NOT include any null terminator. Because of their considerable length and format constraints, this method
of authentication is only available programmatically via the SQL_COPT_SS_ACCESS_TOKEN connection attribute.
There's no corresponding DSN or connection string keyword. The connection string must not contain UID , PWD ,
Authentication , or Trusted_Connection keywords.
NOTE
The ODBC Driver version 13.1 only supports this authentication on Windows. Subsequent versions support this
authentication on all platforms.

Azure Active Directory Authentication Sample Code


The following sample shows the code required to connect to SQL Server using Azure Active Directory with
connection keywords. There's no need to change the application code itself. The connection string, or DSN if one
is used, is the only modification needed to use Azure AD for authentication:

...
SQLCHAR connString[] = "Driver={ODBC Driver 17 for SQL Server};Server=
{server};UID=myuser;PWD=myPass;Authentication=ActiveDirectoryPassword"
...
SQLDriverConnect(hDbc, NULL, connString, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
...

The following sample shows the code required to connect to SQL Server using Azure Active Directory with
access token authentication. In this case, it's necessary to modify application code to process the access token
and set the associated connection attribute.

SQLCHAR connString[] = "Driver={ODBC Driver 17 for SQL Server};Server={server}"


SQLCHAR accessToken[] = "eyJ0eXAiOi..."; // In the format extracted from an OAuth JSON response
...
DWORD dataSize = 2 * strlen(accessToken);
ACCESSTOKEN *pAccToken = malloc(sizeof(ACCESSTOKEN) + dataSize);
pAccToken->dataSize = dataSize;
// Expand access token with padding bytes
for(int i = 0, j = 0; i < dataSize; i += 2, j++) {
pAccToken->data[i] = accessToken[j];
pAccToken->data[i+1] = 0;
}
...
SQLSetConnectAttr(hDbc, SQL_COPT_SS_ACCESS_TOKEN, (SQLPOINTER)pAccToken, SQL_IS_POINTER);
SQLDriverConnect(hDbc, NULL, connString, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
...
free(pAccToken);

The following sample connection string is for use with Azure Active Directory Interactive Authentication. It
doesn't contain PWD field as the password would be entered on the Azure Authentication screen.

SQLCHAR connString[] = "Driver={ODBC Driver 17 for SQL Server};Server=


{server};UID=myuser;Authentication=ActiveDirectoryInteractive"

The following sample connection string is for use with Azure Active Directory Managed Identity Authentication.
UID is set to the object ID of the user identity when using a user-assigned identity.

// For system-assigned identity,


SQLCHAR connString[] = "Driver={ODBC Driver 17 for SQL Server};Server=
{server};Authentication=ActiveDirectoryMsi"
...
// For user-assigned identity with object ID equals to myObjectId
SQLCHAR connString[] = "Driver={ODBC Driver 17 for SQL Server};Server=
{server};UID=myObjectId;Authentication=ActiveDirectoryMsi"
Considerations for using ADFS Federated Accounts on Linux/macOS
Starting with version 17.6, the drivers for Linux and macOS support authentication using Azure Active Directory
ADFS-federated accounts using either username/password ( ActiveDirectoryPassword ) or Kerberos (
ActiveDirectoryIntegrated ). There are some limitations dependent on the platform when using Integrated
mode.
When authenticating with a user whose UPN suffix is different from the Kerberos realm, that is, an alternate
UPN suffix is in use, it's necessary to use the Enterprise Principal option (use the -E option with kinit , and
supply the principal name in the form user@federated-domain ) when obtaining Kerberos tickets. This way, the
driver can correctly determine both the federated domain and the Kerberos realm.
You can verify that a suitable Kerberos ticket is available by inspecting the output of the klist command. If the
federated domain is the same as the Kerberos realm and UPN suffix, the principal name will be of the form
user@realm . If it's different, the principal name should be of the form user@federated-domain@realm .

Linux
On SuSE 11, the default Kerberos library version of 1.6.x doesn't support the Enterprise Principal option
necessary to use alternate UPN suffixes. To use alternate UPN suffixes with Azure AD Integrated authentication,
upgrade the Kerberos library to 1.7 or newer.
On Alpine Linux, the default libcurl doesn't support the SPNEGO/Kerberos authentication required for Azure
AD Integrated authentication.
macOS
The system Kerberos library kinit supports Enterprise Principal with the --enterprise option, but also
implicitly does name canonicalization, which prevents the use of alternate UPN suffixes. To use alternate UPN
suffixes with Azure AD Integrated authentication, install a newer Kerberos library via brew install krb5 and use
its kinit with the -E option as described above.

See Also
Token-based authentication support for Azure SQL Database using Azure AD auth
Using Integrated Authentication
Using Transparent Network IP Resolution with the
ODBC Driver
4/27/2022 • 2 minutes to read • Edit Online

Download ODBC Driver


TransparentNetworkIPResolution is a revision of the existing MultiSubnetFailover feature, available starting with
Microsoft ODBC Driver 13.1 for SQL Server, that affects the connection sequence of the driver in the case where
the first resolved IP of the hostname does not respond and there are multiple IPs associated with the hostname.
It interacts with MultiSubnetFailover to provide the following three connection sequences:
0: One IP is attempted, followed by all IPs in parallel
1: All IPs are attempted in parallel
2: All IPs are attempted one after another

T RA N SPA REN T N ET W O RK IP RESO L UT IO


N M ULT ISUB N ET FA ILO VER B EH AVIO R

(default) (default) 0

(default) Enabled 1

(default) Disabled 0

Enabled (default) 0

Enabled Enabled 1

Enabled Disabled 0

Disabled (default) 2

Disabled Enabled 1

Disabled Disabled 2

The TransparentNetworkIPResolution connection string and DSN keyword controls this setting at the connection-
string level. The default is enabled.

K EY W O RD VA L UES DEFA ULT

TransparentNetworkIPResolution Enabled , Disabled Enabled

The SQL_COPT_SS_TNIR pre-connection attribute allows an application to control this setting programmatically:
C O N N EC T IO N
AT T RIB UT E SIZ E/ T Y P E DEFA ULT VA L UE DESC RIP T IO N

SQL_COPT_SS_TNIR SQL_IS_INTEGER or SQL_IS_ON (1), SQL_IS_ON Enables or disables


(1249) SQL_IS_UINTEGER SQL_IS_OFF (0) TNIR.

For more information about MultiSubnetFailover, see ODBC Driver on


Linux and macOS - High Availability and Disaster Recovery
See Also
Microsoft ODBC Driver for SQL Server on Windows
SQL Server Multi-Subnet Clustering (SQL Server)
Data Classification
4/27/2022 • 5 minutes to read • Edit Online

Download ODBC Driver

Overview
For managing sensitive data, SQL Server and Azure SQL Server introduced the ability to provide database
columns with sensitivity metadata that allows the client application to handle different types of sensitive data
(such as health, financial, etc.) in accordance with data protection policies.
For more information on how to assign classification to columns, see SQL Data Discovery and Classification.
Microsoft ODBC Driver 17.2 or later allows the retrieval of this metadata via SQLGetDescField using the
SQL_CA_SS_DATA_CLASSIFICATION field identifier.

Format
SQLGetDescField has the following syntax:

SQLRETURN SQLGetDescField(
SQLHDESC DescriptorHandle,
SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier,
SQLPOINTER ValuePtr,
SQLINTEGER BufferLength,
SQLINTEGER * StringLengthPtr);

DescriptorHandle
[Input] IRD (Implementation Row Descriptor) handle. Can be retrieved by a call to SQLGetStmtAttr with
SQL_ATTR_IMP_ROW_DESC statement attribute
RecNumber
[Input] 0
FieldIdentifier
[Input] SQL_CA_SS_DATA_CLASSIFICATION
ValuePtr
[Output] Output buffer
BufferLength
[Input] Length of output buffer in bytes
StringLengthPtr [Output] Pointer to the buffer in which to return the total number of bytes available to return in
ValuePtr.

NOTE
If the size of the buffer is unknown, it can be determined by calling SQLGetDescField with ValuePtr as NULL and
examining the value of StringLengthPtr.

If Data Classification information isn't available, an Invalid Descriptor Field error will be returned.
Upon a successful call to SQLGetDescField, the buffer pointed to by ValuePtr will contain the following data:
nn nn [n sensitivitylabels] tt tt [t informationtypes] cc cc [c columnsensitivitys]

NOTE
nn nn , tt tt , and cc cc are multibyte integers, which are stored with the least significant byte at the lowest
address.

sensitivitylabel and informationtype are both of the form


nn [n bytes name] ii [i bytes id]

columnsensitivity is of the form


nn nn [n sensitivityprops]

For each column (c), n 4-byte sensitivityprops are present:


ss ss tt tt

s - index into the sensitivitylabels array, FF FF if not labeled


t - index into the informationtypes array, FF FF if not labeled

The format of the data can be expressed as the following pseudo-structures:

struct IDnamePair {
BYTE nameLen;
USHORT name[nameLen];
BYTE idLen;
USHORT id[idLen];
};

struct SensitivityProp {
USHORT labelIdx;
USHORT infoTypeIdx;
};

USHORT nLabels;
struct IDnamePair labels[nLabels];
USHORT nInfoTypes;
struct IDnamePair infotypes[nInfoTypes];
USHORT nColumns;
struct {
USHORT nProps;
struct SensitivityProp[nProps];
} columnClassification[nColumns];

Code sample
Test application that demonstrates how to read Data Classification metadata. On Windows it can be compiled
using cl /MD dataclassification.c /I (directory of msodbcsql.h) /link odbc32.lib and run with a connection
string, and a SQL query (that returns classified columns) as parameters:

#ifdef _WIN32
#include <windows.h>
#endif
#include <sql.h>
#include <sql.h>
#include <sqlext.h>
#include <msodbcsql.h>
#include <stdio.h>
SQLHANDLE env, dbc, stmt;
void checkRC_exit(SQLRETURN rc, SQLHANDLE hand, SQLSMALLINT htype, int retcode, char *action)
{
if ((rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO) && hand)
{
char msg[1024], state[6];
int i = 0;
SQLRETURN rc2;
SQLINTEGER err;
SQLSMALLINT lenout;
while ((rc2 = SQLGetDiagRec(htype, hand, ++i, state, &err, msg, sizeof(msg), &lenout)) ==
SQL_SUCCESS ||
rc2 == SQL_SUCCESS_WITH_INFO)
printf("%d (%d)[%s]%s\n", i, err, state, msg);
}
if (rc == SQL_ERROR && retcode)
{
printf("Error occurred%s%s\n", action ? " upon " : "", action ? action : "");
exit(retcode);
}
}
void printLabelInfo(char *type, char **pptr)
{
char *ptr = *pptr;
unsigned short nlabels;
printf("----- %s(%u) -----\n", type, nlabels = *(unsigned short*)ptr);
ptr += sizeof(unsigned short);
while (nlabels--)
{
int namelen, idlen;
char *nameptr, *idptr;
namelen = *ptr++;
nameptr = ptr;
ptr += namelen * 2;
idlen = *ptr++;
idptr = ptr;
ptr += idlen * 2;
wprintf(L"Name: \"%.*s\" Id: \"%.*s\"\n", namelen, nameptr, idlen, idptr);
}
*pptr = ptr;
}
int main(int argc, char **argv)
{
unsigned char *dcbuf;
unsigned int dclen = 0;
SQLRETURN rc;
SQLHANDLE ird;
if (argc < 3)
{
fprintf(stderr, "usage: dataclassification connstr query\n");
return 1;
}
checkRC_exit(SQLAllocHandle(SQL_HANDLE_ENV, 0, &env), 0, 0,
2, "allocate environment");
checkRC_exit(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0), env,
SQL_HANDLE_ENV,
3, "set ODBC version");
checkRC_exit(SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc), env, SQL_HANDLE_ENV,
4, "allocate connection");
checkRC_exit(SQLDriverConnect(dbc, 0, argv[1], SQL_NTS, 0, 0, 0, SQL_DRIVER_NOPROMPT), dbc,
SQL_HANDLE_DBC,
5, "connect to server");
checkRC_exit(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt), dbc, SQL_HANDLE_DBC,
6, "allocate statement");
checkRC_exit(SQLExecDirect(stmt, argv[2], SQL_NTS), stmt, SQL_HANDLE_STMT,
7, "execute query");
checkRC_exit(SQLGetStmtAttr(stmt, SQL_ATTR_IMP_ROW_DESC, (SQLPOINTER)&ird, SQL_IS_POINTER, 0), stmt,
SQL_HANDLE_STMT,
8, "get IRD handle");
rc = SQLGetDescFieldW(ird, 0, SQL_CA_SS_DATA_CLASSIFICATION, dcbuf, 0, &dclen);
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
{
checkRC_exit(rc, ird, SQL_HANDLE_DESC, 0, 0);
printf("Error reading SQL_CA_SS_DATA_CLASSIFICATION IRD field. Ensure that the driver and\n"
"server both support the Data Classification feature, and that the query returns columns\n"
"with classification information.\n");
}
else
{
SQLINTEGER dclenout;
unsigned char *dcptr;
unsigned short ncols;
printf("Data Classification information (%u bytes):\n", dclen);
if (!(dcbuf = malloc(dclen)))
{
printf("Memory Allocation Error");
return 9;
}
checkRC_exit(SQLGetDescFieldW(ird, 0, SQL_CA_SS_DATA_CLASSIFICATION, dcbuf, dclen, &dclenout),
ird, SQL_HANDLE_DESC, 10, "reading SQL_CA_SS_DATA_CLASSIFICATION");
dcptr = dcbuf;
printLabelInfo("Labels", &dcptr);
printLabelInfo("Information Types", &dcptr);
printf("----- Column Sensitivities(%u) -----\n", ncols = *(unsigned short*)dcptr);
dcptr += sizeof(unsigned short);
while (ncols--)
{
unsigned short nprops = *(unsigned short*)dcptr;
dcptr += sizeof(unsigned short);
while (nprops--)
{
unsigned short labelidx, typeidx;
labelidx = *(unsigned short*)dcptr; dcptr += sizeof(unsigned short);
typeidx = *(unsigned short*)dcptr; dcptr += sizeof(unsigned short);
printf(labelidx == 0xFFFF ? "(none) " : "%u ", labelidx);
printf(typeidx == 0xFFFF ? "(none)\n" : "%u\n", typeidx);
}
printf("-----\n");
}
if (dcptr != dcbuf + dclen)
{
printf("Error: unexpected parse of DATACLASSIFICATION data\n");
return 11;
}
free(dcbuf);
}
return 0;
}

Supported Version
Microsoft ODBC Driver 17.2 allows the retrieval of Data Classification information via SQLGetDescField if
FieldIdentifier is set to SQL_CA_SS_DATA_CLASSIFICATION (1237).

Starting from Microsoft ODBC Driver 17.4.1.1, it's possible to retrieve the version of Data Classification
supported by a server via SQLGetDescField using the SQL_CA_SS_DATA_CLASSIFICATION_VERSION (1238) field
identifier. In 17.4.1.1, the supported data classification version is set to "2".
Starting from 17.4.2.1, the default version of data classification is set to "1" and is the version the driver reports
to SQL Server as supported. A new connection attribute SQL_COPT_SS_DATACLASSIFICATION_VERSION (1400) can
allow application to change the supported version of Data Classification from "1" up to the maximum
supported.
Example:
To set the version, this call should be made right before the SQLConnect or SQLDriverConnect call:

ret = SQLSetConnectAttr(dbc, SQL_COPT_SS_DATACLASSIFICATION_VERSION, (SQLPOINTER)2, SQL_IS_INTEGER);

The value of the currently supported version of Data Classification can be retrieved via SQLGetConnectAttr call:

ret = SQLGetConnectAttr(dbc, SQL_COPT_SS_DATACLASSIFICATION_VERSION, (SQLPOINTER)&dataClassVersion,


SQL_IS_INTEGER, 0);
Using XA Transactions
4/27/2022 • 16 minutes to read • Edit Online

Download ODBC Driver

Overview
The Microsoft ODBC Driver for SQL Server, starting from version 17.3, provides support for XA transactions
with the Distributed Transaction Coordinator (DTC) on Windows, Linux, and macOS. The XA implementation on
the driver side enables the client application to send serial operations (such as start, commit, rollback a
transaction branch, and so on) to the Transaction Manager (TM). And then the TM will communicate with the
Resource Manager (RM) according to these operations. For more information about the XA Specification and the
Microsoft implementation for DTC (MS DTC), see How It Works: SQL Server DTC(MSDTC and XA Transactions).

The XACALLPARAM Structure


The XACALLPARAM structure defines the information required for an XA transaction manager request. It's defined
as follows:

typedef struct XACallParam {


unsigned int sizeParam;
int operation;
XID xid;
int flags;
int status;
unsigned int sizeData;
unsigned int sizeReturned;
} XACALLPARAM, *PXACALLPARAM;

sizeParam
Size of the XACALLPARAM structure. This size excludes the size of the data following XACALLPARAM .
operation
The XA operation to be passed to the TM. Possible operations are defined in xadefs.h.
xid
Transaction branch identifier.
flags
Flags associated with the TM request. Possible values are defined in xadefs.h.
status
Return status from the TM. See xadefs.h header for possible return statuses.
sizeData
Size of the data buffer following XACALLPARAM .
sizeReturned
Size of data returned.
To make a TM request, the SQLSetConnectAttr function needs to be called with attribute
SQL_COPT_SS_ENLIST_IN_XA and a pointer to the XACALLPARAM object.
SQLSetConnectAttr(hdbc, SQL_COPT_SS_ENLIST_IN_XA, param, SQL_IS_POINTER); // XACALLPARAM *param

Code Sample
The following example shows how to communicate with the TM for XA transactions and execute different
operations from a client application. If the test is run against Microsoft SQL Server, the MS DTC needs to be
properly configured to enable XA transactions. The XA definitions can be found in the xadefs.h header file.

// XA-DTC.cpp : Defines the entry point for the console application.


//

#include "sqlwindef.h"
#include "xplatsec.h"

#include <sql.h>
#include <sqlext.h>
#include "XaTestRunner.h"

#include <iostream>
#include <string>
#include <memory>
#include <thread>
#include <chrono>

enum class TestType { Commit, Commit1Phase, Rollback, Recover};

RETCODE GetRowCount(HSTMT hstmt, const std::string tableName, int& count)


{
char query[256];
count = 0;
sprintf_s(query, sizeof(query), "SELECT COUNT(*) FROM %s", tableName.c_str());
RETCODE rc = SQLExecDirectA(hstmt, (SQLCHAR*)query, SQL_NTS);
XaTestRunner::CheckRC(rc, "GetRowCount::SQLExecDirectA", hstmt, SQL_HANDLE_STMT);
if (!SQL_SUCCEEDED(rc))
{
return rc;
}

rc = SQLFetch(hstmt);
XaTestRunner::CheckRC(rc, "GetRowCount::SQLFetch", hstmt, SQL_HANDLE_STMT);
if (!SQL_SUCCEEDED(rc))
{
return rc;
}

rc = SQLGetData(hstmt, 1, SQL_C_LONG, &count, sizeof(count), NULL);


XaTestRunner::CheckRC(rc, "GetRowCount::SQLGetData", hstmt, SQL_HANDLE_STMT);

return rc;
}

bool TestXaRunner(HDBC hdbc, const char* connString, TestType testType, int timeout = 0)
{
SQLRETURN rc = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)connString, SQL_NTS, NULL, 0, NULL,
SQL_DRIVER_NOPROMPT);
XaTestRunner::CheckRC(rc, "TestXaRunner::Connecting", hdbc, SQL_HANDLE_DBC);
if (!SQL_SUCCEEDED(rc))
{
return false;
}

SQLHSTMT hstmt;
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
XaTestRunner::CheckRC(rc, "TestXaRunner::Alloc statement", hdbc, SQL_HANDLE_DBC);
const int ROWS_TO_TEST = 10;
int rowCount = 0;
bool result = false;

if (SQL_SUCCEEDED(rc))
{
std::string tableName;
auto testRunner = std::make_shared<XaTestRunner>(hdbc);
testRunner->GetUniqueName(tableName);
bool isTableCreated = false;
RETCODE xaStatus = SQL_ERROR;
bool isTimeoutTest = false;

XID xid;
XaTestRunner::GetUniqueXid(xid);

do
{
if (!(isTableCreated = testRunner->CreateTable(tableName)))
{
std::cout << "TestXaRunner::Failed to create table " << tableName.c_str() << std::endl;
break;
}

if (timeout > 0)
{
testRunner->SetTimeout(timeout);
isTimeoutTest = true;
}

rc = testRunner->Start(xid, TMNOFLAGS, xaStatus);


if (SQL_SUCCEEDED(xaStatus))
{
rc = testRunner->ExecuteInsertSequence(tableName, ROWS_TO_TEST, hstmt);
XaTestRunner::CheckRC(rc, "TestXaRunner::ExecuteInsertSequence", hstmt, SQL_HANDLE_STMT);

if (isTimeoutTest)
{
auto timeToSleep = timeout + 5;
std::cout << "Sleep for " << timeToSleep << " seconds" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(timeToSleep));
}

rc = testRunner->End(xid, TMSUCCESS, xaStatus);


if (xaStatus < 0)
{
std::cout << "TestXaRunner::XA End failed status=" << xaStatus << std::endl;
break;
}

switch (testType)
{
case TestType::Commit:
rc = testRunner->Prepare(xid, xaStatus);
if (xaStatus < 0)
{
std::cout << "TestXaRunner::XA Prepare failed status=" << xaStatus << std::endl;
}
else
{
rc = testRunner->Commit(xid, false, xaStatus);
if (xaStatus < 0)
{
std::cout << "TestXaRunner::XA Commit failed status=" << xaStatus << std::endl;
}
}
break;
case TestType::Commit1Phase:
case TestType::Commit1Phase:
rc = testRunner->Commit(xid, true, xaStatus);
if (xaStatus < 0)
{
std::cout << "TestXaRunner::XA Commit one phase failed status=" << xaStatus <<
std::endl;
}
break;
case TestType::Rollback:
rc = testRunner->Rollback(xid, xaStatus);
if (xaStatus < 0)
{
std::cout << "TestXaRunner::XA Rollback failed status=" << xaStatus << std::endl;
}
break;
case TestType::Recover:
break;
default:
break;
}
}
else
{
std::cout << "TestXaRunner::XA Start failed status=" << xaStatus << std::endl;
}

} while (false);

if (isTimeoutTest)
{
result = xaStatus == XAER_NOTA;
std::cout << "TestXaRunner::TimeoutTest" " xaStatus=" << xaStatus << " test " << (result ?
"Succeded" : "Failed") << std::endl;
}
else
{
auto isCommit = testType == TestType::Commit || testType == TestType::Commit1Phase;

rc = GetRowCount(hstmt, tableName, rowCount);


result = (rowCount == (isCommit ? ROWS_TO_TEST : 0)) && SQL_SUCCEEDED(xaStatus);

std::cout << "TestXaRunner::" << (isCommit ? "Commit" : "Rollback") << " rowCount=" << rowCount
<< " xaStatus=" << xaStatus << " test " << (result ? "Succeded" : "Failed") << std::endl;
}

if (isTableCreated)
{
testRunner->DropTable(tableName);
}

rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
rc = SQLDisconnect(hdbc);
}

return result;
}

bool TestCommit(HDBC hdbc, const char* connectionString)


{
return TestXaRunner(hdbc, connectionString, TestType::Commit);
}

bool TestCommit1Phase(HDBC hdbc, const char* connectionString)


{
return TestXaRunner(hdbc, connectionString, TestType::Commit1Phase);
}
bool TestRollback(HDBC hdbc, const char* connectionString)
{
return TestXaRunner(hdbc, connectionString, TestType::Rollback);
}

bool TestSetTimeout(HDBC hdbc, const char* connectionString)


{
bool result = false;
result = TestXaRunner(hdbc, connectionString, TestType::Commit, 2);
result = TestXaRunner(hdbc, connectionString, TestType::Rollback, 5);

return result;
}

bool TestRecover(HDBC hdbc, const char* connectionString)


{
SQLRETURN rc = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)connectionString, SQL_NTS, NULL, 0, NULL,
SQL_DRIVER_NOPROMPT);
XaTestRunner::CheckRC(rc, "TestXaRunner::Connecting", hdbc, SQL_HANDLE_DBC);
if (!SQL_SUCCEEDED(rc))
{
return false;
}

const int ROWS_TO_TEST = 10;


const int transactionCount = 2;
int rowCount = 0;
bool result = false;
std::vector<std::string> tableNames;
auto testRunner = std::make_shared<XaTestRunner>(hdbc);
auto numCompletedTransactions = 0;
RETCODE xaStatus = SQL_ERROR;
const int sleepTime = 2;

for (auto tr = 0; tr < transactionCount; tr++)


{
std::string tbName;
testRunner->GetUniqueName(tbName);
bool isTableCreated = false;
RETCODE xaStatus = SQL_ERROR;

std::cout << "Started transaction " << tr << std::endl;


do
{
if (!(isTableCreated = testRunner->CreateTable(tbName)))
{
tableNames.emplace_back("");
std::cout << "TestRecover::Failed to create table " << tbName.c_str() << std::endl;
break;
}
tableNames.push_back(std::move(tbName));

XID xid;
XaTestRunner::GetUniqueXid(xid);
rc = testRunner->Start(xid, TMNOFLAGS, xaStatus);
if (xaStatus < 0)
{
std::cout << "TestXaRunner::XA Start failed status=" << xaStatus << std::endl;
break;
}

rc = testRunner->ExecuteInsertSequence(tableNames[tr], ROWS_TO_TEST);

rc = testRunner->End(xid, TMSUCCESS, xaStatus);


if (xaStatus < 0)
{
std::cout << "TestXaRunner::XA End failed status=" << xaStatus << std::endl;
break;
break;
}

std::cout << "Completed transaction " << tr << " formatId=" <<xid.formatID <<std::endl;
numCompletedTransactions++;

rc = testRunner->Prepare(xid, xaStatus);
std::cout << "Prepared transaction " << tr << std::endl;

} while (false);
}

std::cout << "Sleep for " << sleepTime << "seconds" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(sleepTime));

std::vector<unsigned char> buff(8092);


unsigned int buffSize = static_cast<unsigned int>(buff.size());
testRunner->Recover(TMSTARTRSCAN | TMENDRSCAN, &buff[0], buffSize, xaStatus);
std::cout << "TestRecover:: After Recover buffSize=" << buffSize << " xaStatus=" << xaStatus <<
std::endl;
if (SQL_SUCCEEDED(xaStatus))
{
auto numRecoveredTransactions = buffSize / sizeof(XID);
std::cout << "TestRecover:: After Recover numRecoveredTransactions=" << numRecoveredTransactions <<
std::endl;
result = numCompletedTransactions == numRecoveredTransactions;
XID* pXid = (XID*)&buff[0];
for (auto tr = 0; tr < numRecoveredTransactions; tr++, pXid++)
{
rc = testRunner->Commit(*pXid, false, xaStatus);
if (SQL_SUCCEEDED(xaStatus))
{
std::cout << "TestRecover::Successfully committed recovered transaction " << tr << "
formatId=" << pXid->formatID << std::endl;
}
else
{
std::cout << "TestRecover::Attempt to commit recovered transaction " << tr << " failed
status=" << xaStatus << " formatId=" << pXid->formatID << std::endl;
}
}
}

for (const auto& name : tableNames)


{
if (!name.empty())
{
testRunner->DropTable(name);
}
}

SQLDisconnect(hdbc);
return result;
}

int main(int argc, char** argv)


{
const char* pConnStr = "";
if (argc < 2)
{
std::cout << "ERROR: Connection string is not specified" << std::endl;
return 0;
}
else
{
pConnStr = argv[1];
std::cout << "Connection string: " << pConnStr << std::endl;
}

SQLHENV henv = NULL;


SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;

std::string connString = pConnStr;


SQLRETURN rc;

rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);


XaTestRunner::CheckRC(rc, "Allocating environment", NULL, 0);

rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);

rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);


XaTestRunner::CheckRC(rc, "Allocating connection", henv, SQL_HANDLE_ENV);
bool result;

result = TestSetTimeout(hdbc, pConnStr);


result = TestCommit(hdbc, pConnStr);
result = TestCommit1Phase(hdbc, pConnStr);
result = TestRollback(hdbc, pConnStr);
result = TestRecover(hdbc, pConnStr);

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);

return 0;
}

The XATestRunner class implements the possible XA calls when communicating with the server.

XaTestRunner.h
#pragma once
#include "xadefs.h"
#include "sqlwindef.h"
#include "xplatsec.h"

#include <sql.h>
#include <sqlext.h>
#include <random>

struct RandomProvider
{
std::random_device rd;
};

class XidMgr
{
public:
static void GetUniqueXid(XID& xid);
static void GetUniqueXid(XID& xid, int formatId, unsigned char* globalId = nullptr, unsigned int
sizeGlobalId = 0);
static int GetRandomNumber(int low = 0, int high = 0xffffffff);
static void GetRandomBuffer(unsigned char* buffer, unsigned int sizeBuffer);

static RandomProvider rndPrv;

};

class XaTestRunner
{
public:
XaTestRunner(HDBC dbc);
~XaTestRunner();

RETCODE Start(const XID& xid, const int flags, RETCODE& xaStatus);


RETCODE End(const XID& xid, const int flags, RETCODE& xaStatus);
RETCODE Prepare(const XID& xid, RETCODE& xaStatus);
RETCODE Prepare(const XID& xid, RETCODE& xaStatus);
RETCODE Commit(const XID& xid, const bool onePhase, RETCODE& xaStatus);
RETCODE Rollback(const XID& xid, RETCODE& xaStatus);
RETCODE Forget(const XID& xid, RETCODE& xaStatus);
RETCODE Recover(const int flags, unsigned char* buffer, unsigned int& sizeBuffer, RETCODE& xaStatus);

bool CreateTable(const std::string& name, SQLHSTMT stmt = NULL);


bool DropTable(const std::string& name, SQLHSTMT stmt = NULL);

void GetUniqueName(std::string& name);


bool ExecuteInsertSequence(const std::string& nameTable, int rows, SQLHSTMT stmt = NULL);

static int CheckRC(SQLRETURN rc, const char *msg, SQLHANDLE handle, SQLSMALLINT htype);

void SetTimeout(const int tmo);


int GetTimeout();

static void GetUniqueXid(XID& xid) { XidMgr::GetUniqueXid(xid); }


static void GetUniqueXid(XID& xid, int formatId, unsigned char* globalId = nullptr, unsigned int
sizeGlobalId = 0)
{
XidMgr::GetUniqueXid(xid, formatId, globalId, sizeGlobalId);
}

static void XidShortToXid(const XID_SHORT& xids, XID& xid);

private:
HDBC m_hdbc;
std::string m_tableName;
std::string m_commandCreateTable;
std::string m_commandInsertRow;

static const char* COMMAND_CREATE_TABLE;


static const char* COMMAND_INSERT_ROW;

bool ExecuteQuery(const char* query, const char* msg, SQLHSTMT stmt = NULL);
RETCODE IssueXaCall(const XID* xid, int operation, const int flags, unsigned char* buffer, unsigned int&
sizeBuffer, RETCODE& xaStatus);

};

XaTestRunner.cpp
#include "XaTestRunner.h"
#include <chrono>
#include <thread>
#include <ctime>
#include <atomic>

const char* XaTestRunner::COMMAND_CREATE_TABLE = "CREATE TABLE %s (c1 INT, c2 VARCHAR(300))";


const char* XaTestRunner::COMMAND_INSERT_ROW = "INSERT INTO %s Values (%d, 'Varchar data for row %d')";

RandomProvider XidMgr::rndPrv;

int XidMgr::GetRandomNumber(int low, int high)


{
std::mt19937 gen(XidMgr::rndPrv.rd());
std::uniform_int_distribution<> dis(low, high);
return dis(gen);
}

void XidMgr::GetRandomBuffer(unsigned char* buffer, unsigned int sizeBuffer)


{
std::mt19937 gen(XidMgr::rndPrv.rd());
std::uniform_int_distribution<> dis(0, 0xff);
for (unsigned int i = 0; i < sizeBuffer; i++)
{
{
buffer[i] = dis(gen);
}
}

XaTestRunner::XaTestRunner(HDBC dbc)
: m_hdbc(dbc)
{
GetUniqueName(m_tableName);
m_commandCreateTable = COMMAND_CREATE_TABLE;
m_commandInsertRow = COMMAND_INSERT_ROW;
}

XaTestRunner::~XaTestRunner()
{
}

void XidMgr::GetUniqueXid(XID& xid)


{
long formatId = (long)XidMgr::GetRandomNumber(0, 0xffff);
GetUniqueXid(xid, formatId);
}

void XidMgr::GetUniqueXid(XID& xid, int formatId, unsigned char* globalId, unsigned int sizeGlobalId)
{
auto isGlobalIdDefined = globalId != nullptr && sizeGlobalId > 0 && sizeGlobalId <= 64;

xid.formatID = formatId;
xid.bqual_length = 64;
xid.gtrid_length = isGlobalIdDefined ? sizeGlobalId : 64;
if (!isGlobalIdDefined)
{
GetRandomBuffer(&xid.data[0], xid.gtrid_length);
}
else
{
memcpy_s(&xid.data[0], sizeof(xid.data), globalId, xid.gtrid_length);
}

GetRandomBuffer(&xid.data[xid.gtrid_length], xid.bqual_length);
}

int XaTestRunner::CheckRC(SQLRETURN rc, const char *msg, SQLHANDLE handle, SQLSMALLINT htype)
{
if (rc == SQL_ERROR)
{
printf("Error occurred upon [%s]\n", msg);

if (handle)
{
SQLSMALLINT i = 0;
SQLSMALLINT outlen = 0;
SQLCHAR errmsg[1024];
SQLCHAR sql_state[6];
SQLINTEGER native_error = 0;

while ((rc = SQLGetDiagRec(htype, handle, ++i, sql_state, &native_error, errmsg, sizeof(errmsg),


&outlen)) == SQL_SUCCESS
|| rc == SQL_SUCCESS_WITH_INFO)
{
printf("Error# %d: [%s] state [%s]\n", i, errmsg, sql_state);
}
}

return 0;
}
else if (rc == SQL_SUCCESS_WITH_INFO && handle)
{
SQLSMALLINT i = 0;
SQLSMALLINT outlen = 0;
SQLSMALLINT outlen = 0;
SQLCHAR errmsg[1024];
SQLCHAR sql_state[6];
SQLINTEGER native_error = 0;

printf("Success with info for [%s]:\n", msg);

while ((rc = SQLGetDiagRec(htype, handle, ++i, sql_state, &native_error, errmsg, sizeof(errmsg),


&outlen)) == SQL_SUCCESS
|| rc == SQL_SUCCESS_WITH_INFO)
{
printf("Msg# %d: [%s] state [%s]\n", i, errmsg, sql_state);
}
}
return 1;
}

RETCODE XaTestRunner::IssueXaCall(const XID* pXid, int operation, const int flags, unsigned char* buffer,
unsigned int& sizeBuffer, RETCODE& xaStatus)
{
auto sizeLimit = sizeBuffer;
unsigned int sizeParam = sizeof(XACALLPARAM) + sizeBuffer;
std::vector<unsigned char> buff(sizeParam);
PXACALLPARAM param = (PXACALLPARAM)(void*)&buff[0];
memset(param, 0, sizeof(XACALLPARAM));
param->flags = flags;
param->operation = operation;
param->sizeParam = sizeParam;
if (pXid)
{
param->xid = *pXid;
}
if (sizeBuffer > 0)
{
param->sizeData = sizeBuffer;
memcpy_s(&param[1], sizeBuffer, buffer, sizeBuffer);
}

RETCODE rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_ENLIST_IN_XA, param, SQL_IS_POINTER);


CheckRC(rc, " XaTestRunner::IssueXaCall", m_hdbc, SQL_HANDLE_DBC);
xaStatus = SQL_SUCCEEDED(rc) ? param->status : rc;
sizeBuffer = param->sizeReturned;
if (sizeBuffer)
{
memcpy_s(buffer, sizeLimit, &param[1], sizeBuffer);
}

return rc;

RETCODE XaTestRunner::Start(const XID& xid, const int flags, RETCODE& xaStatus)


{
unsigned int sizeBuffer = 0;
return IssueXaCall(&xid, OP_START, flags, nullptr, sizeBuffer, xaStatus);
}

RETCODE XaTestRunner::End(const XID& xid, const int flags, RETCODE& xaStatus)


{
unsigned int sizeBuffer = 0;
return IssueXaCall(&xid, OP_END, flags, nullptr, sizeBuffer, xaStatus);
}

RETCODE XaTestRunner::Prepare(const XID& xid, RETCODE& xaStatus)


{
unsigned int sizeBuffer = 0;
return IssueXaCall(&xid, OP_PREPARE, TMNOFLAGS, nullptr, sizeBuffer, xaStatus);
}

RETCODE XaTestRunner::Commit(const XID& xid, const bool onePhase, RETCODE& xaStatus)


RETCODE XaTestRunner::Commit(const XID& xid, const bool onePhase, RETCODE& xaStatus)
{
unsigned int sizeBuffer = 0;
return IssueXaCall(&xid, OP_COMMIT, onePhase ? TMONEPHASE : TMNOFLAGS, nullptr, sizeBuffer, xaStatus);
}

RETCODE XaTestRunner::Rollback(const XID& xid, RETCODE& xaStatus)


{
unsigned int sizeBuffer = 0;
return IssueXaCall(&xid, OP_ROLLBACK, TMNOFLAGS, nullptr, sizeBuffer, xaStatus);
}

RETCODE XaTestRunner::Forget(const XID& xid, RETCODE& xaStatus)


{
unsigned int sizeBuffer = 0;
return IssueXaCall(&xid, OP_FORGET, TMNOFLAGS, nullptr, sizeBuffer, xaStatus);
}

RETCODE XaTestRunner::Recover(const int flags, unsigned char* buffer, unsigned int& sizeBuffer, RETCODE&
xaStatus)
{
return IssueXaCall(nullptr, OP_RECOVER, flags, buffer, sizeBuffer, xaStatus);
}

void XaTestRunner::SetTimeout(const int tmo)


{
int timeout = tmo;
unsigned int sizeBuffer = sizeof(timeout);
RETCODE xaStatus;
IssueXaCall(nullptr, OP_SETTIMEOUT, TMNOFLAGS, (unsigned char*)&timeout, sizeBuffer, xaStatus);
}

int XaTestRunner::GetTimeout()
{
int timeout = 0;
unsigned int sizeBuffer = sizeof(timeout);
RETCODE xaStatus;
IssueXaCall(nullptr, OP_GETTIMEOUT, TMNOFLAGS, (unsigned char*)&timeout, sizeBuffer, xaStatus);
return timeout;
}

void XaTestRunner::XidShortToXid(const XID_SHORT& xids, XID& xid)


{
xid.formatID = xids.formatID;
xid.gtrid_length = xids.gtrid_length;
xid.bqual_length = xids.bqual_length;
memcpy_s(&xid.data[0], sizeof(xid.data), &xids.data[0], sizeof(xids.data));
}

void XaTestRunner::GetUniqueName(std::string& name)


{
static std::atomic<unsigned short> counter(0);
auto id = counter++;

auto duration = std::chrono::system_clock::now().time_since_epoch();


long long millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
char szName[64];
sprintf_s(szName, sizeof(szName), "test_%d_%lld", id, millis);
name = szName;
}

bool XaTestRunner::ExecuteQuery(const char* query, const char* msg, SQLHSTMT stmt)


{
RETCODE rc = SQL_SUCCESS;
SQLHSTMT hstmt = stmt;
bool isAllocateStatement = (stmt == NULL);

if (isAllocateStatement)
{
rc = SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &hstmt);
rc = SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &hstmt);
}

if (SQL_SUCCEEDED(rc))
{
rc = SQLExecDirectA(hstmt, (SQLCHAR*)query, SQL_NTS);
if (!SQL_SUCCEEDED(rc))
{
CheckRC(rc, msg, hstmt, SQL_HANDLE_STMT);
}

if (isAllocateStatement)
{
SQLFreeStmt(hstmt, SQL_CLOSE);
}
}
else
{
CheckRC(rc, "Alloc Statement", m_hdbc, SQL_HANDLE_DBC);
}

return SQL_SUCCEEDED(rc);

bool XaTestRunner::CreateTable(const std::string& name, SQLHSTMT stmt)


{
char query[256];
sprintf_s(query, sizeof(query), m_commandCreateTable.c_str(), name.empty() ? "testRunner" :
name.c_str());

return ExecuteQuery(query, "Create Table", stmt);


}

bool XaTestRunner::DropTable(const std::string& name, SQLHSTMT stmt)


{
char query[256];
const char* tableName = name.empty() ? "testRunner" : name.c_str();
sprintf_s(query, sizeof(query), " IF OBJECT_ID('%s', 'U') IS NOT NULL DROP TABLE %s", tableName,
tableName);

return ExecuteQuery(query, "Drop Table", stmt);


}

bool XaTestRunner::ExecuteInsertSequence(const std::string& nameTable, int rows, SQLHSTMT stmt)


{
SQLHSTMT hstmt = stmt;
bool isAllocateStatement = (stmt == NULL);
RETCODE rc = SQL_SUCCESS;

if (isAllocateStatement)
{
rc = SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &hstmt);
if (!SQL_SUCCEEDED(rc))
{
CheckRC(rc, "Alloc Statement", m_hdbc, SQL_HANDLE_DBC);
return false;
}
}

for (auto r = 0; r < rows; r++)


{
char query[256];
sprintf_s(query, sizeof(query), m_commandInsertRow.c_str(), nameTable.c_str(), r, r);
rc = ExecuteQuery(query, "Insert Row", hstmt);
}

if (isAllocateStatement)
{
SQLFreeStmt(hstmt, SQL_CLOSE);
SQLFreeStmt(hstmt, SQL_CLOSE);
}

return true;
}

Appendix
xadefs.h

// xadefs.h : XA specific definitions.


//

#pragma once

// from xa.h
/*
* Transaction branch identification: XID and NULLXID:
*/
#define XIDDATASIZE 128 /* size in bytes */
#define MAXGTRIDSIZE 64 /* maximum size in bytes of gtrid */
#define MAXBQUALSIZE 64 /* maximum size in bytes of bqual */

#ifndef _XID_T_DEFINED
#define _XID_T_DEFINED
struct xid_t
{
int formatID; /* format identifier */
int gtrid_length; /* value not to exceed 64 */
int bqual_length; /* value not to exceed 64 */
unsigned char data[XIDDATASIZE];
};
#endif

#pragma pack (push, 1)


struct xid_s
{
int formatID; /* format identifier */
unsigned char gtrid_length; /* value not to exceed 64 */
unsigned char bqual_length; /* value not to exceed 64 */
unsigned char data[XIDDATASIZE];
};
#pragma pack (pop)

/*
* xa_() return codes (resource manager reports to transaction manager)
*/
#define XA_RBBASE 100 /* The inclusive lower bound of the rollback codes */
#define XA_RBROLLBACK XA_RBBASE /* The rollback was caused by an unspecified reason */
#define XA_RBCOMMFAIL XA_RBBASE+1 /* The rollback was caused by a communication failure */
#define XA_RBDEADLOCK XA_RBBASE+2 /* A deadlock was detected */
#define XA_RBINTEGRITY XA_RBBASE+3 /* A condition that violates the integrity of the resources was
detected */
#define XA_RBOTHER XA_RBBASE+4 /* The resource manager rolled back the transaction branch for a
reason not on this list */
#define XA_RBPROTO XA_RBBASE+5 /* A protocol error occurred in the resource manager */
#define XA_RBTIMEOUT XA_RBBASE+6 /* A transaction branch took too long */
#define XA_RBTRANSIENT XA_RBBASE+7 /* May retry the transaction branch */
#define XA_RBEND XA_RBTRANSIENT /* The inclusive upper bound of the rollback codes */

#define XA_NOMIGRATE 9 /* resumption must occur where suspension occurred */


#define XA_HEURHAZ 8 /* the transaction branch may have been heuristically completed
*/
#define XA_HEURCOM 7 /* the transaction branch has been heuristically committed */
#define XA_HEURRB 6 /* the transaction branch has been heuristically rolled back */
#define XA_HEURMIX 5 /* the transaction branch has been heuristically committed and
rolled back */
rolled back */
#define XA_RETRY 4 /* routine returned with no effect and may be re-issued */
#define XA_RDONLY 3 /* the transaction branch was read-only and has been committed
*/
#define XA_OK 0 /* normal execution */
#define XAER_ASYNC (-2) /* asynchronous operation already outstanding */
#define XAER_RMERR (-3) /* a resource manager error occurred in the transaction branch
*/
#define XAER_NOTA (-4) /* the XID is not valid */
#define XAER_INVAL (-5) /* invalid arguments were given */
#define XAER_PROTO (-6) /* routine invoked in an improper context */
#define XAER_RMFAIL (-7) /* resource manager unavailable */
#define XAER_DUPID (-8) /* the XID already exists */
#define XAER_OUTSIDE (-9) /* resource manager doing work outside */
/* global transaction */

#define TMNOFLAGS 0x00000000L /* no resource manager features selected */


#define TMREGISTER 0x00000001L /* resource manager dynamically registers */
#define TMNOMIGRATE 0x00000002L /* resource manager does not support association migration */
#define TMUSEASYNC 0x00000004L /* resource manager supports asynchronous operations */
/*
* Flag definitions for xa_ and ax_ routines
*/
/* use TMNOFLAGS, defined above, when not specifying other flags */
#define TMASYNC 0x80000000L /* perform routine asynchronously */
#define TMONEPHASE 0x40000000L /* caller is using one-phase commit optimisation */
#define TMFAIL 0x20000000L /* dissociates caller and marks transaction branch rollback-only
*/
#define TMNOWAIT 0x10000000L /* return if blocking condition exists */
#define TMRESUME 0x08000000L /* caller is resuming association with suspended transaction
branch */
#define TMSUCCESS 0x04000000L /* dissociate caller from transaction branch */
#define TMSUSPEND 0x02000000L /* caller is suspending, not ending, association */
#define TMSTARTRSCAN 0x01000000L /* start a recovery scan */
#define TMENDRSCAN 0x00800000L /* end a recovery scan */
#define TMMULTIPLE 0x00400000L /* wait for any asynchronous operation */
#define TMJOIN 0x00200000L /* caller is joining existing transaction branch */
#define TMMIGRATE 0x00100000L /* caller intends to perform migration */

typedef struct xid_t XID;


typedef struct xid_s XID_SHORT;

enum class XaOperation { start, end, prepare, commit, rollback, forget, recover, getTimeout, setTimeout,
prepareEx, rollbackEx, forgetEx };
const int OP_START = 0;
const int OP_END = 1;
const int OP_PREPARE = 2;
const int OP_COMMIT = 3;
const int OP_ROLLBACK = 4;
const int OP_FORGET = 5;
const int OP_RECOVER = 6;
const int OP_GETTIMEOUT = 7;
const int OP_SETTIMEOUT = 8;

// extended operations, not called directly by client


const int OP_PREPAREEX = 9;
const int OP_ROLLBACKEX = 10;
const int OP_FORGETEX = 11;

typedef struct XACallParam {


unsigned int sizeParam;
int operation;
XID xid;
int flags;
int status;
unsigned int sizeData;
unsigned int sizeReturned;
} XACALLPARAM, *PXACALLPARAM;
#define FLAG_TIGHTLYCOUPLED 0x8000
List of bugs fixed
4/27/2022 • 6 minutes to read • Edit Online

This page contains a listing of bugs fixed in each release, starting with Microsoft ODBC Driver 17 for SQL Server.
Bug fixes in the Microsoft ODBC Driver 18.0 for SQL Server
Fix UI issues where text was cut off and position of items was off.
Fix issue with Active Directory Interactive login where attempting to login after closing the window of the
first failure would automatically succeed if cached credentials were available.
Fixed use of XADTC with Azure SQL Managed Instance.
Fixed loss of Azure Active Directory authentication mode when reconnecting an idle connection.
Fix an issue with federated authentication when using PingFed.
Bug fixes in the Microsoft ODBC Driver 17.9 for SQL Server
Fix UI issues where text was cut off and position of items was off.
Fix issue with Active Directory Interactive login where attempting to login after closing the window of the
first failure would automatically succeed if cached credentials were available.
Fixed use of XADTC with Azure SQL Managed Instance.
Fixed loss of Azure Active Directory authentication mode when reconnecting an idle connection.
Fix an issue with federated authentication when using PingFed.
Bug fixes in the Microsoft ODBC Driver 17.8 for SQL Server
Fix for restrictions on connection string regarding usage of UID and PWD keywords
Fix for inconsistent fonts in non-English dialogs
Fix issue with having multiple connections with different AKV credentials
Fix issue with NVDA not reading connection test results in DSN configuration UI
Bug fixes in the Microsoft ODBC Driver 17.7.2 for SQL Server
Fix issue with 404 Not Found errors when using Managed Service Identity authentication
Fix for intermittent Encryption Not Supported errors under high multithreaded loads
Fix for intermittent crash under high multithreaded loads
Bug fixes in the Microsoft ODBC Driver 17.7 for SQL Server
Fix character encoding of VARIANT columns in BCP NATIVE mode
Fix setting of SQL_ATTR_PARAMS_PROCESSED_PTR under specific conditions
Fix SQLDescribeParam in FMTONLY mode for statements containing comments
Fix an issue with federated authentication when using Okta
Fix excessive memory usage on multi-processor systems
Fix Azure AD authentication for some variants of Azure SQL DB
Bug fixes in the Microsoft ODBC Driver 17.6 for SQL Server
Fix ADAL error when authenticating with a federated account (Windows)
Fix an issue where the driver becomes unresponsive when a timeout occurs during an asynchronous
notification operation
Fix driver reference count upon upgrade in Alpine Linux
Fix libc6 dependency version for Ubuntu
Add missing defines to Linux/Mac msodbcsql.h
Bug fixes in the Microsoft ODBC Driver 17.5.2.2 for SQL Server (Alpine Linux only)
Fix a crash when using Always Encrypted with secure enclaves on Alpine Linux
Bug fixes in the Microsoft ODBC Driver 17.5.2 for SQL Server
Added msodbcsql.h to Alpine Linux package
Bug fixes in the Microsoft ODBC Driver 17.5 for SQL Server
Fix AKV CMK metadata hash computation on Linux/macOS
Fix error when loading OpenSSL 1.0.0
Fix conversion issues when using ISO-8859-1 and ISO-8859-2 codepages
Fix internal library name on macOS to include version number
Fix setting of null indicator when separate length and indicator bindings are used
Bug fixes in the Microsoft ODBC Driver 17.4.2 for SQL Server
Fix for an issue where process ID and application name would not be sent correctly to SQL Server (for
sys.dm_exec_sessions analysis) (Linux)
Removed redundant dependency on libuuid (Linux)
Fix for a bug with sending UTF8 data to SQL Server 2019
Fix for a bug where locales that end in "@euro" were not being correctly detected (Linux)
Fix for XML data being returned incorrectly when fetched as an output parameter while using Always
Encrypted
Bug fixes in the Microsoft ODBC Driver 17.4 for SQL Server
Fix for intermittent issue when Multiple Active Results Sets (MARS) is enabled where the driver stops
responding
Fix connection resiliency issue when async notification is enabled where the driver stops responding
Fix crash when retrieving diagnostic records for multithreaded connection attempts
Fix 'Encryption not supported' upon reconnect after calling SQLGetInfo() with SQL_USER_NAME and
SQL_DATA_SOURCE_READ_ONLY
Fix COM initialization error during Azure Active Directory Interactive Authentication
Fix SQLGetData() for multi-byte UTF8 data
Fix retrieving length of sql_variant columns using SQLGetData()
Fix importing of sql_variant columns containing more than 7992 bytes using bcp
Fix sending of correct encoding to server for narrow character data
Bug fixes in the Microsoft ODBC Driver 17.3 for SQL Server
Fixed TCP send notification event handle memory leak
Fixed redefinition issue of enum _SQL_FILESTREAM_DESIRED_ACCESS in msodbcsql.h header file
Fixed missing ACCESS_TOKEN and AUTHENTICATION related definition in msodbcsql.h header file for Linux
Bug fixes in the Microsoft ODBC Driver 17.2 for SQL Server
Fixed an error message about Azure Active Directory Authentication
Fixed encoding detection when locale environment variables are set differently
Fixed a crash upon disconnect with connection recovery in progress
Fixed detection of connection liveness
Fixed incorrect detection of closed sockets
Fixed an infinite wait when attempting to release a statement handle during failed recovery
Fixed incorrect uninstallation behavior when both version 13 and 17 are installed on Windows
Fixed decryption behavior on older Windows platform (Windows 7, 8 and Server 2012)
Fixed a cache issue when using ADAL Authentication on Windows
Fixed an issue which was locking and overwriting trace logs on Windows
Bug fixes in the Microsoft ODBC Driver 17.1 for SQL Server
Fixed 1-second delay when calling SQLFreeHandle with MARS enabled and connection attribute
"Encrypt=yes"
Fixed an error 22003 crash in SQLGetData when the size of the buffer passed in is smaller then the data
being retrieved (Windows)
Fixed truncated ADAL error messages
Fixed a rare bug on 32-bit Windows when converting a floating point number to an integer
Fixed an issue where inserting double into decimal field with Always Encrypted on would return data
truncation error
Fixed a warning on macOS installer
Fixed sending incorrect state to SQL Server during Session Recovery attempt when Connection Resiliency
and Connection Pooling both are enabled, causing session to be dropped by the Server
Bug fixes in the Microsoft ODBC Driver 17 for SQL Server
Fixed a bug where when using Kerberos authentication, bulk insert could fail with "access denied" error
Removed workaround for a unixODBC bug present in version below 2.3.1 (driver doubled the sizes of certain
buffers passed to unixODBC)
Fixed Connection Resiliency (reconnect) stopping to respond when using ColumnEncryption=enabled
Fixed DSN creation bug, where when using "Active Directory Interactive authentication" option Azure
Authentication window could become unresponsive (Windows)
Fixed a rare crash during ODBC shutdown when asynchronous execution is enabled (happened when
clearing connection handle)
Fixed an issue where SQL Driver caused high CPU consumption while executing long stored procedures
Fixed inability to retrieve data in an encrypted varbinary(max) column without conversion
Fixed a problem where after a null varchar(max) encrypted column is fetched using SQLGetData() on a static
cursor, the following column is also nulled even if it has data
Fixed an issue with fetching varbinary(max) field with Always Encrypted on
Fixed a problem of setlocale() not working with Always Encrypted
Fixed an issue with SQLDescribeParam() returning error when called on XML-type stored procedure
parameter with Always Encrypted on
Fixed escaped underscores not working in SQLTables
Fixed a bug where Hebrew data (varchar) is truncated when returned as wide chars on Linux
Fixed an issue with querying Shift-JIS encoded char/varchar from UTF-8 application
Fixed the bug where calling SQLGetInfo with SQL_DRIVER_NAME parameter returned Linux-style filename
on macOS
Fixed an issue where loading Windows-1252 character data, using input files larger than 32k bytes into
VARCHAR columns using the BCP utility would result in failures
C / C++ ODBC example application accesses an
SQL database
4/27/2022 • 10 minutes to read • Edit Online

Applies to: SQL Server (all supported versions) Azure SQL Database
This C / C++ sample application demonstrates how to use the ODBC APIs to connect to and access an SQL
database.
Between October 2013 and July 2019, this sample C++ ODBC application was downloaded 47,300 times. In July
2019, this application source was moved from Microsoft's Code Gallery to this webpage.

A. ReadMe.txt
Environment Where Tested
===============================
Visual Studio 2012
Win32
Windows Server 2012 R2
Windows 8.1

ODBC Sample
===============================
This sample demonstrates how to use ODBC APIs to Connect to and access database.

Sample Language Implementations


===============================
C++

Files:
=============================================
odbcsql.sln
odbcsql.vcxproj
odbcsql.cpp

To build the sample using the command prompt:


=============================================
1. Open the Command Prompt window and navigate to the Odbcsql directory.
2. Type msbuild odbcsql.sln.

To build the sample using Visual Studio (preferred method):


===========================================================
1. Open File Explorer and navigate to the Odbcsql directory.
2. Double-click the icon for the odbcsql.sln file to open the file in Visual Studio.
3. In the Build menu, select Build Solution. The application will be built in the default \Debug or
\Release directory.

To run the sample:


==================
1. Navigate to the directory that contains the new executable, using the command prompt or File
Explorer.
2. Type Odbcsql.exe at the command line, or double-click the icon for Odbcsql.exe to launch it from
File Explorer.
3. Select the ODBC DSN to connect to. Follow the message of the sample application to input SQL query.

B. odbcsql.cpp code
/*******************************************************************************
/* ODBCSQL: a sample program that implements an ODBC command line interpreter.
/*
/* USAGE: ODBCSQL DSN=<dsn name> or
/* ODBCSQL FILEDSN=<file dsn> or
/* ODBCSQL DRIVER={driver name}
/*
/*
/* Copyright(c) Microsoft Corporation. This is a WDAC sample program and
/* is not suitable for use in production environments.
/*
/******************************************************************************/
/* Modules:
/* Main Main driver loop, executes queries.
/* DisplayResults Display the results of the query if any
/* AllocateBindings Bind column data
/* DisplayTitles Print column titles
/* SetConsole Set console display mode
/* HandleError Show ODBC error messages
/******************************************************************************/

#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <stdlib.h>
#include <sal.h>

/*******************************************/
/* Macro to call ODBC functions and */
/* report an error on failure. */
/* Takes handle, handle type, and stmt */
/*******************************************/

#define TRYODBC(h, ht, x) { RETCODE rc = x;\


if (rc != SQL_SUCCESS) \
{ \
HandleDiagnosticRecord (h, ht, rc); \
} \
if (rc == SQL_ERROR) \
{ \
fwprintf(stderr, L"Error in " L#x L"\n"); \
goto Exit; \
} \
}
/******************************************/
/* Structure to store information about */
/* a column.
/******************************************/

typedef struct STR_BINDING {


SQLSMALLINT cDisplaySize; /* size to display */
WCHAR *wszBuffer; /* display buffer */
SQLLEN indPtr; /* size or null */
BOOL fChar; /* character col? */
struct STR_BINDING *sNext; /* linked list */
} BINDING;

/******************************************/
/* Forward references */
/******************************************/

void HandleDiagnosticRecord (SQLHANDLE hHandle,


SQLSMALLINT hType,
RETCODE RetCode);

void DisplayResults(HSTMT hStmt,


SQLSMALLINT cCols);

void AllocateBindings(HSTMT hStmt,


SQLSMALLINT cCols,
BINDING** ppBinding,
SQLSMALLINT* pDisplay);

void DisplayTitles(HSTMT hStmt,


DWORD cDisplaySize,
BINDING* pBinding);

void SetConsole(DWORD cDisplaySize,


void SetConsole(DWORD cDisplaySize,
BOOL fInvert);

/*****************************************/
/* Some constants */
/*****************************************/

#define DISPLAY_MAX 50 // Arbitrary limit on column width to display


#define DISPLAY_FORMAT_EXTRA 3 // Per column extra display bytes (| <data> )
#define DISPLAY_FORMAT L"%c %*.*s "
#define DISPLAY_FORMAT_C L"%c %-*.*s "
#define NULL_SIZE 6 // <NULL>
#define SQL_QUERY_SIZE 1000 // Max. Num characters for SQL Query passed in.

#define PIPE L'|'

SHORT gHeight = 80; // Users screen height

int __cdecl wmain(int argc, _In_reads_(argc) WCHAR **argv)


{
SQLHENV hEnv = NULL;
SQLHDBC hDbc = NULL;
SQLHSTMT hStmt = NULL;
WCHAR* pwszConnStr;
WCHAR wszInput[SQL_QUERY_SIZE];

// Allocate an environment

if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv) == SQL_ERROR)


{
fwprintf(stderr, L"Unable to allocate an environment handle\n");
exit(-1);
}

// Register this as an application that expects 3.x behavior,


// you must register something if you use AllocHandle

TRYODBC(hEnv,
SQL_HANDLE_ENV,
SQLSetEnvAttr(hEnv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC3,
0));

// Allocate a connection
TRYODBC(hEnv,
SQL_HANDLE_ENV,
SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc));

if (argc > 1)
{
pwszConnStr = *++argv;
}
else
{
pwszConnStr = L"";
}

// Connect to the driver. Use the connection string if supplied


// on the input, otherwise let the driver manager prompt for input.

TRYODBC(hDbc,
SQL_HANDLE_DBC,
SQLDriverConnect(hDbc,
GetDesktopWindow(),
pwszConnStr,
SQL_NTS,
NULL,
0,
0,
NULL,
SQL_DRIVER_COMPLETE));

fwprintf(stderr, L"Connected!\n");

TRYODBC(hDbc,
SQL_HANDLE_DBC,
SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt));

wprintf(L"Enter SQL commands, type (control)Z to exit\nSQL COMMAND>");

// Loop to get input and execute queries

while(_fgetts(wszInput, SQL_QUERY_SIZE-1, stdin))


{
RETCODE RetCode;
SQLSMALLINT sNumResults;

// Execute the query

if (!(*wszInput))
{
wprintf(L"SQL COMMAND>");
continue;
}
RetCode = SQLExecDirect(hStmt,wszInput, SQL_NTS);

switch(RetCode)
{
case SQL_SUCCESS_WITH_INFO:
{
HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode);
// fall through
}
case SQL_SUCCESS:
{
// If this is a row-returning query, display
// results
TRYODBC(hStmt,
SQL_HANDLE_STMT,
SQLNumResultCols(hStmt,&sNumResults));

if (sNumResults > 0)
{
DisplayResults(hStmt,sNumResults);
}
else
{
SQLLEN cRowCount;

TRYODBC(hStmt,
SQL_HANDLE_STMT,
SQLRowCount(hStmt,&cRowCount));

if (cRowCount >= 0)
{
wprintf(L"%Id %s affected\n",
cRowCount,
cRowCount == 1 ? L"row" : L"rows");
}
}
break;
}

case SQL_ERROR:
{
HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode);
break;
}
}

default:
fwprintf(stderr, L"Unexpected return code %hd!\n", RetCode);

}
TRYODBC(hStmt,
SQL_HANDLE_STMT,
SQLFreeStmt(hStmt, SQL_CLOSE));

wprintf(L"SQL COMMAND>");
}

Exit:

// Free ODBC handles and exit

if (hStmt)
{
SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
}

if (hDbc)
{
SQLDisconnect(hDbc);
SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
}

if (hEnv)
{
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
}

wprintf(L"\nDisconnected.");

return 0;

/************************************************************************
/* DisplayResults: display results of a select query
/*
/* Parameters:
/* hStmt ODBC statement handle
/* cCols Count of columns
/************************************************************************/

void DisplayResults(HSTMT hStmt,


SQLSMALLINT cCols)
{
BINDING *pFirstBinding, *pThisBinding;
SQLSMALLINT cDisplaySize;
RETCODE RetCode = SQL_SUCCESS;
int iCount = 0;

// Allocate memory for each column

AllocateBindings(hStmt, cCols, &pFirstBinding, &cDisplaySize);

// Set the display mode and write the titles

DisplayTitles(hStmt, cDisplaySize+1, pFirstBinding);

// Fetch and display the data

bool fNoData = false;

do {
// Fetch a row
// Fetch a row

if (iCount++ >= gHeight - 2)


{
int nInputChar;
bool fEnterReceived = false;

while(!fEnterReceived)
{
wprintf(L" ");
SetConsole(cDisplaySize+2, TRUE);
wprintf(L" Press ENTER to continue, Q to quit (height:%hd)", gHeight);
SetConsole(cDisplaySize+2, FALSE);

nInputChar = _getch();
wprintf(L"\n");
if ((nInputChar == 'Q') || (nInputChar == 'q'))
{
goto Exit;
}
else if ('\r' == nInputChar)
{
fEnterReceived = true;
}
// else loop back to display prompt again
}

iCount = 1;
DisplayTitles(hStmt, cDisplaySize+1, pFirstBinding);
}

TRYODBC(hStmt, SQL_HANDLE_STMT, RetCode = SQLFetch(hStmt));

if (RetCode == SQL_NO_DATA_FOUND)
{
fNoData = true;
}
else
{

// Display the data. Ignore truncations

for (pThisBinding = pFirstBinding;


pThisBinding;
pThisBinding = pThisBinding->sNext)
{
if (pThisBinding->indPtr != SQL_NULL_DATA)
{
wprintf(pThisBinding->fChar ? DISPLAY_FORMAT_C:DISPLAY_FORMAT,
PIPE,
pThisBinding->cDisplaySize,
pThisBinding->cDisplaySize,
pThisBinding->wszBuffer);
}
else
{
wprintf(DISPLAY_FORMAT_C,
PIPE,
pThisBinding->cDisplaySize,
pThisBinding->cDisplaySize,
L"<NULL>");
}
}
wprintf(L" %c\n",PIPE);
}
} while (!fNoData);

SetConsole(cDisplaySize+2, TRUE);
wprintf(L"%*.*s", cDisplaySize+2, cDisplaySize+2, L" ");
SetConsole(cDisplaySize+2, FALSE);
SetConsole(cDisplaySize+2, FALSE);
wprintf(L"\n");

Exit:
// Clean up the allocated buffers

while (pFirstBinding)
{
pThisBinding = pFirstBinding->sNext;
free(pFirstBinding->wszBuffer);
free(pFirstBinding);
pFirstBinding = pThisBinding;
}
}

/************************************************************************
/* AllocateBindings: Get column information and allocate bindings
/* for each column.
/*
/* Parameters:
/* hStmt Statement handle
/* cCols Number of columns in the result set
/* *lppBinding Binding pointer (returned)
/* lpDisplay Display size of one line
/************************************************************************/

void AllocateBindings(HSTMT hStmt,


SQLSMALLINT cCols,
BINDING **ppBinding,
SQLSMALLINT *pDisplay)
{
SQLSMALLINT iCol;
BINDING *pThisBinding, *pLastBinding = NULL;
SQLLEN cchDisplay, ssType;
SQLSMALLINT cchColumnNameLength;

*pDisplay = 0;

for (iCol = 1; iCol <= cCols; iCol++)


{
pThisBinding = (BINDING *)(malloc(sizeof(BINDING)));
if (!(pThisBinding))
{
fwprintf(stderr, L"Out of memory!\n");
exit(-100);
}

if (iCol == 1)
{
*ppBinding = pThisBinding;
}
else
{
pLastBinding->sNext = pThisBinding;
}
pLastBinding = pThisBinding;

// Figure out the display length of the column (we will


// bind to char since we are only displaying data, in general
// you should bind to the appropriate C type if you are going
// to manipulate data since it is much faster...)

TRYODBC(hStmt,
SQL_HANDLE_STMT,
SQLColAttribute(hStmt,
iCol,
SQL_DESC_DISPLAY_SIZE,
NULL,
0,
NULL,
&cchDisplay));

// Figure out if this is a character or numeric column; this is


// used to determine if we want to display the data left- or right-
// aligned.

// SQL_DESC_CONCISE_TYPE maps to the 1.x SQL_COLUMN_TYPE.


// This is what you must use if you want to work
// against a 2.x driver.

TRYODBC(hStmt,
SQL_HANDLE_STMT,
SQLColAttribute(hStmt,
iCol,
SQL_DESC_CONCISE_TYPE,
NULL,
0,
NULL,
&ssType));

pThisBinding->fChar = (ssType == SQL_CHAR ||


ssType == SQL_VARCHAR ||
ssType == SQL_LONGVARCHAR);

pThisBinding->sNext = NULL;

// Arbitrary limit on display size


if (cchDisplay > DISPLAY_MAX)
cchDisplay = DISPLAY_MAX;

// Allocate a buffer big enough to hold the text representation


// of the data. Add one character for the null terminator

pThisBinding->wszBuffer = (WCHAR *)malloc((cchDisplay+1) * sizeof(WCHAR));

if (!(pThisBinding->wszBuffer))
{
fwprintf(stderr, L"Out of memory!\n");
exit(-100);
}

// Map this buffer to the driver's buffer. At Fetch time,


// the driver will fill in this data. Note that the size is
// count of bytes (for Unicode). All ODBC functions that take
// SQLPOINTER use count of bytes; all functions that take only
// strings use count of characters.

TRYODBC(hStmt,
SQL_HANDLE_STMT,
SQLBindCol(hStmt,
iCol,
SQL_C_TCHAR,
(SQLPOINTER) pThisBinding->wszBuffer,
(cchDisplay + 1) * sizeof(WCHAR),
&pThisBinding->indPtr));

// Now set the display size that we will use to display


// the data. Figure out the length of the column name

TRYODBC(hStmt,
SQL_HANDLE_STMT,
SQLColAttribute(hStmt,
iCol,
SQL_DESC_NAME,
NULL,
0,
&cchColumnNameLength,
NULL));

pThisBinding->cDisplaySize = max((SQLSMALLINT)cchDisplay, cchColumnNameLength);


if (pThisBinding->cDisplaySize < NULL_SIZE)
pThisBinding->cDisplaySize = NULL_SIZE;

*pDisplay += pThisBinding->cDisplaySize + DISPLAY_FORMAT_EXTRA;

return;

Exit:

exit(-1);

return;
}

/************************************************************************
/* DisplayTitles: print the titles of all the columns and set the
/* shell window's width
/*
/* Parameters:
/* hStmt Statement handle
/* cDisplaySize Total display size
/* pBinding list of binding information
/************************************************************************/

void DisplayTitles(HSTMT hStmt,


DWORD cDisplaySize,
BINDING *pBinding)
{
WCHAR wszTitle[DISPLAY_MAX];
SQLSMALLINT iCol = 1;

SetConsole(cDisplaySize+2, TRUE);

for (; pBinding; pBinding = pBinding->sNext)


{
TRYODBC(hStmt,
SQL_HANDLE_STMT,
SQLColAttribute(hStmt,
iCol++,
SQL_DESC_NAME,
wszTitle,
sizeof(wszTitle), // Note count of bytes!
NULL,
NULL));

wprintf(DISPLAY_FORMAT_C,
PIPE,
pBinding->cDisplaySize,
pBinding->cDisplaySize,
wszTitle);
}

Exit:

wprintf(L" %c", PIPE);


SetConsole(cDisplaySize+2, FALSE);
wprintf(L"\n");

}
/************************************************************************
/* SetConsole: sets console display size and video mode
/*
/* Parameters
/* siDisplaySize Console display size
/* fInvert Invert video?
/************************************************************************/

void SetConsole(DWORD dwDisplaySize,


BOOL fInvert)
{
HANDLE hConsole;
CONSOLE_SCREEN_BUFFER_INFO csbInfo;

// Reset the console screen buffer size if necessary

hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

if (hConsole != INVALID_HANDLE_VALUE)
{
if (GetConsoleScreenBufferInfo(hConsole, &csbInfo))
{
if (csbInfo.dwSize.X < (SHORT) dwDisplaySize)
{
csbInfo.dwSize.X = (SHORT) dwDisplaySize;
SetConsoleScreenBufferSize(hConsole, csbInfo.dwSize);
}

gHeight = csbInfo.dwSize.Y;
}

if (fInvert)
{
SetConsoleTextAttribute(hConsole, (WORD)(csbInfo.wAttributes | BACKGROUND_BLUE));
}
else
{
SetConsoleTextAttribute(hConsole, (WORD)(csbInfo.wAttributes & ~(BACKGROUND_BLUE)));
}
}
}

/************************************************************************
/* HandleDiagnosticRecord : display error/warning information
/*
/* Parameters:
/* hHandle ODBC handle
/* hType Type of handle (HANDLE_STMT, HANDLE_ENV, HANDLE_DBC)
/* RetCode Return code of failing command
/************************************************************************/

void HandleDiagnosticRecord (SQLHANDLE hHandle,


SQLSMALLINT hType,
RETCODE RetCode)
{
SQLSMALLINT iRec = 0;
SQLINTEGER iError;
WCHAR wszMessage[1000];
WCHAR wszState[SQL_SQLSTATE_SIZE+1];

if (RetCode == SQL_INVALID_HANDLE)
{
fwprintf(stderr, L"Invalid handle!\n");
return;
}

while (SQLGetDiagRec(hType,
while (SQLGetDiagRec(hType,
hHandle,
++iRec,
wszState,
&iError,
wszMessage,
(SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)),
(SQLSMALLINT *)NULL) == SQL_SUCCESS)
{
// Hide data truncated..
if (wcsncmp(wszState, L"01004", 5))
{
fwprintf(stderr, L"[%5.5s] %s (%d)\n", wszState, wszMessage, iError);
}
}
}

C. odbcsql.sln code
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29230.47
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "odbcsql", "odbcsql.vcxproj", "{C5948D2C-C53D-4933-9AC5-
48066AD6A560}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C5948D2C-C53D-4933-9AC5-48066AD6A560}.Debug|x64.ActiveCfg = Debug|x64
{C5948D2C-C53D-4933-9AC5-48066AD6A560}.Debug|x64.Build.0 = Debug|x64
{C5948D2C-C53D-4933-9AC5-48066AD6A560}.Debug|x86.ActiveCfg = Debug|Win32
{C5948D2C-C53D-4933-9AC5-48066AD6A560}.Debug|x86.Build.0 = Debug|Win32
{C5948D2C-C53D-4933-9AC5-48066AD6A560}.Release|x64.ActiveCfg = Release|x64
{C5948D2C-C53D-4933-9AC5-48066AD6A560}.Release|x64.Build.0 = Release|x64
{C5948D2C-C53D-4933-9AC5-48066AD6A560}.Release|x86.ActiveCfg = Release|Win32
{C5948D2C-C53D-4933-9AC5-48066AD6A560}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {32894C74-C0AE-427F-969B-5F757A98EAFF}
EndGlobalSection
EndGlobal

D. odbcsql.vcxproj code
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VSVersion)' == '' and
'$(VisualStudioVersion)' == ''">$(VCTargetsPath11)</VCTargetsPath>
</PropertyGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C5948D2C-C53D-4933-9AC5-48066AD6A560}</ProjectGuid>
<RootNamespace>odbcsql</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>11.0.40930.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<PreprocessorDefinitions>_WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level4</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="odbcsql.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

See also
Download ODBC Driver
Microsoft Open Database Connectivity (ODBC)
4/27/2022 • 2 minutes to read • Edit Online

The Microsoft Open Database Connectivity (ODBC) interface is a C programming language interface that makes
it possible for applications to access data from a variety of database management systems (DBMSs). ODBC is a
low-level, high-performance interface that is designed specifically for relational data stores.
The ODBC interface allows maximum interoperability-an application can access data in diverse DBMSs through
a single interface. Moreover, that application will be independent of any DBMS from which it accesses data.
Users of the application can add software components called drivers, which interface between an application
and a specific DBMS.

Documentation
ODBC Programmer's Reference
Documentation of ODBC interfaces and methods.
ODBC Data Source Administrator
The Microsoft ODBC Data Source Administrator manages database drivers and data sources.
Microsoft-Supplied ODBC Drivers
Documentation for the ODBC Desktop Database Drivers, the ODBC Driver for Oracle, and the Visual FoxPro®
ODBC Driver.
ODBC Test
Microsoft ODBC Test is an ODBC-enabled application that you can use to test ODBC drivers.
ODBC Glossary
Defines terms relevant to ODBC.
ODBCCONF.EXE
Describes the command-line utility for configuring drivers and data source names.

Support
Information about support options can be found on the Microsoft Help and Support Web site.
ODBC Programmer's Reference
4/27/2022 • 3 minutes to read • Edit Online

The ODBC Programmer's Reference contains the following sections.


What's New in ODBC 3.8 lists the new ODBC features that were added in the Windows 8 SDK.
Sample ODBC Program presents a sample ODBC program.
Introduction to ODBC provides a brief history of Structured Query Language and ODBC, and conceptual
information about the ODBC interface.
Developing Applications contains information about developing applications that use the ODBC interface
and drivers that implement it.
Installing and Configuring ODBC Software provides information about installation and a setup DLL
function reference.
Developing an ODBC Driver contains information on writing a driver.
API Reference contains syntax and semantic information for all ODBC functions.
ODBC Appendixes contain technical details and reference tables for ODBC error codes, data types, and
SQL grammar.

Working with the ODBC Documentation


The ODBC interface is designed for use with the C programming language. Use of the ODBC interface spans
three areas: SQL statements, ODBC function calls, and C programming. This documentation assumes the
following:
A working knowledge of the C programming language.
General DBMS knowledge and a familiarity with SQL.
The following typographic conventions are used.

F O RM AT USED F O R

SELECT * FROM Uppercase letters indicate SQL statements, macro names,


and terms used at the operating-system command level.

RETCODE SQLFetch(hdbc) The monospace font is used for sample command lines and
program code.

argument Italicized words indicate programmatic arguments,


information that the user or the application must provide, or
word emphasis.

SQLEndTran Bold type indicates that syntax must be typed exactly as


shown, including function names.

| A vertical bar separates two mutually exclusive choices in a


syntax line.
F O RM AT USED F O R

... An ellipsis indicates that arguments can be repeated several


times.

... A column of three dots indicates continuation of previous


lines of code.

About the Code Examples


The code examples in this guide are designed for illustration purposes only. Because they are written primarily
to demonstrate ODBC principles, efficiency has sometimes been set aside in the interest of clarity. In addition,
whole sections of code have sometimes been omitted for clarity. These include the definitions of non-ODBC
functions (those functions whose names do not start with "SQL") and most error handling.
All code examples use ANSI strings and the same database schema, which is shown at the start of Catalog
Functions.

Recommended Reading
For more information about SQL, the following standards are available:
Database Language - SQL with Integrity Enhancement, ANSI, 1989 ANSI X3.135-1989.
Database Language - SQL: ANSI X3H2 and ISO/IEC JTC1/SC21/WG3 9075:1992 (SQL-92).
Open Group, Data Management: Structured Query Language (SQL), Version 2 (The Open Group, 1996).
In addition to standards and vendor-specific SQL guides, many books describe SQL, including:
Date, C. J., with Darwen, Hugh: A Guide to the SQL Standard (Addison-Wesley, 1993).
Emerson, Sandra L., Darnovsky, Marcy, and Bowman, Judith S.: The Practical SQL Handbook (Addison-
Wesley, 1989).
Groff, James R. and Weinberg, Paul N.: Using SQL (Osborne McGraw-Hill, 1990).
Gruber, Martin: Understanding SQL (Sybex, 1990).
Hursch, Jack L. and Carolyn J.: SQL, The Structured Query Language (TAB Books, 1988).
Melton, Jim, and Simon, Alan R.: Understanding the New SQL: A Complete Guide (Morgan Kaufmann
Publishers, 1993).
Pascal, Fabian: SQL and Relational Basics (M & T Books, 1990).
Trimble, J. Harvey, Jr. and Chappell, David: A Visual Introduction to SQL (Wiley, 1989).
Van der Lans, Rick F.: Introduction to SQL (Addison-Wesley, 1988).
Vang, Soren: SQL and Relational Databases (Microtrend Books, 1990).
Viescas, John: Quick Reference Guide to SQL (Microsoft Corp., 1989).
For additional information about transaction processing, see:
Gray, J. N. and Reuter, Andreas: Transaction Processing: Concepts and Techniques (Morgan Kaufmann
Publishers, 1993).
Hackathorn, Richard D.: Enterprise Database Connectivity (Wiley & Sons, 1993).
For more information about Call-Level Interfaces, the following standards are available:
Open Group, Data Management: SQL Call Level Interface (CLI), C451 (Open Group, 1995).
ISO/IEC 9075-3:1995, Call-Level Interface (SQL/CLI).
For additional information about ODBC, a number of books are available, including:
Geiger, Kyle: Inside ODBC (Microsoft Press®, 1995).
Gryphon, Robert, Charpentier, Luc, Oelschlager, Jon, Shoemaker, Andrew, Cross, Jim, and Lilley, Albert W.:
Using ODBC 2 (Que, 1994).
Johnston, Tom and Osborne, Mark: ODBC Developers Guide (Howard W. Sams & Company, 1994).
North, Ken: Windows Multi-DBMS Programming: Using C++, Visual Basic, ODBC, OLE 2 and Tools for
DBMS Projects (John Wiley & Sons, Inc., 1995).
Stegman, Michael O., Signore, Robert, and Creamer, John: The ODBC Solution, Open Database
Connectivity in Distributed Environments (McGraw-Hill, 1995).
Welch, Keith: Using ODBC 2 (Que, 1994).
Whiting, Bill: Teach Yourself ODBC in Twenty-One Days (Howard W. Sams & Company, 1994).
What's New in ODBC 3.8
4/27/2022 • 2 minutes to read • Edit Online

Windows 8 includes an updated version of ODBC 3.8. ODBC 3.8 in Windows 8 includes the following features:
Driver-Aware Connection Pooling
Asynchronous Execution (Notification Method)
Data Access Tracing (Windows 8)
PowerShell commands have been added to help you manage ODBC data sources, ODBC drivers, ODBC
Performance Counter, and data access tracing at the command line. For more information see Windows
Data Access Components PowerShell Commands.
Windows 7 includes an updated version of ODBC, ODBC 3.8. ODBC 3.8 includes the following features:
Executing connection operations asynchronously. For more information, see Asynchronous Execution
(Polling Method).
Streamed output parameters. For more information, see Retrieving Output Parameters Using
SQLGetData.
ODBC C data type extensibility. For more information, see C Data Types in ODBC.
Driver writers should read Upgrading a 3.5 Driver to a 3.8 Driver.
Asynchronous connection operations can be used by ODBC 3.x and ODBC 2.x applications with an ODBC 3.8
driver.
For more information, see Compatibility Matrix.

See Also
ODBC Programmer's Reference
Sample ODBC Program
4/27/2022 • 2 minutes to read • Edit Online

The ODBC code sample prompts you for an ODBC data source name. You will then be prompted to enter a
query and the sample will display the results of the query.
Introduction to ODBC
4/27/2022 • 2 minutes to read • Edit Online

This section provides a brief history of Structured Query Language and ODBC, and includes conceptual
information about the ODBC interface.
This section contains the following topics:
ODBC Overview
Introduction to SQL and ODBC
ODBC Architecture
ODBC 64-Bit Information
ODBC Overview
4/27/2022 • 2 minutes to read • Edit Online

Open Database Connectivity (ODBC) is a widely accepted application programming interface (API) for database
access. It is based on the Call-Level Interface (CLI) specifications from Open Group and ISO/IEC for database
APIs and uses Structured Query Language (SQL) as its database access language.
ODBC is designed for maximum interoperability - that is, the ability of a single application to access different
database management systems (DBMSs) with the same source code. Database applications call functions in the
ODBC interface, which are implemented in database-specific modules called drivers. The use of drivers isolates
applications from database-specific calls in the same way that printer drivers isolate word processing programs
from printer-specific commands. Because drivers are loaded at run time, a user only has to add a new driver to
access a new DBMS; it is not necessary to recompile or relink the application.
This section contains the following topics.
Why Was ODBC Created?
What Is ODBC?
ODBC and the Standard CLI
Why Was ODBC Created?
4/27/2022 • 2 minutes to read • Edit Online

Historically, companies used a single DBMS. All database access was done either through the front end of that
system or through applications written to work exclusively with that system. However, as the use of computers
grew and more computer hardware and software became available, companies started to acquire different
DBMSs. The reasons were many: People bought what was cheapest, what was fastest, what they already knew,
what was latest on the market, what worked best for a single application. Other reasons were reorganizations
and mergers, where departments that previously had a single DBMS now had several.
The issue grew even more complex with the advent of personal computers. These computers brought in a host
of tools for querying, analyzing, and displaying data, along with a number of inexpensive, easy-to-use
databases. From then on, a single corporation often had data scattered across a myriad of desktops, servers, and
minicomputers, stored in a variety of incompatible databases, and accessed by a vast number of different tools,
few of which could get at all of the data.
The final challenge came with the advent of client/server computing, which seeks to make the most efficient use
of computer resources. Inexpensive personal computers (the clients) sit on the desktop and provide both a
graphical front end to the data and a number of inexpensive tools, such as spreadsheets, charting programs, and
report builders. Minicomputers and mainframe computers (the servers) host the DBMSs, where they can use
their computing power and central location to provide quick, coordinated data access. How then was the front-
end software to be connected to the back-end databases?
A similar problem faced independent software vendors (ISVs). Vendors writing database software for
minicomputers and mainframes were usually forced to write one version of an application for each DBMS or
write DBMS-specific code for each DBMS they wanted to access. Vendors writing software for personal
computers had to write data access routines for each different DBMS with which they wanted to work. This often
meant a huge amount of resources were spent writing and maintaining data access routines rather than
applications, and applications were often sold not on their quality but on whether they could access data in a
given DBMS.
What both sets of developers needed was a way to access data in different DBMSs. The mainframe and
minicomputer group needed a way to merge data from different DBMSs in a single application, while the
personal computer group needed this ability as well as a way to write a single application that was independent
of any one DBMS. In short, both groups needed an interoperable way to access data; they needed open database
connectivity.
What Is ODBC?
4/27/2022 • 2 minutes to read • Edit Online

Many misconceptions about ODBC exist in the computing world. To the end user, it is an icon in the Microsoft®
Windows® Control Panel. To the application programmer, it is a library containing data access routines. To
many others, it is the answer to all database access problems ever imagined.
First and foremost, ODBC is a specification for a database API. This API is independent of any one DBMS or
operating system; although this manual uses C, the ODBC API is language-independent. The ODBC API is based
on the CLI specifications from Open Group and ISO/IEC. ODBC 3.x fully implements both of these specifications
- earlier versions of ODBC were based on preliminary versions of these specifications but did not fully
implement them - and adds features commonly needed by developers of screen-based database applications,
such as scrollable cursors.
The functions in the ODBC API are implemented by developers of DBMS-specific drivers. Applications call the
functions in these drivers to access data in a DBMS-independent manner. A Driver Manager manages
communication between applications and drivers.
Although Microsoft provides a driver manager for computers running Microsoft Windows® 95 and later, has
written several ODBC drivers, and calls ODBC functions from some of its applications, anyone can write ODBC
applications and drivers. In fact, the vast majority of ODBC applications and drivers available today are written
by companies other than Microsoft. Furthermore, ODBC drivers and applications exist on the Macintosh® and
a variety of UNIX platforms.
To help application and driver developers, Microsoft offers an ODBC Software Development Kit (SDK) for
computers running Windows 95 and later that provides the driver manager, installer DLL, test tools, and sample
applications. Microsoft has teamed with Visigenic Software to port these SDKs to the Macintosh and a variety of
UNIX platforms.
It is important to understand that ODBC is designed to expose database capabilities, not supplement them. Thus,
application writers should not expect that using ODBC will suddenly transform a simple database into a fully
featured relational database engine. Nor are driver writers expected to implement functionality not found in the
underlying database. An exception to this is that developers who write drivers that directly access file data (such
as data in an Xbase file) are required to write a database engine that supports at least minimal SQL functionality.
Another exception is that the ODBC component of the Windows SDK, formerly included in the Microsoft Data
Access Components (MDAC) SDK, provides a cursor library that simulates scrollable cursors for drivers that
implement a certain level of functionality.
Applications that use ODBC are responsible for any cross-database functionality. For example, ODBC is not a
heterogeneous join engine, nor is it a distributed transaction processor. However, because it is DBMS-
independent, it can be used to build such cross-database tools.
ODBC and the Standard CLI
4/27/2022 • 2 minutes to read • Edit Online

ODBC aligns with the following specifications and standards that deal with the Call-Level Interface (CLI). (The
ODBC features are a superset of each of these standards.)
The Open Group CAE Specification "Data Management: SQL Call-Level Interface (CLI)"
ISO/IEC 9075-3:1995 (E) Call-Level Interface (SQL/CLI)
As a result of this alignment, the following are true:
An application written to the Open Group and ISO CLI specifications will work with an ODBC 3.x driver or
a standards-compliant driver when it is compiled with the ODBC 3.x header files and linked with ODBC
3.x libraries, and when it gains access to the driver through the ODBC 3.x Driver Manager.
A driver written to the Open Group and ISO CLI specifications will work with an ODBC 3.x application or a
standards-compliant application when it is compiled with the ODBC 3.x header files and linked with
ODBC 3.x libraries, and when the application gains access to the driver through the ODBC 3.x Driver
Manager. (For more information, see Standards-Compliant Applications and Drivers.
The Core interface conformance level encompasses all the features in the ISO CLI and all the nonoptional
features in the Open Group CLI. Optional features of the Open Group CLI appear in higher interface
conformance levels. Because all ODBC 3.x drivers are required to support the features in the Core interface
conformance level, the following are true:
An ODBC 3.x driver will support all the features used by a standards-compliant application.
An ODBC 3.x application using only the features in ISO CLI and the nonoptional features of the Open
Group CLI will work with any standards-compliant driver.
In addition to the call-level interface specifications contained in the ISO/IEC and Open Group CLI standards,
ODBC implements the following features. (Some of these features existed in versions of ODBC prior to ODBC
3.x.)
Multirow fetches by a single function call
Binding to an array of parameters
Bookmark support including fetching by bookmark, variable-length bookmarks, and bulk update and
delete by bookmark operations on discontiguous rows
Row-wise binding
Binding offsets
Support for batches of SQL statements, either in a stored procedure or as a sequence of SQL statements
executed through SQLExecute or SQLExecDirect
Exact or approximate cursor row counts
Positioned update and delete operations and batched updates and deletes by function call (SQLSetPos )
Catalog functions that extract information from the information schema without the need for supporting
information schema views
Escape sequences for outer joins, scalar functions, datetime literals, interval literals, and stored
procedures
Code-page translation libraries
Reporting of a driver's ANSI-conformance level and SQL support
On-demand automatic population of implementation parameter descriptor
Enhanced diagnostics and row and parameter status arrays
Datetime, interval, numeric/decimal, and 64-bit integer application buffer types
Asynchronous execution
Stored procedure support, including escape sequences, output parameter binding mechanisms, and
catalog functions
Connection enhancements including support for connection attributes and attribute browsing
Introduction to SQL and ODBC
4/27/2022 • 2 minutes to read • Edit Online

ODBC was created to provide a uniform method of access to different, or heterogeneous, database management
systems (DBMSs). This introduction discusses concepts related to the development of ODBC.
This section contains the following topics.
Structured Query Language (SQL)
Database Access Architecture
Structured Query Language (SQL)
4/27/2022 • 2 minutes to read • Edit Online

A typical DBMS allows users to store, access, and modify data in an organized, efficient way. Originally, the users
of DBMSs were programmers. Accessing the stored data required writing a program in a programming
language such as COBOL. While these programs were often written to present a friendly interface to a
nontechnical user, access to the data itself required the services of a knowledgeable programmer. Casual access
to the data was not practical.
Users were not entirely happy with this situation. While they could access data, it often required convincing a
DBMS programmer to write special software. For example, if a sales department wanted to see the total sales in
the previous month by each of its salespeople and wanted this information ranked in order by each
salesperson's length of service in the company, it had two choices: Either a program already existed that allowed
the information to be accessed in exactly this way, or the department had to ask a programmer to write such a
program. In many cases, this was more work than it was worth, and it was always an expensive solution for one-
time, or ad hoc, inquiries. As more and more users wanted easy access, this problem grew larger and larger.
Allowing users to access data on an ad hoc basis required giving them a language in which to express their
requests. A single request to a database is defined as a query; such a language is called a query language. Many
query languages were developed for this purpose, but one of these became the most popular: Structured Query
Language, invented at IBM in the 1970s. It is more commonly known by its acronym, SQL, and is pronounced
both as "ess-cue-ell" and as "sequel". SQL became an ANSI standard in 1986 and an ISO standard in 1987; it is
used today in a great many database management systems.
Although SQL solved the ad hoc needs of users, the need for data access by computer programs did not go
away. In fact, most database access still was (and is) programmatic, in the form of regularly scheduled reports
and statistical analyses, data entry programs such as those used for order entry, and data manipulation
programs, such as those used to reconcile accounts and generate work orders.
These programs also use SQL, using one of the following three techniques:
Embedded SQL , in which SQL statements are embedded in a host language such as C or COBOL.
SQL modules , in which SQL statements are compiled on the DBMS and called from a host language.
Call-level interface , or CLI, which consists of functions called to pass SQL statements to the DBMS and
to retrieve results from the DBMS.

NOTE
It is a historical accident that the term call-level interface is used instead of application programming interface (API),
another term for the same thing. In the database world, API is used to describe SQL itself: SQL is the API to a DBMS.

Of these choices, embedded SQL is the most commonly used, although most major DBMSs support proprietary
CLIs.
This section contains the following topics.
Processing an SQL Statement
Embedded SQL
SQL Modules
Call-Level Interfaces
Processing a SQL Statement
4/27/2022 • 2 minutes to read • Edit Online

Before discussing the techniques for using SQL programmatically, it is necessary to discuss how an SQL
statement is processed. The steps involved are common to all three techniques, although each technique
performs them at different times. The following illustration shows the steps involved in processing an SQL
statement, which are discussed throughout the rest of this section.

To process an SQL statement, a DBMS performs the following five steps:


1. The DBMS first parses the SQL statement. It breaks the statement up into individual words, called tokens,
makes sure that the statement has a valid verb and valid clauses, and so on. Syntax errors and
misspellings can be detected in this step.
2. The DBMS validates the statement. It checks the statement against the system catalog. Do all the tables
named in the statement exist in the database? Do all of the columns exist and are the column names
unambiguous? Does the user have the required privileges to execute the statement? Certain semantic
errors can be detected in this step.
3. The DBMS generates an access plan for the statement. The access plan is a binary representation of the
steps that are required to carry out the statement; it is the DBMS equivalent of executable code.
4. The DBMS optimizes the access plan. It explores various ways to carry out the access plan. Can an index
be used to speed a search? Should the DBMS first apply a search condition to Table A and then join it to
Table B, or should it begin with the join and use the search condition afterward? Can a sequential search
through a table be avoided or reduced to a subset of the table? After exploring the alternatives, the DBMS
chooses one of them.
5. The DBMS executes the statement by running the access plan.
The steps used to process an SQL statement vary in the amount of database access they require and the amount
of time they take. Parsing an SQL statement does not require access to the database and can be done very
quickly. Optimization, on the other hand, is a very CPU-intensive process and requires access to the system
catalog. For a complex, multitable query, the optimizer may explore thousands of different ways of carrying out
the same query. However, the cost of executing the query inefficiently is usually so high that the time spent in
optimization is more than regained in increased query execution speed. This is even more significant if the same
optimized access plan can be used over and over to perform repetitive queries.
Embedded SQL
4/27/2022 • 2 minutes to read • Edit Online

The first technique for sending SQL statements to the DBMS is embedded SQL. Because SQL does not use
variables and control-of-flow statements, it is often used as a database sublanguage that can be added to a
program written in a conventional programming language, such as C or COBOL. This is a central idea of
embedded SQL: placing SQL statements in a program written in a host programming language. Briefly, the
following techniques are used to embed SQL statements in a host language:
Embedded SQL statements are processed by a special SQL precompiler. All SQL statements begin with an
introducer and end with a terminator, both of which flag the SQL statement for the precompiler. The
introducer and terminator vary with the host language. For example, the introducer is "EXEC SQL" in C
and "&SQL(" in MUMPS, and the terminator is a semicolon (;) in C and a right parenthesis in MUMPS.
Variables from the application program, called host variables, can be used in embedded SQL statements
wherever constants are allowed. These can be used on input to tailor an SQL statement to a particular
situation and on output to receive the results of a query.
Queries that return a single row of data are handled with a singleton SELECT statement; this statement
specifies both the query and the host variables in which to return data.
Queries that return multiple rows of data are handled with cursors. A cursor keeps track of the current
row within a result set. The DECLARE CURSOR statement defines the query, the OPEN statement begins
the query processing, the FETCH statement retrieves successive rows of data, and the CLOSE statement
ends query processing.
While a cursor is open, positioned update and positioned delete statements can be used to update or
delete the row currently selected by the cursor.
This section contains the following topics.
Embedded SQL Example
Compiling an Embedded SQL Program
Static SQL
Dynamic SQL
Embedded SQL Example
4/27/2022 • 2 minutes to read • Edit Online

The following code is a simple embedded SQL program, written in C. The program illustrates many, but not all,
of the embedded SQL techniques. The program prompts the user for an order number, retrieves the customer
number, salesperson, and status of the order, and displays the retrieved information on the screen.

int main() {
EXEC SQL INCLUDE SQLCA;
EXEC SQL BEGIN DECLARE SECTION;
int OrderID; /* Employee ID (from user) */
int CustID; /* Retrieved customer ID */
char SalesPerson[10] /* Retrieved salesperson name */
char Status[6] /* Retrieved order status */
EXEC SQL END DECLARE SECTION;

/* Set up error processing */


EXEC SQL WHENEVER SQLERROR GOTO query_error;
EXEC SQL WHENEVER NOT FOUND GOTO bad_number;

/* Prompt the user for order number */


printf ("Enter order number: ");
scanf_s("%d", &OrderID);

/* Execute the SQL query */


EXEC SQL SELECT CustID, SalesPerson, Status
FROM Orders
WHERE OrderID = :OrderID
INTO :CustID, :SalesPerson, :Status;

/* Display the results */


printf ("Customer number: %d\n", CustID);
printf ("Salesperson: %s\n", SalesPerson);
printf ("Status: %s\n", Status);
exit();

query_error:
printf ("SQL error: %ld\n", sqlca->sqlcode);
exit();

bad_number:
printf ("Invalid order number.\n");
exit();
}

Note the following about this program:


Host Variables The host variables are declared in a section enclosed by the BEGIN DECL ARE
SECTION and END DECL ARE SECTION keywords. Each host variable name is prefixed by a colon (:)
when it appears in an embedded SQL statement. The colon allows the precompiler to distinguish
between host variables and database objects, such as tables and columns, that have the same name.
Data Types The data types supported by a DBMS and a host language can be quite different. This affects
host variables because they play a dual role. On one hand, host variables are program variables, declared
and manipulated by host language statements. On the other hand, they are used in embedded SQL
statements to retrieve database data. If there is no host language type that corresponds to a DBMS data
type, the DBMS automatically converts the data. However, because each DBMS has its own rules and
idiosyncrasies associated with the conversion process, the host variable types must be chosen carefully.
Error Handling The DBMS reports run-time errors to the applications program through an SQL
Communications Area, or SQLCA. In the preceding code example, the first embedded SQL statement is
INCLUDE SQLCA. This tells the precompiler to include the SQLCA structure in the program. This is
required whenever the program will process errors returned by the DBMS. The WHENEVER...GOTO
statement tells the precompiler to generate error-handling code that branches to a specific label when an
error occurs.
Singleton SELECT The statement used to return the data is a singleton SELECT statement; that is, it
returns only a single row of data. Therefore, the code example does not declare or use cursors.
Compiling an Embedded SQL Program
4/27/2022 • 2 minutes to read • Edit Online

Because an embedded SQL program contains a mix of SQL and host language statements, it cannot be
submitted directly to a compiler for the host language. Instead, it is compiled through a multistep process.
Although this process differs from product to product, the steps are roughly the same for all products.
This illustration shows the steps necessary to compile an embedded SQL program.

Five steps are involved in compiling an embedded SQL program:


1. The embedded SQL program is submitted to the SQL precompiler, a programming tool. The precompiler
scans the program, finds the embedded SQL statements, and processes them. A different precompiler is
required for each programming language supported by the DBMS. DBMS products typically offer
precompilers for one or more languages, including C, Pascal, COBOL, Fortran, Ada, PL/I, and various
assembly languages.
2. The precompiler produces two output files. The first file is the source file, stripped of its embedded SQL
statements. In their place, the precompiler substitutes calls to proprietary DBMS routines that provide the
run-time link between the program and the DBMS. Typically, the names and the calling sequences of
these routines are known only to the precompiler and the DBMS; they are not a public interface to the
DBMS. The second file is a copy of all the embedded SQL statements used in the program. This file is
sometimes called a database request module, or DBRM.
3. The source file output from the precompiler is submitted to the standard compiler for the host
programming language (such as a C or COBOL compiler). The compiler processes the source code and
produces object code as its output. Note that this step has nothing to do with the DBMS or with SQL.
4. The linker accepts the object modules generated by the compiler, links them with various library routines,
and produces an executable program. The library routines linked into the executable program include the
proprietary DBMS routines described in step 2.
5. The database request module generated by the precompiler is submitted to a special binding utility. This
utility examines the SQL statements, parses, validates, and optimizes them, and then produces an access
plan for each statement. The result is a combined access plan for the entire program, representing an
executable version of the embedded SQL statements. The binding utility stores the plan in the database,
usually assigning it the name of the application program that will use it. Whether this step takes place at
compile time or run time depends on the DBMS.
Notice that the steps used to compile an embedded SQL program correlate very closely with the steps described
earlier in Processing an SQL Statement. In particular, notice that the precompiler separates the SQL statements
from the host language code, and the binding utility parses and validates the SQL statements and creates the
access plans. In DBMSs where step 5 takes place at compile time, the first four steps of processing an SQL
statement take place at compile time, while the last step (execution) takes place at run time. This has the effect of
making query execution in such DBMSs very fast.
Static SQL
4/27/2022 • 2 minutes to read • Edit Online

The embedded SQL shown in Embedded SQL Example is known as static SQL. It is called static SQL because the
SQL statements in the program are static; that is, they do not change each time the program is run. As described
in the previous section, these statements are compiled when the rest of the program is compiled.
Static SQL works well in many situations and can be used in any application for which the data access can be
determined at program design time. For example, an order-entry program always uses the same statement to
insert a new order, and an airline reservation system always uses the same statement to change the status of a
seat from available to reserved. Each of these statements would be generalized through the use of host
variables; different values can be inserted in a sales order, and different seats can be reserved. Because such
statements can be hard-coded in the program, such programs have the advantage that the statements need to
be parsed, validated, and optimized only once, at compile time. This results in relatively fast code.
Dynamic SQL performance in ODBC
4/27/2022 • 2 minutes to read • Edit Online

Although static SQL works well in many situations, there's a class of applications in which the data access cannot
be determined in advance. For example, suppose a spreadsheet allows a user to enter a query, which the
spreadsheet then sends to the DBMS to retrieve data. The contents of this query obviously cannot be known to
the programmer when the spreadsheet program is written.

Dynamic execution
To solve this problem, the spreadsheet uses a form of embedded SQL called dynamic SQL. Unlike static SQL
statements, which are hard-coded in the program, dynamic SQL statements can be built at run time and placed
in a string host variable. They're then sent to the DBMS for processing. Because the DBMS must generate an
access plan at run time for dynamic SQL statements, dynamic SQL is generally slower than static SQL. When a
program containing dynamic SQL statements is compiled, the dynamic SQL statements aren't stripped from the
program, as in static SQL. Instead, they're replaced by a function call that passes the statement to the DBMS;
static SQL statements in the same program are treated normally.
The simplest way to execute a dynamic SQL statement is with an EXECUTE IMMEDIATE statement. This statement
passes the SQL statement to the DBMS for compilation and execution.
One disadvantage of the EXECUTE IMMEDIATE statement is that the DBMS must go through each of the five
steps of processing an SQL statement each time the statement is executed. The overhead involved in this
process can be significant if many statements are executed dynamically, and it's wasteful if those statements are
similar.

Prepared execution
To address the above situation, dynamic SQL offers an optimized form of execution called prepared execution,
which uses the following steps:
1. The program constructs an SQL statement in a buffer, just as it does for the EXECUTE IMMEDIATE
statement. Instead of host variables, a question mark (?) can be substituted for a constant anywhere in the
statement text to indicate that a value for the constant will be supplied later. The question mark is called
as a parameter marker.
2. The program passes the SQL statement to the DBMS with a PREPARE statement, which requests that the
DBMS parse, validate, and optimize the statement and generate an execution plan for it. The program
then uses an EXECUTE statement (not an EXECUTE IMMEDIATE statement) to execute the PREPARE
statement at a later time. It passes parameter values for the statement through a special data structure
called the SQL Data Area or SQLDA.
3. The program can use the EXECUTE statement repeatedly, supplying different parameter values each time
the dynamic statement is executed.
Prepared execution is still not the same as static SQL. In static SQL, the first four steps of processing an SQL
statement take place at compile time. In prepared execution, these steps still take place at run time, but they're
only done once. Execution of the plan takes place only when EXECUTE is called. This behavior helps eliminate
some of the performance disadvantages inherent in the architecture of dynamic SQL.

See also
EXECUTE (Transact-SQL)
sp_executesql (Transact-SQL)
SQL Modules
4/27/2022 • 2 minutes to read • Edit Online

The second technique for sending SQL statements to the DBMS is through modules. Briefly, a module consists of
a group of procedures, which are called from the host programming language. Each procedure contains a single
SQL statement, and data is passed to and from the procedure through parameters.
A module can be thought of as an object library that is linked to the application code. However, exactly how the
procedures and the rest of the application are linked is implementation-dependent. For example, the procedures
could be compiled into object code and linked directly to the application code, they could be compiled and
stored on the DBMS and calls to access plan identifiers placed in the application code, or they could be
interpreted at run time.
The main advantage of modules is that they cleanly separate SQL statements from the programming language.
In theory, it should be possible to change one without changing the other and simply relink them.
Call-Level Interfaces
4/27/2022 • 2 minutes to read • Edit Online

The final technique for sending SQL statements to the DBMS is through a call-level interface (CLI). A call-level
interface provides a library of DBMS functions that can be called by the application program. Thus, instead of
trying to blend SQL with another programming language, a call-level interface is similar to the routine libraries
most programmers are accustomed to using, such as the string, I/O, or math libraries in C. Note that DBMSs that
support embedded SQL already have a call-level interface, the calls to which are generated by the precompiler.
However, these calls are undocumented and subject to change without notice.
Call-level interfaces are commonly used in client/server architectures, in which the application program (the
client) resides on one computer and the DBMS (the server) resides on a different computer. The application calls
CLI functions on the local system, and those calls are sent across the network to the DBMS for processing.
A call-level interface is similar to dynamic SQL, in that SQL statements are passed to the DBMS for processing at
run time, but it differs from embedded SQL as a whole in that there are no embedded SQL statements and no
precompiler is required.
Using a call-level interface typically involves the following steps:
1. The application calls a CLI function to connect to the DBMS.
2. The application builds an SQL statement and places it in a buffer. It then calls one or more CLI functions to
send the statement to the DBMS for preparation and execution.
3. If the statement is a SELECT statement, the application calls a CLI function to return the results in
application buffers. Typically, this function returns one row or one column of data at a time.
4. The application calls a CLI function to disconnect from the DBMS.
Database Access Architecture
4/27/2022 • 2 minutes to read • Edit Online

One of the questions in the development of ODBC was which part of the database access architecture to
standardize. The SQL programming interfaces described in the previous section - embedded SQL, SQL modules,
and CLIs - are only one part of this architecture. In fact, because ODBC was primarily intended to connect
personal computer-based applications to minicomputer and mainframe DBMSs, there were also a number of
network components, some of which could be standardized.
This section contains the following topics.
Network Database Access
Standard Database Access Architectures
The ODBC Solution
Network Database Access
4/27/2022 • 2 minutes to read • Edit Online

Accessing a database across a network requires a number of components, each of which is independent of, and
resides beneath, the programming interface. These components are shown in the following illustration.

A further description of each component follows:


Programming Interface As described earlier in this section, the programming interface contains the
calls made by the application. These interfaces (embedded SQL, SQL modules, and call-level interfaces)
are generally specific to each DBMS, although they are usually based on an ANSI or ISO standard.
Data Stream Protocol The data stream protocol describes the stream of data transferred between the
DBMS and its client. For example, the protocol might require the first byte to describe what the rest of the
stream contains: an SQL statement to be executed, a returned error value, or returned data. The format of
the rest of the data in the stream would then depend on this flag. For example, an error stream might
contain the flag, a 2-byte integer error code, a 2-byte integer error message length, and an error
message.
The data stream protocol is a logical protocol and is independent of the protocols used by the underlying
network. Thus, a single data stream protocol can generally be used on a number of different networks.
Data stream protocols are typically proprietary and have been optimized to work with a particular DBMS.
Interprocess Communication Mechanism The interprocess communication (IPC) mechanism is the
process by which one process communicates with another. Examples include named pipes, TCP/IP
sockets, and DECnet sockets. The choice of IPC mechanism is constrained by the operating system and
network being used.
Network Protocol The network protocol is used to transport the data stream over a network. It can be
considered the plumbing that supports the IPC mechanisms used to implement the data stream protocol,
as well as supporting basic network operations such as file transfers and print sharing. Network
protocols include NetBEUI, TCP/IP, DECnet, and SPX/IPX and are specific to each network.
Standard Database Access Architectures
4/27/2022 • 2 minutes to read • Edit Online

In looking at the database access components described in the preceding section, it turns out that two of them -
programming interfaces and data stream protocols - are good candidates for standardization. The other two
components - IPC mechanism and network protocols - not only reside at too low a level but they are both highly
dependent on the network and operating system. There is also a third approach - gateways - that provides
possibilities for standardization.
This section contains the following topics.
Standard Programming Interface
Standard Data Stream Protocol
Standard Gateway
Standard Programming Interface
4/27/2022 • 2 minutes to read • Edit Online

The programming interface is perhaps the most obvious candidate for standardization. In fact, when ODBC was
being developed, ANSI and ISO already provided standards for embedded SQL and SQL modules. Although no
standards existed for a database CLI, the SQL Access Group - an industry consortium of database vendors - was
considering whether to create one; parts of ODBC later became the basis for their work.
One of the requirements for ODBC was that a single application binary had to work with multiple DBMSs. It is
for this reason that ODBC does not use embedded SQL or module languages. Although the language in
embedded SQL and module languages is standardized, each is tied to DBMS-specific precompilers. Thus,
applications must be recompiled for each DBMS and the resulting binaries work only with a single DBMS. While
this is acceptable for the low-volume applications found in the minicomputer and mainframe worlds, it is
unacceptable in the personal computer world. First, it is a logistical nightmare to deliver multiple versions of
high-volume, shrink-wrapped software to customers; second, personal computer applications often need to
access multiple DBMSs simultaneously.
On the other hand, a call-level interface can be implemented through libraries, or database drivers, that reside
on each local machine; a different driver is required for each DBMS. Because modern operating systems can
load such libraries (such as dynamic-link libraries on the Microsoft® Windows® operating system) at run
time, a single application can access data from different DBMSs without recompilation and can also access data
from multiple databases simultaneously. As new database drivers become available, users can just install these
on their computers without having to modify, recompile, or relink their database applications. Furthermore, a
call-level interface was a good candidate for ODBC because Windows - the platform for which ODBC was
originally developed - already made extensive use of such libraries.
Standard Data Stream Protocol
4/27/2022 • 2 minutes to read • Edit Online

A standard data stream protocol is one way to access data in heterogeneous DBMSs. In fact, a standard data
stream protocol already exists:
The ANSI/ISO Remote Database Access (RDA) standard: ISO/IEC 9579:2000. Although the ANSI/ISO system
shows promise, it is not widely implemented today.
Standard Gateway
4/27/2022 • 2 minutes to read • Edit Online

A gateway is a piece of software that causes one DBMS to look like another. That is, the gateway accepts the
programming interface, SQL grammar, and data stream protocol of a single DBMS and translates it to the
programming interface, SQL grammar, and data stream protocol of the hidden DBMS. For example, applications
written to use Microsoft® SQL Server™ can also access DB2 data through the Micro Decisionware DB2
Gateway; this product causes DB2 to look like SQL Server. When gateways are used, a different gateway must be
written for each target database.
Although gateways are limited by architectural differences among DBMSs, they are a good candidate for
standardization. However, if all DBMSs are to standardize on the programming interface, SQL grammar, and data
stream protocol of a single DBMS, whose DBMS is to be chosen as the standard? Certainly no commercial
DBMS vendor is likely to agree to standardize on a competitor's product. And if a standard programming
interface, SQL grammar, and data stream protocol are developed, no gateway is needed.
The ODBC Solution
4/27/2022 • 4 minutes to read • Edit Online

The question, then, is how does ODBC standardize database access? There are two architectural requirements:
Applications must be able to access multiple DBMSs using the same source code without recompiling or
relinking.
Applications must be able to access multiple DBMSs simultaneously.
And there is one more question, due to marketplace reality:
Which DBMS features should ODBC expose? Only features that are common to all DBMSs or any feature that
is available in any DBMS?
ODBC solves these problems in the following manner:
ODBC is a call-level interface. To solve the problem of how applications access multiple DBMSs using
the same source code, ODBC defines a standard CLI. This contains all of the functions in the CLI
specifications from Open Group and ISO/IEC and provides additional functions commonly required by
applications.
A different library, or driver, is required for each DBMS that supports ODBC. The driver implements the
functions in the ODBC API. To use a different driver, the application does not need to be recompiled or
relinked. Instead, the application simply loads the new driver and calls the functions in it. To access
multiple DBMSs simultaneously, the application loads multiple drivers. How drivers are supported is
operating system-specific. For example, on the Microsoft® Windows® operating system, drivers are
dynamic-link libraries (DLLs).
ODBC defines a standard SQL grammar. In addition to a standard call-level interface, ODBC defines
a standard SQL grammar. This grammar is based on the Open Group SQL CAE specification. Differences
between the two grammars are minor and primarily due to the differences between the SQL grammar
required by embedded SQL (Open Group) and a CLI (ODBC). There are also some extensions to the
grammar to expose commonly available language features not covered by the Open Group grammar.
Applications can submit statements using ODBC or DBMS-specific grammar. If a statement uses ODBC
grammar that is different from DBMS-specific grammar, the driver converts it before sending it to the
data source. However, such conversions are rare because most DBMSs already use standard SQL
grammar.
ODBC provides a Driver Manager to manage simultaneous access to multiple DBMSs.
Although the use of drivers solves the problem of accessing multiple DBMSs simultaneously, the code to
do this can be complex. Applications that are designed to work with all drivers cannot be statically linked
to any drivers. Instead, they must load drivers at run time and call the functions in them through a table
of function pointers. The situation becomes more complex if the application uses multiple drivers
simultaneously.
Rather than forcing each application to do this, ODBC provides a Driver Manager. The Driver Manager
implements all of the ODBC functions - mostly as pass-through calls to ODBC functions in drivers - and is
statically linked to the application or loaded by the application at run time. Thus, the application calls
ODBC functions by name in the Driver Manager, rather than by pointer in each driver.
When an application needs a particular driver, it first requests a connection handle with which to identify
the driver and then requests that the Driver Manager load the driver. The Driver Manager loads the driver
and stores the address of each function in the driver. To call an ODBC function in the driver, the
application calls that function in the Driver Manager and passes the connection handle for the driver. The
Driver Manager then calls the function by using the address it stored earlier.
ODBC exposes a significant number of DBMS features but does not require drivers to
suppor t all of them. If ODBC exposed only features that are common to all DBMSs, it would be of little
use; after all, the reason so many different DBMSs exist today is that they have different features. If ODBC
exposed every feature that is available in any DBMS, it would be impossible for drivers to implement.
Instead, ODBC exposes a significant number of features - more than are supported by most DBMSs - but
requires drivers to implement only a subset of those features. Drivers implement the remaining features
only if they are supported by the underlying DBMS or if they choose to emulate them. Thus, applications
can be written to exploit the features of a single DBMS as exposed by the driver for that DBMS, to use
only those features used by all DBMSs, or to check for support of a particular feature and react
accordingly.
So that an application can determine what features a driver and DBMS support, ODBC provides two
functions (SQLGetInfo and SQLGetFunctions ) that return general information about the driver and
DBMS capabilities and a list of functions the driver supports. ODBC also defines API and SQL grammar
conformance levels, which specify broad ranges of features supported by the driver. For more
information, see Conformance Levels.
It is important to remember that ODBC defines a common interface for all of the features it exposes.
Because of this, applications contain feature-specific code, not DBMS-specific code, and can use any
drivers that expose those features. One advantage of this is that applications do not need to be updated
when the features supported by a DBMS are enhanced; instead, when an updated driver is installed, the
application automatically uses the features because its code is feature-specific, not driver-specific or
DBMS-specific.
ODBC Architecture
4/27/2022 • 2 minutes to read • Edit Online

The ODBC architecture has four components:


Application Performs processing and calls ODBC functions to submit SQL statements and retrieve
results.
Driver Manager Loads and unloads drivers on behalf of an application. Processes ODBC function calls
or passes them to a driver.
Driver Processes ODBC function calls, submits SQL requests to a specific data source, and returns results
to the application. If necessary, the driver modifies an application's request so that the request conforms
to syntax supported by the associated DBMS.
Data Source Consists of the data the user wants to access and its associated operating system, DBMS,
and network platform (if any) used to access the DBMS.
Note the following points about the ODBC architecture. First, multiple drivers and data sources can exist, which
allows the application to simultaneously access data from more than one data source. Second, the ODBC API is
used in two places: between the application and the Driver Manager, and between the Driver Manager and each
driver. The interface between the Driver Manager and the drivers is sometimes referred to as the service
provider interface, or SPI. For ODBC, the application programming interface (API) and the service provider
interface (SPI) are the same; that is, the Driver Manager and each driver have the same interface to the same
functions.
This section contains the following topics.
Applications
The Driver Manager
Drivers
Data Sources
Applications
4/27/2022 • 2 minutes to read • Edit Online

An application is a program that calls the ODBC API to access data. Although many types of applications are
possible, most fall into three categories, which are used as examples throughout this guide.
Generic Applications These are also referred to as shrink-wrapped applications or off-the-shelf
applications. Generic applications are designed to work with a variety of different DBMSs. Examples
include a spreadsheet or statistics package that uses ODBC to import data for further analysis and a word
processor that uses ODBC to get a mailing list from a database.
An important subcategory of generic applications is application development environments, such as
PowerBuilder or Microsoft® Visual Basic®. Although the applications constructed with these
environments will probably work only with a single DBMS, the environment itself needs to work with
multiple DBMSs.
What all generic applications have in common is that they are highly interoperable among DBMSs and
they need to use ODBC in a relatively generic manner. For more information about interoperability, see
Choosing a Level of Interoperability.
Ver tical Applications Vertical applications perform a single type of task, such as order entry or tracking
manufacturing data, and work with a database schema that is controlled by the developer of the
application. For a particular customer, the application works with a single DBMS. For example, a small
business might use the application with dBase, while a large business might use it with Oracle.
The application uses ODBC in such a manner that the application is not tied to any one DBMS, although it
might be tied to a limited number of DBMSs that provide similar functionality. Thus, the application
developer can sell the application independently from the DBMS. Vertical applications are interoperable
when they are developed but are sometimes modified to include noninteroperable code once the
customer has chosen a DBMS.
Custom Applications Custom applications are used to perform a specific task in a single company. For
example, an application in a large company might gather sales data from several divisions (each of which
uses a different DBMS) and create a single report. ODBC is used because it is a common interface and
saves programmers from having to learn multiple interfaces. Such applications are generally not
interoperable and are written to specific DBMSs and drivers.
A number of tasks are common to all applications, no matter how they use ODBC. Taken together, they largely
define the flow of any ODBC application. The tasks are:
Selecting a data source and connecting to it.
Submitting an SQL statement for execution.
Retrieving results (if any).
Processing errors.
Committing or rolling back the transaction enclosing the SQL statement.
Disconnecting from the data source.
Because most data access work is done with SQL, the primary task for which applications use ODBC is to submit
SQL statements and retrieve the results (if any) generated by those statements. Other tasks for which
applications use ODBC include determining and adjusting to driver capabilities and browsing the database
catalog.
The Driver Manager
4/27/2022 • 2 minutes to read • Edit Online

The Driver Manager is a library that manages communication between applications and drivers. For example, on
Microsoft® Windows® platforms, the Driver Manager is a dynamic-link library (DLL) that is written by
Microsoft and can be redistributed by users of the redistributable MDAC 2.8 SP1 SDK.
The Driver Manager exists mainly as a convenience to application writers and solves a number of problems
common to all applications. These include determining which driver to load based on a data source name,
loading and unloading drivers, and calling functions in drivers.
To see why the latter is a problem, consider what would happen if the application called functions in the driver
directly. Unless the application was linked directly to a particular driver, it would have to build a table of pointers
to the functions in that driver and call those functions by pointer. Using the same code for more than one driver
at a time would add yet another level of complexity. The application would first have to set a function pointer to
point to the correct function in the correct driver, and then call the function through that pointer.
The Driver Manager solves this problem by providing a single place to call each function. The application is
linked to the Driver Manager and calls ODBC functions in the Driver Manager, not the driver. The application
identifies the target driver and data source with a connection handle. When it loads a driver, the Driver Manager
builds a table of pointers to the functions in that driver. It uses the connection handle passed by the application
to find the address of the function in the target driver and calls that function by address.
For the most part, the Driver Manager just passes function calls from the application to the correct driver.
However, it also implements some functions (SQLDataSources , SQLDrivers , and SQLGetFunctions ) and
performs basic error checking. For example, the Driver Manager checks that handles are not null pointers, that
functions are called in the correct order, and that certain function arguments are valid. For a complete
description of the errors checked by the Driver Manager, see the reference section for each function and
Appendix B: ODBC State Transition Tables.
The final major role of the Driver Manager is loading and unloading drivers. The application loads and unloads
only the Driver Manager. When it wants to use a particular driver, it calls a connection function (SQLConnect ,
SQLDriverConnect , or SQLBrowseConnect ) in the Driver Manager and specifies the name of a particular
data source or driver, such as "Accounting" or "SQL Server." Using this name, the Driver Manager searches the
data source information for the driver's file name, such as Sqlsrvr.dll. It then loads the driver (assuming it is not
already loaded), stores the address of each function in the driver, and calls the connection function in the driver,
which then initializes itself and connects to the data source.
When the application is done using the driver, it calls SQLDisconnect in the Driver Manager. The Driver
Manager calls this function in the driver, which disconnects from the data source. However, the Driver Manager
keeps the driver in memory in case the application reconnects to it. It unloads the driver only when the
application frees the connection used by the driver or uses the connection for a different driver, and no other
connections use the driver. For a complete description of the Driver Manager's role in loading and unloading
drivers, see Driver Manager's Role in the Connection Process.
Drivers
4/27/2022 • 2 minutes to read • Edit Online

Drivers are libraries that implement the functions in the ODBC API. Each is specific to a particular DBMS; for
example, a driver for Oracle cannot directly access data in an Informix DBMS. Drivers expose the capabilities of
the underlying DBMSs; they are not required to implement capabilities not supported by the DBMS. For
example, if the underlying DBMS does not support outer joins, then neither should the driver. The only major
exception to this is that drivers for DBMSs that do not have stand-alone database engines, such as Xbase, must
implement a database engine that at least supports a minimal amount of SQL.
This section contains the following topics.
Driver Tasks
Driver Architecture

See Also
Microsoft-Supplied ODBC Drivers
Driver Tasks
4/27/2022 • 2 minutes to read • Edit Online

Specific tasks performed by drivers include:


Connecting to and disconnecting from the data source.
Checking for function errors not checked by the Driver Manager.
Initiating transactions; this is transparent to the application.
Submitting SQL statements to the data source for execution. The driver must modify ODBC SQL to
DBMS-specific SQL; this is often limited to replacing escape clauses defined by ODBC with DBMS-specific
SQL.
Sending data to and retrieving data from the data source, including converting data types as specified by
the application.
Mapping DBMS-specific errors to ODBC SQLSTATEs.
Driver Architecture
4/27/2022 • 2 minutes to read • Edit Online

Driver architecture falls into two categories, depending on which software processes SQL statements:
File-Based Drivers The driver accesses the physical data directly. In this case, the driver acts as both
driver and data source; that is, it processes ODBC calls and SQL statements. For example, dBASE drivers
are file-based drivers because dBASE does not provide a stand-alone database engine the driver can use.
It is important to note that developers of file-based drivers must write their own database engines.
DBMS-Based Drivers The driver accesses the physical data through a separate database engine. In this
case the driver processes only ODBC calls; it passes SQL statements to the database engine for
processing. For example, Oracle drivers are DBMS-based drivers because Oracle has a stand-alone
database engine the driver uses. Where the database engine resides is immaterial. It can reside on the
same machine as the driver or a different machine on the network; it might even be accessed through a
gateway.
Driver architecture is generally interesting only to driver writers; that is, driver architecture generally makes no
difference to the application. However, the architecture can affect whether an application can use DBMS-specific
SQL. For example, Microsoft Access provides a stand-alone database engine. If a Microsoft Access driver is
DBMS-based - it accesses the data through this engine - the application can pass Microsoft Access-SQL
statements to the engine for processing.
However, if the driver is file-based - that is, it contains a proprietary engine that accesses the Microsoft®
Access .mdb file directly - any attempts to pass Microsoft Access-specific SQL statements to the engine are likely
to result in syntax errors. The reason is that the proprietary engine is likely to implement only ODBC SQL.
This section contains the following topics.
File-Based Drivers
DBMS-Based Drivers
Network Example
Other Driver Architectures
File-Based Drivers
4/27/2022 • 2 minutes to read • Edit Online

File-based drivers are used with data sources such as dBASE that do not provide a stand-alone database engine
for the driver to use. These drivers access the physical data directly and must implement a database engine to
process SQL statements. As a standard practice, the database engines in file-based drivers implement the subset
of ODBC SQL defined by the minimum SQL conformance level; for a list of the SQL statements in this
conformance level, see Appendix C: SQL Grammar.
In comparing file-based and DBMS-based drivers, file-based drivers are harder to write because of the database
engine component, less complicated to configure because there are no network pieces, and less powerful
because few people have the time to write database engines as powerful as those produced by database
companies.
The following illustration shows two different configurations of file-based drivers, one in which the data resides
locally and the other in which it resides on a network file server.
DBMS-Based Drivers
4/27/2022 • 2 minutes to read • Edit Online

DBMS-based drivers are used with data sources such as Oracle or SQL Server that provide a stand-alone
database engine for the driver to use. These drivers access the physical data through the stand-alone engine;
that is, they submit SQL statements to and retrieve results from the engine.
Because DBMS-based drivers use an existing database engine, they are usually easier to write than file-based
drivers. Although a DBMS-based driver can be easily implemented by translating ODBC calls to native API calls,
this results in a slower driver. A better way to implement a DBMS-based driver is to use the underlying data
stream protocol, which is usually what the native API does. For example, a SQL Server driver should use TDS
(the data stream protocol for SQL Server) rather than DB Library (the native API for SQL Server). An exception
to this rule is when ODBC is the native API. For example, Watcom SQL is a stand-alone engine that resides on
the same machine as the application and is loaded directly as the driver.
DBMS-based drivers act as the client in a client/server configuration where the data source acts as the server. In
most cases, the client (driver) and server (data source) reside on different machines, although both could reside
on the same machine running a multitasking operating system. A third possibility is a gateway, which sits
between the driver and data source. A gateway is a piece of software that causes one DBMS to look like another.
For example, applications written to use SQL Server can also access DB2 data through the Micro Decisionware
DB2 Gateway; this product causes DB2 to look like SQL Server.
The following illustration shows three different configurations of DBMS-based drivers. In the first configuration,
the driver and data source reside on the same machine. In the second, the driver and data source reside on
different machines. In the third, the driver and data source reside on different machines and a gateway sits
between them, residing on yet another machine.
Network Example
4/27/2022 • 2 minutes to read • Edit Online

This illustration shows how each of the preceding configurations could appear in a single network.
Other Driver Architectures
4/27/2022 • 3 minutes to read • Edit Online

Some ODBC drivers do not strictly conform to the architecture described previously. This might be because the
drivers perform duties other than those of a traditional ODBC driver, or are not drivers in the normal sense.

Driver as a Middle Component


The ODBC driver may reside between the Driver Manager and one or more other ODBC drivers. When the
driver in the middle is capable of working with multiple data sources, it acts as a dispatcher of ODBC calls (or
appropriately translated calls) to other modules that actually access the data sources. In this architecture, the
driver in the middle is taking on some of the role of a Driver Manager.
Another example of this sort of driver is a spy program for ODBC, which intercepts and copies ODBC functions
being sent between the Driver Manager and the driver. This layer can be used to emulate either a driver or an
application. To the Driver Manager, the layer appears to be the driver; to the driver, the layer appears to be the
Driver Manager.

Heterogeneous Join Engines


Some ODBC drivers are built upon a query engine for performing heterogeneous joins. In one architecture of a
heterogeneous join engine (see the following illustration), the driver appears to the application as a driver but
appears to another instance of the Driver Manager as an application. This driver processes a heterogeneous join
from the application by calling separate SQL statements in drivers for each joined database.

This architecture provides a common interface for the application to access data from different databases. It can
use a common way to retrieve metadata, such as information about special columns (row identifiers), and it can
call common catalog functions to retrieve data dictionary information. By calling the ODBC function
SQLStatistics , for instance, the application can retrieve information about the indexes on the tables to be
joined, even if the tables are on two separate databases. The query processor does not have to worry about how
the databases store metadata.
The application also has standard access to data types. ODBC defines common SQL data types that DBMS-
specific data types are mapped to. An application can call SQLGetTypeInfo to retrieve information about data
types on different databases.
When the application generates a heterogeneous join statement, the query processor in this architecture parses
the SQL statement and then generates separate SQL statements for each database to be joined. By using
metadata about each driver, the query processor can determine the most efficient, intelligent join. For example, if
the statement joins two tables on one database with one table on another database, the query processor can
join the two tables on the one database before joining the result with the table from the other database.

ODBC on the Server


ODBC drivers can be installed on a server so that they can be used by applications on any of a series of client
machines. In this architecture (see the following illustration), a Driver Manager and a single ODBC driver are
installed on each client, and another Driver Manager and a series of ODBC drivers are installed on the server.
This allows each client access to a variety of drivers used and maintained on the server.

One advantage of this architecture is efficient software maintenance and configuration. Drivers need only be
updated in one place: on the server. By using system data sources, data sources can be defined on the server for
use by all clients. The data sources need not be defined on the client. Connection pooling can be used to
streamline the process by which clients connect to data sources.
The driver on the client is usually a very small driver that transfers the Driver Manager call to the server. Its
footprint can be significantly smaller than the fully functional ODBC drivers on the server. In this architecture,
client resources can be freed if the server has more computing power. In addition, the efficiency and security of
the entire system can be enhanced by installing backup servers and performing load balancing to optimize
server use.
Data Sources
4/27/2022 • 2 minutes to read • Edit Online

A data source is simply the source of the data. It can be a file, a particular database on a DBMS, or even a live
data feed. The data might be located on the same computer as the program, or on another computer
somewhere on a network. For example, a data source might be an Oracle DBMS running on an OS/2®
operating system, accessed by Novell® Netware; an IBM DB2 DBMS accessed through a gateway; a collection
of Xbase files in a server directory; or a local Microsoft® Access database file.
The purpose of a data source is to gather all of the technical information needed to access the data - the driver
name, network address, network software, and so on - into a single place and hide it from the user. The user
should be able to look at a list that includes Payroll, Inventory, and Personnel, choose Payroll from the list, and
have the application connect to the payroll data, all without knowing where the payroll data resides or how the
application got to it.
The term data source should not be confused with similar terms. In this manual, DBMS or database refers to a
database program or engine. A further distinction is made between desktop databases, designed to run on
personal computers and often lacking in full SQL and transaction support, and server databases, designed to
run in a client/server situation and characterized by a stand-alone database engine and rich SQL and transaction
support. Database also refers to a particular collection of data, such as a collection of Xbase files in a directory or
a database on SQL Server. It is generally equivalent to the term catalog, used elsewhere in this manual, or the
term qualifier in earlier versions of ODBC.
This section contains the following topics.
Types of Data Sources
Using Data Sources
Data Source Example
Types of Data Sources
4/27/2022 • 2 minutes to read • Edit Online

There are two types of data sources: machine data sources and file data sources. Although both contain similar
information about the source of the data, they differ in the way this information is stored. Because of these
differences, they are used in somewhat different manners.
This section contains the following topics.
Machine Data Sources
File Data Sources
Machine Data Sources
4/27/2022 • 2 minutes to read • Edit Online

Machine data sources are stored on the system with a user-defined name. Associated with the data source name
is all of the information the Driver Manager and driver need to connect to the data source. For an Xbase data
source, this might be the name of the Xbase driver, the full path of the directory containing the Xbase files, and
some options that tell the driver how to use those files, such as single-user mode or read-only. For an Oracle
data source, this might be the name of the Oracle driver, the server where the Oracle DBMS resides, the SQL*Net
connection string that identifies the SQL*Net driver to use, and the system ID of the database on the server.
File Data Sources
4/27/2022 • 2 minutes to read • Edit Online

File data sources are stored in a file and allow connection information to be used repeatedly by a single user or
shared among several users. When a file data source is used, the Driver Manager makes the connection to the
data source using the information in a .dsn file. This file can be manipulated like any other file. A file data source
does not have a data source name, as does a machine data source, and is not registered to any one user or
machine.
A file data source streamlines the connection process, because the .dsn file contains the connection string that
would otherwise have to be built for a call to the SQLDriverConnect function. Another advantage of the .dsn
file is that it can be copied to any machine, so identical data sources can be used by many machines as long as
they have the appropriate driver installed. A file data source can also be shared by applications. A shareable file
data source can be placed on a network and used simultaneously by multiple applications.
A .dsn file can also be unshareable. An unshareable .dsn file resides on a single machine and points to a machine
data source. Unshareable file data sources exist mainly to allow the easy conversion of machine data sources to
file data sources so that an application can be designed to work solely with file data sources. When the Driver
Manager is sent the information in an unshareable file data source, it connects as necessary to the machine data
source that the .dsn file points to.
For more information about file data sources, see Connecting Using File Data Sources, or the SQLDriverConnect
function description.
Using Data Sources
4/27/2022 • 2 minutes to read • Edit Online

Data sources usually are created by the end user or a technician with a program called the ODBC Administrator.
The ODBC Administrator prompts the user for the driver to use and then calls that driver. The driver displays a
dialog box that requests the information it needs to connect to the data source. After the user enters the
information, the driver stores it on the system.
Later, the application calls the Driver Manager and passes it the name of a machine data source or the path of a
file containing a file data source. When passed a machine data source name, the Driver Manager searches the
system to find the driver used by the data source. It then loads the driver and passes the data source name to it.
The driver uses the data source name to find the information it needs to connect to the data source. Finally, it
connects to the data source, typically prompting the user for a user ID and password, which generally are not
stored.
When passed a file data source, the Driver Manager opens the file and loads the specified driver. If the file also
contains a connection string, it passes this to the driver. Using the information in the connection string, the
driver connects to the data source. If no connection string was passed, the driver generally prompts the user for
the necessary information.
Data Source Example
4/27/2022 • 2 minutes to read • Edit Online

On computers running Microsoft® Windows NT® Server/Windows 2000 Server, Microsoft Windows NT
Workstation/Windows 2000 Professional, or Microsoft Windows® 95/98, machine data source information is
stored in the registry. Depending on which registry key the information is stored under, the data source is
known as a user data source or a system data source. User data sources are stored under the
HKEY_CURRENT_USER key and are available only to the current user. System data sources are stored under the
HKEY_LOCAL_MACHINE key and can be used by more than one user on one machine. They can also be used by
systemwide services, which can then gain access to the data source even if no user is logged on to the machine.
For more information about user and system data sources, see SQLManageDataSources.
Suppose a user has three user data sources: Personnel and Inventory, which use an Oracle DBMS; and Payroll,
which uses a Microsoft SQL Server DBMS. The registry values for data sources might be:

HKEY_CURRENT_USER
SOFTWARE
ODBC
Odbc.ini
ODBC Data Sources
Personnel : REG_SZ : Oracle
Inventory : REG_SZ : Oracle
Payroll : REG_SZ : SQL Server

and the registry values for the Payroll data source might be:

HKEY_CURRENT_USER
SOFTWARE
ODBC
Odbc.ini
Payroll
Driver : REG_SZ : C:\WINDOWS\SYSTEM\Sqlsrvr.dll
Description : REG_SZ : Payroll database
Server : REG_SZ : PYRLL1
FastConnectOption : REG_SZ : No UseProcForPrepare : REG_SZ
: Yes
OEMTOANSI : REG_SZ : No
LastUser : REG_SZ : smithjo
Database : REG_SZ : Payroll
Language : REG_SZ :
ODBC 64-Bit Information
4/27/2022 • 6 minutes to read • Edit Online

Beginning with Windows Server 2003, Microsoft operating systems have supported the 64-bit ODBC libraries.
The ODBC headers and libraries first shipped with MDAC 2.7 SDK contain changes to allow programmers to
easily write code for the new 64 bit platforms. By ensuring that your code uses the ODBC defined types listed
below, you can compile the same source code both for 64-bit and 32-bit platforms based on the _WIN64 or
WIN32 macros.
There are several points to keep in mind when programming for a 64-bit processor:
Although the size of a pointer has changed from 4 bytes to 8 bytes, integers and longs are still 4 byte
values. The types INT64 and UINT64 have been defined for 8 byte integers. The new ODBC types
SQLLEN and SQLULEN are defined in the ODBC header file as INT64 and UINT64 when _WIN64 has
been defined.
Several functions in ODBC are declared as taking a pointer parameter. In 32-bit ODBC, parameters
defined as pointers were frequently used to pass either an integer value or a pointer to a buffer
depending on the context of the call. This was, of course, possible due to the fact that pointers and
integers had the same size. In 64-bit Windows, this is not the case.
Some ODBC functions that were previously defined with SQLINTEGER and SQLUINTEGER parameters
have been changed where appropriate to use the new SQLLEN and SQLULEN typedefs. These changes
are listed in the next section, Function Declaration Changes.
Some of the descriptor fields that can be set through the various SQLSet and SQLGet functions have
been changed to accommodate 64-bit values while others are still 32-bit values. Make sure that you use
the appropriate sized variable when setting and retrieving these fields. Specifics of which descriptor fields
have changed are listed under Function Declaration Changes.

Function Declaration Changes


The following function signatures have changed for 64-bit programming. The items in bold text are the specific
parameters that are different.

SQLBindCol (SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber,


SQLSMALLINT TargetType, SQLPOINTER TargetValuePtr, SQLLEN BufferLength, SQLLEN * StrLen_or_Ind);

SQLBindParam (SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber,


SQLSMALLINT ValueType, SQLSMALLINT ParameterType,
SQLULEN ColumnSize, SQLSMALLINT DecimalDigits,
SQLPOINTER ParameterValuePtr, SQLLEN *StrLen_or_Ind);

SQLBindParameter (SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber,


SQLSMALLINT InputOutputType, SQLSMALLINT ValueType,
SQLSMALLINT ParameterType, SQLULEN ColumnSize, SQLSMALLINT DecimalDigits,
SQLPOINTER ParameterValuePtr, SQLLEN BufferLength, SQLLEN *StrLen_or_IndPtr);

SQLColAttribute (SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber,


SQLUSMALLINT FieldIdentifier, SQLPOINTER CharacterAttributePtr,
SQLSMALLINT BufferLength, SQLSMALLINT * StringLengthPtr,
SQLLEN* NumericAttributePtr)

SQLColAttributes (SQLHSTMT hstmt, SQLUSMALLINT icol,


SQLUSMALLINT fDescType, SQLPOINTER rgbDesc,
SQLSMALLINT cbDescMax, SQLSMALLINT *pcbDesc, SQLLEN * pfDesc);
SQLSMALLINT cbDescMax, SQLSMALLINT *pcbDesc, SQLLEN * pfDesc);

SQLDescribeCol (SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber,


SQLCHAR *ColumnName, SQLSMALLINT BufferLength,
SQLSMALLINT *NameLengthPtr, SQLSMALLINT *DataTypePtr, SQLULEN *ColumnSizePtr,
SQLSMALLINT *DecimalDigitsPtr, SQLSMALLINT *NullablePtr);

SQLDescribeParam (SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber,


SQLSMALLINT *DataTypePtr, SQLULEN *ParameterSizePtr, SQLSMALLINT *DecimalDigitsPtr,
SQLSMALLINT *NullablePtr);

SQLExtendedFetch(SQLHSTMT StatementHandle, SQLUSMALLINT FetchOrientation, SQLLEN FetchOffset,


SQLULEN * RowCountPtr, SQLUSMALLINT * RowStatusArray);

SQLFetchScroll (SQLHSTMT StatementHandle, SQLSMALLINT FetchOrientation,


SQLLEN FetchOffset);

SQLGetData (SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber,


SQLSMALLINT TargetType, SQLPOINTER TargetValuePtr, SQLLEN BufferLength, SQLLEN *StrLen_or_Ind);

SQLGetDescRec (SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,


SQLCHAR *Name, SQLSMALLINT BufferLength,
SQLSMALLINT *StringLengthPtr, SQLSMALLINT *TypePtr,
SQLSMALLINT *SubTypePtr, SQLLEN *LengthPtr,
SQLSMALLINT *PrecisionPtr, SQLSMALLINT *ScalePtr,
SQLSMALLINT *NullablePtr);

SQLParamOptions(SQLHSTMT hstmt, SQLULEN crow, SQLULEN * pirow);

SQLPutData (SQLHSTMT StatementHandle, SQLPOINTER DataPtr,


SQLLEN StrLen_or_Ind);

SQLRowCount (SQLHSTMT StatementHandle, SQLLEN* RowCountPtr);

SQLSetConnectOption(SQLHDBC ConnectHandle, SQLUSMALLINT Option,


SQLULEN Value);

SQLSetPos (SQLHSTMT StatementHandle, SQLSETPOSIROW RowNumber, SQLUSMALLINT Operation,


SQLUSMALLINT LockType);

SQLSetParam (SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNumber,


SQLSMALLINT ValueType, SQLSMALLINT ParameterType,
SQLULEN LengthPrecision, SQLSMALLINT ParameterScale,
SQLPOINTER ParameterValue, SQLLEN *StrLen_or_Ind);

SQLSetDescRec (SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber,


SQLSMALLINT Type, SQLSMALLINT SubType, SQLLEN Length,
SQLSMALLINT Precision, SQLSMALLINT Scale, SQLPOINTER DataPtr,
SQLLEN *StringLengthPtr, SQLLEN *IndicatorPtr);

SQLSetScrollOptions (SQLHSTMT hstmt, SQLUSMALLINT fConcurrency,


SQLLEN crowKeyset, SQLUSMALLINT crowRowset);

SQLSetStmtOption (SQLHSTMT StatementHandle, SQLUSMALLINT Option,


SQLULEN Value);

Changes in SQL Data Types


The following four SQL types are still supported on 32-bit only; they are not defined for 64-bit compilers. These
types are no longer used for any parameters in MDAC 2.7; use of these types will cause compiler failures on 64-
bit platforms.
#ifdef WIN32
typedef SQLULEN SQLROWCOUNT;
typedef SQLULEN SQLROWSETSIZE;
typedef SQLULEN SQLTRANSID;
typedef SQLLEN SQLROWOFFSET;
#endif

The definition of SQLSETPOSIROW has changed for both 32-bit and 64-bit compilers:

#ifdef _WIN64
typedef UINT64 SQLSETPOSIROW;
#else
#define SQLSETPOSIROW SQLUSMALLINT
#endif

The definitions of SQLLEN and SQLULEN have changed for 64-bit compilers:

#ifdef _WIN64
typedef INT64 SQLLEN;
typedef UINT64 SQLULEN;
#else
#define SQLLEN SQLINTEGER
#define SQLULEN SQLUINTEGER
#endif

Although SQL_C_BOOKMARK is deprecated in ODBC 3.0, for 64-bit compilers on 2.0 clients, this value has
changed:

#ifdef _WIN64
#define SQL_C_BOOKMARK SQL_C_UBIGINT
#else
#define SQL_C_BOOKMARK SQL_C_ULONG
#endif

The BOOKMARK type is defined differently in the newer headers:

typedef SQLULEN BOOKMARK;

Values Returned from ODBC API Calls Through Pointers


The following ODBC function calls take as an input parameter a pointer to a buffer in which data is returned
from the driver. The context and meaning of the data returned is determined by other input parameters for the
functions. In some cases, these methods may now return 64-bit (8-byte integer) values instead of the typical 32-
bit (4-byte) integer values. These cases are as follows:
SQLColAttribute
When the FieldIdentifier parameter has one of the following values, a 64-bit value is returned in
*NumericAttribute:
SQL_DESC_AUTO_UNIQUE_VALUE
SQL_DESC_CASE_SENSITIVE
SQL_DESC_CONCISE_TYPE
SQL_DESC_COUNT
SQL_DESC_DISPLAY_SIZE
SQL_DESC_FIXED_PREC_SCALE
SQL_DESC_LENGTH
SQL_DESC_NULLABLE
SQL_DESC_NUM_PREC_RADIX
SQL_DESC_OCTET_LENGTH
SQL_DESC_PRECISION
SQL_DESC_SCALE
SQL_DESC_SEARCHABLE
SQL_DESC_TYPE
SQL_DESC_UNNAMED
SQL_DESC_UNSIGNED
SQL_DESC_UPDATABLE
SQLColAttributes
When the fDescType parameter has one of the following values, a 64-bit value is returned in *pfDesc:
SQL_COLUMN_COUNT
SQL_COLUMN_DISPLAY_SIZE
SQL_COLUMN_LENGTH
SQL_DESC_AUTO_UNIQUE_VALUE
SQL_DESC_CASE_SENSITIVE
SQL_DESC_CONCISE_TYPE
SQL_DESC_FIXED_PREC_SCALE
SQL_DESC_SEARCHABLE
SQL_DESC_UNSIGNED
SQL_DESC_UPDATABLE
SQLGetConnectAttr
When the Attribute parameter has one of the following values, a 64-bit value is returned in Value:
SQL_ATTR_ASYNC_ENABLE
SQL_ATTR_ENLIST_IN_DTC
SQL_ATTR_ODBC_CURSORS
SQL_ATTR_QUIET_MODE
SQLGetConnectOption
When the Attribute parameter has one of the following values, a 64-bit value is returned in Value:
SQL_ATTR_QUIET_MODE
SQLGetDescField
When the FieldIdentifier parameter has one of the following values, a 64-bit value is returned in *ValuePtr:
SQL_DESC_ARRAY_SIZE
SQL_DESC_ARRAY_STATUS_PTR
SQL_DESC_BIND_OFFSET_PTR
SQL_DESC_DATA_PTR
SQL_DESC_DISPLAY_SIZE
SQL_DESC_INDICATOR_PTR
SQL_DESC_LENGTH
SQL_DESC_OCTET_LENGTH
SQL_DESC_OCTET_LENGTH_PTR
SQL_DESC_ROWS_PROCESSED_PTR
SQLGetDiagField
When the DiagIdentifier parameter has one of the following values, a 64-bit value is returned in *DiagInfoPtr:
SQL_DIAG_CURSOR_ROW_COUNT
SQL_DIAG_ROW_COUNT
SQL_DIAG_ROW_NUMBER
SQLGetInfo
When the InfoType parameter has one of the following values, a 64-bit value is returned in *InfoValuePtr:
SQL_DRIVER_HDBC
SQL_DRIVER_HENV
SQL_DRIVER_HLIB
When InfoType has either of the following 2 values *InfoValuePtr is 64-bits on both input and output:
SQL_DRIVER_HDESC
SQL_DRIVER_HSTMT
SQLGetStmtAttr
When the Attribute parameter has one of the following values, a 64-bit value is returned in *ValuePtr:
SQL_ATTR_APP_PARAM_DESC
SQL_ATTR_APP_ROW_DESC
SQL_ATTR_ASYNC_ENABLE
SQL_ATTR_CONCURRENCY
SQL_ATTR_CURSOR_SCROLLABLE
SQL_ATTR_CURSOR_SENSITIVITY
SQL_ATTR_CURSOR_TYPE
SQL_ATTR_ENABLE_AUTO_IPD
SQL_ATTR_FETCH_BOOKMARK_PTR
SQL_ATTR_ROWS_FETCHED_PTR
SQL_ATTR_IMP_PARAM_DESC
SQL_ATTR_IMP_ROW_DESC
SQL_ATTR_KEYSET_SIZE
SQL_ATTR_MAX_LENGTH
SQL_ATTR_MAX_ROWS
SQL_ATTR_METADATA_ID
SQL_ATTR_NOSCAN
SQL_ATTR_PARAM_BIND_OFFSET_PTR
SQL_ATTR_PARAM_BIND_TYPE
SQL_ATTR_PARAM_OPERATION_PTR
SQL_ATTR_PARAM_STATUS_PTR
SQL_ATTR_PARAMS_PROCESSED_PTR
SQL_ATTR_PARAMSET_SIZE
SQL_ATTR_QUERY_TIMEOUT
SQL_ATTR_RETRIEVE_DATA
SQL_ATTR_ROW_ARRAY_SIZE
SQL_ATTR_ROW_BIND_OFFSET_PTR
SQL_ATTR_ROW_NUMBER
SQL_ATTR_ROW_OPERATION_PTR
SQL_ATTR_ROW_STATUS_PTR
SQL_ATTR_SIMULATE_CURSOR
SQL_ATTR_USE_BOOKMARKS
SQLGetStmtOption
When the Option parameter has one of the following values, a 64-bit value is returned in *Value:
SQL_KEYSET_SIZE
SQL_MAX_LENGTH
SQL_MAX_ROWS
SQL_ROWSET_SIZE
SQLSetConnectAttr
When the Attribute parameter has one of the following values, a 64-bit value is passed in Value:
SQL_ATTR_ASYNC_ENABLE
SQL_ATTR_ENLIST_IN_DTC
SQL_ATTR_ODBC_CURSORS
SQL_ATTR_QUIET_MODE
SQLSetConnectOption
When the Attribute parameter has one of the following values, a 64-bit value is passed in Value:
SQL_ATTR_QUIET_MODE
SQLSetDescField
When the FieldIdentifier parameter has one of the following values, a 64-bit value is passed in ValuePtr:
SQL_DESC_ARRAY_SIZE
SQL_DESC_ARRAY_STATUS_PTR
SQL_DESC_BIND_OFFSET_PTR
SQL_DESC_DATA_PTR
SQL_DESC_DISPLAY_SIZE
SQL_DESC_INDICATOR_PTR
SQL_DESC_LENGTH
SQL_DESC_OCTET_LENGTH
SQL_DESC_OCTET_LENGTH_PTR
SQL_DESC_ROWS_PROCESSED_PTR
SQLSetStmtAttr
When the Attribute parameter has one of the following values, a 64-bit value is passed in ValuePtr:
SQL_ATTR_APP_PARAM_DESC
SQL_ATTR_APP_ROW_DESC
SQL_ATTR_ASYNC_ENABLE
SQL_ATTR_CONCURRENCY
SQL_ATTR_CURSOR_SCROLLABLE
SQL_ATTR_CURSOR_SENSITIVITY
SQL_ATTR_CURSOR_TYPE
SQL_ATTR_ENABLE_AUTO_IPD
SQL_ATTR_FETCH_BOOKMARK_PTR
SQL_ATTR_IMP_PARAM_DESC
SQL_ATTR_IMP_ROW_DESC
SQL_ATTR_KEYSET_SIZE
SQL_ATTR_MAX_LENGTH
SQL_ATTR_MAX_ROWS
SQL_ATTR_METADATA_ID
SQL_ATTR_NOSCAN
SQL_ATTR_PARAM_BIND_OFFSET_PTR
SQL_ATTR_PARAM_BIND_TYPE
SQL_ATTR_PARAM_OPERATION_PTR
SQL_ATTR_PARAM_STATUS_PTR
SQL_ATTR_PARAMS_PROCESSED_PTR
SQL_ATTR_PARAMSET_SIZE
SQL_ATTR_QUERY_TIMEOUT
SQL_ATTR_RETRIEVE_DATA
SQL_ATTR_ROW_ARRAY_SIZE
SQL_ATTR_ROW_BIND_OFFSET_PTR
SQL_ATTR_ROW_NUMBER
SQL_ATTR_ROW_OPERATION_PTR
SQL_ATTR_ROW_STATUS_PTR
SQL_ATTR_ROWS_FETCHED_PTR
SQL_ATTR_SIMULATE_CURSOR
SQL_ATTR_USE_BOOKMARKS
SQLSetStmtOption
When the Option parameter has one of the following values, a 64-bit value is passed in Value:
SQL_KEYSET_SIZE
SQL_MAX_LENGTH
SQL_MAX_ROWS
SQL_ROWSET_SIZE

See Also
Introduction to ODBC
Developing Applications
4/27/2022 • 2 minutes to read • Edit Online

This section contains information about developing applications that use the ODBC interface and drivers that
implement it.
This section contains the following topics.
ODBC Fundamentals
Basic ODBC Application Steps
Connecting to a Data Source or Driver
Catalog Functions
SQL Statements
Executing Statements
Retrieving Results (Basic)
Retrieving Results (Advanced)
Updating Data Overview
Descriptors
Transactions
Diagnostics
Interoperability
Programming Considerations

See Also
ODBC Programmer's Reference
ODBC Fundamentals
4/27/2022 • 2 minutes to read • Edit Online

This section contains the following topics.


Handles
Buffers
Data Types in ODBC
Conformance Levels
Environment, Connection, and Statement Attributes
Tables and Views
Handles
4/27/2022 • 3 minutes to read • Edit Online

Handles are opaque, 32-bit values that identify a particular item; in ODBC, this item can be an environment,
connection, statement, or descriptor. When the application calls SQL AllocHandle , the Driver Manager or driver
creates a new item of the specified type and returns its handle to the application. The application later uses the
handle to identify that item when calling ODBC functions. The Driver Manager and driver use the handle to
locate information about the item.
For example, the following code uses two statement handles (hstmtOrder and hstmtLine) to identify the
statements on which to create result sets of sales orders and sales order line numbers. It later uses these
handles to identify which result set to fetch data from.

SQLHSTMT hstmtOrder, hstmtLine; // Statement handles.


SQLUINTEGER OrderID;
SQLINTEGER OrderIDInd = 0;
SQLRETURN rc;

// Prepare the statement that retrieves line number information.


SQLPrepare(hstmtLine, "SELECT * FROM Lines WHERE OrderID = ?", SQL_NTS);

// Bind OrderID to the parameter in the preceding statement.


SQLBindParameter(hstmtLine, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,
&OrderID, 0, &OrderIDInd);

// Bind the result sets for the Order table and the Lines table. Bind
// OrderID to the OrderID column in the Orders table. When each row is
// fetched, OrderID will contain the current order ID, which will then be
// passed as a parameter to the statement tofetch line number
// information. Code not shown.

// Create a result set of sales orders.


SQLExecDirect(hstmtOrder, "SELECT * FROM Orders", SQL_NTS);

// Fetch and display the sales order data. Code to check if rc equals
// SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.
while ((rc = SQLFetch(hstmtOrder)) != SQL_NO_DATA) {
// Display the sales order data. Code not shown.

// Create a result set of line numbers for the current sales order.
SQLExecute(hstmtLine);

// Fetch and display the sales order line number data. Code to check
// if rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.
while ((rc = SQLFetch(hstmtLine)) != SQL_NO_DATA) {
// Display the sales order line number data. Code not shown.
}

// Close the sales order line number result set.


SQLCloseCursor(hstmtLine);
}

// Close the sales order result set.


SQLCloseCursor(hstmtOrder);

Handles are meaningful only to the ODBC component that created them; that is, only the Driver Manager can
interpret Driver Manager handles and only a driver can interpret its own handles.
For example, suppose the driver in the preceding example allocates a structure to store information about a
statement and returns the pointer to this structure as the statement handle. When the application calls
SQLPrepare , it passes an SQL statement and the handle of the statement used for sales order line numbers.
The driver sends the SQL statement to the data source, which prepares it and returns an access plan identifier.
The driver uses the handle to find the structure in which to store this identifier.
Later, when the application calls SQLExecute to generate the result set of line numbers for a particular sales
order, it passes the same handle. The driver uses the handle to retrieve the access plan identifier from the
structure. It sends the identifier to the data source to tell it which plan to execute.
ODBC has two levels of handles: Driver Manager handles and driver handles. The application uses Driver
Manager handles when calling ODBC functions because it calls those functions in the Driver Manager. The Driver
Manager uses this handle to find the corresponding driver handle and uses the driver handle when calling the
function in the driver. For an example of how driver and Driver Manager handles are used, see Driver Manager's
Role in the Connection Process.
That there are two levels of handles is an artifact of the ODBC architecture; in most cases, it is not relevant to
either the application or driver. Although there is usually no reason to do so, it is possible for the application to
determine the driver handles by calling SQLGetInfo .
This section contains the following topics.
Environment Handles
Connection Handles
Statement Handles
Descriptor Handles
State Transitions
Environment Handles
4/27/2022 • 2 minutes to read • Edit Online

An environment is a global context in which to access data; associated with an environment is any information
that is global in nature, such as:
The environment's state
The current environment-level diagnostics
The handles of connections currently allocated on the environment
The current settings of each environment attribute
Within a piece of code that implements ODBC (the Driver Manager or a driver), an environment handle
identifies a structure to contain this information.
Environment handles are not frequently used in ODBC applications. They are always used in calls to
SQLDataSources and SQLDrivers and sometimes used in calls to SQL AllocHandle , SQLEndTran ,
SQLFreeHandle , SQLGetDiagField , and SQLGetDiagRec .
Each piece of code that implements ODBC (the Driver Manager or a driver) contains one or more environment
handles. For example, the Driver Manager maintains a separate environment handle for each application that is
connected to it. Environment handles are allocated with SQL AllocHandle and freed with SQLFreeHandle .
Connection Handles
4/27/2022 • 2 minutes to read • Edit Online

A connection consists of a driver and a data source. A connection handle identifies each connection. The
connection handle defines not only which driver to use but which data source to use with that driver. Within a
segment of code that implements ODBC (the Driver Manager or a driver), the connection handle identifies a
structure that contains connection information, such as the following:
The state of the connection
The current connection-level diagnostics
The handles of statements and descriptors currently allocated on the connection
The current settings of each connection attribute
ODBC does not prevent multiple simultaneous connections, if the driver supports them. Therefore, in a
particular ODBC environment, multiple connection handles might point to a variety of drivers and data sources,
to the same driver and a variety of data sources, or even to multiple connections to the same driver and data
source. Some drivers limit the number of active connections they support; the
SQL_MAX_DRIVER_CONNECTIONS option in SQLGetInfo specifies how many active connections a particular
driver supports.
Connection handles are primarily used when connecting to the data source (SQLConnect ,
SQLDriverConnect , or SQLBrowseConnect ), disconnecting from the data source (SQLDisconnect ), getting
information about the driver and data source (SQLGetInfo ), retrieving diagnostics (SQLGetDiagField and
SQLGetDiagRec ), and performing transactions (SQLEndTran ). They are also used when setting and getting
connection attributes (SQLSetConnectAttr and SQLGetConnectAttr ) and when getting the native format of
an SQL statement (SQLNativeSql ).
Connection handles are allocated with SQL AllocHandle and freed with SQLFreeHandle .
Statement Handles
4/27/2022 • 2 minutes to read • Edit Online

A statement is most easily thought of as an SQL statement, such as SELECT * FROM Employee . However, a
statement is more than just an SQL statement - it consists of all of the information associated with that SQL
statement, such as any result sets created by the statement and parameters used in the execution of the
statement. A statement does not even need to have an application-defined SQL statement. For example, when a
catalog function such as SQLTables is executed on a statement, it executes a predefined SQL statement that
returns a list of table names.
Each statement is identified by a statement handle. A statement is associated with a single connection, and there
can be multiple statements on that connection. Some drivers limit the number of active statements they
support; the SQL_MAX_CONCURRENT_ACTIVITIES option in SQLGetInfo specifies how many active statements
a driver supports on a single connection. A statement is defined to be active if it has results pending, where
results are either a result set or the count of rows affected by an INSERT , UPDATE , or DELETE statement, or
data is being sent with multiple calls to SQLPutData .
Within a piece of code that implements ODBC (the Driver Manager or a driver), the statement handle identifies a
structure that contains statement information, such as:
The statement's state
The current statement-level diagnostics
The addresses of the application variables bound to the statement's parameters and result set columns
The current settings of each statement attribute
Statement handles are used in most ODBC functions. Notably, they are used in the functions to bind parameters
and result set columns (SQLBindParameter and SQLBindCol ), prepare and execute statements
(SQLPrepare , SQLExecute , and SQLExecDirect ), retrieve metadata (SQLColAttribute and
SQLDescribeCol ), fetch results (SQLFetch ), and retrieve diagnostics (SQLGetDiagField and
SQLGetDiagRec ). They are also used in catalog functions (SQLColumns , SQLTables , and so on) and a
number of other functions.
Statement handles are allocated with SQL AllocHandle and freed with SQLFreeHandle .
Descriptor Handles
4/27/2022 • 2 minutes to read • Edit Online

A descriptor is a collection of metadata that describes the parameters of an SQL statement or the columns of a
result set, as seen by the application or driver (also known as the implementation). Thus, a descriptor can fill any
of four roles:
Application Parameter Descriptor (APD). Contains information about the application buffers bound
to the parameters in an SQL statement, such as their addresses, lengths, and C data types.
Implementation Parameter Descriptor (IPD). Contains information about the parameters in an SQL
statement, such as their SQL data types, lengths, and nullability.
Application Row Descriptor (ARD). Contains information about the application buffers bound to the
columns in a result set, such as their addresses, lengths, and C data types.
Implementation Row Descriptor (IRD). Contains information about the columns in a result set, such
as their SQL data types, lengths, and nullability.
Four descriptors (one filling each role) are allocated automatically when a statement is allocated. These are
known as automatically allocated descriptors and are always associated with that statement. Applications can
also allocate descriptors with SQL AllocHandle . These are known as explicitly allocated descriptors. They are
allocated on a connection and can be associated with one or more statements on that connection to fulfill the
role of an APD or ARD on those statements.
Most operations in ODBC can be performed without explicit use of descriptors by the application. However,
descriptors provide a convenient shortcut for some operations. For example, suppose an application wants to
insert data from two different sets of buffers. To use the first set of buffers, it would repeatedly call
SQLBindParameter to bind them to the parameters in an INSERT statement and then execute the statement.
To use the second set of buffers, it would repeat this process. Alternatively, it could set up bindings to the first set
of buffers in one descriptor and to the second set of buffers in another descriptor. To switch between the sets of
bindings, the application would simply call SQLSetStmtAttr and associate the correct descriptor with the
statement as the APD.
For more information about descriptors, see Types of Descriptors.
State Transitions
4/27/2022 • 2 minutes to read • Edit Online

ODBC defines discrete states for each environment, each connection, and each statement. For example, the
environment has three possible states: Unallocated (in which no environment is allocated), Allocated (in which
an environment is allocated but no connections are allocated), and Connection (in which an environment and
one or more connections are allocated). Connections have seven possible states; statements have 13 possible
states.
A particular item, as identified by its handle, moves from one state to another when the application calls a
certain function or functions and passes the handle to that item. Such movement is called a state transition. For
example, allocating an environment handle with SQL AllocHandle moves the environment from Unallocated to
Allocated, and freeing that handle with SQLFreeHandle returns it from Allocated to Unallocated. ODBC defines
a limited number of legal state transitions, which is another way of saying that functions must be called in a
certain order.
Some functions, such as SQLGetConnectAttr , do not affect state at all. Other functions affect the state of a
single item. For example, SQLDisconnect moves a connection from a Connection state to an Allocated state.
Finally, some functions affect the state of more than one item. For example, allocating a connection handle with
SQL AllocHandle moves a connection from an Unallocated to an Allocated state and moves the environment
from an Allocated to a Connection state.
If an application calls a function out of order, the function returns a state transition error. For example, if an
environment is in a Connection state and the application calls SQLFreeHandle with that environment handle,
SQLFreeHandle returns SQLSTATE HY010 (Function sequence error), because it can be called only when the
environment is in an Allocated state. By defining this as an invalid state transition, ODBC prevents the
application from freeing the environment while there are active connections.
Some state transitions are inherent in the design of ODBC. For example, it is not possible to allocate a
connection handle without first allocating an environment handle, because the function that allocates a
connection handle requires an environment handle. Other state transitions are enforced by the Driver Manager
and the drivers. For example, SQLExecute executes a prepared statement. If the statement handle passed to it is
not in a Prepared state, SQLExecute returns SQLSTATE HY010 (Function sequence error).
From the application's point of view, state transitions are usually straightforward: Legal state transitions tend to
go hand-in-hand with the flow of a well-written application. State transitions are more complex for the Driver
Manager and the drivers because they must track the state of the environment, each connection, and each
statement. Most of this work is done by the Driver Manager; most of the work that must be done by drivers
occurs with statements with pending results.
Parts 1 and 2 of this manual ("Introduction to ODBC" and "Developing Applications and Drivers") tend not to
explicitly mention state transitions. Instead, they describe the order in which functions must be called. For
example, "Executing Statements" states that a statement must be prepared with SQLPrepare before it can be
executed with SQLExecute . For a complete description of states and state transitions, including which
transitions are checked by the Driver Manager and which must be checked by drivers, see Appendix B: ODBC
State Transition Tables.
Buffers
4/27/2022 • 2 minutes to read • Edit Online

A buffer is any piece of application memory used to pass data between the application and the driver. For
example, application buffers can be associated with, or bound to, result set columns with SQLBindCol . As each
row is fetched, the data is returned for each column in these buffers. Input buffers are used to pass data from
the application to the driver; output buffers are used to return data from the driver to the application.

NOTE
If an ODBC function returns SQL_ERROR, the contents of any output arguments to that function are undefined.

This discussion concerns itself primarily with buffers of indeterminate type. The addresses of these buffers
appear as arguments of type SQLPOINTER, such as the TargetValuePtr argument in SQLBindCol . However,
some of the items discussed here, such as the arguments used with buffers, also apply to arguments used to
pass strings to the driver, such as the TableName argument in SQLTables .
These buffers usually come in pairs. Data buffers are used to pass the data itself, while length/indicator buffers
are used to pass the length of the data in the data buffer or a special value such as SQL_NULL_DATA, which
indicates that the data is NULL. The length of the data in a data buffer is different from the length of the data
buffer itself. The following illustration shows the relationship between the data buffer and the length/indicator
buffer.

A length/indicator buffer is required whenever the data buffer contains variable-length data, such as character
or binary data. If the data buffer contains fixed-length data, such as an integer or date structure, a
length/indicator buffer is needed only to pass indicator values because the length of the data is already known.
If an application uses a length/indicator buffer with fixed-length data, the driver ignores any lengths passed in it.
The length of both the data buffer and the data it contains is measured in bytes, as opposed to characters. This
distinction is unimportant for programs that use ANSI strings because lengths in bytes and characters are the
same.
When the data buffer represents a driver-defined descriptor field, diagnostic field, or attribute, the application
should indicate to the Driver Manager the nature of the function argument that indicates the value for the field
or attribute. The application does this by setting the length argument in any function call that sets the field or
attribute to one of the following values. (The same is true for functions that retrieve the values of the field or
attribute, with the exception that the argument points to the values that for the setting function are in the
argument itself.)
If the function argument that indicates the value for the field or attribute is a pointer to a character string,
the length argument is the length of the string or SQL_NTS.
If the function argument that indicates the value for the field or attribute is a pointer to a binary buffer,
the application places the result of the SQL_LEN_BINARY_ATTR(length) macro in the length argument.
This places a negative value in the length argument.
If the function argument that indicates the value for the field or attribute is a pointer to a value other than
a character string or a binary string, the length argument should have the value SQL_IS_POINTER.
If the function argument that indicates the value for the field or attribute contains a fixed-length value, the
length argument is SQL_IS_INTEGER, SQL_IS_UINTEGER, SQL_IS_SMALLINT, or SQL_ISI_USMALLINT, as
appropriate.
This section contains the following topics.
Deferred Buffers
Allocating and Freeing Buffers
Using Data Buffers
Deferred Buffers
4/27/2022 • 2 minutes to read • Edit Online

A deferred buffer is one whose value is used at some time after it is specified in a function call. For example,
SQLBindParameter is used to associate, or bind, a data buffer with a parameter in an SQL statement. The
application specifies the number of the parameter and passes the address, byte length, and type of the buffer.
The driver saves this information but does not examine the contents of the buffer. Later, when the application
executes the statement, the driver retrieves the information and uses it to retrieve the parameter data and send
it to the data source. Therefore, the input of data in the buffer is deferred. Because deferred buffers are specified
in one function and used in another, it is an application programming error to free a deferred buffer while the
driver still expects it to exist; for more information, see Allocating and Freeing Buffers, later in this section.
Both input and output buffers can be deferred. The following table summarizes the uses of deferred buffers.
Note that deferred buffers bound to result set columns are specified with SQLBindCol , and deferred buffers
bound to SQL statement parameters are specified with SQLBindParameter .

B UF F ER USE TYPE SP EC IF IED W IT H USED B Y

Sending data for input Deferred input SQLBindParameter SQLExecute


parameters SQLExecDirect

Sending data to update or Deferred input SQLBindCol SQLSetPos


insert a row in a result set

Returning data for output Deferred output SQLBindParameter SQLExecute


and input/output SQLExecDirect
parameters

Returning result set data Deferred output SQLBindCol SQLFetch


SQLFetchScroll
SQLSetPos
Allocating and Freeing Buffers
4/27/2022 • 2 minutes to read • Edit Online

All buffers are allocated and freed by the application. If a buffer is not deferred, it need only exist for the duration
of the call to a function. For example, SQLGetInfo returns the value associated with a particular option in the
buffer pointed to by the InfoValuePtr argument. This buffer can be freed immediately after the call to
SQLGetInfo , as shown in the following code example:

SQLSMALLINT InfoValueLen;
SQLCHAR * InfoValuePtr = malloc(50); // Allocate InfoValuePtr.

SQLGetInfo(hdbc, SQL_DBMS_NAME, (SQLPOINTER)InfoValuePtr, 50,


&InfoValueLen);

free(InfoValuePtr); // OK to free InfoValuePtr.

Because deferred buffers are specified in one function and used in another, it is an application programming
error to free a deferred buffer while the driver still expects it to exist. For example, the address of the *ValuePtr
buffer is passed to SQLBindCol for later use by SQLFetch . This buffer cannot be freed until the column is
unbound, such as with a call to SQLBindCol or SQLFreeStmt as shown in the following code example:

SQLRETURN rc;
SQLINTEGER ValueLenOrInd;
SQLHSTMT hstmt;

// Allocate ValuePtr
SQLCHAR * ValuePtr = malloc(50);

// Bind ValuePtr to column 1. It is an error to free ValuePtr here.


SQLBindCol(hstmt, 1, SQL_C_CHAR, ValuePtr, 50, &ValueLenOrInd);

// Fetch each row of data and place the value for column 1 in *ValuePtr.
// Code to check if rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO
// not shown.
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {
// It is an error to free ValuePtr here.
}

// Unbind ValuePtr from column 1. It is now OK to free ValuePtr.


SQLFreeStmt(hstmt, SQL_UNBIND);
free(ValuePtr);

Such an error is easily made by declaring the buffer locally in a function; the buffer is freed when the application
leaves the function. For example, the following code causes undefined and probably fatal behavior in the driver:
SQLRETURN rc;
SQLHSTMT hstmt;

BindAColumn(hstmt);

// Fetch each row of data and try to place the value for column 1 in
// *ValuePtr. Because ValuePtr has been freed, the behavior is undefined
// and probably fatal. Code to check if rc equals SQL_ERROR or
// SQL_SUCCESS_WITH_INFO not shown.
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {}

.
.
.

void BindAColumn(SQLHSTMT hstmt) // WARNING! This function won't work!


{
// Declare ValuePtr locally.
SQLCHAR ValuePtr[50];
SQLINTEGER ValueLenOrInd;

// Bind rgbValue to column.


SQLBindCol(hstmt, 1, SQL_C_CHAR, ValuePtr, sizeof(ValuePtr),
&ValueLenOrInd);

// ValuePtr is freed when BindAColumn exits.


}
Using Data Buffers
4/27/2022 • 2 minutes to read • Edit Online

Data buffers are described by three pieces of information: their type, address, and byte length. Whenever a
function needs one of these pieces of information and does not already know it, it has an argument with which
the application passes it.
This section contains the following topics.
Data Buffer Type
Data Buffer Address
Data Buffer Length
Data Buffer Type
4/27/2022 • 2 minutes to read • Edit Online

The C data type of a buffer is specified by the application. With a single variable, this occurs when the application
allocates the variable. With generic memory - that is, memory pointed to by a pointer of type void - this occurs
when the application casts the memory to a particular type. The driver discovers this type in two ways:
Data buffer type argument. Buffers used to transfer parameter values and result set data, such as the
buffer bound with TargetValuePtr in SQLBindCol , usually have an associated type argument, such as the
TargetType argument in SQLBindCol . In this argument, the application passes the C type identifier that
corresponds to the type of the buffer. For example, in the following call to SQLBindCol , the value
SQL_C_TYPE_DATE tells the driver that the Date buffer is an SQL_DATE_STRUCT:

SQL_DATE_STRUCT Date;
SQLINTEGER DateInd;
SQLBindCol(hstmt, 1, SQL_C_TYPE_DATE, &Date, 0, &DateInd);

For more information about type identifiers, see the Data Types in ODBC section, later in this section.
Predefined type. Buffers used to send and retrieve options or attributes, such as the buffer pointed to
by the InfoValuePtr argument in SQLGetInfo , have a fixed type that depends on the option specified. The
driver assumes that the data buffer is of this type; it is the application's responsibility to allocate a buffer
of this type. For example, in the following call to SQLGetInfo , the driver assumes the buffer is a 32-bit
integer because this is what the SQL_STRING_FUNCTIONS option requires:

SQLUINTEGER StringFuncs;
SQLGetInfo(hdbc, SQL_STRING_FUNCTIONS, (SQLPOINTER) &StringFuncs, 0,
NULL);

The driver uses the C data type to interpret the data in the buffer.
Data Buffer Address
4/27/2022 • 2 minutes to read • Edit Online

The application passes the address of the data buffer to the driver in an argument, often named ValuePtr or a
similar name. For example, in the following call to SQLBindCol , the application specifies the address of the Date
variable:

SQL_DATE_STRUCT Date;
SQLINTEGER DateInd;
SQLBindCol(hstmt, 1, SQL_C_TYPE_DATE, &dsDate, 0, &DateInd);

As mentioned in the Allocating and Freeing Buffers section, the address of a deferred buffer must remain valid
until the buffer is unbound.
Unless it is specifically prohibited, the address of a data buffer can be a null pointer. For buffers used to send
data to the driver, this causes the driver to ignore the information normally contained in the buffer. For buffers
used to retrieve data from the driver, this causes the driver to not return a value. In both cases, the driver ignores
the corresponding data buffer length argument.
Data Buffer Length
4/27/2022 • 2 minutes to read • Edit Online

The application passes the byte length of the data buffer to the driver in an argument, named BufferLength or a
similar name. For example, in the following call to SQLBindCol , the application specifies the length of the
ValuePtr buffer (sizeof( ValuePtr ) ):

SQLCHAR ValuePtr[50];
SQLINTEGER ValueLenOrInd;
SQLBindCol(hstmt, 1, SQL_C_CHAR, ValuePtr, sizeof(ValuePtr), &ValueLenOrInd);

A driver will always return the number of bytes, not the number of characters, in the buffer length argument of
any function that has an output string argument.
Data buffer lengths are required only for output buffers; the driver uses them to avoid writing past the end of
the buffer. However, the driver checks the data buffer length only when the buffer contains variable-length data,
such as character or binary data. If the buffer contains fixed-length data, such as an integer or date structure, the
driver ignores the data buffer length and assumes the buffer is large enough to hold the data; that is, it never
truncates fixed-length data. It is therefore important for the application to allocate a large enough buffer for
fixed-length data.
When a truncation of non-data output strings occurs (such as the cursor name returned for
SQLGetCursorName ), the returned length in the buffer length argument is the maximum character length
possible.
Data buffer lengths are not required for input buffers because the driver does not write to these buffers.
This section contains the following topics.
Using Length/Indicator Values
Data Length, Buffer Length, and Truncation
Character Data and C Strings
Using Length and Indicator Values
4/27/2022 • 3 minutes to read • Edit Online

The length/indicator buffer is used to pass the byte length of the data in the data buffer or a special indicator
such as SQL_NULL_DATA, which indicates that the data is NULL. Depending on the function in which it is used, a
length/indicator buffer is defined to be an SQLINTEGER or an SQLSMALLINT. Therefore, a single argument is
needed to describe it. If the data buffer is a nondeferred input buffer, this argument contains the byte length of
the data itself or an indicator value. It is often named StrLen_or_Ind or a similar name. For example, the
following code calls SQLPutData to pass a buffer full of data; the byte length (ValueLen) is passed directly
because the data buffer (ValuePtr) is an input buffer.

SQLCHAR ValuePtr[50];
SQLINTEGER ValueLen;

// Call local function to place data in ValuePtr. In ValueLen, return the


// number of bytes of data placed in ValuePtr. If there is not enough
// data, this will be less than 50.
FillBuffer(ValuePtr, sizeof(ValuePtr), &ValueLen);

// Call SQLPutData to send the data to the driver.


SQLPutData(hstmt, ValuePtr, ValueLen);

If the data buffer is a deferred input buffer, a nondeferred output buffer, or an output buffer, the argument
contains the address of the length/indicator buffer. It is often named StrLen_or_IndPtr or a similar name. For
example, the following code calls SQLGetData to retrieve a buffer full of data; the byte length is returned to the
application in the length/indicator buffer (ValueLenOrInd), whose address is passed to SQLGetData because
the corresponding data buffer (ValuePtr) is a nondeferred output buffer.

SQLCHAR ValuePtr[50];
SQLINTEGER ValueLenOrInd;
SQLGetData(hstmt, 1, SQL_C_CHAR, ValuePtr, sizeof(ValuePtr), &ValueLenOrInd);

Unless it is specifically prohibited, a length/indicator buffer argument can be 0 (if nondeferred input) or a null
pointer (if output or deferred input). For input buffers, this causes the driver to ignore the byte length of the
data. This returns an error when passing variable-length data but is common when passing non-null, fixed-
length data, because neither a length nor an indicator value is needed. For output buffers, this causes the driver
to not return the byte length of the data or an indicator value. This is an error if the data returned by the driver is
NULL but is common when retrieving fixed-length, non-nullable data, because neither a length nor an indicator
value is needed.
As when the address of a deferred data buffer is passed to the driver, the address of a deferred length/indicator
buffer must remain valid until the buffer is unbound.
The following lengths are valid as length/indicator values:
n, where n > 0.
0.
SQL_NTS. A string sent to the driver in the corresponding data buffer is null-terminated; this is a
convenient way for C programmers to pass strings without having to calculate their byte length. This
value is legal only when the application sends data to the driver. When the driver returns data to the
application, it always returns the actual byte length of the data.
The following values are valid as length/indicator values. SQL_NULL_DATA is stored in the
SQL_DESC_INDICATOR_PTR descriptor field; all other values are stored in the SQL_DESC_OCTET_LENGTH_PTR
descriptor field.
SQL_NULL_DATA. The data is a NULL data value, and the value in the corresponding data buffer is
ignored. This value is legal only for SQL data sent to or retrieved from the driver.
SQL_DATA_AT_EXEC. The data buffer does not contain any data. Instead, the data will be sent with
SQLPutData when the statement is executed or when SQLBulkOperations or SQLSetPos is called.
This value is legal only for SQL data sent to the driver. For more information, see SQLBindParameter,
SQLBulkOperations, and SQLSetPos.
Result of the SQL_LEN_DATA_AT_EXEC(length) macro. This value is similar to SQL_DATA_AT_EXEC. For
more information, see Sending Long Data.
SQL_NO_TOTAL. The driver cannot determine the number of bytes of long data still available to return in
an output buffer. This value is legal only for SQL data retrieved from the driver.
SQL_DEFAULT_PARAM. A procedure is to use the default value of an input parameter in a procedure
instead of the value in the corresponding data buffer.
SQL_COLUMN_IGNORE. SQLBulkOperations or SQLSetPos is to ignore the value in the data buffer.
When updating a row of data by a call to SQLBulkOperations or SQLSetPos, the column value is not
changed. When inserting a new row of data by a call to SQLBulkOperations , the column value is set to
its default or, if the column does not have a default, to NULL.
Data Length, Buffer Length, and Truncation
4/27/2022 • 2 minutes to read • Edit Online

The data length is the byte length of the data as it would be stored in the application's data buffer, not as it is
stored in the data source. This distinction is important because the data is often stored in different types in the
data buffer than in the data source. So for data being sent to the data source, this is the byte length of the data
before conversion to the data source's type. For data being retrieved from the data source, this is the byte length
of the data after conversion to the data buffer's type and before any truncation is done.
For fixed-length data, such as an integer or a date structure, the byte length of the data is always the size of the
data type. In general, applications allocate a data buffer that is the size of the data type. If the application
allocates a smaller buffer, the consequences are undefined because the driver assumes the data buffer is the size
of the data type and does not truncate the data to fit into a smaller buffer. If the application allocates a larger
buffer, the extra space is never used.
For variable-length data, such as character or binary data, it is important to recognize that the byte length of the
data is separate from and often different than the byte length of the buffer. The relation of these two lengths is
described in the Buffers section. If the byte length of the data is greater than the byte length of the buffer, the
driver truncates fetched data to the byte length of the buffer and returns SQL_SUCCESS_WITH_INFO with
SQLSTATE 01004 (Data truncated). However, the returned byte length is the length of the untruncated data.
For example, suppose an application allocates 50 bytes for a binary data buffer. If the driver has 10 bytes of
binary data to return, it returns those 10 bytes in the buffer. The byte length of the data is 10, and the byte
length of the buffer is 50. If the driver has 60 bytes of binary data to return, it truncates the data to 50 bytes,
returns those bytes in the buffer, and returns SQL_SUCCESS_WITH_INFO. The byte length of the data is 60 (the
length before truncation), and the byte length of the buffer is still 50.
A diagnostic record is created for each column that is truncated. Because it takes time for the driver to create
these records and for the application to process them, truncation can degrade performance. Usually, an
application can avoid this problem by allocating large enough buffers, although this might not be possible when
working with long data. When data truncation occurs, the application can sometimes allocate a larger buffer and
refetch the data; this is not true in all cases. If truncation occurs while getting data with calls to SQLGetData , the
application need not call SQLGetData for data that has already been returned; for more information, see
Getting Long Data.
Character Data and C Strings
4/27/2022 • 2 minutes to read • Edit Online

Input parameters that refer to variable-length character data (such as column names, dynamic parameters, and
string attribute values) have an associated length parameter. If the application terminates strings with the null
character, as is typical in C, it provides as an argument either the length in bytes of the string (not including the
null-terminator) or SQL_NTS (Null-Terminated String). A non-negative length argument specifies the actual
length of the associated string. The length argument may be 0 to specify a zero-length string, which is distinct
from a NULL value. The negative value SQL_NTS directs the driver to determine the length of the string by
locating the null-termination character.
When character data is returned from the driver to the application, the driver must always null-terminate it. This
gives the application the choice of whether to handle the data as a string or a character array. If the application
buffer is not large enough to return all of the character data, the driver truncates it to the byte length of the
buffer less the number of bytes required by the null-termination character, null-terminates the truncated data,
and stores it in the buffer. Therefore, applications must always allocate extra space for the null-termination
character in buffers used to retrieve character data. For example, a 51-byte buffer is needed to retrieve 50
characters of data.
Special care must be taken by both the application and the driver when sending or retrieving long character
data in parts with SQLPutData or SQLGetData . If the data is passed as a series of null-terminated strings, the
null-termination characters on these strings must be stripped before the data can be reassembled.
A number of ODBC programmers have confused character data and C strings. That this has occurred is an
artifact of using the C language when defining ODBC functions. If an ODBC driver or application uses another
language - remember that ODBC is language-independent - this confusion is less likely to arise.
When C strings are used to hold character data, the null-termination character is not considered to be part of
the data and is not counted as part of its byte length. For example, the character data "ABC" can be held as the C
string "ABC\0" or the character array {'A', 'B', 'C'}. The byte length of the data is 3, whether or not it is treated as
a string or a character array.
Although applications and drivers commonly use C strings (null-terminated arrays of characters) to hold
character data, there is no requirement to do this. In C, character data can also be treated as an array of
characters (without null-termination) and its byte length passed separately in the length/indicator buffer.
Because character data can be held in a non-null-terminated array and its byte length passed separately, it is
possible to embed null characters in character data. However, the behavior of ODBC functions in this case is
undefined and it is driver-specific whether a driver handles this correctly. Thus, interoperable applications should
always handle character data that can contain embedded null characters as binary data.
Data Types in ODBC
4/27/2022 • 2 minutes to read • Edit Online

ODBC uses two sets of data types: SQL data types and C data types. SQL data types are used in the data source,
and C data types are used in C code in the application.
This section contains the following topic.
Type Identifiers
SQL Data Types in ODBC
C Data Types in ODBC
Data Type Conversions
Type Identifiers
4/27/2022 • 2 minutes to read • Edit Online

To describe SQL and C data types, ODBC defines two sets of type identifiers. A type identifier describes the type
of an SQL column or a C buffer. It is a #define value and is generally passed as a function argument or returned
in metadata.
For example, the following call to SQLBindParameter binds a variable of type SQL_DATE_STRUCT to a date
parameter in an SQL statement. The C type identifier SQL_C_TYPE_DATE specifies the type of the Date variable,
and the SQL type identifier SQL_TYPE_DATE specifies the type of the dynamic parameter.

SQL_DATE_STRUCT Date;
SQLINTEGER DateInd = 0;
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 0, 0,
&Date, 0, &DateInd);
SQL Data Types in ODBC
4/27/2022 • 2 minutes to read • Edit Online

SQL data types are the types in which data is stored in the data source.
This section contains the following topics.
SQL Type Identifiers
Retrieving Data Type Information with SQLGetTypeInfo
SQL Type Identifiers
4/27/2022 • 2 minutes to read • Edit Online

Each data source defines its own SQL data types. ODBC defines type identifiers and describes the general
characteristics of the SQL data types that might be mapped to each type identifier. It is driver-specific how each
data type in the underlying data source is mapped to an SQL type identifier of ODBC.
For example, SQL_CHAR is the type identifier for a character column with a fixed length, typically between 1 and
254 characters. These characteristics correspond to the CHAR data type found in many SQL data sources. Thus,
when an application discovers that the type identifier for a column is SQL_CHAR, it can assume it is probably
dealing with a CHAR column. However, it should still check the byte length of the column before assuming it is
between 1 and 254 characters; the driver for a non-SQL data source, for example, might map a fixed-length
character column of 500 characters to SQL_CHAR or SQL_LONGVARCHAR, because neither is an exact match.
ODBC defines a wide variety of SQL type identifiers. However, the driver is not required to use all of these
identifiers. Instead, it uses only those identifiers it needs to expose the SQL data types supported by the
underlying data source. If the underlying data source supports SQL data types to which no type identifier
corresponds, the driver can define additional type identifiers. For more information, see Driver-Specific Data
Types, Descriptor Types, Information Types, Diagnostic Types, and Attributes.
For a complete description of SQL type identifiers, see C Data Types in Appendix D: Data Types.
Retrieving Data Type Information with
SQLGetTypeInfo
4/27/2022 • 2 minutes to read • Edit Online

Because the mappings from underlying SQL data types to ODBC type identifiers are approximate, ODBC
provides a function (SQLGetTypeInfo ) through which a driver can completely describe each SQL data type in
the data source. This function returns a result set, each row of which describes the characteristics of a single data
type, such as name, type identifier, precision, scale, and nullability.
This information generally is used by generic applications that allow the user to create and alter tables. Such
applications call SQLGetTypeInfo to retrieve the data type information and then present some or all of it to the
user. Such applications need to be aware of two things:
More than one SQL data type can map to a single type identifier, which can make it difficult to determine
which data type to use. To solve this, the result set is ordered first by type identifier and second by
closeness to the type identifier's definition. In addition, data source-defined data types take precedence
over user-defined data types. For example, suppose that a data source defines the INTEGER and
COUNTER data types to be the same except that COUNTER is auto-incrementing. Suppose also that the
user-defined type WHOLENUM is a synonym of INTEGER. Each of these types maps to SQL_INTEGER. In
the SQLGetTypeInfo result set, INTEGER appears first, followed by WHOLENUM and then COUNTER.
WHOLENUM appears after INTEGER because it is user-defined, but before COUNTER because it more
closely matches the definition of the SQL_INTEGER type identifier.
ODBC does not define data type names for use in CREATE TABLE and ALTER TABLE statements. Instead,
the application should use the name returned in the TYPE_NAME column of the result set returned by
SQLGetTypeInfo . The reason for this is that although most of SQL does not vary much across DBMSs,
data type names vary tremendously. Rather than forcing drivers to parse SQL statements and replace
standard data type names with DBMS-specific data type names, ODBC requires applications to use the
DBMS-specific names in the first place.
Note that SQLGetTypeInfo does not necessarily describe all of the data types an application can encounter. In
particular, result sets might contain data types not directly supported by the data source. For example, the data
types of the columns in result sets returned by catalog functions are defined by ODBC and these data types
might not be supported by the data source. To determine the characteristics of the data types in a result set, an
application calls SQLColAttribute .
C Data Types in ODBC
4/27/2022 • 2 minutes to read • Edit Online

ODBC defines the C data types that are used by application variables and their corresponding type identifiers.
These are used by the buffers that are bound to result set columns and statement parameters. For example,
suppose an application wants to retrieve data from a result set column in character format. It declares a variable
with the SQLCHAR * data type and binds this variable to the result set column with a type identifier of
SQL_C_CHAR. For a complete list of C data types and type identifiers, see Appendix D: Data Types.
ODBC also defines a default mapping from each SQL data type to a C data type. For example, a 2-byte integer in
the data source is mapped to a 2-byte integer in the application. To use the default mapping, an application
specifies the SQL_C_DEFAULT type identifier. However, use of this identifier is discouraged for interoperability
reasons.
All integer C data types defined in ODBC 1.x were signed. Unsigned C data types and their corresponding type
identifiers were added in ODBC 2.0. Because of this, applications and drivers need to be particularly careful
when dealing with 1.x versions.

C Data Type Extensibility


In ODBC 3.8, you can specify driver-specific C data types. This enables you to bind a SQL type as a driver-specific
C type in ODBC applications when you call SQLBindCol, SQLGetData, or SQLBindParameter. This can be useful
for supporting new server types, because existing C data types might not correctly represent the new server
data types. Using driver-specific C types can increase the number of conversions that drivers can perform.
For example, suppose a database management system (DBMS) introduced a new SQL type, DATETIMEOFFSET ,
to represent the date and time with time zone information. There would be no specific C type in ODBC that
corresponded to DATETIMEOFFSET . An application would have to bind DATETIMEOFFSET as SQL_C_BINARY
and cast it to a user-defined data type. Beginning in ODBC 3.8 with C data type extensibility, a driver can define a
new corresponding C type. For example, for the new SQL type DATETIMEOFFSET, the driver can define a new
corresponding C type such as SQL_C_DATETIMEOFFSET. Then, an application can bind the new SQL type as a
driver-specific C type.
A C data type is defined in the driver as follows:
The ODBC compliance level for an application, ODBC driver, and Driver Manager is 3.8 (or higher).
The data range of a driver-specific C type is between 0x4000 and 0x7FFF.
The driver defines the structure of the data corresponding to the C type. This can be done in the driver-
specific SDK.
The driver manager will not validate a C type defined in the range of 0x4000 and 0x7FFF; the driver will perform
the validation and any data type conversion. But if the data range of a C type passed to the driver manager is
between 0x0000 and 0x3FFF or between 0x8000 and 0xFFFF, the driver manager will validate the C data type.

NOTE
Driver-specific C data types should be described in the driver documentation.

To specify an ODBC compliance level of 3.8, an application calls SQLSetEnvAttr with the
SQL_ATTR_ODBC_VERSION attribute set to SQL_OV_ODBC3_80 . To determine the version of the driver, an
application calls SQLGetInfo with SQL_DRIVER_ODBC_VER.
For more information about ODBC 3.8, see What's New in ODBC 3.8.

See Also
C Data Types
Data Type Conversions
4/27/2022 • 2 minutes to read • Edit Online

Data can be converted from one type to another at one of four times: when data is transferred from one
application variable to another (C to C), when data in an application variable is sent to a statement parameter (C
to SQL), when data in a result set column is returned in an application variable (SQL to C), and when data is
transferred from one data source column to another (SQL to SQL).
Any conversion that occurs when data is transferred from one application variable to another is outside the
scope of this document.
When an application binds a variable to a result set column or statement parameter, the application implicitly
specifies a data type conversion in its choice of the data type of the application variable. For example, suppose a
column contains integer data. If the application binds an integer variable to the column, it specifies that no
conversion be done; if the application binds a character variable to the column, it specifies that the data be
converted from integer to character.
ODBC defines how data is converted between each SQL and C data type. Basically, ODBC supports all
reasonable conversions, such as character to integer and integer to float, and does not support ill-defined
conversions, such as float to date. Drivers are required to support all conversions for each SQL data type they
support. For a complete list of conversions between SQL and C data types, see Converting Data from SQL to C
Data Types and Converting Data from C to SQL Data Types in Appendix D: Data Types.
ODBC also defines a scalar function for converting data from one SQL data type to another. The CONVERT
scalar function is mapped by the driver to the underlying scalar function or functions defined to perform
conversions in the data source. Because this function is mapped to DBMS-specific functions, ODBC does not
define how these conversions work or what conversions must be supported. An application discovers what
conversions are supported by a particular driver and data source through the SQL_CONVERT options in
SQLGetInfo . For more information about the CONVERT scalar function, see Escape Sequences in ODBC and
Explicit Data Type Conversion Function.
Conformance Levels
4/27/2022 • 2 minutes to read • Edit Online

ODBC drivers give the application access to diverse data sources. Each driver lets the application determine at
run time what ODBC capabilities and what SQL grammar the driver and each data source supports. This is not a
requirement of applications designed to work with a single driver or a small, known set of drivers, because these
applications can simply be written to the capabilities of that driver or drivers. To help applications discover driver
and data source capabilities, two areas of conformance are available: the ODBC interface and SQL grammar.
This section contains the following topics.
Interface Conformance Levels
SQL Conformance Levels
Interface Conformance Levels
4/27/2022 • 2 minutes to read • Edit Online

The purpose of leveling is to inform the application what features are available to it from the driver. A leveling
scheme based on functions does not sufficiently achieve this goal. In ODBC 3.x, drivers are classified based on
the features they possess. Supporting the feature can include supporting the function; it can also include
supporting a descriptor field, a statement attribute, a "Y" value for an information type returned by SQLGetInfo ,
and so on.
To simplify specification of interface conformance, ODBC defines three conformance levels. To meet a particular
conformance level, a driver must satisfy all of the requirements of that conformance level. Conformance with a
given level implies complete conformance with all lower levels.
Conformance levels do not always divide neatly into support for a specific list of ODBC functions, but specify
supported features as listed in the following sections. To provide support for a feature, a driver must support
some or all forms of calls to certain ODBC functions (for more information, see Function Conformance), setting
certain attributes (see Attribute Conformance), and certain descriptor fields (see Descriptor Field Conformance).
The application discovers a driver's interface conformance level by connecting to a data source and calling
SQLGetInfo with the SQL_ODBC_INTERFACE_CONFORMANCE option.
Drivers are free to implement features beyond the level to which they claim complete conformance. Applications
discover any such additional capabilities by calling SQLGetFunctions (to determine which ODBC functions are
present) and SQLGetInfo (to query various other ODBC capabilities).
There are three ODBC interface conformance levels: Core, Level 1, and Level 2.

NOTE
These conformance levels have different requirements than the ODBC API conformance levels of the same name in ODBC
2*.x*. In particular, all the features implied by ODBC 2*.x* API conformance Level 1 are now part of the Core interface
conformance level. As a result, many ODBC drivers may report Core-level interface conformance.

This section contains the following topics.


Core Interface Conformance
Level 1 Interface Conformance
Level 2 Interface Conformance
Function Conformance
Attribute Conformance
Descriptor Field Conformance
Core Interface Conformance
4/27/2022 • 3 minutes to read • Edit Online

All ODBC drivers must exhibit at least Core-level interface conformance. Because the features in the Core level
are those required by most generic interoperable applications, the driver can work with such applications. The
features in the Core level also correspond to the features defined in the ISO CLI specification and to the
nonoptional features defined in the Open Group CLI specification. A Core-level interface-conformant ODBC
driver allows the application to do all of the following:
Allocate and free all types of handles, by calling SQL AllocHandle and SQLFreeHandle .
Use all forms of the SQLFreeStmt function.
Bind result set columns, by calling SQLBindCol .
Handle dynamic parameters, including arrays of parameters, in the input direction only, by calling
SQLBindParameter and SQLNumParams . (Parameters in the output direction are feature 203 in Level
2 Interface Conformance.)
Specify a bind offset.
Use the data-at-execution dialog, involving calls to SQLParamData and SQLPutData .
Manage cursors and cursor names, by calling SQLCloseCursor , SQLGetCursorName , and
SQLSetCursorName .
Gain access to the description (metadata) of result sets, by calling SQLColAttribute , SQLDescribeCol ,
SQLNumResultCols , and SQLRowCount . (Use of these functions on column number 0 to retrieve
bookmark metadata is feature 204 in Level 2 Interface Conformance.)
Query the data dictionary, by calling the catalog functions SQLColumns , SQLGetTypeInfo ,
SQLStatistics , and SQLTables .
The driver is not required to support multipart names of database tables and views. (For more
information, see feature 101 in Level 1 Interface Conformance and feature 201 in Level 2 Interface
Conformance.) However, certain features of the SQL-92 specification, such as column qualification and
names of indexes, are syntactically comparable to multipart naming. The present list of ODBC features is
not intended to introduce new options into these aspects of SQL-92.
Manage data sources and connections, by calling SQLConnect , SQLDataSources , SQLDisconnect ,
and SQLDriverConnect . Obtain information on drivers, no matter which ODBC level they support, by
calling SQLDrivers .
Prepare and execute SQL statements, by calling SQLExecDirect , SQLExecute , and SQLPrepare .
Fetch one row of a result set or multiple rows, in the forward direction only, by calling SQLFetch or by
calling SQLFetchScroll with the FetchOrientation argument set to SQL_FETCH_NEXT.
Obtain an unbound column in parts, by calling SQLGetData .
Obtain current values of all attributes, by calling SQLGetConnectAttr , SQLGetEnvAttr , and
SQLGetStmtAttr , and set all attributes to their default values and set certain attributes to nondefault
values by calling SQLSetConnectAttr , SQLSetEnvAttr , and SQLSetStmtAttr .
Manipulate certain fields of descriptors, by calling SQLCopyDesc , SQLGetDescField , SQLGetDescRec ,
SQLSetDescField , and SQLSetDescRec .
Obtain diagnostic information, by calling SQLGetDiagField and SQLGetDiagRec .
Detect driver capabilities, by calling SQLGetFunctions and SQLGetInfo . Also, detect the result of any
text substitutions made to an SQL statement before it is sent to the data source, by calling
SQLNativeSql .
Use the syntax of SQLEndTran to commit a transaction. A Core-level driver need not support true
transactions; therefore, the application cannot specify SQL_ROLLBACK nor SQL_AUTOCOMMIT_OFF for
the SQL_ATTR_AUTOCOMMIT connection attribute. (For more information, see feature 109 in Level 2
Interface Conformance.)
Call SQLCancel to cancel the data-at-execution dialog and, in multithread environments, to cancel an
ODBC function executing in another thread. Core-level interface conformance does not mandate support
for asynchronous execution of functions, nor the use of SQLCancel to cancel an ODBC function
executing asynchronously. Neither the platform nor the ODBC driver need be multithread for the driver
to conduct independent activities at the same time. However, in multithread environments, the ODBC
driver must be thread-safe. Serialization of requests from the application is a conformant way to
implement this specification, even though it might create serious performance problems.
Obtain the SQL_BEST_ROWID row-identifying column of tables, by calling SQLSpecialColumns .
(Support for SQL_ROWVER is feature 208 in Level 2 Interface Conformance.)

IMPORTANT
ODBC Drivers must implement the functions in the Core interface conformance level.
Level 1 Interface Conformance
4/27/2022 • 2 minutes to read • Edit Online

The Level 1 interface conformance level includes the Core interface conformance level functionality plus
additional features, such as transactions, that are usually available in an OLTP relational DBMS. A Level 1
interface-conformant driver lets the application do the following, in addition to the features in the Core interface
conformance level:

F EAT URE N UM B ER DESC RIP T IO N

101 Specify the schema of database tables and views (using two-
part naming). (For more information, see the three-part
naming feature 201 in Level 2 Interface Conformance.)

102 Invoke true asynchronous execution of ODBC functions,


where applicable ODBC functions are all synchronous or all
asynchronous on a given connection.

103 Use scrollable cursors, and thereby achieve access to a result


set in methods other than forward-only, by calling
SQLFetchScroll with the FetchOrientation argument other
than SQL_FETCH_NEXT. (The SQL_FETCH_BOOKMARK
FetchOrientation is in feature 204 in Level 2 Interface
Conformance.)

104 Obtain primary keys of tables, by calling SQLPrimar yKeys .

105 Use stored procedures, through the ODBC escape sequence


for procedure calls, and query the data dictionary regarding
stored procedures, by calling SQLProcedureColumns and
SQLProcedures . (The process by which procedures are
created and stored on the data source is outside the scope
of this document.)

106 Connect to a data source by interactively browsing the


available servers, by calling SQLBrowseConnect .

107 Use ODBC functions instead of SQL statements to perform


certain database operations: SQLSetPos with
SQL_POSITION and SQL_REFRESH.

108 Gain access to the contents of multiple result sets generated


by batches and stored procedures, by calling
SQLMoreResults .

109 Delimit transactions spanning several ODBC functions, with


true atomicity and the ability to specify SQL_ROLLBACK in
SQLEndTran .
Level 2 Interface Conformance
4/27/2022 • 2 minutes to read • Edit Online

The Level 2 interface conformance level includes the Level 1 interface conformance-level functionality plus the
following features:

F EAT URE N UM B ER DESC RIP T IO N

201 Use three-part names of database tables and views. (For


more information, see the two-part naming support feature
101 in Level 1 Interface Conformance.)

202 Describe dynamic parameters, by calling


SQLDescribeParam .

203 Use not only input parameters but also output and
input/output parameters, and result values of stored
procedures.

204 Use bookmarks, including retrieving bookmarks, by calling


SQLDescribeCol and SQLColAttribute on column
number 0; fetching based on a bookmark, by calling
SQLFetchScroll with the FetchOrientation argument set to
SQL_FETCH_BOOKMARK; and update, delete, and fetch by
bookmark operations, by calling SQLBulkOperations with
the Operation argument set to
SQL_UPDATE_BY_BOOKMARK,
SQL_DELETE_BY_BOOKMARK, or
SQL_FETCH_BY_BOOKMARK.

205 Retrieve advanced information about the data dictionary, by


calling SQLColumnPrivileges , SQLForeignKeys , and
SQLTablePrivileges .

206 Use ODBC functions instead of SQL statements to perform


additional database operations, by calling
SQLBulkOperations with SQL_ADD, or SQLSetPos with
SQL_DELETE or SQL_UPDATE. (Support for calls to
SQLSetPos with the LockType argument set to
SQL_LOCK_EXCLUSIVE or SQL_LOCK_UNLOCK is not a part
of the conformance levels but is an optional feature.)

207 Enable asynchronous execution of ODBC functions for


specified individual statements.

208 Obtain the SQL_ROWVER row-identifying column of tables,


by calling SQLSpecialColumns . (For more information, see
the support for SQLSpecialColumns with the
IdentifierType argument set to SQL_BEST_ROWID as feature
20 in Core Interface Conformance.)

209 Set the SQL_ATTR_CONCURRENCY statement attribute to at


least one value other than SQL_CONCUR_READ_ONLY.
F EAT URE N UM B ER DESC RIP T IO N

210 The ability to time out login request and SQL queries
(SQL_ATTR_LOGIN_TIMEOUT and
SQL_ATTR_QUERY_TIMEOUT).

211 The ability to change the default isolation level; the ability to
execute transactions with the "serializable" level of isolation.
Function Conformance
4/27/2022 • 2 minutes to read • Edit Online

The following table indicates the conformance level of each ODBC function, where this is well defined.

F UN C T IO N C O N F O RM A N C E L EVEL

SQL AllocHandle Core

SQLBindCol Core

SQLBindParameter Core[1]

SQLBrowseConnect Level 1

SQLBulkOperations Level 1

SQLCancel Core[1]

SQLCloseCursor Core

SQLColAttribute Core[1]

SQLColumnPrivileges Level 2

SQLColumns Core

SQLConnect Core

SQLCopyDesc Core

SQLDataSources Core

SQLDescribeCol Core[1]

SQLDescribeParam Level 2

SQLDisconnect Core

SQLDriverConnect Core

SQLDrivers Core

SQLEndTran Core[1]

SQLExecDirect Core

SQLExecute Core
F UN C T IO N C O N F O RM A N C E L EVEL

SQLFetch Core

SQLFetchScroll Core[1]

SQLForeignKeys Level 2

SQLFreeHandle Core

SQLFreeStmt Core

SQLGetConnectAttr Core

SQLGetCursorName Core

SQLGetData Core

SQLGetDescField Core

SQLGetDescRec Core

SQLGetDiagField Core

SQLGetDiagRec Core

SQLGetEnvAttr Core

SQLGetFunctions Core

SQLGetInfo Core

SQLGetStmtAttr Core

SQLGetTypeInfo Core

SQLMoreResults Level 1

SQLNativeSql Core

SQLNumParams Core

SQLNumResultCols Core

SQLParamData Core

SQLPrepare Core

SQLPrimar yKeys Level 1

SQLProcedureColumns Level 1
F UN C T IO N C O N F O RM A N C E L EVEL

SQLProcedures Level 1

SQLPutData Core

SQLRowCount Core

SQLSetConnectAttr Core[2]

SQLSetCursorName Core

SQLSetDescField Core[1]

SQLSetDescRec Core

SQLSetEnvAttr Core[2]

SQLSetPos Level 1[1]

SQLSetStmtAttr Core[2]

SQLSpecialColumns Core[1]

SQLStatistics Core

SQLTablePrivileges Level 2

SQLTables Core

[1] Significant features of this function are available only at higher conformance levels.
[2] Setting certain attributes to nondefault values depends on the conformance level. For more information, see
the next section, Attribute Conformance.
Attribute Conformance
4/27/2022 • 2 minutes to read • Edit Online

The following table indicates the conformance level of each ODBC environment attribute, where this is well
defined.

F UN C T IO N C O N F O RM A N C E L EVEL

SQL_ATTR_CONNECTION_POOLING --[1]

SQL_ATTR_CP_MATCH --[1]

SQL_ATTR_ODBC_VER Core

SQL_ATTR_OUTPUT_NTS --[1]

[1] This is an optional feature and as such is not part of the conformance levels.
The following table indicates the conformance level of each ODBC connection attribute, where this is well
defined.

F UN C T IO N C O N F O RM A N C E L EVEL

SQL_ATTR_ACCESS_MODE Core

SQL_ATTR_ASYNC_ENABLE Level 1/Level 2[1]

SQL_ATTR_AUTO_IPD Level 2

SQL_ATTR_AUTOCOMMIT Level 1

SQL_ATTR_CONNECTION_DEAD Level 1

SQL_ATTR_CONNECTION_TIMEOUT Level 2

SQL_ATTR_CURRENT_CATALOG Level 2

SQL_ATTR_LOGIN_TIMEOUT Level 2

SQL_ATTR_ODBC_CURSORS Core

SQL_ATTR_PACKET_SIZE Level 2

SQL_ATTR_QUIET_MODE Core

SQL_ATTR_TRACE Core

SQL_ATTR_TRACEFILE Core
F UN C T IO N C O N F O RM A N C E L EVEL

SQL_ATTR_TRANSLATE_LIB Core

SQL_ATTR_TRANSLATE_OPTION Core

SQL_ATTR_TXN_ISOLATION Level 1/Level 2[2]

[1] Applications that support connection-level asynchrony (required for Level 1) must support setting this
attribute to SQL_TRUE by calling SQLSetConnectAttr ; the attribute need not be settable to a value other than
its default value through SQLSetStmtAttr . Applications that support statement-level asynchrony (required for
Level 2) must support setting this attribute to SQL_TRUE using either function.
[2] For Level 1 interface conformance, the driver must support one value in addition to the driver-defined
default value (available by calling SQLGetInfo with the SQL_DEFAULT_TXN_ISOLATION option). For Level 2
interface conformance, the driver must also support SQL_TXN_SERIALIZABLE.
The following table indicates the conformance level of each ODBC statement attribute, where this is well defined.

F UN C T IO N C O N F O RM A N C E L EVEL

SQL_ATTR_APP_PARAM_DESC Core

SQL_ATTR_APP_ROW_DESC Core

SQL_ATTR_ASYNC_ENABLE Level 1/Level 2[1]

SQL_ATTR_CONCURRENCY Level 1/Level 2[2]

SQL_ATTR_CURSOR_SCROLLABLE Level 1

SQL_ATTR_CURSOR_SENSITIVITY Level 2

SQL_ATTR_CURSOR_TYPE Core/Level 2[3]

SQL_ATTR_ENABLE_AUTO_IPD Level 2

SQL_ATTR_FETCH_BOOKMARK_PTR Level 2

SQL_ATTR_IMP_PARAM_DESC Core

SQL_ATTR_IMP_ROW_DESC Core

SQL_ATTR_KEYSET_SIZE Level 2

SQL_ATTR_MAX_LENGTH Level 1

SQL_ATTR_MAX_ROWS Level 1

SQL_ATTR_METADATA_ID Core

SQL_ATTR_NOSCAN Core
F UN C T IO N C O N F O RM A N C E L EVEL

SQL_ATTR_PARAM_BIND_OFFSET_PTR Core

SQL_ATTR_PARAM_BIND_TYPE Core

SQL_ATTR_PARAM_OPERATION_PTR Core

SQL_ATTR_PARAM_STATUS_PTR Core

SQL_ATTR_PARAMS_PROCESSED_PTR Core

SQL_ATTR_PARAMSET_SIZE Core

SQL_ATTR_QUERY_TIMEOUT Level 2

SQL_ATTR_RETRIEVE_DATA Level 1

SQL_ATTR_ROW_ARRAY_SIZE Core

SQL_ATTR_ROW_BIND_OFFSET_PTR Core

SQL_ATTR_ROW_BIND_TYPE Core

SQL_ATTR_ROW_NUMBER Level 1

SQL_ATTR_ROW_OPERATION_PTR Level 1

SQL_ATTR_ROW_STATUS_PTR Core

SQL_ATTR_ROWS_FETCHED_PTR Core

SQL_ATTR_SIMULATE_CURSOR Level 2

SQL_ATTR_USE_BOOKMARKS Level 2

[1] Applications that support connection-level asynchrony (required for Level 1) must support setting this
attribute to SQL_TRUE by calling SQLSetConnectAttr ; the attribute need not be settable to a value other than
its default value through SQLSetStmtAttr . Applications that support statement-level asynchrony (required for
Level 2) must support setting this attribute to SQL_TRUE using either function.
[2] For Level 2 interface conformance, the driver must support SQL_CONCUR_READ_ONLY and at least one
other value.
[3] For Level 1 interface conformance, the driver must support SQL_CURSOR_FORWARD_ONLY and at least one
other value. For Level 2 interface conformance, the driver must support all values defined in this document.
Descriptor Field Conformance
4/27/2022 • 2 minutes to read • Edit Online

The following table indicates the conformance level of each ODBC descriptor header field, where this is well
defined.

F UN C T IO N C O N F O RM A N C E L EVEL

SQL_DESC_ALLOC_TYPE Core

SQL_DESC_ARRAY_SIZE Core

SQL_DESC_ARRAY_STATUS_PTR Core (for APD, IPR, and IRD); Level 1 (for ARD)

SQL_DESC_BIND_OFFSET_PTR Core

SQL_DESC_BIND_TYPE Core

SQL_DESC_COUNT Core

SQL_DESC_ROWS_PROCESSED_PTR Core

The following table indicates the conformance level of each ODBC descriptor record field, where this is well
defined.

F UN C T IO N C O N F O RM A N C E L EVEL

SQL_DESC_AUTO_UNIQUE_VALUE Level 2

SQL_DESC_BASE_COLUMN_NAME Core

SQL_DESC_BASE_TABLE_NAME Level 1

SQL_DESC_CASE_SENSITIVE Core

SQL_DESC_CATALOG_NAME Level 2

SQL_DESC_CONCISE_TYPE Core

SQL_DESC_DATA_PTR Core

SQL_DESC_DATETIME_INTERVAL_ CODE Core[1]

SQL_DESC_DATETIME_INTERVAL_ PRECISION Core[1]

SQL_DESC_DISPLAY_SIZE Core

SQL_DESC_FIXED_PREC_SCALE Core
F UN C T IO N C O N F O RM A N C E L EVEL

SQL_DESC_INDICATOR_PTR Core

SQL_DESC_LABEL Level 2

SQL_DESC_LENGTH Core

SQL_DESC_LITERAL_PREFIX Core

SQL_DESC_LITERAL_SUFFIX Core

SQL_DESC_LOCAL_TYPE_NAME Core

SQL_DESC_NAME Core

SQL_DESC_NULLABLE Core

SQL_DESC_OCTET_LENGTH Core

SQL_DESC_OCTET_LENGTH_PTR Core

SQL_DESC_PARAMETER_TYPE Core/Level 2[2]

SQL_DESC_PRECISION Core

SQL_DESC_ROWVER Level 1

SQL_DESC_SCALE Core

SQL_DESC_SCHEMA_NAME Level 1

SQL_DESC_SEARCHABLE Core

SQL_DESC_TABLE_NAME Level 1

SQL_DESC_TYPE Core

SQL_DESC_TYPE_NAME Core

SQL_DESC_UNNAMED Core

SQL_DESC_UNSIGNED Core

SQL_DESC_UPDATABLE Core

[1] Support for these record fields is required only if the driver supports the applicable data types.
[2] For Core-level conformance, the driver must support SQL_PARAM_INPUT. For Level 2 interface conformance,
the driver must also support SQL_PARAM_INPUT_OUTPUT and SQL_PARAM_OUTPUT.
SQL Conformance Levels
4/27/2022 • 2 minutes to read • Edit Online

The level of SQL-92 grammar supported by a driver is indicated by the value returned by a call to SQLGetInfo
with the SQL_SQL_CONFORMANCE information type. This indicates whether the driver conforms to the Entry,
FIPS Transitional, Intermediate, or Full levels defined in SQL-92.
All ODBC drivers must support the minimum SQL grammar described in SQL Minimum Grammar in Appendix
C: SQL Grammar. This grammar is a subset of the Entry level of SQL-92. Drivers may support additional SQL
and be conformant to the SQL-92 Entry, Intermediate, or Full level, or to the FIPS 127-2 Transitional level.
Drivers that comply to a given level of SQL-92 or FIPS 127-2 can support additional features in any of the
higher levels yet not be fully conformant to that level. To determine whether a feature is supported, an
application should call SQLGetInfo with the appropriate information type. The conformance level of an SQL
feature is described in the corresponding information type. (See the SQLGetInfo function description.)
Environment, Connection, and Statement Attributes
4/27/2022 • 2 minutes to read • Edit Online

ODBC defines a number of attributes that are associated with environments, connections, or statements.
Environment attributes affect the entire environment, such as whether connection pooling is enabled.
Environment attributes are set with SQLSetEnvAttr and retrieved with SQLGetEnvAttr .
Connection attributes affect each connection individually, such as how long a driver should wait while
attempting to connect to a data source before timing out. Connection attributes are set with
SQLSetConnectAttr and retrieved with SQLGetConnectAttr . For more information about connection
attributes, see Connection Attributes.
Statement attributes affect each statement individually, such as whether a statement should be executed
asynchronously. Statement attributes are set with SQLSetStmtAttr and retrieved with SQLGetStmtAttr . A few
statement attributes are read-only attributes and cannot be set. For example, the SQL_ATTR_ROW_NUMBER
statement attribute, which is used to retrieve the number of the current row in the cursor, is read-only. For more
information about statement attributes, see Statement Attributes.
In addition to attributes defined by ODBC, a driver can define its own connection and statement attributes.
Driver-defined attributes must be registered with Open Group to ensure that two driver vendors do not assign
the same integer value to different, proprietary attributes. For more information, see Driver-Specific Data Types,
Descriptor Types, Information Types, Diagnostic Types, and Attributes.
For a complete list of attributes, see SQLSetEnvAttr, SQLSetConnectAttr, and SQLSetStmtAttr. Most attributes
are also described in the description of the ODBC function that they affect.
Tables and Views
4/27/2022 • 2 minutes to read • Edit Online

In ODBC functions, tables and views are interchangeable. The term table is used both for tables and for views,
except where the term view is used explicitly.
Basic ODBC Application Steps
4/27/2022 • 2 minutes to read • Edit Online

This section describes the general flow of ODBC applications. It is unlikely that any application calls all of these
functions in exactly this order. However, most applications use some variation of these steps. The basic
application steps are shown in the following illustration.

This section contains the following topics.


Step 1: Connect to the Data Source
Step 2: Initialize the Application
Step 3: Build and Execute an SQL Statement
Step 4a: Fetch the Results
Step 4b: Fetch the Row Count
Step 5: Commit the Transaction
Step 6: Disconnect from the Data Source
Step 1: Connect to the Data Source
4/27/2022 • 2 minutes to read • Edit Online

The first step in any application is to connect to the data source. This phase, including the functions it requires, is
shown in the following illustration.

The first step in connecting to the data source is to load the Driver Manager and allocate the environment
handle with SQL AllocHandle . For more information, see Allocating the Environment Handle.
The application then registers the version of ODBC to which it conforms by calling SQLSetEnvAttr with the
SQL_ATTR_APP_ODBC_VER environment attribute. For more information, see Declaring the Application's ODBC
Version and Backward Compatibility and Standards Compliance.
Next, the application allocates a connection handle with SQL AllocHandle and connects to the data source with
SQLConnect , SQLDriverConnect , or SQLBrowseConnect . For more information, see Allocating a
Connection Handle and Establishing a Connection.
The application then sets any connection attributes, such as whether to manually commit transactions. For more
information, see Connection Attributes.
Step 2: Initialize the Application
4/27/2022 • 2 minutes to read • Edit Online

The second step is to initialize the application, as shown in the following illustration. Exactly what is done here
varies with the application.

At this point, it is common to use SQLGetInfo to discover the capabilities of the driver. For more information,
see Considering Database Features to Use.
All applications need to allocate a statement handle with SQL AllocHandle , and many applications set
statement attributes, such as the cursor type, with SQLSetStmtAttr . For more information, see Allocating a
Statement Handle and Statement Attributes.
Step 3: Build and Execute an SQL Statement
4/27/2022 • 2 minutes to read • Edit Online

The third step is to build and execute an SQL statement, as shown in the following illustration. The methods
used to perform this step are likely to vary tremendously. The application might prompt the user to enter an
SQL statement, build an SQL statement based on user input, or use a hard-coded SQL statement. For more
information, see Constructing SQL Statements.

If the SQL statement contains parameters, the application binds them to application variables by calling
SQLBindParameter for each parameter. For more information, see Statement Parameters.
After the SQL statement is built and any parameters are bound, the statement is executed with SQLExecDirect .
If the statement will be executed multiple times, it can be prepared with SQLPrepare and executed with
SQLExecute . For more information, see Executing a Statement.
The application might also forgo executing an SQL statement altogether and instead call a function to return a
result set containing catalog information, such as the available columns or tables. For more information, see
Uses of Catalog Data.
The application's next action depends on the type of SQL statement executed.

T Y P E O F SQ L STAT EM EN T P RO C EED TO

SELECT or catalog function Step 4a: Fetch the Results

UPDATE , DELETE , or INSERT Step 4b: Fetch the Row Count

All other SQL statements Step 3: Build and Execute an SQL Statement (this topic) or
Step 5: Commit the Transaction
Step 4a: Fetch the Results
4/27/2022 • 2 minutes to read • Edit Online

The next step is to fetch the results, as shown in the following illustration.

If the statement executed in "Step 3: Build and Execute an SQL Statement" was a SELECT statement or a catalog
function, the application first calls SQLNumResultCols to determine the number of columns in the result set.
This step is not necessary if the application already knows the number of result set columns, such as when the
SQL statement is hard-coded in a vertical or custom application.
Next, the application retrieves the name, data type, precision, and scale of each result set column with
SQLDescribeCol . Again, this is not necessary for applications such as vertical and custom applications that
already know this information. The application passes this information to SQLBindCol , which binds an
application variable to a column in the result set.
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.
For a complete description of retrieving results, see Retrieving Results (Basic) and Retrieving Results (Advanced).
The application now returns to "Step 3: Build and Execute an SQL Statement" to execute another statement in the
same transaction; or proceeds to "Step 5: Commit the Transaction" to commit or roll back the transaction.
Step 4b: Fetch the Row Count
4/27/2022 • 2 minutes to read • Edit Online

The next step is to fetch the row count, as shown in the following illustration.

If the statement executed in Step 3 was an UPDATE , DELETE , or INSERT statement, the application retrieves the
count of affected rows with SQLRowCount . For more information, see Determining the Number of Affected
Rows.
The application now returns to step 3 to execute another statement in the same transaction or proceeds to step
5 to commit or roll back the transaction.
Step 5: Commit the Transaction
4/27/2022 • 2 minutes to read • Edit Online

The next step is to commit the transaction, as shown in the following illustration.

The fifth step is to call SQLEndTran to commit or roll back 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. For more
information, see Transactions.
To execute a statement in a new transaction, the application returns to step 3. To disconnect from the data
source, the application proceeds to step 6.
Step 6: Disconnect from the Data Source
4/27/2022 • 2 minutes to read • Edit Online

The final step is to disconnect from the data source, as shown in the following illustration. First, the application
frees any statement handles by calling SQLFreeHandle . For more information, see Freeing a Statement Handle.

Next, the application disconnects from the data source with SQLDisconnect and frees the connection handle
with SQLFreeHandle . For more information, see Disconnecting from a Data Source or Driver.
Finally, the application frees the environment handle with SQLFreeHandle and unloads the Driver Manager.
For more information, see Allocating the Environment Handle.
Connecting to a Data Source or Driver
4/27/2022 • 2 minutes to read • Edit Online

An application can be connected to any number of drivers and data sources. These can be a variety of drivers
and data sources, the same driver and a variety of data sources, or even multiple connections to the same driver
and data source.
This section contains the following topics.
Allocating the Environment Handle
Declaring the Application's ODBC Version
Choosing a Data Source or Driver
Allocating a Connection Handle
Connection Attributes
Establishing a Connection
Driver Manager Connection Pooling
Disconnecting from a Data Source or Driver
The Driver Manager's Role in the Connection Process
Allocating the Environment Handle
4/27/2022 • 2 minutes to read • Edit Online

The first task for any ODBC application is to load the Driver Manager; how this is done is operating-system
dependent. For example, on a computer running Microsoft® Windows NT® Server/Windows 2000 Server,
Windows NT Workstation/Windows 2000 Professional, or Microsoft Windows® 95/98, the application either
links to the Driver Manager library or calls LoadLibrar y to load the Driver Manager DLL.
The next task, which must be done before an application can call any other ODBC function, is to initialize the
ODBC environment and allocate an environment handle, as follows:
1. The application declares a variable of type SQLHENV. It then calls SQL AllocHandle and passes the
address of this variable and the SQL_HANDLE_ENV option. For example:

SQLHENV henv1;

SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv1);

2. The Driver Manager allocates a structure in which to store information about the environment, and
returns the environment handle in the variable.
The Driver Manager does not call SQL AllocHandle in the driver at this time because it does not know which
driver to call. It delays calling SQL AllocHandle in the driver until the application calls a function to connect to a
data source. For more information, see Driver Manager's Role in the Connection Process, later in this section.
When the application has finished using ODBC, it frees the environment handle with SQLFreeHandle . After
freeing the environment, it is an application programming error to use the environment's handle in a call to an
ODBC function; doing so has undefined but probably fatal consequences.
When SQLFreeHandle is called, the driver releases the structure used to store information about the
environment. Note that SQLFreeHandle cannot be called for an environment handle until after all connection
handles on that environment handle have been freed.
For more information about the environment handle, see Environment Handles.
Declaring the Application's ODBC Version
4/27/2022 • 2 minutes to read • Edit Online

Before an application allocates a connection, it must set the SQL_ATTR_ODBC_VERSION environment attribute.
This attribute states that the application follows the ODBC 2.x or ODBC 3.x specification when using the
following items:
SQLSTATEs . Many SQLSTATE values are different in ODBC 2.x and ODBC 3.x.
Date, Time, and Timestamp Type Identifiers . The following table shows the type identifiers for date,
time, and timestamp data in ODBC 2.x and ODBC 3.x.

O DB C 2. X O DB C 3. X

SQL Type Identifiers

SQL_DATE SQL_TYPE_DATE

SQL_TIME SQL_TYPE_TIME

SQL_TIMESTAMP SQL_TYPE_TIMESTAMP

C Type Identifiers

SQL_C_DATE SQL_C_TYPE_DATE

SQL_C_TIME SQL_C_TYPE_TIME

SQL_C_TIMESTAMP SQL_C_TYPE_TIMESTAMP

CatalogName Argument in SQLTables . In ODBC 2.x, the wildcard characters ("%" and "_") in the
CatalogName argument are treated literally. In ODBC 3.x, they are treated as wildcard characters. Thus, an
application that follows the ODBC 2.x specification cannot use these as wildcard characters and does not
escape them when using them as literals. An application that follows the ODBC 3.x specification can use
these as wildcard characters or escape them and use them as literals. For more information, see
Arguments in Catalog Functions.
The ODBC 3.x Driver Manager and ODBC 3.x drivers check the version of the ODBC specification to which an
application is written and respond accordingly. For example, if the application follows the ODBC 2.x specification
and calls SQLExecute before calling SQLPrepare , the ODBC 3.x Driver Manager returns SQLSTATE S1010
(Function sequence error). If the application follows the ODBC 3.x specification, the Driver Manager returns
SQLSTATE HY010 (Function sequence error). For more information, see Backward Compatibility and Standards
Compliance.

IMPORTANT
Applications that follow the ODBC 3.x specification must use conditional code to avoid using functionality new to ODBC
3.x when working with ODBC 2.x drivers. ODBC 2.x drivers do not support functionality new to ODBC 3.x just because the
application declares that it follows the ODBC 3.x specification. Furthermore, ODBC 3.x drivers do not cease to support
functionality new to ODBC 3.x just because the application declares that it follows the ODBC 2.x specification.
Choosing a Data Source or Driver
4/27/2022 • 4 minutes to read • Edit Online

The data source or driver used by an application is sometimes hard-coded in the application. For example, a
custom application written by an MIS department to transfer data from one data source to another would
contain the names of those data sources-the application simply would not work with any other data sources.
Another example is a vertical application, such as one used for order entry. Such an application always uses the
same data source, which has a predefined schema known by the application.
Other applications select the data source or driver at run time. Usually, these are generic applications that do ad
hoc queries, such as a spreadsheet that uses ODBC to import data. Such applications usually list the available
data sources or drivers and let users choose the ones they want to work with. Whether a generic application lists
data sources, drivers, or both frequently depends on whether the application uses DBMS-based or file-based
drivers.
DBMS-based drivers usually require a complex set of connection information, such as the network address,
network protocol, database name, and so on. The purpose of a data source is to hide all of this information.
Therefore, the data source paradigm lends itself to use with DBMS-based drivers. An application can display a
list of data sources to the user in one of two ways. It can call SQLDriverConnect with the DSN (Data Source
Name) keyword and no associated value; the Driver Manager will display a list of data source names. If the
application wants control over the appearance of the list, it calls SQLDataSources to retrieve a list of available
data sources and constructs its own dialog box. This function is implemented by the Driver Manager and can be
called before any drivers are loaded. The application then calls a connection function and passes it the name of
the chosen data source.
If a data source is not specified, the default data source indicated by the system information is used. (For more
information, see Default Subkey.) If SQLConnect is called by using a ServerName argument that cannot be
found, is a null pointer, or is "DEFAULT", the Driver Manager connects to the default data source. The default data
source is also used if the connection string that is used in a call to SQLDriverConnect or SQLBrowseConnect
contains the DSN keyword set to "DEFAULT" or if the specified data source is not found. Additionally, the default
data source is used if the connection string that is used in a call to SQLDriverConnect does not contain the
DSN keyword.
With file-based drivers, it is possible to use a file paradigm. For data stored on the local computer, users
frequently know that their data is in a particular file, such as Employee.dbf. Instead of selecting an unknown data
source, it is easier for such users to select the file they know. To implement this, the application first calls
SQLDrivers . This function is implemented by the Driver Manager and can be called before any drivers are
loaded. SQLDrivers returns a list of available drivers; it also returns values for the FileUsage and FileExtns
keywords. The FileUsage keyword explains whether file-based drivers treat files as tables, as does Xbase, or as
databases, as does Microsoft® Access. The FileExtns keyword lists the file name extensions the driver
recognizes, such as .dbf for an Xbase driver. Using this information, the application constructs a dialog box
through which the user chooses a file. Based on the extension of the chosen file, the application then connects to
the driver by calling SQLDriverConnect with the DRIVER keyword.
There is nothing to stop an application from using a data source with a file-based driver or calling
SQLDriverConnect with the DRIVER keyword to connect to a DBMS-based driver. Here are several common
uses of the DRIVER keyword for DBMS-based drivers:
Not creating data sources. For example, a custom application might use a particular driver and
database. If the driver name and all information that is required to connect to the database is hard-coded
in the application, users do not have to create a data source on their computer to run the application. All
they must do is install the application and driver.
A disadvantage of this method is that the application must be recompiled and redistributed if the
connection information changes. If a data source name is hard-coded in the application instead of
complete connection information, each user must change only the information in the data source.
Accessing a par ticular DBMS a single time. For example, a spreadsheet that retrieves data by calling
ODBC functions might contain the DRIVER keyword to identify a particular driver. Because the driver
name is meaningful to any users who have that driver, the spreadsheet could be passed among those
users. If the spreadsheet contained a data source name, each user would have to create the same data
source to use the spreadsheet.
Browsing the system for all databases accessible to a par ticular driver. For more information,
see Connecting with SQLBrowseConnect, later in this section.
Allocating a Connection Handle ODBC
4/27/2022 • 2 minutes to read • Edit Online

Before the application can connect to a data source or driver, it must allocate a connection handle, as follows:
1. The application declares a variable of type SQLHDBC. It then calls SQL AllocHandle and passes the
address of this variable, the handle of the environment in which to allocate the connection, and the
SQL_HANDLE_DBC option. For example:

SQLHDBC hdbc1;

SQLAllocHandle(SQL_HANDLE_DBC, henv1, &hdbc1);

2. The Driver Manager allocates a structure in which to store information about the statement and returns
the connection handle in the variable.
The Driver Manager does not call SQL AllocHandle in the driver at this time because it does not know which
driver to call. It delays calling SQL AllocHandle in the driver until the application calls a function to connect to a
data source. For more information, see Driver Manager's Role in the Connection Process, later in this section.
It is important to note that allocating a connection handle is not the same as loading a driver. The driver is not
loaded until a connection function is called. Thus, after allocating a connection handle and before connecting to
the driver or data source, the only functions the application can call with the connection handle are
SQLSetConnectAttr , SQLGetConnectAttr , or SQLGetInfo with the SQL_ODBC_VER option. Calling other
functions with the connection handle, such as SQLEndTran , returns SQLSTATE 08003 (Connection not open).
For complete details, see Appendix B: ODBC State Transition Tables.
For more information about connection handles, see Connection Handles.
Connection Attributes
4/27/2022 • 2 minutes to read • Edit Online

Connection attributes are characteristics of the connection. For example, because transactions occur at the
connection level, the transaction isolation level is a connection attribute. Similarly, the login timeout, or number
of seconds to wait while trying to connect before timing out, is a connection attribute.
Connection attributes are set with SQLSetConnectAttr and their current settings retrieved with
SQLGetConnectAttr . If SQLSetConnectAttr is called before the driver is loaded, the Driver Manager stores
the attributes in its connection structure and sets them in the driver as part of the connection process. There is
no requirement that an application set any connection attributes; all connection attributes have defaults, some of
which are driver-specific.
A connection attribute can be set before or after connection, or either, depending on the attribute and the driver.
The login timeout (SQL_ATTR_LOGIN_TIMEOUT) applies to the connection process and is effective only if set
before connecting. The attributes that specify whether to use the ODBC cursor library
(SQL_ATTR_ODBC_CURSORS) and the network packet size (SQL_ATTR_PACKET_SIZE) must be set before
connecting, because the ODBC cursor library resides between the Driver Manager and the driver and therefore
must be loaded before the driver.
The attributes to specify whether a data source is read-only or read-write (SQL_ATTR_ACCESS_MODE) and the
current catalog (SQL_ATTR_CURRENT_CATALOG) can be set before or after connecting, depending on the driver.
However, interoperable applications set them before connecting because some drivers do not support changing
these after connecting.
Some connection attributes have a default before the connection is made, while others do not. Those that do are
SQL_ATTR_ACCESS_MODE, SQL_ATTR_AUTOCOMMIT, SQL_ATTR_LOGIN_TIMEOUT,
SQL_ATTR_ODBC_CURSORS, SQL_ATTR_TRACE, and SQL_ATTR_TRACEFILE.
The translation connection attributes (SQL_ATTR_TRANSLATE_DLL and SQL_ATTR_TRANSLATE_OPTION) must
be set after connecting.
All other connection attributes can be set at any time. For more information, see the SQLSetConnectAttr function
description. (Connection attributes cannot be set on the environment level by a call to SQLSetEnvAttr .)
Establishing a Connection
4/27/2022 • 2 minutes to read • Edit Online

After allocating environment and connection handles and setting any connection attributes, the application is
ready to connect to the data source or driver. There are three different functions the application can use to do
this: SQLConnect (Core interface conformance level), SQLDriverConnect (Core), and SQLBrowseConnect
(Level 1). Each of the three is designed to be used in a different scenario. Before connecting, the application can
determine which of these functions is supported with the ConnectFunctions keyword returned by
SQLDrivers .

NOTE
Some drivers limit the number of active connections they support. An application calls SQLGetInfo with the
SQL_MAX_DRIVER_CONNECTIONS option to determine how many active connections a particular driver supports.

This section contains the following topics.


Default Data Source
Connecting with SQLConnect
Connection Strings
Connecting with SQLDriverConnect
Connecting with SQLBrowseConnect
Default Data Source
4/27/2022 • 2 minutes to read • Edit Online

The driver may select a data source, called the default data source, in certain cases where the application does
not explicitly specify one:
In a call to SQLConnect where the ServerName argument is a zero-length string, a null pointer, or
DEFAULT.
In a call to SQLDriverConnect where InConnectionString either specifies DSN =DEFAULT or specifies
with the DSN keyword a data source that is not contained in the system information.
It is driver-defined how the default data source is specified. This may involve administrative action and may
depend on the user.
Connecting with SQLConnect
4/27/2022 • 2 minutes to read • Edit Online

SQLConnect is the simplest connection function. It requires a data source name and accepts an optional user ID
and password. It works well for applications that hard-code a data source name and do not require a user ID or
password. It also works well for applications that want to control their own "look and feel" or that have no user
interface. Such applications can build a list of data sources using SQLDataSources , prompt the user for data
source, user ID, and password, and then call SQLConnect .
The following example connects to the Northwind database, using a DSN called Northwind, and retrieves all of
the first and last name fields from all of the records in the Employees table.

// Connecting_with_SQLConnect.cpp
// compile with: user32.lib odbc32.lib
#include <windows.h>
#include <sqlext.h>
#include <mbstring.h>
#include <stdio.h>

#define MAX_DATA 100


#define MYSQLSUCCESS(rc) ((rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO) )

class direxec {
RETCODE rc; // ODBC return code
HENV henv; // Environment
HDBC hdbc; // Connection handle
HSTMT hstmt; // Statement handle

unsigned char szData[MAX_DATA]; // Returned data storage


SDWORD cbData; // Output length of data
unsigned char chr_ds_name[SQL_MAX_DSN_LENGTH]; // Data source name

public:
direxec(); // Constructor
void sqlconn(); // Allocate env, stat, and conn
void sqlexec(unsigned char *); // Execute SQL statement
void sqldisconn(); // Free pointers to env, stat, conn, and disconnect
void error_out(); // Displays errors
};

// Constructor initializes the string chr_ds_name with the data source name.
// "Northwind" is an ODBC data source (odbcad32.exe) name whose default is the Northwind database
direxec::direxec() {
_mbscpy_s(chr_ds_name, SQL_MAX_DSN_LENGTH, (const unsigned char *)"Northwind");
}

// Allocate environment handle and connection handle, connect to data source, and allocate statement handle.
void direxec::sqlconn() {
SQLAllocEnv(&henv);
SQLAllocConnect(henv, &hdbc);
rc = SQLConnect(hdbc, chr_ds_name, SQL_NTS, NULL, 0, NULL, 0);

// Deallocate handles, display error message, and exit.


if (!MYSQLSUCCESS(rc)) {
SQLFreeConnect(henv);
SQLFreeEnv(henv);
SQLFreeConnect(hdbc);
if (hstmt)
error_out();
exit(-1);
}
}

rc = SQLAllocStmt(hdbc, &hstmt);
}

// Execute SQL command with SQLExecDirect() ODBC API.


void direxec::sqlexec(unsigned char * cmdstr) {
rc = SQLExecDirect(hstmt, cmdstr, SQL_NTS);
if (!MYSQLSUCCESS(rc)) { //Error
error_out();
// Deallocate handles and disconnect.
SQLFreeStmt(hstmt,SQL_DROP);
SQLDisconnect(hdbc);
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
exit(-1);
}
else {
for ( rc = SQLFetch(hstmt) ; rc == SQL_SUCCESS ; rc=SQLFetch(hstmt) ) {
SQLGetData(hstmt, 1, SQL_C_CHAR, szData, sizeof(szData), &cbData);
// In this example, the data is sent to the console; SQLBindCol() could be called to bind
// individual rows of data and assign for a rowset.
printf("%s\n", (const char *)szData);
}
}
}

// Free the statement handle, disconnect, free the connection handle, and free the environment handle.
void direxec::sqldisconn() {
SQLFreeStmt(hstmt,SQL_DROP);
SQLDisconnect(hdbc);
SQLFreeConnect(hdbc);
SQLFreeEnv(henv);
}

// Display error message in a message box that has an OK button.


void direxec::error_out() {
unsigned char szSQLSTATE[10];
SDWORD nErr;
unsigned char msg[SQL_MAX_MESSAGE_LENGTH + 1];
SWORD cbmsg;

while (SQLError(0, 0, hstmt, szSQLSTATE, &nErr, msg, sizeof(msg), &cbmsg) == SQL_SUCCESS) {


sprintf_s((char *)szData, sizeof(szData), "Error:\nSQLSTATE=%s, Native error=%ld, msg='%s'",
szSQLSTATE, nErr, msg);
MessageBox(NULL, (const char *)szData, "ODBC Error", MB_OK);
}
}

int main () {
direxec x; // Declare an instance of the direxec object.
x.sqlconn(); // Allocate handles, and connect.
x.sqlexec((UCHAR FAR *)"SELECT FirstName, LastName FROM employees"); // Execute SQL command
x.sqldisconn(); // Free handles and disconnect
}
Connection Strings
4/27/2022 • 2 minutes to read • Edit Online

A connection string contains information used for establishing a connection. A complete connection string
contains all the information needed to establish a connection. The connection string is a series of keyword/value
pairs separated by semicolons. (For the complete syntax of a connection string, see the SQLDriverConnect
function description.) The connection string is used by:
SQLDriverConnect , which completes the connection string by interaction with the user.
SQLBrowseConnect , which completes the connection string iteratively with the data source.
SQLConnect does not use a connection string; using SQLConnect is analogous to connecting using a
connection string with exactly three keyword/value pairs (for data source name and, optionally, user ID and
password).
Connecting with SQLDriverConnect
4/27/2022 • 2 minutes to read • Edit Online

SQLDriverConnect is used to connect to a data source using a connection string. SQLDriverConnect is used
instead of SQLConnect for the following scenarios:
Establish a connection using a connection string that contains the data source name, one or more user
IDs, one or more passwords, and other information required by the data source.
Establish a connection using a partial connection string or no additional information; in this case, the
Driver Manager and the driver can each prompt the user for connection information.
Establish a connection to a data source that is not defined in the system information. If the application
supplies a partial connection string, the driver can prompt the user for connection information.
Establish a connection to a data source using a connection string constructed from the information in a
.dsn file.
After a connection is established, SQLDriverConnect returns the completed connection string. The application
can use this string for subsequent connection requests.
This section contains the following topics.
Driver-Specific Connection Information
Prompting the User for Connection Information
Connecting Using File Data Sources
Connecting Directly to Drivers
Driver-Specific Connection Information
4/27/2022 • 2 minutes to read • Edit Online

SQLConnect assumes that a data source name, user ID, and password are sufficient to connect to a data source
and that all other connection information can be stored on the system. This is frequently not the case. For
example, a driver might need one user ID and password to log on to a server and a different user ID and
password to log on to a DBMS. Because SQLConnect accepts a single user ID and password, this means that
the other user ID and password must be stored with the data source information on the system if SQLConnect
is to be used. This is a potential breach of security and should be avoided unless the password is encrypted.
SQLDriverConnect allows the driver to define an arbitrary amount of connection information in the keyword-
value pairs of the connection string. For example, suppose a driver requires a data source name, a user ID and
password for the server, and a user ID and password for the DBMS. A custom program that always uses the XYZ
Corp data source might prompt the user for IDs and passwords and build the following set of keyword-value
pairs, or connection string, to pass to SQLDriverConnect :

NOTE
If you are connecting to a data source provider that supports Windows authentication, you should specify
Trusted_Connection=yes instead of user ID and password information in the connection string.

DSN={MyDataSourceName};UID={MyUserID};PWD={MyServerPassword};UIDDBMS={MyDBMSUserID};PWDDBMS=
{MyDBMSUserPassword};

The DSN (Data Source Name) keyword names the data source, the UID and PWD keywords specify the user ID
and password for the server, and the UIDDBMS and PWDDBMS keywords specify the user ID and password
for the DBMS. Notice that the final semicolon is optional. SQLDriverConnect parses this string; uses the XYZ
Corp data source name to retrieve additional connection information from the system, such as the server
address; and logs on to the server and DBMS using the specified user IDs and passwords.
Keyword-value pairs in SQLDriverConnect must follow certain syntax rules. The keywords and their values
should not contain the []{}(),;?*=!@ characters. The value of the DSN keyword cannot consist only of blanks
and should not contain leading blanks. Because of the registry grammar, keywords and data source names
cannot contain the backslash (\) character. Spaces are not allowed around the equal sign in the keyword-value
pair.
The FILEDSN keyword can be used in a call to SQLDriverConnect to specify the name of a file that contains
data source information (see Connecting Using File Data Sources, later in this section). The SAVEFILE keyword
can be used to specify the name of a .dsn file in which the keyword-value pairs of a successful connection made
by the call to SQLDriverConnect will be saved. For more information about file data sources, see the
SQLDriverConnect function description.
Prompting the User for Connection Information
4/27/2022 • 2 minutes to read • Edit Online

If the application uses SQLConnect and needs to prompt the user for any connection information, such as a
user name and password, it must do so itself. While this allows the application to control its "look and feel," it
might force the application to contain driver-specific code. This occurs when the application needs to prompt the
user for driver-specific connection information. This presents an impossible situation for generic applications,
which are designed to work with any and all drivers, including drivers that do not exist when the application is
written.
SQLDriverConnect can prompt the user for connection information. For example, the custom program
mentioned earlier could pass the following connection string to SQLDriverConnect :

DSN=XYZ Corp;

The driver might then display a dialog box that prompts for user IDs and passwords, similar to the following
illustration.

That the driver can prompt for connection information is particularly useful to generic and vertical applications.
These applications should not contain driver-specific information, and having the driver prompt for the
information it needs keeps that information out of the application. This is shown by the previous two examples.
When the application passed only the data source name to the driver, the application did not contain any driver-
specific information and was therefore not tied to a particular driver. When the application passed a complete
connection string to the driver, it was tied to the driver that could interpret that string.
A generic application might take this one step further and not even specify a data source. When
SQLDriverConnect receives an empty connection string, the Driver Manager displays the following dialog box.

After the user selects a data source, the Driver Manager constructs a connection string specifying that data
source and passes it to the driver. The driver can then prompt the user for any additional information it needs.
The conditions under which the driver prompts the user are controlled by the DriverCompletion flag; there are
options to always prompt, prompt if necessary, or never prompt. For a complete description of this flag, see the
SQLDriverConnect function description.
Connecting Using File Data Sources
4/27/2022 • 2 minutes to read • Edit Online

The connection information for a file data source is stored in a .dsn file. As a result, the connection string can be
used repeatedly by a single user or shared among several users if they have the appropriate driver installed. The
file contains a driver name (or another data source name in the case of an unshareable file data source) and
optionally, a connection string that can be used by SQLDriverConnect . The Driver Manager builds the
connection string for the call to SQLDriverConnect from the keywords in the .dsn file.
A file data source allows an application to specify connection options without having to build a connection string
for use with SQLDriverConnect . The file data source usually is created by specifying the SAVEFILE keyword,
which causes the Driver Manager to save the output connection string created by a call to SQLDriverConnect
to the .dsn file. That connection string can be used repeatedly by calling SQLDriverConnect with the FILEDSN
keyword. This streamlines the connection process and provides a persistent source of the connection string.
File data sources also can be created by calling SQLCreateDataSource in the installer DLL. Information can be
written into the .dsn file by calling SQLWriteFileDSN , and read from the .dsn file by calling SQLReadFileDSN ;
both of these functions are also in the installer DLL. For information about the installer DLL, see Configuring
Data Sources.
The keywords used for connection information are in the [ODBC] section of a .dsn file. The minimum
information that a shareable .dsn file would have in the [ODBC] section is the DRIVER keyword:

DRIVER = SQL Server

The shareable .dsn file usually contains a connection string, as follows:

DRIVER = SQL Server


UID = Larry
DATABASE = MyDB

When the file data source is unshareable, the .dsn file contains only a DSN keyword. When the Driver Manager
is sent the information in an unshareable file data source, it connects as necessary to the data source indicated
by the DSN keyword. An unshareable .dsn file would contain the following keyword:

DSN = MyDataSource

The connection string used for a file data source is the union of the keywords specified in the .dsn file and the
keywords specified in the connection string in the call to SQLDriverConnect . If any of the keywords in the .dsn
file conflict with keywords in the connection string, the Driver Manager decides which keyword value should be
used. For more information, see SQLDriverConnect.

See Also
https://support.microsoft.com/kb/165866
Connecting Directly to Drivers
4/27/2022 • 2 minutes to read • Edit Online

As was discussed in Choosing a Data Source or Driver, earlier in this section, some applications do not want to
use a data source at all. Instead, they want to connect directly to a driver. SQLDriverConnect provides a way
for the application to connect directly to a driver without specifying a data source. Conceptually, a temporary
data source is created at run time.
To connect directly to a driver, the application specifies the DRIVER keyword in the connection string instead of
the DSN keyword. The value of the DRIVER keyword is the description of the driver as returned by
SQLDrivers . For example, suppose a driver has the description Paradox Driver and requires the name of a
directory containing the data files. To connect to this driver, the application might use either of the following
connection strings:

DRIVER={Paradox Driver};Directory=C:\PARADOX;
DRIVER={Paradox Driver};

With the first string, the driver would not need any additional information. With the second string, the driver
would need to prompt for the name of the directory containing the data files.
Connecting with SQLBrowseConnect
4/27/2022 • 2 minutes to read • Edit Online

SQLBrowseConnect , like SQLDriverConnect , uses a connection string. However, by using


SQLBrowseConnect , an application can construct a complete connection string at run time. This allows the
application to do two things:
Build its own dialog boxes to prompt for this information, thereby retaining control over its "look and
feel."
Browse the system for data sources that can be used by a particular driver, possibly in several steps. For
example, the user might first browse the network for servers and, after choosing a server, browse the
server for databases accessible by the driver.
The application calls SQLBrowseConnect and passes a connection string, known as the browse request
connection string, that specifies a driver or data source. The driver returns a connection string, known as the
browse result connection string, that contains keywords, possible values (if the keyword accepts a discrete set of
values), and user-friendly names. The application builds a dialog box with the user-friendly names and prompts
the user for values. It then builds a new browse request connection string from these values and returns this to
the driver with another call to SQLBrowseConnect .
Because connection strings are passed back and forth, the driver can provide several levels of browsing by
returning a new connection string when the application returns the old one. For example, the first time an
application calls SQLBrowseConnect , the driver might return keywords to prompt the user for a server name.
When the application returns the server name, the driver might return keywords to prompt the user for a
database. The browsing process would be complete after the application returned the database name.
Each time SQLBrowseConnect returns a new browse result connection string, it returns SQL_NEED_DATA as
its return code. This tells the application that the connection process is not complete. Until SQLBrowseConnect
returns SQL_SUCCESS, the connection is in a Need Data state and cannot be used for other purposes, such as to
set a connection attribute. The application can terminate the connection browsing process by calling
SQLDisconnect .
This section contains the following topic.
SQL Server Browsing Example
SQL Server Browsing Example
4/27/2022 • 2 minutes to read • Edit Online

The following example shows how SQLBrowseConnect might be used to browse the connections available
with a driver for SQL Server. First, the application requests a connection handle:

SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

Next, the application calls SQLBrowseConnect and specifies the SQL Server driver, using the driver description
returned by SQLDrivers :

SQLBrowseConnect(hdbc, "DRIVER={SQL Server};", SQL_NTS, BrowseResult,


sizeof(BrowseResult), &BrowseResultLen);

Because this is the first call to SQLBrowseConnect , the Driver Manager loads the SQL Server driver and calls
the driver's SQLBrowseConnect function with the same arguments it received from the application.

NOTE
If you are connecting to a data source provider that supports Windows authentication, you should specify
Trusted_Connection=yes instead of user ID and password information in the connection string.

The driver determines that this is the first call to SQLBrowseConnect and returns the second level of
connection attributes: server, user name, password, application name, and workstation ID. For the server
attribute, it returns a list of valid server names. The return code from SQLBrowseConnect is SQL_NEED_DATA.
Here is the browse result string:

"SERVER:Server={red,blue,green,yellow};UID:Login ID=?;PWD:Password=?;
*APP:AppName=?;*WSID:WorkStation ID=?;"

Each keyword in the browse result string is followed by a colon and one or more words before the equal sign.
These words are the user-friendly name that an application can use to build a dialog box. The APP and WSID
keywords are prefixed by an asterisk, which means they are optional. The SERVER , UID , and PWD keywords
are not prefixed by an asterisk; values must be supplied for them in the next browse request string. The value for
the SERVER keyword may be one of the servers returned by SQLBrowseConnect or a user-supplied name.
The application calls SQLBrowseConnect again, specifying the green server and omitting the APP and WSID
keywords and the user-friendly names after each keyword:

SQLBrowseConnect(hdbc, "SERVER=green;UID=Smith;PWD=Sesame;", SQL_NTS,


BrowseResult, sizeof(BrowseResult), &BrowseResultLen);

The driver attempts to connect to the green server. If there are any nonfatal errors, such as a missing keyword-
value pair, SQLBrowseConnect returns SQL_NEED_DATA and remains in the same state as it was prior to the
error. The application can call SQLGetDiagField or SQLGetDiagRec to determine the error. If the connection is
successful, the driver returns SQL_NEED_DATA and returns the browse result string:
"*DATABASE:Database={master,model,pubs,tempdb};
*LANGUAGE:Language={us_english,Franais};"

Because the attributes in this string are optional, the application can omit them. However, the application must
call SQLBrowseConnect again. If the application chooses to omit the database name and language, it specifies
an empty browse request string. In this example, the application chooses the pubs database and calls
SQLBrowseConnect a final time, omitting the L ANGUAGE keyword and the asterisk before the DATABASE
keyword:

SQLBrowseConnect(hdbc, "DATABASE=pubs;", SQL_NTS, BrowseResult,


sizeof(BrowseResult), &BrowseResultLen);

Because the DATABASE attribute is the final connection attribute required by the driver, the browsing process is
complete, the application is connected to the data source, and SQLBrowseConnect returns SQL_SUCCESS.
SQLBrowseConnect also returns the complete connection string as the browse result string:

"DSN=MySQLServer;SERVER=green;UID=Smith;PWD=Sesame;DATABASE=pubs;"

The final connection string returned by the driver does not contain the user-friendly names after each keyword,
nor does it contain optional keywords not specified by the application. The application can use this string with
SQLDriverConnect to reconnect to the data source on the current connection handle (after disconnecting) or
to connect to the data source on a different connection handle. For example:

SQLDriverConnect(hdbc, hwnd, BrowseResult, SQL_NTS, ConnStrOut,


sizeof(ConnStrOut), &ConnStrOutLen, SQL_DRIVER_NOPROMPT);
Driver Manager Connection Pooling
4/27/2022 • 6 minutes to read • Edit Online

Connection pooling enables an application to use a connection from a pool of connections that do not need to
be re-established for each use. Once a connection has been created and placed in a pool, an application can
reuse that connection without performing the complete connection process.
Using a pooled connection can result in significant performance gains, because applications can save the
overhead involved in making a connection. This can be particularly significant for middle-tier applications that
connect over a network or for applications that repeatedly connect and disconnect, such as Internet applications.
In addition to performance gains, the connection pooling architecture enables an environment and its associated
connections to be used by multiple components in a single process. This means that stand-alone components in
the same process can interact with each other without being aware of each other. A connection in a connection
pool can be used repeatedly by multiple components.

NOTE
Connection pooling can be used by an ODBC application exhibiting ODBC 2.x behavior, as long as the application can call
SQLSetEnvAttr. When using connection pooling, the application must not execute SQL statements that change the
database or the context of the database, such as changing the <database name>, which changes the catalog used by a
data source.

An ODBC driver must be fully thread-safe, and connections must not have thread affinity to support connection
pooling. This means the driver is able to handle a call on any thread at any time and is able to connect on one
thread, to use the connection on another thread, and to disconnect on a third thread.
The connection pool is maintained by the Driver Manager. Connections are drawn from the pool when the
application calls SQLConnect or SQLDriverConnect and are returned to the pool when the application calls
SQLDisconnect . The size of the pool grows dynamically, based on the requested resource allocations. It shrinks
based on the inactivity timeout: If a connection is inactive for a period of time (it has not been used in a
connection), it is removed from the pool. The size of the pool is limited only by memory constraints and limits
on the server.
The Driver Manager determines whether a specific connection in a pool should be used according to the
arguments passed in SQLConnect or SQLDriverConnect , and according to the connection attributes set after
the connection was allocated.
When the Driver Manager is pooling connections, it needs to be able to determine if a connection is still working
before handing out the connection. Otherwise, the Driver Manager keeps on handing out the dead connection
to the application whenever a transient network failure occurs. A new connection attribute has been defined in
ODBC 3*.x*: SQL_ATTR_CONNECTION_DEAD. This is a read-only connection attribute that returns either
SQL_CD_TRUE or SQL_CD_FALSE. The value SQL_CD_TRUE means that the connection has been lost, while the
value SQL_CD_FALSE means that the connection is still active. (Drivers conforming to earlier versions of ODBC
can also support this attribute.)
A driver must implement this option efficiently or it will impair the connection pooling performance. Specifically,
a call to get this connection attribute should not cause a round trip to the server. Instead, a driver should just
return the last known state of the connection. The connection is dead if the last trip to the server failed, and not
dead if the last trip succeeded.
Remarks
If a connection has been lost (reported via SQL_ATTR_CONNECTION_DEAD), the ODBC Driver Manager will
destroy that connection by calling SQLDisconnect in the driver. New connection requests might not find a usable
connection in the pool. Eventually the Driver Manager might make a new connection, assuming the pool is
empty.
To use a connection pool, an application performs the following steps:
1. Enables connection pooling by calling SQLSetEnvAttr to set the SQL_ATTR_CONNECTION_POOLING
environment attribute to SQL_CP_ONE_PER_DRIVER or SQL_CP_ONE_PER_HENV. This call must be made
before the application allocates the shared environment for which connection pooling is to be enabled.
The environment handle in the call to SQLSetEnvAttr should be set to null, which makes
SQL_ATTR_CONNECTION_POOLING a process-level attribute. If the attribute is set to
SQL_CP_ONE_PER_DRIVER, a single connection pool is supported for each driver. If an application works
with many drivers and few environments, this might be more efficient because fewer comparisons may
be required. If set to SQL_CP_ONE_PER_HENV, a single connection pool is supported for each
environment. If an application works with many environments and few drivers, this might be more
efficient because fewer comparisons may be required. Connection pooling is disabled by setting
SQL_ATTR_CONNECTION_POOLING to SQL_CP_OFF.
2. Allocates an environment by calling SQL AllocHandle with the HandleType argument set to
SQL_HANDLE_ENV. The environment allocated by this call will be an implicit shared environment because
connection pooling has been enabled. The environment to be used is not determined, however, until
SQL AllocHandle with a HandleType of SQL_HANDLE_DBC is called on this environment.
3. Allocates a connection by calling SQL AllocHandle with InputHandle set to SQL_HANDLE_DBC, and the
InputHandle set to the environment handle allocated for connection pooling. The Driver Manager
attempts to find an existing environment that matches the environment attributes set by the application.
If no such environment exists, one is created, with a reference count (maintained by the Driver Manager)
of 1. If a matching shared environment is found, the environment is returned to the application and its
reference count is incremented. (The actual connection to be used is not determined by the Driver
Manager until SQLConnect or SQLDriverConnect is called.)
4. Calls SQLConnect or SQLDriverConnect to make the connection. The Driver Manager uses the
connection options in the call to SQLConnect (or the connection keywords in the call to
SQLDriverConnect ) and the connection attributes set after connection allocation to determine which
connection in the pool should be used.

NOTE
How a requested connection is matched to a pooled connection is determined by the SQL_ATTR_CP_MATCH
environment attribute. For more information, see SQLSetEnvAttr.

ODBC applications using connection pooling should call CoInitializeEx during application initialization
and CoUninitialize when the application closes.
5. Calls SQLDisconnect when done with the connection. The connection is returned to the connection pool
and becomes available for reuse.
For an in-depth discussion, see Pooling in the Microsoft Data Access Components.

Connection Pooling Considerations


Performing any of the following actions using a SQL command (rather than through the ODBC API) can affect
the connection's state and cause unexpected problems when connection pooling is active:
Opening a connection and changing the default database.
Using the SET statement to change any configurable options (including SET ROWCOUNT, ANSI_NULL,
IMPLICIT_TRANSACTIONS, SHOWPLAN, STATISTICS, TEXTSIZE, and DATEFORMAT).
Creating temporary tables and stored procedures.
If any of these actions are performed outside of the ODBC API, the next person who uses the connection will
automatically inherit the previous settings, tables, or procedures.

NOTE
Do not expect certain settings to be present in the connection state. You should always set the connection state in your
application and ensure that the application removes any unused connection pooling settings.

Driver-Aware Connection Pooling


Beginning in Windows 8, an ODBC driver can use connections in the pool more efficiently. For more
information, see Driver-Aware Connection Pooling.

See Also
Connecting to a Data Source or Driver
Developing an ODBC Driver
Pooling in the Microsoft Data Access Components
Driver-Aware Connection Pooling
4/27/2022 • 2 minutes to read • Edit Online

Driver aware connection pooling is a new feature of the Driver Manager in Windows 8. Driver aware connection
pooling allows driver writers to customize the connection pooling behavior in their ODBC driver.

NOTE
Driver aware connection pooling is not supported with cursor library. An application will receive error message if it
attempts to enable cursor library via SQLSetConnectAttr, when driver aware connection pooling is enabled.

Driver aware connection pooling addresses the following problems related to Driver Manager connection
pooling:
Pool Fragmentation The Driver Manager will only return a connection from the pool if it is an exact match
with the connection string of a new connection request. One reason for the Driver Manager to require an exact
match is that the Driver Manager does not understand every driver-specific connection string keyword and its
value. However, some connection string keyword values (such as the name of the database) may not require an
exact match, since the driver can change the database in less than the time needed to open a new connection
(the exact time difference depends on the data source). And, differences in some connection attributes (such as
SQL_ATTR_CURRENT_CATALOG) can take more time to change than differences in other attributes (such as
SQL_ATTR_LOGIN_TIMEOUT). This, too, can prevent the Driver Manager from using the lowest-cost, reusable
connection from the pool. When a driver has to create many new connections, an application's performance can
decrease and the data source scalability can decrease. Pool fragmentation can be reduced with driver-aware
connection pooling because a driver can better estimate the cost of reusing a connection in the pool for a
connection request.
No consideration of application preference Some data sources can efficiently open new connections
(compared to resetting some attributes), so, an application may prefer to open a new connection instead of
trying to reuse a slightly mismatched connection from the pool and reset some values (although this may be
slower during the connection pool initialization phrase). But some applications may keep the server load smaller
and open fewer connections, although there may be a bigger cost to fix the mismatches for correct behavior.
Without driver-aware connection pooling, you cannot specify this kind of preference effectively, because the
Driver Manager does not recognize all driver-specific connection attributes. Driver-aware connection pooling
allows a driver to obtain the user preference (with a driver-specific attribute of SQLSetConnectAttr) so that it can
better estimate the cost of reusing a connection from the pool based on a user's preference.
For more information about driver-aware connection pooling, see Developing Connection-Pool Awareness in an
ODBC Driver.

Determining Driver Support


Driver-aware connection pooling is an optional feature that a driver may not support. To determine if a driver
supports it, use the SQL_DRIVER_AWARE_POOLING_SUPPORTED InfoType of SQLGetInfo.

How to Enable Driver-Aware Connection Pooling


An application can use a driver's connection-pooling awareness by setting the
SQL_ATTR_CONNECTION_POOLING attribute to SQL_CP_DRIVER_AWARE with SQLSetEnvAttr. If a driver does
not support connection-pool awareness, Driver Manager connection pooling will be used (same as if
SQL_CP_ONE_PER_HENV had been specified, instead of SQL_CP_DRIVER_AWARE). ODBC 2.x and 3.x
applications can enable this feature.

See Also
Developing an ODBC Driver
Disconnecting from a Data Source or Driver
4/27/2022 • 2 minutes to read • Edit Online

When an application has finished using a data source, it calls SQLDisconnect . SQLDisconnect frees any
statements that are allocated on the connection and disconnects the driver from the data source. It returns an
error if a transaction is in process.
After disconnecting, the application can call SQLFreeHandle to free the connection. After freeing the
connection, it is an application programming error to use the connection's handle in a call to an ODBC function;
doing so has undefined but probably fatal consequences. When SQLFreeHandle is called, the driver releases
the structure used to store information about the connection.
The application also can reuse the connection, either to connect to a different data source or reconnect to the
same data source. The decision to remain connected, as opposed to disconnecting and reconnecting later,
requires that the application writer consider the relative costs of each option; both connecting to a data source
and remaining connected can be relatively costly depending on the connection medium. In making a correct
tradeoff, the application must also make assumptions about the likelihood and timing of further operations on
the same data source.
Driver Manager's Role in the Connection Process
4/27/2022 • 2 minutes to read • Edit Online

Remember that applications do not call driver functions directly. Instead, they call Driver Manager functions with
the same name and the Driver Manager calls the driver functions. Usually, this happens almost immediately. For
example, the application calls SQLExecute in the Driver Manager and after a few error checks, the Driver
Manager calls SQLExecute in the driver.
The connection process is different. When the application calls SQL AllocHandle with the SQL_HANDLE_ENV
and SQL_HANDLE_DBC options, the function allocates handles only in the Driver Manager. The Driver Manager
does not call this function in the driver because it does not know which driver to call. Similarly, if the application
passes the handle of an unconnected connection to SQLSetConnectAttr or SQLGetConnectAttr , only the
Driver Manager executes the function. It stores or gets the attribute value from its connection handle and
returns SQLSTATE 08003 (Connection not open) when getting a value for an attribute that has not been set and
for which ODBC does not define a default value.
When the application calls SQLConnect , SQLDriverConnect , or SQLBrowseConnect , the Driver Manager
first determines which driver to use. It then checks to determine whether a driver is currently loaded on the
connection:
If no driver is loaded on the connection, the Driver Manager checks whether the specified driver is loaded
on another connection in the same environment. If not, the Driver Manager loads the driver on the
connection and calls SQL AllocHandle in the driver with the SQL_HANDLE_ENV option.
The Driver Manager then calls SQL AllocHandle in the driver with the SQL_HANDLE_DBC option,
whether or not it was just loaded. If the application set any connection attributes, the Driver Manager calls
SQLSetConnectAttr in the driver; if an error occurs, the Driver Manager's connection function returns
SQLSTATE IM006 (Driver's SQLSetConnectAttr failed). Finally, the Driver Manager calls the connection
function in the driver.
If the specified driver is loaded on the connection, the Driver Manager calls only the connection function
in the driver. In this case, the driver must make sure that all connection attributes on the connection
maintain their current settings.
If a different driver is loaded on the connection, the Driver Manager calls SQLFreeHandle in the driver
to free the connection. If there are no other connections that use the driver, the Driver Manager calls
SQLFreeHandle in the driver to free the environment and unloads the driver. The Driver Manager then
performs the same operations as when a driver is not loaded on the connection.
The Driver Manager will lock the environment handle (henv) before calling a driver's SQL AllocHandle and
SQLFreeHandle when HandleType is set to SQL_HANDLE_DBC .
When the application calls SQLDisconnect , the Driver Manager calls SQLDisconnect in the driver. However, it
leaves the driver loaded in case the application reconnects to the driver. When the application calls
SQLFreeHandle with the SQL_HANDLE_DBC option, the Driver Manager calls SQLFreeHandle in the driver. If
the driver is not used by any other connections, the Driver Manager then calls SQLFreeHandle in the driver
with the SQL_HANDLE_ENV option and unloads the driver.
Catalog Functions
4/27/2022 • 2 minutes to read • Edit Online

All databases have a structure that outlines how data will be stored in the database. For example, a simple sales
order database might have the structure shown in the following illustration, in which the ID columns are used to
link the tables.

This structure, along with other information such as privileges, is stored in a set of system tables called the
database's catalog, which is also known as a data dictionary.
An application can discover this structure through calls to the catalog functions. The catalog functions return
information in result sets and are usually implemented through SELECT statements against the tables in the
catalog. For example, an application might request a result set containing information about all the tables on the
system or all the columns in a particular table.
This section contains the following topics.
Uses of Catalog Data
Catalog Functions in ODBC
Uses of Catalog Data
4/27/2022 • 2 minutes to read • Edit Online

Applications use catalog data in a variety of ways. Here are some common uses:
Constructing SQL statements at run time. Vertical applications, such as an order entry application,
contain hard-coded SQL statements. The tables and columns that are used by the application are fixed
ahead of time, as are the statements that access these tables. For example, an order entry application
usually contains a single, parameterized INSERT statement for adding new orders to the system.
Generic applications, such as a spreadsheet program that uses ODBC to retrieve data, often construct SQL
statements at run time based on input from the user. Such an application could require the user to type
the names of the tables and columns to use. However, it would be easier for the user if the application
displayed lists of tables and columns from which the user could make selections. To build these lists, the
application would call the SQLTables and SQLColumns catalog functions.
Constructing SQL statements during development. Application development environments
typically allow the programmer to create database queries while developing a program. The queries are
then hard-coded in the application being built.
Such environments could also use SQLTables and SQLColumns to create lists from which the
programmer could make selections. These environments might also use SQLPrimar yKeys and
SQLForeignKeys to automatically determine and show relationships between selected tables, and use
SQLStatistics to determine and highlight indexed fields so the programmer can create efficient queries.
Constructing cursors. An application, driver, or middleware that provides a scrollable cursor engine
could use SQLSpecialColumns to determine which column or columns uniquely identify a row. The
program could build a keyset containing the values of these columns for each row that has been fetched.
When the application scrolls back to the row, it would then use these values to fetch the most recent data
for the row. For more information about scrollable cursors and keysets, see Scrollable Cursors.
Catalog Functions in ODBC
4/27/2022 • 2 minutes to read • Edit Online

ODBC contains the following catalog functions:

F UN C T IO N DESC RIP T IO N

SQLTables Returns a list of catalogs, schemas, tables, or table types in


the data source.

SQLColumns Returns a list of columns in one or more tables.

SQLStatistics Returns a list of statistics about a single table. Also returns a


list of indexes associated with that table.

SQLSpecialColumns Returns a list of columns that uniquely identifies a row in a


single table. Also returns a list of columns in that table that
are automatically updated.

SQLPrimar yKeys Returns a list of columns that compose the primary key of a
single table.

SQLForeignKeys Returns a list of foreign keys in a single table or a list of


foreign keys in other tables that refer to a single table.

SQLTablePrivileges Returns a list of privileges associated with one or more


tables.

SQLColumnPrivileges Returns a list of privileges associated with one or more


columns in a single table.

SQLProcedures Returns a list of procedures in the data source.

SQLProcedureColumns Returns a list of input and output parameters, the return


value, and the columns in the result set of a single
procedure.

SQLGetTypeInfo Returns a list of the SQL data types supported by the data
source. These data types are generally used in CREATE
TABLE and ALTER TABLE statements.

Because SQLTables , SQLColumns , SQLStatistics , and SQLSpecialColumns conform to the Open Group CLI,
and SQLGetTypeInfo conforms to the ISO 92 CLI, they are implemented by most drivers. The remaining
catalog functions are in the ODBC conformance level.
This section contains the following topics.
Data Returned by Catalog Functions
Arguments in Catalog Functions
Schema Views
Data Returned by Catalog Functions
4/27/2022 • 2 minutes to read • Edit Online

Each catalog function returns data as a result set. This result set is no different from any other result set. It is
usually generated by a predefined, parameterized SELECT statement that is hard-coded in the driver or stored
in a procedure in the data source. For information about how to retrieve data from a result set, see Was a Result
Set Created?.
The result set for each catalog function is described in the reference entry for that function. In addition to the
listed columns, the result set can contain driver-specific columns after the last predefined column. These
columns (if any) are described in the driver documentation.
Applications should bind driver-specific columns relative to the end of the result set. That is, they should
calculate the number of a driver-specific column as the number of the last column - retrieved with
SQLNumResultCols - less the number of columns that occur after the required column. This saves having to
change the application when new columns are added to the result set in future versions of ODBC or the driver.
For this scheme to work, drivers must add new driver-specific columns before old driver-specific columns so
that column numbers do not change relative to the end of the result set.
Identifiers that are returned in the result set are not quoted, even if they contain special characters. For example,
suppose the identifier quote character (which is driver-specific and returned through SQLGetInfo ) is a double
quotation mark (") and the Accounts Payable table contains a column named Customer Name. In the row
returned by SQLColumns for this column, the value of the TABLE_NAME column is Accounts Payable, not
"Accounts Payable", and the value of the COLUMN_NAME column is Customer Name, not "Customer Name". To
retrieve the names of customers in the Accounts Payable table, the application would quote these names:

SELECT "Customer Name" FROM "Accounts Payable"

For more information, see Quoted Identifiers.


The catalog functions are based on an SQL-like authorization model in which a connection is made based on a
user name and password, and only data for which the user has a privilege is returned. Password protection of
individual files, which does not fit into this model, is driver-defined.
The result sets returned by the catalog functions are almost never updatable, and applications should not expect
to be able to change the structure of the database by changing the data in these result sets.
Arguments in Catalog Functions
4/27/2022 • 2 minutes to read • Edit Online

All catalog functions accept arguments with which an application can restrict the scope of the data returned. For
example, the first and second calls to SQLTables in the following code return a result set containing information
about all tables, while the third call returns information about the Orders table:

SQLTables(hstmt1, NULL, 0, NULL, 0, NULL, 0, NULL, 0);


SQLTables(hstmt2, NULL, 0, NULL, 0, "%", SQL_NTS, NULL, 0);
SQLTables(hstmt3, NULL, 0, NULL, 0, "Orders", SQL_NTS, NULL, 0);

Catalog function string arguments fall into four different types: ordinary argument (OA), pattern value argument
(PV), identifier argument (ID), and value list argument (VL). Most string arguments can be of one of two different
types, depending on the value of the SQL_ATTR_METADATA_ID statement attribute. The following table lists the
arguments for each catalog function and describes the type of the argument for an SQL_TRUE or SQL_FALSE
value of SQL_ATTR_METADATA_ID.

T Y P E W H EN SQ L _ T Y P E W H EN SQ L _

AT T R_M ETA DATA _ AT T R_M ETA DATA _

F UN C T IO N A RGUM EN T ID = SQ L _FA L SE ID = SQ L _T RUE

SQLColumnPrivileges CatalogName SchemaName OA OA OA PV ID ID ID ID


TableName ColumnName

SQLColumns CatalogName SchemaName OA PV PV PV ID ID ID ID


TableName ColumnName

SQLForeignKeys PKCatalogName OA OA OA OA OA OA ID ID ID ID ID ID
PKSchemaName
PKTableName
FKCatalogName
FKSchemaName
FKTableName

SQLPrimar yKeys CatalogName SchemaName OA OA OA ID ID ID


TableName

SQLProcedureColumns CatalogName SchemaName OA PV PV PV ID ID ID ID


ProcName ColumnName

SQLProcedures CatalogName SchemaName OA PV PV ID ID ID


ProcName

SQLSpecialColumns CatalogName SchemaName OA OA OA ID ID ID


TableName

SQLStatistics CatalogName SchemaName OA OA OA ID ID ID


TableName
T Y P E W H EN SQ L _ T Y P E W H EN SQ L _

AT T R_M ETA DATA _ AT T R_M ETA DATA _

F UN C T IO N A RGUM EN T ID = SQ L _FA L SE ID = SQ L _T RUE

SQLTablePrivileges CatalogName SchemaName OA PV PV ID ID ID


TableName

SQLTables CatalogName SchemaName PV PV PV VL ID ID ID VL


TableName TableType

This section contains the following topics.


Ordinary Arguments
Pattern Value Arguments
Identifier Arguments
Value List Arguments
Ordinary Arguments
4/27/2022 • 2 minutes to read • Edit Online

When a catalog function string argument is an ordinary argument, it is treated as a literal string. An ordinary
argument accepts neither a string search pattern nor a list of values. The case of an ordinary argument is
significant, and quote characters in the string are taken literally. These arguments are treated as ordinary
arguments if the SQL_ATTR_METADATA_ID statement attribute is set to SQL_FALSE; they are treated as identifier
arguments instead if this attribute is set to SQL_TRUE.
If an ordinary argument is set to a null pointer and the argument is a required argument, the function returns
SQL_ERROR and SQLSTATE HY009 (Invalid use of null pointer). If an ordinary argument is set to a null pointer
and the argument is not a required argument, the argument's behavior is driver-dependent. The required
arguments are listed in the following table.

F UN C T IO N REQ UIRED A RGUM EN T S

SQLColumnPrivileges TableName

SQLForeignKeys PKTableName, FKTableName

SQLPrimar yKeys TableName

SQLSpecialColumns TableName

SQLStatistics TableName
Pattern Value Arguments
4/27/2022 • 2 minutes to read • Edit Online

Some arguments in the catalog functions, such as the TableName argument in SQLTables , accept search
patterns. These arguments accept search patterns if the SQL_ATTR_METADATA_ID statement attribute is set to
SQL_FALSE; they are identifier arguments that do not accept a search pattern if this attribute is set to SQL_TRUE.
The search pattern characters are:
An underscore (_), which represents any single character.
A percent sign (%), which represents any sequence of zero or more characters.
An escape character, which is driver-specific and is used to include underscores, percent signs, and the
escape character as literals. If the escape character precedes a non-special character, the escape character
has no special meaning. If the escape character precedes a special character, it escapes the special
character. For example, "\a" would be treated as two characters, "\" and "a", but "\%" would be treated as
the non-special single character "%".
The escape character is retrieved with the SQL_SEARCH_PATTERN_ESCAPE option in SQLGetInfo . It must
precede any underscore, percent sign, or escape character in an argument that accepts search patterns to
include that character as a literal. Examples are shown in the following table.

SEA RC H PAT T ERN DESC RIP T IO N

%A% All identifiers containing the letter A

ABC_ All four character identifiers starting with ABC

ABC\_ The identifier ABC_, assuming the escape character is a


backslash (\)

\\% All identifiers starting with a backslash (\), assuming the


escape character is a backslash

Special care must be taken to escape search pattern characters in arguments that accept search patterns. This is
particularly true for the underscore character, which is commonly used in identifiers. A common mistake in
applications is to retrieve a value from one catalog function and pass that value to a search pattern argument in
another catalog function. For example, suppose an application retrieves the table name MY_TABLE from the
result set for SQLTables and passes this to SQLColumns to retrieve a list of columns in MY_TABLE. Instead of
getting the columns for MY_TABLE, the application will get the columns for all the tables that match the search
pattern MY_TABLE, such as MY_TABLE, MY1TABLE, MY2TABLE, and so on.

NOTE
ODBC 2.x drivers do not support search patterns in the CatalogName argument in SQLTables . ODBC 3*.x* drivers accept
search patterns in this argument if the SQL_ATTR_ ODBC_VERSION environment attribute is set to SQL_OV_ODBC3; they
do not accept search patterns in this argument if it is set to SQL_OV_ODBC2.

Passing a null pointer to a search pattern argument does not constrain the search for that argument; that is, a
null pointer and the search pattern % (any characters) are equivalent. However, a zero-length search pattern -
that is, a valid pointer to a string of length zero - matches only the empty string ("").
Identifier Arguments
4/27/2022 • 2 minutes to read • Edit Online

If a string in an identifier argument is quoted, the driver removes leading and trailing blanks and treats literally
the string within the quotation marks. If the string is not quoted, the driver removes trailing blanks and folds the
string to uppercase. Setting an identifier argument to a null pointer returns SQL_ERROR and SQLSTATE HY009
(Invalid use of null pointer), unless the argument is a catalog name and catalogs are not supported.
These arguments are treated as identifier arguments if the SQL_ATTR_METADATA_ID statement attribute is set to
SQL_TRUE. In this case, the underscore (_) and the percent sign (%) will be treated as the actual character, not as
a search pattern character. These arguments are treated as either an ordinary argument or a pattern argument,
depending on the argument, if this attribute is set to SQL_FALSE.
Although identifiers containing special characters must be quoted in SQL statements, they must not be quoted
when passed as catalog function arguments, because quote characters passed to catalog functions are
interpreted literally. For example, suppose the identifier quote character (which is driver-specific and returned
through SQLGetInfo ) is a double quotation mark ("). The first call to SQLTables returns a result set containing
information about the Accounts Payable table, while the second call returns information about the "Accounts
Payable" table, which is probably not what was intended.

SQLTables(hstmt1, NULL, 0, NULL, 0, "Accounts Payable", SQL_NTS, NULL, 0);


SQLTables(hstmt2, NULL, 0, NULL, 0, "\"Accounts Payable\"", SQL_NTS, NULL, 0);

Quoted identifiers are used to distinguish a true column name from a pseudo-column of the same name, such
as ROWID in Oracle. If "ROWID" is passed in an argument of a catalog function, the function will work with the
ROWID pseudo-column if it exists. If the pseudo-column does not exist, the function will work with the "ROWID"
column. If ROWID is passed in an argument of a catalog function, the function will work with the ROWID
column.
For more information about quoted identifiers, see Quoted Identifiers.
Value List Arguments
4/27/2022 • 2 minutes to read • Edit Online

A value list argument consists of a list of comma-separated values to be used for matching. There is only one
value list argument in the ODBC catalog functions: the TableType argument in SQLTables . Setting TableType to a
null pointer is the same as if it is set to SQL_ALL_TABLE_TYPES, which enumerates all possible members of the
value list. This argument is not affected by the SQL_ATTR_METADATA_ID statement attribute. For more
information, see the SQLTables function description.
Schema Views
4/27/2022 • 2 minutes to read • Edit Online

An application can retrieve metadata information from the DBMS either by calling ODBC catalog functions or by
using INFORMATION_SCHEMA views. The views are defined by the ANSI SQL-92 standard.
If supported by the DBMS and the driver, the INFORMATION_SCHEMA views provide a more powerful and
comprehensive means of retrieving metadata than the ODBC catalog functions provide. An application can
execute its own custom SELECT statement against one of these views, can join views, or can perform a union on
views. While offering greater utility and a wider range of metadata, INFORMATION_SCHEMA views are not often
supported by the DBMS. This might change as more DBMSs and drivers achieve compliance with SQL-92.
To determine which views are supported, an application calls SQLGetInfo with the SQL_INFO_SCHEMA_VIEWS
option. To retrieve metadata from a supported view, the application executes a SELECT statement that specifies
the schema information required.
SQL Statements
4/27/2022 • 2 minutes to read • Edit Online

ODBC applications perform almost all database access by executing SQL statements. The form of these
statements - hard-coded or constructed at run time, interoperable or data source-specific, and so on - depends
on the needs of the application.
This section contains the following topics.
Constructing SQL Statements
Interoperability of SQL Statements
Escape Sequences in ODBC
Constructing SQL Statements
4/27/2022 • 2 minutes to read • Edit Online

SQL statements can be constructed in one of three ways: hard-coded during development, constructed at run
time, or entered directly by the user.
This section contains the following topics.
Hard-Coded SQL Statements
SQL Statements Constructed at Run Time
SQL Statements Entered by the User
Hard-Coded SQL Statements
4/27/2022 • 3 minutes to read • Edit Online

Applications that perform a fixed task usually contain hard-coded SQL statements. For example, an order entry
system might use the following call to list open sales orders:

SQLExecDirect(hstmt, "SELECT OrderID FROM Orders WHERE Status = 'OPEN'", SQL_NTS);

There are several advantages to hard-coded SQL statements: They can be tested when the application is written;
they are simpler to implement than statements constructed at run time; and they simplify the application.
Using statement parameters and preparing statements provide even better ways to use hard-coded SQL
statements. For example, suppose the Parts table contains the PartID, Description, and Price columns. One way
to insert a new row into this table would be to construct and execute an INSERT statement:

#define DESC_LEN 51
#define STATEMENT_LEN 51

SQLUINTEGER PartID;
SQLCHAR Desc[DESC_LEN], Statement[STATEMENT_LEN];
SQLREAL Price;

// Set part ID, description, and price.


GetNewValues(&PartID, Desc, &Price);

// Build INSERT statement.


sprintf_s(Statement, 100, "INSERT INTO Parts (PartID, Description, Price) "
"VALUES (%d, '%s', %f)", PartID, Desc, Price);

// Execute the statement.


SQLExecDirect(hstmt, Statement, SQL_NTS);

An even better way is to use a hard-coded, parameterized statement. This has two advantages over a statement
with hard-coded data values. First, it is easier to construct a parameterized statement because the data values
can be sent in their native types, such as integers and floating-point numbers, rather than converting them to
strings. Second, such a statement can be used more than once simply by changing the parameter values and
reexecuting it; there is no need to rebuild it.
#define DESC_LEN 51

SQLCHAR * Statement = "INSERT INTO Parts (PartID, Description, Price) "


"VALUES (?, ?, ?)";
SQLUINTEGER PartID;
SQLCHAR Desc[DESC_LEN];
SQLREAL Price;
SQLINTEGER PartIDInd = 0, DescLenOrInd = SQL_NTS, PriceInd = 0;

// Bind the parameters.


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,
&PartID, 0, &PartIDInd);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, DESC_LEN - 1, 0,
Desc, sizeof(Desc), &DescLenOrInd);
SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 7, 0,
&Price, 0, &PriceInd);

// Set part ID, description, and price.


GetNewValues(&PartID, Desc, &Price);

// Execute the statement.


SQLExecDirect(hstmt, Statement, SQL_NTS);

Assuming this statement is to be executed more than once, it can be prepared for even greater efficiency:

#define DESC_LEN 51

SQLCHAR *Statement = "INSERT INTO Parts (PartID, Description, Price) "


"VALUES (?, ?, ?)";
SQLUINTEGER PartID;
SQLCHAR Desc[DESC_LEN];
SQLREAL Price;
SQLINTEGER PartIDInd = 0, DescLenOrInd = SQL_NTS, PriceInd = 0;

// Prepare the INSERT statement.


SQLPrepare(hstmt, Statement, SQL_NTS);

// Bind the parameters.


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,
&PartID, 0, &PartIDInd);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, DESC_LEN - 1, 0,
Desc, sizeof(Desc), &DescLenOrInd);
SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 7, 0,
&Price, 0, &PriceInd);

// Loop to continually get new values and insert them.


while (GetNewValues(&PartID, Desc, &Price))
SQLExecute(hstmt);

Perhaps the most efficient way to use the statement is to construct a procedure containing the statement, as
shown in the following code example. Because the procedure is constructed at development time and stored on
the data source, it does not need to be prepared at run time. A drawback of this method is that the syntax for
creating procedures is DBMS-specific and procedures must be constructed separately for each DBMS on which
the application is to run.
#define DESC_LEN 51

SQLUINTEGER PartID;
SQLCHAR Desc[DESC_LEN];
SQLREAL Price;
SQLINTEGER PartIDInd = 0, DescLenOrInd = SQL_NTS, PriceInd = 0;

// Bind the parameters.


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,
&PartID, 0, &PartIDInd);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, DESC_LEN - 1, 0,
Desc, sizeof(Desc), &DescLenOrInd);
SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 7, 0,
&Price, 0, &PriceInd);

// Loop to continually get new values and insert them.


while (GetNewValues(&PartID, Desc, &Price))
SQLExecDirect(hstmt, "{call InsertPart(?, ?, ?)}", SQL_NTS);

For more information about parameters, prepared statements, and procedures, see Executing a Statement.
SQL Statements Constructed at Run Time
4/27/2022 • 2 minutes to read • Edit Online

Applications that perform ad hoc analysis commonly build SQL statements at run time. For example, a
spreadsheet might allow a user to select columns from which to retrieve data:

// SQL_Statements_Constructed_at_Run_Time.cpp
#include <windows.h>
#include <stdio.h>
#include <sqltypes.h>

int main() {
SQLCHAR *Statement = 0, *TableName = 0;
SQLCHAR **TableNamesArray, **ColumnNamesArray = 0;
BOOL *ColumnSelectedArray = 0;
BOOL CommaNeeded;
SQLSMALLINT i = 0, NumColumns = 0;

// Use SQLTables to build a list of tables (TableNamesArray[]). Let the


// user select a table and store the selected table in TableName.

// Use SQLColumns to build a list of the columns in the selected table


// (ColumnNamesArray). Set NumColumns to the number of columns in the
// table. Let the user select one or more columns and flag these columns
// in ColumnSelectedArray[].

// Build a SELECT statement from the selected columns.


CommaNeeded = FALSE;
Statement = (SQLCHAR*)malloc(8);
strcpy_s((char*)Statement, 8, "SELECT ");

for (i = 0 ; i = NumColumns ; i++) {


if (ColumnSelectedArray[i]) {
if (CommaNeeded)
strcat_s((char*)Statement, sizeof(Statement), ",");
else
CommaNeeded = TRUE;
strcat_s((char*)Statement, sizeof(Statement), (char*)ColumnNamesArray[i]);
}
}

strcat_s((char*)Statement, 15, " FROM ");


// strcat_s((char*)Statement, 100, (char*)TableName);

// Execute the statement . It will be executed once, do not prepare it.


// SQLExecDirect(hstmt, Statement, SQL_NTS);
}

Another class of applications that commonly constructs SQL statements at run time are application
development environments. However, the statements they construct are hard-coded in the application they are
building, where they can usually be optimized and tested.
Applications that construct SQL statements at run time can provide tremendous flexibility to the user. As can be
seen from the preceding example, which did not even support such common operations as WHERE clauses,
ORDER BY clauses, or joins, constructing SQL statements at run time is vastly more complex than hard-coding
statements. Furthermore, testing such applications is problematic because they can construct an arbitrary
number of SQL statements.
A potential disadvantage of constructing SQL statements at run time is that it takes far more time to construct a
statement than use a hard-coded statement. Fortunately, this is rarely a concern. Such applications tend to be
user-interface intensive, and the time the application spends constructing SQL statements is generally small
compared to the time the user spends entering criteria.
SQL Statements Entered by the User
4/27/2022 • 2 minutes to read • Edit Online

Applications that perform ad hoc analysis also commonly allow the user to enter SQL statements directly. For
example:

SQLCHAR * Statement, SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH];


SQLSMALLINT i, MsgLen;
SQLINTEGER NativeError;
SQLRETURN rc1, rc2;

// Prompt user for SQL statement.


GetSQLStatement(Statement);

// Execute the statement directly. Because it will be executed only once,


// do not prepare it.
rc1 = SQLExecDirect(hstmt, Statement, SQL_NTS);

// Process any errors or returned information.


if ((rc1 == SQL_ERROR) || rc1 == SQL_SUCCESS_WITH_INFO) {
i = 1;
while ((rc2 = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError,
Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA) {
DisplayError(SqlState, NativeError, Msg, MsgLen);
i++;
}
}

This approach simplifies application coding; the application relies on the user to build the SQL statement and on
the data source to check the statement's validity. Because it's difficult to write a graphical user interface that
adequately exposes the intricacies of SQL, simply asking the user to enter the SQL statement text may be a
preferable alternative. However, this requires the user to know not only SQL but also the schema of the data
source being queried. Some applications provide a graphical user interface by which the user can create a basic
SQL statement and also provide a text interface with which the user can modify it.
Interoperability of SQL Statements
4/27/2022 • 2 minutes to read • Edit Online

Like the rest of an application, SQL statements can be interoperable or DBMS-specific. And like the rest of the
application, the choice of how interoperable SQL statements need to be depends on the type of application.
Custom applications are less likely to use interoperable SQL statements because they are usually designed to
exploit the capabilities of one or possibly two DBMSs. Generic applications use interoperable SQL statements
because they are designed to work with a variety of DBMSs. And vertical applications usually fall somewhere in
between, demanding a certain level of functionality but otherwise using interoperable SQL statements.
This section contains the following topics.
Choosing an SQL Grammar
Constructing Interoperable SQL Statements
Choosing an SQL Grammar
4/27/2022 • 2 minutes to read • Edit Online

The first decision to make when constructing SQL statements is which grammar to use. In addition to the
grammars available from the various standards bodies, such as Open Group, ANSI, and ISO, virtually every
DBMS vendor defines its own grammar, each of which varies slightly from the standard.
Appendix C: SQL Grammar, describes the minimum SQL grammar that all ODBC drivers must support. This
grammar is a subset of the Entry level of SQL-92. Drivers may support additional grammar to conform to the
Intermediate, Full, or FIPS 127-2 Transitional levels defined by SQL-92. For more information, see SQL Minimum
Grammar in Appendix C: SQL Grammar, and SQL-92.
Appendix C also defines escape sequences containing standard grammar for commonly available language
features, such as outer joins, that are not covered by the SQL-92 grammar. For more information, see ODBC
Escape Sequences in Appendix C: SQL Grammar, and Escape Sequences, later in this section.
The grammar that is chosen affects how the driver processes the statement. Drivers must modify SQL-92 SQL
and the ODBC-defined escape sequences to DBMS-specific SQL. Because most SQL grammars are based on one
or more of the various standards, most drivers do little or no work to meet this requirement. It often consists
only of searching for the escape sequences defined by ODBC and replacing them with DBMS-specific grammar.
When a driver encounters grammar it does not recognize, it assumes the grammar is DBMS-specific and passes
the SQL statement without modification to the data source for execution.
Therefore, there are really two choices of grammar to use: the SQL-92 grammar (and the ODBC escape
sequences) and a DBMS-specific grammar. Of the two, only the SQL-92 grammar is interoperable, so all
interoperable applications should use it. Applications that are not interoperable can use the SQL-92 grammar or
a DBMS-specific grammar. DBMS-specific grammars have two advantages: They can exploit any features not
covered by SQL-92, and they are marginally faster because the driver does not have to modify them. The latter
feature can be partially enforced by setting the SQL_ATTR_NOSCAN statement attribute, which stops the driver
from searching for and replacing escape sequences.
If the SQL-92 grammar is used, the application can discover how it is modified by the driver by calling
SQLNativeSql . This is often useful when debugging applications. SQLNativeSql accepts an SQL statement
and returns it after the driver has modified it. Because this function is in the Core interface conformance level, it
is supported by all drivers.
Constructing Interoperable SQL Statements
4/27/2022 • 2 minutes to read • Edit Online

As mentioned in the previous sections, interoperable applications should use the ODBC SQL grammar. Beyond
using this grammar, however, a number of additional problems are faced by interoperable applications. For
example, what does an application do if it wants to use a feature, such as outer joins, that is not supported by all
data sources?
At this point, the application writer must make some decisions about which language features are required and
which are optional. In most cases, if a particular driver does not support a feature required by the application,
the application simply refuses to run with that driver. However, if the feature is optional, the application can work
around the feature. For example, it might disable those parts of the interface that allow the user to use the
feature.
To determine which features are supported, applications start by calling SQLGetInfo with the
SQL_SQL_CONFORMANCE option. The SQL conformance level gives the application a broad view of which SQL
is supported. To refine this view, the application calls SQLGetInfo with any of a number of other options. For a
complete list of these options, see the SQLGetInfo function description. Finally, SQLGetTypeInfo returns
information about the data types supported by the data source. The following sections list a number of possible
factors that applications should watch for when constructing interoperable SQL statements.
This section contains the following topics.
Catalog and Schema Usage
Catalog Position
Quoted Identifiers
Identifier Case
Escape Sequences
Literal Prefixes and Suffixes
Parameter Markers in Procedure Calls
DDL Statements
Catalog and Schema Usage
4/27/2022 • 2 minutes to read • Edit Online

Data sources do not necessarily support catalog and schema names as object name identifiers in all SQL
statements. Data sources might support catalog and schema names in one or more of the following classes of
SQL statements: Data Manipulation Language (DML) statements, procedure calls, table definition statements,
index definition statements, and privilege definition statements. To determine the classes of SQL statements in
which catalog and schema names can be used, an application calls SQLGetInfo with the SQL_CATALOG_USAGE
and SQL_SCHEMA_USAGE options.
Catalog Position
4/27/2022 • 2 minutes to read • Edit Online

The position of a catalog name in an identifier and how it is separated from the rest of the identifier varies from
data source to data source. For example, in an Xbase data source, the catalog name is a directory and, in
Microsoft® Windows®, is separated from the table name (which is a file name) by a backslash (\). The
following illustration demonstrates this condition.

In a SQL Server data source, the catalog is a database and is separated from the schema and table names by a
period (.).

In an Oracle data source, the catalog is also the database but follows the table name and is separated from the
schema and table names by an at sign (@).

To determine the catalog separator and the location of the catalog name, an application calls SQLGetInfo with
the SQL_CATALOG_NAME_SEPARATOR and SQL_CATALOG_LOCATION options. Interoperable applications
should construct identifiers according to these values.
When quoting identifiers that contain more than one part, applications must be careful to quote each part
separately and not quote the character that separates the identifiers. For example, the following statement to
select all of the rows and columns of an Xbase table quotes the catalog (\XBASE\SALES\CORP) and table
(Parts.dbf) names, but not the catalog separator (\):

SELECT * FROM "\XBASE\SALES\CORP"\"PARTS.DBF"

The following statement to select all of the rows and columns of an Oracle table quotes the catalog (Sales),
schema (Corporate), and table (Parts) names, but not the catalog (@) or schema (.) separators:

SELECT * FROM "Corporate"."Parts"@"Sales"

For information about quoting identifiers, see the next section, Quoted Identifiers.
Quoted Identifiers
4/27/2022 • 2 minutes to read • Edit Online

In an SQL statement, identifiers containing special characters or match keywords must be enclosed in identifier
quote characters; identifiers enclosed in such characters are known as quoted identifiers (also known as
delimited identifiers in SQL-92). For example, the Accounts Payable identifier is quoted in the following SELECT
statement:

SELECT * FROM "Accounts Payable"

The reason for quoting identifiers is to make the statement parseable. For example, if Accounts Payable was not
quoted in the previous statement, the parser would assume there were two tables, Accounts and Payable, and
return a syntax error that they were not separated by a comma. The identifier quote character is driver-specific
and is retrieved with the SQL_IDENTIFIER_QUOTE_CHAR option in SQLGetInfo . The lists of special characters
and of keywords are retrieved with the SQL_SPECIAL_CHARACTERS and SQL_KEYWORDS options in
SQLGetInfo .
To be safe, interoperable applications often quote all identifiers except those for pseudo-columns, such as the
ROWID column in Oracle. SQLSpecialColumns returns a list of pseudo-columns. Also, if there are application-
specific restrictions on where special characters can appear in an object name, it is best for interoperable
applications not to use special characters in those positions.
Identifier Case
4/27/2022 • 2 minutes to read • Edit Online

In SQL statements and catalog function arguments, identifiers and quoted identifiers can be either case-sensitive
or not, which an application can determine by calling SQLGetInfo with the SQL_IDENTIFIER_CASE and
SQL_QUOTED_IDENTIFIER_CASE options.
Each of these options has four possible return values: one stating that the identifier or quoted identifier case is
sensitive and three stating that it is not sensitive. The three values that are not case-sensitive further describe
the case in which identifiers are stored in the system catalog. How identifiers are stored in the system catalog is
relevant only for display purposes, such as when an application displays the results of a catalog function; it does
not change the case-sensitivity of identifiers.
Escape Sequences
4/27/2022 • 2 minutes to read • Edit Online

ODBC defines escape sequences containing standard grammar for date, time, timestamp, and datetime interval
literals, scalar function calls, LIKE predicate escape characters, outer joins, and procedure calls. Interoperable
applications should use these sequences whenever possible.
To determine if a driver supports the escape sequences for date, time, timestamp, or datetime interval literals, an
application calls SQLGetTypeInfo . If the data source supports a date, time, timestamp, or datetime interval data
type, it must also support the corresponding escape sequence. To determine whether the other escape
sequences are supported, an application calls SQLGetInfo .
For more information, see Escape Sequences in ODBC, later in this section.
Literal Prefixes and Suffixes
4/27/2022 • 2 minutes to read • Edit Online

In an SQL statement, a literal is a character representation of an actual data value. For example, in the following
statement, ABC, FFFF, and 10 are literals:

SELECT CharCol, BinaryCol, IntegerCol FROM MyTable


WHERE CharCol = 'ABC' AND BinaryCol = 0xFFFF AND IntegerCol = 10

Literals for some data types require special prefixes and suffixes. In the preceding example, the character literal
(ABC) requires a single quotation mark (') as both a prefix and a suffix, the binary literal (FFFF) requires the
characters 0x as a prefix, and the integer literal (10) does not require a prefix or suffix.
For all data types except date, time, and timestamps, interoperable applications should use the values returned
in the LITERAL_PREFIX and LITERAL_SUFFIX columns in the result set created by SQLGetTypeInfo . For date,
time, timestamp, and datetime interval literals, interoperable applications should use the escape sequences
discussed in the preceding section.
Parameter Markers in Procedure Calls
4/27/2022 • 2 minutes to read • Edit Online

When calling procedures that accept parameters, interoperable applications should use parameter markers
instead of literal parameter values. Some data sources do not support the use of literal parameter values in
procedure calls. For more information about parameters, see Statement Parameters. For more information
about calling procedures, see Procedure Calls, later in this section.
DDL Statements
4/27/2022 • 2 minutes to read • Edit Online

Data Definition Language (DDL) statements vary tremendously among DBMSs. ODBC SQL defines statements
for the most common data definition operations: creating and dropping tables, indexes, and views; altering
tables; and granting and revoking privileges. All other DDL statements are data source-specific. Therefore,
interoperable applications cannot perform some data definition operations. In general, this is not a problem,
because such operations tend to be highly DBMS-specific and are best left to the proprietary database
administration software shipped with most DBMSs or the setup program shipped with the driver.
Another problem in data definition is that data type names vary tremendously among DBMSs. Rather than
defining standard data type names and forcing drivers to convert them to DBMS-specific names,
SQLGetTypeInfo provides a way for applications to discover DBMS-specific data type names. Interoperable
applications should use these names in SQL statements to create and alter tables; the names listed in Appendix
C: SQL Grammar, and Appendix D: Data Types, are examples only.
Escape Sequences in ODBC
4/27/2022 • 2 minutes to read • Edit Online

A number of language features, such as outer joins and scalar function calls, are commonly implemented by
DBMSs. However, the syntaxes for these features tend to be DBMS-specific, even when standard syntaxes are
defined by the various standards bodies. Because of this, ODBC defines escape sequences that contain standard
syntaxes for the following language features:
Date, time, timestamp, and datetime interval literals
Scalar functions such as numeric, string, and data type conversion functions
LIKE predicate escape character
Outer joins
Procedure calls
The escape sequence used by ODBC is as follows:

(extension)

Remarks
The escape sequence is recognized and parsed by drivers, which replace the escape sequences with DBMS-
specific grammar. For more information about escape sequence syntax, see ODBC Escape Sequences in
Appendix C: SQL Grammar.

NOTE
In ODBC 2.x, this was the standard syntax of the escape sequence: --(*vendor( vendor-name), product( product-
name) extension *)--
In addition to this syntax, a shorthand syntax was defined of the form: { extension}
In ODBC 3.x, the long form of the escape sequence has been deprecated, and the shorthand form is used exclusively.

Because the escape sequences are mapped by the driver to DBMS-specific syntaxes, an application can use
either the escape sequence or DBMS-specific syntax. However, applications that use the DBMS-specific syntax
will not be interoperable. When using the escape sequence, applications should make sure that the
SQL_ATTR_NOSCAN statement attribute is turned off, which it is by default. Otherwise, the escape sequence will
be sent directly to the data source, where it will generally cause a syntax error.
Drivers support only those escape sequences that they can map to underlying language features. For example, if
the data source does not support outer joins, neither will the driver. To determine which escape sequences are
supported, an application calls SQLGetTypeInfo and SQLGetInfo . For more information, see the next section,
Date, Time, and Timestamp Literals.
This section contains the following topics.
Date, Time, and Timestamp Literals
Scalar Function Calls
LIKE Predicate Escape Character
Outer Joins
Procedure Calls
Date, Time, and Timestamp Literals
4/27/2022 • 2 minutes to read • Edit Online

The escape sequence for date, time, and timestamp literals is


{ -type ' value '}
where literal-type is one of the values listed in the following table.

L IT ERA L -T Y P E M EA N IN G F O RM AT O F VA L UE

d Date yyyy-mm-dd

t Time* hh:mm:ss[1]

ts Timestamp yyyy-mm-dd hh:mm:ss[.f...][1]

[1] The number of digits to the right of the decimal point in a time or timestamp interval literal containing a
seconds component is dependent on the seconds precision, as contained in the SQL_DESC_PRECISION
descriptor field. (For more information, see SQLSetDescField.)
For more information about the date, time, and timestamp escape sequences, see Date, Time, and Timestamp
Escape Sequences in Appendix C: SQL Grammar.
For example, both of the following SQL statements update the open date of sales order 1023 in the Orders table.
The first statement uses the escape sequence syntax. The second statement uses the Oracle Rdb native syntax for
the DATE column and is not interoperable.

UPDATE Orders SET OpenDate={d '1995-01-15'} WHERE OrderID=1023


UPDATE Orders SET OpenDate='15-Jan-1995' WHERE OrderID=1023

The escape sequence for a date, time, or timestamp literal also can be placed in a character variable bound to a
date, time, or timestamp parameter. For example, the following code uses a date parameter bound to a character
variable to update the open date of sales order 1023 in the Orders table:

SQLCHAR OpenDate[56]; // The size of a date literal is 55.


SQLINTEGER OpenDateLenOrInd = SQL_NTS;

// Bind the parameter.


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_TYPE_DATE, 0, 0,
OpenDate, sizeof(OpenDate), &OpenDateLenOrInd);

// Place the date in the OpenDate variable. In addition to the escape


// sequence shown, it would also be possible to use either of the
// strings "{d '1995-01-15'}" and "15-Jan-1995", although the latter
// is data source-specific.
strcpy_s( (char*) OpenDate, _countof(OpenDate), "{d '1995-01-15'}");

// Execute the statement.


SQLExecDirect(hstmt, "UPDATE Orders SET OpenDate=? WHERE OrderID = 1023", SQL_NTS);

However, it is usually more efficient to bind the parameter directly to a date structure:
SQL_DATE_STRUCT OpenDate;
SQLINTEGER OpenDateInd = 0;

// Bind the parameter.


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 0, 0,
&OpenDate, 0, &OpenDateLen);

// Place the date in the dsOpenDate structure.


OpenDate.year = 1995;
OpenDate.month = 1;
OpenDate.day = 15;

// Execute the statement.


SQLExecDirect(hstmt, "UPDATE Employee SET OpenDate=? WHERE OrderID = 1023", SQL_NTS);

To determine whether a driver supports the ODBC escape sequences for date, time, or timestamp literals, an
application calls SQLGetTypeInfo . If the data source supports a date, time, or timestamp data type, it must also
support the corresponding escape sequence.
Data sources can also support the datetime literals defined in the ANSI SQL-92 specification, which are different
from the ODBC escape sequences for date, time, or timestamp literals. To determine whether a data source
supports the ANSI literals, an application calls SQLGetInfo with the SQL_ANSI_SQL_DATETIME_LITERALS
option.
To determine whether a driver supports the ODBC escape sequences for interval literals, an application calls
SQLGetTypeInfo . If the data source supports a datetime interval data type, it must also support the
corresponding escape sequence.
Data sources can also support the datetime literals defined in the ANSI SQL-92 specification, which are different
from the ODBC escape sequences for datetime interval literals. To determine whether a data source supports the
ANSI literals, an application calls SQLGetInfo with the SQL_ANSI_SQL_DATETIME_LITERALS option.
Scalar Function Calls
4/27/2022 • 2 minutes to read • Edit Online

Scalar functions return a value for each row. For example, the absolute value scalar function takes a numeric
column as an argument and returns the absolute value of each value in the column. The escape sequence for
calling a scalar function is
{fn scalar-function }
where scalar-function is one of the functions listed in Appendix E: Scalar Functions. For more information about
the scalar function escape sequence, see Scalar Function Escape Sequence in Appendix C: SQL Grammar.
For example, the following SQL statements create the same result set of uppercase customer names. The first
statement uses the escape-sequence syntax. The second statement uses the native syntax for Ingres for OS/2
and is not interoperable.

SELECT {fn UCASE(Name)} FROM Customers

SELECT uppercase(Name) FROM Customers

An application can mix calls to scalar functions that use native syntax and calls to scalar functions that use ODBC
syntax. For example, assume that names in the Employee table are stored as a last name, a comma, and a first
name. The following SQL statement creates a result set of last names of employees in the Employee table. The
statement uses the ODBC scalar function SUBSTRING and the SQL Server scalar function CHARINDEX and
will execute correctly only on SQL Server.

SELECT {fn SUBSTRING(Name, 1, CHARINDEX(',', Name) - 1)} FROM Customers

For maximum interoperability, applications should use the CONVERT scalar function to make sure that the
output of a scalar function is the required type. The CONVERT function converts data from one SQL data type
to the specified SQL data type. The syntax of the CONVERT function is
CONVERT( value_exp , data_type)
where value_exp is a column name, the result of another scalar function, or a literal value, and data_type is a
keyword that matches the #define name that is used by an SQL data type identifier as defined in Appendix D:
Data Types. For example, the following SQL statement uses the CONVERT function to make sure that the output
of the CURDATE function is a date, instead of a timestamp or character data:

INSERT INTO Orders (OrderID, CustID, OpenDate, SalesPerson, Status)


VALUES (?, ?, {fn CONVERT({fn CURDATE()}, SQL_DATE)}, ?, ?)

To determine which scalar functions are supported by a data source, an application calls SQLGetInfo with the
SQL_CONVERT_FUNCTIONS, SQL_NUMERIC_FUNCTIONS, SQL_STRING_FUNCTIONS,
SQL_SYSTEM_FUNCTIONS, and SQL_TIMEDATE_FUNCTIONS options. To determine which conversion
operations are supported by the CONVERT function, an application calls SQLGetInfo with any of the options
that start with SQL_CONVERT.
LIKE Predicate Escape Character
4/27/2022 • 2 minutes to read • Edit Online

In a LIKE predicate, the percent sign (%) matches zero or more of any character and the underscore (_) matches
any one character. To match an actual percent sign or underscore in a LIKE predicate, an escape character must
come before the percent sign or underscore. The escape sequence that defines the LIKE predicate escape
character is:
{escape ' escape-character '}
where escape-character is any character supported by the data source.
For more information about the LIKE escape sequence, see LIKE Escape Sequence in Appendix C: SQL Grammar.
For example, the following SQL statements create the same result set of customer names that start with the
characters "%AAA". The first statement uses the escape-sequence syntax. The second statement uses the native
syntax for Microsoft® Access and is not interoperable. Notice that the second percent character in each LIKE
predicate is a wildcard character that matches zero or more of any character.

SELECT Name FROM Customers WHERE Name LIKE '\%AAA%' {escape '\'}

SELECT Name FROM Customers WHERE Name LIKE '[%]AAA%'

To determine whether the LIKE predicate escape character is supported by a data source, an application calls
SQLGetInfo with the SQL_LIKE_ESCAPE_CLAUSE option.
Outer Joins
4/27/2022 • 2 minutes to read • Edit Online

ODBC supports the SQL-92 left, right, and full outer join syntax. The escape sequence for outer joins is
{oj outer-join}
where outer-join is
table-reference {LEFT | RIGHT | FULL} OUTER JOIN {table-reference | outer-join} ON search-condition
table-reference specifies a table name, and search-condition specifies the join condition between the table-
references.
An outer join request must appear after the FROM keyword and before the WHERE clause (if one exists). For
complete syntax information, see Outer Join Escape Sequence in Appendix C: SQL Grammar.
For example, the following SQL statements create the same result set that lists all customers and shows which
has open orders. The first statement uses the escape-sequence syntax. The second statement uses the native
syntax for Oracle and is not interoperable.

SELECT Customers.CustID, Customers.Name, Orders.OrderID, Orders.Status


FROM {oj Customers LEFT OUTER JOIN Orders ON Customers.CustID=Orders.CustID}
WHERE Orders.Status='OPEN'

SELECT Customers.CustID, Customers.Name, Orders.OrderID, Orders.Status


FROM Customers, Orders
WHERE (Orders.Status='OPEN') AND (Customers.CustID= Orders.CustID(+))

To determine the types of outer joins that a data source and driver support, an application calls SQLGetInfo
with the SQL_OJ_CAPABILITIES flag. The types of outer joins that might be supported are left, right, full, or
nested outer joins; outer joins in which the column names in the ON clause do not have the same order as their
respective table names in the OUTER JOIN clause; inner joins in conjunction with outer joins; and outer joins
using any ODBC comparison operator. If the SQL_OJ_CAPABILITIES information type returns 0, no outer join
clause is supported.
Procedure Calls
4/27/2022 • 2 minutes to read • Edit Online

A procedure is an executable object stored on the data source. Generally, it is one or more SQL statements that
have been precompiled. The escape sequence for calling a procedure is
{ [?= ]call procedure-name[( [parameter][,[parameter]]...) ]}
where procedure-name specifies the name of a procedure and parameter specifies a procedure parameter.
For more information about the procedure call escape sequence, see Procedure Call Escape Sequence in
Appendix C: SQL Grammar.
A procedure can have zero or more parameters. It can also return a value, as indicated by the optional
parameter marker ?= at the start of the syntax. If parameter is an input or an input/output parameter, it can be a
literal or a parameter marker. However, interoperable applications should always use parameter markers
because some data sources do not accept literal parameter values. If parameter is an output parameter, it must
be a parameter marker. Parameter markers must be bound with SQLBindParameter before the procedure call
statement is executed.
Input and input/output parameters can be omitted from procedure calls. If a procedure is called with
parentheses but without any parameters, such as {call procedure-name()}, the driver instructs the data source to
use the default value for the first parameter. If the procedure does not have any parameters, this might cause the
procedure to fail. If a procedure is called without parentheses, such as {call procedure-name}, the driver does not
send any parameter values.
Literals can be specified for input and input/output parameters in procedure calls. For example, suppose the
procedure Inser tOrder has five input parameters. The following call to Inser tOrder omits the first parameter,
provides a literal for the second parameter, and uses a parameter marker for the third, fourth, and fifth
parameters:

{call InsertOrder(, 10, ?, ?, ?)} // Not interoperable!

Notice that if a parameter is omitted, the comma delimiting it from other parameters must still appear. If an
input or input/output parameter is omitted, the procedure uses the default value of the parameter. Another way
to specify the default value of an input or input/output parameter is to set the value of the length/indicator
buffer bound to the parameter to SQL_DEFAULT_PARAM.
If an input/output parameter is omitted or if a literal is supplied for the parameter, the driver discards the output
value. Similarly, if the parameter marker for the return value of a procedure is omitted, the driver discards the
return value. Finally, if an application specifies a return value parameter for a procedure that does not return a
value, the driver sets the value of the length/indicator buffer bound to the parameter to SQL_NULL_DATA.
Suppose the procedure PARTS_IN_ORDERS creates a result set that contains a list of orders that contain a
particular part number. The following code calls this procedure for part number 544:
SQLUINTEGER PartID;
SQLINTEGER PartIDInd = 0;

// Bind the parameter.


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0,
&PartID, 0, PartIDInd);

// Place the department number in PartID.


PartID = 544;

// Execute the statement.


SQLExecDirect(hstmt, "{call PARTS_IN_ORDERS(?)}", SQL_NTS);

To determine whether a data source supports procedures, an application calls SQLGetInfo with the
SQL_PROCEDURES option.
For more information about procedures, see Procedures.
Executing Statements ODBC
4/27/2022 • 2 minutes to read • Edit Online

ODBC applications perform almost all database access by executing SQL statements. The general sequence of
events is to allocate a statement handle, set any statement attributes, execute the statement, retrieve any results,
and free the statement handle.
This section contains the following topics.
Allocating a Statement Handle
Statement Attributes
Executing a Statement
Statement Parameters
Asynchronous Execution (Polling Method)
Asynchronous Execution (Notification Method)
Freeing a Statement Handle
Allocating a Statement Handle ODBC
4/27/2022 • 2 minutes to read • Edit Online

Before the application can execute a statement, it must allocate a statement handle as follows:
1. The application declares a variable of type HSTMT. It then calls SQL AllocHandle and passes the address
of this variable, the handle of the connection in which to allocate the statement, and the
SQL_HANDLE_STMT option. For example:

SQLHSTMT hstmt1;

SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);

2. The Driver Manager allocates a structure in which to store information about the statement and calls
SQL AllocHandle in the driver with the SQL_HANDLE_STMT option.
3. The driver allocates its own structure in which to store information about the statement and returns the
driver statement handle to the Driver Manager.
4. The Driver Manager returns the Driver Manager statement handle to the application in the application
variable.
The statement handle identifies which statement to use when calling ODBC functions. For more information
about statement handles, see Statement Handles.
Statement Attributes
4/27/2022 • 2 minutes to read • Edit Online

Statement attributes are characteristics of the statement. For example, whether to use bookmarks and what kind
of cursor to use with the statement's result set are statement attributes.
Statement attributes are set with SQLSetStmtAttr and their current settings retrieved with SQLGetStmtAttr .
There is no requirement that an application set any statement attributes; all statement attributes have defaults,
some of which are driver-specific.
When a statement attribute can be set depends on the attribute itself. The SQL_ATTR_CONCURRENCY,
SQL_ATTR_CURSOR_TYPE, SQL_ATTR_SIMULATE_CURSOR, and SQL_ATTR_USE_BOOKMARKS statement
attributes must be set before the statement is executed. The SQL_ATTR_ASYNC_ENABLE and
SQL_ATTR_NOSCAN statement attributes can be set at any time but are not applied until the statement is used
again. SQL_ATTR_MAX_LENGTH, SQL_ATTR_MAX_ROWS, and SQL_ATTR_QUERY_TIMEOUT statement attributes
can be set at any time, but it is driver-specific whether they are applied before the statement is used again. The
remaining statement attributes can be set at any time.

NOTE
The ability to set statement attributes at the connection level by calling SQLSetConnectAttr has been deprecated in
ODBC 3.x. ODBC 3.x applications should never set statement attributes at the connection level. ODBC 3.x drivers need
only support this functionality if they should work with ODBC 2.x applications. For more information, see
SQLSetConnectOption Mapping in Appendix G: Driver Guidelines for Backward Compatibility.
An exception to this is the SQL_ATTR_METADATA_ID and SQL_ATTR_ASYNC_ENABLE attributes, which are both connection
attributes and statement attributes and can be set either at the connection level or the statement level.
None of the statement attributes introduced in ODBC 3.x (except for SQL_ATTR_METADATA_ID) can be set at the
connection level.

For more information, see the SQLSetStmtAttr function description.


Executing a Statement
4/27/2022 • 3 minutes to read • Edit Online

There are four ways to execute a statement, depending on when they are compiled (prepared) by the database
engine and who defines them:
Direct Execution The application defines the SQL statement. It is prepared and executed at run time in a
single step.
Prepared Execution The application defines the SQL statement. It is prepared and executed at run time
in separate steps. The statement can be prepared once and executed multiple times.
Procedures The application can define and compile one or more SQL statements at development time
and store these statements on the data source as a procedure. The procedure is executed one or more
times at run time. The application can enumerate available stored procedures using catalog functions.
Catalog Functions The driver writer creates a function that returns a predefined result set. Usually, this
function submits a predefined SQL statement or calls a procedure created for this purpose. The function
is executed one or more times at run time.
A particular statement (as identified by its statement handle) can be executed any number of times. The
statement can be executed with a variety of different SQL statements, or it can be executed repeatedly with the
same SQL statement. For example, the following code uses the same statement handle (hstmt1) to retrieve and
display the tables in the Sales database. It then reuses this handle to retrieve the columns in a table selected by
the user.

SQLHSTMT hstmt1;
SQLCHAR * Table;

// Create a result set of all tables in the Sales database.


SQLTables(hstmt1, "Sales", SQL_NTS, "sysadmin", SQL_NTS, NULL, 0, NULL, 0);

// Fetch and display the table names; then close the cursor.
// Code not shown.

// Have the user select a particular table.


SelectTable(Table);

// Reuse hstmt1 to create a result set of all columns in Table.


SQLColumns(hstmt1, "Sales", SQL_NTS, "sysadmin", SQL_NTS, Table, SQL_NTS, NULL, 0);

// Fetch and display the column names in Table; then close the cursor.
// Code not shown.

And the following code shows how a single handle is used to repeatedly execute the same statement to delete
rows from a table.
SQLHSTMT hstmt1;
SQLUINTEGER OrderID;
SQLINTEGER OrderIDInd = 0;

// Prepare a statement to delete orders from the Orders table.


SQLPrepare(hstmt1, "DELETE FROM Orders WHERE OrderID = ?", SQL_NTS);

// Bind OrderID to the parameter for the OrderID column.


SQLBindParameter(hstmt1, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,
&OrderID, 0, &OrderIDInd);

// Repeatedly execute hstmt1 with different values of OrderID.


while ((OrderID = GetOrderID()) != 0) {
SQLExecute(hstmt1);
}

For many drivers, allocating statements is an expensive task, so reusing the same statement in this manner is
usually more efficient than freeing existing statements and allocating new ones. Applications that create result
sets on a statement must be careful to close the cursor over the result set before reexecuting the statement; for
more information, see Closing the Cursor.
Reusing statements also forces the application to avoid a limitation in some drivers of the number of statements
that can be active at one time. The exact definition of "active" is driver-specific, but it often refers to any
statement that has been prepared or executed and still has results available. For example, after an INSERT
statement has been prepared, it is generally considered to be active; after a SELECT statement has been
executed and the cursor is still open, it is generally considered to be active; after a CREATE TABLE statement has
been executed, it is not generally considered to be active.
An application determines how many statements can be active on a single connection at one time by calling
SQLGetInfo with the SQL_MAX_CONCURRENT_ACTIVITIES option. An application can use more active
statements than this limit by opening multiple connections to the data source; because connections can be
expensive, however, the effect on performance should be considered.
Applications can limit the amount of time allotted for a statement to execute with the
SQL_ATTR_QUERY_TIMEOUT statement attribute. If the timeout period expires before the data source returns
the result set, the function executing the SQL statement returns SQLSTATE HYT00 (Timeout expired). By default,
there is no timeout.
This section contains the following topics.
Direct Execution
Prepared Execution
Procedures
Batches of SQL Statements
Executing Catalog Functions
Direct Execution ODBC
4/27/2022 • 2 minutes to read • Edit Online

Direct execution is the simplest way to execute a statement. When the statement is submitted for execution, the
data source compiles it into an access plan and then executes that access plan.
Direct execution is commonly used by generic applications that build and execute statements at run time. For
example, the following code builds an SQL statement and executes it a single time:

SQLCHAR *SQLStatement;

// Build an SQL statement.


BuildStatement(SQLStatement);

// Execute the statement.


SQLExecDirect(hstmt, SQLStatement, SQL_NTS);

Direct execution works best for statements that will be executed a single time. Its major drawback is that the SQL
statement is parsed every time it is executed. In addition, the application cannot retrieve information about the
result set created by the statement (if any) until after the statement is executed; this is possible if the statement is
prepared and executed in two separate steps.
To execute a statement directly, the application performs the following actions:
1. Sets the values of any parameters. For more information, see Statement Parameters, later in this section.
2. Calls SQLExecDirect and passes it a string containing the SQL statement.
3. When SQLExecDirect is called, the driver:
Modifies the SQL statement to use the data source's SQL grammar without parsing the statement;
this includes replacing the escape sequences discussed in Escape Sequences in ODBC. The
application can retrieve the modified form of an SQL statement by calling SQLNativeSql . Escape
sequences are not replaced if the SQL_ATTR_NOSCAN statement attribute is set.
Retrieves the current parameter values and converts them as necessary. For more information, see
Statement Parameters, later in this section.
Sends the statement and converted parameter values to the data source for execution.
Returns any errors. These include sequencing or state diagnostics such as SQLSTATE 24000
(Invalid cursor state), syntactic errors such as SQLSTATE 42000 (Syntax error or access violation),
and semantic errors such as SQLSTATE 42S02 (Base table or view not found).
Prepared Execution ODBC
4/27/2022 • 3 minutes to read • Edit Online

Prepared execution is an efficient way to execute a statement more than once. The statement is first compiled, or
prepared, into an access plan. The access plan is then executed one or more times at a later time. For more
information about access plans, see Processing an SQL Statement.
Prepared execution is commonly used by vertical and custom applications to repeatedly execute the same,
parameterized SQL statement. For example, the following code prepares a statement to update the prices of
different parts. It then executes the statement multiple times with different parameter values each time.

SQLREAL Price;
SQLUINTEGER PartID;
SQLINTEGER PartIDInd = 0, PriceInd = 0;

// Prepare a statement to update salaries in the Employees table.


SQLPrepare(hstmt, "UPDATE Parts SET Price = ? WHERE PartID = ?", SQL_NTS);

// Bind Price to the parameter for the Price column and PartID to
// the parameter for the PartID column.
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 7, 0,
&Price, 0, &PriceInd);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 10, 0,
&PartID, 0, &PartIDInd);

// Repeatedly execute the statement.


while (GetPrice(&PartID, &Price)) {
SQLExecute(hstmt);
}

Prepared execution is faster than direct execution for statements executed more than once, primarily because
the statement is compiled only once; statements executed directly are compiled each time they are executed.
Prepared execution also can provide a reduction in network traffic because the driver can send an access plan
identifier to the data source each time the statement is executed, rather than an entire SQL statement, if the data
source supports access plan identifiers.
The application can retrieve the metadata for the result set after the statement is prepared and before it is
executed. However, returning metadata for prepared, unexecuted statements is expensive for some drivers and
should be avoided by interoperable applications if possible. For more information, see Result Set Metadata.
Prepared execution should not be used for statements executed a single time. For such statements, it is slightly
slower than direct execution because it requires an additional ODBC function call.

IMPORTANT
Committing or rolling back a transaction, either by explicitly calling SQLEndTran or by working in auto-commit mode,
causes some data sources to delete the access plans for all statements on a connection. For more information, see the
SQL_CURSOR_COMMIT_BEHAVIOR and SQL_CURSOR_ROLLBACK_BEHAVIOR options in the SQLGetInfo function
description.

To prepare and execute a statement, the application:


1. Calls SQLPrepare and passes it a string containing the SQL statement.
2. Sets the values of any parameters. Parameters can actually be set before or after preparing the statement.
For more information, see Statement Parameters, later in this section.
3. Calls SQLExecute and does any additional processing that is necessary, such as fetching data.
4. Repeats steps 2 and 3 as necessary.
5. When SQLPrepare is called, the driver:
Modifies the SQL statement to use the data source's SQL grammar without parsing the statement.
This includes replacing the escape sequences discussed in Escape Sequences in ODBC. The
application can retrieve the modified form of an SQL statement by calling SQLNativeSql . Escape
sequences are not replaced if the SQL_ATTR_NOSCAN statement attribute is set.
Sends the statement to the data source for preparation.
Stores the returned access plan identifier for later execution (if the preparation succeeded) or
returns any errors (if the preparation failed). Errors include syntactic errors such as SQLSTATE
42000 (Syntax error or access violation) and semantic errors such as SQLSTATE 42S02 (Base table
or view not found).

NOTE
Some drivers do not return errors at this point but instead return them when the statement is executed or
when catalog functions are called. Thus, SQLPrepare might appear to have succeeded when in fact it has
failed.

6. When SQLExecute is called, the driver:


Retrieves the current parameter values and converts them as necessary. For more information, see
Statement Parameters, later in this section.
Sends the access plan identifier and converted parameter values to the data source.
Returns any errors. These are generally run-time errors such as SQLSTATE 24000 (Invalid cursor
state). However, some drivers return syntactic and semantic errors at this point.
If the data source does not support statement preparation, the driver must emulate it to the extent possible. For
example, the driver might do nothing when SQLPrepare is called and then perform direct execution of the
statement when SQLExecute is called.
If the data source supports syntax checking without execution, the driver might submit the statement for
checking when SQLPrepare is called and submit the statement for execution when SQLExecute is called.
If the driver cannot emulate statement preparation, it stores the statement when SQLPrepare is called and
submits it for execution when SQLExecute is called.
Because emulated statement preparation is not perfect, SQLExecute can return any errors normally returned
by SQLPrepare .
Procedures ODBC
4/27/2022 • 2 minutes to read • Edit Online

A procedure is an executable object stored on the data source. Generally, it is one or more SQL statements that
have been precompiled.
This section contains the following topics.
When to Use Procedures
Executing Procedures
When to Use Procedures
4/27/2022 • 3 minutes to read • Edit Online

There are a number of advantages to using procedures, all based on the fact that using procedures moves SQL
statements from the application to the data source. What is left in the application is an interoperable procedure
call. These advantages include:
Performance Procedures are usually the fastest way to execute SQL statements. Like prepared
execution, the statement is compiled and executed in two separate steps. Unlike prepared execution,
procedures are executed only at run time. They are compiled at a different time.
Business Rules A business rule is a rule about the way in which a company does business. For example,
only someone with the title Sales Person might be allowed to add new sales orders. Placing these rules in
procedures allows individual companies to customize vertical applications by rewriting the procedures
called by the application without having to modify the application code. For example, an order entry
application might call the procedure Inser tOrder with a fixed number of parameters; exactly how
Inser tOrder is implemented can vary from company to company.
Replaceability Closely related to placing business rules in procedures is the fact that procedures can be
replaced without recompiling the application. If a business rule changes after a company has bought and
installed an application, the company can change the procedure containing that rule. From the
application's standpoint, nothing has changed; it still calls a particular procedure to accomplish a
particular task.
DBMS-specific SQL Procedures provide a way for applications to exploit DBMS-specific SQL and still
remain interoperable. For example, a procedure on a DBMS that supports control-of-flow statements in
SQL might trap and recover from errors, while a procedure on a DBMS that does not support control-of-
flow statements might simply return an error.
Procedures sur vive transactions On some data sources, the access plans for all prepared statements
on a connection are deleted when a transaction is committed or rolled back. By placing SQL statements in
procedures, which are permanently stored in the data source, the statements survive the transaction.
Whether the procedures survive in a prepared, partially prepared, or unprepared state is DBMS-specific.
Separate development Procedures can be developed separately from the rest of the application. In
large corporations, this might provide a way to further exploit the skills of highly specialized
programmers. In other words, application programmers can write user-interface code and database
programmers can write procedures.
Procedures are generally used by vertical and custom applications. These applications tend to perform fixed
tasks, and it is possible to hard-code procedure calls in them. For example, an order entry application might call
the procedures Inser tOrder , DeleteOrder , UpdateOrder , and GetOrders .
There is little reason to call procedures from generic applications. Procedures are usually written to perform a
task in the context of a particular application and so have no use to generic applications. For example, a
spreadsheet has no reason to call the Inser tOrder procedure just mentioned. Furthermore, generic
applications should not construct procedures at run time in hopes of providing faster statement execution; not
only is this likely to be slower than prepared or direct execution, it also requires DBMS-specific SQL statements.
An exception to this is application-development environments, which often provide a way for programmers to
build SQL statements that execute procedures and may provide a way for programmers to test procedures.
Such environments call SQLProcedures to list available procedures and SQLProcedureColumns to list the
input, input/output, and output parameters, the procedure return value, and the columns of any result sets
created by a procedure. However, such procedures must be developed beforehand on each data source; doing
so requires DBMS-specific SQL statements.
There are three major disadvantages to using procedures. The first is that procedures must be written and
compiled for each DBMS with which the application is to run. While this is not a problem for custom
applications, it can significantly increase development and maintenance time for vertical applications designed
to run with a number of DBMSs.
The second disadvantage is that many DBMSs do not support procedures. Again, this is most likely to be a
problem for vertical applications designed to run with a number of DBMSs. To determine whether procedures
are supported, an application calls SQLGetInfo with the SQL_PROCEDURES option.
The third disadvantage, which is particularly applicable to application development environments, is that ODBC
does not define a standard grammar for creating procedures. That is, although applications can call procedures
interoperably, they cannot create them interoperably.
Executing Procedures
4/27/2022 • 2 minutes to read • Edit Online

ODBC defines a standard escape sequence for executing procedures. For the syntax of this sequence and a code
example that uses it, see Procedure Calls.
To execute a procedure, an application performs the following actions:
1. Sets the values of any parameters. For more information, see Statement Parameters, later in this section.
2. Calls SQLExecDirect and passes it a string containing the SQL statement that executes the procedure.
This statement can use the escape sequence defined by ODBC or DBMS-specific syntax; statements that
use DBMS-specific syntax are not interoperable.
3. When SQLExecDirect is called, the driver:
Retrieves the current parameter values and converts them as necessary. For more information, see
Statement Parameters, later in this section.
Calls the procedure in the data source and sends it the converted parameter values. How the
driver calls the procedure is driver-specific. For example, it might modify the SQL statement to use
the data source's SQL grammar and submit this statement for execution, or it might call the
procedure directly using a Remote Procedure Call (RPC) mechanism that is defined in the data
stream protocol of the DBMS.
Returns the values of any input/output or output parameters or the procedure return value,
assuming the procedure succeeds. These values might not be available until after all other results
(row counts and result sets) generated by the procedure have been processed. If the procedure
fails, the driver returns any errors.
Batches of SQL Statements
4/27/2022 • 2 minutes to read • Edit Online

A batch of SQL statements is a group of two or more SQL statements or a single SQL statement that has the
same effect as a group of two or more SQL statements. In some implementations, the entire batch statement is
executed before any results are available. This is often more efficient than submitting statements separately,
because network traffic can often be reduced and the data source can sometimes optimize execution of a batch
of SQL statements. In other implementations, calling SQLMoreResults triggers the execution of the next
statement in the batch. ODBC supports the following types of batches:
Explicit Batches An explicit batch is two or more SQL statements separated by semicolons (;). For
example, the following batch of SQL statements opens a new sales order. This requires inserting rows
into both the Orders and Lines tables. Note that there is no semicolon after the last statement.

INSERT INTO Orders (OrderID, CustID, OpenDate, SalesPerson, Status)


VALUES (2002, 1001, {fn CURDATE()}, 'Garcia', 'OPEN');
INSERT INTO Lines (OrderID, Line, PartID, Quantity)
VALUES (2002, 1, 1234, 10);
INSERT INTO Lines (OrderID, Line, PartID, Quantity)
VALUES (2002, 2, 987, 8);
INSERT INTO Lines (OrderID, Line, PartID, Quantity)
VALUES (2002, 3, 566, 17);
INSERT INTO Lines (OrderID, Line, PartID, Quantity)
VALUES (2002, 4, 412, 500)

Procedures If a procedure contains more than one SQL statement, it is considered to be a batch of SQL
statements. For example, the following SQL Server-specific statement creates a procedure that returns a
result set containing information about a customer and a result set listing all the open sales orders for
that customer:

CREATE PROCEDURE GetCustInfo (@CustomerID INT) AS


SELECT * FROM Customers WHERE CustID = @CustomerID
SELECT OrderID FROM Orders
WHERE CustID = @CustomerID AND Status = 'OPEN'

The CREATE PROCEDURE statement itself is not a batch of SQL statements. However, the procedure it
creates is a batch of SQL statements. No semicolons separate the two SELECT statements because the
CREATE PROCEDURE statement is specific to SQL Server, and SQL Server does not require semicolons
to separate multiple statements in a CREATE PROCEDURE statement.
Arrays of Parameters Arrays of parameters can be used with a parameterized SQL statement as an
effective way to perform bulk operations. For example, arrays of parameters can be used with the
following INSERT statement to insert multiple rows into the Lines table while executing only a single
SQL statement:

INSERT INTO Lines (OrderID, Line, PartID, Quantity)


VALUES (?, ?, ?, ?)

If a data source does not support arrays of parameters, the driver can emulate them by executing the SQL
statement once for each set of parameters. For more information, see Statement Parameters and Arrays
of Parameter Values, later in this section.
The different types of batches cannot be mixed in an interoperable manner. That is, how an application
determines the result of executing an explicit batch that includes procedure calls, an explicit batch that uses
arrays of parameters, and a procedure call that uses arrays of parameters is driver-specific.
This section contains the following topics.
Result-Generating and Result-Free Statements
Executing Batches
Errors and Batches
Result-Generating and Result-Free Statements
4/27/2022 • 2 minutes to read • Edit Online

SQL statements can be loosely divided into the following five categories:
Result Set-Generating Statements These are SQL statements that generate a result set. For example, a
SELECT statement.
Row Count-Generating Statements These are SQL statements that generate a count of affected rows.
For example, an UPDATE or DELETE statement.
Data Definition Language (DDL) Statements These are SQL statements that modify the structure of
the database. For example, CREATE TABLE or DROP INDEX .
Context-Changing Statements These are SQL statements that change the context of a database. For
example, the USE and SET statements in SQL Server.
Administrative Statements These are SQL statements used for administrative purposes in a database.
For example, GRANT and REVOKE .
SQL statements in the first two categories are collectively known as result-generating statements. SQL
statements in the latter three categories are collectively known as result-free statements. ODBC defines the
semantics of batches that include only result-generating statements. These semantics vary widely and are
therefore data source-specific. For example, the SQL Server driver does not support dropping an object and
then referring to or re-creating the same object in the same batch. Therefore, the term batch as used in this
manual refers only to batches of result-generating statements.
Executing Batches
4/27/2022 • 2 minutes to read • Edit Online

Before an application executes a batch of statements, it should first check whether they are supported. To do this,
the application calls SQLGetInfo with the SQL_BATCH_SUPPORT, SQL_PARAM_ARRAY_ROW_COUNTS, and
SQL_PARAM_ARRAY_SELECTS options. The first option returns whether row count-generating and result set-
generating statements are supported in explicit batches and procedures, while the latter two options return
information about the availability of row counts and result sets in parameterized execution.
Batches of statements are executed through SQLExecute or SQLExecDirect . For example, the following call
executes an explicit batch of statements to open a new sales order.

SQLCHAR *BatchStmt =
"INSERT INTO Orders (OrderID, CustID, OpenDate, SalesPerson, Status)"
"VALUES (2002, 1001, {fn CURDATE()}, 'Garcia', 'OPEN');"
"INSERT INTO Lines (OrderID, Line, PartID, Quantity) VALUES (2002, 1, 1234, 10);"
"INSERT INTO Lines (OrderID, Line, PartID, Quantity) VALUES (2002, 2, 987, 8);"
"INSERT INTO Lines (OrderID, Line, PartID, Quantity) VALUES (2002, 3, 566, 17);"
"INSERT INTO Lines (OrderID, Line, PartID, Quantity) VALUES (2002, 4, 412, 500)";

SQLExecDirect(hstmt, BatchStmt, SQL_NTS);

When a batch of result-generating statements is executed, it returns one or more row counts or result sets. For
information about how to retrieve these, see Multiple Results.
If a batch of statements includes parameter markers, these are numbered in increasing parameter order as they
are in any other statement. For example, the following batch of statements has parameters numbered from 1
through 21; those in the first INSERT statement are numbered 1 through 5 and those in the last INSERT
statement are numbered 18 through 21.

INSERT INTO Orders (OrderID, CustID, OpenDate, SalesPerson, Status)


VALUES (?, ?, ?, ?, ?);
INSERT INTO Lines (OrderID, Line, PartID, Quantity) VALUES (?, ?, ?, ?);
INSERT INTO Lines (OrderID, Line, PartID, Quantity) VALUES (?, ?, ?, ?);
INSERT INTO Lines (OrderID, Line, PartID, Quantity) VALUES (?, ?, ?, ?);
INSERT INTO Lines (OrderID, Line, PartID, Quantity) VALUES (?, ?, ?, ?);

For more information about parameters, see Statement Parameters, later in this section.
Errors and Batches
4/27/2022 • 2 minutes to read • Edit Online

When an error occurs while executing a batch of SQL statements, one of the following four outcomes are
possible. (Each possible outcome is data source-specific and might even depend on the statements included in
the batch.)
No statements in the batch are executed.
No statements in the batch are executed and the transaction is rolled back.
All of the statements before the error statement are executed.
All of the statements except the error statement are executed.
In the first two cases, SQLExecute and SQLExecDirect return SQL_ERROR. In the latter two cases, they may
return SQL_SUCCESS_WITH_INFO or SQL_SUCCESS, depending on the implementation. In all cases, further
error information can be retrieved with SQLGetDiagField , SQLGetDiagRec , or SQLError . However, the
nature and depth of this information is data source-specific. Furthermore, this information is unlikely to exactly
identify the statement in error.
Executing Catalog Functions
4/27/2022 • 2 minutes to read • Edit Online

Because a catalog function creates a result set, it is equivalent to executing any result set-generating SQL
statement. In fact, catalog functions are often implemented by executing predefined SQL statements or calling
predefined procedures that are shipped with the driver or DBMS. Almost anything that applies to SQL
statements that create result sets also applies to catalog functions. For example, the SQL_ATTR_MAX_ROWS
statement attribute limits the number of rows returned by the catalog function, just as it limits the number of
rows returned by a SELECT statement.
To execute a catalog function, an application just calls the function.
For more information about catalog functions, see Catalog Functions.
Statement Parameters
4/27/2022 • 2 minutes to read • Edit Online

A parameter is a variable in an SQL statement. For example, suppose a Parts table has columns named PartID,
Description, and Price. To add a part without parameters would require constructing an SQL statement such as:

INSERT INTO Parts (PartID, Description, Price) VALUES (2100, 'Drive shaft', 50.00)

Although this statement inserts a new order, it is not a good solution for an order entry application because the
values to insert cannot be hard-coded in the application. An alternative is to construct the SQL statement at run
time, using the values to be inserted. This is also not a good solution, because of the complexity of constructing
statements at run time. The best solution is to replace the elements of the VALUES clause with question marks
(?), or parameter markers:

INSERT INTO Parts (PartID, Description, Price) VALUES (?, ?, ?)

The parameter markers are then bound to application variables. To add a new row, the application has only to
set the values of the variables and execute the statement. The driver then retrieves the current values of the
variables and sends them to the data source. If the statement will be executed multiple times, the application can
make the process even more efficient by preparing the statement.
The statement just shown might be hard-coded in an order entry application to insert a new row. However,
parameter markers are not limited to vertical applications. For any application, they ease the difficulty of
constructing SQL statements at run time by avoiding conversions to and from text. For example, the part ID just
shown is most likely stored in the application as an integer. If the SQL statement is constructed without
parameter markers, the application must convert the part ID to text and the data source must convert it back to
an integer. By using a parameter marker, the application can send the part ID to the driver as an integer, which
usually can send it to the data source as an integer. This saves two conversions. For long data values, this is very
important, because the text forms of such values frequently exceed the allowed length of an SQL statement.
Parameters are valid only in certain places in SQL statements. For example, they are not allowed in the select list
(the list of columns to be returned by a SELECT statement), nor are they allowed as both operands of a binary
operator such as the equal sign (=), because it would be impossible to determine the parameter type. Generally,
parameters are valid only in Data Manipulation Language (DML) statements, and not in Data Definition
Language (DDL) statements. For more information, see Parameter Markers in Appendix C: SQL Grammar.
When the SQL statement invokes a procedure, named parameters can be used. Named parameters are
identified by their names, not by their position in the SQL statement. They can be bound by a call to
SQLBindParameter , but the parameter is identified by the SQL_DESC_NAME field of the IPD (implementation
parameter descriptor), not by the ParameterNumber argument of SQLBindParameter . They can also be bound
by calling SQLSetDescField or SQLSetDescRec . For more information about named parameters, see Binding
Parameters by Name (Named Parameters), later in this section. For more information about descriptors, see
Descriptors.
This section contains the following topics.
Binding Parameters
Setting Parameter Values
Sending Long Data
Retrieving Output Parameters by SQLGetData
Procedure Parameters
Arrays of Parameter Values
Binding Parameters ODBC
4/27/2022 • 2 minutes to read • Edit Online

Each parameter in an SQL statement must be associated, or bound, to a variable in the application before the
statement is executed. When the application binds a variable to a parameter, it describes that variable - address,
C data type, and so on - to the driver. It also describes the parameter itself - SQL data type, precision, and so on.
The driver stores this information in the structure it maintains for that statement and uses the information to
retrieve the value from the variable when the statement is executed.
Parameters can be bound or rebound at any time before a statement is executed. If a parameter is rebound after
a statement is executed, the binding does not apply until the statement is executed again. To bind a parameter to
a different variable, an application simply rebinds the parameter with the new variable; the previous binding is
automatically released.
A variable remains bound to a parameter until a different variable is bound to the parameter, until all
parameters are unbound by calling SQLFreeStmt with the SQL_RESET_PARAMS option, or until the statement
is released. For this reason, the application must be sure that variables are not freed until after they are
unbound. For more information, see Allocating and Freeing Buffers.
Because parameter bindings are just information stored in the structure maintained by the driver for the
statement, they can be set in any order. They are also independent of the SQL statement that is executed. For
example, suppose an application binds three parameters and then executes the following SQL statement:

INSERT INTO Parts (PartID, Description, Price) VALUES (?, ?, ?)

If the application then immediately executes the SQL statement

SELECT * FROM Orders WHERE OrderID = ?, OpenDate = ?, Status = ?

on the same statement handle, the parameter bindings for the INSERT statement are used because those are
the bindings stored in the statement structure. In most cases, this is a poor programming practice and should be
avoided. Instead, the application should call SQLFreeStmt with the SQL_RESET_PARAMS option to unbind all
the old parameters and then bind new ones.
This section contains the following topics.
Binding Parameter Markers
Binding Parameters by Name (Named Parameters)
Parameter Binding Offsets
Describing Parameters
Binding Parameter Markers
4/27/2022 • 2 minutes to read • Edit Online

The application binds parameters by calling SQLBindParameter . SQLBindParameter binds one parameter at
a time. With it, the application specifies the following:
The parameter number. Parameters are numbered in increasing parameter order in the SQL statement,
starting with the number 1. While it is legal to specify a parameter number that is higher than the
number of parameters in the SQL statement, the parameter value will be ignored when the statement is
executed.
The parameter type (input, input/output, or output). Except for parameters in procedure calls, all
parameters are input parameters. For more information, see Procedure Parameters, later in this section.
The C data type, address, and byte length of the variable bound to the parameter. The driver must be able
to convert the data from the C data type to the SQL data type or an error is returned. For a list of
supported conversions, see Converting Data from C to SQL Data Types in Appendix D: Data Types.
The SQL data type, precision, and scale of the parameter itself.
The address of a length/indicator buffer. It provides the byte length of binary or character data, specifies
that the data is NULL, or specifies that the data will be sent with SQLPutData . For more information, see
Using Length/Indicator Values.
For example, the following code binds SalesPerson and CustID to parameters for the SalesPerson and CustID
columns. Because SalesPerson contains character data, which is variable length, the code specifies the byte
length of SalesPerson (11) and binds SalesPersonLenOrInd to contain the byte length of the data in SalesPerson.
This information is not necessary for CustID because it contains integer data, which is of fixed length.

SQLCHAR SalesPerson[11];
SQLINTEGER SalesPersonLenOrInd, CustIDInd;
SQLUINTEGER CustID;

// Bind SalesPerson to the parameter for the SalesPerson column and


// CustID to the parameter for the CustID column.
SQLBindParameter(hstmt1, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 10, 0,
SalesPerson, sizeof(SalesPerson), &SalesPersonLenOrInd);
SQLBindParameter(hstmt1, 2, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 10, 0,
&CustID, 0, &CustIDInd);

// Set values of salesperson and customer ID and length/indicators.


strcpy_s((char*)SalesPerson, _countof(SalesPerson), "Garcia");
SalesPersonLenOrInd = SQL_NTS;
CustID = 1331;
CustIDInd = 0;

// Execute a statement to get data for all orders made to the specified
// customer by the specified salesperson.
SQLExecDirect(hstmt1,"SELECT * FROM Orders WHERE SalesPerson=? AND CustID=?",SQL_NTS);

When SQLBindParameter is called, the driver stores this information in the structure for the statement. When
the statement is executed, it uses the information to retrieve the parameter data and send it to the data source.
NOTE
In ODBC 1.0, parameters were bound with SQLSetParam . The Driver Manager maps calls between SQLSetParam and
SQLBindParameter , depending on the versions of ODBC used by the application and driver.
Binding Parameters by Name (Named Parameters)
4/27/2022 • 2 minutes to read • Edit Online

Certain DBMSs allow an application to specify the parameters to a stored procedure by name instead of by
position in the procedure call. Such parameters are called named parameters. ODBC supports the use of named
parameters. In ODBC, named parameters are used only in calls to stored procedures and cannot be used in
other SQL statements.
The driver checks the value of the SQL_DESC_UNNAMED field of the IPD to determine whether named
parameters are used. If SQL_DESC_UNNAMED is not set to SQL_UNNAMED, the driver uses the name in the
SQL_DESC_NAME field of the IPD to identify the parameter. To bind the parameter, an application can call
SQLBindParameter to specify the parameter information and then can call SQLSetDescField to set the
SQL_DESC_NAME field of the IPD. When named parameters are used, the order of the parameter in the
procedure call is not important and the parameter's record number is ignored.
The difference between unnamed parameters and named parameters is in the relationship between the record
number of the descriptor and the parameter number in the procedure. When unnamed parameters are used, the
first parameter marker is related to the first record in the parameter descriptor, which in turn is related to the
first parameter (in creation order) in the procedure call. When named parameters are used, the first parameter
marker is still related to the first record of the parameter descriptor, but the relationship between the record
number of the descriptor and the parameter number in the procedure does not exist anymore. Named
parameters do not use the mapping of the descriptor record number to the procedure parameter position;
instead, the descriptor record name is mapped to the procedure parameter name.

NOTE
If automatic population of the IPD is enabled, the driver will populate the descriptor such that the order of the descriptor
records will match the order of the parameters in the procedure definition, even if named parameters are used.

If a named parameter is used, all parameters must be named parameters. If any parameter is not a named
parameter, then none of the parameters ca be named parameters. If there were a mixture of named parameters
and unnamed parameters, the behavior would be driver-dependent.
As an example of named parameters, suppose a SQL Server stored procedure has been defined as follows:

CREATE PROCEDURE test @title_id int = 1, @quote char(30) AS <blah>

In this procedure, the first parameter, @title_id, has a default value of 1. An application can use the following
code to invoke this procedure such that it specifies only one dynamic parameter. This parameter is a named
parameter with the name "@quote".
// Prepare the procedure invocation statement.
SQLPrepare(hstmt, "{call test(?)}", SQL_NTS);

// Populate record 1 of ipd.


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
30, 0, szQuote, 0, &cbValue);

// Get ipd handle and set the SQL_DESC_NAMED and SQL_DESC_UNNAMED fields
// for record #1.
SQLGetStmtAttr(hstmt, SQL_ATTR_IMP_PARAM_DESC, &hIpd, 0, 0);
SQLSetDescField(hIpd, 1, SQL_DESC_NAME, "@quote", SQL_NTS);

// Assuming that szQuote has been appropriately initialized,


// execute.
SQLExecute(hstmt);
Parameter Binding Offsets
4/27/2022 • 2 minutes to read • Edit Online

An application can specify that an offset is added to bound parameter buffer addresses and the corresponding
length/indicator buffer addresses when SQLExecDirect or SQLExecute is called. The result of these additions
determines the addresses used in these operations.
Bind offsets allow an application to change bindings without calling SQLBindParameter for previously bound
parameters. A call to SQLBindParameter to rebind a parameter changes the buffer address and the
length/indicator pointer. Rebinding with an offset, on the other hand, simply adds an offset to the existing bound
parameter buffer address and length/indicator buffer address. When offsets are used, the bindings are a
"template" of how the application buffers are laid out and the application can move this "template" to different
areas of memory by changing the offset. A new offset can be specified at any time and is always added to the
originally bound values.
To specify a bind offset, the application sets the SQL_ATTR_PARAM_BIND_OFFSET_PTR statement attribute to the
address of an SQLINTEGER buffer. Before the application calls a function that uses the bindings, it places an
offset in bytes in this buffer, as long as neither the parameter buffer address nor the length/indicator buffer
address is 0, and the bound parameter is in the SQL statement. The sum of the address and the offset must be a
valid address. (This means that either or both the offset and the address to which the offset is added can be
invalid, as long as their sum is a valid address.)

NOTE
Binding offsets are not supported by ODBC 2.x drivers.
Describing Parameters
4/27/2022 • 2 minutes to read • Edit Online

SQLBindParameter has arguments that describe the parameter: its SQL type, precision, and scale. The driver
uses this information, or metadata, to convert the parameter value to the type needed by the data source. At first
glance, it might seem that the driver is in a better position to know the parameter metadata than the application;
after all, the driver can easily discover the metadata for a result set column. As it turns out, this is not the case.
First, most data sources do not provide a way for the driver to discover parameter metadata. Second, most
applications already know the metadata.
If an SQL statement is hard-coded in the application, the application writer already knows the type of each
parameter. If an SQL statement is constructed by the application at run time, the application can determine the
metadata as it builds the statement. For example, when the application constructs the clause

WHERE OrderID = ?

it can call SQLColumns for the OrderID column.


The only situation in which the application cannot easily determine the parameter metadata is when the user
enters a parameterized statement. In this case, the application calls SQLPrepare to prepare the statement,
SQLNumParams to determine the number of parameters, and SQLDescribeParam to describe each
parameter. However, as was noted earlier, most data sources do not provide a way for the driver to discover
parameter metadata, so SQLDescribeParam is not widely supported.
Setting Parameter Values
4/27/2022 • 2 minutes to read • Edit Online

To set the value of a parameter, the application simply sets the value of the variable bound to the parameter. It is
not important when this value is set, as long as it is set before the statement is executed. The application can set
the value before or after binding the variable, and it can change the value as many times as it wants. When the
statement is executed, the driver simply retrieves the current value of the variable. This is particularly useful
when a prepared statement is executed more than once; the application sets new values for some or all of the
variables each time the statement is executed. For an example of this, see Prepared Execution, earlier in this
section.
If a length/indicator buffer was bound in the call to SQLBindParameter , it must be set to one of the following
values before the statement is executed:
The byte length of the data in the bound variable. The driver checks this length only if the variable is
character or binary (ValueType is SQL_C_CHAR or SQL_C_BINARY).
SQL_NTS. The data is a null-terminated string.
SQL_NULL_DATA. The data value is NULL, and the driver ignores the value of the bound variable.
SQL_DATA_AT_EXEC or the result of the SQL_LEN_DATA_AT_EXEC macro. The value of the parameter is to
be sent with SQLPutData . For more information, see Sending Long Data, later in this section.
The following table shows the values of the bound variable and the length/indicator buffer that the application
sets for a variety of parameter values.

PA RA M ET ER VA L UE IN VA L UE IN

PA RA M ET ER ( SQ L ) VA RIA B L E ( C ) B O UN D L EN GT H / IN DIC ATO R

VA L UE DATA T Y P E DATA T Y P E VA RIA B L E B UF F ER[ D]

"ABC" SQL_CHAR SQL_C_CHAR ABC\0[a] SQL_NTS or 3

10 SQL_INTEGER SQL_C_SLONG 10 --

10 SQL_INTEGER SQL_C_CHAR 10\0[a] SQL_NTS or 2

1 P.M. SQL_TYPE_TIME SQL_C_TYPE_TIME 13,0,0[b] --

1 P.M. SQL_TYPE_TIME SQL_C_CHAR {t '13:00:00'}\0[a], [c] SQL_NTS or 14

NULL SQL_SMALLINT SQL_C_SSHORT -- SQL_NULL_DATA

[a] "\0" represents a null-termination character. The null-termination character is required only if the value in the
length/indicator buffer is SQL_NTS.
[b] The numbers in this list are the numbers stored in the fields of the TIME_STRUCT structure.
[c] The string uses the ODBC date escape clause. For more information, see Date, Time, and Timestamp Literals.
[d] Drivers must always check this value to see whether it is a special value, such as SQL_NULL_DATA.
What a driver does with a parameter value at execution time is driver-dependent. If necessary, the driver
converts the value from the C data type and byte length of the bound variable to the SQL data type, precision,
and scale of the parameter. In most cases, the driver then sends the value to the data source. In some cases, it
formats the value as text and inserts it into the SQL statement before sending the statement to the data source.
Sending Long Data
4/27/2022 • 3 minutes to read • Edit Online

DBMSs define long data as any character or binary data over a certain size, such as 254 characters. It might not
be possible to store an entire item of long data in memory, such as when the item represents a long text
document or a bitmap. Because such data cannot be stored in a single buffer, the data source sends it to the
driver in parts with SQLPutData when the statement is executed. Parameters for which data is sent at execution
time are known as data-at-execution parameters.

NOTE
An application can actually send any type of data at execution time with SQLPutData , although only character and
binary data can be sent in parts. However, if the data is small enough to fit in a single buffer, there is generally no reason
to use SQLPutData . It is much easier to bind the buffer and let the driver retrieve the data from the buffer.

To send data at execution time, the application performs the following actions:
1. Passes a 32-bit value that identifies the parameter in the ParameterValuePtr argument in
SQLBindParameter rather than passing the address of a buffer. This value is not analyzed by the driver.
It will be returned to the application later, so it should mean something to the application. For example, it
might be the number of the parameter or the handle of a file containing data.
2. Passes the address of a length/indicator buffer in the StrLen_or_IndPtr argument of SQLBindParameter .
3. Stores SQL_DATA_AT_EXEC or the result of the SQL_LEN_DATA_AT_EXEC(length) macro in the
length/indicator buffer. Both of these values indicate to the driver that the data for the parameter will be
sent with SQLPutData . SQL_LEN_DATA_AT_EXEC(length) is used when sending long data to a data
source that needs to know how many bytes of long data will be sent so that it can preallocate space. To
determine if a data source requires this value, the application calls SQLGetInfo with the
SQL_NEED_LONG_DATA_LEN option. All drivers must support this macro; if the data source does not
require the byte length, the driver can ignore it.
4. Calls SQLExecute or SQLExecDirect . The driver discovers that a length/indicator buffer contains the
value SQL_DATA_AT_EXEC or the result of the SQL_LEN_DATA_AT_EXEC(length) macro and returns
SQL_NEED_DATA as the return value of the function.
5. Calls SQLParamData in response to the SQL_NEED_DATA return value. If long data needs to be sent,
SQLParamData returns SQL_NEED_DATA. In the buffer pointed to by the ValuePtrPtr argument, the
driver returns the value that identifies the data-at-execution parameter. If there is more than one data-at-
execution parameter, the application must use this value to determine which parameter to send data for;
the driver is not required to request data for data-at-execution parameters in any particular order.
6. Calls SQLPutData to send the parameter data to the driver. If the parameter data does not fit into a
single buffer, as is often the case with long data, the application calls SQLPutData repeatedly to send the
data in parts; it is up to the driver and data source to reassemble the data. If the application passes null-
terminated string data, the driver or data source must remove the null-termination character as part of
the reassembly process.
7. Calls SQLParamData again to indicate that it has sent all of the data for the parameter. If there are any
data-at-execution parameters for which data has not been sent, the driver returns SQL_NEED_DATA and
the value that identifies the next parameter; the application returns to step 6. If data has been sent for all
data-at-execution parameters, the statement is executed. SQLParamData returns SQL_SUCCESS or
SQL_SUCCESS_WITH_INFO and can return any return value or diagnostic that SQLExecute or
SQLExecDirect can return.
After SQLExecute or SQLExecDirect returns SQL_NEED_DATA and before data has been completely sent for
the last data-at-execution parameter, the statement is in a Need Data state. While a statement is in a Need Data
state, the application can call only SQLPutData , SQLParamData , SQLCancel , SQLGetDiagField , or
SQLGetDiagRec ; all other functions return SQLSTATE HY010 (Function sequence error). Calling SQLCancel
cancels execution of the statement and returns it to its previous state. For more information, see Appendix B:
ODBC State Transition Tables.
For an example of sending data at execution time, see the SQLPutData function description.
Retrieving Output Parameters Using SQLGetData
4/27/2022 • 10 minutes to read • Edit Online

Before ODBC 3.8, an application could only retrieve the output parameters of a query with a bound output
buffer. However, it is difficult to allocate a very large buffer when the size of the parameter value is very large
(for example, a large image). ODBC 3.8 introduces a new way to retrieve output parameters in parts. An
application can now call SQLGetData with a small buffer multiple times to retrieve a large parameter value.
This is similar to retrieving large column data.
To bind an output parameter or input/output parameter to be retrieved in parts, call SQLBindParameter with
the InputOutputType argument set to SQL_PARAM_OUTPUT_STREAM or
SQL_PARAM_INPUT_OUTPUT_STREAM. With SQL_PARAM_INPUT_OUTPUT_STREAM, an application can use
SQLPutData to input data into the parameter, and then use SQLGetData to retrieve the output parameter. The
input data must be in the data-at-execution (DAE) form, using SQLPutData instead of binding it to a
preallocated buffer.
This feature can be used by ODBC 3.8 applications or recompiled ODBC 3.x and ODBC 2.x applications, and
these applications must have an ODBC 3.8 driver that supports retrieving output parameters using
SQLGetData and ODBC 3.8 Driver Manager. For information about how to enable an older application to use
new ODBC features, see Compatibility Matrix.

Usage Example
For example, consider executing a stored procedure, {CALL sp_f(?,?)} , where both parameters are bound as
SQL_PARAM_OUTPUT_STREAM, and the stored procedure returns no result set (later in this topic you will find a
more complex scenario):
1. For each parameter, call SQLBindParameter with InputOutputType set to
SQL_PARAM_OUTPUT_STREAM and ParameterValuePtr set to a token, such as a parameter number, a
pointer to data, or a pointer to a structure that the application uses to bind input parameters. This
example will use the parameter ordinal as the token.
2. Execute the query with SQLExecDirect or SQLExecute . SQL_PARAM_DATA_AVAILABLE will be returned,
indicating that there are streamed output parameters available for retrieval.
3. Call SQLParamData to get the parameter that is available for retrieval. SQLParamData will return
SQL_PARAM_DATA_AVAILABLE with the token of the first available parameter, which is set in
SQLBindParameter (step 1). The token is returned in the buffer that the ValuePtrPtr points to.
4. Call SQLGetData with the argument Col_or_Param_Num set to the parameter ordinal to retrieve the
data of the first available parameter. If SQLGetData returns SQL_SUCCESS_WITH_INFO and SQLState
01004 (data truncated), and the type is variable length on both the client and server, there is more data to
retrieve from the first available parameter. You can continue to call SQLGetData until it returns
SQL_SUCCESS or SQL_SUCCESS_WITH_INFO with a different SQLState .
5. Repeat step 3 and step 4 to retrieve the current parameter.
6. Call SQLParamData again. If it returns anything except SQL_PARAM_DATA_AVAILABLE, there is no more
streamed parameter data to retrieve, and the return code will be the return code of the next statement
that is executed.
7. Call SQLMoreResults to process the next set of parameters until it returns SQL_NO_DATA.
SQLMoreResults will return SQL_NO_DATA in this example if the statement attribute
SQL_ATTR_PARAMSET_SIZE was set to 1. Otherwise, SQLMoreResults will return
SQL_PARAM_DATA_AVAILABLE to indicate that there are streamed output parameters available for the
next set of parameters to retrieve.
Similar to a DAE input parameter, the token used in the argument ParameterValuePtr in SQLBindParameter
(step 1) can be a pointer that points to an application data structure, which contains the ordinal of the parameter
and more application-specific information, if necessary.
The order of the returned streamed output or input/output parameters is driver specific and might not always
be the same as the order specified in the query.
If the application does not call SQLGetData in step 4, the parameter value is discarded. Similarly, if the
application calls SQLParamData before all of a parameter value has been read by SQLGetData , the remainder
of the value is discarded, and the application can process the next parameter.
If the application calls SQLMoreResults before all streamed output parameters are processed
(SQLParamData does still return SQL_PARAM_DATA_AVAILABLE), all remaining parameters are discarded.
Similarly, if the application calls SQLMoreResults before all of a parameter value has been read by
SQLGetData , the remainder of the value and all remaining parameters are discarded, and the application can
continue to process the next parameter set.
Note that an application can specify the C data type in both SQLBindParameter and SQLGetData . The C data
type specified with SQLGetData overrides the C data type specified in SQLBindParameter , unless the C data
type specified in SQLGetData is SQL_APD_TYPE.
Although a streamed output parameter is more useful when the data type of the output parameter is of type
BLOB, this functionality can also be used with any data type. The data types supported by streamed output
parameters are specified in the driver.
If there are SQL_PARAM_INPUT_OUTPUT_STREAM parameters to be processed, SQLExecute or
SQLExecDirect will return SQL_NEED_DATA first. An application can call SQLParamData and SQLPutData to
send DAE parameter data. When all DAE input parameters are processed, SQLParamData returns
SQL_PARAM_DATA_AVAILABLE to indicate streamed output parameters are available.
When there are streamed output parameters and bound output parameters to be processed, the driver
determines the order for processing output parameters. So, if an output parameter is bound to a buffer (the
SQLBindParameter parameter InputOutputType is set to SQL_PARAM_INPUT_OUTPUT or
SQL_PARAM_OUTPUT), the buffer may not be populated until SQLParamData returns SQL_SUCCESS or
SQL_SUCCESS_WITH_INFO. An application should read a bound buffer only after SQLParamData returns
SQL_SUCCESS or SQL_SUCCESS_WITH_INFO that is after all streamed output parameters are processed.
The data source can return a warning and result set, in addition to the streamed output parameter. In general,
warnings and result sets are processed separately from a streamed output parameter by calling
SQLMoreResults . Process warnings and the result set before processing the streamed output parameter.
The following table describes different scenarios of a single command sent to the server, and how the
application should work.

RET URN VA L UE F RO M SQ L EXEC UT E O R


SC EN A RIO SQ L EXEC DIREC T W H AT TO DO N EXT

Data only includes streamed output SQL_PARAM_DATA_AVAILABLE Use SQLParamData and


parameters SQLGetData to retrieve streamed
output parameters.
RET URN VA L UE F RO M SQ L EXEC UT E O R
SC EN A RIO SQ L EXEC DIREC T W H AT TO DO N EXT

Data includes a result set and SQL_SUCCESS Retrieve the result set with
streamed output parameters SQLBindCol and SQLGetData .

Call SQLMoreResults to start


processing streamed output
parameters. It should return
SQL_PARAM_DATA_AVAILABLE.

Use SQLParamData and


SQLGetData to retrieve streamed
output parameters.

Data includes a warning message and SQL_SUCCESS_WITH_INFO Use SQLGetDiagRec and


streamed output parameters SQLGetDiagField to process warning
messages.

Call SQLMoreResults to start


processing streamed output
parameters. It should return
SQL_PARAM_DATA_AVAILABLE.

Use SQLParamData and


SQLGetData to retrieve streamed
output parameters.

Data includes a warning message, SQL_SUCCESS_WITH_INFO Use SQLGetDiagRec and


result set and streamed output SQLGetDiagField to process warning
parameters messages. Then call SQLMoreResults
to start processing the result set.

Retrieve a result set with SQLBindCol


and SQLGetData .

Call SQLMoreResults to start


processing streamed output
parameters. SQLMoreResults should
return SQL_PARAM_DATA_AVAILABLE.

Use SQLParamData and


SQLGetData to retrieve streamed
output parameters.
RET URN VA L UE F RO M SQ L EXEC UT E O R
SC EN A RIO SQ L EXEC DIREC T W H AT TO DO N EXT

Query with DAE input parameters, for SQL NEED_DATA Call SQLParamData and
example, a streamed input/output SQLPutData to send DAE input
(DAE) parameter parameter data.

After all DAE input parameters are


processed, SQLParamData can return
any return code that SQLExecute and
SQLExecDirect can return. The cases
in this table can then be applied.

If the return code is


SQL_PARAM_DATA_AVAILABLE,
streamed output parameters are
available. An application must call
SQLParamData again to retrieve the
token for the streamed output
parameter, as described in the first row
of this table.

If the return code is SQL_SUCCESS,


either there is a result set to process or
the processing is complete.

If the return code is


SQL_SUCCESS_WITH_INFO, there are
warning messages to process.

After SQLExecute , SQLExecDirect , or SQLMoreResults returns SQL_PARAM_DATA_AVAILABLE, a function


sequence error will result if an application calls a function that is not in the following list:
SQL AllocHandle / SQL AllocHandleStd
SQLDataSources / SQLDrivers
SQLGetInfo / SQLGetFunctions
SQLGetConnectAttr / SQLGetEnvAttr / SQLGetDescField / SQLGetDescRec
SQLNumParams
SQLDescribeParam
SQLNativeSql
SQLParamData
SQLMoreResults
SQLGetDiagField / SQLGetDiagRec
SQLCancel
SQLCancelHandle (with statement handle)
SQLFreeStmt (with Option = SQL_CLOSE, SQL_DROP or SQL_UNBIND)
SQLCloseCursor
SQLDisconnect
SQLFreeHandle (with HandleType = SQL_HANDLE_STMT)
SQLGetStmtAttr
Applications can still use SQLSetDescField or SQLSetDescRec to set the binding information. Field mapping
will not be changed. However, fields inside the descriptor might return new values. For example,
SQL_DESC_PARAMETER_TYPE might return SQL_PARAM_INPUT_OUTPUT_STREAM or
SQL_PARAM_OUTPUT_STREAM.

Usage Scenario: Retrieve an Image in Parts from a Result Set


SQLGetData can be used to get data in parts when a stored procedure returns a result set that contains one
row of metadata about an image and the image is returned in a large output parameter.

// CREATE PROCEDURE SP_TestOutputPara


// @ID_of_picture as int,
// @Picture as varbinary(max) out
// AS
// output the image data through streamed output parameter
// GO
BOOL displayPicture(SQLUINTEGER idOfPicture, SQLHSTMT hstmt) {
SQLLEN lengthOfPicture; // The actual length of the picture.
BYTE smallBuffer[100]; // A very small buffer.
SQLRETURN retcode, retcode2;

// Bind the first parameter (input parameter)


SQLBindParameter(
hstmt,
1, // The first parameter.
SQL_PARAM_INPUT, // Input parameter: The ID_of_picture.
SQL_C_ULONG, // The C Data Type.
SQL_INTEGER, // The SQL Data Type.
0, // ColumnSize is ignored for integer.
0, // DecimalDigits is ignored for integer.
&idOfPicture, // The Address of the buffer for the input parameter.
0, // BufferLength is ignored for integer.
NULL); // This is ignored for integer.

// Bind the streamed output parameter.


SQLBindParameter(
hstmt,
2, // The second parameter.
SQL_PARAM_OUTPUT_STREAM, // A streamed output parameter.
SQL_C_BINARY, // The C Data Type.
SQL_VARBINARY, // The SQL Data Type.
0, // ColumnSize: The maximum size of varbinary(max).
0, // DecimalDigits is ignored for binary type.
(SQLPOINTER)2, // ParameterValuePtr: An application-defined
// token (this will be returned from SQLParamData).
// In this example, we used the ordinal
// of the parameter.
0, // BufferLength is ignored for streamed output parameters.
&lengthOfPicture); // StrLen_or_IndPtr: The status variable returned.

retcode = SQLPrepare(hstmt, L"{call SP_TestOutputPara(?, ?)}", SQL_NTS);


if ( retcode == SQL_ERROR )
return FALSE;

retcode = SQLExecute(hstmt);
if ( retcode == SQL_ERROR )
return FALSE;

// Assume that the retrieved picture exists. Use SQLBindCol or SQLGetData to retrieve the result-set.

// Process the result set and move to the streamed output parameters.
retcode = SQLMoreResults( hstmt );

// SQLGetData retrieves and displays the picture in parts.


// SQLGetData retrieves and displays the picture in parts.
// The streamed output parameter is available.
while (retcode == SQL_PARAM_DATA_AVAILABLE) {
SQLPOINTER token; // Output by SQLParamData.
SQLLEN cbLeft; // #bytes remained
retcode = SQLParamData(hstmt, &token); // returned token is 2 (according to the binding)
if ( retcode == SQL_PARAM_DATA_AVAILABLE ) {
// A do-while loop retrieves the picture in parts.
do {
retcode2 = SQLGetData(
hstmt,
(UWORD) token, // the value of the token is the ordinal.
SQL_C_BINARY, // The C-type.
smallBuffer, // A small buffer.
sizeof(smallBuffer), // The size of the buffer.
&cbLeft); // How much data we can get.
}
while ( retcode2 == SQL_SUCCESS_WITH_INFO );
}
}

return TRUE;
}

Usage Scenario: Send and Receive a Large Object as a Streamed


Input/Output Parameter
SQLGetData can be used to get and send data in parts when a stored procedure passes a large object as an
input/output parameter, streaming the value to and from the database. You do not have to store all of the data in
memory.

// CREATE PROCEDURE SP_TestInOut


// @picture as varbinary(max) out
// AS
// output the image data through output parameter
// go

BOOL displaySimilarPicture(BYTE* image, ULONG lengthOfImage, SQLHSTMT hstmt) {


BYTE smallBuffer[100]; // A very small buffer.
SQLRETURN retcode, retcode2;
SQLLEN statusOfPicture;

// First bind the parameters, before preparing the statement that binds the output streamed parameter.
SQLBindParameter(
hstmt,
1, // The first parameter.
SQL_PARAM_INPUT_OUTPUT_STREAM, // I/O-streamed parameter: The Picture.
SQL_C_BINARY, // The C Data Type.
SQL_VARBINARY, // The SQL Data Type.
0, // ColumnSize: The maximum size of varbinary(max).
0, // DecimalDigits is ignored.
(SQLPOINTER)1, // An application defined token.
0, // BufferLength is ignored for streamed I/O parameters.
&statusOfPicture); // The status variable.

statusOfPicture = SQL_DATA_AT_EXEC; // Input data in parts (DAE parameter at input).

retcode = SQLPrepare(hstmt, L"{call SP_TestInOut(?) }", SQL_NTS);


if ( retcode == SQL_ERROR )
return FALSE;

// Execute the statement.


retcode = SQLExecute(hstmt);
if ( retcode == SQL_ERROR )
return FALSE;
if ( retcode == SQL_NEED_DATA ) {
// Use SQLParamData to loop through DAE input parameters. For
// each, use SQLPutData to send the data to database in parts.

// This example uses an I/O parameter with streamed output.


// Therefore, the last call to SQLParamData should return
// SQL_PARAM_DATA_AVAILABLE to indicate the end of the input phrase
// and report that a streamed output parameter is available.

// Assume retcode is set to the return value of the last call to


// SQLParamData, which is equal to SQL_PARAM_DATA_AVAILABLE.
}

// Start processing the streamed output parameters.


while ( retcode == SQL_PARAM_DATA_AVAILABLE ) {
SQLPOINTER token; // Output by SQLParamData.
SQLLEN cbLeft; // #bytes remained
retcode = SQLParamData(hstmt, &token);
if ( retcode == SQL_PARAM_DATA_AVAILABLE ) {
do {
retcode2 = SQLGetData(
hstmt,
(UWORD) token, // the value of the token is the ordinal.
SQL_C_BINARY, // The C-type.
smallBuffer, // A small buffer.
sizeof(smallBuffer), // The size of the buffer.
&cbLeft); // How much data we can get.
}
while ( retcode2 == SQL_SUCCESS_WITH_INFO );
}
}

return TRUE;
}

See Also
Statement Parameters
Procedure Parameters
4/27/2022 • 2 minutes to read • Edit Online

Parameters in procedure calls can be input, input/output, or output parameters. This is different from
parameters in all other SQL statements, which are always input parameters.
Input parameters are used to send values to the procedure. For example, suppose the Parts table has PartID,
Description, and Price columns. The InsertPart procedure might have an input parameter for each column in the
table. For example:

{call InsertPart(?, ?, ?)}

A driver should not modify the contents of an input buffer until SQLExecDirect or SQLExecute returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, SQL_INVALID_HANDLE, or SQL_NO_DATA. The
contents of the input buffer should not be modified while SQLExecDirect or SQLExecute returns
SQL_NEED_DATA or SQL_STILL_EXECUTING.
Input/output parameters are used both to send values to procedures and retrieve values from procedures. Using
the same parameter as both an input and an output parameter tends to be confusing and should be avoided.
For example, suppose a procedure accepts an order ID and returns the ID of the customer. This can be defined
with a single input/output parameter:

{call GetCustID(?)}

It might be better to use two parameters: an input parameter for the order ID and an output or input/output
parameter for the customer ID:

{call GetCustID(?, ?)}

Output parameters are used to retrieve the procedure return value and to retrieve values from procedure
arguments; procedures that return values are sometimes known as functions. For example, suppose the
GetCustID procedure just mentioned returns a value that indicates whether it was able to find the order. In the
following call, the first parameter is an output parameter used to retrieve the procedure return value, the second
parameter is an input parameter used to specify the order ID, and the third parameter is an output parameter
used to retrieve the customer ID:

{? = call GetCustID(?, ?)}

Drivers handle values for input and input/output parameters in procedures no differently than input parameters
in other SQL statements. When the statement is executed, they retrieve the values of the variables bound to
these parameters and send them to the data source.
After the statement has been executed, drivers store the returned values of input/output and output parameters
in the variables bound to those parameters. These returned values are not guaranteed to be set until after all
results returned by the procedure have been fetched and SQLMoreResults has returned SQL_NO_DATA. If
executing the statement results in an error, the contents of the input/output parameter buffer or output
parameter buffer are undefined.
An application calls SQLProcedure to determine whether a procedure has a return value. It calls
SQLProcedureColumns to determine the type (return value, input, input/output, or output) of each procedure
parameter.
Arrays of Parameter Values
4/27/2022 • 2 minutes to read • Edit Online

It is often useful for applications to pass arrays of parameters. For example, using arrays of parameters and a
parameterized INSERT statement, an application can insert a number of rows at once. There are several
advantages to using arrays. First, network traffic is reduced because the data for many statements is sent in a
single packet (if the data source supports parameter arrays natively). Second, some data sources can execute
SQL statements using arrays faster than executing the same number of separate SQL statements. Finally, when
the data is stored in an array, as is often the case for screen data, the application can bind all of the rows in a
particular column with a single call to SQLBindParameter and update them by executing a single statement.
Unfortunately, not many data sources support parameter arrays. However, a driver can emulate parameter
arrays by executing an SQL statement once for each set of parameter values. This can lead to increases in speed
because the driver can then prepare the statement that it plans to execute once for each parameter set. It might
also lead to simpler application code.
This section contains the following topics.
Binding Arrays of Parameters
Using Arrays of Parameters
Binding Arrays of Parameters
4/27/2022 • 5 minutes to read • Edit Online

Applications that use arrays of parameters bind the arrays to the parameters in the SQL statement. There are
two binding styles:
Bind an array to each parameter. Each data structure (array) contains all the data for a single parameter.
This is called column-wise binding because it binds a column of values for a single parameter.
Define a structure to hold the parameter data for an entire set of parameters and bind an array of these
structures. Each data structure contains the data for a single SQL statement. This is called row-wise
binding because it binds a row of parameters.
As when the application binds single variables to parameters, it calls SQLBindParameter to bind arrays to
parameters. The only difference is that the addresses passed are array addresses, not single-variable addresses.
The application sets the SQL_ATTR_PARAM_BIND_TYPE statement attribute to specify whether it is using
column-wise (the default) or row-wise binding. Whether to use column-wise or row-wise binding is largely a
matter of application preference. Depending on how the processor accesses memory, row-wise binding might
be faster. However, the difference is likely to be negligible except for very large numbers of rows of parameters.

Column-Wise Binding
When using column-wise binding, an application binds one or two arrays to each parameter for which data is to
be provided. The first array holds the data values, and the second array holds length/indicator buffers. Each
array contains as many elements as there are values for the parameter.
Column-wise binding is the default. The application also can change from row-wise binding to column-wise
binding by setting the SQL_ATTR_PARAM_BIND_TYPE statement attribute. The following illustration shows how
column-wise binding works.

For example, the following code binds 10-element arrays to parameters for the PartID, Description, and Price
columns, and executes a statement to insert 10 rows. It uses column-wise binding.

#define DESC_LEN 51
#define ARRAY_SIZE 10

SQLCHAR * Statement = "INSERT INTO Parts (PartID, Description, Price) "


"VALUES (?, ?, ?)";
SQLUINTEGER PartIDArray[ARRAY_SIZE];
SQLCHAR DescArray[ARRAY_SIZE][DESC_LEN];
SQLREAL PriceArray[ARRAY_SIZE];
SQLINTEGER PartIDIndArray[ARRAY_SIZE], DescLenOrIndArray[ARRAY_SIZE],
PriceIndArray[ARRAY_SIZE];
SQLUSMALLINT i, ParamStatusArray[ARRAY_SIZE];
SQLUSMALLINT i, ParamStatusArray[ARRAY_SIZE];
SQLULEN ParamsProcessed;

memset(DescLenOrIndArray, 0, sizeof(DescLenOrIndArray));
memset(PartIDIndArray, 0, sizeof(PartIDIndArray));
memset(PriceIndArray, 0, sizeof(PriceIndArray));

// Set the SQL_ATTR_PARAM_BIND_TYPE statement attribute to use


// column-wise binding.
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0);

// Specify the number of elements in each parameter array.


SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, ARRAY_SIZE, 0);

// Specify an array in which to return the status of each set of


// parameters.
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_STATUS_PTR, ParamStatusArray, 0);

// Specify an SQLUINTEGER value in which to return the number of sets of


// parameters processed.
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &ParamsProcessed, 0);

// Bind the parameters in column-wise fashion.


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,
PartIDArray, 0, PartIDIndArray);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, DESC_LEN - 1, 0,
DescArray, DESC_LEN, DescLenOrIndArray);
SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 7, 0,
PriceArray, 0, PriceIndArray);

// Set part ID, description, and price.


for (i = 0; i < ARRAY_SIZE; i++) {
GetNewValues(&PartIDArray[i], DescArray[i], &PriceArray[i]);
PartIDIndArray[i] = 0;
DescLenOrIndArray[i] = SQL_NTS;
PriceIndArray[i] = 0;
}

// Execute the statement.


SQLExecDirect(hstmt, Statement, SQL_NTS);

// Check to see which sets of parameters were processed successfully.


for (i = 0; i < ParamsProcessed; i++) {
printf("Parameter Set Status\n");
printf("------------- -------------\n");
switch (ParamStatusArray[i]) {
case SQL_PARAM_SUCCESS:
case SQL_PARAM_SUCCESS_WITH_INFO:
printf("%13d Success\n", i);
break;

case SQL_PARAM_ERROR:
printf("%13d Error\n", i);
break;

case SQL_PARAM_UNUSED:
printf("%13d Not processed\n", i);
break;

case SQL_PARAM_DIAG_UNAVAILABLE:
printf("%13d Unknown\n", i);
break;

}
}

Row-Wise Binding
When using row-wise binding, an application defines a structure for each set of parameters. The structure
contains one or two elements for each parameter. The first element holds the parameter value, and the second
element holds the length/indicator buffer. The application then allocates an array of these structures, which
contains as many elements as there are values for each parameter.
The application declares the size of the structure to the driver with the SQL_ATTR_PARAM_BIND_TYPE statement
attribute. The application binds the addresses of the parameters in the first structure of the array. Thus, the
driver can calculate the address of the data for a particular row and column as

Address = Bound Address + ((Row Number - 1) * Structure Size) + Offset

where rows are numbered from 1 to the size of the parameter set. The offset, if defined, is the value pointed to
by the SQL_ATTR_PARAM_BIND_OFFSET_PTR statement attribute. The following illustration shows how row-
wise binding works. The parameters can be placed in the structure in any order but are shown in sequential
order for clarity.

The following code creates a structure with elements for the values to store in the PartID, Description, and Price
columns. It then allocates a 10-element array of these structures and binds it to parameters for the PartID,
Description, and Price columns, using row-wise binding. It then executes a statement to insert 10 rows.

#define DESC_LEN 51
#define ARRAY_SIZE 10

typedef tagPartStruct {
SQLREAL Price;
SQLUINTEGER PartID;
SQLCHAR Desc[DESC_LEN];
SQLINTEGER PriceInd;
SQLINTEGER PartIDInd;
SQLINTEGER DescLenOrInd;
} PartStruct;

PartStruct PartArray[ARRAY_SIZE];
SQLCHAR * Statement = "INSERT INTO Parts (PartID, Description,
Price) "
"VALUES (?, ?, ?)";
SQLUSMALLINT i, ParamStatusArray[ARRAY_SIZE];
SQLULEN ParamsProcessed;

// Set the SQL_ATTR_PARAM_BIND_TYPE statement attribute to use


// column-wise binding.
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_BIND_TYPE, sizeof(PartStruct), 0);

// Specify the number of elements in each parameter array.


SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, ARRAY_SIZE, 0);

// Specify an array in which to return the status of each set of


// parameters.
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_STATUS_PTR, ParamStatusArray, 0);
// Specify an SQLUINTEGER value in which to return the number of sets of
// parameters processed.
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &ParamsProcessed, 0);

// Bind the parameters in row-wise fashion.


SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,
&PartArray[0].PartID, 0, &PartArray[0].PartIDInd);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, DESC_LEN - 1, 0,
PartArray[0].Desc, DESC_LEN, &PartArray[0].DescLenOrInd);
SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 7, 0,
&PartArray[0].Price, 0, &PartArray[0].PriceInd);

// Set part ID, description, and price.


for (i = 0; i < ARRAY_SIZE; i++) {
GetNewValues(&PartArray[i].PartID, PartArray[i].Desc, &PartArray[i].Price);
PartArray[0].PartIDInd = 0;
PartArray[0].DescLenOrInd = SQL_NTS;
PartArray[0].PriceInd = 0;
}

// Execute the statement.


SQLExecDirect(hstmt, Statement, SQL_NTS);

// Check to see which sets of parameters were processed successfully.


for (i = 0; i < ParamsProcessed; i++) {
printf("Parameter Set Status\n");
printf("------------- -------------\n");
switch (ParamStatusArray[i]) {
case SQL_PARAM_SUCCESS:
case SQL_PARAM_SUCCESS_WITH_INFO:
printf("%13d Success\n", i);
break;

case SQL_PARAM_ERROR:
printf("%13d Error\n", i);
break;

case SQL_PARAM_UNUSED:
printf("%13d Not processed\n", i);
break;

case SQL_PARAM_DIAG_UNAVAILABLE:
printf("%13d Unknown\n", i);
break;

}
Using Arrays of Parameters
4/27/2022 • 6 minutes to read • Edit Online

To use arrays of parameters, the application calls SQLSetStmtAttr with an Attribute argument of
SQL_ATTR_PARAMSET_SIZE to specify the number of sets of parameters. It calls SQLSetStmtAttr with an
Attribute argument of SQL_ATTR_PARAMS_PROCESSED_PTR to specify the address of a variable in which the
driver can return the number of sets of parameters processed, including error sets. It calls SQLSetStmtAttr
with an Attribute argument of SQL_ATTR_PARAM_STATUS_PTR to point to an array in which to return status
information for each row of parameter values. The driver stores these addresses in the structure it maintains for
the statement.

NOTE
In ODBC 2.x, SQLParamOptions was called to specify multiple values for a parameter. In ODBC 3.x, the call to
SQLParamOptions has been replaced by calls to SQLSetStmtAttr to set the SQL_ATTR_PARAMSET_SIZE and
SQL_ATTR_PARAMS_PROCESSED_ARRAY attributes.

Before executing the statement, the application sets the value of each element of each bound array. When the
statement is executed, the driver uses the information it stored to retrieve the parameter values and send them
to the data source; if possible, the driver should send these values as arrays. Although the use of arrays of
parameters is best implemented by executing the SQL statement with all of the parameters in the array with a
single call to the data source, this capability is not widely available in DBMSs today. However, drivers can
simulate it by executing an SQL statement multiple times, each with a single set of parameters.
Before an application uses arrays of parameters, it must be sure that they are supported by the drivers used by
the application. There are two ways to do this:
Use only drivers known to support arrays of parameters. The application can hard-code the names of
these drivers, or the user can be instructed to use only these drivers. Custom applications and vertical
applications commonly use a limited set of drivers.
Check for support of arrays of parameters at run time. A driver supports arrays of parameters if it is
possible to set the SQL_ATTR_PARAMSET_SIZE statement attribute to a value greater than 1. Generic
applications and vertical applications commonly check for support of arrays of parameters at run time.
The availability of row counts and result sets in parameterized execution can be determined by calling
SQLGetInfo with the SQL_PARAM_ARRAY_ROW_COUNTS and SQL_PARAM_ARRAY_SELECTS options. For
INSERT , UPDATE , and DELETE statements, the SQL_PARAM_ARRAY_ROW_COUNTS option indicates whether
individual row counts (one for each parameter set) are available (SQL_PARC_BATCH) or whether row counts are
rolled up into one (SQL_PARC_NO_BATCH). For SELECT statements, the SQL_PARAM_ARRAY_SELECTS option
indicates whether a result set is available for each set of parameters (SQL_PAS_BATCH) or whether only one
result set is available (SQL_PAS_NO_BATCH). If the driver does not allow result set-generating statements to be
executed with an array of parameters, SQL_PARAM_ARRAY_SELECTS returns SQL_PAS_NO_SELECT. It is data
source-specific whether arrays of parameters can be used with other types of statements, especially because the
use of parameters in these statements would be data source-specific and would not follow ODBC SQL grammar.
The array pointed to by the SQL_ATTR_PARAM_OPERATION_PTR statement attribute can be used to ignore rows
of parameters. If an element of the array is set to SQL_PARAM_IGNORE, the set of parameters corresponding to
that element is excluded from the SQLExecute or SQLExecDirect call. The array pointed to by the
SQL_ATTR_PARAM_OPERATION_PTR attribute is allocated and filled in by the application and read by the driver.
If fetched rows are used as input parameters, the values of the row status array can be used in the parameter
operation array.

Error Processing
If an error occurs while executing the statement, the execution function returns an error and sets the row
number variable to the number of the row containing the error. It is data source-specific whether all rows except
the error set are executed or whether all rows before (but not after) the error set are executed. Because it
processes sets of parameters, the driver sets the buffer specified by the SQL_ATTR_PARAMS_PROCESSED_PTR
statement attribute to the number of the row currently being processed. If all sets except the error set are
executed, the driver sets this buffer to SQL_ATTR_PARAMSET_SIZE after all rows are processed.
If the SQL_ATTR_PARAM_STATUS_PTR statement attribute has been set, SQLExecute or SQLExecDirect returns
the parameter status array, which provides the status of each set of parameters. The parameter status array is
allocated by the application and filled in by the driver. Its elements indicate whether the SQL statement was
executed successfully for the row of parameters or whether an error occurred while processing the set of
parameters. If an error occurred, the driver sets the corresponding value in the parameter status array to
SQL_PARAM_ERROR and returns SQL_SUCCESS_WITH_INFO. The application can check the status array to
determine which rows were processed. Using the row number, the application can often correct the error and
resume processing.
How the parameter status array is used is determined by the SQL_PARAM_ARRAY_ROW_COUNTS and
SQL_PARAM_ARRAY_SELECTS options returned by a call to SQLGetInfo . For INSERT , UPDATE , and DELETE
statements, the parameter status array is filled in with status information if SQL_PARC_BATCH is returned for
SQL_PARAM_ARRAY_ROW_COUNTS, but not if SQL_PARC_NO_BATCH is returned. For SELECT statements, the
parameter status array is filled in if SQL_PAS_BATCH is returned for SQL_PARAM_ARRAY_SELECT, but not if
SQL_PAS_NO_BATCH or SQL_PAS_NO_SELECT is returned.

Data-at-Execution Parameters
If any of the values in the length/indicator array are SQL_DATA_AT_EXEC or the result of the
SQL_LEN_DATA_AT_EXEC(length) macro, the data for those values is sent with SQLPutData in the usual way.
The following aspects of this process bear special comment because they are not readily obvious:
When the driver returns SQL_NEED_DATA, it must set the address of the row number variable to the row
for which it needs data. As in the single-valued case, the application cannot make any assumptions about
the order in which the driver will request parameter values within a single set of parameters. If an error
occurs in the execution of a data-at-execution parameter, the buffer specified by the
SQL_ATTR_PARAMS_PROCESSED_PTR statement attribute is set to the number of the row on which the
error occurred, the status for the row in the row status array specified by the
SQL_ATTR_PARAM_STATUS_PTR statement attribute is set to SQL_PARAM_ERROR, and the call to
SQLExecute , SQLExecDirect , SQLParamData , or SQLPutData returns SQL_ERROR. The contents of
this buffer are undefined if SQLExecute , SQLExecDirect , or SQLParamData return
SQL_STILL_EXECUTING.
Because the driver does not interpret the value in the ParameterValuePtr argument of
SQLBindParameter for data-at-execution parameters, if the application provides a pointer to an array,
SQLParamData does not extract and return an element of this array to the application. Instead, it returns
the scalar value the application had supplied. This means the value returned by SQLParamData is not
sufficient to specify the parameter for which the application needs to send data; the application also
needs to consider the current row number.
When only some of the elements of an array of parameters are data-at-execution parameters, the
application must pass the address of an array in ParameterValuePtr that contains elements for all the
parameters. This array is interpreted normally for the parameters that are not data-at-execution
parameters. For the data-at-execution parameters, the value that SQLParamData provides to the
application, which normally could be used to identify the data that the driver is requesting on this
occasion, is always the address of the array.
Asynchronous Execution
4/27/2022 • 2 minutes to read • Edit Online

ODBC supports asynchronous operations for both statement and connection operations. There are two ways to
determine when an asynchronous operation is complete:
1. Asynchronous Execution (Polling Method)
2. Asynchronous Execution (Notification Method)

See Also
Executing Statements ODBC
Asynchronous Execution (Polling Method)
4/27/2022 • 11 minutes to read • Edit Online

Prior to ODBC 3.8 and the Windows 7 SDK, asynchronous operations were permitted only on statement
functions. For more information, see the Executing Statement Operations Asynchronously , later in this
topic.
ODBC 3.8 in the Windows 7 SDK introduced asynchronous execution on connection-related operations. For
more information, see the Executing Connection Operations Asynchronously section, later in this topic.
In the Windows 7 SDK, for asynchronous statement or connection operations, an application determined that
the asynchronous operation was complete using the polling method. Beginning in the Windows 8 SDK, you can
determine that an asynchronous operation is complete using the notification method. For more information, see
Asynchronous Execution (Notification Method).
By default, drivers execute ODBC functions synchronously; that is, the application calls a function and the driver
does not return control to the application until it has finished executing the function. However, some functions
can be executed asynchronously; that is, the application calls the function, and the driver, after minimal
processing, returns control to the application. The application can then call other functions while the first
function is still executing.
Asynchronous execution is supported for most functions that are largely executed on the data source, such as
the functions to establish connections, prepare and execute SQL statements, retrieve metadata, fetch data, and
commit transactions. It is most useful when the task being executed on the data source takes a long time, such
as a login process or a complex query against a large database.
When the application executes a function with a statement or connection that is enabled for asynchronous
processing, the driver performs a minimal amount of processing (such as checking arguments for errors), hands
processing to the data source, and returns control to the application with the SQL_STILL_EXECUTING return
code. The application then performs other tasks. To determine when the asynchronous function has finished, the
application polls the driver at regular intervals by calling the function with the same arguments as it originally
used. If the function is still executing, it returns SQL_STILL_EXECUTING; if it has finished executing, it returns the
code it would have returned had it executed synchronously, such as SQL_SUCCESS, SQL_ERROR, or
SQL_NEED_DATA.
Whether a function executes synchronously or asynchronously is driver specific. For example, suppose the result
set metadata is cached in the driver. In this case, it takes very little time to execute SQLDescribeCol and the
driver should simply execute the function rather than artificially delay execution. On the other hand, if the driver
needs to retrieve the metadata from the data source, it should return control to the application while it is doing
this. Therefore, the application must be able to handle a return code other than SQL_STILL_EXECUTING when it
first executes a function asynchronously.

Executing Statement Operations Asynchronously


The following statement functions operate on a data source and can execute asynchronously:
SQLBulkOperations
SQLColAttribute
SQLColumnPrivileges
SQLColumns
SQLDescribeCol
SQLDescribeParam
SQLExecDirect
SQLExecute
SQLFetch
SQLFetchScroll
SQLForeignKeys
SQLGetData
SQLGetTypeInfo
SQLMoreResults
SQLNumParams
SQLNumResultCols
SQLParamData
SQLPrepare
SQLPrimaryKeys
SQLProcedureColumns
SQLProcedures
SQLPutData
SQLSetPos
SQLSpecialColumns
SQLStatistics
SQLTablePrivileges
SQLTables
Asynchronous statement execution is controlled on either a per-statement or a per-connection basis, depending
on the data source. That is, the application specifies not that a particular function is to be executed
asynchronously, but that any function executed on a particular statement is to be executed asynchronously. To
find out which one is supported, an application calls SQLGetInfo with an option of SQL_ASYNC_MODE.
SQL_AM_CONNECTION is returned if connection-level asynchronous execution (for a statement handle) is
supported; SQL_AM_STATEMENT if statement-level asynchronous execution is supported.
To specify that functions executed with a particular statement are to be executed asynchronously, the application
calls SQLSetStmtAttr with the SQL_ATTR_ASYNC_ENABLE attribute and sets it to SQL_ASYNC_ENABLE_ON. If
connection-level asynchronous processing is supported, the SQL_ATTR_ASYNC_ENABLE statement attribute is
read-only and its value is the same as the connection attribute of the connection on which the statement was
allocated. It is driver-specific whether the value of the statement attribute is set at statement allocation time or
later. Attempting to set it will return SQL_ERROR and SQLSTATE HYC00 (Optional feature not implemented).
To specify that functions executed with a particular connection are to be executed asynchronously, the
application calls SQLSetConnectAttr with the SQL_ATTR_ASYNC_ENABLE attribute and sets it to
SQL_ASYNC_ENABLE_ON. All future statement handles allocated on the connection will be enabled for
asynchronous execution; it is driver-defined whether existing statement handles will be enabled by this action. If
SQL_ATTR_ASYNC_ENABLE is set to SQL_ASYNC_ENABLE_OFF, all statements on the connection are in
synchronous mode. An error is returned if asynchronous execution is enabled while there is an active statement
on the connection.
To determine the maximum number of active concurrent statements in asynchronous mode that the driver can
support on a given connection, the application calls SQLGetInfo with the
SQL_MAX_ASYNC_CONCURRENT_STATEMENTS option.
The following code demonstrates how the polling model works:
SQLHSTMT hstmt1;
SQLRETURN rc;

// Specify that the statement is to be executed asynchronously.


SQLSetStmtAttr(hstmt1, SQL_ATTR_ASYNC_ENABLE, SQL_ASYNC_ENABLE_ON, 0);

// Execute a SELECT statement asynchronously.


while ((rc=SQLExecDirect(hstmt1,"SELECT * FROM Orders",SQL_NTS))==SQL_STILL_EXECUTING) {
// While the statement is still executing, do something else.
// Do not use hstmt1, because it is being used asynchronously.
}

// When the statement has finished executing, retrieve the results.

While a function is executing asynchronously, the application can call functions on any other statements. The
application can also call functions on any connection, except the one associated with the asynchronous
statement. But the application can only call the original function and the following functions (with the statement
handle or its associated connection, environment handle), after a statement operation returns
SQL_STILL_EXECUTING:
SQLCancel
SQLCancelHandle (on the statement handle)
SQLGetDiagField
SQLGetDiagRec
SQLAllocHandle
SQLGetEnvAttr
SQLGetConnectAttr
SQLDataSources
SQLDrivers
SQLGetInfo
SQLGetFunctions
SQLNativeSql
If the application calls any other function with the asynchronous statement or with the connection associated
with that statement, the function returns SQLSTATE HY010 (Function sequence error), for example.
SQLHDBC hdbc1, hdbc2;
SQLHSTMT hstmt1, hstmt2, hstmt3;
SQLCHAR * SQLStatement = "SELECT * FROM Orders";
SQLUINTEGER InfoValue;
SQLRETURN rc;

SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);


SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt2);
SQLAllocHandle(SQL_HANDLE_STMT, hdbc2, &hstmt3);

// Specify that hstmt1 is to be executed asynchronously.


SQLSetStmtAttr(hstmt1, SQL_ATTR_ASYNC_ENABLE, SQL_ASYNC_ENABLE_ON, 0);

// Execute hstmt1 asynchronously.


while ((rc = SQLExecDirect(hstmt1, SQLStatement, SQL_NTS)) == SQL_STILL_EXECUTING) {
// The following calls return HY010 because the previous call to
// SQLExecDirect is still executing asynchronously on hstmt1. The
// first call uses hstmt1 and the second call uses hdbc1, on which
// hstmt1 is allocated.
SQLExecDirect(hstmt1, SQLStatement, SQL_NTS); // Error!
SQLGetInfo(hdbc1, SQL_UNION, (SQLPOINTER) &InfoValue, 0, NULL); // Error!

// The following calls do not return errors. They use a statement


// handle other than hstmt1 or a connection handle other than hdbc1.
SQLExecDirect(hstmt2, SQLStatement, SQL_NTS); // OK
SQLTables(hstmt3, NULL, 0, NULL, 0, NULL, 0, NULL, 0); // OK
SQLGetInfo(hdbc2, SQL_UNION, (SQLPOINTER) &InfoValue, 0, NULL); // OK
}

When an application calls a function to determine whether it is still executing asynchronously, it must use the
original statement handle. This is because asynchronous execution is tracked on a per-statement basis. The
application must also supply valid values for the other arguments - the original arguments will do - to get past
error checking in the Driver Manager. However, after the driver checks the statement handle and determines that
the statement is executing asynchronously, it ignores all other arguments.
While a function is executing asynchronously - that is, after it has returned SQL_STILL_EXECUTING and before it
returns a different code - the application can cancel it by calling SQLCancel or SQLCancelHandle with the
same statement handle. This is not guaranteed to cancel function execution. For example, the function might
have already finished. Furthermore, the code returned by SQLCancel or SQLCancelHandle only indicates
whether the attempt to cancel the function was successful, not whether it actually canceled the function. To
determine whether the function was canceled, the application calls the function again. If the function was
canceled, it returns SQL_ERROR and SQLSTATE HY008 (Operation canceled). If the function was not canceled, it
returns another code, such as SQL_SUCCESS, SQL_STILL_EXECUTING, or SQL_ERROR with a different SQLSTATE.
To disable asynchronous execution of a particular statement when the driver supports statement-level
asynchronous processing, the application calls SQLSetStmtAttr with the SQL_ATTR_ASYNC_ENABLE attribute
and sets it to SQL_ASYNC_ENABLE_OFF. If the driver supports connection-level asynchronous processing, the
application calls SQLSetConnectAttr to set SQL_ATTR_ASYNC_ENABLE to SQL_ASYNC_ENABLE_OFF, which
disables asynchronous execution of all statements on the connection.
The application should process diagnostic records in the repeating loop of the original function. If
SQLGetDiagField or SQLGetDiagRec is called when an asynchronous function is executing, it will return the
current list of diagnostic records. Each time the original function call is repeated, it clears previous diagnostic
records.

Executing Connection Operations Asynchronously


Before ODBC 3.8, asynchronous execution was allowed for statement-related operations such as prepare,
execute, and fetch, as well as for catalog metadata operations. Starting in ODBC 3.8, asynchronous execution is
also possible for connection-related operations such as connect, disconnect, commit, and rollback.
For more information on ODBC 3.8, see What's New in ODBC 3.8.
Executing connection operations asynchronously is useful in the following scenarios:
When a small number of threads manages a large number of devices with very high data rates. To
maximize responsiveness and scalability it is desirable for all operations to be asynchronous.
When you want to overlap database operations over multiple connections to reduce elapsed transfer
times.
Efficient asynchronous ODBC calls and the ability to cancel connection operations enable an application
to allow the user to cancel any slow operation without having to wait for timeouts.
The following functions, which operate on connection handles, can now be executed asynchronously:
SQLBrowseConnect
SQLConnect
SQLDisconnect
SQLDriverConnect
SQLEndTran
SQLSetConnectAttr
To determine whether a driver supports asynchronous operations on these functions, an application calls
SQLGetInfo with SQL_ASYNC_DBC_FUNCTIONS. SQL_ASYNC_DBC_CAPABLE is returned if asynchronous
operations are supported. SQL_ASYNC_DBC_NOT_CAPABLE is returned if asynchronous operations are not
supported.
To specify that functions executed with a particular connection are to be executed asynchronously, the
application calls SQLSetConnectAttr and sets the SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE attribute to
SQL_ASYNC_DBC_ENABLE_ON. Setting a connection attribute before establishing a connection always executes
synchronously. Also, the operation setting the connection attribute
SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE with SQLSetConnectAttr always executes synchronously.
An application can enable asynchronous operation before making a connection. Because the Driver Manager
cannot determine which driver to use before making a connection, the Driver Manager will always return
success in SQLSetConnectAttr . However, it may fail to connect if the ODBC driver does not support
asynchronous operations.
In general, there can be at most one asynchronously executing function associated with a particular connection
handle or statement handle. However, a connection handle can have more than one associated statement
handle. If there is no asynchronous operation executing on the connection handle, an associated statement
handle can execute an asynchronous operation. Similarly, you can have an asynchronous operation on a
connection handle if there are no asynchronous operations in progress on any associated statement handle. An
attempt to execute an asynchronous operation using a handle that is currently executing an asynchronous
operation will return HY010, "Function sequence error".
If a connection operation returns SQL_STILL_EXECUTING, an application can only call the original function and
the following functions for that connection handle:
SQLCancelHandle (on the connection handle)
SQLGetDiagField
SQLGetDiagRec
SQL AllocHandle (allocating ENV/DBC)
SQL AllocHandleStd (allocating ENV/DBC)
SQLGetEnvAttr
SQLGetConnectAttr
SQLDataSources
SQLDrivers
SQLGetInfo
SQLGetFunctions
The application should process diagnostic records in the repeating loop of the original function. If
SQLGetDiagField or SQLGetDiagRec is called when an asynchronous function is executing, it will return the
current list of diagnostic records. Each time the original function call is repeated, it clears previous diagnostic
records.
If a connection is being opened or closed asynchronously, the operation is complete when the application
receives SQL_SUCCESS or SQL_SUCCESS_WITH_INFO in the original function call.
A new function has been added to ODBC 3.8, SQLCancelHandle . This function cancels the six connection
functions (SQLBrowseConnect , SQLConnect , SQLDisconnect , SQLDriverConnect , SQLEndTran , and
SQLSetConnectAttr ). An application should call SQLGetFunctions to determine if the driver supports
SQLCancelHandle . As with SQLCancel , if SQLCancelHandle returns success, it does not mean the operation
was canceled. An application should call the original function again to determine if the operation was canceled.
SQLCancelHandle lets you cancel asynchronous operations on connection handles or statement handles.
Using SQLCancelHandle to cancel an operation on a statement handle is the same as calling SQLCancel .
It is not necessary to support both SQLCancelHandle and asynchronous connection operations at the same
time. A driver can support asynchronous connection operations but not SQLCancelHandle , or vice versa.
Asynchronous connection operations and SQLCancelHandle can also be used by ODBC 3.x and ODBC 2.x
applications with an ODBC 3.8 driver and ODBC 3.8 Driver Manager. For information about for how to enable an
older application to use new features in later ODBC version, see Compatibility Matrix.
Connection Pooling
Whenever connection pooling is enabled, asynchronous operations are only minimally supported for
establishing a connection (with SQLConnect and SQLDriverConnect ) and closing a connection with
SQLDisconnect . But an application should still be able to handle the SQL_STILL_EXECUTING return value from
SQLConnect , SQLDriverConnect , and SQLDisconnect .
When connection pooling is enabled, SQLEndTran and SQLSetConnectAttr are supported for asynchronous
operations.

Examples
A. Enable asynchronous execution of connection functions
The following example shows how to use SQLSetConnectAttr to enable asynchronous execution for
connection-related functions.
BOOL AsyncConnect (SQLHANDLE hdbc)
{
SQLRETURN r;
SQLHANDLE hdbc;

// Enable asynchronous execution of connection functions.


// This must be executed synchronously, that is r != SQL_STILL_EXECUTING
r = SQLSetConnectAttr(
hdbc,
SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE,
reinterpret_cast<SQLPOINTER> (SQL_ASYNC_DBC_ENABLE_ON),
0);
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
{
return FALSE;
}

TCHAR szConnStrIn[256] = _T("DSN=AsyncDemo");

r = SQLDriverConnect(hdbc, NULL, (SQLTCHAR *) szConnStrIn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);

if (r == SQL_ERROR)
{
// Use SQLGetDiagRec to process the error.
// If SQLState is HY114, the driver does not support asynchronous execution.
return FALSE;
}

while (r == SQL_STILL_EXECUTING)
{
// Do something else.

// Check for completion, with the same set of arguments.


r = SQLDriverConnect(hdbc, NULL, (SQLTCHAR *) szConnStrIn, SQL_NTS, NULL, 0, NULL,
SQL_DRIVER_NOPROMPT);
}

if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)


{
return FALSE;
}

return TRUE;
}

B. Asynchronous commit operations


This example shows asynchronous commit operations. Rollback operations can also be done this way.
BOOL AsyncCommit ()
{
SQLRETURN r;

// Assume that SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE is SQL_ASYNC_DBC_ENABLE_ON.

r = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);


while (r == SQL_STILL_EXECUTING)
{
// Do something else.

// Check for completion with the same set of arguments.


r = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);
}

if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)


{
return FALSE;
}
return TRUE;
}

See Also
Executing Statements ODBC
Asynchronous Execution (Notification Method)
4/27/2022 • 12 minutes to read • Edit Online

ODBC allows asynchronous execution of connection and statement operations. An application thread can call an
ODBC function in asynchronous mode and the function can return before the operation is complete, allowing
the application thread to perform other tasks. In the Windows 7 SDK, for asynchronous statement or connection
operations, an application determined that the asynchronous operation was complete using the polling method.
For more information, see Asynchronous Execution (Polling Method). Beginning in the Windows 8 SDK, you can
determine that an asynchronous operation is complete using the notification method.
In the polling method, applications need to call the asynchronous function each time it wants the status of the
operation. The notification method is similar to callback and wait in ADO.NET. ODBC, however, uses Win32
events as the notification object.
The ODBC Cursor Library and ODBC asynchronous notification cannot be used at the same time. Setting both
attributes will return an error with SQLSTATE S1119 (Cursor Library and Asynchronous Notification cannot be
enabled at the same time).
See Notification of Asynchronous Function Completion for information for driver developers.

NOTE
The notification method is not supported with cursor library. An application will receive error message if it attempts to
enable cursor library via SQLSetConnectAttr, when the notification method is enabled.

Overview
When an ODBC function is called in asynchronous mode, the control is returned to the calling application
immediately with the return code SQL_STILL_EXECUTING. The application must repeatedly poll the function until
it returns something other than SQL_STILL_EXECUTING. The polling loop increases CPU utilization, causing poor
performance in many asynchronous scenarios.
Whenever the notification model is used, the polling model is disabled. Applications should not call the original
function again. Call SQLCompleteAsync Function to complete the asynchronous operation. If an application calls
the original function again before the asynchronous operation is complete, the call will return SQL_ERROR with
SQLSTATE IM017 (Polling is disabled in Asynchronous Notification Mode).
When using the notification model, the application can call SQLCancel or SQLCancelHandle to cancel a
statement or connection operation. If the cancel request is successful, ODBC will return SQL_SUCCESS. This
message does not indicate that the function was actually canceled; it indicates that the cancel request was
processed. Whether the function is actually canceled is driver-dependent and data source-dependent. When an
operation is canceled, the Driver Manager will still signal the event. The Driver Manager returns SQL_ERROR in
the return code buffer and the state is SQLSTATE HY008 (Operation canceled) to indicate the cancelation is
successful. If the function completed its normal processing, the Driver Manager returns SQL_SUCCESS or
SQL_SUCCESS_WITH_INFO.
Downlevel Behavior
The ODBC Driver Manager version supporting this notification on complete is ODBC 3.81.
A P P L IC AT IO N O DB C
VERSIO N DRIVER M A N A GER VERSIO N DRIVER VERSIO N B EH AVIO R

New application of any ODBC 3.81 ODBC 3.80 Driver Application can use this
ODBC version feature if the driver
supports this feature,
otherwise the Driver
Manager will error out.

New application of any ODBC 3.81 Pre-ODBC 3.80 Driver The Driver Manager will
ODBC version error out if the driver does
not support this feature.

New application of any Pre-ODBC 3.81 Any When the application uses
ODBC version this feature, an old Driver
Manager will regard the
new attributes as driver-
specific attributes, and the
driver should error out. A
new Driver Manager will
not pass these attributes to
the driver.

An application should check the Driver Manager version before using this feature. Otherwise, if a poorly written
driver does not error out and the Driver Manager version is pre ODBC 3.81, behavior is undefined.

Use Cases
This section shows use cases for asynchronous execution and the polling mechanism.
Integrate Data from Multiple ODBC Sources
A data integration application asynchronously fetches data from multiple data sources. Some of the data are
from remote data sources and some data are from local files. The application cannot continue until the
asynchronous operations are completed.
Instead of repeatedly polling an operation to determine if it is complete, the application can create an event
object and associate it with an ODBC connection handle or an ODBC statement handle. The application then calls
operating system synchronization APIs to wait on one event object or many event objects (both ODBC events
and other Windows events). ODBC will signal the event object when the corresponding ODBC asynchronous
operation is completed.
On Windows, Win32 event objects will be used and that will provide the user a unified programming model.
Driver Managers on other platforms can use the event object implementation specific to those platforms.
The following code sample demonstrates the use of connection and statement asynchronous notification:

// This function opens NUMBER_OPERATIONS connections and executes one query on statement of each connection.
// Asynchronous Notification is used

#define NUMBER_OPERATIONS 5
int AsyncNotificationSample(void)
{
RETCODE rc;

SQLHENV hEnv = NULL;


SQLHDBC arhDbc[NUMBER_OPERATIONS] = {NULL};
SQLHSTMT arhStmt[NUMBER_OPERATIONS] = {NULL};

HANDLE arhDBCEvent[NUMBER_OPERATIONS] = {NULL};


RETCODE arrcDBC[NUMBER_OPERATIONS] = {0};
HANDLE arhSTMTEvent[NUMBER_OPERATIONS] = {NULL};
HANDLE arhSTMTEvent[NUMBER_OPERATIONS] = {NULL};
RETCODE arrcSTMT[NUMBER_OPERATIONS] = {0};

rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &hEnv);


if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;

rc = SQLSetEnvAttr(hEnv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3_80,
SQL_IS_INTEGER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;

// Connection operations begin here

// Alloc NUMBER_OPERATIONS connection handles


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &arhDbc[i]);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Enable DBC Async on all connection handles


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc= SQLSetConnectAttr(arhDbc[i], SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE,
(SQLPOINTER)SQL_ASYNC_DBC_ENABLE_ON, SQL_IS_INTEGER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Application must create event objects


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
arhDBCEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial state is not-signaled
if (!arhDBCEvent[i]) goto Cleanup;
}

// Enable notification on all connection handles


// Event
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc= SQLSetConnectAttr(arhDbc[i], SQL_ATTR_ASYNC_DBC_EVENT, arhDBCEvent[i], SQL_IS_POINTER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Initiate connect establishing


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLDriverConnect(arhDbc[i], NULL, (SQLTCHAR*)TEXT("Driver={ODBC Driver 11 for SQL Server};SERVER=dp-
srv-sql2k;DATABASE=pubs;UID=sa;PWD=XYZ;"), SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
}

// Can do some other staff before calling WaitForMultipleObjects


WaitForMultipleObjects(NUMBER_OPERATIONS, arhDBCEvent, TRUE, INFINITE); // Wait All

// Complete connect API calls


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLCompleteAsync(SQL_HANDLE_DBC, arhDbc[i], & arrcDBC[i]);
}

BOOL fFail = FALSE; // Whether some connection openning fails.

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
if ( !SQL_SUCCEEDED(arrcDBC[i]) )
fFail = TRUE;
}

// If some SQLDriverConnect() fail, clean up.


if (fFail)
{
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (SQL_SUCCEEDED(arrcDBC[i]) )
{
SQLDisconnect(arhDbc[i]); // This is also async
}
else
{
SetEvent(arhDBCEvent[i]); // Previous SQLDriverConnect() failed. No need to call
SQLDisconnect().
}
}
WaitForMultipleObjects(NUMBER_OPERATIONS, arhDBCEvent, TRUE, INFINITE);
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (SQL_SUCCEEDED(arrcDBC[i]) )
{
SQLCompleteAsync(SQL_HANDLE_DBC, arhDbc[i], &arrcDBC[i]);; // To Complete
}
}

goto Cleanup;
}

// Statement Operations begin here

// Alloc statement handle


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc = SQLAllocHandle(SQL_HANDLE_STMT, arhDbc[i], &arhStmt[i]);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Enable STMT Async on all statement handles


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc = SQLSetStmtAttr(arhStmt[i], SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_ON,
SQL_IS_INTEGER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Create event objects


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
arhSTMTEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial state is not-
signaled
if (!arhSTMTEvent[i]) goto Cleanup;
}

// Enable notification on all statement handles


// Event
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
rc= SQLSetStmtAttr(arhStmt[i], SQL_ATTR_ASYNC_STMT_EVENT, arhSTMTEvent[i], SQL_IS_POINTER);
if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;
}

// Initiate SQLExecDirect() calls


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLExecDirect(arhStmt[i], (SQLTCHAR*)TEXT("select au_lname, au_fname from authors"), SQL_NTS);
}

// Can do some other staff before calling WaitForMultipleObjects


WaitForMultipleObjects(NUMBER_OPERATIONS, arhSTMTEvent, TRUE, INFINITE); // Wait All

// Now, call SQLCompleteAsync to complete the operation and get return code
// Now, call SQLCompleteAsync to complete the operation and get return code
for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLCompleteAsync(SQL_HANDLE_STMT, arhStmt[i], &arrcSTMT[i]);
}

// Check return values


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if ( !SQL_SUCCEEDED(arrcSTMT[i]) ) goto Cleanup;
}

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
//Do some binding jobs here, set SQL_ATTR_ROW_ARRAY_SIZE
}

// Now, initiate fetching


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLFetch(arhStmt[i]);
}

// Can do some other staff before calling WaitForMultipleObjects


WaitForMultipleObjects(NUMBER_OPERATIONS, arhSTMTEvent, TRUE, INFINITE);

// Now, to complete the operations and get return code


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
SQLCompleteAsync(SQL_HANDLE_STMT, arhStmt[i], &arrcSTMT[i]);
}

// Check return code


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if ( !SQL_SUCCEEDED(arrcSTMT[i]) ) goto Cleanup;
}

// USE fetched data here!!

Cleanup:

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
if (arhStmt[NUMBER_OPERATIONS])
{
SQLFreeHandle(SQL_HANDLE_STMT, arhStmt[i]);
arhStmt[i] = NULL;
}
}

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
if (arhSTMTEvent[i])
{
CloseHandle(arhSTMTEvent[i]);
arhSTMTEvent[i] = NULL;
}
}

for (int i=0; i<NUMBER_OPERATIONS; i++)


{
if (arhDbc[i])
{
SQLFreeHandle(SQL_HANDLE_DBC, arhDbc[i]);
arhDbc[i] = NULL;
}
}

for (int i=0; i<NUMBER_OPERATIONS; i++)


for (int i=0; i<NUMBER_OPERATIONS; i++)
{
if (arhDBCEvent[i])
{
CloseHandle(arhDBCEvent[i]);
arhDBCEvent[i] = NULL;
}
}

if (hEnv)
{
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
hEnv = NULL;
}

return 0;
}

Determining if a Driver Supports Asynchronous Notification


An ODBC application can determine if an ODBC driver supports asynchronous notification by calling
SQLGetInfo. The ODBC Driver Manager will consequently call the SQLGetInfo of the driver with
SQL_ASYNC_NOTIFICATION.

SQLUINTEGER InfoValue;
SQLLEN cbInfoLength;

SQLRETURN retcode;
retcode = SQLGetInfo (hDbc,
SQL_ASYNC_NOTIFICATION,
&InfoValue,
sizeof(InfoValue),
NULL);
if (SQL_SUCCEEDED(retcode))
{
if (SQL_ASYNC_NOTIFICATION_CAPABLE == InfoValue)
{
// The driver supports asynchronous notification
}
else if (SQL_ASYNC_NOTIFICATION_NOT_CAPABLE == InfoValue)
{
// The driver does not support asynchronous notification
}
}

Associating a Win32 Event Handle with an ODBC Handle


Applications are responsible for creating Win32 event objects using the corresponding Win32 functions. An
application can associate one Win32 event handle with one ODBC connection handle or one ODBC statement
handle.
Connection attributes SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE and SQL_ATTR_ASYNC_DBC_EVENT
determine whether ODBC executes in asynchronous mode and whether ODBC enables notification mode for a
connection handle. Statement attributes SQL_ATTR_ASYNC_ENABLE and SQL_ATTR_ASYNC_STMT_EVENT
determine whether ODBC executes in asynchronous mode and whether ODBC enables notification mode for a
statement handle.

SQ L _AT T R_A SY N C _EN A B L E O R


SQ L _AT T R_A SY N C _DB C _F UN C T IO N _E SQ L _AT T R_A SY N C _ST M T _EVEN T O R
NABLE SQ L _AT T R_A SY N C _DB C _EVEN T M O DE

Enable non-null Asynchronous Notification


SQ L _AT T R_A SY N C _EN A B L E O R
SQ L _AT T R_A SY N C _DB C _F UN C T IO N _E SQ L _AT T R_A SY N C _ST M T _EVEN T O R
NABLE SQ L _AT T R_A SY N C _DB C _EVEN T M O DE

Enable null Asynchronous Polling

Disable any Synchronous

An application can temporally disable asynchronous operation mode. ODBC ignores values of
SQL_ATTR_ASYNC_DBC_EVENT if the connection level asynchronous operation is disabled. ODBC ignores values
of SQL_ATTR_ASYNC_STMT_EVENT if the statement level asynchronous operation is disabled.
Synchronous call of SQLSetStmtAttr and SQLSetConnectAttr
SQLSetConnectAttr supports asynchronous operations but the invocation of SQLSetConnectAttr to
set SQL_ATTR_ASYNC_DBC_EVENT is always synchronous.
SQLSetStmtAttr does not support asynchronous execution.
Error-out scenario
When SQLSetConnectAttr is called before making a connection, the Driver Manager cannot determine which
driver to use. Therefore, the Driver Manager returns success for SQLSetConnectAttr but the attribute may not
be ready to set in the driver. The Driver Manager will set these attributes when the application calls a connection
function. The Driver Manager may error-out because driver does not support asynchronous operations.
Inheritance of connection attributes
Usually, the statements of a connection will inherit the connection attributes. However, the attribute
SQL_ATTR_ASYNC_DBC_EVENT is not inheritable and only affects the connection operations.
To associate an event handle with an ODBC connection handle, an ODBC application calls ODBC API
SQLSetConnectAttr and specifies SQL_ATTR_ASYNC_DBC_EVENT as the attribute and the event handle as the
attribute value. The new ODBC attribute SQL_ATTR_ASYNC_DBC_EVENT is of type SQL_IS_POINTER.

HANDLE hEvent;
hEvent = CreateEvent(
NULL, // default security attributes
FALSE, // auto-reset event
FALSE, // initial state is non-signaled
NULL // no name
);

Usually, applications create auto-reset event objects. ODBC will not reset the event object. Applications must
make sure that the object is not in signaled state before calling any asynchronous ODBC function.

SQLRETURN retcode;
retcode = SQLSetConnectAttr ( hDBC,
SQL_ATTR_ASYNC_DBC_EVENT, // Attribute name
(SQLPOINTER) hEvent, // Win32 Event handle
SQL_IS_POINTER); // Length Indicator

SQL_ATTR_ASYNC_DBC_EVENT is a Driver Manager-only attribute that will not be set in the driver.
The default value of SQL_ATTR_ASYNC_DBC_EVENT is NULL. If the driver does not support asynchronous
notification, getting or setting SQL_ATTR_ASYNC_DBC_EVENT will return SQL_ERROR with SQLSTATE HY092
(Invalid attribute/option identifier).
If the last SQL_ATTR_ASYNC_DBC_EVENT value set on an ODBC connection handle is not NULL and the
application enabled asynchronous mode by setting attribute SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE with
SQL_ASYNC_DBC_ENABLE_ON, calling any ODBC connection function that supports asynchronous mode will
get a completion notification. If the last SQL_ATTR_ASYNC_DBC_EVENT value set on an ODBC connection handle
is NULL, ODBC will not send the application any notification, regardless whether asynchronous mode is enabled.
An application can set SQL_ATTR_ASYNC_DBC_EVENT before or after setting the attribute
SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE.
Applications can set the SQL_ATTR_ASYNC_DBC_EVENT attribute on an ODBC connection handle before calling
a connection function (SQLConnect , SQLBrowseConnect , or SQLDriverConnect ). Because the ODBC Driver
Manager does not know which ODBC driver the application will use, it will return SQL_SUCCESS. When the
application calls a connection function, the ODBC Driver Manager will check whether the driver supports
asynchronous notification. If the driver does not support asynchronous notification, the ODBC Driver Manager
will return SQL_ERROR with SQLSTATE S1_118 (Driver does not support asynchronous notification). If the driver
supports asynchronous notification, the ODBC Driver Manager will call the driver and set the corresponding
attributes SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK and
SQL_ATTR_ASYNC_DBC_NOTIFICATION_CONTEXT.
Similarly, an application calls SQLSetStmtAttr on an ODBC statement handle and specifies the
SQL_ATTR_ASYNC_STMT_EVENT attribute to enable or disable statement level asynchronous notification.
Because a statement function is always called after the connection is established, SQLSetStmtAttr will return
SQL_ERROR with SQLSTATE S1_118 (Driver does not support asynchronous notification) immediately if the
corresponding driver does not support asynchronous operations or the driver supports asynchronous
operation but does not support asynchronous notification.

SQLRETURN retcode;
retcode = SQLSetStmtAttr ( hSTMT,
SQL_ATTR_ASYNC_STMT_EVENT, // Attribute name
(SQLPOINTER) hEvent, // Win32 Event handle
SQL_IS_POINTER); // length Indicator

SQL_ATTR_ASYNC_STMT_EVENT, which can be set to NULL, is a Driver Manager-only attribute that will not be
set in the driver.
The default value of SQL_ATTR_ASYNC_STMT_EVENT is NULL. If the driver does not support asynchronous
notification, getting or setting the SQL_ATTR_ASYNC_ STMT_EVENT attribute will return SQL_ERROR with
SQLSTATE HY092 (Invalid attribute/option identifier).
An application should not associate the same event handle with more than one ODBC handle. Otherwise, one
notification will be lost if two asynchronous ODBC function invocations complete on two handles that share the
same event handle. To avoid a statement handle inheriting the same event handle from the connection handle,
ODBC returns SQL_ERROR with SQLSTATE IM016 (Cannot set statement attribute into connection handle) if an
application sets SQL_ATTR_ASYNC_STMT_EVENT on a connection handle.
Calling Asynchronous ODBC Functions
After enabling asynchronous notification and starting an asynchronous operation, the application can call any
ODBC function. If the function belongs to the set of functions that support asynchronous operation, the
application will get a completion notification when the operation completes, regardless of whether the function
failed or succeeded. The only exception is that the application calls an ODBC function with an invalid connection
or statement handle. In this case, ODBC will not get the event handle and set it to the signaled state.
The application must ensure that the associated event object is in a non-signaled state before starting an
asynchronous operation on the corresponding ODBC handle. ODBC will not reset the event object.
Getting Notification from ODBC
An application thread can call WaitForSingleObject to wait on one event handle or call
WaitForMultipleObjects to wait on an array of event handles and be suspended until one or all of the event
objects become signaled or the time-out interval elapses.

DWORD dwStatus = WaitForSingleObject(


hEvent, // The event associated with the ODBC handle
5000 // timeout is 5000 millisecond
);

If (dwStatus == WAIT_TIMEOUT)
{
// time-out interval elapsed before all the events are signaled.
}
Else
{
// Call the corresponding Asynchronous ODBC API to complete all processing and retrieve the return code.
}
Freeing a Statement Handle ODBC
4/27/2022 • 2 minutes to read • Edit Online

As mentioned earlier, it is more efficient to reuse statements than to drop them and allocate new ones. Before
executing a new SQL statement on a statement, applications should be sure that the current statement settings
are appropriate. These include statement attributes, parameter bindings, and result set bindings. Generally,
parameters and result sets for the old SQL statement need to be unbound (by calling SQLFreeStmt with the
SQL_RESET_PARAMS and SQL_UNBIND options) and rebound for the new SQL statement.
When the application has finished using the statement, it calls SQLFreeHandle to free the statement. After
freeing the statement, it is an application programming error to use the statement's handle in a call to an ODBC
function; doing so has undefined but probably fatal consequences.
When SQLFreeHandle is called, the driver releases the structure used to store information about the
statement.
SQLDisconnect automatically frees all statements on a connection.
Retrieving Results (Basic)
4/27/2022 • 2 minutes to read • Edit Online

A result set is a set of rows on the data source that matches certain criteria. It is a conceptual table that results
from a query and that is available to an application in tabular form. SELECT statements, catalog functions, and
some procedures create result sets. In the following example, the first SQL statement creates a result set
containing all the rows and all the columns in the Orders table, and the second SQL statement creates a result
set containing OrderID, SalesPerson, and Status columns for the rows in the Orders table in which the Status is
OPEN:

SELECT * FROM Orders


SELECT OrderID, SalesPerson, Status FROM Orders WHERE Status = 'OPEN'

A result set can be empty, which is different from no result set at all. For example, the following SQL statement
creates an empty result set:

SELECT * FROM Orders WHERE 1 = 2

An empty result set is no different from any other result set except that it has no rows. For example, the
application can retrieve metadata for the result set, can attempt to fetch rows, and must close the cursor over
the result set.
The process of retrieving rows from the data source and returning them to the application is called fetching. This
section explains the basic parts of that process. For information about more advanced topics, such as block and
scrollable cursors, see Block Cursors and Scrollable Cursors. For information about updating, deleting, and
inserting rows, see Updating Data Overview.
This section contains the following topics.
Was a Result Set Created?
Result Set Metadata
Binding Columns
Fetching Data
Closing the Cursor
Was a Result Set Created?
4/27/2022 • 2 minutes to read • Edit Online

In most situations, application programmers know whether the statements their application executes will create
a result set. This is the case if the application uses hard-coded SQL statements written by the programmer. It is
usually the case when the application constructs SQL statements at run time: The programmer can easily include
code that flags whether a SELECT statement or an INSERT statement is being constructed. In a few situations,
the programmer cannot possibly know whether a statement will create a result set. This is true if the application
provides a way for the user to enter and execute an SQL statement. It is also true when the application
constructs a statement at run time to execute a procedure.
In such cases, the application calls SQLNumResultCols to determine the number of columns in the result set. If
this is 0, the statement did not create a result set; if it is any other number, the statement did create a result set.
The application can call SQLNumResultCols at any time after the statement is prepared or executed. However,
because some data sources cannot easily describe the result sets that will be created by prepared statements,
performance will suffer if SQLNumResultCols is called after a statement is prepared but before it is executed.
Some data sources also support determining the number of rows that an SQL statement returns in a result set.
To do so, the application calls SQLRowCount . Exactly what the row count represents is indicated by the setting
of the SQL_DYNAMIC_CURSOR_ATTRIBUTES2, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2,
SQL_KEYSET_CURSOR_ATTRIBUTES2, or SQL_STATIC_CURSOR_ATTRIBUTES2 option (depending on the type of
the cursor) returned by a call to SQLGetInfo . This bitmask indicates for each cursor type whether the row count
returned is exact, approximate, or is not available at all. Whether row counts for static or keyset-driven cursors
are affected by changes made through SQLBulkOperations or SQLSetPos , or by positioned update or delete
statements, depends on other bits returned by the same option arguments listed previously. For more
information, see the SQLGetInfo function description.
Result Set Metadata
4/27/2022 • 2 minutes to read • Edit Online

Metadata is data that describes other data. For example, result set metadata describes the result set, such as the
number of columns in the result set, the data types of those columns, their names, precision, nullability, and so
on.
Interoperable applications should always check the metadata of result set columns. The metadata for a column
in a result set might differ from the metadata for the column as returned by a catalog function. For example,
suppose that an updatable column is included in a result set created by joining two tables. While
SQLColumnPrivileges might indicate that a user can update the column, the result set metadata might not if
the column is on the "many" side of the join; many data sources can update columns on the "one" side of a join
but not on the "many" side. Even data types cannot be assumed to be the same, because the data source might
promote the data type while creating the result set.
This section contains the following topics.
How is Metadata Used?
SQLDescribeCol and SQLColAttribute
How is Metadata Used?
4/27/2022 • 2 minutes to read • Edit Online

Applications require metadata for most result set operations. For example, the application uses the data type of
a column to determine what kind of variable to bind to that column. It uses the byte length of a character
column to determine how much space it needs to display data from that column. How an application determines
the metadata for a column depends on the type of the application.
Vertical applications work with predefined tables and perform predefined operations on those tables. Because
the result set metadata for such applications is defined before the application is even written and is controlled
by the application developer, it can be hard-coded into the application. For example, if an order ID column is
defined as a 4-byte integer in the data source, the application can always bind a 4-byte integer to that column.
When metadata is hard-coded in the application, a change to the tables used by the application generally
implies a change to the application code. This is rarely a problem, because such changes are usually made as
part of a new release of the application.
Like vertical applications, custom applications generally work with predefined tables and perform predefined
operations on those tables. For example, an application might be written to transfer data among three different
data sources; the data to be transferred is usually known when the application is written. Thus, custom
applications also tend to have hard-coded metadata.
Generic applications, especially those that support ad hoc queries, almost never know the metadata of the result
sets they create. Therefore, they must discover the metadata at run time using the functions
SQLNumResultCols , SQLDescribeCol , and SQLColAttribute , which are described in the next section,
SQLDescribeCol and SQLColAttribute.
All applications, regardless of their type, can hard-code metadata for the result sets returned by the catalog
functions. These result sets are defined in the reference section of this manual.
SQLDescribeCol and SQLColAttribute
4/27/2022 • 2 minutes to read • Edit Online

SQLDescribeCol and SQLColAttribute are used to retrieve result set metadata. The difference between these
two functions is that SQLDescribeCol always returns the same five pieces of information (a column's name,
data type, precision, scale, and nullability), while SQLColAttribute returns a single piece of information
requested by the application. However, SQLColAttribute can return a much richer selection of metadata,
including a column's case-sensitivity, display size, updatability, and searchability.
Many applications, especially ones that only display data, require only the metadata returned by
SQLDescribeCol . For these applications, it is faster to use SQLDescribeCol than SQLColAttribute because
the information is returned in a single call. Other applications, especially ones that update data, require the
additional metadata returned by SQLColAttribute and therefore use both functions. In addition,
SQLColAttribute supports driver-specific metadata; for more information, see Driver-Specific Data Types,
Descriptor Types, Information Types, Diagnostic Types, and Attributes.
An application can retrieve result set metadata at any time after a statement has been prepared or executed and
before the cursor over the result set is closed. Very few applications require result set metadata after the
statement is prepared and before it is executed. If possible, applications should wait to retrieve metadata until
after the statement is executed, because some data sources cannot return metadata for prepared statements and
emulating this capability in the driver is often a slow process. For example, the driver might generate a zero-row
result set by replacing the WHERE clause of a SELECT statement with the clause WHERE 1 = 2 and executing
the resulting statement.
Metadata is often expensive to retrieve from the data source. Because of this, drivers should cache any metadata
they retrieve from the server and hold it for as long as the cursor over the result set is open. Also, applications
should request only the metadata they absolutely need.
Binding Columns
4/27/2022 • 2 minutes to read • Edit Online

Data fetched from the data source is returned to the application in variables that the application has allocated
for this purpose. Before this can be done, the application must associate, or bind, these variables to the columns
of the result set; conceptually, this process is the same as binding application variables to statement parameters.
When the application binds a variable to a result set column, it describes that variable - address, data type, and
so on - to the driver. The driver stores this information in the structure it maintains for that statement and uses
the information to return the value from the column when the row is fetched.
This section contains the following topics.
Binding Result Set Columns
Using SQLBindCol
Binding Result Set Columns
4/27/2022 • 2 minutes to read • Edit Online

Applications can bind as many or as few columns of the result set as they choose, including binding no columns
at all. When a row of data is fetched, the driver returns the data for the bound columns to the application.
Whether the application binds all of the columns in the result set depends on the application. For example,
applications that generate reports usually have a fixed format; such applications create a result set containing all
of the columns used in the report and then bind and retrieve the data for all of these columns. Applications that
display screens full of data sometimes allow the user to decide which columns to display; such applications
create a result set containing all columns the user might want, but bind and retrieve the data only for those
columns chosen by the user.
Data can be retrieved from unbound columns by calling SQLGetData . This is commonly called to retrieve long
data, which often exceeds the length of a single buffer and must be retrieved in parts.
Columns can be bound at any time, even after rows have been fetched. However, the new bindings do not take
effect until the next time a row is fetched; they are not applied to data from rows already fetched.
A variable remains bound to a column until a different variable is bound to the column, until the column is
unbound by calling SQLBindCol with a null pointer as the variable's address, until all columns are unbound by
calling SQLFreeStmt with the SQL_UNBIND option, or until the statement is released. For this reason, the
application must be sure that all bound variables remain valid as long as they are bound. For more information,
see Allocating and Freeing Buffers.
Because column bindings are just information associated with the statement structure, they can be set in any
order. They are also independent of the result set. For example, suppose an application binds the columns of the
result set generated by the following SQL statement:

SELECT * FROM Orders

If the application then executes the SQL statement

SELECT * FROM Lines

on the same statement handle, the column bindings for the first result set are still in effect because those are the
bindings stored in the statement structure. In most cases, this is a poor programming practice and should be
avoided. Instead, the application should call SQLFreeStmt with the SQL_UNBIND option to unbind all the old
columns and then bind new ones.
Using SQLBindCol
4/27/2022 • 6 minutes to read • Edit Online

The application binds columns by calling SQLBindCol . This function binds one column at a time. With it, the
application specifies the following:
The column number. Column 0 is the bookmark column; this column is not included in some result sets.
All other columns are numbered starting with the number 1. It is an error to bind a higher-numbered
column than there are columns in the result set; this error cannot be detected until the result set has been
created, so it is returned by SQLFetch , not SQLBindCol .
The C data type, address, and byte length of the variable bound to the column. It is an error to specify a C
data type to which the SQL data type of the column cannot be converted; this error might not be detected
until the result set has been created, so it is returned by SQLFetch , not SQLBindCol . For a list of
supported conversions, see Converting Data from SQL to C Data Types in Appendix D: Data Types. For
information about the byte length, see Data Buffer Length.
The address of a length/indicator buffer. The length/indicator buffer is optional. It is used to return the
byte length of binary or character data or return SQL_NULL_DATA if the data is NULL. For more
information, see Using Length/Indicator Values.
When SQLBindCol is called, the driver associates this information with the statement. When each row of data is
fetched, it uses the information to place the data for each column in the bound application variables.
For example, the following code binds variables to the SalesPerson and CustID columns. Data for the columns
will be returned in SalesPerson and CustID. Because SalesPerson is a character buffer, the application specifies its
byte length (11) so that the driver can determine whether to truncate the data. The byte length of the returned
title, or whether it is NULL, will be returned in SalesPersonLenOrInd.
Because CustID is an integer variable and has fixed length, there is no need to specify its byte length; the driver
assumes it is sizeof( SQLUINTEGER ) . The byte length of the returned customer ID data, or whether it is NULL,
will be returned in CustIDInd. Note that the application is interested only in whether the salary is NULL, because
the byte length is always sizeof( SQLUINTEGER ) .
SQLCHAR SalesPerson[11];
SQLUINTEGER CustID;
SQLINTEGER SalesPersonLenOrInd, CustIDInd;
SQLRETURN rc;
SQLHSTMT hstmt;

// Bind SalesPerson to the SalesPerson column and CustID to the


// CustID column.
SQLBindCol(hstmt, 1, SQL_C_CHAR, SalesPerson, sizeof(SalesPerson),
&SalesPersonLenOrInd);
SQLBindCol(hstmt, 2, SQL_C_ULONG, &CustID, 0, &CustIDInd);

// Execute a statement to get the sales person/customer of all orders.


SQLExecDirect(hstmt, "SELECT SalesPerson, CustID FROM Orders ORDER BY SalesPerson",
SQL_NTS);

// Fetch and print the data. Print "NULL" if the data is NULL. Code to
// check if rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {
if (SalesPersonLenOrInd == SQL_NULL_DATA)
printf("NULL ");
else
printf("%10s ", SalesPerson);
if (CustIDInd == SQL_NULL_DATA)
printf("NULL\n");
else
printf("%d\n", CustID);
}

// Close the cursor.


SQLCloseCursor(hstmt);

The following code executes a SELECT statement entered by the user and prints each row of data in the result
set. Because the application cannot predict the shape of the result set created by the SELECT statement, it
cannot bind hard-coded variables to the result set as in the preceding example. Instead, the application allocates
a buffer that holds the data and a length/indicator buffer for each column in that row. For each column, it
calculates the offset to the start of the memory for the column and adjusts this offset so that the data and
length/indicator buffers for the column start on alignment boundaries. It then binds the memory starting at the
offset to the column. From the driver's point of view, the address of this memory is indistinguishable from the
address of a variable bound in the preceding example. For more information about alignment, see Alignment.

// This application allocates a buffer at run time. For each column, this
// buffer contains memory for the column's data and length/indicator.
// For example:
// column 1 column 2 column 3 column 4
// <------------><---------------><-----><------------>
// db1 li1 db2 li2 db3 li3 db4 li4
// | | | | | | | |
// _____V_____V________V_______V___V___V______V_____V_
// |__________|__|_____________|__|___|__|__________|__|
//
// dbn = data buffer for column n
// lin = length/indicator buffer for column n

// Define a macro to increase the size of a buffer so that it is a


// multiple of the alignment size. Thus, if a buffer starts on an
// alignment boundary, it will end just before the next alignment
// boundary. In this example, an alignment size of 4 is used because
// this is the size of the largest data type used in the application's
// buffer--the size of an SDWORD and of the largest default C data type
// are both 4. If a larger data type (such as _int64) was used, it would
// be necessary to align for that size.
#define ALIGNSIZE 4
#define ALIGNBUF(Length) Length % ALIGNSIZE ? \
#define ALIGNBUF(Length) Length % ALIGNSIZE ? \
Length + ALIGNSIZE - (Length % ALIGNSIZE) : Length

SQLCHAR SelectStmt[100];
SQLSMALLINT NumCols, *CTypeArray, i;
SQLINTEGER * ColLenArray, *OffsetArray, SQLType, *DataPtr;
SQLRETURN rc;
SQLHSTMT hstmt;

// Get a SELECT statement from the user and execute it.


GetSelectStmt(SelectStmt, 100);
SQLExecDirect(hstmt, SelectStmt, SQL_NTS);

// Determine the number of result set columns. Allocate arrays to hold


// the C type, byte length, and buffer offset to the data.
SQLNumResultCols(hstmt, &NumCols);
CTypeArray = (SQLSMALLINT *) malloc(NumCols * sizeof(SQLSMALLINT));
ColLenArray = (SQLINTEGER *) malloc(NumCols * sizeof(SQLINTEGER));
OffsetArray = (SQLINTEGER *) malloc(NumCols * sizeof(SQLINTEGER));

OffsetArray[0] = 0;
for (i = 0; i < NumCols; i++) {
// Determine the column's SQL type. GetDefaultCType contains a switch
// statement that returns the default C type for each SQL type.
SQLColAttribute(hstmt, ((SQLUSMALLINT) i) + 1, SQL_DESC_TYPE, NULL, 0, NULL, (SQLPOINTER) &SQLType);
CTypeArray[i] = GetDefaultCType(SQLType);

// Determine the column's byte length. Calculate the offset in the


// buffer to the data as the offset to the previous column, plus the
// byte length of the previous column, plus the byte length of the
// previous column's length/indicator buffer. Note that the byte
// length of the column and the length/indicator buffer are increased
// so that, assuming they start on an alignment boundary, they will
// end on the byte before the next alignment boundary. Although this
// might leave some holes in the buffer, it is a relatively
// inexpensive way to guarantee alignment.
SQLColAttribute(hstmt, ((SQLUSMALLINT) i)+1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &ColLenArray[i]);
ColLenArray[i] = ALIGNBUF(ColLenArray[i]);
if (i)
OffsetArray[i] = OffsetArray[i-1]+ColLenArray[i-1]+ALIGNBUF(sizeof(SQLINTEGER));
}

// Allocate the data buffer. The size of the buffer is equal to the
// offset to the data buffer for the final column, plus the byte length
// of the data buffer and length/indicator buffer for the last column.
void *DataPtr = malloc(OffsetArray[NumCols - 1] +
ColLenArray[NumCols - 1] + ALIGNBUF(sizeof(SQLINTEGER)));

// For each column, bind the address in the buffer at the start of the
// memory allocated for that column's data and the address at the start
// of the memory allocated for that column's length/indicator buffer.
for (i = 0; i < NumCols; i++)
SQLBindCol(hstmt,
((SQLUSMALLINT) i) + 1,
CTypeArray[i],
(SQLPOINTER)((SQLCHAR *)DataPtr + OffsetArray[i]),
ColLenArray[i],
(SQLINTEGER *)((SQLCHAR *)DataPtr + OffsetArray[i] + ColLenArray[i]));

// Retrieve and print each row. PrintData accepts a pointer to the data,
// its C type, and its byte length/indicator. It contains a switch
// statement that casts and prints the data according to its type. Code
// to check if rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {
for (i = 0; i < NumCols; i++) {
PrintData((SQLCHAR *)DataPtr[OffsetArray[i]], CTypeArray[i],
(SQLINTEGER *)((SQLCHAR *)DataPtr[OffsetArray[i] + ColLenArray[i]]));
}
}
// Close the cursor.
SQLCloseCursor(hstmt);
Fetching Data
4/27/2022 • 2 minutes to read • Edit Online

The process of retrieving rows from the result set and returning them to the application is called fetching. This
section describes how to fetch data.
This section contains the following topics.
Cursors
Fetching a Row of Data
Getting Long Data
ODBC Cursors
4/27/2022 • 2 minutes to read • Edit Online

An application fetches data with a cursor. A cursor is different from a result set: A result set is the set of rows
that matches particular search criteria, whereas a cursor is the software that returns those rows to the
application. The name cursor, as it applies to databases, probably originated from the blinking cursor on a
computer terminal. Just as that cursor indicates the current position on the screen and where the typed words
will appear next, a cursor on a result set indicates the current position in the result set and what row will be
returned next.
The cursor model in ODBC is based on the cursor model in embedded SQL. One notable difference between
these models is the way cursors are opened. In embedded SQL, a cursor must be explicitly declared and opened
before it can be used. In ODBC, a cursor is implicitly opened when a statement that creates a result set is
executed. When the cursor is opened, it is positioned before the first row of the result set. In both embedded
SQL and ODBC, a cursor must be closed after the application has finished using it.
Different cursors have different characteristics. The most common type of cursor, which is called a forward-only
cursor, can only move forward through the result set. To return to a previous row, the application must close and
reopen the cursor and then read rows from the beginning of the result set until it reaches the required row.
Forward-only cursors provide a fast mechanism for making a single pass through a result set.
Forward-only cursors are less useful for screen-based applications, in which the user scrolls backward and
forward through the data. Such applications can use a forward-only cursor by reading the result set once,
caching the data locally, and performing scrolling themselves. However, this works well only with small amounts
of data. A better solution is to use a scrollable cursor, which provides random access to the result set. Such
applications can also increase performance by fetching more than one row of data at a time, using what is called
a block cursor. For more information about block cursors, see Using Block Cursors.
The forward-only cursor is the default cursor type in ODBC and is discussed in the following sections. For more
information about block cursors and scrollable cursors, see Block Cursors and Scrollable Cursors.

IMPORTANT
Committing or rolling back a transaction, either by explicitly calling SQLEndTran or by operating in auto-commit mode,
causes some data sources to close all the cursors on all statements on a connection. For more information, see the
SQL_CURSOR_COMMIT_BEHAVIOR and SQL_CURSOR_ROLLBACK_BEHAVIOR attributes in the SQLGetInfo function
description.
Fetching a Row of Data
4/27/2022 • 3 minutes to read • Edit Online

To fetch a row of data, an application calls SQLFetch . SQLFetch can be called with any kind of cursor, but it
only moves the rowset cursor in a forward-only direction. SQLFetch advances the cursor to the next row and
returns the data for any columns that were bound with calls to SQLBindCol . When the cursor reaches the end
of the result set, SQLFetch returns SQL_NO_DATA. For examples of calling SQLFetch , see Using SQLBindCol.
Exactly how SQLFetch is implemented is driver-specific, but the general pattern is for the driver to retrieve the
data for any bound columns from the data source, convert it according to the types of the bound variables, and
place the converted data in those variables. If the driver cannot convert any data, SQLFetch returns an error.
The application can continue fetching rows, but the data for the current row is lost. What happens to the data for
unbound columns depends on the driver, but most drivers either retrieve and discard it or never retrieve it at all.
The driver also sets the values of any length/indicator buffers that have been bound. If the data value for a
column is NULL, the driver sets the corresponding length/indicator buffer to SQL_NULL_DATA. If the data value
is not NULL, the driver sets the length/indicator buffer to the byte length of the data after conversion. If this
length cannot be determined, as is sometimes the case with long data that is retrieved by more than one
function call, the driver sets the length/indicator buffer to SQL_NO_TOTAL. For fixed-length data types, such as
integers and date structures, the byte length is the size of the data type.
For variable-length data, such as character and binary data, the driver checks the byte length of the converted
data against the byte length of the buffer bound to the column; the buffer's length is specified in the
BufferLength argument in SQLBindCol . If the byte length of the converted data is greater than the byte length
of the buffer, the driver truncates the data to fit in the buffer, returns the untruncated length in the
length/indicator buffer, returns SQL_SUCCESS_WITH_INFO, and places SQLSTATE 01004 (Data truncated) in the
diagnostics. The only exception to this is if a variable-length bookmark is truncated when returned by
SQLFetch , which returns SQLSTATE 22001 (String data, right truncated).
Fixed-length data is never truncated, because the driver assumes that the size of the bound buffer is the size of
the data type. Data truncation tends to be rare, because the application usually binds a buffer large enough to
hold the entire data value; it determines the necessary size from the metadata. However, the application might
explicitly bind a buffer it knows to be too small. For example, it might retrieve and display the first 20 characters
of a part description or the first 100 characters of a long text column.
Character data must be null-terminated by the driver before it is returned to the application, even if it has been
truncated. The null-termination character is not included in the returned byte length but does require space in
the bound buffer. For example, suppose an application uses strings composed of character data in the ASCII
character set, a driver has 50 characters of data to return, and the application's buffer is 25 bytes long. In the
application's buffer, the driver returns the first 24 characters followed by a null-termination character. In the
length/indicator buffer, it returns a byte length of 50.
The application can restrict the number of rows in the result set by setting the SQL_ATTR_MAX_ROWS statement
attribute before executing the statement that creates the result set. For example, the preview mode in an
application used to format reports needs only enough data to display the first page of the report. By restricting
the size of the result set, such a feature would run faster. This statement attribute is intended to reduce network
traffic and might not be supported by all drivers.
Getting Long Data
4/27/2022 • 4 minutes to read • Edit Online

DBMSs define long data as any character or binary data over a certain size, such as 255 characters. This data
may be small enough to be stored in a single buffer, such as a part description of several thousand characters.
However, it might be too long to store in memory, such as long text documents or bitmaps. Because such data
cannot be stored in a single buffer, it is retrieved from the driver in parts with SQLGetData after the other data
in the row has been fetched.

NOTE
An application can actually retrieve any type of data with SQLGetData , not just long data, although only character and
binary data can be retrieved in parts. However, if the data is small enough to fit in a single buffer, there is generally no
reason to use SQLGetData . It is much easier to bind a buffer to the column and let the driver return the data in the
buffer.

To retrieve long data from a column, an application first calls SQLFetchScroll or SQLFetch to move to a row
and fetch the data for bound columns. The application then calls SQLGetData . SQLGetData has the same
arguments as SQLBindCol : a statement handle; a column number; the C data type, address, and byte length of
an application variable; and the address of a length/indicator buffer. Both functions have the same arguments
because they perform essentially the same task: They both describe an application variable to the driver and
specify that the data for a particular column should be returned in that variable. The major differences are that
SQLGetData is called after a row is fetched (and is sometimes referred to as late binding for this reason) and
that the binding specified by SQLGetData lasts only for the duration of the call.
Regarding a single column, SQLGetData behaves like SQLFetch : It retrieves the data for the column, converts
it to the type of the application variable, and returns it in that variable. It also returns the byte length of the data
in the length/indicator buffer. For more information about how SQLFetch returns data, see Fetching a Row of
Data.
SQLGetData differs from SQLFetch in one important respect. If it is called more than once in succession for
the same column, each call returns a successive part of the data. Each call except the last call returns
SQL_SUCCESS_WITH_INFO and SQLSTATE 01004 (String data, right truncated); the last call returns
SQL_SUCCESS. This is how SQLGetData is used to retrieve long data in parts. When there is no more data to
return, SQLGetData returns SQL_NO_DATA. The application is responsible for putting the long data together,
which might mean concatenating the parts of the data. Each part is null-terminated; the application must
remove the null-termination character if concatenating the parts. Retrieving data in parts can be done for
variable-length bookmarks as well as for other long data. The value returned in the length/indicator buffer
decreases in each call by the number of bytes returned in the previous call, although it is common for the driver
to be unable to discover the amount of available data and return a byte length of SQL_NO_TOTAL. For example:
// Declare a binary buffer to retrieve 5000 bytes of data at a time.
SQLCHAR BinaryPtr[5000];
SQLUINTEGER PartID;
SQLINTEGER PartIDInd, BinaryLenOrInd, NumBytes;
SQLRETURN rc;
SQLHSTMT hstmt;

// Create a result set containing the ID and picture of each part.


SQLExecDirect(hstmt, "SELECT PartID, Picture FROM Pictures", SQL_NTS);

// Bind PartID to the PartID column.


SQLBindCol(hstmt, 1, SQL_C_ULONG, &PartID, 0, &PartIDInd);

// Retrieve and display each row of data.


while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {
// Display the part ID and initialize the picture.
DisplayID(PartID, PartIDInd);
InitPicture();

// Retrieve the picture data in parts. Send each part and the number
// of bytes in each part to a function that displays it. The number
// of bytes is always 5000 if there were more than 5000 bytes
// available to return (cbBinaryBuffer > 5000). Code to check if
// rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.
while ((rc = SQLGetData(hstmt, 2, SQL_C_BINARY, BinaryPtr, sizeof(BinaryPtr),
&BinaryLenOrInd)) != SQL_NO_DATA) {
NumBytes = (BinaryLenOrInd > 5000) || (BinaryLenOrInd == SQL_NO_TOTAL) ?
5000 : BinaryLenOrInd;
DisplayNextPictPart(BinaryPtr, NumBytes);
}
}

// Close the cursor.


SQLCloseCursor(hstmt);

There are several restrictions on using SQLGetData . Generally, columns accessed with SQLGetData :
Must be accessed in order of increasing column number (because of the way the columns of a result set
are read from the data source). For example, it is an error to call SQLGetData for column 5 and then call
it for column 4.
Cannot be bound.
Must have a higher column number than the last bound column. For example, if the last bound column is
column 3, it is an error to call SQLGetData for column 2. For this reason, applications should make sure
to place long data columns at the end of the select list.
Cannot be used if SQLFetch or SQLFetchScroll was called to retrieve more than one row. For more
information, see Using Block Cursors.
Some drivers do not enforce these restrictions. Interoperable applications should either assume they exist or
determine which restrictions are not enforced by calling SQLGetInfo with the SQL_GETDATA_EXTENSIONS
option.
If the application does not need all the data in a character or binary data column, it can reduce network traffic in
DBMS-based drivers by setting the SQL_ATTR_MAX_LENGTH statement attribute before executing the
statement. This restricts the number of bytes of data that will be returned for any character or binary column.
For example, suppose a column contains long text documents. An application that browses the table containing
this column might have to display only the first page of each document. Although this statement attribute can
be simulated in the driver, there is no reason to do this. In particular, if an application wants to truncate character
or binary data, it should bind a small buffer to the column with SQLBindCol and let the driver truncate the
data.
Closing the Cursor
4/27/2022 • 2 minutes to read • Edit Online

When an application has finished using a cursor, it calls SQLCloseCursor to close the cursor. For example:

SQLCloseCursor(hstmt);

Until the application closes the cursor, the statement on which the cursor is opened cannot be used for most
other operations, such as executing another SQL statement. For a complete list of functions that can be called
while a cursor is open, see Appendix B: ODBC State Transition Tables.

NOTE
To close a cursor, an application should call SQLCloseCursor , not SQLCancel.

Cursors remain open until they are explicitly closed, except when a transaction is committed or rolled back, in
which case some data sources close the cursor. In particular, reaching the end of the result set, when SQLFetch
returns SQL_NO_DATA, does not close a cursor. Even cursors on empty result sets (result sets created when a
statement executed successfully but which returned no rows) must be explicitly closed.
Retrieving Results (Advanced)
4/27/2022 • 2 minutes to read • Edit Online

An application can specify that an offset is added to bound data buffer addresses and the corresponding
length/indicator buffer addresses when SQLBulkOperations , SQLFetch , SQLFetchScroll , or SQLSetPos is
called. The results of these additions determine the addresses used in these operations.
Bind offsets allow an application to change bindings without calling SQLBindCol for previously bound
columns. A call to SQLBindCol to rebind data changes the buffer address and the length/indicator pointer.
Rebinding with an offset, on the other hand, simply adds an offset to the existing bound data buffer address and
length/indicator buffer address. When offsets are used, the bindings are a "template" of how the application
buffers are laid out and the application can move this "template" to different areas of memory by changing the
offset. A new offset can be specified at any time and is always added to the originally bound values.
To specify a bind offset, the application sets the SQL_ATTR_ROW_BIND_OFFSET_PTR statement attribute to the
address of an SQLINTEGER buffer. Before the application calls a function that uses the bindings, such as
SQLBulkOperations , SQLFetch , SQLFetchScroll , or SQLSetPos , it places an offset in bytes in this buffer, as
long as neither the data buffer address nor the length/indicator buffer address is 0, and as long as the bound
column is in the result set. The sum of the address and the offset must be a valid address. (This means that
either or both the offset and the address to which the offset is added can be invalid, as long as their sum is a
valid address.) The SQL_ATTR_ROW_BIND_OFFSET_PTR statement attribute is a pointer so that the offset value
can be applied to more than one set of binding data, all of which can be changed by changing one offset value.
An application must make sure that the pointer remains valid until the cursor is closed.

NOTE
Binding offsets are not supported by ODBC 2.x drivers.

This section contains the following topics.


Block Cursors
Scrollable Cursors
The ODBC Cursor Library
Multiple Results
Block Cursors
4/27/2022 • 2 minutes to read • Edit Online

Many applications spend a significant amount of time bringing data across the network. Part of this time is
spent actually bringing the data across the network, and part of it is spent on network overhead, such as the call
made by the driver to request a row of data. The latter time can be reduced if the application makes efficient use
of block, or fat, cursors, which can return more than one row at a time.
An application always has the option of using a block cursor. On data sources from which only one row at a time
can be fetched, block cursors must be simulated in the driver. This can be done by performing multiple single-
row fetches. While this is unlikely to provide any performance gains, it opens opportunities for applications.
Such applications will then experience performance increases as DBMSs implement block cursors natively and
the drivers associated with those DBMSs expose them.
The rows returned in a single fetch with a block cursor are called the rowset. It is important not to confuse the
rowset with the result set. The result set is maintained at the data source, while the rowset is maintained in
application buffers. While the result set is fixed, the rowset is not - it changes position and contents each time a
new set of rows is fetched. Just as a single-row cursor such as the traditional SQL forward-only cursor points to
a current row, a block cursor points to the rowset, which can be thought of as current rows.
To perform operations that operate on a single row when multiple rows have been fetched, the application must
first indicate which row is the current row. The current row is required by calls to SQLGetData and positioned
update and delete statements. When a block cursor first returns a rowset, the current row is the first row of the
rowset. To change the current row, the application calls SQLSetPos or SQLBulkOperations (to update by
bookmark). The following illustration shows the relationship of the result set, rowset, current row, rowset cursor,
and block cursor. For more information, see Using Block Cursors, later in this section, and Positioned Update and
Delete Statements and Updating Data with SQLSetPos.

Whether a cursor is a block cursor is independent of whether it is scrollable. For example, most of the work in a
report application is spent retrieving and printing rows. Because of this, it will work fastest with a forward-only,
block cursor. It uses a forward-only cursor to avoid the expense of a scrollable cursor, and a block cursor to
reduce the network traffic.
This section contains the following topics.
Binding Columns for Use with Block Cursors
Using Block Cursors
Row Status Array
Binding Columns for Use with Block Cursors
4/27/2022 • 2 minutes to read • Edit Online

Because block cursors return multiple rows, applications that use them must bind an array of variables to each
column instead of a single variable. These arrays are collectively known as the rowset buffers. Following are the
two styles of binding:
Bind an array to each column. This is called column-wise binding because each data structure (array)
contains data for a single column.
Define a structure to hold the data for an entire row and bind an array of these structures. This is called
row-wise binding because each data structure contains the data for a single row.
As when the application binds single variables to columns, it calls SQLBindCol to bind arrays to columns. The
only difference is that the addresses passed are array addresses, not single variable addresses. The application
sets the SQL_BIND_BY_COLUMN statement attribute to specify whether it is using column-wise or row-wise
binding. Whether to use column-wise or row-wise binding is largely a matter of application preference. Row-
wise binding might correspond more closely to the application's layout of data, in which case it would provide
better performance.
This section contains the following topics.
Column-Wise Binding
Row-Wise Binding
Column-Wise Binding
4/27/2022 • 2 minutes to read • Edit Online

When using column-wise binding, an application binds one or two, or in some cases three, arrays to each
column for which data is to be returned. The first array holds the data values, and the second array holds
length/indicator buffers. Indicators and length values can be stored in separate buffers by setting the
SQL_DESC_INDICATOR_PTR and SQL_DESC_OCTET_LENGTH_PTR descriptor fields to different values; if this is
done, a third array is bound. Each array contains as many elements as there are rows in the rowset.
The application declares that it is using column-wise binding with the SQL_ATTR_ROW_BIND_TYPE statement
attribute, which determines the bind type for rowset buffers as opposed to parameter set buffers. The driver
returns the data for each row in successive elements of each array. The following illustration shows how
column-wise binding works.

For example, the following code binds 10-element arrays to the OrderID, SalesPerson, and Status columns:
#define ROW_ARRAY_SIZE 10

SQLUINTEGER OrderIDArray[ROW_ARRAY_SIZE], NumRowsFetched;


SQLCHAR SalesPersonArray[ROW_ARRAY_SIZE][11],
StatusArray[ROW_ARRAY_SIZE][7];
SQLINTEGER OrderIDIndArray[ROW_ARRAY_SIZE],
SalesPersonLenOrIndArray[ROW_ARRAY_SIZE],
StatusLenOrIndArray[ROW_ARRAY_SIZE];
SQLUSMALLINT RowStatusArray[ROW_ARRAY_SIZE], i;
SQLRETURN rc;
SQLHSTMT hstmt;

// Set the SQL_ATTR_ROW_BIND_TYPE statement attribute to use


// column-wise binding. Declare the rowset size with the
// SQL_ATTR_ROW_ARRAY_SIZE statement attribute. Set the
// SQL_ATTR_ROW_STATUS_PTR statement attribute to point to the
// row status array. Set the SQL_ATTR_ROWS_FETCHED_PTR statement
// attribute to point to cRowsFetched.
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, ROW_ARRAY_SIZE, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, &NumRowsFetched, 0);

// Bind arrays to the OrderID, SalesPerson, and Status columns.


SQLBindCol(hstmt, 1, SQL_C_ULONG, OrderIDArray, 0, OrderIDIndArray);
SQLBindCol(hstmt, 2, SQL_C_CHAR, SalesPersonArray, sizeof(SalesPersonArray[0]),
SalesPersonLenOrIndArray);
SQLBindCol(hstmt, 3, SQL_C_CHAR, StatusArray, sizeof(StatusArray[0]),
StatusLenOrIndArray);

// Execute a statement to retrieve rows from the Orders table.


SQLExecDirect(hstmt, "SELECT OrderID, SalesPerson, Status FROM Orders", SQL_NTS);

// Fetch up to the rowset size number of rows at a time. Print the actual
// number of rows fetched; this number is returned in NumRowsFetched.
// Check the row status array to print only those rows successfully
// fetched. Code to check if rc equals SQL_SUCCESS_WITH_INFO or
// SQL_ERROR not shown.
while ((rc = SQLFetchScroll(hstmt,SQL_FETCH_NEXT,0)) != SQL_NO_DATA) {
for (i = 0; i < NumRowsFetched; i++) {
if ((RowStatusArray[i] == SQL_ROW_SUCCESS) ||
(RowStatusArray[i] == SQL_ROW_SUCCESS_WITH_INFO)) {
if (OrderIDIndArray[i] == SQL_NULL_DATA)
printf(" NULL ");
else
printf("%d\t", OrderIDArray[i]);
if (SalesPersonLenOrIndArray[i] == SQL_NULL_DATA)
printf(" NULL ");
else
printf("%s\t", SalesPersonArray[i]);
if (StatusLenOrIndArray[i] == SQL_NULL_DATA)
printf(" NULL\n");
else
printf("%s\n", StatusArray[i]);
}
}
}

// Close the cursor.


SQLCloseCursor(hstmt);
Row-Wise Binding
4/27/2022 • 2 minutes to read • Edit Online

When using row-wise binding, an application defines a structure containing one or two, or in some cases three,
elements for each column for which data is to be returned. The first element holds the data value, and the
second element holds the length/indicator buffer. Indicators and length values can be stored in separate buffers
by setting the SQL_DESC_INDICATOR_PTR and SQL_DESC_OCTET_LENGTH_PTR descriptor fields to different
values; if this is done, the structure contains a third element. The application then allocates an array of these
structures, which contains as many elements as there are rows in the rowset.
The application declares the size of the structure to the driver with the SQL_ATTR_ROW_BIND_TYPE statement
attribute and binds the address of each member in the first element of the array. Thus, the driver can calculate
the address of the data for a particular row and column as

Address = Bound Address + ((Row Number - 1) * Structure Size)

where rows are numbered from 1 to the size of the rowset. (One is subtracted from the row number because
array indexing in C is zero-based.) The following illustration shows how row-wise binding works. Generally, only
columns that will be bound are included in the structure. The structure can contain fields that are unrelated to
result set columns. The columns can be placed in the structure in any order but are shown in sequential order
for clarity.

For example, the following code creates a structure with elements in which to return data for the OrderID,
SalesPerson, and Status columns, and length/indicators for the SalesPerson and Status columns. It allocates 10
of these structures and binds them to the OrderID, SalesPerson, and Status columns.

#define ROW_ARRAY_SIZE 10

// Define the ORDERINFO struct and allocate an array of 10 structs.


typedef struct {
SQLUINTEGER OrderID;
SQLINTEGER OrderIDInd;
SQLCHAR SalesPerson[11];
SQLINTEGER SalesPersonLenOrInd;
SQLCHAR Status[7];
SQLINTEGER StatusLenOrInd;
} ORDERINFO;
ORDERINFO OrderInfoArray[ROW_ARRAY_SIZE];

SQLULEN NumRowsFetched;
SQLUSMALLINT RowStatusArray[ROW_ARRAY_SIZE], i;
SQLRETURN rc;
SQLHSTMT hstmt;
SQLHSTMT hstmt;

// Specify the size of the structure with the SQL_ATTR_ROW_BIND_TYPE


// statement attribute. This also declares that row-wise binding will
// be used. Declare the rowset size with the SQL_ATTR_ROW_ARRAY_SIZE
// statement attribute. Set the SQL_ATTR_ROW_STATUS_PTR statement
// attribute to point to the row status array. Set the
// SQL_ATTR_ROWS_FETCHED_PTR statement attribute to point to
// NumRowsFetched.
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, sizeof(ORDERINFO), 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, ROW_ARRAY_SIZE, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROWS_FETCHED_PTR, &NumRowsFetched, 0);

// Bind elements of the first structure in the array to the OrderID,


// SalesPerson, and Status columns.
SQLBindCol(hstmt, 1, SQL_C_ULONG, &OrderInfoArray[0].OrderID, 0, &OrderInfoArray[0].OrderIDInd);
SQLBindCol(hstmt, 2, SQL_C_CHAR, OrderInfoArray[0].SalesPerson,
sizeof(OrderInfoArray[0].SalesPerson),
&OrderInfoArray[0].SalesPersonLenOrInd);
SQLBindCol(hstmt, 3, SQL_C_CHAR, OrderInfoArray[0].Status,
sizeof(OrderInfoArray[0].Status), &OrderInfoArray[0].StatusLenOrInd);

// Execute a statement to retrieve rows from the Orders table.


SQLExecDirect(hstmt, "SELECT OrderID, SalesPerson, Status FROM Orders", SQL_NTS);

// Fetch up to the rowset size number of rows at a time. Print the actual
// number of rows fetched; this number is returned in NumRowsFetched.
// Check the row status array to print only those rows successfully
// fetched. Code to check if rc equals SQL_SUCCESS_WITH_INFO or
// SQL_ERRORnot shown.
while ((rc = SQLFetchScroll(hstmt,SQL_FETCH_NEXT,0)) != SQL_NO_DATA) {
for (i = 0; i < NumRowsFetched; i++) {
if (RowStatusArray[i] == SQL_ROW_SUCCESS|| RowStatusArray[i] ==
SQL_ROW_SUCCESS_WITH_INFO) {
if (OrderInfoArray[i].OrderIDInd == SQL_NULL_DATA)
printf(" NULL ");
else
printf("%d\t", OrderInfoArray[i].OrderID);
if (OrderInfoArray[i].SalesPersonLenOrInd == SQL_NULL_DATA)
printf(" NULL ");
else
printf("%s\t", OrderInfoArray[i].SalesPerson);
if (OrderInfoArray[i].StatusLenOrInd == SQL_NULL_DATA)
printf(" NULL\n");
else
printf("%s\n", OrderInfoArray[i].Status);
}
}
}

// Close the cursor.


SQLCloseCursor(hstmt);
Using Block Cursors
4/27/2022 • 2 minutes to read • Edit Online

Support for block cursors is built into ODBC 3.x. SQLFetch can be used only for multirow fetches when called in
ODBC 3.x; if an ODBC 2.x application calls SQLFetch , it will open only a single-row, forward-only cursor. When
an ODBC 3.x application calls SQLFetch in an ODBC 2.x driver, it returns a single row unless the driver supports
SQLExtendedFetch . For more information, see Block Cursors, Scrollable Cursors, and Backward Compatibility
in Appendix G: Driver Guidelines for Backward Compatibility.
To use block cursors, the application sets the rowset size, binds the rowset buffers (as described in the previous
section), optionally sets the SQL_ATTR_ROWS_FETCHED_PTR and SQL_ATTR_ROW_STATUS_PTR statement
attributes, and calls SQLFetch or SQLFetchScroll to fetch a block of rows. The application can change the
rowset size and bind new rowset buffers (by calling SQLBindCol or specifying a bind offset) even after rows
have been fetched.
This section contains the following topics.
Rowset Size
Number of Rows Fetched and Status
SQLGetData and Block Cursors; block curso
Rowset Size
4/27/2022 • 2 minutes to read • Edit Online

Which rowset size to use depends on the application. Screen-based applications commonly follow one of two
strategies. The first is to set the rowset size to the number of rows displayed on the screen; if the user resizes the
screen, the application changes the rowset size accordingly. The second is to set the rowset size to a larger
number, such as 100, which reduces the number of calls to the data source. The application scrolls locally within
the rowset when possible and fetches new rows only when it scrolls outside the rowset.
Other applications, such as reports, tend to set the rowset size to the largest number of rows the application can
reasonably handle - with a larger rowset, the network overhead per row is sometimes reduced. Exactly how
large a rowset can be depends on the size of each row and the amount of memory available.
Rowset size is set by a call to SQLSetStmtAttr with an Attribute argument of SQL_ATTR_ROW_ARRAY_SIZE.
The application can change the rowset size, bind new rowset buffers (by calling SQLBindCol or specifying a
binding offset) even after rows have been fetched, or both. The implications of changing the rowset size depend
on the function:
SQLFetch and SQLFetchScroll use the rowset size at the time of the call to determine how many rows
to fetch. However, SQLFetchScroll with a FetchOrientation of SQL_FETCH_NEXT increments the cursor
based on the rowset of the previous fetch and then fetches a rowset based on the current rowset size.
SQLSetPos uses the rowset size that is in effect as of the preceding call to SQLFetch or
SQLFetchScroll , because SQLSetPos operates on a rowset that has already been set. SQLSetPos also
will pick up the new rowset size if SQLBulkOperations has been called after the rowset size was
changed.
SQLBulkOperations uses the rowset size in effect at the time of the call, because it performs operations
on a table independent of any fetched rowset.
Number of Rows Fetched and Status
4/27/2022 • 2 minutes to read • Edit Online

If the SQL_ATTR_ROWS_FETCHED_PTR statement attribute has been set, it specifies a buffer that returns the
number of rows fetched by the call to SQLFetch or SQLFetchScroll , and error rows. (This number is a count of
all rows that do not have the status SQL_ROW_NO_ROWS.) After a call to SQLBulkOperations or SQLSetPos ,
the buffer contains the number of rows that were affected by a bulk operation performed by the function. If the
SQL_ATTR_ROW_STATUS_PTR statement attribute has been set, SQLFetch or SQLFetchScroll returns the row
status array, which provides the status of each returned row. Both of the buffers pointed to by these fields are
allocated by the application and populated by the driver. An application must make sure that these pointers
remain valid until the cursor is closed.
Entries in the row status array state whether each row was fetched successfully, whether it was updated, added,
or deleted since it was last fetched, and whether an error occurred while fetching the row. If SQLFetch or
SQLFetchScroll encounters an error while retrieving one row of a multirow rowset, or if SQLBulkOperations
with an Operation argument of SQL_FETCH_BY_BOOKMARK encounters an error while performing a bulk fetch,
it sets the corresponding value in the row status array to SQL_ROW_ERROR, continues fetching rows, and
returns SQL_SUCCESS_WITH_INFO. For more information about error handling and the row status array, see the
SQLFetch and SQLFetchScroll function descriptions.
SQLGetData and Block Cursors
4/27/2022 • 2 minutes to read • Edit Online

SQLGetData operates on a single column of a single row and cannot fetch an array containing data from
multiple rows. This is because the primary use of SQLGetData is to fetch long data in parts, and there is little or
no reason to do this for more than one row at a time.
To use SQLGetData with a block cursor, an application first calls SQLSetPos to position the cursor on a single
row. It then calls SQLGetData for a column in that row. However, this behavior is optional. To determine if a
driver supports the use of SQLGetData with block cursors, an application calls SQLGetInfo with the
SQL_GETDATA_EXTENSIONS option.
Row Status Array
4/27/2022 • 2 minutes to read • Edit Online

In addition to data, SQLFetch and SQLFetchScroll can return an array that gives the status of each row in the
rowset. This array is specified through the SQL_ATTR_ROW_STATUS_PTR statement attribute. This array is
allocated by the application and must have as many elements as are specified by the
SQL_ATTR_ROW_ARRAY_SIZE statement attribute. The values in the array are set by SQLBulkOperations ,
SQLFetch , SQLFetchScroll , and SQLSetPos. The values describe the status of the row and whether that
status has changed since it was last fetched.

RO W STAT US A RRAY VA L UE DESC RIP T IO N

SQL_ROW_SUCCESS The row was successfully fetched and has not changed since
it was last fetched.

SQL_ROW_SUCCESS_WITH_INFO The row was successfully fetched and has not changed since
it was last fetched. However, a warning was returned about
the row.

SQL_ROW_ERROR An error occurred while fetching the row.

SQL_ROW_UPDATED The row was successfully fetched and has been updated
since it was last fetched. If the row is fetched again or
refreshed by SQLSetPos , its status is changed to the new
status.

Some drivers cannot detect changes to data and therefore


cannot return this value. To determine whether a driver can
detect updates to refetched rows, an application calls
SQLGetInfo with the SQL_ROW_UPDATES option.

SQL_ROW_DELETED The row has been deleted since it was last fetched.

SQL_ROW_ADDED The row was inserted by SQLBulkOperations . If the row is


fetched again or is refreshed by SQLSetPos , its status is
SQL_ROW_SUCCESS.

This value is not set by SQLFetch or SQLFetchScroll.

SQL_ROW_NOROW The rowset overlapped the end of the result set, and no row
was returned that corresponded to this element of the row
status array.
Scrollable Cursors
4/27/2022 • 2 minutes to read • Edit Online

In modern screen-based applications, the user scrolls backward and forward through the data. For such
applications, returning to a previously fetched row is a problem. One possibility is to close and reopen the
cursor and then fetch rows until the cursor reaches the required row. Another possibility is to read the result set,
cache it locally, and implement scrolling in the application. Both possibilities work well only with small result
sets, and the latter possibility is difficult to implement. A better solution is to use a scrollable cursor, which can
move backward and forward in the result set.
A scrollable cursor is commonly used in modern screen-based applications in which the user scrolls back and
forth through the data. However, applications should use scrollable cursors only when forward-only cursors will
not do the job, as scrollable cursors are generally more expensive than forward-only cursors.
The ability to move backward raises a question not applicable to forward-only cursors: Should a scrollable
cursor detect changes made to rows previously fetched? That is, should it detect updated, deleted, and newly
inserted rows?
This question arises because the definition of a result set - the set of rows that matches certain criteria - does
not state when rows are checked to see whether they match that criteria, nor does it state whether rows must
contain the same data each time they are fetched. The former omission makes it possible for scrollable cursors
to detect whether rows have been inserted or deleted, while the latter makes it possible for them to detect
updated data.
The ability to detect changes is sometimes useful, sometimes not. For example, an accounting application needs
a cursor that ignores all changes; balancing books is impossible if the cursor shows the latest changes. On the
other hand, an airline reservation system needs a cursor that shows the latest changes to the data; without such
a cursor, it must continually requery the database to show the most up-to-date flight availability.
To cover the needs of different applications, ODBC defines four different types of scrollable cursors. These
cursors vary both in expense and in their ability to detect changes to the result set. Note that if a scrollable
cursor can detect changes to rows, it can only detect them when it attempts to refetch those rows; there is no
way for the data source to notify the cursor of changes to the currently fetched rows. Note as well that visibility
of changes is also controlled by the transaction isolation level; for more information, see Transaction Isolation.
This section contains the following topics.
Scrollable Cursor Types
Using Scrollable Cursors
Relative and Absolute Scrolling
Bookmarks
Scrollable Cursor Types
4/27/2022 • 2 minutes to read • Edit Online

The four types of scrollable cursors are static, dynamic, keyset-driven, and mixed. Static cursors detect few or no
changes but are relatively cheap to implement. Dynamic cursors detect all changes but are expensive to
implement. Keyset-driven and mixed cursors lie in between, detecting most changes but at less expense than
dynamic cursors.
The following terms are used to define the characteristics of each type of scrollable cursor:
Own updates, deletes, and inser ts. Updates, deletes, and inserts made through the cursor, either with
a call to SQLBulkOperations or SQLSetPos or with a positioned update or delete statement.
Other updates, deletes, and inser ts. Updates, deletes, and inserts not made by the cursor, including
those made by other operations in the same transaction, those made through other transactions, and
those made by other applications.
Membership. The set of rows in the result set.
Order. The order in which rows are returned by the cursor.
Values. The values in each row in the result set.
For information about how to update, delete, and insert data, see Updating Data Overview.
This section contains the following topics.
ODBC Static Cursors
ODBC Dynamic Cursors
Keyset-Driven Cursors
Mixed Cursors
ODBC Static Cursors
4/27/2022 • 2 minutes to read • Edit Online

A static cursor is one in which the result set appears to be static. It does not usually detect changes that were
made to the membership, order, or values of the result set after the cursor is opened. For example, suppose a
static cursor fetches a row and another application then updates that row. If the static cursor refetches the row,
the values it sees are unchanged, despite the changes that were made by the other application.
Static cursors can detect their own updates, deletes, and inserts, although they are not required to do this.
Whether a particular static cursor detects these changes is reported through the SQL_STATIC_SENSITIVITY
option in SQLGetInfo . Static cursors never detect other updates, deletes, and inserts.
The row status array specified by the SQL_ATTR_ROW_STATUS_PTR statement attribute can contain
SQL_ROW_SUCCESS, SQL_ROW_SUCCESS_WITH_INFO, or SQL_ROW_ERROR for any row. It returns
SQL_ROW_UPDATED, SQL_ROW_DELETED, or SQL_ROW_ADDED for rows updated, deleted, or inserted by the
cursor, assuming that the cursor can detect such changes.
Static cursors are typically implemented by locking the rows in the result set or by making a copy, or snapshot,
of the result set. Although locking rows is relatively easy to do, it has the drawback of significantly reducing
concurrency. Making a copy allows for greater concurrency and allows the cursor to keep track of its own
updates, deletes, and inserts by modifying the copy. However, a copy is more expensive to make and can diverge
from the underlying data as that data is changed by others.
ODBC Dynamic Cursors
4/27/2022 • 2 minutes to read • Edit Online

A dynamic cursor is just that: dynamic. It can detect any changes made to the membership, order, and values of
the result set after the cursor is opened. For example, suppose a dynamic cursor fetches two rows and another
application then updates one of those rows and deletes the other. If the dynamic cursor then attempts to refetch
those rows, it will not find the deleted row but will return the new values for the updated row.
Dynamic cursors detect all updates, deletes, and inserts, both their own and those made by others. (This is
subject to the isolation level of the transaction, as set by the SQL_ATTR_TXN_ISOLATION connection attribute.)
The row status array specified by the SQL_ATTR_ROW_STATUS_PTR statement attribute reflects these changes
and can contain SQL_ROW_SUCCESS, SQL_ROW_SUCCESS_WITH_INFO, SQL_ROW_ERROR,
SQL_ROW_UPDATED, and SQL_ROW_ADDED. It cannot return SQL_ROW_DELETED because a dynamic cursor
does not return deleted rows outside the rowset and therefore no longer recognizes the existence of the deleted
row in the result set or its corresponding element in the row status array. SQL_ROW_ADDED is returned only
when a row is updated by a call to SQLSetPos , not when it is updated by another cursor.
One way of implementing dynamic cursors in the database is by creating a selective index that defines the
membership and ordering of the result set. Because the index is updated when others make changes, a cursor
based on such an index is sensitive to all changes. Additional selection within the result set defined by this index
is possible by processing along the index.
Dynamic cursors can be simulated by requiring the result set to be ordered by a unique key. With such a
restriction, fetches are made by executing a SELECT statement each time the cursor fetches rows. For example,
suppose the result set is defined by this statement:

SELECT * FROM Customers ORDER BY Name, CustID

To fetch the next rowset in this result set, the simulated cursor sets the parameters in the following SELECT
statement to the values in the last row of the current rowset, and then executes it:

SELECT * FROM Customers WHERE (Name > ?) AND (CustID > ?)


ORDER BY Name, CustID

This statement creates a second result set, the first rowset of which is the next rowset in the original result set -
in this case, the set of rows in the Customers table. The cursor returns this rowset to the application.
It is interesting to note that a dynamic cursor implemented in this manner actually creates many result sets,
which allows it to detect changes to the original result set. The application never learns of the existence of these
auxiliary result sets; it simply appears as if the cursor is able to detect changes to the original result set.
Keyset-Driven Cursors
4/27/2022 • 2 minutes to read • Edit Online

A keyset-driven cursor lies between a static and a dynamic cursor in its ability to detect changes. Like a static
cursor, it does not always detect changes to the membership and order of the result set. Like a dynamic cursor, it
does detect changes to the values of rows in the result set (subject to the isolation level of the transaction, as set
by the SQL_ATTR_TXN_ISOLATION connection attribute).
When a keyset-driven cursor is opened, it saves the keys for the entire result set; this fixes the apparent
membership and order of the result set. As the cursor scrolls through the result set, it uses the keys in this
keyset to retrieve the current data values for each row. For example, suppose a keyset-driven cursor fetches a
row and another application then updates that row. If the cursor refetches the row, the values it sees are the new
ones because it refetched the row using its key. Because of this, the keyset-driven cursors always detect changes
made by themselves and others.
When the cursor attempts to retrieve a row that has been deleted, this row appears as a "hole" in the result set:
The key for the row exists in the keyset, but the row no longer exists in the result set. If the key values in a row
are updated, the row is considered to have been deleted and then inserted, so such rows also appear as holes in
the result set. While a keyset-driven cursor can always detect rows deleted by others, it can optionally remove
the keys for rows it deletes itself from the keyset. Keyset-driven cursors that do this cannot detect their own
deletes. Whether a particular keyset-driven cursor detects its own deletes is reported through the
SQL_STATIC_SENSITIVITY option in SQLGetInfo .
Rows inserted by others are never visible to a keyset-driven cursor because no keys for these rows exist in the
keyset. However, a keyset-driven cursor can optionally add the keys for rows it inserts itself to the keyset. Keyset-
driven cursors that do this can detect their own inserts. Whether a particular keyset-driven cursor detects its
own inserts is reported through the SQL_STATIC_SENSITIVITY option in SQLGetInfo .
The row status array specified by the SQL_ATTR_ROW_STATUS_PTR statement attribute can contain
SQL_ROW_SUCCESS, SQL_ROW_SUCCESS_WITH_INFO, or SQL_ROW_ERROR for any row. It returns
SQL_ROW_UPDATED, SQL_ROW_DELETED, or SQL_ROW_ADDED for rows it detects as updated, deleted, or
inserted.
Keyset-driven cursors are commonly implemented by creating a temporary table that contains the keys for each
row in the result set. Because the cursor must also determine whether rows have been updated, this table also
commonly contains a column with row versioning information.
To scroll over the original result set, the keyset-driven cursor opens a static cursor over the temporary table. To
retrieve a row in the original result set, the cursor first retrieves the appropriate key from the temporary table
and then retrieves the current values for the row. If block cursors are used, the cursor must retrieve multiple
keys and rows.
Mixed Cursors
4/27/2022 • 2 minutes to read • Edit Online

A mixed cursor is a combination of a keyset-driven cursor and a dynamic cursor. It is used when the result set is
too large to reasonably save keys for the entire result set. Mixed cursors are implemented by creating a keyset
that is smaller than the entire result set but larger than the rowset.
As long as the application scrolls within the keyset, the behavior is keyset-driven. When the application scrolls
outside the keyset, the behavior is dynamic: The cursor fetches the requested rows and creates a new keyset.
After the new keyset is created, the behavior reverts to keyset-driven within that keyset.
For example, suppose a result set has 1,000 rows and uses a mixed cursor with a keyset size of 100 and a rowset
size of 10. When the first rowset is fetched, the cursor creates a keyset consisting of the keys for the first 100
rows. It then returns the first 10 rows, as requested.
Now suppose another application deletes rows 11 and 101. If the cursor attempts to retrieve row 11, it will
encounter a gap because it has a key for this row but no row exists; this is keyset-driven behavior. If the cursor
attempts to retrieve row 101, the cursor will not detect that the row is missing because it does not have a key for
the row. Instead, it will retrieve what was previously row 102. This is dynamic cursor behavior.
A mixed cursor is equivalent to a keyset-driven cursor when the keyset size is equal to the result set size. A
mixed cursor is equivalent to a dynamic cursor when the keyset size is equal to 1.
Using Scrollable Cursors
4/27/2022 • 2 minutes to read • Edit Online

Using a scrollable cursor requires these three steps:


1. Determine the cursor capabilities.
2. Set up the cursor.
3. Scroll and fetch rows.
This section contains the following topics.
Determining Cursor Capabilities
Setting Up the Cursor
Cursor Characteristics and Cursor Type
Scrolling and Fetching Rows
Determining Cursor Capabilities
4/27/2022 • 2 minutes to read • Edit Online

The following four options in SQLGetInfo describe what types of cursors are supported and what their
capabilities are:
SQL_CURSOR_SENSITIVITY. Indicates whether a cursor is sensitive to changes made by another cursor.
SQL_SCROLL_OPTIONS. Lists the supported cursor types (forward-only, static, keyset-driven, dynamic, or
mixed). All data sources must support forward-only cursors.
SQL_DYNAMIC_CURSOR_ATTRIBUTES1, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1,
SQL_KEYSET_CURSOR_ATTRIBUTES1, or SQL_STATIC_CURSOR_ATTRIBUTES1 (depending on the type of
the cursor). Lists the fetch types supported by scrollable cursors. The bits in the return value correspond
to the fetch types in SQLFetchScroll .
SQL_KEYSET_CURSOR_ATTRIBUTES2 or SQL_STATIC_CURSOR_ATTRIBUTES2 (depending on the type of
the cursor). Lists whether static and keyset-driven cursors can detect their own updates, deletes, and
inserts.
An application can determine cursor capabilities at run time by calling SQLGetInfo with these options. This is
commonly done by generic applications. Cursor capabilities also can be determined during application
development and their use hard-coded into the application. This is commonly done by vertical and custom
applications but can also be done by generic applications that use a client-side cursor implementation such as
the ODBC cursor library.
Setting Up the Cursor
4/27/2022 • 2 minutes to read • Edit Online

The application can specify the cursor type before executing a statement that creates a result set. It does this
with the SQL_ATTR_CURSOR_TYPE statement attribute. If the application does not explicitly specify a type, a
forward-only cursor will be used. To get a mixed cursor, an application specifies a keyset-driven cursor but
declares a keyset size less than the result set size.
For keyset-driven and mixed cursors, the application can also specify the keyset size. It does this with the
SQL_ATTR_KEYSET_SIZE statement attribute. If the keyset size is set to 0, which is the default, the keyset size is
set to the result set size and a keyset-driven cursor is used. The keyset size can be changed after the cursor has
been opened.
The application can also set the rowset size; for more information, see Using Block Cursors, earlier in this
section.
Cursor Characteristics and Cursor Type
4/27/2022 • 2 minutes to read • Edit Online

An application can specify the characteristics of a cursor instead of specifying the cursor type (forward-only,
static, keyset-driven, or dynamic). To do this, the application selects the cursor's scrollability (by setting the
SQL_ATTR_CURSOR_SCROLLABLE statement attribute) and sensitivity (by setting the
SQL_ATTR_CURSOR_SENSITIVITY statement attribute) before opening the cursor on the statement handle. The
driver then chooses the cursor type that most efficiently provides the characteristics that the application
requested.
Whenever an application sets any of the statement attributes SQL_ATTR_CONCURRENCY,
SQL_ATTR_CURSOR_SCROLLABLE, SQL_ATTR_CURSOR_SENSITIVITY, or SQL_ATTR_CURSOR_TYPE, the driver
makes any required change to the other statement attributes in this set of four attributes so that their values
remain consistent. As a result, when the application specifies a cursor characteristic, the driver can change the
attribute that indicates cursor type based on this implicit selection; when the application specifies a type, the
driver can change any of the other attributes to be consistent with the characteristics of the selected type. For
more information about these statement attributes, see the SQLSetStmtAttr function description.
An application that sets statement attributes to specify both a cursor type and cursor characteristics runs the risk
of obtaining a cursor that is not the most efficient method available on that driver of meeting the application's
requirements.
The implicit setting of statement attributes is driver-defined except that it must follow these rules:
Forward-only cursors are never scrollable; see the definition of SQL_ATTR_CURSOR_SCROLLABLE in
SQLSetStmtAttr.
Insensitive cursors are never updatable (and thus their concurrency is read-only); this is based on their
definition of insensitive cursors in the ISO SQL standard.
Consequently, the implicit setting of statement attributes occurs in the cases described in the following table.

A P P L IC AT IO N SET S AT T RIB UT E TO OT H ER AT T RIB UT ES SET IM P L IC IT LY

SQL_ATTR_CONCURRENCY to SQL_CONCUR_READ_ONLY SQL_ATTR_CURSOR_SENSITIVITY to SQL_INSENSITIVE.

SQL_ATTR_CONCURRENCY to SQL_CONCUR_LOCK, SQL_ATTR_CURSOR_SENSITIVITY to SQL_UNSPECIFIED or


SQL_CONCUR_ROWVER, or SQL_CONCUR_VALUES SQL_SENSITIVE, as defined by the driver. It can never be set
to SQL_INSENSITIVE, because insensitive cursors are always
read-only.

SQL_ATTR_CURSOR_SCROLLABLE to SQL_NONSCROLLABLE SQL_ATTR_CURSOR_TYPE to


SQL_CURSOR_FORWARD_ONLY

SQL_ATTR_CURSOR_SCROLLABLE to SQL_SCROLLABLE SQL_ATTR_CURSOR_TYPE to SQL_CURSOR_STATIC,


SQL_CURSOR_KEYSET_DRIVEN, or SQL_CURSOR_DYNAMIC,
as specified by the driver. It is never set to
SQL_CURSOR_FORWARD_ONLY.

SQL_ATTR_CURSOR_SENSITIVITY to SQL_INSENSITIVE SQL_ATTR_CONCURRENCY to SQL_CONCUR_READ_ONLY.

SQL_ATTR_CURSOR_TYPE to SQL_CURSOR_STATIC.
A P P L IC AT IO N SET S AT T RIB UT E TO OT H ER AT T RIB UT ES SET IM P L IC IT LY

SQL_ATTR_CURSOR_SENSITIVITY to SQL_SENSITIVE SQL_ATTR_CONCURRENCY to SQL_CONCUR_LOCK,


SQL_CONCUR_ROWVER, or SQL_CONCUR_VALUES, as
specified by the driver. It is never set to
SQL_CONCUR_READ_ONLY.

SQL_ATTR_CURSOR_TYPE to
SQL_CURSOR_FORWARD_ONLY, SQL_CURSOR_STATIC,
SQL_CURSOR_KEYSET_DRIVEN, or SQL_CURSOR_DYNAMIC,
as specified by the driver.

SQL_ATTR_CURSOR_SENSITIVITY to SQL_UNSPECIFIED SQL_ATTR_CONCURRENCY to SQL_CONCUR_READ_ONLY,


SQL_CONCUR_LOCK, SQL_CONCUR_ROWVER, or
SQL_CONCUR_VALUES, as specified by the driver.

SQL_ATTR_CURSOR_TYPE to
SQL_CURSOR_FORWARD_ONLY, SQL_CURSOR_STATIC,
SQL_CURSOR_KEYSET_DRIVEN, or SQL_CURSOR_DYNAMIC,
as specified by the driver.

SQL_ATTR_CURSOR_TYPE to SQL_CURSOR_DYNAMIC SQL_ATTR_SCROLLABLE to SQL_SCROLLABLE.

SQL_ATTR_CURSOR_SENSITIVITY to SQL_SENSITIVE. (But


only if SQL_ATTR_CONCURRENCY is not equal to
SQL_CONCUR_READ_ONLY. Updatable dynamic cursors are
always sensitive to changes that were made in their own
transaction.)

SQL_ATTR_CURSOR_TYPE to SQL_ATTR_CURSOR_SCROLLABLE to
SQL_CURSOR_FORWARD_ONLY SQL_NONSCROLLABLE.

SQL_ATTR_CURSOR_TYPE to SQL_CURSOR_KEYSET_DRIVEN SQL_ATTR_SCROLLABLE to SQL_SCROLLABLE.

SQL_ATTR_SENSITIVITY to SQL_UNSPECIFIED or
SQL_SENSITIVE (according to driver-defined criteria, if
SQL_ATTR_CONCURRENCY is not
SQL_CONCUR_READ_ONLY).

SQL_ATTR_CURSOR_TYPE to SQL_CURSOR_STATIC SQL_ATTR_SCROLLABLE to SQL_SCROLLABLE.

SQL_ATTR_SENSITIVITY to SQL_INSENSITIVE (if


SQL_ATTR_CONCURRENCY is SQL_CONCUR_READ_ONLY).

SQL_ATTR_SENSITIVITY to SQL_UNSPECIFIED or
SQL_SENSITIVE (if SQL_ATTR_CONCURRENCY is not
SQL_CONCUR_READ_ONLY).
Scrolling and Fetching Rows (ODBC)
4/27/2022 • 2 minutes to read • Edit Online

When using a scrollable cursor, applications call SQLFetchScroll to position the cursor and fetch rows.
SQLFetchScroll supports relative scrolling (next, prior, and relative n rows), absolute scrolling (first, last, and
row n), and positioning by bookmark. The FetchOrientation and FetchOffset arguments in SQLFetchScroll
specify which rowset to fetch, as shown in the following diagrams.

Fetching Next, Prior, First, and Last Rowsets

Fetching Absolute, Relative, and Bookmarked Rowsets


SQLFetchScroll positions the cursor to the specified row and returns the rows in the rowset starting with that
row. If the specified rowset overlaps the end of the result set, a partial rowset is returned. If the specified rowset
overlaps the start of the result set, the first rowset in the result set is usually returned; for complete details, see
the SQLFetchScroll function description.
In some cases, the application might want to position the cursor without retrieving any data. For example, it
might want to test whether a row exists or just get the bookmark for the row without bringing other data across
the network. To do this, it sets the SQL_ATTR_RETRIEVE_DATA statement attribute to SQL_RD_OFF. The variable
bound to the bookmark column (if any) is always updated, regardless of the setting of this statement attribute.
After the rowset has been retrieved, the application can call SQLSetPos to position to a particular row in the
rowset or refresh rows in the rowset. For more information on using SQLSetPos , see Updating Data with
SQLSetPos.

NOTE
Scrolling is supported in ODBC 2.x drivers by SQLExtendedFetch . For more information, see Block Cursors, Scrollable
Cursors, and Backward Compatibilityin Appendix G: Driver Guidelines for Backward Compatibility.
Relative and Absolute Scrolling
4/27/2022 • 2 minutes to read • Edit Online

Most of the scrolling options in SQLFetchScroll position the cursor relative to the current position or to an
absolute position. SQLFetchScroll supports fetching the next, prior, first, and last rowsets, as well as relative
fetching (fetch the rowset n rows from the start of the current rowset) and absolute fetching (fetch the rowset
starting at row n). If n is negative in an absolute fetch, rows are counted from the end of the result set. Thus, an
absolute fetch of row -1 means to fetch the rowset that starts with the last row in the result set.
Dynamic cursors detect rows inserted into and deleted from the result set, so there is no easy way for dynamic
cursors to retrieve the row at a particular number other than reading from the start of the result set, which is
likely to be slow. Furthermore, absolute fetching is not very useful in dynamic cursors because row numbers
change as rows are inserted and deleted; therefore, successively fetching the same row number can yield
different rows.
Applications that use SQLFetchScroll only for its block cursor capabilities, such as reports, are likely to pass
through the result set a single time, using only the option to fetch the next rowset. Screen-based applications, on
the other hand, can take advantage of all the capabilities of SQLFetchScroll . If the application sets the rowset
size to the number of rows displayed on the screen and binds the screen buffers to the result set, it can translate
scroll bar operations directly to calls to SQLFetchScroll .

SC RO L L B A R O P ERAT IO N SQ L F ETC H SC RO L L SC RO L L IN G O P T IO N

Page up SQL_FETCH_PRIOR

Page down SQL_FETCH_NEXT

Line up SQL_FETCH_RELATIVE with FetchOffset equal to -1

Line down SQL_FETCH_RELATIVE with FetchOffset equal to 1

Scroll box at top SQL_FETCH_FIRST

Scroll box at bottom SQL_FETCH_LAST

Random scroll box position SQL_FETCH_ABSOLUTE

Such applications also need to position the scroll box after a scrolling operation, which requires the current row
number and the number of rows. For the current row number, applications can either keep track of the current
row number or call SQLGetStmtAttr with the SQL_ATTR_ROW_NUMBER attribute to retrieve it.
The number of rows in the cursor, which is the size of the result set, is available as the
SQL_DIAG_CURSOR_ROW_COUNT field of the diagnostic header. The value in this field is defined only after
SQLExecute , SQLExecDirect , or SQLMoreResult has been called. This count can be either an approximate
count or an exact count, depending on the capabilities of the driver. The driver's support can be determined by
calling SQLGetInfo with the cursor attributes information types and checking whether the
SQL_CA2_CRC_APPROXIMATE or SQL_CA2_CRC_EXACT bit is returned for the type of cursor.
An exact row count is never supported for a dynamic cursor. For other types of cursors, the driver can support
either exact or approximate row counts, but not both. If the driver supports neither exact nor approximate row
counts for a specific cursor type, the SQL_DIAG_CURSOR_ROW_COUNT field contains the number of rows that
have been fetched so far. Regardless of what the driver supports, SQLFetchScroll with an Operation of
SQL_FETCH_LAST will cause the SQL_DIAG_CURSOR_ROW_COUNT field to contain the exact row count.
Bookmarks (ODBC)
4/27/2022 • 2 minutes to read • Edit Online

A bookmark is a value used to identify a row of data. The meaning of the bookmark value is known only to the
driver or data source. For example, it might be as simple as a row number or as complex as a disk address.
Bookmarks in ODBC are a bit different from bookmarks in real books. In a real book, the reader places a
bookmark at a specific page and then looks for that bookmark to return to the page. In ODBC, the application
requests a bookmark for a particular row, stores it, and passes it back to the cursor to return to the row. Thus,
bookmarks in ODBC are similar to a reader writing down a page number, remembering it, and then looking up
the page again.
To determine a driver's support of bookmarks, an application calls SQLGetInfo with the
SQL_BOOKMARK_PERSISTENCE option. The bits in this value describe what operations bookmarks survive, such
as whether bookmarks are still valid after the cursor is closed.
This section contains the following topics.
Bookmark Types
Retrieving Bookmarks
Scrolling by Bookmark
Updating, Deleting, or Fetching by Bookmark
Comparing Bookmarks
Bookmark Types
4/27/2022 • 2 minutes to read • Edit Online

All bookmarks in ODBC 3.x are variable-length bookmarks. This allows a primary key or a unique index
associated with a table to be used as a bookmark. The bookmark also can be a 32-bit value, as was used in
ODBC 2.x. To specify that a bookmark is used with a cursor, an ODBC 3.x application sets the
SQL_ATTR_USE_BOOKMARK statement attribute to SQL_UB_VARIABLE. A variable-length bookmark is
automatically used.
An application can call SQLColAttribute with the FieldIdentifier argument set to SQL_DESC_OCTET_LENGTH to
obtain the length of the bookmark. Because a variable-length bookmark can be a long value, an application
should not bind to column 0 unless it will use the bookmark for many of the rows in the rowset.
Fixed-length bookmarks are supported only for backward compatibility. If an ODBC 2.x application working with
an ODBC 3.x driver calls SQLSetStmtOption to set SQL_USE_BOOKMARKS to SQL_UB_ON, it is mapped in the
Driver Manager to SQL_UB_VARIABLE. A variable-length bookmark is used, even if only 32 bits of it are
populated. If a driver supports fixed-length bookmarks, it will support variable-length bookmarks. If an ODBC
3.x application working with an ODBC 2.x driver calls SQLSetStmtAttr to set SQL_ATTR_USE_BOOKMARKS to
SQL_UB_VARIABLE, it is mapped in the Driver Manager to SQL_UB_ON and a 32-bit fixed-length bookmark is
used. The SQL_ATTR_FETCH_BOOKMARK_PTR statement attribute must then point to a 32-bit bookmark. If the
bookmarks used are longer than 32 bits, such as when primary keys are used as bookmarks, the cursor must
map the actual values to 32-bit values. It could, for example, build a hash table of them. When an ODBC 3.x
application working with an ODBC 2.x driver binds a bookmark, the buffer length must be 4.
Retrieving Bookmarks
4/27/2022 • 2 minutes to read • Edit Online

If the application will use bookmarks, it must set the SQL_ATTR_USE_BOOKMARKS statement attribute to
SQL_UB_VARIABLE before preparing or executing the statement. This is necessary because building and
maintaining bookmarks can be an expensive operation, so bookmarks should be enabled only when an
application can make good use of them.
Bookmarks are returned as column 0 of the result set. There are three ways an application can retrieve them:
Bind column 0 of the result set. SQLFetch or SQLFetchScroll returns the bookmarks for each row in
the rowset along with the data for other bound columns.
Call SQLSetPos to position to a row in the rowset and then call SQLGetData for column 0. If a driver
supports bookmarks, it must always support the ability to call SQLGetData for column 0, even if it does
not allow applications to call SQLGetData for other columns before the last bound column.
Call SQLBulkOperations with the Operation argument set to SQL_ADD, and column 0 bound. The
cursor inserts the row and returns the bookmark for the row in the bound buffer.
Scrolling by Bookmark
4/27/2022 • 2 minutes to read • Edit Online

When fetching rows with SQLFetchScroll , an application can use a bookmark as a basis for selecting the
starting row. This is a form of absolute addressing because it does not depend on the current cursor position. To
scroll to a bookmarked row, the application calls SQLFetchScroll with a FetchOrientation of
SQL_FETCH_BOOKMARK. This operation uses the bookmark pointed to by the
SQL_ATTR_FETCH_BOOKMARK_PTR statement attribute. It returns the rowset starting with the row identified by
that bookmark. An application can specify an offset for this operation in the FetchOffset argument of the call to
SQLFetchScroll . When an offset is specified, the first row of the returned rowset is determined by adding the
number in the FetchOffset argument to the number of the row identified by the bookmark. This use of the
FetchOffset argument is not supported when used with ODBC 2.x drivers; when an application calls
SQLFetchScroll in an ODBC 2.x driver with FetchOrientation set to SQL_FETCH_BOOKMARK, the FetchOffset
argument must be set to 0.
Updating, Deleting, or Fetching by Bookmark
4/27/2022 • 2 minutes to read • Edit Online

Bookmarks can be used to identify data to be updated in the result set, deleted from the result set, or fetched
from the result set to the rowset buffers. These operations are performed by a call to SQLBulkOperations with
an Option argument of SQL_UPDATE_BY_BOOKMARK, SQL_DELETE_BY_BOOKMARK, or
SQL_FETCH_BY_BOOKMARK. The bookmarks used in these operations are stored in column 0 of the rowset
buffers. When updating by bookmark, the data that result set columns are updated to is retrieved from the
rowset buffers. For more information, see Updating Data with SQLBulkOperations.
Comparing Bookmarks
4/27/2022 • 2 minutes to read • Edit Online

Because bookmarks are byte-comparable, they can be compared for equality or inequality. To do so, an
application treats each bookmark as an array of bytes and compares two bookmarks byte-by-byte. Because
bookmarks are guaranteed to be distinct only within a result set, it makes no sense to compare bookmarks that
were obtained from different result sets.
The ODBC Cursor Library
4/27/2022 • 2 minutes to read • Edit Online

IMPORTANT
This feature will be removed in a future version of Windows. Avoid using this feature in new development work and plan
to modify applications that currently use this feature. Microsoft recommends using the driver's cursor functionality.

Block and scrollable cursors are very useful additions to many applications. However, not all drivers support
block and scrollable cursors. The same is true of positioned update and delete statements and SQLSetPos ,
which are discussed in Updating Data. Therefore, the ODBC component of the Windows SDK, formerly included
in the Microsoft Data Access Components (MDAC) SDK, includes a cursor library. The cursor library implements
block, static cursors, positioned update and delete statements, and SQLSetPos for any driver that meets the
Open Group Standard CLI conformance level. The cursor library may be redistributed with ODBC applications;
see the licensing agreement in the SDK for more information.
To use the cursor library, an application sets the SQL_ATTR_ODBC_CURSORS connection attribute before it
connects to the data source. For more information about the cursor library, see Appendix F: ODBC Cursor
Library.
Multiple Results
4/27/2022 • 2 minutes to read • Edit Online

A result is something returned by the data source after a statement is executed. ODBC has two types of results:
result sets and row counts. Row counts are the number of rows affected by an update, delete, or insert
statement. Batches, described in Batches of SQL Statements, can generate multiple results.
The following table lists the SQLGetInfo options an application uses to determine whether a data source
returns multiple results for each different type of batch. In particular, a data source can return a single row count
for the entire batch of statements or individual row counts for each statement in the batch. In the case of a result
set-generating statement executed with an array of parameters, the data source can return a single result set for
all sets of parameters or individual result sets for each set of parameters.

B ATC H T Y P E RO W C O UN T S RESULT SET S

Explicit batch SQL_BATCH_ROW_COUNT[a] --[b]

Procedure SQL_BATCH_ROW_COUNT[a] --[b]

Arrays of parameters SQL_PARAM_ARRAYS_ROW_COUNTS SQL_PARAM_ARRAYS_SELECTS

[a] Row count-generating statements in a batch may be supported, yet the return of the row counts not
supported. The SQL_BATCH_SUPPORT option in SQLGetInfo indicates whether row count-generating
statements are allowed in batches; the SQL_BATCH_ROW_COUNTS option indicates whether these row counts
are returned to the application.
[b] Explicit batches and procedures always return multiple result sets when they include multiple result set-
generating statements.

NOTE
The SQL_MULT_RESULT_SETS option introduced in ODBC 1.0 provides only general information about whether multiple
result sets can be returned. In particular, it is set to "Y" if the SQL_BS_SELECT_EXPLICIT or SQL_BS_SELECT_PROC bits are
returned for SQL_BATCH_SUPPORT or if SQL_PAS_BATCH is returned for SQL_PARAM_ARRAYS_SELECT.

To process multiple results, an application calls SQLMoreResults . This function discards the current result and
makes the next result available. It returns SQL_NO_DATA when no more results are available. For example,
suppose the following statements are executed as a batch:

SELECT * FROM Parts WHERE Price > 100.00;


UPDATE Parts SET Price = 0.9 * Price WHERE Price > 100.00

After these statements are executed, the application fetches rows from the result set created by the SELECT
statement. When it is done fetching rows, it calls SQLMoreResults to make available the number of parts that
were repriced. If necessary, SQLMoreResults discards unfetched rows and closes the cursor. The application
then calls SQLRowCount to determine how many parts were repriced by the UPDATE statement.
It is driver-specific whether the entire batch statement is executed before any results are available. In some
implementations, this is the case; in others, calling SQLMoreResults triggers the execution of the next
statement in the batch.
If one of the statements in a batch fails, SQLMoreResults will return either SQL_ERROR or
SQL_SUCCESS_WITH_INFO. If the batch was aborted when the statement failed or the failed statement was the
last statement in the batch, SQLMoreResults will return SQL_ERROR. If the batch was not aborted when the
statement failed and the failed statement was not the last statement in the batch, SQLMoreResults will return
SQL_SUCCESS_WITH_INFO. SQL_SUCCESS_WITH_INFO indicates that at least one result set or count was
generated and that the batch was not aborted.
Updating Data Overview
4/27/2022 • 2 minutes to read • Edit Online

Applications can update data either by executing SQL statements or by calling SQLSetPos or
SQLBulkOperations . UPDATE , DELETE , and INSERT statements act directly on the data source and are
usually supported by drivers. Searched update and delete statements contain a specification of the rows to
change. Positioned update and delete statements and SQLSetPos act on the data source through a cursor and
are less widely supported.
Whether cursors can detect changes made to the result set with the methods described in this section depends
on the type of the cursor and how it is implemented. Forward-only cursors do not revisit rows and therefore will
not detect any changes. For information about whether scrollable cursors can detect changes, see Scrollable
Cursors.
This section contains the following topics.
UPDATE, DELETE, and INSERT Statements
Positioned Update and Delete Statements
Simulating Positioned Update and Delete Statements
Determining the Number of Affected Rows
Updating Data with SQLSetPos
Updating Data with SQLBulkOperations
Long Data and SQLSetPos and SQLBulkOperations
UPDATE, DELETE, and INSERT Statements
4/27/2022 • 2 minutes to read • Edit Online

SQL-based applications make changes to tables by executing the UPDATE , DELETE , and INSERT statements.
These statements are part of the Minimum SQL grammar conformance level and must be supported by all
drivers and data sources.
The syntax of these statements is:
UPDATE table-name
SET column-identifier = {expression | NULL }
[, column-identifier = {expression | NULL }]...
[WHERE search-condition]
DELETE FROM table-name[WHERE search-condition]
INSERT INTO table-name[( column-identifier [, column-identifier]...) ]
{query-specification | VALUES ( insert-value [, insert-value]...) }
Note that the query-specification element is valid only in the Core and Extended SQL grammars, and that the
expression and search-condition elements become more complex in the Core and Extended SQL grammars.
Like other SQL statements, UPDATE , DELETE , and INSERT statements are often more efficient when they use
parameters. For example, the following statement can be prepared and repeatedly executed to insert multiple
rows in the Orders table:

INSERT INTO Orders (PartID, Description, Price) VALUES (?, ?, ?)

This efficiency can be increased by passing arrays of parameter values. For more information about statement
parameters and arrays of parameter values, see Statement Parameters.
Positioned Update and Delete Statements
4/27/2022 • 3 minutes to read • Edit Online

Applications can update or delete the current row in a result set with a positioned update or delete statement.
Positioned update and delete statements are supported by some data sources, but not all of them. To determine
whether a data source supports positioned update and delete statements, an application calls SQLGetInfo with
the SQL_DYNAMIC_CURSOR_ATTRIBUTES1, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1,
SQL_KEYSET_CURSOR_ATTRIBUTES1, or SQL_STATIC_CURSOR_ATTRIBUTES1 InfoType (depending on the type
of the cursor). Note that the ODBC cursor library simulates positioned update and delete statements.
To use a positioned update or delete statement, the application must create a result set with a SELECT FOR
UPDATE statement. The syntax of this statement is:
SELECT [ALL | DISTINCT ] select-list
FROM table-reference-list
[WHERE search-condition]
FOR UPDATE OF [column-name [, column-name]...]
The application then positions the cursor on the row to be updated or deleted. It can do this by calling
SQLFetchScroll to retrieve a rowset containing the required row and calling SQLSetPos to position the
rowset cursor on that row. The application then executes the positioned update or delete statement on a
different statement than the statement being used by the result set. The syntax of these statements is:
UPDATE table-name
SET column-identifier = {expression | NULL }
[, column-identifier = {expression | NULL }]...
WHERE CURRENT OF cursor-name
DELETE FROM table-name WHERE CURRENT OF cursor-name
Notice that these statements require a cursor name. The application either can specify a cursor name with
SQLSetCursorName before executing the statement that creates the result set or can let the data source
automatically generate a cursor name when the cursor is created. In the latter case, the application retrieves this
cursor name for use in positioned update and delete statements by calling SQLGetCursorName .
For example, the following code allows a user to scroll through the Customers table and delete customer
records or update their addresses and phone numbers. It calls SQLSetCursorName to specify a cursor name
before it creates the result set of customers and uses three statement handles: hstmtCust for the result set,
hstmtUpdate for a positioned update statement, and hstmtDelete for a positioned delete statement. Although
the code could bind separate variables to the parameters in the positioned update statement, it updates the
rowset buffers and binds the elements of these buffers. This keeps the rowset buffers synchronized with the
updated data.

#define POSITIONED_UPDATE 100


#define POSITIONED_DELETE 101

SQLUINTEGER CustIDArray[10];
SQLCHAR NameArray[10][51], AddressArray[10][51],
PhoneArray[10][11];
SQLINTEGER CustIDIndArray[10], NameLenOrIndArray[10],
SQLINTEGER CustIDIndArray[10], NameLenOrIndArray[10],
AddressLenOrIndArray[10],
PhoneLenOrIndArray[10];
SQLUSMALLINT RowStatusArray[10], Action, RowNum;
SQLHSTMT hstmtCust, hstmtUpdate, hstmtDelete;

// Set the SQL_ATTR_BIND_TYPE statement attribute to use column-wise


// binding. Declare the rowset size with the SQL_ATTR_ROW_ARRAY_SIZE
// statement attribute. Set the SQL_ATTR_ROW_STATUS_PTR statement
// attribute to point to the row status array.
SQLSetStmtAttr(hstmtCust, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);
SQLSetStmtAttr(hstmtCust, SQL_ATTR_ROW_ARRAY_SIZE, 10, 0);
SQLSetStmtAttr(hstmtCust, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);

// Bind arrays to the CustID, Name, Address, and Phone columns.


SQLBindCol(hstmtCust, 1, SQL_C_ULONG, CustIDArray, 0, CustIDIndArray);
SQLBindCol(hstmtCust, 2, SQL_C_CHAR, NameArray, sizeof(NameArray[0]),
NameLenOrIndArray);
SQLBindCol(hstmtCust, 3, SQL_C_CHAR, AddressArray, sizeof(AddressArray[0]),
AddressLenOrIndArray);
SQLBindCol(hstmtCust, 4, SQL_C_CHAR, PhoneArray, sizeof(PhoneArray[0]),
PhoneLenOrIndArray);

// Set the cursor name to Cust.


SQLSetCursorName(hstmtCust, "Cust", SQL_NTS);

// Prepare positioned update and delete statements.


SQLPrepare(hstmtUpdate,
"UPDATE Customers SET Address = ?, Phone = ? WHERE CURRENT OF Cust",
SQL_NTS);
SQLPrepare(hstmtDelete, "DELETE FROM Customers WHERE CURRENT OF Cust", SQL_NTS);

// Execute a statement to retrieve rows from the Customers table.


SQLExecDirect(hstmtCust,
"SELECT CustID, Name, Address, Phone FROM Customers FOR UPDATE OF Address, Phone",
SQL_NTS);

// Fetch and display the first 10 rows.


SQLFetchScroll(hstmtCust, SQL_FETCH_NEXT, 0);
DisplayData(CustIDArray, CustIDIndArray, NameArray, NameLenOrIndArray, AddressArray,
AddressLenOrIndArray, PhoneArray, PhoneLenOrIndArray, RowStatusArray);

// Call GetAction to get an action and a row number from the user.
while (GetAction(&Action, &RowNum)) {
switch (Action) {

case SQL_FETCH_NEXT:
case SQL_FETCH_PRIOR:
case SQL_FETCH_FIRST:
case SQL_FETCH_LAST:
case SQL_FETCH_ABSOLUTE:
case SQL_FETCH_RELATIVE:
// Fetch and display the requested data.
SQLFetchScroll(hstmtCust, Action, RowNum);
DisplayData(CustIDArray, CustIDIndArray, NameArray, NameLenOrIndArray,
AddressArray, AddressLenOrIndArray, PhoneArray,
PhoneLenOrIndArray, RowStatusArray);
break;

case POSITIONED_UPDATE:
// Get the new data and place it in the rowset buffers.
GetNewData(AddressArray[RowNum - 1], &AddressLenOrIndArray[RowNum - 1],
PhoneArray[RowNum - 1], &PhoneLenOrIndArray[RowNum - 1]);

// Bind the elements of the arrays at position RowNum-1 to the


// parameters of the positioned update statement.
SQLBindParameter(hstmtUpdate, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
50, 0, AddressArray[RowNum - 1], sizeof(AddressArray[0]),
&AddressLenOrIndArray[RowNum - 1]);
SQLBindParameter(hstmtUpdate, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
SQLBindParameter(hstmtUpdate, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
10, 0, PhoneArray[RowNum - 1], sizeof(PhoneArray[0]),
&PhoneLenOrIndArray[RowNum - 1]);

// Position the rowset cursor. The rowset is 1-based.


SQLSetPos(hstmtCust, RowNum, SQL_POSITION, SQL_LOCK_NO_CHANGE);

// Execute the positioned update statement to update the row.


SQLExecute(hstmtUpdate);
break;

case POSITIONED_DELETE:
// Position the rowset cursor. The rowset is 1-based.
SQLSetPos(hstmtCust, RowNum, SQL_POSITION, SQL_LOCK_NO_CHANGE);

// Execute the positioned delete statement to delete the row.


SQLExecute(hstmtDelete);
break;
}
}

// Close the cursor.


SQLCloseCursor(hstmtCust);
Simulating Positioned Update and Delete
Statements
4/27/2022 • 4 minutes to read • Edit Online

If the data source does not support positioned update and delete statements, the driver can simulate these. For
example, the ODBC cursor library simulates positioned update and delete statements. The general strategy for
simulating positioned update and delete statements is to convert positioned statements to searched ones. This
is done by replacing the WHERE CURRENT OF clause with a searched WHERE clause that identifies the
current row.
For example, because the CustID column uniquely identifies each row in the Customers table, the positioned
delete statement

DELETE FROM Customers WHERE CURRENT OF CustCursor

might be converted to

DELETE FROM Customers WHERE (CustID = ?)

The driver may use one of the following row identifiers in the WHERE clause:
Columns whose values serve to identify uniquely every row in the table. For example, calling
SQLSpecialColumns with SQL_BEST_ROWID returns the optimal column or set of columns that serve
this purpose.
Pseudo-columns, provided by some data sources, for the purpose of uniquely identifying every row.
These may also be retrievable by calling SQLSpecialColumns .
A unique index, if available.
All the columns in the result set.
Exactly which columns a driver should use in the WHERE clause it constructs depends on the driver. On some
data sources, determining a row identifier can be costly. However, it is faster to execute and guarantees that a
simulated statement updates or deletes at most one row. Depending on the capabilities of the underlying DBMS,
using a row identifier can be expensive to set up. However, it is faster to execute and guarantees that a simulated
statement will update or delete only one row. The option of using all the columns in the result set is usually
much easier to set up. However, it is slower to execute and, if the columns do not uniquely identify a row, can
result in rows being unintentionally updated or deleted, especially when the select list for the result set does not
contain all the columns that exist in the underlying table.
Depending upon which of the preceding strategies the driver supports, an application can choose which
strategy it wants the driver to use with the SQL_ATTR_SIMULATE_CURSOR statement attribute. Although it
might seem odd for an application to risk unintentionally updating or deleting a row, the application can remove
this risk by ensuring that the columns in the result set uniquely identify each row in the result set. This saves the
driver the effort of having to do this.
If the driver chooses to use a row identifier, it intercepts the SELECT FOR UPDATE statement that creates the
result set. If the columns in the select list do not effectively identify a row, the driver adds the necessary columns
to the end of the select list. Some data sources have a single column that always uniquely identifies a row, such
as the ROWID column in Oracle; if such a column is available, the driver uses this. Otherwise, the driver calls
SQLSpecialColumns for each table in the FROM clause to retrieve a list of the columns that uniquely identify
each row. A common restriction that results from this technique is that cursor simulation fails if there is more
than one table in the FROM clause.
No matter how the driver identifies rows, it usually strips the FOR UPDATE OF clause off the SELECT FOR
UPDATE statement before sending it to the data source. The FOR UPDATE OF clause is used only with
positioned update and delete statements. Data sources that do not support positioned update and delete
statements generally do not support it.
When the application submits a positioned update or delete statement for execution, the driver replaces the
WHERE CURRENT OF clause with a WHERE clause containing the row identifier. The values of these columns
are retrieved from a cache maintained by the driver for each column it uses in the WHERE clause. After the
driver has replaced the WHERE clause, it sends the statement to the data source for execution.
For example, suppose that the application submits the following statement to create a result set:

SELECT Name, Address, Phone FROM Customers FOR UPDATE OF Phone, Address

If the application has set SQL_ATTR_SIMULATE_CURSOR to request a guarantee of uniqueness and if the data
source does not provide a pseudo-column that always uniquely identifies a row, the driver calls
SQLSpecialColumns for the Customers table, discovers that CustID is the key to the Customers table and adds
this to the select list, and strips the FOR UPDATE OF clause:

SELECT Name, Address, Phone, CustID FROM Customers

If the application has not requested a guarantee of uniqueness, the driver strips only the FOR UPDATE OF
clause:

SELECT Name, Address, Phone FROM Customers

Suppose the application scrolls through the result set and submits the following positioned update statement
for execution, where Cust is the name of the cursor over the result set:

UPDATE Customers SET Address = ?, Phone = ? WHERE CURRENT OF Cust

If the application has not requested a guarantee of uniqueness, the driver replaces the WHERE clause and binds
the CustID parameter to the variable in its cache:

UPDATE Customers SET Address = ?, Phone = ? WHERE (CustID = ?)

If the application has not requested a guarantee of uniqueness, the driver replaces the WHERE clause and binds
the Name, Address, and Phone parameters in this clause to the variables in its cache:

UPDATE Customers SET Address = ?, Phone = ?


WHERE (Name = ?) AND (Address = ?) AND (Phone = ?)
Determining the Number of Affected Rows
4/27/2022 • 2 minutes to read • Edit Online

After an application updates, deletes, or inserts rows, it can call SQLRowCount to determine how many rows
were affected. SQLRowCount returns this value whether or not the rows were updated, deleted, or inserted by
executing an UPDATE , DELETE , or INSERT statement, by executing a positioned update or delete statement, or
by calling SQLSetPos .
If a batch of SQL statements is executed, the count of affected rows might be a total count for all statements in
the batch or individual counts for each statement in the batch. For more information, see Batches of SQL
Statements and Multiple Results.
The number of affected rows is also returned in the SQL_DIAG_ROW_COUNT diagnostic header field in the
diagnostic area associated with the statement handle. However, the data in this field is reset after every function
call on the same statement handle, whereas the value returned by SQLRowCount remains the same until a call
to SQLBulkOperations , SQLExecute , SQLExecDirect , SQLPrepare , or SQLSetPos .
Updating Data with SQLSetPos
4/27/2022 • 2 minutes to read • Edit Online

Applications can update or delete any row in the rowset with SQLSetPos . Calling SQLSetPos is a convenient
alternative to constructing and executing an SQL statement. It lets an ODBC driver support positioned updates
even when the data source does not support positioned SQL statements. It is part of the paradigm of achieving
complete database access by means of function calls.
SQLSetPos operates on the current rowset and can be used only after a call to SQLFetchScroll . The
application specifies the number of the row to update, delete, or insert, and the driver retrieves the new data for
that row from the rowset buffers. SQLSetPos can also be used to designate a specified row as the current row,
or to refresh a particular row in the rowset from the data source.
Rowset size is set by a call to SQLSetStmtAttr with an Attribute argument of SQL_ATTR_ROW_ARRAY_SIZE.
SQLSetPos uses a new rowset size, however, only after a call to SQLFetch or SQLFetchScroll . For example, if
the rowset size is changed, SQLSetPos is called and then SQLFetch or SQLFetchScroll is called, and the call
to SQLSetPos uses the old rowset size while SQLFetch or SQLFetchScroll uses the new rowset size.
The first row in the rowset is row number 1. The RowNumber argument in SQLSetPos must identify a row in
the rowset; that is, its value must be in the range between 1 and the number of rows that were most recently
fetched (which may be less than the rowset size). If RowNumber is 0, the operation applies to every row in the
rowset.
Because most interaction with relational databases is done through SQL, SQLSetPos is not widely supported.
However, a driver can easily emulate it by constructing and executing an UPDATE or DELETE statement.
To determine what operations SQLSetPos supports, an application calls SQLGetInfo with the
SQL_DYNAMIC_CURSOR_ATTRIBUTES1, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1,
SQL_KEYSET_CURSOR_ATTRIBUTES1, or SQL_STATIC_CURSOR_ATTRIBUTES1 information option (depending on
the type of the cursor).
This section contains the following topics.
Updating Rows in the Rowset with SQLSetPos
Deleting Rows in the Rowset with SQLSetPos
Updating Rows in the Rowset with SQLSetPos
4/27/2022 • 3 minutes to read • Edit Online

The update operation of SQLSetPos makes the data source update one or more selected rows of a table, using
data in the application buffers for each bound column (unless the value in the length/indicator buffer is
SQL_COLUMN_IGNORE). Columns that are not bound will not be updated.
To update rows with SQLSetPos , the application does the following:
1. Places the new data values in the rowset buffers. For information on how to send long data with
SQLSetPos , see Long Data and SQLSetPos and SQLBulkOperations.
2. Sets the value in the length/indicator buffer of each column as necessary. This is the byte length of the
data or SQL_NTS for columns bound to string buffers, the byte length of the data for columns bound to
binary buffers, and SQL_NULL_DATA for any columns to be set to NULL.
3. Sets the value in the length/indicator buffer of those columns which are not to be updated to
SQL_COLUMN_IGNORE. Although the application can skip this step and resend existing data, this is
inefficient and risks sending values to the data source that were truncated when they were read.
4. Calls SQLSetPos with Operation set to SQL_UPDATE and RowNumber set to the number of the row to
update. If RowNumber is 0, all rows in the rowset are updated.
After SQLSetPos returns, the current row is set to the updated row.
When updating all rows of the rowset (RowNumber is equal to 0), an application can disable the update of
certain rows by setting the corresponding elements of the row operation array (pointed to by the
SQL_ATTR_ROW_OPERATION_PTR statement attribute) to SQL_ROW_IGNORE. The row operation array
corresponds in size and number of elements to the row status array (pointed to by the
SQL_ATTR_ROW_STATUS_PTR statement attribute). To update only those rows in the result set that were
successfully fetched and have not been deleted from the rowset, the application uses the row status array from
the function that fetched the rowset as the row operation array to SQLSetPos .
For every row that is sent to the data source as an update, the application buffers should have valid row data. If
the application buffers were filled by fetching and if a row status array has been maintained, its values at each of
these row positions should not be SQL_ROW_DELETED, SQL_ROW_ERROR, or SQL_ROW_NOROW.
For example, the following code allows a user to scroll through the Customers table and update, delete, or add
new rows. It places the new data in the rowset buffers before calling SQLSetPos to update or add new rows. An
extra row is allocated at the end of the rowset buffers to hold new rows; this prevents existing data from being
overwritten when data for a new row is placed in the buffers.

#define UPDATE_ROW 100


#define DELETE_ROW 101
#define ADD_ROW 102

SQLUINTEGER CustIDArray[11];
SQLCHAR NameArray[11][51], AddressArray[11][51],
PhoneArray[11][11];
SQLINTEGER CustIDIndArray[11], NameLenOrIndArray[11],
AddressLenOrIndArray[11],
PhoneLenOrIndArray[11];
SQLUSMALLINT RowStatusArray[10], Action, RowNum;
SQLRETURN rc;
SQLHSTMT hstmt;
// Set the SQL_ATTR_ROW_BIND_TYPE statement attribute to use column-wise
// binding. Declare the rowset size with the SQL_ATTR_ROW_ARRAY_SIZE
// statement attribute. Set the SQL_ATTR_ROW_STATUS_PTR statement
// attribute to point to the row status array.
SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, 10, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);

// Bind arrays to the CustID, Name, Address, and Phone columns.


SQLBindCol(hstmt, 1, SQL_C_ULONG, CustIDArray, 0, CustIDIndArray);
SQLBindCol(hstmt, 2, SQL_C_CHAR, NameArray, sizeof(NameArray[0]), NameLenOrIndArray);
SQLBindCol(hstmt, 3, SQL_C_CHAR, AddressArray, sizeof(AddressArray[0]),
AddressLenOrIndArray);
SQLBindCol(hstmt, 4, SQL_C_CHAR, PhoneArray, sizeof(PhoneArray[0]),
PhoneLenOrIndArray);

// Execute a statement to retrieve rows from the Customers table.


SQLExecDirect(hstmt, "SELECT CustID, Name, Address, Phone FROM Customers", SQL_NTS);

// Fetch and display the first 10 rows.


rc = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);
DisplayData(CustIDArray, CustIDIndArray, NameArray, NameLenOrIndArray, AddressArray,
AddressLenOrIndArray, PhoneArray, PhoneLenOrIndArray, RowStatusArray);

// Call GetAction to get an action and a row number from the user.
while (GetAction(&Action, &RowNum)) {
switch (Action) {

case SQL_FETCH_NEXT:
case SQL_FETCH_PRIOR:
case SQL_FETCH_FIRST:
case SQL_FETCH_LAST:
case SQL_FETCH_ABSOLUTE:
case SQL_FETCH_RELATIVE:
// Fetch and display the requested data.
SQLFetchScroll(hstmt, Action, RowNum);
DisplayData(CustIDArray, CustIDIndArray,
NameArray, NameLenOrIndArray,
AddressArray, AddressLenOrIndArray,
PhoneArray, PhoneLenOrIndArray, RowStatusArray);
break;

case UPDATE_ROW:
// Place the new data in the rowset buffers and update the
// specified row.
GetNewData(&CustIDArray[RowNum - 1], &CustIDIndArray[RowNum - 1],
NameArray[RowNum - 1], &NameLenOrIndArray[RowNum - 1],
AddressArray[RowNum - 1], &AddressLenOrIndArray[RowNum - 1],
PhoneArray[RowNum - 1], &PhoneLenOrIndArray[RowNum - 1]);
SQLSetPos(hstmt, RowNum, SQL_UPDATE, SQL_LOCK_NO_CHANGE);
break;

case DELETE_ROW:
// Delete the specified row.
SQLSetPos(hstmt, RowNum, SQL_DELETE, SQL_LOCK_NO_CHANGE);
break;

case ADD_ROW:
// Place the new data in the rowset buffers at index 10.
// This is an extra element for new rows so rowset data is
// not overwritten. Insert the new row. Row 11 corresponds
// to index 10.
GetNewData(&CustIDArray[10], &CustIDIndArray[10],
NameArray[10], &NameLenOrIndArray[10],
AddressArray[10], &AddressLenOrIndArray[10],
PhoneArray[10], &PhoneLenOrIndArray[10]);
SQLSetPos(hstmt, 11, SQL_ADD, SQL_LOCK_NO_CHANGE);
break;
break;
}
}

// Close the cursor.


SQLCloseCursor(hstmt);
Deleting Rows in the Rowset with SQLSetPos
4/27/2022 • 2 minutes to read • Edit Online

The delete operation of SQLSetPos makes the data source delete one or more selected rows of a table. To
delete rows with SQLSetPos , the application calls SQLSetPos with Operation set to SQL_DELETE and
RowNumber set to the number of the row to delete. If RowNumber is 0, all rows in the rowset are deleted.
After SQLSetPos returns, the deleted row is the current row and its status is SQL_ROW_DELETED. The row
cannot be used in any further positioned operations, such as calls to SQLGetData or SQLSetPos .
When deleting all rows of the rowset (RowNumber is equal to 0), the application can prevent the driver from
deleting certain rows by using the row operation array, in the same way as for the update operation of
SQLSetPos . (See Updating Rows in the Rowset with SQLSetPos.)
Every row that is deleted should be a row that exists in the result set. If the application buffers were filled by
fetching and if a row status array has been maintained, its values at each of these row positions should not be
SQL_ROW_DELETED, SQL_ROW_ERROR, or SQL_ROW_NOROW.
Updating Data with SQLBulkOperations
4/27/2022 • 2 minutes to read • Edit Online

Applications can perform bulk update, delete, fetch, or insertion operations on the underlying table at the data
source with a call to SQLBulkOperations . Calling SQLBulkOperations is a convenient alternative to
constructing and executing an SQL statement. It lets an ODBC driver support positioned updates even when the
data source does not support positioned SQL statements. It is part of the paradigm of achieving complete
database access by means of function calls.
SQLBulkOperations operates on the current rowset and can be used only after a call to SQLFetch or
SQLFetchScroll . The application specifies the rows to update, delete, or refresh by caching their bookmarks.
The driver retrieves the new data for rows to be updated, or the new data to be inserted into the underlying
table, from the rowset buffers.
The rowset size to be used by SQLBulkOperations is set by a call to SQLSetStmtAttr with an Attribute
argument of SQL_ATTR_ROW_ARRAY_SIZE. Unlike SQLSetPos , which uses a new rowset size only after a call to
SQLFetch or SQLFetchScroll , SQLBulkOperations uses the new rowset size after the call to
SQLSetStmtAttr .
Because most interaction with relational databases is done through SQL, SQLBulkOperations is not widely
supported. However, a driver can easily emulate it by constructing and executing an UPDATE , DELETE , or
INSERT statement.
To determine what operations SQLBulkOperation supports, an application calls SQLGetInfo with the
SQL_DYNAMIC_CURSOR_ATTRIBUTES1, SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1,
SQL_KEYSET_CURSOR_ATTRIBUTES1, or SQL_STATIC_CURSOR_ATTRIBUTES1 information option (depending on
the type of the cursor).
This section contains the following topics.
Updating Rows by Bookmark with SQLBulkOperations
Deleting Rows by Bookmark with SQLBulkOperations
Inserting Rows with SQLBulkOperations
Fetching Rows with SQLBulkOperations
Updating Rows by Bookmark with
SQLBulkOperations
4/27/2022 • 2 minutes to read • Edit Online

When updating a row by bookmark, SQLBulkOperations makes the data source update one or more rows of
the table. The rows are identified by the bookmark in a bound bookmark column. The row is updated using data
in the application buffers for each bound column (except when the value in the length/indicator buffer for a
column is SQL_COLUMN_IGNORE). Unbound columns will not be updated.
To update rows by bookmark with SQLBulkOperations , the application:
1. Retrieves and caches the bookmarks of all rows to be updated. If there is more than one bookmark and
column-wise binding is used, the bookmarks are stored in an array; if there is more than one bookmark
and row-wise binding is used, the bookmarks are stored in an array of row structures.
2. Sets the SQL_ATTR_ROW_ARRAY_SIZE statement attribute to the number of bookmarks and binds the
buffer containing the bookmark value, or the array of bookmarks, to column 0.
3. Places the new data values in the rowset buffers. For information on how to send long data with
SQLBulkOperations , see Long Data and SQLSetPos and SQLBulkOperations.
4. Sets the value in the length/indicator buffer of each column as necessary. This is the byte length of the
data or SQL_NTS for columns bound to string buffers, the byte length of the data for columns bound to
binary buffers, and SQL_NULL_DATA for any columns to be set to NULL.
5. Sets the value in the length/indicator buffer of those columns that are not to be updated to
SQL_COLUMN_IGNORE. Although the application can skip this step and resend existing data, this is
inefficient and risks sending values to the data source that were truncated when they were read.
6. Calls SQLBulkOperations with the Operation argument set to SQL_UPDATE_BY_BOOKMARK.
For every row that is sent to the data source as an update, the application buffers should have valid row data. If
the application buffers were filled by fetching, if a row status array has been maintained, and if the status value
for a row is SQL_ROW_DELETED, SQL_ROW_ERROR, or SQL_ROW_NOROW, invalid data could inadvertently be
sent to the data source.
Deleting Rows by Bookmark with
SQLBulkOperations
4/27/2022 • 2 minutes to read • Edit Online

When deleting a row by bookmark, SQLBulkOperations makes the data source delete one or more selected
rows of the table. The rows are identified by the bookmark in a bound bookmark column.
To delete rows by bookmark with SQLBulkOperations , the application does the following:
1. Retrieves and caches the bookmarks of all rows to be deleted. If there is more than one bookmark and
column-wise binding is used, the bookmarks are stored in an array; if there is more than one bookmark
and row-wise binding is used, the bookmarks are stored in an array of row structures.
2. Sets the SQL_ATTR_ROW_ARRAY_SIZE statement attribute to the number of bookmarks and binds the
buffer containing the bookmark value, or the array of bookmarks, to column 0.
3. Calls SQLBulkOperations with Operation set to SQL_DELETE_BY_BOOKMARK.
Inserting Rows with SQLBulkOperations
4/27/2022 • 2 minutes to read • Edit Online

Inserting data with SQLBulkOperations is similar to updating data with SQLBulkOperations because it uses
data from the bound application buffers.
So that each column in the new row has a value, all bound columns with a length/indicator value of
SQL_COLUMN_IGNORE and all unbound columns must either accept NULL values or have a default.
To insert rows with SQLBulkOperations , the application does the following:
1. Sets the SQL_ATTR_ROW_ARRAY_SIZE statement attribute to the number of rows to insert and places the
new data values in the bound application buffers. For information on how to send long data with
SQLBulkOperations , see Long Data and SQLSetPos and SQLBulkOperations.
2. Sets the value in the length/indicator buffer of each column as necessary. This is the byte length of the
data or SQL_NTS for columns bound to string buffers, the byte length of the data for columns bound to
binary buffers, and SQL_NULL_DATA for any columns to be set to NULL. The application sets the value in
the length/indicator buffer of those columns that are to be set to their default (if one exists) or NULL (if
one does not) to SQL_COLUMN_IGNORE.
3. Calls SQLBulkOperations with the Operation argument set to SQL_ADD.
After SQLBulkOperations returns, the current row is unchanged. If the bookmark column (column 0) is bound,
SQLBulkOperations returns the bookmarks of the inserted rows in the rowset buffer bound to that column.
Fetching Rows with SQLBulkOperations
4/27/2022 • 2 minutes to read • Edit Online

Data can be refetched into a rowset using bookmarks by a call to SQLBulkOperations. The rows to be fetched
are identified by the bookmarks in a bound bookmark column. Columns with a value of SQL_COLUMN_IGNORE
are not fetched.
To perform bulk fetches with SQLBulkOperations , the application does the following:
1. Retrieves and caches the bookmarks of all rows to be updated. If there is more than one bookmark and
column-wise binding is used, the bookmarks are stored in an array; if there is more than one bookmark
and row-wise binding is used, the bookmarks are stored in an array of row structures.
2. Sets the SQL_ATTR_ROW_ARRAY_SIZE statement attribute to the number of rows to fetch and binds the
buffer containing the bookmark value, or the array of bookmarks, to column 0.
3. Sets the value in the length/indicator buffer of each column as necessary. This is the byte length of the
data or SQL_NTS for columns bound to string buffers, the byte length of the data for columns bound to
binary buffers, and SQL_NULL_DATA for any columns to be set to NULL. The application sets the value in
the length/indicator buffer of those columns that are to be set to their default (if one exists) or NULL (if
one does not) to SQL_COLUMN_IGNORE.
4. Calls SQLBulkOperations with the Operation argument set to SQL_FETCH_BY_BOOKMARK.
There is no need for the application to use the row operation array to prevent the operation to be performed on
certain columns. The application selects the rows it wants to fetch by copying only the bookmarks for those
rows into the bound bookmark array.
Long Data and SQLSetPos and SQLBulkOperations
4/27/2022 • 3 minutes to read • Edit Online

As is the case with parameters in SQL statements, long data can be sent when updating rows with
SQLBulkOperations or SQLSetPos or when inserting rows with SQLBulkOperations . The data is sent in
parts, with multiple calls to SQLPutData . Columns for which data is sent at execution time are known as data-
at-execution columns.

NOTE
An application actually can send any type of data at execution time with SQLPutData , although only character and
binary data can be sent in parts. However, if the data is small enough to fit in a single buffer, there is generally no reason
to use SQLPutData . It is much easier to bind the buffer and let the driver retrieve the data from the buffer.

Because long data columns typically are not bound, the application must bind the column before calling
SQLBulkOperations or SQLSetPos and unbind it after calling SQLBulkOperations or SQLSetPos . The
column must be bound because SQLBulkOperations or SQLSetPos operates only on bound columns and
must be unbound so that SQLGetData can be used to retrieve data from the column.
To send data at execution time, the application does the following:
1. Places a 32-bit value in the rowset buffer instead of a data value. This value will be returned to the
application later, so the application should set it to a meaningful value, such as the number of the column
or the handle of a file containing data.
2. Sets the value in the length/indicator buffer to the result of the SQL_LEN_DATA_AT_EXEC(length) macro.
This value indicates to the driver that the data for the parameter will be sent with SQLPutData . The
length value is used when sending long data to a data source that needs to know how many bytes of long
data will be sent so that it can preallocate space. To determine whether a data source requires this value,
the application calls SQLGetInfo with the SQL_NEED_LONG_DATA_LEN option. All drivers must support
this macro; if the data source does not require the byte length, the driver can ignore it.
3. Calls SQLBulkOperations or SQLSetPos . The driver discovers that a length/indicator buffer contains
the result of the SQL_LEN_DATA_AT_EXEC(length) macro and returns SQL_NEED_DATA as the return value
of the function.
4. Calls SQLParamData in response to the SQL_NEED_DATA return value. If long data needs to be sent,
SQLParamData returns SQL_NEED_DATA. In the buffer pointed to by the ValuePtrPtr argument, the
driver returns the unique value that the application placed in the rowset buffer. If there is more than one
data-at-execution column, the application uses this value to determine which column to send data for; the
driver is not required to request data for data-at-execution columns in any particular order.
5. Calls SQLPutData to send the column data to the driver. If the column data does not fit in a single buffer,
as is often the case with long data, the application calls SQLPutData repeatedly to send the data in parts;
it is up to the driver and data source to reassemble the data. If the application passes null-terminated
string data, the driver or data source must remove the null-termination character as part of the
reassembly process.
6. Calls SQLParamData again to indicate that it has sent all of the data for the column. If there are any
data-at-execution columns for which data has not been sent, the driver returns SQL_NEED_DATA and the
unique value for the next data-at-execution column; the application returns to step 5. If data has been sent
for all data-at-execution columns, the data for the row is sent to the data source. SQLParamData then
returns SQL_SUCCESS or SQL_SUCCESS_WITH_INFO and can return any SQLSTATE that
SQLBulkOperations or SQLSetPos can return.
After SQLBulkOperations or SQLSetPos returns SQL_NEED_DATA and before data has been completely sent
for the last data-at-execution column, the statement is in a Need Data state. In this state, the application can call
only SQLPutData , SQLParamData , SQLCancel , SQLGetDiagField , or SQLGetDiagRec ; all other functions
return SQLSTATE HY010 (Function sequence error). Calling SQLCancel cancels execution of the statement and
returns it to its previous state. For more information, see Appendix B: ODBC State Transition Tables.
Descriptors
4/27/2022 • 2 minutes to read • Edit Online

A descriptor handle refers to a data structure that holds information about either columns or dynamic
parameters.
ODBC functions that operate on column and parameter data implicitly set and retrieve descriptor fields. For
instance, when SQLBindCol is called to bind column data, it sets descriptor fields that completely describe the
binding. When SQLColAttribute is called to describe column data, it returns data stored in descriptor fields.
An application calling ODBC functions need not concern itself with descriptors. No database operation requires
that the application gain direct access to descriptors. However, for some applications, gaining direct access to
descriptors streamlines many operations. For example, direct access to descriptors provides a way to rebind
column data, which can be more efficient than calling SQLBindCol again.

NOTE
The physical representation of the descriptor is not defined. Applications gain direct access to a descriptor only by
manipulating its fields by calling ODBC functions with the descriptor handle.

This section contains the following topics.


Types of Descriptors
Descriptor Fields
Allocating and Freeing Descriptors
Getting and Setting Descriptor Fields
Types of Descriptors
4/27/2022 • 2 minutes to read • Edit Online

A descriptor is used to describe one of the following:


A set of zero or more parameters. A parameter descriptor can be used to describe:
The application parameter buffer, which contains either the input dynamic arguments as set by the
application or the output dynamic arguments following the execution of a CALL statement of SQL.
The implementation parameter buffer. For input dynamic arguments, this contains the same
arguments as the application parameter buffer, after any data conversion the application may
specify. For output dynamic arguments, this contains the returned arguments, before any data
conversion that the application may specify.
For input dynamic arguments, the application must operate on an application parameter descriptor
before executing any SQL statement that contains dynamic parameter markers. For both input and
output dynamic arguments, the application can specify different data types from those in the
implementation parameter descriptor to achieve data conversion.
A single row of database data. A row descriptor can be used to describe:
The implementation row buffer, which contains the row from the database. (These buffers
conceptually contain data as written to or read from the database. However, the stored form of
database data is not specified. A database could perform additional conversion on the data from
its form in the implementation buffer.)
The application row buffer, which contains the row of data as presented to the application,
following any data conversion that the application may specify.
The application operates on the application row descriptor in any case where column data from the
database must appear in application variables. To achieve data conversion of column data, the application
can specify different data types from those in the implementation row descriptor.
The descriptor types are summarized in the following table.

B UF F ER T Y P E RO W S DY N A M IC PA RA M ET ERS

Application buffer Application row descriptor (ARD) Application parameter descriptor (APD)

Implementation buffer Implementation row descriptor (IRD) Implementation parameter descriptor


(IPD)

For either the parameter or the row buffers, if the application specifies different data types in corresponding
records of the implementation and application descriptors, the driver performs data conversion when it uses the
descriptors. For example, it may convert numeric and datetime values to character-string format. (For valid
conversions, see Appendix D: Data Types.)
A descriptor can perform different roles. Different statements can share any descriptor that the application
explicitly allocates. A row descriptor in one statement can serve as a parameter descriptor in another statement.
It is always known whether a given descriptor is an application descriptor or an implementation descriptor, even
if the descriptor has not yet been used in a database operation. For the descriptors that the implementation
implicitly allocates, the implementation records the predefined row relative to the statement handle. Any
descriptor that the application allocates by calling SQL AllocHandle is an application descriptor.
Descriptor Fields
4/27/2022 • 2 minutes to read • Edit Online

Descriptors contain header and record fields that completely describe columns or parameters.
A descriptor contains a single copy of the following header fields. Changing a header field affects all columns or
parameters.
SQL_DESC_ALLOC_TYPE
SQL_DESC_ARRAY_SIZE
SQL_DESC_ARRAY_STATUS_PTR
SQL_DESC_BIND_OFFSET_PTR
SQL_DESC_BIND_TYPE
SQL_DESC_COUNT
SQL_DESC_ROWS_PROCESSED_PTR
A descriptor contains zero or more descriptor records. Each record describes a column or parameter, depending
on the type of descriptor. When a new column or parameter is bound, a new record is added to the descriptor.
When a column or parameter is unbound, a record is removed from the descriptor. Each record contains a single
copy of the following fields:
SQL_DESC_AUTO_UNIQUE_VALUE
SQL_DESC_BASE_COLUMN_NAME
SQL_DESC_BASE_TABLE_NAME
SQL_DESC_CASE_SENSITIVE
SQL_DESC_CATALOG_NAME
SQL_DESC_CONCISE_TYPE
SQL_DESC_DATA_PTR
SQL_DESC_DATETIME_INTERVAL_CODE
SQL_DESC_DATETIME_INTERVAL_PRECISION
SQL_DESC_DISPLAY_SIZE
SQL_DESC_FIXED_PREC_SCALE
SQL_DESC_INDICATOR_PTR
SQL_DESC_LABEL
SQL_DESC_LENGTH
SQL_DESC_LITERAL_PREFIX
SQL_DESC_LITERAL_SUFFIX
SQL_DESC_LOCAL_TYPE_NAME
SQL_DESC_NAME
SQL_DESC_NULLABLE
SQL_DESC_OCTET_LENGTH
SQL_DESC_OCTET_LENGTH_PTR
SQL_DESC_PARAMETER_TYPE
SQL_DESC_PRECISION
SQL_DESC_SCALE
SQL_DESC_SCHEMA_NAME
SQL_DESC_SEARCHABLE
SQL_DESC_TABLE_NAME
SQL_DESC_TYPE
SQL_DESC_TYPE_NAME
SQL_DESC_UNNAMED
SQL_DESC_UNSIGNED
SQL_DESC_UPDATABLE
Many statement attributes correspond to the header field of a descriptor. Setting these attributes through a call
to SQLSetStmtAttr and setting the corresponding descriptor header field by calling SQLSetDescField have
the same effect. The same is true for SQLGetStmtAttr and SQLGetDescField , both of which retrieve the same
information. Calling the statement functions instead of the descriptor functions has the advantage that a
descriptor handle does not have to be retrieved.
The following header fields can be set by setting statement attributes:
SQL_DESC_ARRAY_SIZE
SQL_DESC_ARRAY_STATUS_PTR
SQL_DESC_BIND_OFFSET_PTR
SQL_DESC_BIND_TYPE
SQL_DESC_ROWS_PROCESSED_PTR
This section contains the following topics.
Record Count
Bound Descriptor Records
Deferred Fields
Consistency Check
Record Count
4/27/2022 • 2 minutes to read • Edit Online

The SQL_DESC_COUNT header field of a descriptor is the one-based index of the highest-numbered record that
contains data. This field is not a count of all columns or parameters that are bound. When a descriptor is
allocated, the initial value of SQL_DESC_COUNT is 0.
The driver takes any action necessary to allocate and maintain whatever storage it requires to hold descriptor
information. The application does not explicitly specify the size of a descriptor nor allocate new records. When
the application provides information for a descriptor record whose number is higher than the value of
SQL_DESC_COUNT, the driver automatically increases SQL_DESC_COUNT. When the application unbinds the
highest-numbered descriptor record, the driver automatically decreases SQL_DESC_COUNT to contain the
number of the highest remaining bound record.
Bound Descriptor Records
4/27/2022 • 2 minutes to read • Edit Online

When the application sets the SQL_DESC_DATA_PTR field of a descriptor record so that it no longer contains a
null value, the record is said to be bound.
If the descriptor is an APD, each bound record constitutes a bound parameter. For input parameters, the
application must bind a parameter for each dynamic parameter marker in the SQL statement before executing
the statement. For output parameters, the application need not bind the parameter.
If the descriptor is an ARD, which describes a row of database data, each bound record constitutes a bound
column.
Deferred Fields
4/27/2022 • 2 minutes to read • Edit Online

The values of deferred fields are not used when they are set, but the driver saves the addresses of the variables
for a deferred effect. For an application parameter descriptor, the driver uses the contents of the variables at the
time of the call to SQLExecDirect or SQLExecute . For an application row descriptor, the driver uses the
contents of the variables at the time of the fetch.
The following are deferred fields:
The SQL_DESC_DATA_PTR and SQL_DESC_INDICATOR_PTR fields of a descriptor record.
The SQL_DESC_OCTET_LENGTH_PTR field of an application descriptor record.
In the case of a multirow fetch, the SQL_DESC_ARRAY_STATUS_PTR and
SQL_DESC_ROWS_PROCESSED_PTR fields of a descriptor header.
When a descriptor is allocated, the deferred fields of each descriptor record initially have a null value. The
meaning of the null value is as follows:
If SQL_DESC_ARRAY_STATUS_PTR has a null value, a multirow fetch fails to return this component of the
per-row diagnostic information.
If SQL_DESC_DATA_PTR has a null value, the record is unbound.
If the SQL_DESC_OCTET_LENGTH_PTR field of an ARD has a null value, the driver does not return length
information for that column.
If the SQL_DESC_OCTET_LENGTH_PTR field of an APD has a null value and the parameter is a character
string, the driver assumes that string is null-terminated. For output dynamic parameters, a null value in
this field prevents the driver from returning length information. (If the SQL_DESC_TYPE field does not
indicate a character-string parameter, the SQL_DESC_OCTET_LENGTH_PTR field is ignored.)
The application must not deallocate or discard variables used for deferred fields between the time it associates
them with the fields and the time the driver reads or writes them.
Consistency Check
4/27/2022 • 2 minutes to read • Edit Online

A consistency check is performed by the driver automatically whenever an application sets the
SQL_DESC_DATA_PTR field of the APD, ARD, or IPD. Whenever this field is set, the driver checks that the value of
the SQL_DESC_TYPE field and the values applicable to the SQL_DESC_TYPE field in the same record are valid
and consistent.
The SQL_DESC_DATA_PTR field of an IPD is not normally set; however, an application can do so to force a
consistency check of IPD fields. The value that the SQL_DESC_DATA_PTR field of the IPD is set to is not actually
stored and cannot be retrieved by a call to SQLGetDescField or SQLGetDescRec ; the setting is made only to
force the consistency check. A consistency check cannot be performed on an IRD.
For more information on the consistency check, see SQLSetDescRec.
Allocating and Freeing Descriptors
4/27/2022 • 2 minutes to read • Edit Online

Descriptors are either implicitly or explicitly allocated, as described in the following sections.
Implicitly Allocated Descriptors
Explicitly Allocated Descriptors
Initialization of Descriptor Fields
Automatic Population of the IPD
Freeing Descriptors
Implicitly Allocated Descriptors
4/27/2022 • 2 minutes to read • Edit Online

When a statement handle is allocated, the application implicitly allocates one set of four descriptors. The
application can obtain the handles of these implicitly allocated descriptors as attributes of the statement handle.
When the application frees the statement handle, the driver frees all implicitly allocated descriptors on that
handle.
Explicitly Allocated Descriptors
4/27/2022 • 2 minutes to read • Edit Online

An application can explicitly allocate an application descriptor on a connection at any time it is connected to the
database. By specifying that descriptor handle as an attribute of a statement handle using SQLSetStmtAttr , the
application directs the driver to use that descriptor in place of the corresponding implicitly allocated application
descriptors. The application cannot specify alternate implementation descriptors.
An application can associate an explicitly allocated descriptor with more than one statement. Only when an
application is actually connected to the database can a descriptor be an explicitly allocated descriptor. The
application can free such a descriptor explicitly, or implicitly by freeing its connection.
Initialization of Descriptor Fields
4/27/2022 • 2 minutes to read • Edit Online

When an application row descriptor is allocated, its fields receive initial values as indicated in SQLSetDescField.
The initial value of the SQL_DESC_TYPE field is SQL_DEFAULT. This provides for a standard treatment of
database data for presentation to the application. The application may specify different treatment of the data by
setting fields of the descriptor record.
The initial value of SQL_DESC_ARRAY_SIZE in the descriptor header is 1. The application can modify this field to
enable multirow fetch.
The concept of a default value is not valid for the fields of an IRD. An application can gain access to the fields of
an IRD only when there is a prepared or executed statement associated with it.
Certain fields of an IPD are defined only after the IPD has been automatically populated by the driver. If not, they
are undefined. These fields are SQL_DESC_CASE_SENSITIVE, SQL_DESC_FIXED_PREC_SCALE,
SQL_DESC_TYPE_NAME, SQL_DESC_UNSIGNED, and SQL_DESC_LOCAL_TYPE_NAME.
Automatic Population of the IPD
4/27/2022 • 2 minutes to read • Edit Online

Some drivers are capable of setting the fields of the IPD after a parameterized query has been prepared. The
descriptor fields are automatically populated with information about the parameter, including the data type,
precision, scale, and other characteristics. This is equivalent to supporting SQLDescribeParam . This
information can be particularly valuable to an application when it has no other way to discover it, such as when
an ad hoc query is performed with parameters that the application does not know about.
An application determines whether the driver supports automatic population by calling SQLGetConnectAttr
with an Attribute of SQL_ATTR_AUTO_IPD. If SQL_TRUE is returned, the driver supports it and the application can
enable it by setting the SQL_ATTR_ENABLE_AUTO_IPD statement attribute to SQL_TRUE.
When automatic population is supported and enabled, the driver populates the fields of the IPD after an SQL
statement containing parameter markers has been prepared by a call to SQLPrepare . An application can
retrieve this information by calling SQLGetDescField or SQLGetDescRec , or SQLDescribeParam . The
application can use the information to bind the most appropriate application buffer for a parameter or to specify
a data conversion for it.
Automatic population of the IPD might produce a performance penalty. An application can turn it off by
resetting the SQL_ATTR_ENABLE_AUTO_IPD statement attribute to SQL_FALSE (the default value).
Freeing Descriptors
4/27/2022 • 2 minutes to read • Edit Online

Explicitly allocated descriptors can be freed either explicitly, by calling SQLFreeHandle with HandleType of
SQL_HANDLE_DESC, or implicitly, when the connection handle is freed. When an explicitly allocated descriptor is
freed, all statement handles to which the freed descriptor applied automatically revert to the descriptors
implicitly allocated for them.
Implicitly allocated descriptors can be freed only by calling SQLDisconnect , which drops any statements or
descriptors open on the connection, or by calling SQLFreeHandle with a HandleType of SQL_HANDLE_STMT to
free a statement handle and all the implicitly allocated descriptors associated with the statement. An implicitly
allocated descriptor cannot be freed by calling SQLFreeHandle with a HandleType of SQL_HANDLE_DESC.
Even when freed, an implicitly allocated descriptor remains valid, and SQLGetDescField can be called on its
fields.
Getting and Setting Descriptor Fields
4/27/2022 • 2 minutes to read • Edit Online

This section describes the methods an application can use to retrieve or set the values in descriptor fields.
This section contains the following topics.
Obtaining Descriptor Handles
Retrieving the Values in Descriptor Fields
Setting Descriptor Fields
Copying Descriptors
Using Concise Functions
Obtaining Descriptor Handles
4/27/2022 • 2 minutes to read • Edit Online

An application obtains the handle of any explicitly allocated descriptor as an output argument of the call to
SQL AllocHandle . The handle of an implicitly allocated descriptor is obtained by calling SQLGetStmtAttr .
Retrieving the Values in Descriptor Fields
4/27/2022 • 2 minutes to read • Edit Online

An application can call SQLGetDescField to obtain a single field of a descriptor record. SQLGetDescField
gives the application access to all the descriptor fields defined in ODBC, and to driver-defined fields as well.
SQLGetDescRec can be called to retrieve the settings of multiple descriptor fields that affect the data type and
storage of column or parameter data.
Setting Descriptor Fields
4/27/2022 • 2 minutes to read • Edit Online

To modify the fields of a descriptor, an application can call SQLSetDescField . Some fields are read-only and
cannot be set. (See the SQLSetDescField function description.)
Descriptor record fields are set with a record number (RecNumber) of 1 or higher, while descriptor header fields
are set with a record number of 0. A record number of 0 is also used to set bookmark fields, in accordance with
the convention that bookmarks are contained in column 0. This might leave the impression that bookmark fields
are contained within the descriptor header, but this is not the case. Bookmark fields are distinct from header
fields.
When setting fields individually, the application should follow the sequence defined in SQLSetDescField. Setting
some fields causes the driver to set other fields. This ensures that the descriptor is always ready to use once the
application has specified a data type. When the application sets the SQL_DESC_TYPE field, the driver checks that
other fields that specify the type are valid and consistent.
If a function call that would set a descriptor field fails, the contents of the descriptor field are undefined after the
failed function call.
Copying Descriptors
4/27/2022 • 2 minutes to read • Edit Online

The SQLCopyDesc function is called to copy the fields of one descriptor to another descriptor. Fields can be
copied only to an application descriptor or an IPD, but not to an IRD. Fields can be copied from any type of
descriptor. Only those fields that are defined for both the source and target descriptors are copied.
SQLCopyDesc does not copy the SQL_DESC_ALLOC_TYPE field, because a descriptor's allocation type cannot
be changed. Copied fields overwrite the existing fields.
An ARD on one statement handle can serve as the APD on another statement handle. This allows an application
to copy rows between tables without copying data at the application level. To do this, a row descriptor that
describes a fetched row of a table is reused as a parameter descriptor for a parameter in an INSERT statement.
The SQL_MAX_CONCURRENT_ACTIVITIES information type must be greater than 1 for this operation to
succeed.
Using Concise Functions
4/27/2022 • 2 minutes to read • Edit Online

Some ODBC functions gain implicit access to descriptors. Application writers may find them more convenient
than calling SQLSetDescField or SQLGetDescField . These functions are called concise functions because they
perform a number of functions, including setting or getting descriptor fields. Some concise functions let an
application set or retrieve several related descriptor fields in a single function call.
Concise functions can be called without first retrieving a descriptor handle for use as an argument. These
functions work with the descriptor fields associated with the statement handle that they are called on.
The concise functions SQLBindCol and SQLBindParameter bind a column or parameter by setting the
descriptor fields that correspond to their arguments. Each of these functions performs more tasks than simply
setting descriptors. SQLBindCol and SQLBindParameter provide a complete specification of the binding of a
data column or dynamic parameter. An application can, however, change individual details of a binding by
calling SQLSetDescField or SQLSetDescRec and can completely bind a column or parameter by making a
series of suitable calls to these functions.
The concise functions SQLColAttribute , SQLDescribeCol , SQLDescribeParam , SQLNumParams , and
SQLNumResultCols retrieve values in descriptor fields.
SQLSetDescRec and SQLGetDescRec are concise functions that, with one call, set or get multiple descriptor
fields that affect the data type and storage of column or parameter data. SQLSetDescRec is an effective way to
change the binding of column or parameter data in one step.
SQLSetStmtAttr and SQLGetStmtAttr serve as concise functions in some cases. (See Descriptor Fields.)
Transactions ODBC
4/27/2022 • 2 minutes to read • Edit Online

A transaction is a unit of work that is done as a single,atomic operation; that is, the operation succeeds or fails as
a whole. For example, consider transferring money from one bank account to another. This involves two steps:
withdrawing the money from the first account and depositing it in the second. It is important that both steps
succeed; it is not acceptable for one step to succeed and the other to fail. A database that supports transactions
is able to guarantee this.
Transactions can be completed by either being committed or being rolled back. When a transaction is
committed, the changes made in that transaction are made permanent. When a transaction is rolled back, the
affected rows are returned to the state they were in before the transaction was started. To extend the account
transfer example, an application executes one SQL statement to debit the first account and a different SQL
statement to credit the second account. If both statements succeed, the application then commits the
transaction. But if either statement fails for any reason, the application rolls back the transaction. In either case,
the application guarantees a consistent state at the end of the transaction.
A single transaction can encompass multiple database operations that occur at different times. If other
transactions had complete access to the intermediate results, the transactions might interfere with one another.
For example, suppose one transaction inserts a row, a second transaction reads that row, and the first
transaction is rolled back. The second transaction now has data for a row that does not exist.
To solve this problem, there are various schemes to isolate transactions from one another. Transaction isolation
is generally implemented by locking rows, which precludes more than one transaction from using the same row
at the same time. In some databases, locking a row may also lock other rows.
With increased transaction isolation comes reduced concurrency, or the ability of two transactions to use the
same data at the same time. For more information, see Setting the Transaction Isolation Level.
This section contains the following topics.
Transactions in ODBC
Transaction Isolation
Concurrency Control
Transactions in ODBC ODBC
4/27/2022 • 2 minutes to read • Edit Online

Transactions in ODBC are completed at the connection level; that is, when an application completes a
transaction, it commits or rolls back all work done through all statement handles on that connection.
This section contains the following topics.
Transaction Support
Commit Mode
Committing and Rolling Back Transactions
Effect of Transactions on Cursors and Prepared Statements
Transaction Support
4/27/2022 • 2 minutes to read • Edit Online

The degree of support for transactions is driver-defined. ODBC is designed to be implemented on a single-user
or desktop database that has no need to manage multiple updates to its data. Moreover, some databases that
support transactions do so only for the Data Manipulation Language (DML) statements of SQL; there are
restrictions or special transaction semantics regarding the use of Data Definition Language (DDL) when a
transaction is active. That is, there may be transaction support for multiple simultaneous updates to tables but
not for changing the number and definition of tables during a transaction.
An application determines whether transactions are supported, whether DDL can be included in a transaction,
and any special effects of including DDL in a transaction, by calling SQLGetInfo with the SQL_TXN_CAPABLE
option. For more information, see the SQLGetInfo function description.
If the driver does not support transactions but the application has the ability (using an API other than ODBC) to
lock and unlock data, applications can achieve transaction support by locking and unlocking records and tables
as needed. To implement the account-transfer example, the application would lock the records for both accounts,
copy the current values, debit the first account, credit the second account, and unlock the records. If any steps
failed, the application would reset the accounts using the copies.
Even data sources that support transactions might not be able to support more than one transaction at a time
within a particular environment. Applications call SQLGetInfo with the SQL_MULTIPLE_ACTIVE_TXN option to
determine whether a data source can support simultaneous active transactions on more than one connection in
the same environment. Because there is one transaction per connection, this is only interesting to applications
that have multiple connections to the same data source.
Commit Mode
4/27/2022 • 2 minutes to read • Edit Online

Transactions in ODBC can be in one of two modes: auto-commit mode or manual-commit mode.
This section contains the following topics.
Auto-Commit Mode
Manual-Commit Mode
Setting the Commit Mode
Auto-Commit Mode
4/27/2022 • 2 minutes to read • Edit Online

In auto-commit mode, every database operation is a transaction that is committed when performed. This mode
is suitable for many real-world transactions that consist of a single SQL statement. It is unnecessary to delimit or
specify completion of these transactions. In databases without transaction support, auto-commit mode is the
only supported mode. In such databases, statements are committed when they are executed and there is no way
to roll them back; they are therefore always in auto-commit mode.
If the underlying DBMS does not support auto-commit mode transactions, the driver can emulate them by
manually committing each SQL statement as it is executed.
If a batch of SQL statements is executed in auto-commit mode, it is data source-specific when the statements in
the batch are committed. They can be committed as they are executed or as a whole after the entire batch has
been executed. Some data sources may support both of these behaviors and may provide a way of selecting one
or the others. In particular, if an error occurs in the middle of the batch, it is data source-specific whether the
already-executed statements are committed or rolled back. Thus, interoperable applications that use batches
and require them to be committed or rolled back as a whole should execute batches only in manual-commit
mode.
Manual-Commit Mode
4/27/2022 • 2 minutes to read • Edit Online

In manual-commit mode, applications must explicitly complete transactions by calling SQLEndTran to commit
them or roll them back. This is the normal transaction mode for most relational databases.
Transactions in ODBC do not have to be explicitly initiated. Instead, a transaction begins implicitly whenever the
application starts operating on the database. If the data source requires explicit transaction initiation, the driver
must provide it whenever the application executes a statement requiring a transaction and there is no current
transaction.
Setting the Commit Mode
4/27/2022 • 2 minutes to read • Edit Online

Applications specify the transaction mode with the SQL_ATTR_AUTOCOMMIT connection attribute. By default,
ODBC transactions are in auto-commit mode (unless SQLSetConnectAttr and SQLSetConnectOption are
not supported, which is unlikely). Switching from manual-commit mode to auto-commit mode automatically
commits any open transaction on the connection.
Committing and Rolling Back Transactions
4/27/2022 • 2 minutes to read • Edit Online

To commit or roll back a transaction in manual-commit mode, an application calls SQLEndTran . Drivers for
DBMSs that support transactions typically implement this function by executing a COMMIT or ROLLBACK
statement. The Driver Manager does not call SQLEndTran when the connection is in auto-commit mode; it
simply returns SQL_SUCCESS, even if the application attempts to roll back the transaction. Because drivers for
DBMSs that do not support transactions are always in auto-commit mode, they can either implement
SQLEndTran to return SQL_SUCCESS without doing anything or not implement it at all.

NOTE
Applications should not commit or roll back transactions by executing COMMIT or ROLLBACK statements with
SQLExecute or SQLExecDirect . The effects of doing this are undefined. Possible problems include the driver no longer
knowing when a transaction is active and these statements failing against data sources that do not support transactions.
These applications should call SQLEndTran instead.

If an application passes the environment handle to SQLEndTran but does not pass a connection handle, the
Driver Manager conceptually calls SQLEndTran with the environment handle for each driver that has one or
more active connections in the environment. The driver then commits the transactions on each connection in the
environment. However, it is important to realize that neither the driver nor the Driver Manager performs a two-
phase commit on the connections in the environment; this is merely a programming convenience to
simultaneously call SQLEndTran for all connections in the environment.
(A two-phase commit is generally used to commit transactions that are spread across multiple data sources. In
its first phase, the data sources are polled as to whether they can commit their part of the transaction. In the
second phase, the transaction is actually committed on all data sources. If any data sources reply in the first
phase that they cannot commit the transaction, the second phase does not occur.)
Effect of Transactions on Cursors and Prepared
Statements
4/27/2022 • 2 minutes to read • Edit Online

Committing or rolling back a transaction has one of the following effects on cursors and access plans:
All cursors are closed, and access plans for prepared statements on that connection are deleted, or
All cursors are closed, and access plans for prepared statements on that connection remain intact, or
All cursors remain open, and access plans for prepared statements on that connection remain intact.
For example, suppose a data source exhibits the first behavior in this list, the most restrictive of these behaviors.
Now suppose an application does the following:
1. Sets the commit mode to manual-commit.
2. Creates a result set of sales orders on statement 1.
3. Creates a result set of the lines in a sales order on statement 2, when the user highlights that order.
4. Calls SQLExecute to execute a positioned update statement that has been prepared on statement 3,
when the user updates a line.
5. Calls SQLEndTran to commit the positioned update statement.
Because of the data source's behavior, the call to SQLEndTran in step 5 causes it to close the cursors on
statements 1 and 2 and to delete the access plan on all statements. The application must reexecute statements 1
and 2 to re-create the result sets and reprepare the statement on statement 3.
In auto-commit mode, functions other than SQLEndTran commit transactions:
SQLExecute or SQLExecDirect In the preceding example, the call to SQLExecute in step 4 commits a
transaction. This causes the data source to close the cursors on statements 1 and 2 and delete the access
plan on all statements on that connection.
SQLBulkOperations or SQLSetPos In the preceding example, suppose that in step 4 the application
calls SQLSetPos with the SQL_UPDATE option on statement 2, instead of executing a positioned update
statement on statement 3. This commits a transaction and causes the data source to close the cursors on
statements 1 and 2, and discards all access plans on that connection.
SQLCloseCursor In the preceding example, suppose that when the user highlights a different sales
order, the application calls SQLCloseCursor on statement 2 before creating a result of the lines for the
new sales order. The call to SQLCloseCursor commits the SELECT statement that created the result set
of lines and causes the data source to close the cursor on statement 1, and then discards all access plans
on that connection.
Applications, especially screen-based applications in which the user scrolls around the result set and updates or
deletes rows, must be careful to code around this behavior.
To determine how a data source behaves when a transaction is committed or rolled back, an application calls
SQLGetInfo with the SQL_CURSOR_COMMIT_BEHAVIOR and SQL_CURSOR_ROLLBACK_BEHAVIOR options.
Transaction Isolation
4/27/2022 • 2 minutes to read • Edit Online

Transaction isolation refers to the degree of interaction between multiple concurrent transactions. To see why
this is important, you'll need to first look at the idea of serializability.
This section contains the following topics.
Serializability
Transaction Isolation Levels
Setting the Transaction Isolation Level
Scrollable Cursors and Transaction Isolation
Serializability
4/27/2022 • 2 minutes to read • Edit Online

Ideally, transactions should be serializable. Transactions are said to be serializable if the results of running
transactions simultaneously are the same as the results of running them serially - that is, one after the other. It is
not important which transaction executes first, only that the result does not reflect any mixing of the
transactions.
For example, suppose transaction A multiplies data values by 2 and transaction B adds 1 to data values. Now
suppose that there are two data values: 0 and 10. If these transactions are run one after the other, the new values
will be 1 and 21 if transaction A is run first, or 2 and 22 if transaction B is run first. But what if the order in which
the two transactions are run is different for each value? If transaction A is run first on the first value and
transaction B is run first on the second value, the new values are 1 and 22. If this order is reversed, the new
values are 2 and 21. The transactions are serializable if 1, 21 and 2, 22 are the only possible results. The
transactions are not serializable if 1, 22 or 2, 21 is a possible result.
So why is serializability desirable? In other words, why is it important that it appears that one transaction
finishes before the next transaction starts? Consider the following problem. A salesman is entering orders at the
same time a clerk is sending out bills. Suppose the salesman enters an order from Company X but does not
commit it; the salesman is still talking to the representative from Company X. The clerk requests a list of all open
orders and discovers the order for Company X and sends them a bill. Now the representative from Company X
decides they want to change their order, so the salesman changes it before committing the transaction.
Company X gets an incorrect bill.
If the salesman's and clerk's transactions were serializable, this problem would never have occurred. Either the
salesman's transaction would have finished before the clerk's transaction started, in which case the clerk would
have sent out the correct bill, or the clerk's transaction would have finished before the salesman's transaction
started, in which case the clerk would not have sent a bill to Company X at all.
Transaction Isolation Levels (ODBC)
4/27/2022 • 4 minutes to read • Edit Online

Transaction isolation levels are a measure of the extent to which transaction isolation succeeds. In particular,
transaction isolation levels are defined by the presence or absence of the following phenomena:
Dir ty Reads A dirty read occurs when a transaction reads data that has not yet been committed. For
example, suppose transaction 1 updates a row. Transaction 2 reads the updated row before transaction 1
commits the update. If transaction 1 rolls back the change, transaction 2 will have read data that is
considered never to have existed.
Nonrepeatable Reads A nonrepeatable read occurs when a transaction reads the same row twice but
gets different data each time. For example, suppose transaction 1 reads a row. Transaction 2 updates or
deletes that row and commits the update or delete. If transaction 1 rereads the row, it retrieves different
row values or discovers that the row has been deleted.
Phantoms A phantom is a row that matches the search criteria but is not initially seen. For example,
suppose transaction 1 reads a set of rows that satisfy some search criteria. Transaction 2 generates a new
row (through either an update or an insert) that matches the search criteria for transaction 1. If
transaction 1 reexecutes the statement that reads the rows, it gets a different set of rows.
The four transaction isolation levels (as defined by SQL-92) are defined in terms of these phenomena. In the
following table, an "X" marks each phenomenon that can occur.

T RA N SA C T IO N ISO L AT IO N
L EVEL DIRT Y REA DS N O N REP EATA B L E REA DS P H A N TO M S

Read uncommitted X X X

Read committed -- X X

Repeatable read -- -- X

Serializable -- -- --

The following table describes simple ways that a DBMS might implement the transaction isolation levels.

IMPORTANT
Most DBMSs use more complex schemes than these to increase concurrency. These examples are provided for illustration
purposes only. In particular, ODBC does not prescribe how particular DBMSs isolate transactions from each other.

T RA N SA C T IO N ISO L AT IO N P O SSIB L E IM P L EM EN TAT IO N

Read uncommitted Transactions are not isolated from each other. If the DBMS
supports other transaction isolation levels, it ignores
whatever mechanism it uses to implement those levels. So
that they do not adversely affect other transactions,
transactions running at the Read Uncommitted level are
usually read-only.
T RA N SA C T IO N ISO L AT IO N P O SSIB L E IM P L EM EN TAT IO N

Read committed The transaction waits until rows write-locked by other


transactions are unlocked; this prevents it from reading any
"dirty" data.

The transaction holds a read lock (if it only reads the row) or
write lock (if it updates or deletes the row) on the current
row to prevent other transactions from updating or deleting
it. The transaction releases read locks when it moves off the
current row. It holds write locks until it is committed or rolled
back.

Repeatable read The transaction waits until rows write-locked by other


transactions are unlocked; this prevents it from reading any
"dirty" data.

The transaction holds read locks on all rows it returns to the


application and write locks on all rows it inserts, updates, or
deletes. For example, if the transaction includes the SQL
statement SELECT * FROM Orders , the transaction read-
locks rows as the application fetches them. If the transaction
includes the SQL statement DELETE FROM Orders
WHERE Status = 'CLOSED' , the transaction write-locks
rows as it deletes them.

Because other transactions cannot update or delete these


rows, the current transaction avoids any nonrepeatable
reads. The transaction releases its locks when it is committed
or rolled back.

Serializable The transaction waits until rows write-locked by other


transactions are unlocked; this prevents it from reading any
"dirty" data.

The transaction holds a read lock (if it only reads rows) or


write lock (if it can update or delete rows) on the range of
rows it affects. For example, if the transaction includes the
SQL statement SELECT * FROM Orders , the range is the
entire Orders table; the transaction read-locks the table and
does not allow any new rows to be inserted into it. If the
transaction includes the SQL statement DELETE FROM
Orders WHERE Status = 'CLOSED' , the range is all rows
with a Status of "CLOSED"; the transaction write-locks all
rows in the Orders table with a Status of "CLOSED" and does
not allow any rows to be inserted or updated such that the
resulting row has a Status of "CLOSED".

Because other transactions cannot update or delete the rows


in the range, the current transaction avoids any
nonrepeatable reads. Because other transactions cannot
insert any rows in the range, the current transaction avoids
any phantoms. The transaction releases its lock when it is
committed or rolled back.

It is important to note that the transaction isolation level does not affect a transaction's ability to see its own
changes; transactions can always see any changes they make. For example, a transaction might consist of two
UPDATE statements, the first of which raises the pay of all employees by 10 percent and the second of which
sets the pay of any employees over some maximum amount to that amount. This succeeds as a single
transaction only because the second UPDATE statement can see the results of the first.
Setting the Transaction Isolation Level
4/27/2022 • 2 minutes to read • Edit Online

To set the transaction isolation level, an application uses the SQL_ATTR_TXN_ISOLATION connection attribute. If
the data source does not support the requested isolation level, the driver or data source can set a higher level. To
determine what transaction isolation levels a data source supports and what the default isolation level is, an
application calls SQLGetInfo with the SQL_TXN_ISOLATION_OPTION and SQL_DEFAULT_TXN_ISOLATION
options, respectively.
Higher levels of transaction isolation offer the most protection for the integrity of database data. Serializable
transactions are guaranteed to be unaffected by other transactions and therefore guaranteed to maintain
database integrity.
However, a higher level of transaction isolation can cause slower performance because it increases the chances
that the application will have to wait for locks on data to be released. An application can specify a lower level of
isolation to increase performance in the following cases:
When it can be guaranteed that no other transactions exist that might interfere with an application's
transactions. This situation occurs only in limited circumstances, such as when one person in a small
company maintains dBASE files that contain personnel data on one computer and does not share these
files.
When speed is more critical than accuracy and any errors are likely to be small. For example, suppose
that a company makes many small sales and that large sales are rare. A transaction that estimates the
total value of all open sales might safely use the Read Uncommitted isolation level. Although the
transaction would include orders that are being opened or closed and are subsequently rolled back, these
would generally cancel each other out and the transaction would be much faster because it is not blocked
every time that it encounters such an order.
For more information, see Optimistic Concurrency.
Scrollable Cursors and Transaction Isolation
4/27/2022 • 2 minutes to read • Edit Online

The following table lists the factors governing the visibility of changes.

C H A N GES M A DE B Y : VISIB IL IT Y DEP EN DS O N :

Cursor Cursor type, cursor implementation

Other statements in same transaction Cursor type

Statements in other transactions Cursor type, transaction isolation level

These factors are shown in the following illustration.

The following table summarizes the ability of each cursor type to detect changes made by itself, by other
operations in its own transaction, and by other transactions. The visibility of the latter changes depends on the
cursor type and the isolation level of the transaction containing the cursor.

OT H R OT H R OT H R OT H R

C URSO R OWN T XN T XN T XN T XN
T Y P E\ A C T IO
N SEL F T XN ( RU[ A ] ) ( RC [ A ] ) ( RR[ A ] ) ( S[ A ] )

Static

Insert Maybe[b] No No No No No

Update Maybe[b] No No No No No

Delete Maybe[b] No No No No No

Keyset-driven

Insert Maybe[b] No No No No No

Update Yes Yes Yes Yes No No


OT H R OT H R OT H R OT H R

C URSO R OWN T XN T XN T XN T XN
T Y P E\ A C T IO
N SEL F T XN ( RU[ A ] ) ( RC [ A ] ) ( RR[ A ] ) ( S[ A ] )

Delete Maybe[b] Yes Yes Yes No No

Dynamic

Insert Yes Yes Yes Yes Yes No

Update Yes Yes Yes Yes No No

Delete Yes Yes Yes Yes No No

[a] The letters in parentheses indicate the isolation level of the transaction containing the cursor; the isolation
level of the other transaction (in which the change was made) is irrelevant.
RU: Read uncommitted
RC: Read committed
RR: Repeatable read
S: Serializable
[b] Depends on how the cursor is implemented. Whether the cursor can detect such changes is reported
through the SQL_STATIC_SENSITIVITY option in SQLGetInfo .
Concurrency Control
4/27/2022 • 2 minutes to read • Edit Online

Concurrency is the ability of two transactions to use the same data at the same time, and with increased
transaction isolation usually comes reduced concurrency. This is because transaction isolation is usually
implemented by locking rows, and as more rows are locked, fewer transactions can be completed without being
blocked at least temporarily by a locked row. While reduced concurrency is generally accepted as a trade-off for
the higher transaction isolation levels necessary to maintain database integrity, it can become a problem in
interactive applications with high read/write activity that use cursors.
For example, suppose an application executes the SQL statement SELECT * FROM Orders . It calls
SQLFetchScroll to scroll around the result set and allows the user to update, delete, or insert orders. After the
user updates, deletes, or inserts an order, the application commits the transaction.
If the isolation level is Repeatable Read, the transaction might - depending on how it is implemented - lock each
row returned by SQLFetchScroll . If the isolation level is Serializable, the transaction might lock the entire
Orders table. In either case, the transaction releases its locks only when it is committed or rolled back. So if the
user spends a lot of time reading orders and very little time updating, deleting, or inserting them, the
transaction could easily lock a large number of rows, making them unavailable to other users.
This is a problem even if the cursor is read-only and the application allows the user to read only existing orders.
In this case, the application commits the transaction, and releases locks, when it calls SQLCloseCursor (in auto-
commit mode) or SQLEndTran (in manual-commit mode).
This section contains the following topics.
Concurrency Types
Optimistic Concurrency
Concurrency Types
4/27/2022 • 2 minutes to read • Edit Online

To solve the problem of reduced concurrency in cursors, ODBC exposes four different types of cursor
concurrency:
Read-only The cursor can read data but cannot update or delete data. This is the default concurrency
type. Although the DBMS might lock rows to enforce the Repeatable Read and Serializable isolation
levels, it can use read locks instead of write locks. This results in higher concurrency because other
transactions can at least read the data.
Locking The cursor uses the lowest level of locking necessary to make sure it can update or delete rows
in the result set. This usually results in very low concurrency levels, especially at the Repeatable Read and
Serializable transaction isolation levels.
Optimistic concurrency using row versions and optimistic concurrency using values The
cursor uses optimistic concurrency: It updates or deletes rows only if they have not changed since they
were last read. To detect changes, it compares row versions or values. There is no guarantee that the
cursor will be able to update or delete a row, but concurrency is much higher than when locking is used.
For more information, see the following section, Optimistic Concurrency.
An application specifies what type of concurrency it wants the cursor to use with the SQL_ATTR_CONCURRENCY
statement attribute. To determine what types are supported, it calls SQLGetInfo with the
SQL_SCROLL_CONCURRENCY option.
Optimistic Concurrency
4/27/2022 • 2 minutes to read • Edit Online

Optimistic concurrency derives its name from the optimistic assumption that collisions between transactions
will rarely occur; a collision is said to have occurred when another transaction updates or deletes a row of data
between the time it is read by the current transaction and the time it is updated or deleted. It is the opposite of
pessimistic concurrency, or locking, in which the application developer believes that such collisions are
commonplace.
In optimistic concurrency, a row is left unlocked until the time comes to update or delete it. At that point, the row
is reread and checked to see if it has been changed since it was last read. If the row has changed, the update or
delete fails and must be tried again.
To determine whether a row has been changed, its new version is checked against a cached version of the row.
This checking can be based on the row version, such as the timestamp column in SQL Server, or the values of
each column in the row. Many DBMSs do not support row versions.
Optimistic concurrency can be implemented by the data source or the application. In either case, the application
should use a low transaction isolation level such as Read Committed; using a higher level negates the increased
concurrency gained by using optimistic concurrency.
If optimistic concurrency is implemented by the data source, the application sets the SQL_ATTR_CONCURRENCY
statement attribute to SQL_CONCUR_ROWVER or SQL_CONCUR_VALUES. To update or delete a row, it executes
a positioned update or delete statement or calls SQLSetPos just as it would with pessimistic concurrency; the
driver or data source returns SQLSTATE 01001 (Cursor operation conflict) if the update or delete fails due to a
collision.
If the application itself implements optimistic concurrency, it sets the SQL_ATTR_CONCURRENCY statement
attribute to SQL_CONCUR_READ_ONLY to read a row. If it will compare row versions and does not know the
row version column, it calls SQLSpecialColumns with the SQL_ROWVER option to determine the name of this
column.
The application updates or deletes the row by increasing the concurrency to SQL_CONCUR_LOCK (to gain write
access to the row) and executing an UPDATE or DELETE statement with a WHERE clause that specifies the
version or values the row had when the application read it. If the row has changed since then, the statement will
fail. If the WHERE clause does not uniquely identify the row, the statement might also update or delete other
rows; row versions always uniquely identify rows, but row values uniquely identify rows only if they include the
primary key.
Diagnostics
4/27/2022 • 2 minutes to read • Edit Online

Functions in ODBC return diagnostic information in two ways. The return code indicates the overall success or
failure of the function, while diagnostic records provide detailed information about the function. At least one
diagnostic record - the header record - is returned even if the function succeeds.
Diagnostic information is used at development time to catch programming errors such as invalid handles and
syntax errors in hard-coded SQL statements. It is used at run time to catch run-time errors and warnings such as
data truncation, access violations, and syntax errors in SQL statements entered by the user.
This section contains the following topics.
Return Codes
Diagnostic Records
Using SQLGetDiagRec and SQLGetDiagField
Implementing SQLGetDiagRec and SQLGetDiagField
Diagnostic Handling Examples
Return Codes ODBC
4/27/2022 • 2 minutes to read • Edit Online

Each function in ODBC returns a code, known as its return code, which indicates the overall success or failure of
the function. Program logic is generally based on return codes.
For example, the following code calls SQLFetch to retrieve the rows in a result set. It checks the return code of
the function to determine if the end of the result set was reached (SQL_NO_DATA), if any warning information
was returned (SQL_SUCCESS_WITH_INFO), or if an error occurred (SQL_ERROR).

SQLRETURN rc;
SQLHSTMT hstmt;

while ((rc=SQLFetch(hstmt)) != SQL_NO_DATA) {


if (rc == SQL_SUCCESS_WITH_INFO) {
// Call function to display warning information.
} else if (rc == SQL_ERROR) {
// Call function to display error information.
break;
}
// Process row.
}

The return code SQL_INVALID_HANDLE always indicates a programming error and should never be
encountered at run time. All other return codes provide run-time information, although SQL_ERROR may
indicate a programming error.
The following table defines the return codes.

RET URN C O DE DESC RIP T IO N

SQL_SUCCESS Function completed successfully. The application calls


SQLGetDiagField to retrieve additional information from
the header record.

SQL_SUCCESS_WITH_INFO Function completed successfully, possibly with a nonfatal


error (warning). The application calls SQLGetDiagRec or
SQLGetDiagField to retrieve additional information.

SQL_ERROR Function failed. The application calls SQLGetDiagRec or


SQLGetDiagField to retrieve additional information. The
contents of any output arguments to the function are
undefined.

SQL_INVALID_HANDLE Function failed due to an invalid environment, connection,


statement, or descriptor handle. This indicates a
programming error. No additional information is available
from SQLGetDiagRec or SQLGetDiagField . This code is
returned only when the handle is a null pointer or is the
wrong type, such as when a statement handle is passed for
an argument that requires a connection handle.
RET URN C O DE DESC RIP T IO N

SQL_NO_DATA No more data was available. The application calls


SQLGetDiagRec or SQLGetDiagField to retrieve
additional information. One or more driver-defined status
records in class 02xxx may be returned. Note: In ODBC 2.x,
this return code was named SQL_NO_DATA_FOUND.

SQL_NEED_DATA More data is needed, such as when parameter data is sent at


execution time or additional connection information is
required. The application calls SQLGetDiagRec or
SQLGetDiagField to retrieve additional information, if any.

SQL_STILL_EXECUTING A function that was started asynchronously is still executing.


The application calls SQLGetDiagRec or SQLGetDiagField
to retrieve additional information, if any.
Diagnostic Records
4/27/2022 • 2 minutes to read • Edit Online

Associated with each environment, connection, statement, and descriptor handle are diagnostic records. These
records contain diagnostic information about the last function called that used a particular handle. The records
are replaced only when another function is called using that handle. There is no limit to the number of
diagnostic records that can be stored at any one time.
There are two types of diagnostic records: a header record and zero or more status records. The header record is
record 0; the status records are records 1 and above. Diagnostic records are composed of a number of separate
fields, which are different for the header record and the status records. In addition, ODBC components can
define their own diagnostic record fields.
Although diagnostic records can be thought of as structures, there is no requirement for them to actually be
structures; how a driver stores the diagnostic information is driver-specific.
Fields in diagnostic records are retrieved with SQLGetDiagField . The SQLSTATE, native error number, and
diagnostic message fields of status records can be retrieved in a single call with SQLGetDiagRec .
This section contains the following topics.
Header Record
Status Records
Header Record
4/27/2022 • 2 minutes to read • Edit Online

The fields in the header record contain general information about a function's execution, including the return
code, row count, number of status records, and type of statement executed. The header record is always created
unless the function returns SQL_INVALID_HANDLE. For a complete list of fields in the header record, see the
SQLGetDiagField function description.
Status Records
4/27/2022 • 2 minutes to read • Edit Online

The fields in the status records contain information about specific errors or warnings returned by the Driver
Manager, driver, or data source, including the SQLSTATE, native error number, diagnostic message, column
number, and row number. Status records can be created only if the function returns SQL_ERROR,
SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_NEED_DATA, or SQL_STILL_EXECUTING. For a complete list of
fields in the status records, see the SQLGetDiagField function description.
This section contains the following topics.
Sequence of Status Records
SQLSTATEs
Diagnostic Messages
Sequence of Status Records
4/27/2022 • 2 minutes to read • Edit Online

If two or more status records are returned, the Driver Manager and driver rank them according to the following
rules. The record with the highest rank is the first record. The source of a record (Driver Manager, driver,
gateway, and so on) is not considered when ranking records.
Errors Status records that describe errors have the highest rank. Among error records, records that
indicate a transaction failure or possible transaction failure outrank all other records. If two or more
records describe the same error condition, SQLSTATEs defined by the Open Group CLI specification
(classes 03 through HZ) outrank ODBC-defined and driver-defined SQLSTATEs.
Implementation-defined No Data Values Status records that describe driver-defined No Data values
(class 02) have the second highest rank.
Warnings Status records that describe warnings (class 01) have the lowest rank. If two or more records
describe the same warning condition, warning SQLSTATEs defined by the Open Group CLI specification
outrank ODBC-defined and driver-defined SQLSTATEs.
If there are two or more records with the highest rank, it is undefined which record is the first record. The order
of all other records is undefined. In particular, because warnings may appear before errors, applications should
check all status records when a function returns a value other than SQL_SUCCESS.
SQLSTATEs
4/27/2022 • 2 minutes to read • Edit Online

SQLSTATEs provide detailed information about the cause of a warning or error. The SQLSTATEs in this manual
are based on those found in the ISO/IEF CLI specification, although those SQLSTATEs that start with IM are
specific to ODBC.
Unlike return codes, the SQLSTATEs in this manual are guidelines, and drivers are not required to return them.
Therefore, while drivers should return the proper SQLSTATE for any error or warning they are capable of
detecting, applications should not count on this always occurring. The reasons for this situation are twofold:
Incompleteness Although this manual lists a large number of errors and warnings and possible causes
for those errors and warnings, it is not complete and probably never will be; driver implementations
simply vary too much. Any given driver probably will not return all of the SQLSTATEs listed in this manual
and might return SQLSTATEs not listed in this manual.
Complexity Some database engines - particularly relational database engines - return literally
thousands of errors and warnings. The drivers for such engines are unlikely to map all of these errors and
warnings to SQLSTATEs because of the effort involved, the inexactness of the mappings, the large size of
the resulting code, and the low value of the resulting code, which often returns programming errors that
should never be encountered at run time. Therefore, drivers should map as many errors and warnings as
seems reasonable and be sure to map those errors and warnings on which application logic might be
based, such as SQLSTATE 01004 (Data truncated).
Because SQLSTATEs are not returned reliably, most applications just display them to the user along with their
associated diagnostic message, which is often tailored to the specific error or warning that occurred, and native
error code. There is rarely any loss of functionality in doing this, because applications cannot base programming
logic on most SQLSTATEs anyway. For example, suppose SQLExecDirect returns SQLSTATE 42000 (Syntax error
or access violation). If the SQL statement that caused this error is hard-coded or built by the application, this is a
programming error and the code needs to be fixed. If the SQL statement is entered by the user, this is a user
error and the application has done all that is possible by informing the user of the problem.
When applications do base programming logic on SQLSTATEs, they should be prepared for the SQLSTATE not to
be returned or for a different SQLSTATE to be returned. Exactly which SQLSTATEs are returned reliably can be
based only on experience with numerous drivers. However, a general guideline is that SQLSTATEs for errors that
occur in the driver or Driver Manager, as opposed to the data source, are more likely to be returned reliably. For
example, most drivers probably return SQLSTATE HYC00 (Optional feature not implemented), while fewer
drivers probably return SQLSTATE 42021 (Column already exists).
The following SQLSTATEs indicate run-time errors or warnings and are good candidates on which to base
programming logic. However, there is no guarantee that all drivers return them.
01004 (Data truncated)
01S02 (Option value changed)
HY008 (Operation canceled)
HYC00 (Optional feature not implemented)
HYT00 (Timeout expired)
SQLSTATE HYC00 (Optional feature not implemented) is particularly significant because it is the only way in
which an application can determine whether a driver supports a particular statement or connection attribute.
For a complete list of SQLSTATEs and what functions return them, see Appendix A: ODBC Error Codes. For a
detailed explanation of the conditions under which each function might return a particular SQLSTATE, see that
function.
Diagnostic Messages
4/27/2022 • 2 minutes to read • Edit Online

A diagnostic message is returned with each SQLSTATE. The same SQLSTATE is often returned with a number of
different messages. For example, SQLSTATE 42000 (Syntax error or access violation) is returned for most errors
in SQL syntax. However, each syntax error is likely to be described by a different message.
Sample diagnostic messages are listed in the Error column in the table of SQLSTATEs in Appendix A and in each
function. Although drivers can return these messages, they are more likely to return whatever message is
passed to them by the data source.
Applications generally display diagnostic messages to the user, along with the SQLSTATE and native error code.
This helps the user and support personnel determine the cause of any problems. The component information
embedded in the message is particularly helpful in doing this.
Diagnostic messages come from data sources and components in an ODBC connection, such as drivers,
gateways, and the Driver Manager. Typically, data sources do not directly support ODBC. Consequently, if a
component in an ODBC connection receives a message from a data source, it must identify the data source as
the source of the message. It must also identify itself as the component that received the message.
If the source of an error or warning is a component itself, the diagnostic message must explain this. Therefore,
the text of messages has two different formats. For errors and warnings that do not occur in a data source, the
diagnostic message must use this format:
[ vendor-identifier ][ ODBC-component-identifier ] component-supplied-text
For errors and warnings that occur in a data source, the diagnostic message must use this format:
[ vendor-identifier ][ ODBC-component-identifier ][ data-source-identifier ] data-source-supplied-text
The following table shows the meaning of each element.

EL EM EN T M EA N IN G

vendor-identifier Identifies the vendor of the component in which the error or


warning occurred or that received the error or warning
directly from the data source.

ODBC-component-identifier Identifies the component in which the error or warning


occurred or that received the error or warning directly from
the data source.

data-source-identifier Identifies the data source. For file-based drivers, this is


typically a file format, such as Xbase[1] For DBMS-based
drivers, this is the DBMS product.

component-supplied-text Generated by the ODBC component.

data-source-supplied-text Generated by the data source.

[1] In this case, the driver is acting as both the driver and the data source.
Brackets ([ ] ) must be included in the message and do not indicate optional items.
Using SQLGetDiagRec and SQLGetDiagField
4/27/2022 • 2 minutes to read • Edit Online

Applications call SQLGetDiagRec or SQLGetDiagField to retrieve diagnostic information. These functions


accept an environment, connection, statement, or descriptor handle and return diagnostics from the function
that last used that handle. The diagnostics logged on a particular handle are discarded when a new function is
called using that handle. If the function returned multiple diagnostic records, the application calls these functions
multiple times; the total number of status records is retrieved by calling SQLGetDiagField for the header
record (record 0) with the SQL_DIAG_NUMBER option.
Applications retrieve individual diagnostic fields by calling SQLGetDiagField and specifying the field to
retrieve. Certain diagnostic fields do not have any meaning for certain types of handles. For a list of diagnostic
fields and their meanings, see the SQLGetDiagField function description.
Applications retrieve the SQLSTATE, native error code, and diagnostic message in a single call by calling
SQLGetDiagRec ; SQLGetDiagRec cannot be used to retrieve information from the header record.
For example, the following code prompts the user for an SQL statement and executes it. If any diagnostic
information was returned, it calls SQLGetDiagField to get the number of status records and SQLGetDiagRec
to get the SQLSTATE, native error code, and diagnostic message from those records.

SQLCHAR SqlState[6], SQLStmt[100], Msg[SQL_MAX_MESSAGE_LENGTH];


SQLINTEGER NativeError;
SQLSMALLINT i, MsgLen;
SQLRETURN rc1, rc2;
SQLHSTMT hstmt;

// Prompt the user for an SQL statement.


GetSQLStmt(SQLStmt);

// Execute the SQL statement and return any errors or warnings.


rc1 = SQLExecDirect(hstmt, SQLStmt, SQL_NTS);
if ((rc1 == SQL_SUCCESS_WITH_INFO) || (rc1 == SQL_ERROR)) {
SQLLEN numRecs = 0;
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc2 = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError,
Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA) {
DisplayError(SqlState,NativeError,Msg,MsgLen);
i++;
}
}

if ((rc1 == SQL_SUCCESS) || (rc1 == SQL_SUCCESS_WITH_INFO)) {


// Process statement results, if any.
}
Implementing SQLGetDiagRec and
SQLGetDiagField
4/27/2022 • 2 minutes to read • Edit Online

SQLGetDiagRec and SQLGetDiagField are implemented by the Driver Manager and each driver. The Driver
Manager and each driver maintain diagnostic records for each environment, connection, statement, and
descriptor handle, and free those records only when another function is called with that handle or the handle is
freed.
Although both the Driver Manager and each driver must determine the first status record according to the
rankings in Sequence of Status Records, the Driver Manager determines the final sequence of records.
SQLGetDiagRec and SQLGetDiagField do not post diagnostic records about themselves.
This section contains the following topics.
Diagnostic Handling Rules
Role of the Driver Manager
Role of the Driver
Diagnostic Handling Rules
4/27/2022 • 2 minutes to read • Edit Online

The following rules govern diagnostic handling in SQLGetDiagRec and SQLGetDiagField .


For all ODBC components:
Must not replace, alter, or mask errors or warnings received from another ODBC component.
May add an additional status record when they receive a diagnostic message from another ODBC
component. The added record must add real information value to the original message.
For the ODBC component that directly interfaces a data source:
Must prefix its vendor identifier, its component identifier, and the data source's identifier to the diagnostic
message it receives from the data source.
Must preserve the data source's native error code.
Must preserve the data source's diagnostic message.
For any ODBC component that generates an error or warning independent of the data source:
Must supply the correct SQLSTATE for the error or warning.
Must generate the text of the diagnostic message.
Must prefix its vendor identifier and its component identifier to the diagnostic message.
Must return a native error code, if one is available and meaningful.
For the ODBC component that interfaces with the Driver Manager:
Must initialize the output arguments of SQLGetDiagRec and SQLGetDiagField .
Must format and return the diagnostic information as output arguments of SQLGetDiagRec and
SQLGetDiagField when that function is called.
For one ODBC component other than the Driver Manager:
Must set the SQLSTATE based on the native error. For file-based drivers and DBMS-based drivers that do not
use a gateway, the driver must set the SQLSTATE. For DBMS-based drivers that use a gateway, either the
driver or a gateway that supports ODBC may set the SQLSTATE.
Role of the Driver Manager
4/27/2022 • 2 minutes to read • Edit Online

The Driver Manager determines the final order in which to return status records that it generates. In particular, it
determines which record has the highest rank and is to be returned first. The driver is responsible for ordering
status records that it generates. If status records are posted by both the Driver Manager and the driver, the
Driver Manager is responsible for ordering them. For more information, see Sequence of Status Records.
The Driver Manager does as much error checking as it can. This saves every driver from checking for the same
errors. For example, if a function argument accepts a discrete number of values, such as Operation in
SQLSetPos , the Driver Manager checks that the specified value is legal.
The following sections describe the types of conditions checked by the Driver Manager. They are not intended to
be exhaustive; for a complete list of the SQLSTATEs the Driver Manager returns, see the "Diagnostics" section of
each function; the description of each check made by the Driver Manager starts with the letters "(DM)." Also see
the state transition tables in Appendix B: ODBC State Transition Tables; errors shown in parentheses are detected
by the Driver Manager.
This section contains the following topics.
Argument Value Checks
State Transition Checks
General Error Checks
Driver Manager Error and Warning Checks
Argument Value Checks
4/27/2022 • 2 minutes to read • Edit Online

The Driver Manager checks the following types of arguments. Unless otherwise noted, the Driver Manager
returns SQL_ERROR for errors in argument values.
Environment, connection, and statement handles usually cannot be null pointers. The Driver Manager
returns SQL_INVALID_HANDLE when it finds a null handle.
Required pointer arguments, such as OutputHandlePtr in SQL AllocHandle and CursorName in
SQLSetCursorName , cannot be null pointers.
Option flags that do not support driver-specific values must be a legal value. For example, Operation in
SQLSetPos must be SQL_POSITION, SQL_REFRESH, SQL_UPDATE, SQL_DELETE, or SQL_ADD.
Option flags must be supported in the version of ODBC supported by the driver. For example, InfoType in
SQLGetInfo cannot be SQL_ASYNC_MODE (introduced in ODBC 3.0) when calling an ODBC 2.0 driver.
Column and parameter numbers must be greater than 0 or greater than or equal to 0, depending on the
function. The driver must check the upper limit of these argument values based on the current result set
or SQL statement.
Length/indicator arguments and data buffer length arguments must contain appropriate values. For
example, the argument that specifies the length of a table name in SQLColumns (NameLength3) must
be SQL_NTS or a value greater than 0; BufferLength in SQLDescribeCol must be greater than or equal
to 0. The driver might also need to check these arguments. For example, it might check that
NameLength3 is less than or equal to the maximum length of a table name in the data source.
State Transition Checks
4/27/2022 • 2 minutes to read • Edit Online

The Driver Manager checks that the state of the environment, connection, or statement is appropriate for the
function being called. For example, a connection must be in an allocated state when SQLConnect is called; a
statement must be in a prepared state when SQLExecute is called. The Driver Manager returns SQL_ERROR for
state transition errors.
General Error Checks
4/27/2022 • 2 minutes to read • Edit Online

The Driver Manager checks one general error. It always returns SQL_ERROR when it encounters the following
error: The function must be supported by the driver.
Driver Manager Error and Warning Checks
4/27/2022 • 2 minutes to read • Edit Online

The Driver Manager completely or partially implements a number of functions and therefore checks for all or
some of the errors and warnings in those functions.
The Driver Manager implements SQLDataSources and SQLDrivers and checks for all errors and
warnings in these functions.
The Driver Manager checks whether a driver implements SQLGetFunctions . If the driver does not
implement SQLGetFunctions , the Driver Manager implements and checks for all errors and warnings in
it.
The Driver Manager partially implements SQL AllocHandle , SQLConnect , SQLDriverConnect ,
SQLBrowseConnect , SQLFreeHandle , SQLGetDiagRec , and SQLGetDiagField and checks for some
errors in these functions. It may return the same errors as the driver for some of these functions because
both perform similar operations. For example, the Driver Manager or driver may return SQLSTATE IM008
(Dialog failed) if either one is unable to display a login dialog box for SQLDriverConnect .
Role of the Driver
4/27/2022 • 2 minutes to read • Edit Online

The driver checks for all errors and warnings not checked by the Driver Manager and orders status records that
it generates. (An ODBC 2.x driver does not order status records.) This includes errors and warnings in data
truncation, data conversion, syntax, and some state transitions. The driver might also check errors and warnings
partially checked by the Driver Manager. For example, although the Driver Manager checks whether the value of
Operation in SQLSetPos is legal, the driver must check whether it is supported.
The driver also maps native errors - that is, errors returned by the data source - to SQLSTATEs. For example, the
driver might map a number of different native errors for illegal SQL syntax to SQLSTATE 42000 (Syntax error or
access violation). The driver returns the native error number in the SQL_DIAG_NATIVE field of the status record.
Driver documentation should show how errors and warnings are mapped from the data source to arguments in
SQLGetDiagRec and SQLGetDiagField .
Diagnostic Handling Examples
4/27/2022 • 2 minutes to read • Edit Online

The following examples show how various components in an ODBC connection might generate diagnostic
messages and how various drivers might return diagnostics to the application with SQLGetDiagRec .
File-Based Driver Diagnostic Example
DBMS-Based Driver Diagnostic Example
Gateways Diagnostic Example
Driver Manager Diagnostic Example
File-Based Driver Diagnostic Example
4/27/2022 • 2 minutes to read • Edit Online

A file-based driver acts both as an ODBC driver and as a data source. It can therefore generate errors and
warnings both as a component in an ODBC connection and as a data source. Because it also is the component
that interfaces with the Driver Manager, it formats and returns arguments for SQLGetDiagRec .
For example, if a Microsoft® driver for dBASE could not allocate sufficient memory, it might return the
following values from SQLGetDiagRec :

SQLSTATE: "HY001"
Native Error: 42052
Diagnostic Msg: "[Microsoft][ODBC dBASE Driver]Unable to allocate sufficient memory."

Because this error was not related to the data source, the driver only added prefixes to the diagnostic message
for the vendor ([Microsoft]) and the driver ([ODBC dBASE Driver]).
If the driver could not find the file Employee.dbf, it might return the following values from SQLGetDiagRec :

SQLSTATE: "42S02"
Native Error: -1305
Diagnostic Msg: "[Microsoft][ODBC dBASE Driver][dBASE]No such table or object"

Because this error was related to the data source, the driver added the file format of the data source ([dBASE]) as
a prefix to the diagnostic message. Because the driver was also the component that interfaced with the data
source, it added prefixes for the vendor ([Microsoft]) and the driver ([ODBC dBASE Driver]).
DBMS-Based Driver Diagnostic Example
4/27/2022 • 2 minutes to read • Edit Online

A DBMS-based driver sends requests to a DBMS and returns information to the application through the Driver
Manager. Because the driver is the component that interfaces with the Driver Manager, it formats and returns
arguments for SQLGetDiagRec .
For example, if, using SQL/Services, a Microsoft driver for Oracle Rdb encountered an invalid cursor name, it
might return the following values from SQLGetDiagRec :

SQLSTATE: "34000"
Native Error: 0
Diagnostic Msg: "[Microsoft][ODBC Rdb Driver]Invalid cursor name: EMPLOYEE_CURSOR."

Because the error occurred in the driver, it added prefixes to the diagnostic message for the vendor ([Microsoft])
and the driver ([ODBC Rdb Driver]).
If the DBMS could not find the table EMPLOYEE, the driver might format and return the following values from
SQLGetDiagRec :

SQLSTATE: "42S02"
Native Error: -1
Diagnostic Msg: "[Microsoft][ODBC Rdb Driver][Rdb] %SQL-F-RELNOTDEF, Table EMPLOYEE "
"is not defined in schema."

Because the error occurred in the data source, the driver added a prefix for the data source identifier ([Rdb]) to
the diagnostic message. Because the driver was the component that interfaced with the data source, it added
prefixes for its vendor ([Microsoft]) and identifier ([ODBC Rdb Driver]) to the diagnostic message.
Gateways Diagnostic Example
4/27/2022 • 2 minutes to read • Edit Online

In a gateway architecture, a driver sends requests to a gateway that supports ODBC. The gateway sends the
requests to a DBMS. Because it is the component that interfaces with the Driver Manager, the driver formats and
returns arguments for SQLGetDiagRec .
For example, if Oracle based a gateway to Rdb on Microsoft Open Data Services and if Rdb could not find the
table EMPLOYEE, the gateway might generate this diagnostic message:

"[42S02][-1][DEC][ODS Gateway][Rdb]%SQL-F-RELNOTDEF, Table EMPLOYEE is not defined "


"in schema."

Because the error occurred in the data source, the gateway added a prefix for the data source identifier ([Rdb]) to
the diagnostic message. Because the gateway was the component that interfaced with the data source, it added
prefixes for its vendor ([DEC]) and identifier ([ODS Gateway]) to the diagnostic message. It also added the
SQLSTATE value and the Rdb error code to the beginning of the diagnostic message. This permitted it to
preserve the semantics of its own message structure and still supply the ODBC diagnostic information to the
driver. The driver parses the error information attached to the error statement by the gateway.
Because the gateway driver is the component that interfaces with the Driver Manager, it would use the
preceding diagnostic message to format and return the following values from SQLGetDiagRec :

SQLSTATE: "42S02"
Native Error: -1
Diagnostic Msg: "[DEC][ODS Gateway][Rdb]%SQL-F-RELNOTDEF, Table EMPLOYEE is not "
"defined in schema."
Driver Manager Diagnostic Example
4/27/2022 • 2 minutes to read • Edit Online

The Driver Manager can also generate diagnostic messages. For example, if an application passed an invalid
direction option to SQLDataSources , the Driver Manager might format and return the following values from
SQLGetDiagRec :

SQLSTATE: "HY103"
Native Error: 0
Diagnostic Msg: "[Microsoft][ODBC Driver Manager]Direction option out of range"

Because the error occurred in the Driver Manager, it added prefixes to the diagnostic message for its vendor
([Microsoft]) and its identifier ([ODBC Driver Manager]).
Interoperability
4/27/2022 • 2 minutes to read • Edit Online

Interoperability is the ability of a single application to operate with many different DBMSs. The need to write
generic, interoperable applications was one of the major factors leading to the development of ODBC. However,
interoperability is not a simple path followed from "not interoperable" to "completely interoperable." The path
has many branches, and each requires trade-offs among features, speed, code complexity, and development
time.
The process of writing an interoperable application follows several steps:
1. Deciding whether the application will use ODBC.
2. Choosing a level of interoperability and deciding which trade-offs are necessary to reach that level.
3. Writing interoperable code and testing it as fully as possible.
It should be noted that interoperability is primarily the domain of the application writer. Drivers are designed to
work with a single DBMS and, by definition, are not interoperable. They play a role in interoperability by
correctly implementing and exposing ODBC over a single DBMS.
This section contains the following topics.
Is ODBC the Answer?
Choosing a Level of Interoperability
Determining the Target DBMSs and Drivers
Considering Database Features to Use
Length of the Product Cycle
Writing an Interoperable Application
Testing Interoperable Applications
Is ODBC the Answer?
4/27/2022 • 2 minutes to read • Edit Online

Before delving into the question of interoperability, consider the following question: Should the application use
ODBC at all? This might seem a strange question to ask in a guide to ODBC, but it is, in fact, a legitimate one.
ODBC was not designed to completely replace native database APIs, nor was it designed to provide database
access in all circumstances. It was designed to provide a common interface to databases and was intended to
free application programmers from having to learn about and maintain links to multiple databases.
Custom applications are prime candidates for native database APIs. The main reason is that custom applications
often work with a single DBMS and have no need to be interoperable. Native database APIs might do a better
job than ODBC of exposing the capabilities of a particular DBMS and might expose capabilities not exposed by
ODBC. Furthermore, because the developers of custom applications are usually familiar with the native database
API for their DBMS, there is little reason to learn ODBC. However, it is interesting to note that for some DBMSs,
ODBC is the native database API.
So which applications are candidates for ODBC? The best candidates are applications that work with more than
one DBMS. This includes virtually all generic and vertical applications. It also includes a number of custom
applications. For example, custom applications that use several different DBMSs are much easier and cleaner to
write with ODBC than with multiple native APIs. And custom applications written with ODBC are much easier to
migrate as a company moves from one DBMS to another or deploys the same application against different
DBMSs.
Choosing a Level of Interoperability
4/27/2022 • 2 minutes to read • Edit Online

Assuming the application will use ODBC, the next step is to determine what level of interoperability is required.
The basic level of interoperability is usually a function of the application type: Custom applications tend not to
be interoperable, vertical applications tend to be interoperable among a limited number of DBMSs, and generic
applications tend to be interoperable among all DBMSs.
This section contains the following topics.
Custom Applications
Vertical Applications
Generic Applications
Custom Applications
4/27/2022 • 2 minutes to read • Edit Online

Custom applications typically perform a specific task for a few DBMSs. For example, an application might
retrieve data from a single DBMS and generate a report, or it might transfer data among several DBMSs. What
these applications have in common is that these DBMSs are known before the application is written and are
unlikely to change over the life of the application.
The custom application therefore requires little or no interoperability. The application developer can choose a
single driver for each DBMS and code directly to those drivers. The application can safely contain driver-specific
code to exploit the capabilities of those drivers and might even make calls to the native database API to use
functionality not supported by ODBC.
The major interoperability concern of most custom applications is whether the target DBMSs will change in the
future. If so, this process can be simplified by writing more interoperable code to start with. However, such
changing of DBMSs is rare and generally entails a large amount of work. Because of this, developers of custom
applications rarely choose to increase interoperability at the expense of functionality; they usually choose to
recode that functionality when they change DBMSs.
Vertical Applications
4/27/2022 • 2 minutes to read • Edit Online

Vertical applications typically perform a well-defined task against a single DBMS. For example, an order entry
application tracks the orders in a company. What these types of applications have in common is that the
database schema is usually designed by the application developer and, while the application might work with a
number of different DBMSs, it works with a single DBMS for a single customer.
Because vertical applications usually require certain functionality, such as scrollable cursors or transactions, they
rarely support all DBMSs. Instead, they tend to be highly interoperable among a limited set of DBMSs. Typically,
vertical application developers choose to support those DBMSs that represent a large fraction of the market and
ignore the rest. They might even choose to support specific drivers for those DBMSs to reduce their testing and
product support costs.
Because vertical applications can support a known set of DBMSs, they sometimes contain driver-specific or
DBMS-specific code. However, such code is best kept to a minimum because it requires extra time to maintain.
Generic Applications
4/27/2022 • 2 minutes to read • Edit Online

Generic applications sometimes perform a hard-coded task, such as a spreadsheet retrieving data from a
database. They might also perform a variety of user-defined tasks, such as a generic query application allowing
the user to enter and execute an SQL statement. What generic applications have in common is that they must
work with a variety of different DBMSs and that the developer does not know beforehand what these DBMSs
will be.
Therefore, generic applications need to be highly interoperable. The developer must make many choices, trading
off interoperability for features, and must write code that expects drivers to support a wide range of
functionality. While generic applications might be tuned to work with popular DBMSs, they rarely contain driver-
specific or DBMS-specific code.
Determining the Target DBMSs and Drivers
4/27/2022 • 2 minutes to read • Edit Online

The next question to consider is, what are the target DBMSs for the application, and what drivers are available
that support those DBMSs? Because generic applications tend to be highly interoperable, the question of target
DBMSs is most applicable to custom and vertical applications. However, the question of target drivers applies to
all applications, because drivers vary widely in speed, quality, feature support, and availability. Also, if drivers are
to be redistributed with the application, the cost and availability of licensing plans need to be considered.
For many custom applications, the target DBMSs are obvious: They are existing DBMSs that the application is
designed to access. DBMSs to which future migration is planned should also be considered. However, the major
question for these applications is which driver or drivers to use with them. For other custom applications - those
which are not designed to access an existing DBMS - the target DBMSs can be chosen based on feature support,
concurrent user support, driver availability, and affordability.
For vertical applications, the target DBMSs are usually chosen based on feature support, driver availability, and
market. For example, a vertical application designed for small businesses must target DBMSs that are affordable
to those businesses; a vertical application designed as an add-on to existing DBMSs must target widely used
DBMSs.
When choosing target DBMSs, the differences between desktop and server databases should be considered.
Desktop databases such as dBASE, Paradox, and Btrieve are less powerful than server databases. Because they
are generally accessed through the less powerful SQL engines found in most file-based drivers, they often lack
full transaction support, support fewer concurrent users, and have limited SQL. However, they are inexpensive
and have a large installed base.
Server databases such as Oracle, DB2, and SQL Server provide full transaction support, support many
concurrent users, and have rich SQL. They are much more expensive and have a smaller installed base. On the
other hand, software prices tend to be higher, somewhat offsetting a smaller potential market.
Thus, target DBMSs sometimes can be chosen based on the features required by the application and the
application's target market. For example, an order entry system for large corporations might not target desktop
databases because these lack adequate transaction support. A similar system designed for small businesses
might exclude most server databases on the basis of cost. And developers of generic applications might target
both but avoid using the advanced features found in server databases.
Considering Database Features to Use
4/27/2022 • 3 minutes to read • Edit Online

After the basic level of interoperability is known, the database features used by the application must be
considered. For example, what SQL statements will the application execute? Will the application use scrollable
cursors? Transactions? Procedures? Long data? For ideas about what features might not be supported by all
DBMSs, see the SQLGetInfo, SQLSetConnectAttr, and SQLSetStmtAttr function descriptions, and Appendix C:
SQL Grammar. The features required by an application might eliminate some DBMSs from the list of target
DBMSs. They might also show that the application can easily target many DBMSs.
For example, if the required features are simple, they can usually be implemented with a high degree of
interoperability. An application that executes a simple SELECT statement and retrieves results with a forward-
only cursor is likely to be highly interoperable by virtue of its simplicity: Almost all drivers and DBMSs support
the functionality it needs.
However, if the required features are more complex, such as scrollable cursors, positioned update and delete
statements, and procedures, trade-offs must often be made. There are several possibilities:
Lower interoperability, more features. The application includes the features but works only with
DBMSs that support them.
Higher interoperability, fewer features. The application drops the features but works with more
DBMSs.
Higher interoperability, optional features. The application includes the features but makes them
available only with those DBMSs that support them.
Higher interoperability, more features. The application uses the features with DBMSs that support
them and emulates them for DBMSs that do not.
The first two cases are relatively simple to implement, because the features are used either with all supported
DBMSs or with none. The latter two cases, on the other hand, are more complex. It is necessary in both cases to
check whether the DBMS supports the features and in the last case to write a potentially large amount of code
to emulate these features. Therefore, these schemes are likely to require more development time and may be
slower at run time.
Consider a generic query application that can connect to a single data source. The application accepts a query
from the user and displays the results in a window. Now suppose this application has one feature that allows
users to display the results of multiple queries simultaneously. That is, they can execute a query and look at
some of the results, execute a different query and look at some of its results, and then return to the first query.
This presents an interoperability problem because some drivers support only a single active statement.
The application has a number of choices, based on what the driver returns for the
SQL_MAX_CONCURRENT_ACTIVITIES option in SQLGetInfo :
Always suppor t multiple queries. After connecting to a driver, the application checks the number of
active statements. If the driver supports only one active statement, the application closes the connection
and informs the user that the driver does not support required functionality. The application is easy to
implement and has full functionality but has lower interoperability.
Never suppor t multiple queries. The application drops the feature altogether. It is easy to implement
and has high interoperability but has less functionality.
Suppor t multiple queries only if the driver does. After connecting to a driver, the application
checks the number of active statements. The application allows the user to start a new statement when
one is already active only if the driver supports multiple active statements. The application has higher
functionality and interoperability but is harder to implement.
Always suppor t multiple queries and emulate them when necessar y. After connecting to a
driver, the application checks the number of active statements. The application always allows the user to
start a new statement when one is already active. If the driver supports only one active statement, the
application opens an additional connection to that driver and executes the new statement on that
connection. The application has full functionality and high interoperability but is harder to implement.
Length of the Product Cycle
4/27/2022 • 2 minutes to read • Edit Online

The final question about interoperability is time. Developing an interoperable application usually takes longer
than developing a noninteroperable one. The reason is that the application must check DBMS capabilities,
perform the same tasks differently for different DBMSs, work around functionality supported by some DBMSs
but not others, and so on.
In addition to development time, product lifetime must be considered. If the application is designed to be used
once, such as an application that transfers data when migrating from one DBMS to another, there is no point in
making it interoperable. The application will be used once and discarded.
If the application will exist for a long time, it might be easier to maintain as an interoperable application. This is
true even for custom applications that have a single DBMS as a target. The reason is that interoperable code
uses a limited subset of database features. The driver is required to keep those features available, even in the
face of changes to the underlying DBMS. Thus, interoperable code can shift the burden of coping with changes
to the DBMS from the application developer to the driver developer.
Writing an Interoperable Application
4/27/2022 • 2 minutes to read • Edit Online

Whenever an application uses the same code against more than one driver, that code must be interoperable
among those drivers. In most cases, this is an easy task. For example, the code to fetch rows with a forward-only
cursor is the same for all drivers. In some cases, this can be more difficult. For example, the code to construct
identifiers for use in SQL statements needs to consider identifier case, quoting, and one-part, two-part, and
three-part naming conventions.
In general, interoperable code must cope with problems of feature support and feature variability. Feature
support refers to whether or not a particular feature is supported. For example, not all DBMSs support
transactions, and interoperable code must work correctly regardless of transaction support. Feature variability
refers to variation in the manner in which a particular feature is supported. For example, catalog names are
placed at the start of identifiers in some DBMSs and at the end of identifiers in others.
Applications can deal with feature support and feature variability at design time or at run time. To deal with
feature support and variability at design time, a developer looks at the target DBMSs and drivers and makes
sure that the same code will be interoperable among them. This is generally the way in which applications with
low or limited interoperability deal with these problems.
For example, if the developer guarantees that a vertical application will work only with four particular DBMSs
and if each of those DBMSs supports transactions, the application does not need code to check for transaction
support at run time. It can always assume transactions are available because of the design-time decision to use
only four DBMSs, each of which supports transactions.
To deal with feature support and variability at run time, the application must test for different capabilities at run
time and act accordingly. This is generally the way in which highly interoperable applications deal with these
problems. For feature support problems, this means writing code that makes the feature optional or writing
code that emulates the feature when it is not available. For feature variability problems, this means writing code
that supports all possible variations.
This section contains the following topics.
Checking Feature Support and Variability
Features to Watch For
Checking Feature Support and Variability
4/27/2022 • 2 minutes to read • Edit Online

To check feature support and variability, applications generally call SQLGetInfo , SQLGetFunctions , and
SQLGetTypeInfo . A good starting place is the driver's API and SQL grammar conformance levels. These
describe broad levels of feature support. The application can then call SQLGetInfo with other options to
determine the support or variability of features it needs, SQLGetFunctions to determine whether functions it
needs beyond the returned conformance level are supported, and SQLGetTypeInfo to determine what SQL
data types are supported.
An application can determine whether a statement or connection attribute is supported by calling
SQLSetStmtAttr or SQLSetConnectAttr with that attribute. If the function returns SQL_SUCCESS or
SQL_SUCCESS_WITH_INFO, the attribute is supported; if it returns SQL_ERROR and SQLSTATE HYC00 (Optional
feature not implemented), the attribute is not supported.
Applications can also determine a limited amount of information before connecting to the driver by calling
SQLDrivers .
Features to Watch For
4/27/2022 • 2 minutes to read • Edit Online

This section describes a number of features that application developers often take for granted. In fact, these
features vary widely in support and manner of support among DBMSs; failure to code for them is likely to cause
problems in interoperable applications.
This section does not list all features that application developers need to consider. For that information, see the
SQLGetInfo, SQLSetStmtAttr, and SQLSetConnectAttr function descriptions, Appendix C: SQL Grammar, and the
sections of this manual that discuss each feature.
This section contains the following topics.
Version Number
Multiple Active Statements and Connections
Transaction Support in DBMSs
Commit and Rollback Behavior
NOT NULL in CREATE TABLE Statements
Supported Data Types
ODBC SQL Grammar
Batch Processing
Version Number
4/27/2022 • 2 minutes to read • Edit Online

There are several versions of ODBC, each with different features. An application determines which ODBC version
the Driver Manager and a particular driver support by calling SQLGetInfo with the SQL_ODBC_VER and
SQL_DRIVER_ODBC_VER options.
Multiple Active Statements and Connections
4/27/2022 • 2 minutes to read • Edit Online

Some drivers and DBMSs limit the number of statements and connections that can be active at one time. These
numbers can be as small as one. For more information, see the SQL_MAX_CONCURRENT_ACTIVITIES and
SQL_MAX_DRIVER_CONNECTIONS options in the SQLGetInfo function description, and Statement Handles and
Connection Handles.
Transaction Support in DBMSs
4/27/2022 • 2 minutes to read • Edit Online

Some databases, especially desktop databases such as dBASE, Paradox, and Btrieve, do not support transactions.
Even among databases that support transactions, there is variation in what kinds of SQL statements can be in a
transaction. For more information, see the SQL_TXN_CAPABLE option in the SQLGetInfo function description.
Commit and Rollback Behavior
4/27/2022 • 2 minutes to read • Edit Online

A common behavior among server DBMSs is to close cursors and discard prepared statements when a
statement is committed or rolled back. Desktop databases are more likely to keep cursors open and keep
prepared statements. For more information, see the SQL_CURSOR_COMMIT_BEHAVIOR and
SQL_CURSOR_ROLLBACK_BEHAVIOR options in the SQLGetInfo function description and Effect of Transactions
on Cursors and Prepared Statements.
NOT NULL in CREATE TABLE Statements
4/27/2022 • 2 minutes to read • Edit Online

Some databases, and especially desktop databases, do not support the NOT NULL column constraint in
CREATE TABLE statements. For more information, see the SQL_NON_NULLABLE_COLUMNS option in the
SQLGetInfo function description.
Supported Data Types
4/27/2022 • 2 minutes to read • Edit Online

The data types supported by DBMSs vary considerably. An application can determine the names and
characteristics of supported data types by calling SQLGetTypeInfo . Because of wide variation in data type
names, the application must use the data type names returned by SQLGetTypeInfo in CREATE TABLE
statements. For more information, see Data Types in ODBC.
ODBC SQL Grammar
4/27/2022 • 2 minutes to read • Edit Online

Interoperable applications should always use the ODBC SQL grammar in SQL statements. However,
considerable variation is possible even within this grammar. For more information, see Interoperability of SQL
Statements.
Batch Processing
4/27/2022 • 2 minutes to read • Edit Online

Support for batches of SQL statements is not widespread, so interoperable applications should use them
conditionally or not at all. For more information, see Executing Batches.
Testing Interoperable Applications
4/27/2022 • 2 minutes to read • Edit Online

Testing interoperable applications is at best a time-consuming business and at worst impossible because new
drivers continually appear on the market. However, a reasonable degree of testing is possible. Applications with
limited or low interoperability need only be tested against those drivers they are guaranteed to support.
However, they must be fully tested against these drivers.
Highly interoperable applications cannot be tested practically against all drivers. The best that most application
developers can do is to test them fully against a small number of drivers and cursorily against several more.
Tested drivers should include the most popular drivers for the most popular DBMSs in the application's market;
if the market covers all DBMSs, drivers for both desktop and server DBMSs should be tested.
One of the problems in testing ODBC applications is the number of components involved: the application itself,
the Driver Manager, the driver, the DBMS, and possibly network software or gateways. Applications can make it
easier to track errors by posting the error messages returned by ODBC functions through SQLGetDiagField
and SQLGetDiagRec . These messages identify the manufacturer and component in which errors occur. For
more information, see Diagnostics.
Programming Considerations
4/27/2022 • 2 minutes to read • Edit Online

This section briefly discusses a number of topics related to writing ODBC applications and drivers.
This section contains the following topics.
Multithreading
Alignment
Unicode
Translation DLLs
Diagnostic Tools
Visual Studio Analyzer
Driver-Specific Data Types, Descriptor Types, Information Types, Diagnostic Types, and Attributes
Backward Compatibility and Standards Compliance
ODBC in Windows
Multithreading
4/27/2022 • 2 minutes to read • Edit Online

On multithread operating systems, drivers must be thread-safe. That is, it must be possible for applications to
use the same handle on more than one thread. How this is achieved is driver-specific, and it is likely that drivers
will serialize any attempts to concurrently use the same handle on two different threads.
Applications commonly use multiple threads instead of asynchronous processing. The application creates a
separate thread, calls an ODBC function on it, and then continues processing on the main thread. Rather than
having to continually poll the asynchronous function, as is the case when the SQL_ATTR_ASYNC_ENABLE
statement attribute is used, the application can simply let the newly created thread finish.
Functions that accept a statement handle and are running on one thread can be canceled by calling SQLCancel
with the same statement handle from another thread. Although drivers should not serialize the use of
SQLCancel in this manner, there is no guarantee that calling SQLCancel will actually cancel the function
running on the other thread.
Alignment
4/27/2022 • 2 minutes to read • Edit Online

The alignment issues in an ODBC application are generally no different than they are in any other application.
That is, most ODBC applications have few or no problems with alignment. The penalties for not aligning
addresses vary with the hardware and operating system and might be as minor as a slight performance penalty
or as major as a fatal run-time error. Therefore, ODBC applications, and portable ODBC applications in particular,
should be careful to align data properly.
One example of when ODBC applications encounter alignment issues is when they allocate a large block of
memory and bind different parts of that memory to the columns in a result set. This is most likely to occur when
a generic application must determine the shape of a result set at run time and allocate and bind memory
accordingly.
For example, suppose an application executes a SELECT statement entered by the user and fetches the results
from this statement. Because the shape of this result set is not known when the program is written, the
application must determine the type of each column after the result set is created and bind memory accordingly.
The easiest way to do this is to allocate a large block of memory and bind different addresses in that block to
each column. To access the data in a column, the application casts the memory bound to that column.
The following diagram shows a sample result set and how a block of memory might be bound to it using the
default C data type for each SQL data type. Each "X" represents a single byte of memory. (This example shows
only the data buffers that are bound to the columns. This is done for simplicity. In actual code, the
length/indicator buffers must also be aligned.)

Assuming the bound addresses are stored in the Address array, the application uses the following expressions to
access the memory bound to each column:

(SQLCHAR *) Address[0]
(SQLSMALLINT *) Address[1]
(SQLINTEGER *) Address[2]

Notice that the addresses bound to the second and third columns start on odd-numbered bytes and that the
address bound to the third column is not divisible by four, which is the size of an SDWORD. On some machines,
this will not be a problem; on others, it will cause a slight performance penalty; on still others, it will cause a fatal
run-time error. A better solution would be to align each bound address on its natural alignment boundary.
Assuming this is 1 for a UCHAR, 2 for an SWORD, and 4 for an SDWORD, this would give the result shown in the
following illustration, where an "X" represents a byte of memory that is used and an "O" represents a byte of
memory that is unused.
While this solution does not use all of the application's memory, it does not encounter any alignment problems.
Unfortunately, it takes a fair amount of code to implement this solution, as each column must be aligned
individually according to its type. A simpler solution is to align all columns on the size of the largest alignment
boundary, which is 4 in the example shown in the following illustration.

Although this solution leaves larger holes, the code to implement it is relatively simple and fast. In most cases,
this offsets the penalty paid in unused memory. For an example that uses this method, see Using SQLBindCol.
Unicode
4/27/2022 • 2 minutes to read • Edit Online

Unicode defines encoding for characters in many languages.


For more information about the Unicode standard, see The Unicode Consortium.
Unicode defines a universal character set. A Windows ANSI code page defines a character set, typically
containing characters for one language. It may be more difficult to write an application that is required to use
different code pages.
Unicode does not require a code page. Every code point is mapped to a single character in some language.
Currently, the only Unicode encoding that ODBC supports is UCS-2, which uses a 16-bit integer (fixed length) to
represent a character. Unicode allows applications to work in different languages.
The ODBC 3.5 (or higher) Driver Manager is Unicode-enabled. This affects two major areas: function calls and
string data types. The Driver Manager maps function string arguments and string data as required by the
application and driver, both of which can be either Unicode-enabled or ANSI-enabled. These two areas are
discussed in detail in the sections, Unicode Function Arguments and Unicode Data.
The ODBC 3.5 (or higher) Driver Manager supports the use of a Unicode driver with both a Unicode application
and an ANSI application. It also supports the use of an ANSI driver with an ANSI application. The Driver
Manager provides limited Unicode-to-ANSI mapping for a Unicode application working with an ANSI driver.
This section contains the following topics.
Unicode Function Arguments
Unicode Data
Unicode Function Arguments
4/27/2022 • 2 minutes to read • Edit Online

The ODBC 3.5 (or higher) Driver Manager supports both ANSI and Unicode versions of all functions that accept
pointers to character strings or SQLPOINTER in their arguments. The Unicode functions are implemented as
functions (with a suffix of W), not as macros. The ANSI functions (which can be called with or without a suffix of
A) are identical to the current ODBC API functions.

Remarks
For Unicode functions that always return or take strings or length arguments, the arguments are passed as
count-of-characters. For functions that return length information for server data, the display size and precision
are described in number of characters. When a length (transfer size of the data) could refer to string or
nonstring data, the length is described in octet lengths. For example, SQLGetInfoW will still take the length as
count-of-bytes, but SQLExecDirectW will use count-of-characters.
Count-of-characters refers to the number of bytes (octets) for ANSI functions and the number of WCHAR (16-bit
words) for UNICODE functions. In particular, a double-byte character sequence (DBCS) or a multibyte character
sequence (MBCS) can be composed of multiple bytes. A UTF-16 Unicode character sequence can be composed
of multiple WCHARs.
The following is a list of the ODBC API functions that support both Unicode (W) and ANSI (A) versions:
SQLBrowseConnect
SQLColAttribute
SQLColAttributes
SQLColumnPrivileges
SQLColumns
SQLConnect
SQLDataSources
SQLDescribeCol
SQLDriverConnect
SQLDrivers
SQLError
SQLExecDirect
SQLForeignKeys
SQLGetConnectAttr
SQLGetConnectOption
SQLGetCursorName
SQLGetDescField
SQLGetDescRec
SQLGetDiagField
SQLGetDiagRec
SQLGetInfo
SQLGetStmtAttr
SQLGetTypeInfo
SQLNativeSql
SQLPrepare
SQLPrimar yKeys
SQLProcedureColumns
SQLProcedures
SQLSetConnectAttr
SQLSetConnectOption
SQLSetCursorName
SQLSetDescField
SQLSetStmtAttr
SQLSpecialColumns
SQLStatistics
SQLTablePrivileges
SQLTables
The following is a list of the ODBC Installer and ODBC Translator functions that support both Unicode (W) and
ANSI (A) versions:
SQLConfigDataSource
SQLCreateDataSource
SQLDataSourceToDriver
SQLDriverToDataSource
SQLGetAvailableDrivers
SQLGetInstalledDrivers
SQLGetTranslator
SQLInstallDriver
SQLInstallDriverManager
SQLInstallerError
SQLInstallODBC
SQLReadFileDSN
SQLRemoveDSNFromINI
SQLValidDSN
SQLWriteDSNToINI

NOTE
Deprecated functions have Unicode-to-ANSI mapping support because the ODBC 3.x Driver Manager supports
recompiling ODBC 2.x applications with the UNICODE #define .

This section contains the following topics.


Unicode Applications
Unicode Drivers
Function Mapping in the Driver Manager
Unicode Applications
4/27/2022 • 2 minutes to read • Edit Online

You can recompile an application as a Unicode application in one of two ways:


Include the Unicode #define contained in the Sqlucode.h header file in the application.
Compile the application with the compiler's Unicode option. (This option will be different for different
compilers.)
To convert an ANSI application to a Unicode application, write the application to store and pass Unicode data. In
addition, calls to functions that support SQLPOINTER arguments must be converted to use count of bytes.
After an application is compiled as a Unicode application, if the application calls an ODBC API function (without a
suffix), the Driver Manager recognizes the application as a Unicode application and converts the function call to
a Unicode function (with the W suffix) if the underlying driver supports Unicode. When an ANSI application
makes a function call without a suffix, the Driver Manager converts it to ANSI if the underlying driver supports
ANSI. If both the application and the driver support the same character encoding, the driver manager passes the
calls through to the driver (with certain exceptions for ANSI applications).
An application can call both Unicode functions (with the W suffix) and ANSI functions (with or without the A
suffix). Unicode and ANSI function calls can be mixed. If the cursor library is to be used, however, Unicode and
ANSI function calls cannot be mixed. The cursor library is either Unicode or ANSI, not a mixture.
An application can be written such that it can be compiled as either a Unicode application or an ANSI
application. In this case, character data types can be declared as SQL_C_TCHAR. This is a macro that inserts
SQL_C_WCHAR if the application is compiled as a Unicode application or inserts SQL_C_CHAR if it is compiled
as an ANSI application. The application programmer must be careful of functions that take SQLPOINTER as their
argument, because the size of the length argument will change (for string data types) depending on whether the
application is ANSI or Unicode.
A function can be called in one of three ways: as a Unicode-only function call (with the W suffix), as an ANSI-only
function call (with the A suffix), or as the ODBC function call with no suffix. The arguments to the three forms of
a function are identical. Only those functions with SQLCHAR * arguments or SQLPOINTER arguments that point
to strings require Unicode and ANSI forms. For functions that have arguments that can be declared as a
character type, such as SQLBindCol or SQLGetData (which do not have Unicode and ANSI forms), the
argument can be declared as the Unicode type, the ANSI type, or in the case of a C type argument, the
SQL_C_TCHAR macro. For more information, see Unicode Data.
An application can be written as a Unicode application even if no Unicode drivers are available for it to work
with. The Driver Manager will map Unicode functions and data types to ANSI. There are some restrictions to the
Unicode to ANSI mappings that can be performed. The existence of a Unicode driver for the Unicode application
to work with will result in better performance and will remove the restrictions inherent in the Unicode to ANSI
mappings.
Unicode Drivers
4/27/2022 • 2 minutes to read • Edit Online

Whether a driver should be a Unicode driver or an ANSI driver depends entirely on the nature of the data
source. If the data source supports Unicode data, the driver should be a Unicode driver. If the data source only
supports ANSI data, the driver should remain an ANSI driver.
A Unicode driver must export SQLConnectW to be recognized as a Unicode driver by the Driver Manager.
A Unicode driver must accept Unicode functions (with a suffix of W) and store Unicode data. It can also accept
ANSI functions, but is not required to. (The Driver Manager does not pass an ANSI function call with the A suffix
to the driver, but converts it to an ANSI function call without the suffix and then passes it to the driver.)
A Unicode driver must be able to return result sets in either Unicode or ANSI, depending on the application's
binding. If an application binds to SQL_C_CHAR, the Unicode driver must convert SQL_WCHAR data to
SQL_CHAR. The driver manager will map SQL_C_WCHAR to SQL_C_CHAR for ANSI drivers but does no
mapping for Unicode drivers.

NOTE
When determining the driver type, the Driver Manager will call SQLSetConnectAttr and set the SQL_ATTR_ANSI_APP
attribute at connection time. If the application is using ANSI APIs, SQL_ATTR_ANSI_APP will be set to SQL_AA_TRUE, and if
it is using Unicode, it will be set to a value of SQL_AA_FALSE. This attribute is used so that the driver can exhibit different
behavior based on the application type. The attribute cannot be set by the application directly, and it is not supported by
SQLGetConnectAttr . If a driver exhibits the same behavior for both ANSI and Unicode applications, it should return
SQL_ERROR for this attribute. If the driver returns SQL_SUCCESS, the Driver Manager will separate ANSI and Unicode
connections when Connection Pooling is used.
Function Mapping in the Driver Manager
4/27/2022 • 2 minutes to read • Edit Online

The driver manager supports two entry points for functions that take string arguments. The undecorated
function (SQLDriverConnect ) is the ANSI form of the function. The Unicode form is decorated with a W
(SQLDriverConnectW .)
The ODBC header file also supports functions decorated with an A, (SQLDriverConnectA ) for the convenience
of mixed ANSI/Unicode applications. Calls made to the A functions are actually calls into the undecorated entry
point (SQLDriverConnect .)
If the application is compiled with the _UNICODE #define , the ODBC header file will map undecorated function
calls (SQLDriverConnect ) to the Unicode version (SQLDriverConnectW .)
The Driver Manager recognizes a driver as a Unicode driver if SQLConnectW is supported by the driver.
If the driver is a Unicode driver, the Driver Manager makes function calls as follows:
Passes a function without string arguments or parameters directly through to the driver.
Passes Unicode functions (with the W suffix) directly through to the driver.
Converts an ANSI function (with the A suffix) to a Unicode function (with the W suffix) by converting the
string arguments into Unicode characters and passes the Unicode function to the driver.
If the driver is an ANSI driver, the Driver Manager makes function calls as follows:
Passes functions without string arguments or parameters directly through to the driver.
Converts Unicode functions (with the W suffix) to an ANSI function call and passes it to the driver.
Passes an ANSI function directly to the driver.
The Driver Manager is Unicode-enabled internally. As a result, the optimum performance is obtained by a
Unicode application working with a Unicode driver, because the Driver Manager simply passes Unicode
functions through to the driver. When an ANSI application is working with an ANSI driver, the Driver Manager
must convert strings from ANSI to Unicode when processing some functions, such as SQLDriverConnect .
After processing the function, the Driver Manager must then convert the Unicode string back to ANSI before
sending the function to the ANSI driver.
An application should not modify or read its bound parameter buffers when the driver returns
SQL_STILL_EXECUTING or SQL_NEED_DATA. The Driver Manager leaves the buffers bound to ANSI until the
driver returns SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, or SQL_ERROR. A multithreaded application should
not gain access to any bound parameter values that another thread is executing an SQL statement on. The
Driver Manager converts the data from Unicode to ANSI "in place," and the other thread might see ANSI data in
these buffers while the driver is still processing the SQL statement. Applications that bind Unicode data to an
ANSI driver must not bind two different columns to the same address.
Unicode Data
4/27/2022 • 2 minutes to read • Edit Online

SQL Unicode data types are provided to describe data that resides in Unicode natively on the DBMS. A C
Unicode data type is provided to allow an application to bind data to a Unicode buffer. The Driver Manager can
convert data from a Unicode C type (SQL_C_WCHAR) to make it function with an ANSI driver.
An ODBC 3.0 or 2.x application will always bind to the ANSI data types. For optimum performance, an ODBC 3.5
(or higher) application should bind to the ANSI data C type if the SQL column type is ANSI, and should bind to
the Unicode C data type if the SQL column type is Unicode.
The SQL Unicode type indicators are SQL_WCHAR, SQL_WVARCHAR, and SQL_WLONGVARCHAR. SQL_WCHAR
data has a fixed string length, while SQL_WVARCHAR has a variable length with a declared maximum and
SQL_WLONGVARCHAR has a variable length with a maximum that depends on the data source.
The C Unicode type indicator is SQL_C_WCHAR. This is the default for each of the SQL Unicode type indicators.
All of the SQL types can be converted to SQL_C_WCHAR, and SQL_C_WCHAR can be converted to all of the SQL
types. An application can retrieve data in one of three ways:
Retrieve the data as SQL_C_CHAR.
Retrieve the data as SQL_C_WCHAR.
Declare the data as SQL_C_TCHAR. This is a macro that inserts SQL_C_WCHAR if the application is
compiled as a Unicode application or inserts SQL_C_CHAR if it is compiled as an ANSI application.
SQL_C_TCHAR is declared in a function as follows:

SQLBindParameter(StatementHandle, 1, SQL_PARAM_INPUT, SQL_C_TCHAR, SQL_WCHAR, NameLen, 0, Name, 0, &Name)

When the application is compiled as a Unicode application, the ValueType argument would be changed from
SQL_C_TCHAR to SQL_C_WCHAR. When the application is compiled as an ANSI application, the ValueType
argument would be changed to SQL_C_CHAR.
Unicode drivers must still support ANSI data types, including SQL_CHAR. If an application working with a
Unicode driver binds to SQL_CHAR, the Driver Manager will not map the SQL_CHAR data to SQL_WCHAR. The
Unicode driver must accept the SQL_CHAR data.
The Driver Manager stores driver and DSN names in Unicode and maps them to ANSI as needed. If a Unicode
character cannot be mapped to an ANSI character (as can occur if characters from a code page that is not the
native code page of the computer are used in driver and DSN names), the characters that could not be
converted are represented by a default character supplied by the system.
Translation DLLs
4/27/2022 • 2 minutes to read • Edit Online

The application and data source often store data in different character sets. ODBC provides a generic mechanism
that allows the driver to translate data from one character set to another. It consists of a DLL that implements the
translation functions SQLDriverToDataSource and SQLDataSourceToDriver , which are called by the driver
to translate all data flowing between the data source and driver. This DLL can be written by the application
developer, the driver developer, or a third party.
The translation DLL for a particular data source can be specified in the system information for that data source;
for more information, see Data Source Specification Subkeys. It can also be set at run time with the
SQL_ATTR_TRANSLATE_DLL and SQL_ATTR_TRANSLATE_OPTION connection attributes.
The translation option is a value that can be interpreted only by a particular translation DLL. For example, if the
translation DLL translates between different code pages, the option might give the numbers of the code pages
used by the application and the data source. There is no requirement for a translation DLL to use a translation
option.
After a translation DLL has been specified, the driver loads it and calls it to translate all data flowing between the
application and data source. This includes all SQL statements and character parameters being sent to the data
source, and all character results, character metadata such as column names, and error messages retrieved from
the data source. Connection data is not translated, because the translation DLL is not loaded until after the
application has connected to the data source.
Diagnostic Tools
4/27/2022 • 2 minutes to read • Edit Online

Two facilities can assist with diagnosing problems in ODBC applications. Both are available from the ODBC
Administrator and implemented by the Driver Manager. Tracing provides a means to record to a log file the
sequence of function calls. Visual Studio Analyzer allows the analysis of information about the interaction of
components in a distributed environment.
This section contains the following topics.
Tracing
Visual Studio Analyzer
Tracing
4/27/2022 • 2 minutes to read • Edit Online

The ODBC Driver Manager has a trace facility that allows the sequence of function calls made by an ODBC
application to be recorded and transcribed into a log file. Tracing is performed by a trace DLL that captures calls
between the application and the Driver Manager, and between the Driver Manager and the driver. This method
of tracing replaces the tracing performed by the ODBC 2*.x* Driver Manager and the tracing performed in ODBC
2*.x* by ODBC Spy.
This section contains the following topics.
Trace DLL
Trace File
Enabling Tracing
Dynamic Tracing
Trace DLL
4/27/2022 • 2 minutes to read • Edit Online

The DLL that performs tracing is one of the ODBC core components. The trace DLL is currently provided as a
sample DLL in the ODBC component of the Windows SDK, and was formerly included the Microsoft Data Access
Components (MDAC) SDK. Therefore, the registry entry, interface, and sample code for the trace DLL are
available. This DLL can be replaced by a trace DLL produced by either an ODBC user or a third-party vendor. A
custom trace DLL should be given a different name than the original sample trace DLL. Trace DLLs must be
installed in the system directory, or they will fail to load. The connection strings will not be passed to the trace
DLL by the Driver Manager.
The trace DLL traces input arguments, output arguments, deferred arguments, return codes, and SQLSTATEs.
When tracing is enabled, the Driver Manager calls the trace DLL at two points: once upon function entry (before
argument validation) and again just before the function returns.
When an application calls a function, the Driver Manager calls a trace function in the trace DLL before calling the
function in the driver or processing the call itself. Each ODBC function has a corresponding trace function
(prefixed with Trace) that is identical to the ODBC function with the exception of the name. When the trace
function is called, the trace DLL captures the input arguments and returns a return code. Because the trace DLL is
called before the Driver Manager validates arguments, invalid function calls are traced, so state transition errors
and invalid arguments are logged.
After calling the trace function in the trace DLL, the Driver Manager calls the ODBC function in the driver. It then
calls TraceReturn in the trace DLL. This function takes two arguments: the value returned by the trace DLL for
the trace function, and the return code returned by the driver to the Driver Manager for the ODBC function (or
the value returned by the Driver Manager itself if it processed the function). The function uses the value returned
for the trace function to manipulate captured input argument values. It writes the code returned for the ODBC
function to the log file (or displays it dynamically, if that is enabled). It dereferences the output argument
pointers and logs the output argument values.
Trace File
4/27/2022 • 2 minutes to read • Edit Online

An application specifies the trace file either by setting the TraceFile keyword in the Odbc.ini registry entry or by
calling SQLSetConnectAttr with the SQL_ATTR_TRACEFILE connection attribute. If the file does not exist when
tracing is enabled, the Driver Manager will create the file. Each application should have its own dedicated trace
file to avoid contention. An application can use more than one trace file; an application's setup program can
provide the user with a choice of trace files. If tracing is enabled dynamically, an application can also display
trace results, rather than logging to the trace file.
The trace file provides a log of each ODBC function call with the data types and values of all arguments. It logs
all input functions and logs all returned functions with return codes and error states.
In ODBC 3.x, parameters to connection functions are not provided to the trace DLL.
Enabling Tracing
4/27/2022 • 2 minutes to read • Edit Online

Tracing can be enabled in the following three ways:


Set the Trace and TraceFile keywords in the Odbc.ini registry entry. This enables or disables tracing
when SQL AllocHandle with a HandleType of SQL_HANDLE_ENV is called. These options are set in the
Tracing tab of the ODBC Data Source Administrator dialog box displayed during data source setup. For
more information, see Registry Entries for Data Sources.
Call SQLSetConnectAttr to set the SQL_ATTR_TRACE connection attribute to SQL_OPT_TRACE_ON. This
enables or disables tracing for the duration of the connection. For more information, see the
SQLSetConnectAttr function description.
Use ODBCSharedTraceFlag to turn tracing on or off dynamically. (For more information, see the next
topic, Dynamic Tracing.)
Dynamic Tracing
4/27/2022 • 2 minutes to read • Edit Online

Tracing can be enabled or disabled at any point in an application run. This allows an application to trace any
number of function calls.
The variable ODBCSharedTraceFlag is set to enable tracing dynamically. This variable is shared among all
running copies of the Driver Manager. If any application sets this variable, tracing is enabled for all ODBC
applications currently running. To turn tracing off when dynamic tracing is enabled, an application calls
SQLSetConnectAttr to set SQL_ATTR_TRACE to SQL_TRACE_OFF. This call will turn tracing off for that
application only. Applications that are linked with Odbc32.lib can modify use of this variable. Trace data can be
displayed in a real-time window, instead of the trace file, which must be opened after the ODBC session.
Controls can be added to an application's screen to turn tracing on or off at will.
The trace DLL shipped with ODBC 3*.x* is not thread-safe. It is not guaranteed that the log file is written
correctly if global tracing is enabled (the variable ODBCSharedTraceFlag is set) and more than one application
writes to the trace file at the same time. This condition does not return an error.
Visual Studio Analyzer
4/27/2022 • 2 minutes to read • Edit Online

IMPORTANT
Support for Visual Studio Analyzer was removed beginning in Windows 8 (Visual Studio Analyzer was only included in
older versions of Visual Studio.). For an alternative troubleshooting mechanism, use BID tracing.

Microsoft® Visual Studio™ Analyzer provides a high-level view of the ODBC application. The developer can
evaluate, analyze, and debug the structure, performance, and interactions from the application's perspective,
rather than from a component or code perspective. The information gathered by Visual Studio Analyzer is in the
form of events, which represent some kind of interaction between two components of the application. Events
can be composed of function calls and returns from functions, such as connections, database queries, and
transactions.
This section contains the following topic.
Enabling Visual Studio Analyzer
Enabling Visual Studio Analyzer
4/27/2022 • 2 minutes to read • Edit Online

IMPORTANT
Support for Visual Studio Analyzer was removed beginning in Windows 8 (Visual Studio Analyzer was only included in
older versions of Visual Studio.). For an alternative troubleshooting mechanism, use BID tracing.

Microsoft Visual Studio Analyzer is an application-analysis tool designed to provide a high-level look at an
application's performance across all tiers and systems. It focuses on the interaction between components. Visual
Studio Analyzer can be started and stopped from the ODBC Administrator's Tracing tab.
To view any of the events that ODBC generates, follow these steps:
1. Access the ODBC Data Source Administrator.
2. Click the Tracing tab.
3. Click Star t Visual Studio Analyzer Tracing .
4. Click OK .
Visual Studio Analyzer event-generation continues until Stop Visual Studio Analyzer Tracing is selected.
This section contains the following topic.
Events Generated by the ODBC Driver Manager
Events Generated by the ODBC Driver Manager
4/27/2022 • 2 minutes to read • Edit Online

IMPORTANT
Support for Visual Studio Analyzer was removed beginning in Windows 8 (Visual Studio Analyzer was only included in
older versions of Visual Studio.). For an alternative troubleshooting mechanism, use BID tracing.

Events generated by the ODBC Driver Manager are registered when the Start Visual Studio Analyzer button is
clicked. The tool itself offers system-defined events and the ability to create custom events. For more
information about events, see the Visual Studio Analyzer Reference Guide within the Visual Studio suite of
documentation.

VISUA L ST UDIO A N A LY Z ER EVEN T DESC RIP T IO N

Call Generated on every ODBC API entry.

ReturnException Generated on every ODBC API return if the return code is


SQL_ERROR.

ReturnNormal Generated on every ODBC API return if the return code is


not SQL_ERROR.

Connection Star t Indicates that a connection started; generated when the


ODBC Driver Manager calls the driver's connection APIs.

Connection Complete Indicates that a connection completed; generated when the


driver's connection APIs return to the ODBC Driver Manager.

Disconnect Star t Generated when the ODBC Driver Manager calls the driver's
SQLDisconnect function.

Disconnect Complete Generated when the driver's SQLDisconnect function


returns to the ODBC Driver Manager.

Quer ySend Generated when the ODBC Driver Manager calls the driver's
SQLPrepare , SQLExecute , SQLExecDirect functions, as
well as catalog functions such as SQLTables and
SQLColumns .

Quer yResult Generated when the driver returns a result set to the ODBC
Driver Manager for functions involving queries.

TransactionStar t Generated when an application sets the value of


SQL_ATTR_AUTOCOMMIT to SQL_AUTOCOMMIT_OFF, or
after an application successfully calls SQLEndTran .

TransactionCommit Generated when an application calls SQLEndTran to


commit a local transaction.
VISUA L ST UDIO A N A LY Z ER EVEN T DESC RIP T IO N

TransactionRollback Generated when an application calls SQLEndTran to roll


back a local transaction.

JoinDTC Generated when an application joins the Distributed


Transaction Coordinator (DTC).

LeaveDTC Generated when an application leaves the Distributed


Transaction Coordinator (DTC).
Driver-Specific Data Types, Descriptor Types,
Information Types, Diagnostic Types, and Attributes
4/27/2022 • 2 minutes to read • Edit Online

Drivers can allocate driver-specific values for the following:


SQL Data Type Indicators These are used in ParameterType in SQLBindParameter and in DataType in
SQLGetTypeInfo and returned by SQLColAttribute , SQLColumns , SQLDescribeCol ,
SQLGetTypeInfo , SQLDescribeParam , SQLProcedureColumns , and SQLSpecialColumns .
Descriptor Fields These are used in FieldIdentifier in SQLColAttribute , SQLGetDescField , and
SQLSetDescField .
Diagnostic Fields These are used in DiagIdentifier in SQLGetDiagField and SQLGetDiagRec .
Information Types These are used in InfoType in SQLGetInfo .
Connection and Statement Attributes These are used in Attribute in SQLGetConnectAttr ,
SQLGetStmtAttr , SQLSetConnectAttr , and SQLSetStmtAttr .
For each of these items, there are two sets of values: values reserved for use by ODBC, and values reserved for
use by drivers. Before implementing driver-specific values, a driver writer must request a value for each driver-
specific type, field, or attribute from Open Group. For new driver development, use the range described in the
table below. The ODBC 3.8 Driver Manager will not generate an error if an unknown value is used that is not in
the range described below. However, later versions of the Driver Manager might generate an error if unknown
values are received that are not in the range.
When any of these values is passed to an ODBC function, the driver must check whether the value is valid.
Drivers return SQLSTATE HYC00 (Optional feature not implemented) for driver-specific values that apply to
other drivers.
Starting with ODBC 3.8, driver writers can allocate driver-specific attributes within a reserved range.

NOTE
The ODBC 3.8 Driver Manager neither validates nor enforces these ranges for backward compatibility. A future version of
the Driver Manager might enforce them, however.

O DB C C O N STA N T
F O R DRIVER-
DRIVER- SP EC IF IC DRIVER- SP EC IF IC SP EC IF IC VA L UE
AT T RIB UT E T Y P E O DB C DATA T Y P E RA N GE B A SE RA N GE L IM IT RA N GE B A SE

SQL data type SQLSMALLINT 0x4000 0x7FFF SQL_DRIVER_SQL_TY


indicators PE_BASE

Descriptor fields SQLSMALLINT 0x4000 0x7FFF SQL_DRIVER_DESCRI


PTOR_BASE

Diagnostic fields SQLSMALLINT 0x4000 0x7FFF SQL_DRIVER_DIAGN


OSTIC_BASE
O DB C C O N STA N T
F O R DRIVER-
DRIVER- SP EC IF IC DRIVER- SP EC IF IC SP EC IF IC VA L UE
AT T RIB UT E T Y P E O DB C DATA T Y P E RA N GE B A SE RA N GE L IM IT RA N GE B A SE

Information types SQLUSMALLINT 0x4000 0x7FFF SQL_DRIVER_INFO_T


YPE_BASE

Connection SQLINTEGER 0x00004000 0x00007FFF SQL_DRIVER_CONNE


attributes CT_ATTR_BASE

Statement attributes SQLINTEGER 0x00004000 0x00007FFF SQL_DRIVER_STATEM


ENT_ATTR_BASE

NOTE
Driver-specific data types, descriptor fields, diagnostic fields, information types, statement attributes, and connection
attributes must be described in the driver documentation. When any of these values is passed to an ODBC function, the
driver must check whether the value is valid. Drivers return SQLSTATE HYC00 (Optional feature not implemented) for
driver-specific values that apply to other drivers.

The base values are defined to facilitate driver development. For example, driver specific diagnostic attributes
can be defined in the following format:

SQL_DRIVER_DIAGNOSTIC_BASE+0, SQL_DRIVER_DIAGNOSTIC_BASE +1
Backward Compatibility and Standards Compliance
4/27/2022 • 2 minutes to read • Edit Online

Backward compatibility is the ability of newer ODBC components to work with old ODBC components. The
following sections discuss how these components are affected by the changes in ODBC 3.x. The information
contained in them primarily addresses the writing of an ODBC 3.x application and how backward compatibility
issues are handled by ODBC drivers. For specific guidelines about how backward compatibility issues affect the
writing of an ODBC 3.x driver, see Appendix G: Driver Guidelines for Backward Compatibility.
This section contains the following topics.
Affected ODBC Components
Types of Changes
Application/Driver Compatibility
New Features
Duplicated Features
Behavioral Changes
Writing ODBC 3.x Applications
Writing ODBC 3.x Drivers
Affected ODBC Components
4/27/2022 • 2 minutes to read • Edit Online

Backward compatibility describes how applications, the Driver Manager, and drivers are affected by the
introduction of a new version of the Driver Manager. This affects applications and driver when either or both of
them remain in the old version. There are, therefore, three types of backward compatibility to consider, as shown
in the following table.

TYPE VERSIO N O F DM VERSIO N O F A P P L IC AT IO N VERSIO N O F DRIVER

Backward Compatibility of 3.x 2.x 2.x


Driver Manager

Backward Compatibility of 3.x 2.x 3.x


Driver[1]

Backward Compatibility of 3.x 3.x 2.x


Application

[1] The backward compatibility of drivers is primarily discussed in Appendix G: Driver Guidelines for Backward
Compatibility.

NOTE
A standards-compliant application - for example, an application that has been written in accordance with the Open Group
or ISO CLI standards - is guaranteed to work with an ODBC 3.x driver through the ODBC 3.x Driver Manager. It is
assumed that the functionality that the application is using is available in the driver. It is also assumed that the standards-
compliant application has been compiled with the ODBC 3.x header files.
Types of Changes
4/27/2022 • 2 minutes to read • Edit Online

Three types of changes are made in ODBC 3.x (and any version of ODBC). Each of these affects backward
compatibility differently and is handled in a different way. These changes are described in the following table.

T Y P E O F C H A N GE DESC RIP T IO N

New features These are features that are new to ODBC 3.x, such as out-of-
line binding or descriptors. These are implemented only
when the application and driver, as well as the Driver
Manager, are of version 3.x, so there is no attempt to make
these backward compatible.

Duplicated features These are features that exist in ODBC 2.x and ODBC 3.x but
are implemented in different ways in each. The functions
SQL AllocHandle and SQL AllocStmt are an example.
Backward compatibility issues for these and other duplicated
features are mostly handled by mappings in the Driver
Manager.

Behavioral changes These are features that are handled differently in ODBC 2.x
and ODBC 3.x. A datetime #define is an example. These
features are handled by the ODBC 3.x driver based on an
environment attribute setting. (See Behavioral Changes for
more information.)
Application and Driver Compatibility
4/27/2022 • 2 minutes to read • Edit Online

ODBC applications and driver fall into a number of categories in addition to their version. Some of these
applications are incompatible with some drivers; in other cases, the type of the application or driver may have a
bearing on the backward compatibility issues between them.
This section contains the following topics.
Types of Applications
Types of Drivers
Compatibility Matrix
Types of Applications
4/27/2022 • 2 minutes to read • Edit Online

ODBC applications can be classified as follows:


Pure ODBC 2.
x Application A 32-bit application that:
Calls only ODBC 2.x functions (including the ODBC 1.0 function SQLSetParam ). These include
ODBC 1.x applications that have been ported to 32-bit.
Expects ODBC 2.x behavior for features that have had behavioral changes. (See Behavioral
Changes for more information.)
Has not been recompiled with ODBC 3.5 headers.
Pure ODBC 2.
x Recompiled Application A pure ODBC 2.x application that has been recompiled using the ODBC 3.5
header files, by setting ODBCVER=0x0250.
Pure ODBC 2.
x Unicode Application A pure ODBC 2.x recompiled application that is Unicode-compliant and uses the
SQL_WCHAR data type.
Pure Open Group and ISO -compliant ODBC Application A 32-bit application that:
Calls functions defined in the Open Group or ISO CLI standards. (These functions may include
deprecated 3.0 functions.)
Does not use the Unicode data types.
Expects ODBC 3.0 behavior for features that have had behavioral changes.
Pure ODBC 3.0 Application A 32-bit application that:
Is compiled with 3.0 headers.
Calls any ODBC 3.0 function, possibly including those that are deprecated.
Expects ODBC 3.0 behavior for features that have had behavioral changes.
Pure ODBC 3.5 Application A 32 or 64-bit application that:
May use Unicode data types.
Calls any ODBC 3.5 function, possibly including those that are deprecated.
Expects ODBC 3.5 behavior for features that have had behavioral changes.
Pure ODBC 3.8 (or later) Application A 32-bit or 64-bit application that:
May use Unicode data types.
Calls any ODBC 3.8 function, possibly including those that are deprecated.
Expects ODBC 3.8 behavior for features that have had behavioral changes.
Replaced Application A 32 or 64-bit application that:
Implements new behavior for duplicated functionality.
Uses any new features in a later version of ODBC only within conditional code.
Has limited conditional code to handle behavioral changes or has registered itself to be an earlier
version of ODBC application.
Types of Drivers
4/27/2022 • 2 minutes to read • Edit Online

ODBC drivers can be classified as follows:


32-bit ODBC 2.
x Driver A 32-bit driver that:
Exports only ODBC 2.x functions.
Exhibits ODBC 2.x behavior for behavioral changes.
ISO and Open Group-Compliant Driver A 32-bit driver that:
Exports all functions that are documented in the Open Group or ISO CLI documents. This will
include some of functions that are deprecated in ODBC.
Exhibits ODBC 3.0 behavior for behavioral changes.
Does not necessarily go through the ODBC 3.0 Driver Manager.
ODBC 3.0 Driver A 32-bit driver that:
Exports only functions that are in ODBC 3.0 minus deprecated functions.
Is capable of exhibiting ODBC 2.x behavior or ODBC 3.0 behavior with respect to behavioral
changes, based on the SQL_ATTR_APP_ODBC_VERSION environment attribute.
ODBC 3.5 (or later) ANSI Driver A 32-bit driver that:
Exports only functions that are in ODBC 3.5 minus deprecated functions.
Is capable of exhibiting ODBC 2.x behavior or ODBC 3.0 behavior, or ODBC 3.5 behavior with
respect to behavioral changes, based on the SQL_ATTR_APP_ODBC_VERSION environment
attribute.
ODBC 3.5 (or later) Unicode Driver A 32-bit driver that:
Supports all the features of an ODBC 3.5 ANSI driver.
Exports Unicode versions of all ODBC string APIs.
Can store and process Unicode data on the data source.

NOTE
16-bit ODBC drivers will not work directly with the ODBC 3.x Driver Manager. However, it is possible for 16-bit drivers to
work with the 2.0 ODBC Driver Manager, which subsequently thunks up to the 3.x Driver Manager.
Compatibility Matrix
4/27/2022 • 2 minutes to read • Edit Online

The following table describes the compatibility of the types of applications and drivers defined previously in this
section.

A P P L IC AT IO N T Y P E 32- B IT O DB C O DB C 3. X ISO A N D O P EN
GRO UP - C O M P L IA N T
A N D VERSIO N 2. X DRIVER DRIVER O DB C 3. 8 DRIVER DRIVER

16-bit application, Compatible Compatible Compatible Compatible


any version

Pure 2.x application Compatible Compatible Compatible Not compatible[3]

Pure 2.x recompiled Compatible Compatible[1] Compatible[1] Not compatible[3]


application

Pure 2.x Unicode Compatible Compatible[1] Compatible[1] Not Compatible[3]


application

Pure Open Group Not compatible Compatible[2] Compatible[2] Compatible[2]


and ISO-compliant
application

Pure 3.0 application Not compatible Compatible Compatible Not compatible[4]

Pure 3.5 application Not compatible Compatible Compatible Not compatible[4]

Pure 3.8 (or higher) Not compatible [5] Not compatible [5] Compatible Not compatible [4]
application

Replaced application Compatible Compatible Compatible Not compatible[3]

[1] The application must recompile using ODBC 3.5 (or higher) headers with the UNICODE option (if it is a
Unicode application) and must set ODBCVER to 0x0250.
[2] The application must compile using ODBC 3.5 (or higher)headers and link with the ODBC Driver Manager. It
must also set the header flag ODBC_STD.
[3] This configuration can potentially fail to work because there are features in ODBC 2.x that are not in the
standards, such as bookmarks.
[4] This configuration can potentially fail to work because there are features in ODBC 3.x that are not in the
standards, such as bookmarks.
[5] This configuration can potentially fail because there are features in ODBC 3.8 that are not in ODBC 2.x or 3.x
drivers, such as driver-specific C Data Types in ODBC.

Driver Manager Compatibility


An ODBC 3.0 application that must operate with all Driver Manager versions should do the following on startup:
Allocate an environment handle.
Set the SQL_ATTR_ODBC_VERSION environment attribute to SQL_OV_ODBC3_80. If the Driver Manager
returns SQL_ERROR, the Driver Manager is older than 3.8. Reset SQL_ATTR_ODBC_VERSION to
SQL_OV_ODBC3 or SQL_OV_ODBC2, as appropriate, to correspond to the Driver Manager.
Allocate a connection handle.
Make a connection.
Call SQLGetInfo for SQL_DRIVER_ODBC_VER to determine the driver version. If the driver is an ODBC 3.8
driver, you can use driver-specific C types. Otherwise, do not use driver-specific C data types.
Note that a recompiled ODBC 3.x application can use ODBC 3.8 features other than driver-specific C types
without specifying SQL_OV_ODBC3_80 for SQL_ATTR_ODBC_VERSION. This is similar to a recompiled ODBC 2.x
application using ODBC 3.x features.

Using SQLCancelHandle in an Application Compatible with all Driver


Managers
Because SQLCancelHandle Function is not supported in Driver Managers that were released before Windows 7,
an application cannot be loaded in older versions of Windows if it calls SQLCancelHandle directly. To work
with all versions of Driver Managers and use SQLCancelHandle on new versions of Windows, an application
should call SQLCancelHandle indirectly by using LoadLibrar y and GetProcAddress.

See Also
What's New in ODBC 3.8
New Features
4/27/2022 • 2 minutes to read • Edit Online

The following new functionality has been introduced in ODBC 3.x. An ODBC 3.x application working with an
ODBC 2.x driver will not be able to use this functionality. The ODBC 3.x Driver Manager does not map these
features when working with an ODBC 2.x driver.
Functions that take a descriptor handle as an argument: SQLSetDescField , SQLGetDescField ,
SQLSetDescRec , SQLGetDescRec , and SQLCopyDesc .
The functions SQLSetEnvAttr and SQLGetEnvAttr .
The use of SQL AllocHandle to allocate a descriptor handle. (The use of SQL AllocHandle to allocate
environment, connection, and statement handles is duplicated, not new, functionality.)
The use of SQLGetConnectAttr to get the SQL_ATTR_AUTO_IPD connection attributes. (The use of
SQLSetConnectAttr to set, and SQLGetConnectAttr to get, other connection attributes is duplicated,
not new, functionality.)
The use of SQLSetStmtAttr to set, and SQLGetStmtAttr to get, the following statement attributes. (The
use of SQLSetStmtAttr to set, and SQLGetStmtAttr to get, other statement attributes is duplicated, not
new, functionality.)
SQL_ATTR_APP_ROW_DESC
SQL_ATTR_APP_PARAM_DESC
SQL_ATTR_ENABLE_AUTO_IPD
SQL_ATTR_FETCH_BOOKMARK_PTR
SQL_ATTR_BIND_OFFSET
SQL_ATTR_METADATA_ID
SQL_ATTR_PARAM_BIND_OFFSET_PTR
SQL_ATTR_PARAM_BIND_TYPE
SQL_ATTR_PARAM_OPERATION_PTR
SQL_DESC_PARAM_STATUS_PTR
SQL_ATTR_PARAMS_PROCESSED_PTR
SQL_ATTR_PARAMSET_SIZE
SQL_ATTR_ROW_BIND_OFFSET_PTR
SQL_ATTR_ROW_OPERATION_PTR
SQL_ATTR_ROW_ARRAY_SIZE
The use of SQLGetStmtAttr to get the following statement attributes. (The use of SQLGetStmtAttr to
get other statement attributes is duplicated functionality, not new functionality.)
SQL_ATTR_IMP_ROW_DESC SQL_ATTR_IMP_PARAM_DESC
Use of the interval C data type, the interval SQL data types, the BIGINT C data types, and the
SQL_C_NUMERIC data structure.
Row-wise binding of parameters.
Offset-based bookmark fetches, such as calling SQLFetchScroll with a FetchOrientation argument of
SQL_FETCH_BOOKMARK and specifying an offset other than 0.
SQLFetch returning the row status array, number of rows fetched, fetching multiple rows, intermixing
calls with SQLFetchScroll , and intermixing calls with SQLBulkOperations or SQLSetPos . For more
information, see the next section, Block Cursors, Scrollable Cursors, and Backward Compatibility for
ODBC 3.x Applications.
Named parameters.
Any of the ODBC 3.x-specific SQLGetInfo options. (If an ODBC 3.x application working with an ODBC 2.x
driver calls the SQL_XXX_CURSOR_ATTRIBUTES1 information types, which have replaced several ODBC
2.x information types, some of the information might be reliable, but some might be unreliable. For more
information, see SQLGetInfo.)
Bind offsets.
Updating, refreshing, and deleting by bookmarks (through a call to SQLBulkOperations ).
Calling SQLBulkOperations or SQLSetPos in the S5 state.
The ROW_NUMBER and COLUMN_NUMBER fields in the diagnostic record (which have to be retrieved
by the replacement functions SQLGetDiagField or SQLGetDiagRec ).
Approximate row counts.
Warning information (SQL_ROW_SUCCESS_WITH_INFO from SQLFetchScroll ).
Variable-length bookmarks.
Extended error information for arrays of parameters.
All of the new columns in the result sets returned by the catalog functions.
Use of SQLDescribeCol and SQLColAttribute on column 0.
Use of any ODBC 3.x-specific column attributes in a call to SQLColAttribute .
Use of multiple environment handles.
This section contains the following topic.
Block Cursors, Scrollable Cursors, and Backward Compatibility for ODBC 3.x Applications
Block Cursors, Scrollable Cursors, and Backward
Compatibility for ODBC 3.x Applications
4/27/2022 • 4 minutes to read • Edit Online

The existence of both SQLFetchScroll and SQLExtendedFetch represents the first clear split in ODBC
between the Application Programming Interface (API), which is the set of functions the application calls, and the
Service Provider Interface (SPI), which is the set of functions the driver implements. This split is required to
balance the requirement in ODBC 3.x, which uses SQLFetchScroll , to align with the standards and be
compatible with ODBC 2.x, which uses SQLExtendedFetch .
The ODBC 3.x API, which is the set of functions the application calls, includes SQLFetchScroll and related
statement attributes. The ODBC 3.x SPI, which is the set of functions the driver implements, includes
SQLFetchScroll , SQLExtendedFetch , and related statement attributes. Because ODBC does not formally
enforce this split between the API and the SPI, it is possible for ODBC 3.x applications to call
SQLExtendedFetch and related statement attributes. However, there is no reason for ODBC 3.x applications to
do this. For more information about APIs and SPIs, see the introduction to ODBC Architecture.
For information about how the ODBC 3.x Driver Manager maps calls to ODBC 2.x and ODBC 3.x drivers, and
what functions and statement attributes an ODBC 3.x driver should implement for block and scrollable cursors,
see What the Driver Does in Appendix G: Driver Guidelines for Backward Compatibility.
The following table summarizes what functions and statement attributes an ODBC 3.x application should use
with block and scrollable cursors. It also lists changes between ODBC 2.x and ODBC 3.x in this area that ODBC
3.x applications should be aware of to be compatible with ODBC 2.x drivers.

F UN C T IO N O R

STAT EM EN T AT T RIB UT E C O M M EN T S

SQL_ATTR_FETCH_BOOKMARK_PTR Points to the bookmark to use with SQLFetchScroll.

When an application sets this in an ODBC 2.x driver, this


must point to a fixed-length bookmark.

SQL_ATTR_ROW_STATUS_PTR Points to the row status array filled by SQLFetch ,


SQLFetchScroll, SQLBulkOperations , and SQLSetPos .

If an application sets this in an ODBC 2.x driver and calls


SQLBulkOperation with an Operation of SQL_ADD before
calling SQLFetchScroll, SQLFetch , or
SQLExtendedFetch , SQLSTATE HY011 (Attribute cannot be
set now) is returned.

When an application calls SQLFetch in an ODBC 2.x driver,


SQLFetch is mapped to SQLExtendedFetch and therefore
returns values in this array.

SQL_ATTR_ROWS_FETCHED_PTR Points to the buffer in which SQLFetch and


SQLFetchScroll return the number of rows fetched.

When an application calls SQLFetch in an ODBC 2.x driver,


SQLFetch is mapped to SQLExtendedFetch and therefore
returns a value in this buffer.
F UN C T IO N O R

STAT EM EN T AT T RIB UT E C O M M EN T S

SQL_ATTR_ROW_ARRAY_SIZE Sets the rowset size.

If an application calls SQLBulkOperations with an


Operation of SQL_ADD in an ODBC 2.x driver,
SQL_ROWSET_SIZE will be used for the call, not
SQL_ATTR_ROW_ARRAY_SIZE, because the call is mapped to
SQLSetPos with an Operation of SQL_ADD, which uses
SQL_ROWSET_SIZE.

Calling SQLSetPos with an Operation of SQL_ADD or


SQLExtendedFetch in an ODBC 2.x driver uses
SQL_ROWSET_SIZE.

Calling SQLFetch or SQLFetchScroll in an ODBC 2.x driver


uses SQL_ATTR_ROW_ARRAY_SIZE.

SQLBulkOperations Performs insert and bookmark operations. When


SQLBulkOperations with an Operation of SQL_ADD is
called in an ODBC 2.x driver, it is mapped to SQLSetPos
with an Operation of SQL_ADD. The following are
implementation details:

- When working with an ODBC 2.x driver, an application


must use only the implicitly allocated ARD associated with
the StatementHandle; it cannot allocate another ARD for
adding rows, because explicit descriptor operations are not
supported in an ODBC 2.x driver. An application must use
SQLBindCol to bind to the ARD, not SQLSetDescField or
SQLSetDescRec.
- When calling an ODBC 3.x driver, an application can call
SQLBulkOperations with an Operation of SQL_ADD
before calling SQLFetch or SQLFetchScroll. When calling
an ODBC 2.x driver, an application must call
SQLFetchScroll before calling SQLBulkOperations with
an Operation of SQL_ADD.

SQLFetch Returns the next rowset. The following are implementation


details:

- When an application calls SQLFetch in an ODBC 2.x driver,


it is mapped to SQLExtendedFetch .
- When an application calls SQLFetch in an ODBC 3.x driver,
it returns the number of rows specified with the
SQL_ATTR_ROW_ARRAY_SIZE statement attribute.
F UN C T IO N O R

STAT EM EN T AT T RIB UT E C O M M EN T S

SQLFetchScroll Returns the specified rowset. The following are


implementation details:

- When an application calls SQLFetchScroll in an ODBC 2.x


driver, it returns SQLSTATE 01S01 (Error in row) before each
error that applies to a single row. It does this only because
the ODBC 3.x Driver Manager maps this to
SQLExtendedFetch and SQLExtendedFetch returns this
SQLSTATE. When an application calls SQLFetchScroll in an
ODBC 3.x driver, it never returns SQLSTATE 01S01 (Error in
row).
- When an application calls SQLFetchScroll in an ODBC 2.x
driver with FetchOrientation set to SQL_FETCH_BOOKMARK,
the FetchOffset argument must be set to 0. SQLSTATE
HYC00 (Optional feature not implemented) is returned if
offset-based bookmark fetching is attempted with an ODBC
2.x driver.

NOTE
ODBC 3.x applications should not use SQLExtendedFetch or the SQL_ROWSET_SIZE statement attribute. Instead, they
should use SQLFetchScroll and the SQL_ATTR_ROW_ARRAY_SIZE statement attribute. ODBC 3.x applications should not
use SQLSetPos with an Operation of SQL_ADD but should use SQLBulkOperations with an Operation of SQL_ADD.
Duplicated Features
4/27/2022 • 2 minutes to read • Edit Online

The following ODBC 2.x functions have been duplicated by ODBC 3.x functions. As a result, the ODBC 2.x
functions are deprecated in ODBC 3.x. The ODBC 3.x functions are referred to as replacement functions.
When an application uses a deprecated ODBC 2.x function and the underlying driver is an ODBC 3.x driver, the
Driver Manager maps the function call to the corresponding replacement function. The only exception to this
rule is SQLExtendedFetch . (See the footnote at the end of the following table.) For more information about
these mappings, see Mapping Deprecated Functions in Appendix G: Driver Guidelines for Backward
Compatibility.
When an application uses a replacement function and the underlying driver is an ODBC 2.x driver, the Driver
Manager maps the function call to the corresponding deprecated function.

O DB C 2. X F UN C T IO N O DB C 3. X F UN C T IO N

SQL AllocConnect SQL AllocHandle

SQL AllocEnv SQL AllocHandle

SQL AllocStmt SQL AllocHandle

SQLColAttributes SQLColAttribute

SQLError SQLGetDiagRec

SQLExtendedFetch [1] SQLFetchScroll

SQLFreeConnect SQLFreeHandle

SQLFreeEnv SQLFreeHandle

SQLGetConnectOption SQLGetConnectAttr

SQLGetStmtOption SQLGetStmtAttr

SQLParamOptions SQLSetStmtAttr , SQLGetStmtAttr

SQLSetConnectOption SQLSetConnectAttr

SQLSetParam SQLBindParameter

SQLSetStmtOption SQLSetStmtAttr

SQLTransact SQLEndTran

[1] The function SQLExtendedFetch is duplicated functionality; SQLFetchScroll provides the same
functionality in ODBC 3.x. However, the Driver Manager does not map SQLExtendedFetch to SQLFetchScroll
when going against an ODBC 3.x driver. For more information, see What the Driver Manager Does in Appendix
G: Driver Guidelines for Backward Compatibility. The Driver Manager maps SQLFetchScroll to
SQLExtendedFetch when going against an ODBC 2.x driver.

NOTE
The function SQLBindParam is a special case. SQLBindParam is duplicated functionality. This is not an ODBC 2.x
function, but a function that is present in the Open Group and ISO standards. The functionality provided by this function
is completely subsumed by that of SQLBindParameter . As a result, the Driver Manager maps a call to SQLBindParam
to SQLBindParameter when the underlying driver is an ODBC 3.x driver. However, when the underlying driver is an
ODBC 2.x driver, the Driver Manager does not perform this mapping.
Behavioral Changes
4/27/2022 • 2 minutes to read • Edit Online

Behavioral changes are those changes for which the syntax of the interface remains the same, but the semantics
have changed. For these changes, functionality used in ODBC 2.x behaves differently than the same functionality
in ODBC 3.x.
Whether an application exhibits ODBC 2.x behavior or ODBC 3.x behavior is determined by the
SQL_ATTR_ODBC_VERSION environment attribute. This 32-bit value is set to SQL_OV_ODBC2 to exhibit ODBC
2.x behavior, and SQL_OV_ODBC3 to exhibit ODBC 3.x behavior.
The SQL_ATTR_ODBC_VERSION environment attribute is set by a call to SQLSetEnvAttr . After an application
calls SQL AllocHandle to allocate an environment handle, it must callSQLSetEnvAttr immediately to set the
behavior it exhibits. (As a result, there is a new environment state to describe the environment handle in an
allocated, but versionless, state.) For more information, see Appendix B: ODBC State Transition Tables.
An application states what behavior it exhibits with the SQL_ATTR_ODBC_VERSION environment attribute, but
the attribute has no effect on the application's connection with an ODBC 2.x or ODBC 3.x driver. An ODBC 3.x
application can connect to either an ODBC 2.x or 3.x driver, no matter what the setting of the environment
attribute.
ODBC 3.x applications should never call SQL AllocEnv . As a result, if the Driver Manager receives a call to
SQL AllocEnv , it recognizes the application as an ODBC 2.x application.
The SQL_ATTR_ODBC_VERSION attribute affects three different aspects of an ODBC 3.x driver's behavior:
SQLSTATEs
Data types for date, time, and timestamp
The CatalogName argument in SQLTables accepts search patterns in ODBC 3.x, but not in ODBC 2.x
The setting of the SQL_ATTR_ODBC_VERSION environment attribute does not affect SQLSetParam or
SQLBindParam . SQLColAttribute is also not affected by this bit. Although SQLColAttribute returns
attributes that are affected by the version of ODBC (date type, precision, scale and length), the intended behavior
is determined by the value of the FieldIdentifier argument. When FieldIdentifier is equal to SQL_DESC_TYPE,
SQLColAttribute returns the ODBC 3.x codes for date, time, and timestamp; when FieldIdentifier is equal to
SQL_COLUMN_TYPE, SQLColAttribute returns the ODBC 2.x codes for date, time, and timestamp.
This section contains the following topics.
SQLSTATE Mappings
Datetime Data Type Changes
SQLSTATE Mappings
4/27/2022 • 2 minutes to read • Edit Online

This topic discusses SQLSTATE values for ODBC 2.x and ODBC 3.x. For more information on ODBC 3.x SQLSTATE
values, see Appendix A: ODBC Error Codes.
In ODBC 3.x, HYxxx SQLSTATEs are returned instead of S1xxx, and 42Sxx SQLSTATEs are returned instead of
S00XX. This was done to align with Open Group and ISO standards. In many cases, the mapping is not one-to-
one because the standards have redefined the interpretation of several SQLSTATEs.
When an ODBC 2.x application is upgraded to an ODBC 3.x application, the application has to be changed to
expect ODBC 3.x SQLSTATEs instead of ODBC 2.x SQLSTATEs. The following table lists the ODBC 3.x SQLSTATEs
that each ODBC 2.x SQLSTATE is mapped to.
When the SQL_ATTR_ODBC_VERSION environment attribute is set to SQL_OV_ODBC2, the driver posts ODBC
2.x SQLSTATEs instead of ODBC 3.x SQLSTATEs when SQLGetDiagField or SQLGetDiagRec is called. A specific
mapping can be determined by noting the ODBC 2.x SQLSTATE in column 1 of the following table that
corresponds to the ODBC 3.x SQLSTATE in column 2.

O DB C 2. X SQ L STAT E O DB C 3. X SQ L STAT E C O M M EN T S

01S03 01001

01S04 01001

22003 HY019

22008 22007

22005 22018

24000 07005

37000 42000

70100 HY018

S0001 42S01

S0002 42S02

S0011 42S11

S0012 42S12

S0021 42S21

S0022 42S22

S0023 42S23
O DB C 2. X SQ L STAT E O DB C 3. X SQ L STAT E C O M M EN T S

S1000 HY000

S1001 HY001

S1002 07009 ODBC 2.x SQLSTATE S1002 is mapped


to ODBC 3.x SQLSTATE 07009 if the
underlying function is SQLBindCol,
SQLColAttribute ,
SQLExtendedFetch , SQLFetch ,
SQLFetchScroll, or SQLGetData .

S1003 HY003

S1004 HY004

S1008 HY008

S1009 HY009 Returned for an invalid use of a null


pointer.

S1009 HY024 Returned for an invalid attribute value.

S1009 HY092 Returned for updating or deleting data


by a call to SQLSetPos , or adding,
updating, or deleting data by a call to
SQLBulkOperations , when the
concurrency is read-only.

S1010 HY007 HY010 SQLSTATE S1010 is mapped to


SQLSTATE HY007 when
SQLDescribeCol is called prior to
calling SQLPrepare , SQLExecDirect ,
or a catalog function for the
StatementHandle. Otherwise,
SQLSTATE S1010 is mapped to
SQLSTATE HY010.

S1011 HY011

S1012 HY012

S1090 HY090

S1091 HY091

S1092 HY092

S1093 07009 ODBC 3.x SQLSTATE 07009 is mapped


to ODBC 2.x SQLSTATE S1093 if the
underlying function is
SQLBindParameter or
SQLDescribeParam .

S1096 HY096
O DB C 2. X SQ L STAT E O DB C 3. X SQ L STAT E C O M M EN T S

S1097 HY097

S1098 HY098

S1099 HY099

S1100 HY100

S1101 HY101

S1103 HY103

S1104 HY104

S1105 HY105

S1106 HY106

S1107 HY107

S1108 HY108

S1109 HY109

S1110 HY110

S1111 HY111

S1C00 HYC00

S1T00 HYT00

NOTE
ODBC 3.x SQLSTATE 07008 is mapped to ODBC 2.x SQLSTATE S1000.
Datetime Data Type Changes
4/27/2022 • 2 minutes to read • Edit Online

In ODBC 3.x, the identifiers for date, time, and timestamp SQL data types have changed from SQL_DATE,
SQL_TIME, and SQL_TIMESTAMP (with instances of #define in the header file of 9, 10, and 11) to
SQL_TYPE_DATE, SQL_TYPE_TIME, and SQL_TYPE_TIMESTAMP (with instances of #define in the header file of
91, 92, and 93), respectively. The corresponding C type identifiers have changed from SQL_C_DATE,
SQL_C_TIME, and SQL_C_TIMESTAMP to SQL_C_TYPE_DATE, SQL_C_TYPE_TIME, and SQL_C_TYPE_TIMESTAMP,
respectively.
The column size and decimal digits returned for the SQL datetime data types in ODBC 3.x are the same as the
precision and scale returned for them in ODBC 2.x. These values are different than the values in the
SQL_DESC_PRECISION and SQL_DESC_SCALE descriptor fields. (For more information, see Column Size,
Decimal Digits, Transfer Octet Length, and Display Size.)
These changes affect SQLDescribeCol , SQLDescribeParam , and SQLColAttribute ; SQLBindCol ,
SQLBindParameter , and SQLGetData ; and SQLColumns , SQLGetTypeInfo , SQLProcedureColumns ,
SQLStatistics , and SQLSpecialColumns .
The following table shows how the ODBC 3.x Driver Manager performs mapping of the date, time, and
timestamp C data types entered in the TargetType arguments of SQLBindCol and SQLGetData or in the
ValueType argument of SQLBindParameter .

DATA T Y P E 2. X A P P TO 2. X A P P TO 3. X A P P TO 3. X A P P TO

C O DE EN T ERED 2. X DRIVER 3. X DRIVER 2. X DRIVER 3. X DRIVER

SQL_C_DATE (9) No mapping SQL_C_TYPE_DATE No mapping[1] SQL_C_TYPE_DATE


(91) (91)

SQL_C_TYPE_DATE Error (from DM) Error (from DM) SQL_C_DATE (9) No mapping[2]
(91)

SQL_C_TIME (10) No mapping SQL_C_TYPE_TIME No mapping[1] SQL_C_TYPE_TIME


(92) (92)

SQL_C_TYPE_TIME Error (from DM) Error (from DM) SQL_C_TIME (10) No mapping[2]
(92)

SQL_C_TIMESTAMP No mapping SQL_C_TYPE_TIMEST No mapping[1] SQL_C_TYPE_TIMEST


(11) AMP (93) AMP (93)

SQL_C_TYPE_TIMEST Error (from DM) Error (from DM) SQL_C_TIMESTAMP No mapping[2]


AMP (93) (11)

[1] As a result of this, an ODBC 3.x application working with an ODBC 2.x driver can use the date, time, or
timestamp codes returned in the result sets that are returned by the catalog functions.
[2] As a result of this, an ODBC 3.x application working with an ODBC 3.x driver can use the date, time, or
timestamp codes returned in the result sets that are returned by the catalog functions.
The following table shows how the ODBC 3.x Driver Manager performs mapping of the date, time, and
timestamp SQL data types entered in the ParameterType argument of SQLBindParameter or in the DataType
argument of SQLGetTypeInfo .

DATA T Y P E 2. X A P P TO 2. X A P P TO 3. X A P P TO 3. X A P P TO

C O DE EN T ERED 2. X DRIVER 3. X DRIVER 2. X DRIVER 3. X DRIVER

SQL_DATE (9) No mapping SQL_TYPE_DATE (91) No mapping[1] SQL_TYPE_DATE (91)

SQL_TYPE_DATE (91) Error (from DM) Error (from DM) SQL_DATE (9) No mapping[2]

SQL_TIME (10) No mapping SQL_TYPE_TIME (92) No mapping[1] SQL_TYPE_TIME (92)

SQL_TYPE_TIME (92) Error (from DM) Error (from DM) SQL_TIME (10) No mapping[2]

SQL_TIMESTAMP No mapping SQL_TYPE_TIMESTA No mapping[1] SQL_TYPE_TIMESTA


(11) MP (93) MP (93)

SQL_TYPE_TIMESTA Error (from DM) Error (from DM) SQL_TIMESTAMP No mapping[2]


MP (93) (11)

[1] As a result of this, an ODBC 3.x application working with an ODBC 2.x driver can use the date, time, or
timestamp codes returned in the result sets that are returned by the catalog functions.
[2] As a result of this, an ODBC 3.x application working with an ODBC 3.x driver can use the date, time, or
timestamp codes returned in the result sets that are returned by the catalog functions.
Writing ODBC 3.x Applications
4/27/2022 • 4 minutes to read • Edit Online

When an ODBC 2.x application is upgraded to ODBC 3.x, it should be written such that it works with both ODBC
2.x and 3.x drivers. The application should incorporate conditional code to take full advantage of the ODBC 3.x
features.
The SQL_ATTR_ODBC_VERSION environment attribute should be set to SQL_OV_ODBC2. This will ensure that
the driver behaves like an ODBC 2.x driver with respect to the changes described in the section Behavioral
Changes.
If the application will use any of the features described in the section New Features, conditional code should be
used to determine whether the driver is an ODBC 3.x or ODBC 2.x driver. The application uses
SQLGetDiagField and SQLGetDiagRec to obtain ODBC 3.x SQLSTATEs while doing error processing on these
conditional code fragments. The following points about the new functionality should be considered:
An application affected by the change in rowset size behavior should be careful not to call SQLFetch
when the array size is greater than 1. These applications should replace calls to SQLExtendedFetch with
calls to SQLSetStmtAttr to set the SQL_ATTR_ARRAY_STATUS_PTR statement attribute and to
SQLFetchScroll , so that they have common code that works with both ODBC 3.x and ODBC 2.x drivers.
Because SQLSetStmtAttr with SQL_ATTR_ROW_ARRAY_SIZE will be mapped to SQLSetStmtAttr with
SQL_ROWSET_SIZE for ODBC 2.x drivers, applications can just set SQL_ATTR_ROW_ARRAY_SIZE for their
multirow fetch operations.
Most applications that are upgrading are not actually affected by changes in SQLSTATE codes. For those
applications that are affected, they can do a mechanical search and replace in most cases using the error
conversion table in the "SQLSTATE Mapping" section to convert ODBC 3.x error codes to ODBC 2.x codes.
Since the ODBC 3.x Driver Manager will perform mapping from ODBC 2.x SQLSTATEs to ODBC 3.x
SQLSTATEs, these application writers need only check for the ODBC 3.x SQLSTATEs and not worry about
including ODBC 2.x SQLSTATEs in conditional code.
If an application makes great use of date, time, and timestamp data types, the application can declare
itself to be an ODBC 2.x application and use its existing code instead of using conditioning code.
The upgrade should also include the following steps:
Call SQLSetEnvAttr before allocating a connection to set the SQL_ATTR_ODBC_VERSION environment
attribute to SQL_OV_ODBC2.
Replace all calls to SQL AllocEnv , SQL AllocConnect , or SQL AllocStmt with calls to SQL AllocHandle
with the appropriate HandleType argument of SQL_HANDLE_ENV, SQL_HANDLE_DBC, or
SQL_HANDLE_STMT.
Replace all calls to SQLFreeEnv or SQLFreeConnect with calls to SQLFreeHandle with the
appropriate HandleType argument of SQL_HANDLE_DBC or SQL_HANDLE_STMT.
Replace all calls to SQLSetConnectOption with calls to SQLSetConnectAttr . If setting an attribute
whose value is a string, set the StringLength argument appropriately. Change Attribute argument from
SQL_XXXX to SQL_ATTR_XXXX.
Replace all calls to SQLGetConnectOption with calls to SQLGetConnectAttr . If getting a string or
binary attribute, set BufferLength to the appropriate value and pass in a StringLength argument. Change
Attribute argument from SQL_XXXX to SQL_ATTR_XXXX.
Replace all calls to SQLSetStmtOption with calls to SQLSetStmtAttr . If setting an attribute whose
value is a string, set the StringLength argument appropriately. Change Attribute argument from
SQL_XXXX to SQL_ATTR_XXXX.
Replace all calls to SQLGetStmtOption with calls to SQLGetStmtAttr . If getting a string or binary
attribute, set BufferLength to the appropriate value and pass in a StringLength argument. Change
Attribute argument from SQL_XXXX to SQL_ATTR_XXXX.
Replace all calls to SQLTransact with calls to SQLEndTran . If the rightmost valid handle in the
SQLTransact call is an environment handle, a HandleType argument of SQL_HANDLE_ENV should be
used in the SQLEndTran call with the appropriate Handle argument. If the rightmost valid handle in your
SQLTransact call is a connection handle, a HandleType argument of SQL_HANDLE_DBC should be used
in the SQLEndTran call with the appropriate Handle argument.
Replace all calls to SQLColAttributes with calls to SQLColAttribute . If the FieldIdentifier argument is
either SQL_COLUMN_PRECISION, SQL_COLUMN_SCALE, or SQL_COLUMN_LENGTH, do not change
anything other than the name of the function. If not, change FieldIdentifier from SQL_COLUMN_XXXX to
SQL_DESC_XXXX. If FieldIdentifier is SQL_DESC_CONCISE_TYPE and the data type is a datetime data type,
change to the corresponding ODBC 3.x data type.
If using block cursors, scrollable cursors, or both, the application does the following:
Sets the rowset size, cursor type, and cursor concurrency using SQLSetStmtAttr .
Calls SQLSetStmtAttr to set SQL_ATTR_ROW_STATUS_PTR to point to an array of status records.
Calls SQLSetStmtAttr to set SQL_ATTR_ROWS_FETCHED_PTR to point to an SQLINTEGER.
Performs the required bindings and executes the SQL statement.
Calls SQLFetchScroll in a loop to fetch rows and move around in the result set.
If it wants to fetch by bookmark, the application calls SQLSetStmtAttr to set
SQL_ATTR_FETCH_BOOKMARK_PTR to a variable that will contain the bookmark for the row that it
wants to fetch, and calls SQLFetchScroll with a FetchOrientation argument of
SQL_FETCH_BOOKMARK.
If using arrays of parameters, the application does the following:
Calls SQLSetStmtAttr to set the SQL_ATTR_PARAMSET_SIZE attribute to the size of the parameter
array.
Calls SQLSetStmtAttr to set SQL_ATTR_ROWS_PROCESSED_PTR to point to an internal
UDWORD variable.
Performs prepare, bind, and execute operations as appropriate.
If execution halts for some reason (such as SQL_NEED_DATA), it can find the "current" row of
parameters by inspecting the location pointed to by SQL_ATTR_ROWS_PROCESSED_PTR.
This section contains the following topics.
Mapping Replacement Functions for Backward Compatibility of Applications
Calling SQLCloseCursor
Calling SQLGetDiagField
Calling SQLSetPos
Cursor Library Operations
Mapping the Cursor Attributes1 Information Types
SQL_NO_DATA
Mapping Replacement Functions for Backward
Compatibility of Applications
4/27/2022 • 14 minutes to read • Edit Online

An ODBC 3.x application working through the ODBC 3.x Driver Manager will work against an ODBC 2.x driver as
long as no new features are used. Both duplicated functionality and behavioral changes do, however, affect the
way that the ODBC 3.x application works on an ODBC 2.x driver. When working with an ODBC 2.x driver, the
Driver Manager maps the following ODBC 3.x functions, which have replaced one or more ODBC 2.x functions,
into the corresponding ODBC 2.x functions.

O DB C 3. X F UN C T IO N O DB C 2. X F UN C T IO N

SQL AllocHandle SQL AllocEnv , SQL AllocConnect , or SQL AllocStmt

SQLBulkOperations SQLSetPos

SQLColAttribute SQLColAttributes

SQLEndTran SQLTransact

SQLFetch SQLExtendedFetch

SQLFetchScroll SQLExtendedFetch

SQLFreeHandle SQLFreeEnv , SQLFreeConnect , or SQLFreeStmt

SQLGetConnectAttr SQLGetConnectOption

SQLGetDiagRec SQLError

SQLGetStmtAttr SQLGetStmtOption [1]

SQLSetConnectAttr SQLSetConnectOption

SQLSetStmtAttr SQLSetStmtOption [1]

[1] Other actions might also be taken, depending on the attribute being requested.

SQLAllocHandle
The Driver Manager maps this to SQL AllocEnv , SQL AllocConnect , or SQL AllocStmt , as appropriate. The
following call to SQL AllocHandle :

SQLAllocHandle(HandleType, InputHandle, OutputHandlePtr);

will result in the Driver Manager performing the following (conceptual, no error checking) mapping:
switch (HandleType) {
case SQL_HANDLE_ENV: return (SQLAllocEnv(OutputHandlePtr));
case SQL_HANDLE_DBC: return (SQLAllocConnect (InputHandle, OutputHandlePtr));
case SQL_HANDLE_STMT: return (SQLAllocStmt (InputHandle, OutputHandlePtr));
default: // return SQL_ERROR, SQLSTATE HY092 ("Invalid attribute/option identifier")
}

SQLBulkOperations
The Driver Manager maps this to SQLSetPos . The following call to SQLBulkOperations :

SQLBulkOperations(hstmt, Operation);

will result in the following sequence of steps:


1. If the Operation argument is SQL_ADD, the Driver Manager calls SQLSetPos as follows:

SQLSetPos (hstmt, 0, SQL_ADD, SQL_LOCK_NO_CHANGE);

2. If the Operation argument is not SQL_ADD, the driver returns SQLSTATE HY092 (Invalid attribute/option
identifier).
3. If the application attempts to change the SQL_ATTR_ROW_STATUS_PTR between calls to SQLFetch or
SQLFetchScroll and SQLBulkOperations , the Driver Manager will return SQLSTATE HY011 (Attribute
cannot be set now).
4. If the Operation argument is SQL_ADD, the application must call SQLBindCol to bind the data to be
inserted. It cannot call SQLSetDescField or SQLSetDescRec to bind the data to be inserted.
5. If the Operation argument is SQL_ADD and the number of rows to be inserted is not the same as the
current rowset size, SQLSetStmtAttr must be called to set the SQL_ATTR_ROW_ARRAY_SIZE statement
attribute to the number of rows to be inserted before calling SQLBulkOperations . To revert back to the
previous rowset size, the application must set the SQL_ATTR_ROW_ARRAY_SIZE statement attribute
before SQLFetch , SQLFetchScroll , or SQLSetPos is called.

SQLColAttribute
The Driver Manager maps this to SQLColAttributes . The following call to SQLColAttribute :

SQLColAttribute(StatementHandle, ColumnNumber, FieldIdentifier, CharacterAttributePtr, BufferLength,


StringLengthPtr, NumericAttributePtr);

will result in the following sequence of steps:


1. If FieldIdentifier is one of the following:
SQL_DESC_PRECISION, SQL_DESC_SCALE, SQL_DESC_LENGTH, SQL_DESC_OCTET_LENGTH,
SQL_DESC_UNNAMED, SQL_DESC_BASE_COLUMN_NAME, SQL_DESC_LITERAL_PREFIX,
SQL_DESC_LITERAL_SUFFIX, or SQL_DESC_LOCAL_TYPE_NAME
the Driver Manager returns SQL_ERROR with SQLSTATE HY091 (Invalid descriptor field identifier). No
further rules of this section apply.
2. The Driver Manager maps SQL_COLUMN_COUNT, SQL_COLUMN_NAME, or SQL_COLUMN_NULLABLE
to SQL_DESC_COUNT, SQL_DESC_NAME, or SQL_DESC_NULLABLE, respectively. (An ODBC 2.x driver
need only support SQL_COLUMN_COUNT, SQL_COLUMN_NAME, and SQL_COLUMN_NULLABLE, not
SQL_DESC_COUNT, SQL_DESC_NAME, and SQL_DESC_NULLABLE.) The call to SQLColAttribute is
mapped to:

SQLColAttributes(StatementHandle, ColumnNumber, FieldIdentifier, CharacterAttributePtr, BufferLength,


StringLengthPtr, NumericAttributePtr);

3. All other FieldIdentifier values are passed through to the driver, with SQLColAttribute mapped to
SQLColAttributes as shown previously.
4. If BufferLength is less than 0, the Driver Manager returns SQL_ERROR with SQLSTATE HY090 (Invalid
string or buffer length). No further rules of this section apply.
5. If FieldIdentifier is SQL_DESC_CONCISE_TYPE and the returned type is a concise datetime data type, the
Driver Manager maps the return values for date, time, and timestamp codes.
6. The Driver Manager performs necessary checks to see whether SQLSTATE HY010 (Function sequence
error) needs to be raised. If so, the Driver Manager returns SQL_ERROR and SQLSTATE HY010 (Function
sequence error). No further rules of this section apply.

SQLEndTran
The Driver Manager maps this to SQLTransact . The following call to SQLEndTran :

SQLEndTran(HandleType, Handle, CompletionType);

will result in the Driver Manager performing the following (conceptual, no error checking) mapping:

switch (HandleType) {
case SQL_HANDLE_ENV:return(SQLTransact(Handle, SQL_NULL_HDBC, CompletionType));
case SQL_HANDLE_DBC:return(SQLTransact(SQL_NULL_HENV, Handle, CompletionType);
default: // return SQL_ERROR, SQLSTATE HY092 ("Invalid attribute/option identifier")
}

SQLFetch
The Driver Manager maps this to SQLExtendedFetch with a FetchOrientation argument of SQL_FETCH_NEXT.
The following call to SQLFetch :

SQLFetch (StatementHandle);

will result in the Driver Manager calling SQLExtendedFetch , as follows:

rc = SQLExtendedFetch(StatementHandle, FetchOrientation, FetchOffset, &RowCount, RowStatusArray);

In this call, the pcRow argument is set to the value that the application sets the SQL_ATTR_ROWS_FETCHED_PTR
statement attribute to through a call to SQLSetStmtAttr .

NOTE
When the application calls SQLSetStmtAttr to set SQL_ATTR_ROW_STATUS_PTR to point to a status array, the Driver
Manager caches the pointer. RowStatusArray can be equal to a null pointer.
If the driver does not support SQLExtendedFetch and the cursor library is loaded, the Driver Manager uses the
cursor library's SQLExtendedFetch to map SQLFetch to SQLExtendedFetch . If the driver does not support
SQLExtendedFetch and the cursor library is not loaded, the Driver Manager passes the call to SQLFetch
through to the driver. If the application calls SQLSetStmtAttr to set SQL_ATTR_ROW_STATUS_PTR, the Driver
Manager ensures that the array is populated. If the application calls SQLSetStmtAttr to set
SQL_ATTR_ROWS_FETCHED_PTR, the Driver Manager sets this field to 1.

SQLFetchScroll
The Driver Manager maps this to SQLExtendedFetch . The following call to SQLFetchScroll :

SQLFetchScroll(StatementHandle, FetchOrientation, FetchOffset);

will result in the following sequence of steps:


1. When the application calls SQLSetStmtAttr to set SQL_ATTR_ROW_STATUS_PTR (which sets the
SQL_DESC_ARRAY_STATUS_PTR field in the IRD) to point to a status array, the Driver Manager caches this
pointer. Let this pointer be RowStatusArray; otherwise, let RowStatusArray be equal to a null pointer. If the
RowStatusArray argument is set to a null pointer, the Driver Manager generates a row-status array.
2. If FetchOrientation is not one of SQL_FETCH_NEXT, SQL_FETCH_PRIOR, SQL_FETCH_ABSOLUTE,
SQL_FETCH_RELATIVE, SQL_FETCH_FIRST, SQL_FETCH_LAST, or SQL_FETCH_BOOKMARK, the Driver
Manager returns with SQL_ERROR and SQLSTATE HY106 (Fetch type out of range). No further rules of
this section apply.
3. Case:
If FetchOrientation is equal to SQL_FETCH_BOOKMARK, then:
If SQLSetStmtAttr was called earlier to set the value of SQL_ATTR_FETCH_BOOKMARK_PTR, then
let Bmk be the value obtained by dereferencing the pointer SQL_DESC_FETCH_BOOKMARK_PTR.
Otherwise, return SQL_ERROR with SQLSTATE HY111 (Invalid bookmark value). No further rules
of this section apply.
The Driver Manager now calls SQLExtendedFetch , as follows:

rc = SQLExtendedFetch(StatementHandle, FetchOrientation, Bmk, pcRow, RowStatusArray);

Otherwise, the Driver Manager calls SQLExtendedFetch , as follows:

rc = SQLExtendedFetch(StatementHandle, FetchOrientation, FetchOffset, pcRow, RowStatusArray);

In these calls, the pcRow argument is set to the value that the application sets the
SQL_ATTR_ROWS_FETCHED_PTR statement attribute to through a call to SQLSetStmtAttr .
SQL_ATTR_ROW_ARRAY_SIZE is mapped to SQL_ROWSET_SIZE.
If rc is equal to SQL_SUCCESS or SQL_SUCCESS_WITH_INFO, and if FetchOrientation is equal to
SQL_FETCH_BOOKMARK and FetchOffset is not equal to 0, then the Driver Manager posts a warning,
SQLSTATE 01S10 (Attempt to fetch by a bookmark offset, offset value ignored), and returns
SQL_SUCCESS_WITH_INFO.

SQLFreeHandle
The Driver Manager maps this to SQLFreeEnv , SQLFreeConnect , or SQLFreeStmt as appropriate. The
following call to SQLFreeHandle :

SQLFreeHandle(HandleType, Handle);

will result in the Driver Manager performing the following (conceptual, no error checking) mapping:

switch (HandleType) {
case SQL_HANDLE_ENV: return (SQLFreeEnv(Handle));
case SQL_HANDLE_DBC: return (SQLFreeConnect(Handle));
case SQL_HANDLE_STMT: return (SQLFreeStmt(Handle, SQL_DROP));
default: // return SQL_ERROR, SQLSTATE HY092 ("Invalid attribute/option identifier")
}

SQLGetConnectAttr
The Driver Manager maps this to SQLGetConnectOption . The following call to SQLGetConnectAttr :

SQLGetConnectAttr(ConnectionHandle, Attribute, ValuePtr, BufferLength, StringLengthPtr);

will result in the following sequence of steps:


1. If Attribute is not a driver-defined connection or statement attribute and is not an attribute defined in
ODBC 2.x, the Driver Manager returns SQL_ERROR with SQLSTATE HY092 (Invalid attribute/option
identifier). No further rules in this section apply.
2. If Attribute is equal to SQL_ATTR_AUTO_IPD or SQL_ATTR_METADATA_ID, the Driver Manager returns
SQL_ERROR with SQLSTATE HY092 (Invalid attribute/option identifier).
3. The Driver Manager performs necessary checks to see if SQLSTATE 08003 (Connection not open) or
SQLSTATE HY010 (Function sequence error) needs to be raised. If so, the Driver Manager returns
SQL_ERROR and posts the appropriate error message. No further rules of this section apply.
4. The Driver Manager calls SQLGetConnectOption as follows:

SQLGetConnectOption (ConnectionHandle, Attribute, ValuePtr);

Note that the BufferLength and StringLengthPtr are ignored.

SQLGetData
When an ODBC 3.x application working with an ODBC 2.x driver calls SQLGetData with the ColumnNumber
argument equal to 0, the ODBC 3.x Driver Manager maps this to a call to SQLGetStmtOption with the Option
attribute set to SQL_GET_BOOKMARK.

SQLGetStmtAttr
The Driver Manager maps this to SQLGetStmtOption . The following call to SQLGetStmtAttr :

SQLGetStmtAttr(StatementHandle, Attribute, ValuePtr, BufferLength, StringLengthPtr);

will result in the following sequence of steps:


1. If Attribute is not a driver-defined connection or statement attribute and is not an attribute defined in
ODBC 2.x, the Driver Manager returns SQL_ERROR with SQLSTATE HY092 (Invalid attribute/option
identifier). No further rules in this section apply.
2. If Attribute is one of the following:
SQL_ATTR_APP_ROW_DESC
SQL_ATTR_APP_PARAM_DESC
SQL_ATTR_AUTO_IPD
SQL_ATTR_ROW_BIND_TYPE
SQL_ATTR_IMP_ROW_DESC
SQL_ATTR_IMP_PARAM_DESC
SQL_ATTR_METADATA_ID
SQL_ATTR_PARAM_BIND_TYPE
SQL_ATTR_PREDICATE_PTR
SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR
SQL_ATTR_PARAM_BIND_OFFSET_PTR
SQL_ATTR_ROW_BIND_OFFSET_PTR
SQL_ATTR_ROW_OPERATION_PTR
SQL_ATTR_PARAM_OPERATION_PTR
the Driver Manager returns SQL_ERROR with SQLSTATE HY092 (Invalid attribute/option identifier). No
further rules of this section apply.
3. The Driver Manager performs necessary checks to see whether SQLSTATE HY010 (Function sequence
error) needs to be raised. If so, the Driver Manager returns SQL_ERROR and SQLSTATE HY010 (Function
sequence error). No further rules of this section apply.
4. If Attribute is equal to SQL_ATTR_ROWS_FETCHED_PTR, the Driver Manager returns a pointer to the
internal Driver Manager variable cRow , which it has used or will use in a call to SQLExtendedFetch . No
further rules of this section apply.
5. If Attribute is equal to SQL_DESC_FETCH_BOOKMARK_PTR, the Driver Manager returns the appropriate
pointer that it had cached during a call to SQLSetStmtAttr .
6. If Attribute is equal to SQL_ATTR_ROW_STATUS_PTR, the Driver Manager returns the appropriate pointer
that it had cached during a call to SQLSetStmtAttr .
7. The Driver Manager calls SQLGetStmtOption as follows:

SQLGetStmtOption (hstmt, fOption, pvParam);

where hstmt, fOption, and pvParam will be set to the values of StatementHandle, Attribute, and ValuePtr,
respectively. The BufferLength and StringLengthPtr are ignored.

SQLSetConnectAttr
The Driver Manager maps this to SQLSetConnectOption . The following call to SQLSetConnectAttr :
SQLSetConnectAttr(ConnectionHandle, Attribute, ValuePtr, StringLength);

will result in the following sequence of steps:


1. If Attribute is not a driver-defined connection or statement attribute and is not an attribute defined in
ODBC 2.x, the Driver Manager returns SQL_ERROR with SQLSTATE HY092 (Invalid attribute/option
identifier). No further rules in this section apply.
2. If Attribute is equal to SQL_ATTR_AUTO_IPD, the Driver Manager returns SQL_ERROR with SQLSTATE
HY092 (Invalid attribute/option identifier).
3. The Driver Manager performs necessary checks to see whether SQLSTATE 08003 (Connection not open)
or SQLSTATE HY010 (Function sequence error) need to be raised. If one of these errors needs to be raised,
the Driver Manager returns SQL_ERROR and posts the appropriate error message. No further rules of
this section apply.
4. The Driver Manager calls SQLSetConnectOption as follows:

SQLSetConnectOption (hdbc, fOption, vParam);

where hdbc, fOption, and vParam will be set to the values of ConnectionHandle, Attribute, and ValuePtr,
respectively. StringLengthPtr is ignored.

NOTE
The ability to set statement attributes on the connection level has been deprecated. Statement attributes should never be
set on the connection level by an ODBC 3.x application.

SQLSetStmtAttr
The Driver Manager maps this to SQLSetStmtOption . The following call to SQLSetStmtAttr :

SQLSetStmtAttr(StatementHandle, Attribute, ValuePtr, StringLength);

will result in the following sequence of steps:


1. If Attribute is not a driver-defined connection or statement attribute and is not an attribute defined in
ODBC 2.x, the Driver Manager returns SQL_ERROR with SQLSTATE HY092 (Invalid attribute/option
identifier). No further rules in this section apply.
2. If Attribute is one of the following:
SQL_ATTR_APP_ROW_DESC
SQL_ATTR_APP_PARAM_DESC
SQL_ATTR_AUTO_IPD
SQL_ATTR_ROW_BIND_TYPE
SQL_ATTR_IMP_ROW_DESC
SQL_ATTR_IMP_PARAM_DESC
SQL_ATTR_METADATA_ID
SQL_ATTR_PARAM_BIND_TYPE
SQL_ATTR_PREDICATE_PTR
SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR
SQL_ATTR_PARAM_BIND_OFFSET_PTR
SQL_ATTR_ROW_BIND_OFFSET_PTR
SQL_ATTR_ROW_OPERATION_PTR
SQL_ATTR_PARAM_OPERATION_PTR
the Driver Manager returns SQL_ERROR with SQLSTATE HY092 (Invalid attribute/option identifier). No
further rules of this section apply.
3. The Driver Manager performs the necessary checks to see whether SQLSTATE HY010 (Function sequence
error) need to be raised. If so, the Driver Manager returns SQL_ERROR and SQLSTATE HY010 (Function
sequence error). No further rules of this section apply.
4. If Attribute is equal to SQL_ATTR_PARAMSET_SIZE or SQL_ATTR_PARAMS_PROCESSED_PTR, see the
section "Mappings for Handling Parameter Arrays," later in this topic. No further rules of this section
apply.
5. If Attribute is equal to SQL_ATTR_ROWS_FETCHED_PTR, the Driver Manager caches the pointer value for
later use with SQLFetchScroll .
6. If Attribute is equal to SQL_ATTR_ROW_STATUS_PTR, the Driver Manager caches the pointer value for
later use with SQLFetchScroll or SQLSetPos . No further rules of this section apply.
7. If Attribute is equal to SQL_ATTR_FETCH_BOOKMARK_PTR, the Driver Manager caches ValuePtr and will
use the cached value later in a call to SQLFetchScroll . No further rules of this section apply.
8. The Driver Manager calls SQLSetStmtOption as follows:

SQLSetStmtOption (hstmt, fOption, vParam);

where hstmt, fOption, and vParam will be set to the values of StatementHandle, Attribute, and ValuePtr,
respectively. The StringLength argument is ignored.
If an ODBC 2.x driver supports character-string, driver-specific statement options, an ODBC 3.x
application should call SQLSetStmtOption to set those options.

Mappings for Handling Parameter Arrays


When the application calls:

SQLSetStmtAttr (StatementHandle, SQL_ATTR_PARAMSET_SIZE, Size, StringLength);

the Driver Manager calls:

SQLParamOptions (StatementHandle, Size, &RowCount);

The Driver Manager later returns a pointer to this variable when the application calls SQLGetStmtAttr to
retrieve SQL_ATTR_PARAMS_PROCESSED_PTR. The Driver Manager cannot change this internal variable until
the statement handle is returned to the prepared or allocated state.
An ODBC 3.x application can call SQLGetStmtAttr to obtain the value of SQL_ATTR_PARAMS_PROCESSED_PTR
even though it has not explicitly set the SQL_DESC_ARRAY_SIZE field in the APD. This situation could arise, for
example, if the application has a generic routine that checks for the current "row" of parameters being processed
when SQLExecute returns SQL_NEED_DATA. This routine is invoked whether or not the SQL_DESC_ARRAY_SIZE
is 1 or is greater than 1. To account for this, the Driver Manager will need to define this internal variable whether
or not the application has called SQLSetStmtAttr to set the SQL_DESC_ARRAY_SIZE field in APD. If
SQL_DESC_ARRAY_SIZE has not been set, the Driver Manager has to make sure that this variable contains the
value 1 prior to returning from SQLExecDirect or SQLExecute .

Error Handling
In ODBC 3.x, calling SQLFetch or SQLFetchScroll populates the SQL_DESC_ARRAY_STATUS_PTR in the IRD,
and the SQL_DIAG_ROW_NUMBER field of a given diagnostic record contains the number of the row in the
rowset that this record pertains to. Using this, the application can correlate an error message with a given row
position.
An ODBC 2.x driver will be unable to provide this functionality. However, it will provide error demarcation with
SQLSTATE 01S01 (Error in row). An ODBC 3.x application that is using SQLFetch or SQLFetchScroll while
going against an ODBC 2.x driver needs to be aware of this fact. Note also that such an application will be
unable to call SQLGetDiagField to actually get the SQL_DIAG_ROW_NUMBER field anyway. An ODBC 3.x
application working with an ODBC 2.x driver will be able to call SQLGetDiagField only with a DiagIdentifier
argument of SQL_DIAG_MESSAGE_TEXT, SQL_DIAG_NATIVE, SQL_DIAG_RETURNCODE, or
SQL_DIAG_SQLSTATE. The ODBC 3.x Driver Manager maintains the diagnostic data structure when working with
an ODBC 2.x driver, but the ODBC 2.x driver returns only these four fields.
When an ODBC 2.x application is working with an ODBC 2.x driver, if an operation can cause multiple errors to
be returned by the Driver Manager, different errors may be returned by the ODBC 3.x Driver Manager than by
the ODBC 2.x Driver Manager.

Mappings for Bookmark Operations


The ODBC 3.x Driver Manager performs the following mappings when an ODBC 3.x application working with an
ODBC 2.x driver performs bookmark operations.
SQLBindCol
When an ODBC 3.x application working with an ODBC 2.x driver calls SQLBindCol to bind to column 0 with
fCType equal to SQL_C_VARBOOKMARK, the ODBC 3.x Driver Manager checks to see whether the BufferLength
argument is less than 4 or greater than 4, and if so, returns SQLSTATE HY090 (Invalid string or buffer length). If
the BufferLength argument is equal to 4, the Driver Manager calls SQLBindCol in the driver, after replacing
fCType with SQL_C_BOOKMARK.
SQLColAttribute
When an ODBC 3.x application working with an ODBC 2.x driver calls SQLColAttribute with the
ColumnNumber argument set to 0, the Driver Manager returns the FieldIdentifier values listed in the following
table.

FIEL DIDEN T IFIER VA L UE

SQL_DESC_AUTO_UNIQUE_VALUE SQL_FALSE

SQL_DESC_CASE_SENSITIVE SQL_FALSE

SQL_DESC_CATALOG_NAME "" (empty string)


FIEL DIDEN T IFIER VA L UE

SQL_DESC_CONCISE_TYPE SQL_BINARY

SQL_DESC_COUNT The same value returned by SQLNumResultCols

SQL_DESC_DATETIME_INTERVAL_CODE 0

SQL_DESC_DISPLAY_SIZE 8

SQL_DESC_FIXED_PREC_SCALE SQL_FALSE

SQL_DESC_LABEL "" (empty string)

SQL_DESC_LENGTH 0

SQL_DESC_LITERAL_PREFIX "" (empty string)

SQL_DESC_LITERAL_SUFFIX "" (empty string)

SQL_DESC_LOCAL_TYPE_NAME "" (empty string)

SQL_DESC_NAME "" (empty string)

SQL_DESC_NULLABLE SQL_NO_NULLS

SQL_DESC_OCTET_LENGTH 4

SQL_DESC_PRECISION 4

SQL_DESC_SCALE 0

SQL_DESC_SCHEMA_NAME "" (empty string)

SQL_DESC_SEARCHABLE SQL_PRED_NONE

SQL_DESC_TABLE_NAME "" (empty string)

SQL_DESC_TYPE SQL_BINARY

SQL_DESC_TYPE_NAME "" (empty string)

SQL_DESC_UNNAMED SQL_UNNAMED

SQL_DESC_UNSIGNED SQL_FALSE

SQL_DESC_UPDATEABLE SQL_ATTR_READ_ONLY

SQLDescribeCol
When an ODBC 3.x application working with an ODBC 2.x driver calls SQLDescribeCol with the
ColumnNumber argument set to 0, the Driver Manager returns the values listed in the following table.
B UF F ER VA L UE

ColumnName "" (empty string)

*NameLengthPtr 0

*DataTypePtr SQL_BINARY

*ColumnSizePtr 4

*DecimalDigitsPtr 0

*NullablePtr SQL_NO_NULLS

SQLGetData
When an ODBC 3.x application working with an ODBC 2.x driver makes the following call to SQLGetData to
retrieve a bookmark:

SQLGetData(StatementHandle, 0, SQL_C_VARBOOKMARK, TargetValuePtr, BufferLength, StrLen_or_IndPtr)

the call is mapped to SQLGetStmtOption with an fOption of SQL_GET_BOOKMARK, as follows:

SQLGetStmtOption(hstmt, SQL_GET_BOOKMARK, TargetValuePtr)

where hstmt and pvParam are set to the values in StatementHandle and TargetValuePtr, respectively. The
bookmark is returned in the buffer pointed to by the pvParam (TargetValuePtr) argument. The value in the buffer
pointed to by the StrLen_or_IndPtr argument in the call to SQLGetData is set to 4.
This mapping is necessary to account for the case in which SQLFetch was called prior to the call to
SQLGetData and the ODBC 2.x driver did not support SQLExtendedFetch . In this case, SQLFetch would be
passed through to the ODBC 2.x driver, in which case bookmark retrieval is not supported.
SQLGetData cannot be called multiple times in an ODBC 2.x driver to retrieve a bookmark in parts, so calling
SQLGetData with the BufferLength argument set to a value less than 4 and the ColumnNumber argument set
to 0 will return SQLSTATE HY090 (Invalid string or buffer length). SQLGetData can, however, be called multiple
times to retrieve the same bookmark.
SQLSetStmtAttr
When an ODBC 3.x application working with an ODBC 2.x driver calls SQLSetStmtAttr to set the
SQL_ATTR_USE_BOOKMARKS attribute to SQL_UB_VARIABLE, the Driver Manager sets the attribute to
SQL_UB_ON in the underlying ODBC 2.x driver.
Calling SQLCloseCursor
4/27/2022 • 2 minutes to read • Edit Online

Because SQLCloseCursor is almost the same as SQLFreeStmt with SQL_CLOSE, the Driver Manager does not
map this function. Replacement functions are mapped so that existing ODBC 2.x applications can easily move to
ODBC 3.x by using the new functions. Such a move makes it easier for such applications to begin using new
ODBC 3.x functionality inside of conditional code in a modular fashion. SQLCloseCursor does not represent
any new functionality. An application does not gain any advantage by moving to SQLCloseCursor from
SQLFreeStmt with SQL_CLOSE.
Calling SQLGetDiagField
4/27/2022 • 2 minutes to read • Edit Online

When an ODBC 3.x application calls SQLGetDiagField in an ODBC 2.x driver, the driver will return
SQL_SUCCESS and the appropriate information in *DiagInfoPtr if the DiagIdentifier argument is
SQL_DIAG_CLASS_ORIGIN, SQL_DIAG_CLASS_SUBCLASS_ORIGIN, SQL_DIAG_CONNECTION_NAME,
SQL_DIAG_MESSAGE_TEXT, SQL_DIAG_NATIVE, SQL_DIAG_NUMBER, SQL_DIAG_RETURNCODE,
SQL_DIAG_SERVER_NAME, or SQL_DIAG_SQLSTATE. All other diagnostic fields will return SQL_ERROR.
Calling SQLSetPos
4/27/2022 • 2 minutes to read • Edit Online

In ODBC 2.x, the pointer to the row status array was an argument to SQLExtendedFetch . The row status array
was later updated by a call to SQLSetPos . Some drivers have relied on the fact that this array does not change
between SQLExtendedFetch and SQLSetPos . In ODBC 3.x, the pointer to the status array is a descriptor field
and therefore the application can easily change it to point to a different array. This can be a problem when an
ODBC 3.x application is working with an ODBC 2.x driver but is calling SQLSetStmtAttr to set the array status
pointer and is calling SQLFetchScroll to fetch data. The Driver Manager maps it as a sequence of calls to
SQLExtendedFetch . In the following code, an error would normally be raised when the Driver Manager maps
the second SQLSetStmtAttr call when working with an ODBC 2.x driver:

SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, rgfRowStatus, 0);


SQLFetchScroll(hstmt, fFetchType, iRow);
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, rgfRowStat1, 0);
SQLSetPos(hstmt, iRow, fOption, fLock);

The error would be raised if there were no way to change the row status pointer in ODBC 2.x between calls to
SQLExtendedFetch . Instead, the Driver Manager performs the following steps when working with an ODBC 2.x
driver:
1. Initializes an internal Driver Manager flag fSetPosError to TRUE.
2. When an application calls SQLFetchScroll , the Driver Manager sets fSetPosError to FALSE.
3. When the application calls SQLSetStmtAttr to set SQL_ATTR_ROW_STATUS_PTR, the Driver Manager
sets fSetPosError equal toTRUE.
4. When the application calls SQLSetPos , with fSetPosError equal to TRUE, the Driver Manager raises
SQL_ERROR with SQLSTATE HY011 (Attribute cannot be set now) to indicate that the application
attempted to call SQLSetPos after changing the row status pointer but prior to calling SQLFetchScroll .
Cursor Library Operations
4/27/2022 • 2 minutes to read • Edit Online

IMPORTANT
This feature will be removed in a future version of Windows. Avoid using this feature in new development work and plan
to modify applications that currently use this feature. Microsoft recommends using the driver's cursor functionality.

If an application working with an ODBC 2.x driver makes calls to the ODBC 3.x cursor library, the application
might be able to use ODBC 3.x features that are not supported by the ODBC 2.x driver. An application writer
should be careful how these features are used, however. Use of the ODBC 3.x cursor library does not make an
ODBC 2.x driver into an ODBC 3.x driver.
Mapping the Cursor Attributes1 Information Types
4/27/2022 • 2 minutes to read • Edit Online

When an ODBC 3.x application calls SQLGetInfo in an ODBC 2*.x* driver with the
SQL_XXXX_CURSOR_ATTRIBUTES1 information type (for dynamic, forward-only, keyset-driver, or static cursors),
the setting of the bits returned by Driver Manager depends on what the ODBC 2.x driver returns for the
corresponding ODBC 2.x information types. The bits are set as shown in the following table.

B IT IN O DB C 2. X IN F O RM AT IO N

SQ L _XXXX_C URSO R_AT T RIB UT ES1 C URSO R T Y P E TYPE

SQL_CA1_NEXT All SQL_FETCH_DIRECTION

SQL_CA1_ABSOLUTE Dynamic, keyset-driver, static SQL_FETCH_DIRECTION


SQL_CA1_RELATIVE
SQL_CA1_BOOKMARK

SQL_CA1_LOCK_NO_CHANGE Dynamic, keyset-driver, static SQL_LOCK_TYPES


SQL_CA1_LOCK_UNLOCK
SQL_CA1_LOCK_EXCLUSIVE

SQL_CA1_POSITIONED_UPDATE All SQL_POSITIONED_STATEMENTS


SQL_CA1_POSITIONED_DELETE
SQL_CA1_SELECT_FOR_UPDATE

SQL_CA1_POS_POSITION Dynamic, keyset-driver, static SQL_POS_OPERATIONS


SQL_CA1_POS_DELETE
SQL_CA1_POS_REFRESH
SQL_CA1_POS_BULK_ADD
SQL_NO_DATA
4/27/2022 • 2 minutes to read • Edit Online

When an ODBC 3.x application calls SQLExecDirect , SQLExecute , or SQLParamData in an ODBC 2.x driver to
execute a searched update or delete statement that does not affect any rows at the data source, the driver
should return SQL_SUCCESS, not SQL_NO_DATA. When an ODBC 2.x or ODBC 3.x application working with an
ODBC 3.x driver calls SQLExecDirect , SQLExecute , or SQLParamData with the same result, the ODBC 3.x
driver should return SQL_NO_DATA.
Writing ODBC 3.x Drivers
4/27/2022 • 2 minutes to read • Edit Online

The following table shows function support in an ODBC 3.x driver and an ODBC application, and the mapping
performed by the Driver Manager when the functions are called against an ODBC 3.x driver.

SUP P O RT ED SUP P O RT ED M A P P ED/ SUP P O RT ED

BY AN BY AN B Y T H E O DB C 3. X

O DB C 3. X O DB C 3. X DRIVER M A N A GER TO

F UN C T IO N DRIVER? A P P L IC AT IO N ? A N O DB C 3. X DRIVER?

SQL AllocConnect No No[1] Yes

SQL AllocEnv No No[1] Yes

SQL AllocHandle Yes Yes No

SQL AllocStmt No No[1] Yes

SQLBindCol Yes Yes No

SQLBindParam No Yes[2] Yes

SQLBindParameter Yes Yes No

SQLBrowseConnect Yes Yes No

SQLBulkOperations Yes Yes No

SQLCancel Yes Yes No

SQLCloseCursor Yes Yes No

SQLColAttribute Yes Yes No

SQLColAttributes No[3] No Yes

SQLColumnPrivileges Yes Yes No

SQLColumns Yes Yes No

SQLConnect Yes Yes No

SQLCopyDesc Yes Yes Yes[4]

SQLDataSources No Yes Yes

SQLDescribeCol Yes Yes No


SUP P O RT ED SUP P O RT ED M A P P ED/ SUP P O RT ED

BY AN BY AN B Y T H E O DB C 3. X

O DB C 3. X O DB C 3. X DRIVER M A N A GER TO

F UN C T IO N DRIVER? A P P L IC AT IO N ? A N O DB C 3. X DRIVER?

SQLDescribeParam Yes Yes No

SQLDisconnect Yes Yes No

SQLDriverConnect Yes Yes No

SQLDrivers No Yes Yes

SQLEndTran Yes Yes No

SQLError No No[1] Yes

SQLExecDirect Yes Yes No

SQLExecute Yes Yes No

SQLExtendedFetch Yes No No

SQLFetch Yes Yes No

SQLFetchScroll Yes Yes No

SQLForeignKeys Yes Yes No

SQLFreeConnect No Yes[1] Yes

SQLFreeEnv No Yes[1] Yes

SQLFreeHandle Yes Yes No

SQLFreeStmt Yes Yes No

SQLGetConnectAttr Yes Yes No

SQLGetConnectOption No[5] No[1] Yes

SQLGetCursorName Yes Yes No

SQLGetData Yes Yes No

SQLGetDescField Yes Yes No

SQLGetDescRec Yes Yes No

SQLGetDiagField Yes Yes No


SUP P O RT ED SUP P O RT ED M A P P ED/ SUP P O RT ED

BY AN BY AN B Y T H E O DB C 3. X

O DB C 3. X O DB C 3. X DRIVER M A N A GER TO

F UN C T IO N DRIVER? A P P L IC AT IO N ? A N O DB C 3. X DRIVER?

SQLGetDiagRec Yes Yes No

SQLGetEnvAttr Yes Yes No

SQLGetFunctions No[6] Yes Yes

SQLGetInfo Yes Yes No

SQLGetStmtAttr Yes Yes No

SQLGetStmtOption No[5] No[1] Yes

SQLGetTypeInfo Yes Yes No

SQLMoreResults Yes Yes No

SQLNativeSql Yes Yes No

SQLNumParams Yes Yes No

SQLNumResultCols Yes Yes No

SQLParamData Yes Yes No

SQLParamOptions No No Yes

SQLPrepare Yes Yes No

SQLPrimar yKeys Yes Yes No

SQLProcedureColumns Yes Yes No

SQLProcedures Yes Yes No

SQLPutData Yes Yes No

SQLRowCount Yes Yes No

SQLSetConnectAttr Yes Yes No

SQLSetConnectOption No[5] No[1] Yes

SQLSetCursorName Yes Yes No

SQLSetDescField Yes Yes No


SUP P O RT ED SUP P O RT ED M A P P ED/ SUP P O RT ED

BY AN BY AN B Y T H E O DB C 3. X

O DB C 3. X O DB C 3. X DRIVER M A N A GER TO

F UN C T IO N DRIVER? A P P L IC AT IO N ? A N O DB C 3. X DRIVER?

SQLSetDescRec Yes Yes No

SQLSetEnvAttr Yes Yes No

SQLSetPos Yes Yes No

SQLSetParam No No Yes

SQLSetScrollOption Yes Yes No

SQLSetStmtAttr Yes Yes No

SQLSetStmtOption No[5] No[1] Yes

SQLSpecialColumns Yes Yes No

SQLStatistics Yes Yes No

SQLTablePrivileges Yes Yes No

SQLTables Yes Yes No

SQLTransact No No[1] Yes

[1] This function is deprecated in ODBC 3.x. ODBC 3.x applications should not use this function. However, an
Open Group or ISO CLI-compliant application can call this function.
[2] ODBC 3.x applications should use SQLBindParameter instead of SQLBindParam . However, an Open
Group or ISO CLI-compliant application can call this function.
[3] Driver writers should note that the ODBC 2.x column attributes SQL_COLUMN_PRECISION,
SQL_COLUMN_SCALE, and SQL_COLUMN_LENGTH must be supported with SQLColAttribute .
[4] SQLCopyDesc is partially implemented by the Driver Manager when a descriptor is being copied across
connections that belong to different drivers. Drivers are required to support SQLCopyDesc across two of their
own connections. Functions such as SQLDrivers , which are implemented solely by the Driver Manager, do not
show up on this list.
[5] Under certain circumstances, drivers may need to support this function. For more information, see this
function's reference page.
[6] The driver can choose to support SQLGetFunctions if the set of functions that the driver supports varies
from connection to connection.
ODBC in Windows
4/27/2022 • 2 minutes to read • Edit Online

The following items apply only to ODBC running in Microsoft® Windows NT®/Windows 2000 and Microsoft
Windows® 95/98 operating systems.
This section contains the following topics.
Standards-Compliant Applications and Drivers
Header Files
Passing CString Objects to ODBC Functions
Creating and Terminating Threads
Standards-Compliant Applications and Drivers
4/27/2022 • 2 minutes to read • Edit Online

A standards-compliant application or driver is one that conforms to the Open Group CAE Specification "Data
Management: SQL Call-Level Interface (CLI)," and the ISO/IEC 9075-3:1995 (E) Call-Level Interface (SQL/CLI).
ODBC 3.x guarantees the following features:
An application written to the Open Group and ISO CLI specifications will work with an ODBC 3.x driver or
a standards-compliant driver when it is compiled with the ODBC 3.x header files and linked with ODBC
3.x libraries, and when it gains access to the driver through the ODBC 3.x Driver Manager.
A driver written to the Open Group and ISO CLI specifications will work with an ODBC 3.x application or a
standards-compliant application when it is compiled with the ODBC 3.x header files and linked with
ODBC 3.x libraries, and when the application gains access to the driver through the ODBC 3.x Driver
Manager.
Standards-compliant applications and drivers are compiled with the ODBC_STD compile flag.
Standards-compliant applications exhibit the following behavior:
If a standards-compliant application calls SQL AllocEnv (which can occur because SQL AllocEnv is a
valid function in the Open Group and ISO CLI), the call is mapped to SQL AllocHandleStd at compile
time. As a result, at run time, the application calls SQL AllocHandleStd . During the course of processing
this call, the Driver Manager sets the SQL_ATTR_ODBC_VERSION environment attribute to
SQL_OV_ODBC3. A call to SQL AllocHandleStd is equivalent to a call to SQL AllocHandle with a
HandleType of SQL_HANDLE_ENV and a call to SQLSetEnvAttr to set SQL_ATTR_ODBC_VERSION to
SQL_OV_ODBC3.
If a standards-compliant application calls SQLBindParam (which can occur because SQLBindParam is
a valid function in the Open Group and ISO CLI), the ODBC 3.x Driver Manager maps the call to the
equivalent call in SQLBindParameter . (See SQLBindParam Mapping in Appendix G: Driver Guidelines
for Backward Compatibility.)
To align with the ISO CLI, the ODBC 3.x header files contain aliases for information types used in calls to
SQLGetInfo . A standards-compliant application can use these aliases instead of the ODBC 3.x
information types. For more information, see the next topic, Header Files.
A standards-compliant application must verify that all features it supports are supported in the driver it
will work with. Setting the SQL_ATTR_CURSOR_SCROLLABLE statement attribute to SQL_SCROLLABLE
and setting the SQL_ATTR_CURSOR_SENSITIVITY statement attribute to SQL_INSENSITIVE or
SQL_SENSITIVE are capabilities that are available as optional features in the standards but are not
included in the ODBC 3.x Core level and therefore might not be supported by all ODBC 3.x drivers. If a
standards-compliant application uses these capabilities, it should verify that the driver that it will work
with supports them.
Header Files
4/27/2022 • 2 minutes to read • Edit Online

The Sql.h header file contains prototypes for the functions and features in the Core ODBC Interface conformance
level. The Sqlext.h header file contains prototypes for the functions and features in the Level 1 and Level 2 API
conformance levels. The Sqltypes.h header file contains type definitions and indicators for the SQL data types.
The header files all contain a #define , ODBCVER, that an application or driver can set to be compiled for
different versions of ODBC.
To align with the ISO CLI and Open Group CLI, the header files contain aliases for the information types used in
calls to SQLGetInfo . In the following table, the column "ODBC name" indicates the ODBC name for the
information type in ODBC API Reference. The column "Alias in header file" indicates the name that is used in the
ISO CLI and the Open Group CLI. The actual numeric value of these manifest names is the same in both ODBC
and the standard CLIs. These aliases enable a standards-compliant application or driver to compile with the
ODBC 3.x header files.
These aliases include expansions of abbreviations in the ODBC names so that the names are more
understandable. "MAX" is expanded to "MAXIMUM", "LEN" to "LENGTH", "MULT" to "MULTIPLE", "OJ" to
"OUTER_JOIN", and "TXN" to "TRANSACTION."

O DB C N A M E A L IA S IN H EA DER F IL E

SQL_MAX_CATALOG_NAME_LEN SQL_MAXIMUM_CATALOG_NAME_LENGTH

SQL_MAX_COLUMN_NAME_LEN SQL_MAXIMUM_COLUMN_NAME_LENGTH

SQL_MAX_COLUMNS_IN_GROUP_BY SQL_MAXIMUM_COLUMNS_IN_GROUP_BY

SQL_MAX_COLUMNS_IN_ORDER_BY SQL_MAXIMUM_COLUMNS_IN_ORDER_BY

SQL_MAX_COLUMNS_IN_SELECT SQL_MAXIMUM_COLUMNS_IN_SELECT

SQL_MAX_COLUMNS_IN_TABLE SQL_MAXIMUM_COLUMNS_IN_TABLE

SQL_MAX_CONCURRENT_ACTIVITIES SQL_MAXIMUM_CONCURRENT_ACTIVITIES

SQL_MAX_CURSOR_NAME_LEN SQL_MAXIMUM_CURSOR_NAME_LENGTH

SQL_MAX_DRIVER_CONNECTIONS SQL_MAXIMUM_DRIVER_CONNECTIONS

SQL_MAX_IDENTIFIER_LEN SQL_MAXIMUM_IDENTIFIER_LENGTH

SQL_MAX_SCHEMA_NAME_LEN SQL_MAXIMUM_SCHEMA_NAME_LENGTH

SQL_MAX_STATEMENT_LEN SQL_MAXIMUM_STATEMENT_LENGTH

SQL_MAX_TABLE_NAME_LEN SQL_MAXIMUM_TABLE_NAME_LENGTH

SQL_MAX_TABLES_IN_SELECT SQL_MAXIMUM_TABLES_IN_SELECT
O DB C N A M E A L IA S IN H EA DER F IL E

SQL_MAX_USER_NAME_LEN SQL_MAXIMUM_USER_NAME_LENGTH

SQL_MULT_RESULT_SETS SQL_MULTIPLE_RESULT_SETS

SQL_OJ_CAPABILITIES SQL_OUTER_JOIN_CAPABILITIES

SQL_TXN_CAPABLE SQL_TRANSACTION_CAPABLE

SQL_TXN_ISOLATION_OPTION SQL_TRANSACTION_ISOLATION_OPTION
CString Class
4/27/2022 • 2 minutes to read • Edit Online

Because objects of the CString class in Microsoft® Visual C++® are signed and string arguments in ODBC
functions are unsigned, applications that pass CString objects to ODBC functions without casting them will
receive compiler warnings.
Creating and Terminating Threads
4/27/2022 • 2 minutes to read • Edit Online

Multithread applications that use ODBC should call the Microsoft® Visual C++® Run-Time Library functions
_beginthread and _endthread (or _beginthreadex and _endthreadex ) to create and terminate threads that
call the ODBC Driver Manager. If applications call the Microsoft Windows NT® functions CreateThread and
EndThread instead, memory leaks will occur because the Driver Manager and some ODBC drivers call C run-
time functions that will not work on a thread created by calling CreateThread . For more information, see the
Microsoft Windows® documentation.
Installing and Configuring the ODBC Software
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

This section contains the following topics.


Installing ODBC Components
Configuring Data Sources
Installation and Configuration Components Reference
ODBC Header Files
Registry Entries for ODBC Components
Registry Entries for Data Sources
Installing ODBC Components
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

This section describes how ODBC components are installed and removed. Because driver developers always
install an ODBC component (their driver), they need to read this section. Application developers need to read
this section only if they will ship ODBC components with their applications. ODBC components include the
Driver Manager, drivers, translators, the installer DLL, the cursor library, and any related files. For the purposes
of this section, ODBC applications are not considered to be ODBC components.

NOTE
This section is specific to Microsoft Windows platforms. How ODBC components are installed on other platforms is
platform-specific.

ODBC components are installed and removed on a component-by-component basis, not a file-by-file basis. For
example, if a translator consists of the translator itself and a number of data files, these files are installed and
removed as a group; they must not be installed and removed on a file-by-file basis. The reason for this is to
make sure that only complete components exist on the system.
For purposes of installing and removing components, the following are defined to be ODBC components:
Core components. The Driver Manager, cursor library, installer DLL, and any other related files make up
the core components and must be installed and removed as a group.
Drivers. Each driver is a separate component.
Translators. Each translator is a separate component.
With the support of Unicode in ODBC 3.5 and later, some consideration must be given to using OLE DB
components with ODBC. The 1.1 version of the OLE DB Provider for ODBC was written to specific Unicode
specifications within ODBC 3.0. Because these specifications changed in ODBC 3.5, it is necessary to have
version 1.5 or later of the provider when using ODBC 3.5 and later. This section contains the following topics.
Installation Components
Usage Counting
Installation Components
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

The installation process starts when the user runs the setup program. The setup program works in conjunction
with the installer DLL and a driver setup DLL for each driver. Both the setup program and the installer DLL use
the arguments in the SQLInstallDriverEx and SQLInstallTranslatorEx functions to determine which files to
copy or delete for each component. The following illustration shows the relationship between these installation
components.

IMPORTANT
The Odbc.inf file that was used in ODBC 2.x to describe the files required by each ODBC component is not used in ODBC
3.x. Drivers that ship ODBC 3.x components do not need to create an Odbc.inf file. The removal of SQLInstallDriver and
SQLInstallODBC , and the deprecation of SQLInstallTranslator , have rendered Odbc.inf unnecessary. The driver
information that used to be in the Driver Keyword sections of Odbc.inf is now provided in the lpszDriver argument in
SQLInstallDriverEx. The translator information that used to be in the [ODBC Translator] and Translator Specification
sections of Odbc.inf is now provided in the lpszTranslator argument of SQLInstallTranslatorEx. These changes allow the
ODBC Installer to be more portable across platforms.

For more information about these components, see the following topics at the end of this section.
Setup Program
Installer DLL
Driver Setup DLL
Usage Counting
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

Two types of usage counts are maintained in the registry for each component: a component usage count and
one or more optional file usage counts. The component usage count helps the installer DLL maintain registry
entries. It is stored in the UsageCount value under the ODBC Core, driver, and translator subkeys. For the format
of the UsageCount value and more information about these subkeys, see Registry Entries for ODBC
Components.
When a component is first installed, the installer DLL creates a subkey for it and sets the data for the
UsageCount value in that subkey to 1. When the component is installed again, the installer DLL increments the
usage count. When the component is removed, the installer DLL decrements the usage count. If the usage count
falls to 0, the installer DLL removes the subkey for the component.
Cau t i on

An application should not physically remove Driver Manager files when the component usage count and the file
usage count reach zero.
File usage counts help determine when a file must actually be copied or deleted as opposed to incrementing or
decrementing the usage count. This is important because ODBC components, and therefore the files in ODBC
components, are shared and can be installed or removed by a variety of applications. The application can delete
driver and translator files if the component usage count and the file usage count reach zero. Driver Manager
files should not, however, be deleted when both the component usage count and the file usage count have
reached zero, because these files can be used by other applications that have not incremented the file usage
count.

NOTE
File usage counts are optional in Microsoft® WindowsNT®/Windows2000.

File usage counts are maintained by the setup program after it calls SQLInstallDriverManager ,
SQLInstallDriverEx , SQLInstallTranslatorEx , SQLRemoveDriverManager , SQLRemoveDriver , or
SQLRemoveTranslator .
When a component is first installed, the setup program or installer DLL creates a value under the following key
for each file in that component that is not already on the system:
NOTE
HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
Windows
CurrentVersion
SharedDlls

It sets the data for those values to 1 and copies the file to the system. When the component is installed again,
the setup program or installer DLL increments the usage counts. When the component is removed, the setup
program or installer DLL decrements the usage counts. If any usage count falls to 0, the setup program or
installer DLL removes the value for the file and, if the component is a driver or a translator, deletes the file.
Driver Manager files should not be deleted.
The format of the file usage count value is shown in the following table.

NAME DATA T Y P E DATA

full-path REG_DWORD count

For example, suppose a driver for Informix uses the Infrmx32.dll and Infrmx32.hlp files, and suppose that this
driver has been installed twice. The values under the SharedDlls subkey for the Informix driver would be as
follows:

C:\WINDOWS\SYSTEM32\INFRMX32.DLL : REG_DWORD : 0x2


C:\WINDOWS\SYSTEM32\INFRMX32.HLP : REG_DWORD : 0x2
Configuring Data Sources
4/27/2022 • 2 minutes to read • Edit Online

Information about data sources is stored in the system registry. Users modify data source information through
an administration program. This can be the ODBC Administrator, the ODBC Control Panel device, or an
administration program written by an application or driver developer.
You can use PowerShell commands to modify data sources. For more information about these PowerShell
commands, see Windows Data Access Components PowerShell Commands.

NOTE
This section is specific to Microsoft Windows® platforms. How data sources are configured on other platforms is
platform-specific.

This section contains the following topic:


Configuration Components
Configuration Components
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

Data sources are configured by the installer DLL, which in turn calls driver setup DLLs and translator setup DLLs
as they are needed. The installer DLL is either invoked directly from Control Panel or loaded and called by
another program, known as the administration program. The following illustration shows the relationship
between the configuration components.

For more information about these components, see the following topics at the end of this section.
Setup Program
Installer DLL
Driver Setup DLL

See Also
Installation Components
Installation and Configuration Components
Reference
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

The following sections provide information about the components used to install and configure ODBC.
Administration Program
Driver Setup DLL
Installer DLL
Setup Program
Translator Setup DLLs
Administration Program
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

An administration program, the ODBC Administrator, is included with the Windows SDK/MDAC SDK. This
program and can be redistributed by users of the SDK. In addition, developers can write their own
administration programs. Generally, developers write their own administration programs only if they want to
retain complete control over data source configuration, or if they are configuring data sources directly from an
application that is acting as an administration program. For example, a spreadsheet program might allow users
to add and then use data sources at run time.
The administration program first loads the installer DLL. It then calls functions in the installer DLL to perform the
following tasks:
Add, modify, or delete data sources interactively. The administration program can call
SQLManageDataSources , SQLCreateDataSource , or SQLConfigDataSource .
SQLManageDataSources displays a dialog box with which the user can add, modify, or delete data
sources and specify tracing options; this function is called when the installer DLL is invoked directly from
the Control Panel. SQLCreateDataSource displays a dialog box with which the user can only add data
sources. SQLConfigDataSource passes the call directly to the driver setup DLL.
In all cases, the installer DLL calls ConfigDSN in the driver setup DLL to actually add, modify, or delete
the data source. The driver setup DLL might prompt the user for additional information.
Add, modify, or delete data sources silently. The administration program calls
SQLConfigDataSource in the installer DLL and passes it a null window handle, the name of a data
source to add, modify, or delete, and a list of values for the registry. The installer DLL calls ConfigDSN in
the driver setup DLL to actually add, modify, or delete the data source.
Add, modify, or delete a default data source. The default data source is the same as any other data
source, except that its name is Default. It is added, modified, or deleted in the same fashion as any other
data source.
Setup Program
4/27/2022 • 2 minutes to read • Edit Online

NOTE: Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows
operation system . You should only explicitly install ODBC on earlier versions of Windows.

The user runs the setup program to start the setup process. The setup program is written by the application or
driver developer. In addition to installing ODBC components, it can install other software. For example,
application developers might use the same setup program both to install ODBC components and to install their
applications.
Developers can write the setup program from scratch, using the Microsoft® Windows® SDK setup utilities or
setup software from other vendors. This gives those developers complete control over the setup program's look
and feel. The setup program can be written to install additional software, such as an ODBC application. For more
information on the Windows SDK setup utilities, see the Windows SDK documentation.
How much of the installation is actually done by the setup program depends on what functions it calls in the
installer DLL. The installer DLL contains functions to install individual ODBC components. The setup program
simply calls SQLInstallDriverManager , SQLInstallDriverEx , or SQLInstallTranslatorEx in the installer DLL
to retrieve the path of the directory in which the component is to be installed and to add information about the
component to the registry. These functions do not actually copy files; the setup program does this using the
information in the arguments of these functions.
The installer DLL also contains functions to remove ODBC components. The setup program calls
SQLRemoveDriverManager , SQLRemoveDriver , or SQLRemoveTranslator in the installer DLL to
decrement a component's usage count in the registry and, if the component's new usage count falls to 0,
remove all information about the component from the registry. These functions do not actually remove the files
for the component; the setup program does this if the new usage count falls to 0.
Installer DLL
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

The installer DLL contains functions to install and remove ODBC components, maintain registry information
about those components, and maintain registry information about data sources. It is written by Microsoft and
can be redistributed. For a complete description of the functions in the installer DLL, see Installer DLL API
Reference.

See Also
Registry Entries for ODBC Components
Registry Entries for Data Sources
Driver Setup DLL
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

The driver setup DLL contains the ConfigDriver and ConfigDSN functions. ConfigDriver performs driver-
specific installation tasks, such as entering driver-specific information into the registry. ConfigDSN maintains
driver-specific information about data sources in the registry. For a complete description of these functions, see
Setup DLL API Reference.
ConfigDSN calls the following functions in the installer DLL to maintain data source information in the registry:
SQLWriteDSNToIni . Add a data source.
SQLRemoveDSNFromIni . Delete a data source.
SQLWritePrivateProfileString . Write a driver-specific value under a data source specification subkey.
SQLGetPrivateProfileString . Read a driver-specific value from a data source specification subkey.
SQLGetTranslator . Prompt the user for a translator name and option. This function calls
ConfigTranslator in the translator setup DLL.
The driver setup DLL is written by the driver developer. It can be part of the driver DLL or a separate DLL.
Translator Setup DLLs
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

The translator setup DLL contains the ConfigTranslator function, which returns the default option for a
translator. If necessary, it prompts the user for this information. For a complete description of this function, see
Setup DLL API Reference.
The translator setup DLL is written by the translator developer. It can be part of the translator DLL or a separate
DLL.
ODBC Header Files
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Redistribution of ODBC header files is not required. None are considered "Core".

Header Files
Odbcinst.h
Sql.h
Sqlext.h
Sqltypes.h
Sqlucode.h
Msdasql.h
Msdadc.h
Sqlspi.h (used for driver development, see ODBC Service Provider Interface (SPI) Reference for more
information) available beginning in the Windows 8 SDK.
Registry Entries for ODBC Components
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

The installer DLL maintains information in the registry about each installed ODBC component. On computers
running Microsoft Windows NT and Microsoft Windows 95/98, this information is stored in subkeys under the
following key in the registry:

HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\Odbcinst.ini

Because Odbcinst.ini is a subkey of the HKEY_LOCAL_MACHINE tree, the information about ODBC components
is available to all users of the machine.
This section contains the following topics.
ODBC Core Subkey
ODBC Drivers Subkey
Driver Specification Subkeys
Default Driver Subkey
ODBC Translators Subkey
Translator Specification Subkeys
ODBC Core Subkey
4/27/2022 • 2 minutes to read • Edit Online

The value under the ODBC Core subkey gives the usage count for the core components (Driver Manager, cursor
library, installer DLL, and so on). The format of this value is shown in the following table.

NAME DATA T Y P E DATA

UsageCount REG_DWORD count

For example, suppose the ODBC Core components have been installed by the setup programs for three different
applications and two different drivers. The value under the ODBC Core subkey would be:

UsageCount : REG_DWORD : 0x5


ODBC Drivers Subkey
4/27/2022 • 2 minutes to read • Edit Online

The values under the ODBC Drivers subkey list the installed drivers. The format of these values is shown in the
following table.

NAME DATA T Y P E DATA

driver-description REG_SZ Installed

The driver-description name is defined by the driver developer. It is usually the name of the DBMS associated
with the driver.
For example, suppose drivers have been installed for formatted text files and SQL Server. The values under the
ODBC Drivers subkey might be:

Text : REG_SZ : Installed


SQL Server : REG_SZ : Installed
Driver Specification Subkeys
4/27/2022 • 4 minutes to read • Edit Online

Each driver listed in the ODBC Drivers subkey has a subkey of its own. This subkey has the same name as the
corresponding value under the ODBC Drivers subkey. The values under this subkey list the full paths of the
driver and driver setup DLLs, the values of the driver keywords returned by SQLDrivers , and the usage count.
The formats of the values are as shown in the following table.

NAME DATA T Y P E DATA

APILevel REG_SZ 0 |1 |2

ConnectFunctions REG_SZ {Y |N}{Y |N}{Y |N}

CreateDSN REG_SZ driver-description

Driver REG_SZ driver-DLL-path

DriverODBCVer REG_SZ nn.nn

FileExtns REG_SZ *. file-extension1[,*. file-extension2]...

FileUsage REG_SZ 0 |1 |2

Setup REG_SZ setup-DLL-path

SQLLevel REG_SZ 0 |1 |2

UsageCount REG_DWORD count

The use of each keyword is shown in the following table.

K EY W O RD USA GE

APILevel A number indicating the ODBC interface conformance level


supported by the driver:

0 = None

1 = Level 1 supported

2 = Level 2 supported

This must be the same as the value returned for the


SQL_ODBC_INTERFACE_CONFORMANCE option in
SQLGetInfo .
K EY W O RD USA GE

CreateDSN The name of one or more data sources to be created when


the driver is installed. The system information must include
one data source specification section for each data source
listed with the CreateDSN keyword. These sections should
not include the Driver keyword, because this is specified in
the driver specification section, but must include enough
information for the ConfigDSN function in the driver setup
DLL to create a data source specification without displaying
any dialog boxes. For the format of a data source
specification section, see Data Source Specification Subkeys.

ConnectFunctions A three-character string indicating whether the driver


supports SQLConnect , SQLDriverConnect , and
SQLBrowseConnect . If the driver supports SQLConnect ,
the first character is "Y"; otherwise, it is "N". If the driver
supports SQLDriverConnect , the second character is "Y";
otherwise, it is "N". If the driver supports
SQLBrowseConnect , the third character is "Y"; otherwise,
it is "N". For example, if a driver supports SQLConnect and
SQLDriverConnect but not SQLBrowseConnect , the
three-character string is "YYN".

DriverODBCVer A character string with the version of ODBC that the driver
supports. The version is of the form nn.nn, where the first
two digits are the major version and the next two digits are
the minor version. For the version of ODBC described in this
manual, the driver must return "03.00".

This must be the same as the value returned for the


SQL_DRIVER_ODBC_VER option in SQLGetInfo .

FileExtns For file-based drivers, a comma-separated list of extensions


of the files the driver can use. For example, a dBASE driver
might specify *.dbf and a formatted text file driver might
specify *.txt,*.csv. For an example of how an application
might use this information, see the FileUsage keyword.
K EY W O RD USA GE

FileUsage A number indicating how a file-based driver directly treats


files in a data source.

0 = The driver is not a file-based driver. For example, an


ORACLE driver is a DBMS-based driver.

1 = A file-based driver treats files in a data source as tables.


For example, an Xbase driver treats each Xbase file as a table.

2 = A file-based driver treats files in a data source as a


catalog. For example, a Microsoft® Access driver treats
each Microsoft Access file as a complete database.

An application might use this to determine how users will


select data. For example, Xbase and Paradox users often
think of data as stored in files, while ORACLE and Microsoft
Access users generally think of data as stored in tables.

When a user selects Open Data File from the File menu,
an application could display the Windows File Open
common dialog box. The list of file types would use the file
extensions specified with the FileExtns keyword for drivers
that specify a FileUsage value of 1 and "Y" as the second
character of the value of the ConnectFunctions keyword.
After the user selects a file, the application would call
SQLDriverConnect with the DRIVER keyword and then
execute a SELECT * FROM table-name statement.

When the user selects Impor t Data from the File menu, an
application could display a list of descriptions for drivers that
specify a FileUsage value of 0 or 2, and "Y" as the second
character of the value of the ConnectFunctions keyword.
After the user selects a driver, the application would call
SQLDriverConnect with the DRIVER keyword and then
display a custom Select Table dialog box.

SQLLevel A number indicating the SQL-92 grammar supported by the


driver:

0 = SQL-92 Entry

1 = FIPS127-2 Transitional

2 = SQL-92 Intermediate

3 = SQL-92 Full

This must be the same as the value returned for the


SQL_SQL_CONFORMANCE option in SQLGetInfo .

For information about usage counts, see Usage Counting earlier in this section.
Applications should not set the usage count. ODBC will maintain this count.
For example, suppose a driver for formatted text files has a driver DLL named Text.dll, a separate driver setup
DLL named Txtsetup.dll, and has been installed three times. If the driver supports the Level 1 API conformance
level, supports the Minimum SQL grammar conformance level, treats files as tables, and can use files with the
.txt and .csv extensions, the values under the Text subkey might be as follows:
APILevel : REG_SZ : 1
ConnectFunctions : REG_SZ : YYN
Driver : REG_SZ : C:\WINDOWS\SYSTEM32\TEXT.DLL
DriverODBCVer : REG_SZ : 03.00.00
FileExtns : REG_SZ : *.txt,*.csv
FileUsage : REG_SZ : 1
Setup : REG_SZ : C:\WINDOWS\SYSTEM32\TXTSETUP.DLL
SQLLevel : REG_SZ : 0
UsageCount : REG_DWORD : 0x3
Default Driver Subkey
4/27/2022 • 2 minutes to read • Edit Online

The Default subkey contains a single value that describes the driver used by the default data source. The format
of this value is shown in the following table.

NAME DATA T Y P E DATA

Driver REG_SZ default-driver-description

The default-driver-description name is the same as the name of the value under the ODBC Drivers subkey that
describes the driver.
For example, if the default data source uses the SQL Server driver, the value under the Default subkey might be:

Driver : REG_SZ : SQL Server

NOTE
The default driver contained in the Default subkey can refer to either a default user DSN or a default system DSN. If both
a default user DSN and a default system DSN have been created, the default driver is determined by the DSN that was
created last, so it might not be a valid entry for the DSN that was created first.
ODBC Translators Subkey
4/27/2022 • 2 minutes to read • Edit Online

The values under the ODBC Translators subkey list the installed translators. The format of these values is shown
in the following table.

NAME DATA T Y P E DATA

translator-desc REG_SZ Installed

The translator-desc name is defined by the translator developer.


For example, suppose a user has installed the Microsoft® Code Page Translator and a custom ASCII to EBCDIC
translator. The values under the ODBC Translators subkey might be as follows:

MS Code Page Translator: REG_SZ : Installed


ASCII to EBCDIC: REG_SZ : Installed.
Translator Specification Subkeys
4/27/2022 • 2 minutes to read • Edit Online

Each translator listed in the ODBC Translators subkey has a subkey of its own. This subkey has the same name as
the corresponding value under the ODBC Translators subkey. The values under this subkey list the full paths of
the translator and translator setup DLLs and the usage count. The formats of the values are as shown in the
following table.

NAME DATA T Y P E DATA

Translator REG_SZ translator-DLL-path

Setup REG_SZ setup-DLL-path

UsageCount REG_DWORD count

For information about usage counts, see Usage Counting earlier in this section.
Applications should not set the usage count. ODBC will maintain this count.
For example, suppose the Microsoft Code Page Translator has a translation DLL named Mscpxl32.dll, that the
translator setup functions are in the same DLL, and that the translator has been installed three times. The values
under the Microsoft Code Page Translator subkey might be as follows:

Translator : REG_SZ : C:\WINDOWS\SYSTEM32\MSCPXL32.DLL


Setup : REG_SZ : C:\WINDOWS\SYSTEM32\MSCPXL32.DLL
UsageCount : REG_DWORD : 0x3
Registry Entries for Data Sources
4/27/2022 • 2 minutes to read • Edit Online

NOTE
Starting with Windows XP and Windows Server 2003, ODBC is included in the Windows operation system. You should
only explicitly install ODBC on earlier versions of Windows.

The installer DLL maintains information in the registry about each data source. In Microsoft Windows
NT/Windows 2000 and Microsoft Windows 95/98, this information is stored in subkeys under one of the
following two keys in the registry:

HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\Odbc.ini

HKEY_CURRENT_USER\SOFTWARE\ODBC\Odbc.ini

Which key is used depends on whether the data source is a system data source, which is available to all users, or
a user data source, which is available only to the current user. System data sources are stored on the
HKEY_LOCAL_MACHINE tree, and user data sources are stored on the HKEY_CURRENT_USER tree. In all other
respects, system data sources and user data sources are identical.
This section contains the following topics.
ODBC Data Sources Subkey
Data Source Specification Subkeys
Default Subkey
ODBC Subkey
ODBC Data Sources subkey
4/27/2022 • 2 minutes to read • Edit Online

The values under the ODBC Data Sources subkey list the data sources. The format of these values is shown in the
following table.

NAME DATA T Y P E DATA

data-source-name REG_SZ driver-description

The data-source-name value is defined by the administration program (which usually prompts the user for it),
and driver-description is defined by the driver developer (it is usually the name of the DBMS associated with the
driver).
For example, suppose three data sources have been defined: Inventory, which uses SQL Server; Payroll, which
uses dBASE; and Personnel, which uses formatted text files. The values under the ODBC Data Sources subkey
might be as follows:

Inventory : REG_SZ : SQL Server


Payroll : REG_SZ : dBASE
Personnel : REG_SZ : Text
Data Source Specification Subkeys
4/27/2022 • 2 minutes to read • Edit Online

Each data source listed in the ODBC Data Sources subkey has a subkey of its own. This subkey has the same
name as the corresponding value under the ODBC Data Sources subkey. The values under this subkey must list
the driver DLL and may list a description of the data source. If the driver supports translators, the values may list
the name of a default translator, the default translation DLL, and the default translation option. The values may
also list other information required by the driver to connect to the data source. For example, the driver might
require a server name, database name, or schema name.
The formats of the values are as shown in the following table. Only the Driver value is required.

NAME DATA T Y P E DATA

Description REG_SZ description

Driver REG_SZ driver-DLL-path

TranslationDLL REG_SZ translator-DLL-path

TranslationName REG_SZ translator-name

TranslationOption REG_SZ translation-option

opt-value-name opt-value-type opt-value-data

For example, suppose the SQL Server driver requires the server name and a flag for OEM to ANSI conversion
and defines the Server and OEMTOANSI values for these. Suppose also that the Inventory data source uses the
Microsoft® Code Page Translator to translate between the Windows® Latin 1 (1250) and Multilingual (850)
code pages. The values under the Inventory subkey might be as follows:

Description : REG_SZ : Inventory database on server InvServ


Driver : REG_SZ : C:\WINDOWS\SYSTEM32\SQLSRV32.DLL
OEMTOANSI : REG_SZ : Yes
Server : REG_SZ : InvServ
TranslationDLL : REG_SZ : C:\WINDOWS\SYSTEM32\MSCPXL32.DLL
TranslationName : REG_SZ : MS Code Page Translator
TranslationOption : REG_SZ : 12500850
Default Subkey
4/27/2022 • 2 minutes to read • Edit Online

The registry may specify a default data source with the Default subkey. This subkey is a special case of a data
source specification subkey and has the same values as any other data source specification subkey. The only
difference is that it is not listed as a value under the ODBC Data Sources subkey.
ODBC Subkey
4/27/2022 • 2 minutes to read • Edit Online

The values under the ODBC subkey specify ODBC tracing options. These options are set through the Tracing tab
of the ODBC Data Source Administrator dialog box displayed by SQLManageDataSources . The ODBC subkey
itself is optional. The format of these values is as shown in the following table.

NAME DATA T Y P E DATA

Trace REG_SZ 0 |1

TraceFile REG_SZ tracefile-path

The values have the meanings described in the following table.

VA L UE M EA N IN G

Trace If the Trace value is set to 1 when an application calls


SQL AllocHandle with the SQL_HANDLE_ENV option,
tracing is enabled for the calling application.

If the Trace keyword is set to 0 when an application calls


SQL AllocHandle with the SQL_HANDLE_ENV option,
tracing is disabled for the calling application. This is the
default value.

An application can enable or disable tracing with the


SQL_ATTR_TRACE connection attribute. However, doing so
does not change the data for this value.

TraceFile If tracing is enabled, the Driver Manager writes to the trace


file specified by the TraceFile value.

If no trace file is specified, the Driver Manager writes to the


Sql.log file on the current drive. This is the default value.

Tracing should be used only for a single application, or each


application should specify a different trace file. Otherwise,
two or more applications will attempt to open the same
trace file at the same time, causing an error.

An application can specify a new trace file with the


SQL_ATTR_TRACEFILE connection attribute. However, doing
so does not change the data for this value.

For example, suppose that tracing is enabled and the trace file is C:\Odbc.log. The values under the ODBC
subkey would be as follows:

Trace : REG_SZ : 1
TraceFile : REG_SZ : C:\ODBC.LOG
Developing an ODBC Driver
4/27/2022 • 2 minutes to read • Edit Online

This section contains topics that discuss how to develop an ODBC driver.
This section contains the following topics
ODBC Driver Architecture
Upgrading a 3.5 Driver to a 3.8 Driver
Developing Connection-Pool Awareness in an ODBC Driver
Notification of Asynchronous Function Completion
ODBC Driver Architecture
4/27/2022 • 2 minutes to read • Edit Online

Driver writers must be aware that the driver architecture can affect whether an application can use DBMS-
specific SQL.

File-based Drivers
When the driver accesses the physical data directly, the driver acts as both driver and data source. The driver
must process both ODBC calls and SQL statements. Developers of file-based drivers must write their own
database engines.
DBMS-Based Drivers
When a separate database engine is used to access physical data, the driver processes only ODBC calls. It passes
SQL statements to the database engine for processing.
Network Architecture
File and DBMS ODBC configurations can exist on a single network.
Other Driver Architectures
When a driver is required to work with a variety of data sources, it can be used as middleware. Heterogeneous
join engine architecture can make the driver appear as a driver manager. Drivers can also be installed on
servers, where they can be shared by a series of clients.
For more information about driver architecture, see Driver Manager and Driver Architecture in the section on
ODBC Architecture.
More information about driver issues can be found in the locations described in the following table.
ISSUE TO P IC LO C AT IO N

Compatibility issues with applications Application/Driver Compatibility Programming Considerations, in the


and drivers ODBC Programmer's Reference

Writing ODBC drivers Writing ODBC 3.x Drivers Programming Considerations, in the
ODBC Programmer's Reference

Driver guidelines for backward Driver Guidelines for Backward Appendix G: Driver Guidelines for
compatibility Compatibility Backward Compatibility, in the ODBC
Programmer's Reference

Connecting to a driver Choosing a Data Source or Driver Connecting to a Data Source or Driver,
in the ODBC Programmer's Reference

Identifying drivers Viewing Drivers Viewing Drivers, in the Microsoft


ODBC Data Source Administrator
online Help

Enabling connection pooling ODBC Connection Pooling Connecting to a Data Source or Driver,
in the ODBC Programmer's Reference

Unicode/ANSI driver and connection Unicode Drivers Programming Considerations, in the


issues ODBC Programmer's Reference

See Also
Developing an ODBC Driver
Upgrading a 3.5 Driver to a 3.8 Driver
4/27/2022 • 4 minutes to read • Edit Online

This topic provides guidelines and considerations for upgrading an ODBC 3.5 driver to an ODBC 3.8 driver.
Ve r si o n N u m b e r s

The following guidelines relate to version numbers:


A driver should support SQL_OV_ODBC3_80 for SQL_ATTR_ODBC_VERSION, returning SQL_ERROR for
values other than SQL_OV_ODBC2, SQL_OV_ODBC3, and SQL_OV_ODBC3_80. Future versions of the
Driver Manager will assume that a driver supports an ODBC compliance level if the driver returns
SQL_SUCCESS from SQLSetEnvAttr Function.
A version 3.8 driver should return 03.80 from SQLGetInfo when SQL_DRIVER_ODBC_VER is passed to
InfoType. However, older Driver Managers, which were included in older versions of Microsoft Windows,
will treat the driver as a version 3.5 driver, and issue a warning.
In Windows 7, the Driver Manager version is 03.80. In Windows 8, the Driver Manager version is 03.81
via the SQLGetInfo SQL_DM_VER (InfoType parameter). SQL_ODBC_VER reports the version as 03.80 in
both Windows 7 and Windows 8.
D r i v e r- Sp e c i fi c C D a t a T y p e s

A driver can have customized C data types when it works with a version 3.8 ODBC application. (For more
information, see C Data Types in ODBC.) However, there is no requirement for a 3.8 driver to implement any
driver-specific C types. But the driver should still perform the range check of C types; the Driver Manager will
not do that for 3.8 drivers. To facilitate driver development, the value of the driver specific, C data type can be
defined in the following format:

SQL_DRIVER_C_TYPE_BASE+0, SQL_DRIVER_C_TYPE_BASE+1

D r i v e r- sp e c i fi c D a t a T y p e s, D e sc r i p t o r T y p e s, I n fo r m a t i o n T y p e s, D i a g n o st i c T y p e s, a n d A t t r i b u t e s

When developing a new driver, you should use the driver-specific range for data types, descriptor types,
information types, diagnostic types, and attributes. Driver-specific ranges and their base type values are
discussed in Driver-Specific Data Types, Descriptor Types, Information Types, Diagnostic Types, and Attributes.
Co n n ec t i o n Po o l i n g

For better management of connection pooling, ODBC 3.8 introduces the SQL_ATTR_RESET_CONNECTION
connection attribute in SQLSetConnectAttr . SQL_RESET_CONNECTION_YES is the only valid value for this
attribute. SQL_ATTR_RESET_CONNECTION will be set just before the Driver Manager puts a connection in the
connection pool, allowing the driver to reset the other connection attributes to their default values.
To avoid unnecessary communication with the server, a driver can defer the connection attribute reset until the
next communication with the remote server, after the connection is reused from the pool.
Note that SQL_ATTR_RESET_CONNECTION is only used in communication between the Driver Manager and a
driver. An application cannot set this attribute directly. All version 3.8 drivers should implement this connection
attribute.
St r e a m e d O u t p u t P a r a m e t e r s

ODBC version 3.8 introduces streamed output parameters, a more scalable way to retrieve output parameters.
(For more information, see Retrieving Output Parameters Using SQLGetData.) To support this feature, a driver
should set SQL_GD_OUTPUT_PARAMS in the return value when SQL_GETDATA_EXTENSIONS is the InfoType in a
SQLGetInfo call. Support for an SQL type with streamed output parameters must be implemented in the driver.
The Driver Manager will not generate an error for an invalid SQL type. The SQL types that support streamed
output parameters is defined in the driver.
A driver should return SQL_ERROR if the application used SQLGetData to retrieve a parameter that is not the
same as the parameter returned by SQLParamData .
A sy n c h r o n o u s Ex e c u t i o n fo r C o n n e c t i o n O p e r a t i o n s (P o l l i n g M e t h o d )

A driver can enable asynchronous support for various connection operations.


Beginning in Windows 7, ODBC supports the polling method (for more information, see Asynchronous
Execution (Polling Method). There is no requirement for a version 3.8 ODBC driver to implement asynchronous
operations on connection handles. Even if a driver does not implement asynchronous operations on connection
handles, the driver should still implement the SQL_ASYNC_DBC_FUNCTIONS InfoType and return
SQL_ASYNC_DBC_NOT_CAPABLE .
When asynchronous connection operations are enabled, the running time of a connection operation is the total
time of all repeated calls. If the last repeated call occurs after the total time has exceeded the value set by the
SQL_ATTR_CONNECTION_TIMEOUT connection attribute, and the operation has not finished, the driver returns
SQL_ERROR and logs a diagnostic record with SQLState HYT01 and the message "Connection timeout expired".
There is no timeout if the operation finished.
SQ L C a n c e l H a n d l e F u n c t i o n

ODBC 3.8 supports SQLCancelHandle Function, which is used to cancel both connection and statement
operations. A driver that supports SQLCancelHandle must export the function. A driver should not cancel any
synchronous or asynchronous connection function that is in progress if the application calls SQLCancel or
SQLCancelHandle on a statement handle. Similarly, a driver should not cancel any synchronous or
asynchronous statement function that is in progress if an application calls SQLCancelHandle on the
connection handle. Also, a driver should not cancel the browsing operation (SQLBrowseConnect returns
SQL_NEED_DATA) if the application calls SQLCancelHandle on the connection handle. In these cases, a driver
should return HY010, "function sequence error".
It is not necessary to support both SQLCancelHandle and asynchronous connection operations at the same
time. A driver can support asynchronous connection operations but not SQLCancelHandle , or vice versa.
Su sp e n d e d C o n n e c t i o n s

The ODBC 3.8 Driver Manager can put a connection into suspended state. An application will call
SQLDisconnect to release resources associated with the connection. In this case, a driver should try to release
as many resources as possible without checking the state of the connection. For more information about the
suspended state, see SQLEndTran Function.
D r i v e r- A w a r e C o n n e c t i o n P o o l i n g

ODBC in Windows 8 allows drivers to customize connection pool behavior. For more information, see Driver-
Aware Connection Pooling.
A sy n c h r o n o u s Ex e c u t i o n (N o t i fi c a t i o n M e t h o d )

ODBC 3.8 supports the notification method for asynchronous operations, available beginning on Windows 8.
For more information, see Asynchronous Execution (Notification Method).

See Also
Developing an ODBC Driver
Microsoft-Supplied ODBC Drivers
What's New in ODBC 3.8
Developing Connection-Pool Awareness in an
ODBC Driver
4/27/2022 • 7 minutes to read • Edit Online

This topic discusses the details of developing an ODBC driver that contains information about how the driver
should provide connection pooling services.

Enabling Driver-Aware Connection Pooling


A driver must implement the following ODBC Service Provider Interface (SPI) functions:
SQLSetConnectAttrForDbcInfo
SQLSetConnectInfo
SQLSetDriverConnectInfo
SQLGetPoolID
SQLRateConnection
SQLPoolConnect
SQLCleanupConnectionPoolID
See ODBC Service Provider Interface (SPI) Reference for more information.
A driver must also implement the following existing functions so that the driver-aware pooling can be enabled:

F UN C T IO N A DDED F UN C T IO N A L IT Y

SQLAllocHandle Support the new handle type:


SQL_HANDLE_DBC_INFO_TOKEN (see the description
SQLFreeHandle below).

SQLGetDiagField

SQLGetDiagRec

SQLSetConnectAttr Support the new set-only connection attribute:


SQL_ATTR_DBC_INFO_TOKEN for resetting the connection
(see the description below).

NOTE
Deprecated functions such as SQLError and SQLSetConnectOption are not supported for driver-aware connection
pooling.

The Pool ID
The pool ID is a pointer-length driver-specific ID to represent a particular group of connections that can be used
interchangeably. Given a set of connection information, a driver should be able to quickly deduce the
corresponding pool ID.
For example, the pool ID should encode the server name and credential information. However, the database
name is not needed because a driver may be able to reuse a connection and then change the database in less
time than making a new connection.
A driver should define a set of key attributes, which will comprise the pool ID. The value of these key attributes
can come from connection attributes, connection string, and DSN. In case there are any conflicts in these
sources, the existing, driver-specific resolution policy should be used for backward compatibility.
The Driver Manager will use a different pool for different pool IDs. All connections in the same pool are reusable.
The Driver Manager will never reuse a connection with a different pool ID.
Therefore drivers should assign a unique pool ID for every group of connections with the same value in their
defined key attributes. If a driver uses the same pool ID for two connections with different values in their key
attributes, the Driver Manager will still put them into the same pool (the Driver Manager knows nothing about
the driver-specific key attributes). This means that the driver will need to report to the Driver Manager that a
connection with a different set of key attributes is not reusable inside SQLRateConnection Function. This can
decrease performance and this is not recommended.
The Driver Manager will not reuse a connection allocated from another driver environment even if all
connection information matches. The Driver Manager will use a different pool for different environment, even
when connections have the same pool ID. Therefore, the pool ID is local to its driver environment.
The function for getting the pool ID from the driver is SQLGetPoolID Function.

The Connection Rating


Compared to establishing a new connection, you can get better performance by resetting some connection
information (such as DATABASE) in a pooled connection. So, you may not want the database name to be in your
set of key attributes. Otherwise, you can have a separate pool for each database, which may not be good in mid-
tier applications, where customers use various different connection strings.
Whenever you reuse a connection that has some attribute mismatch, you should reset the mismatched
attributes based on the new application request, so that the returned connection is identical to the application
request (see the discussion of the attribute SQL_ATTR_DBC_INFO_TOKEN in SQLSetConnectAttr Function).
However, resetting those attributes may decrease performance. For example, resetting a database requires a
network call to server. Therefore, reuse a connection that is perfectly matched, if one is available.
A rating function in the driver can evaluate an existing connection with a new connection request. For example,
the driver's rating function can determine:
If the existing connection is perfectly matched with the request.
If there are only some insignificant mismatches, such as connection timeout, which do not require
communication with the server to reset.
If there are some mismatched attributes that require a communication with the server to reset but would
still result in better performance than establishing a new connection.
If the mismatched occurred for an attribute that is very time-consuming to reset (the developer of the
driver may consider adding this attribute into the set of key attributes, which is used to generate the pool
ID).
A score between 0 and 100 is possible, where 0 means do not reuse and 100 means perfectly matched.
SQLRateConnection is the function for rating a connection.

New ODBC Handle - SQL_HANDLE_DBC_INFO_TOKEN


To support driver-aware connection pooling, the driver needs connection information to compute the Pool ID.
The driver also needs connection information to compare new connection requests with connections in the pool.
Whenever no connection in the pool can be reused, the driver has to establish a new connection, hence
requiring connection information.
Since connection information can come from multiple sources (connection string, connection attributes, and
DSN), the driver may need to parse the connection string and resolve the conflict between these sources in each
of the above function call.
Therefore, a new ODBC handle is introduced: SQL_HANDLE_DBC_INFO_TOKEN. With
SQL_HANDLE_DBC_INFO_TOKEN, a driver does not need to parse the connection string and resolve conflicts in
connection information more than once. Since this is a driver-specific data structure, the driver can store data
such as connection information or pool ID.
This handle is only used as an interface between the Driver Manager and driver. An application cannot allocate
this handle directly.
The parent handle of this handle is of type SQL_HANDLE_ENV, meaning that the driver can obtain the
environment information from the HENV handle during connection information resolution.
Whenever it receives a new connection request, the Driver Manager will allocate a handle of type
SQL_HANDLE_DBC_INFO_TOKEN for storing connection information, after it confirms that the driver supports
connection-pool awareness. When finished using the handle (but before returning some return codes other than
SQL_STILL_EXECUTING from SQLDriverConnect or SQLConnect), the Driver Manager will free the handle.
Therefore, the handle is created after the SQLAllocHandle call, and destroyed after the SQLFreeHandle call. The
Driver Manager guarantees the handle will be freed before freeing its associated HENV (when
SQLDriverConnect or SQLConnect returns an error).
The driver should modify the following functions to accept the new handle type
SQL_HANDLE_DBC_INFO_TOKEN:
1. SQLAllocHandle
2. SQLFreeHandle
3. SQLGetDiagField
4. SQLGetDiagRec
The Driver Manager guarantees that multiple threads will not use the same SQL_HANDLE_DBC_INFO_TOKEN
handle simultaneously. Therefore, the synchronization model of this handle can be very simple inside the driver.
The Driver Manager will not take an environment lock before allocating and freeing
SQL_HANDLE_DBC_INFO_TOKEN.
The Driver Manager's SQL AllocHandle and SQLFreeHandle will not accept this new handle type.
SQL_HANDLE_DBC_INFO_TOKEN may contain confidential information such as credentials. Therefore, a driver
should securely clear the memory buffer (using SecureZeroMemory) that contains the sensitive information
before releasing this handle with SQLFreeHandle . Whenever an application's environment handle is closed, all
associated connection pools will be closed.

Driver Manager Connection Pool Rating Algorithm


This section discusses the rating algorithm for Driver Manager connection pooling. Driver developers can
implement the same algorithm for backward compatibility. This algorithm may not be the best one. You should
refine this algorithm based your implementation (otherwise, there is no reason to implement this feature).
The Driver Manager will return an integral rating from 0 to 100 for each connection from the pool. 0 means the
connection cannot be reused and 100 indicates a perfect matched. Assume the connection request is named
hRequest and the existing connection from the pool is named as hCandidate. If any one of the following
conditions is false, the pooled connection hCandidate cannot be reused for hRequest (the Driver Manager will
assign a rating of 0).
hCandidate and hRequest both come from either UNICODE API (such as SQLDriverConnectW) or ANSI
API (such as SQLDriverConnectA). (UNICODE drivers can behavior different given ANSI API and
UNICODE API (see the connection attribute SQL_ATTR_ANSI_APP).)
hCandidate and hRequest are created by the same function; either SQLDriverConnect or SQLConnect.
The connection string used to open hCandidate should be the same as hRequest, when
SQLDriverConnect is used.
The ServerName (or DSN), user name, and password used to open hCandidate should be the same used
to open hRequest when SQLConnect is used.
The security identifier (SID) of the current thread should be the same as the SID used to open hCandidate.
For driver that is expensive to enlist and unenlist (see the discussion of SQL_DTC_TRANSITION_COST in
SQLConnect), reusing hRequest must not require an extra enlistment or unenlistment.
The following table shows score assignment for different scenarios.

C O M PA RISO N O N C O N N EC T IO N
AT T RIB UT ES B ET W EEN T H E P O O L ED REQ UIRE EXT RA EN L IST M EN T /
C O N N EC T IO N A N D T H E REQ UEST N O EN L IST M EN T / UN EN L IST M EN T UN EN L IST M EN T

Catalog 60 50
(SQL_ATTR_CURRENT_CATALOG) is
different

Some connection attributes are 90 70


different, but catalog is the same

All connection attributes perfectly 100 80


matched

Sequence Diagram
This sequence diagram shows the basic pooling mechanism described in this topic. It only shows the use of
SQLDriverConnect but the SQLConnect case is similar.
State Diagram
This state diagram shows the connection info token object, described in this topic. The diagram only shows
SQLDriverConnect but the SQLConnect case is similar. Since the Driver Manager may need to handle errors at
any time, the Driver Manager can call SQLFreeHandle for any state.
See Also
Driver-Aware Connection Pooling
ODBC Service Provider Interface (SPI) Reference
Notification of Asynchronous Function Completion
4/27/2022 • 2 minutes to read • Edit Online

In the Windows 8 SDK, ODBC added a mechanism to notify applications when an asynchronous operation
completes, which we will refer to as "notification on completion". (See Asynchronous Execution (Notification
Method) for more information.) This topic discusses some of the issues for driver developers.

The Interface between the Driver Manager and Driver


The Driver Manager internally provides a callback function SQLAsyncNotificationCallback Function.
SQL AsyncNotificationCallback can only be called by the driver -- an application cannot directly call it. The
driver calls SQL AsyncNotificationCallback whenever new data received from the server after last returning
SQL_STILL_EXECUTING.
The Driver Manager provides a callback mechanism so a driver can notify the Driver Manager when some
progress has been made in executing an asynchronous operation after the corresponding function returns
SQL_STILL_EXECUTING
The Driver Manager sets the SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK attribute on a driver
connection handle with a non-NULL function pointer, which is of type SQL_ASYNC_NOTIFICATION_CALLBACK,
for the driver to work in notification mode for any asynchronous operations on that handle. Similarly, the Driver
Manager sets the SQL_ATTR_ASYNC_STMT_NOTIFICATION_CALLBACK attribute on a driver statement handle
with a non-NULL function pointer, which is also of type SQL_ASYNC_NOTIFICATION_CALLBACK, for the driver to
work in notification mode for any asynchronous operations on that handle.
If an asynchronous operation is performed on a driver handle, the asynchronous driver functions should work in
a non-blocking style. If the operation cannot complete immediately, the driver function should return
SQL_STILL_EXECUTING. This requirement is true for both polling mode and notification mode.
If a handle is in notification asynchronous mode, the driver must call the notification callback function, whose
address is the value for the SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK or
SQL_ATTR_ASYNC_STMT_NOTIFICATION_CALLBACK attribute, once after returning SQL_STILL_EXECUTING. In
other words, one returning SQL_STILL_EXECUTING must be paired with one invocation of the notification
callback function. The driver should use the current value of the
SQL_ATTR_ASYNC_DBC_NOTIFICATION_CONTEXT or SQL_ATTR_ASYNC_STMT_NOTIFICATION_CONTEXT
handle attribute as the value for the call back function parameter pContext.
The driver must not call back in the thread that calls the driver function; there is no reason to notify progress
before the function returns. The driver should use its own thread to callback. The Driver Manager will not use
the driver's callback thread for executing extensive processing logic.
The Driver Manager will call the original function again after the driver calls back. The Driver Manager may use
a thread that is neither an application thread nor a driver thread. If the driver uses some information associated
with the thread (for example, security token or user identifier), the driver should save the required information
in the initial asynchronous call and use the saved value before the whole asynchronous operation completes.
Usually, only SQLDriverConnect , SQLConnect , or SQLBrowseConnect need to use that kind of information.

See Also
Developing an ODBC Driver
SQLAsyncNotificationCallback Function
4/27/2022 • 2 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 3.8
Standards Compliance: None
Summar y
SQL AsyncNotificationCallback allows a driver to call back to the Driver Manager when there is some
progress for the current asynchronous operation after the driver returns SQL_STILL_EXECUTING.
SQL AsyncNotificationCallback can only called by the driver.
Drivers do not call SQL AsyncNotificationCallback with function name SQL AsyncNotificationCallback .
Instead, the Driver Manager passes a function pointer to a driver as the value for the
SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK or SQL_ATTR_ASYNC_STMT_NOTIFICATION_CALLBACK
attribute of the corresponding connection handle or statement handle, respectively. Different handles may be
assigned different function pointer values. The type of the function pointer is defined as
SQL_ASYNC_NOTIFICATION_CALLBACK.
SQL AsyncNotificationCallback is thread-safe. A driver can choose to use multiple threads calling
SQL AsyncNotificationCallback on different handles simultaneously.

Syntax
typedef SQLRETURN (SQL_API *SQL_ASYNC_NOTIFICATION_CALLBACK)(
SQLPOINTER pContex,
BOOL fLast);

Arguments
pContex
Pointer to a data structure defined by the Driver Manager. The value is passed to the driver via
SQLSetConnectAttr(SQL_ATTR_ASYNC_DBC_NOTIFICATION_CONTEXT) or
SQLSetStmtAttr(SQL_ATTR_ASYNC_STMT_NOTIFICATION_CONTEXT). The driver does not have access to the
value.
fLast
Used by a driver to indicates that this callback function invocation is the last one for the current asynchronous
operation. The driver will return a return code other than SQL_STILL_EXECUTING when the Driver Manager calls
the function again. The Driver Manager may use this information, for example, to inform the application in
advance that the asynchronous operation will complete.
If Handle is not a valid handle of the type specified by HandleType, SQLCancelHandle returns
SQL_INVALID_HANDLE.

Returns
SQL_SUCCESS or SQL_ERROR.
Diagnostics
SQL AsyncNotificationCallback can return SQL_ERROR for the following two situations (these indicate an
implementation problem in the driver or Driver Manager.

ERRO R DESC RIP T IO N

Connection or statement did not request notification.

Invalid handle The driver passed in an invalid handle, which failed the
internal Driver Manager validation tests.

See Also
Asynchronous Execution (Polling Method)
ODBC Reference
4/27/2022 • 2 minutes to read • Edit Online

The following topics contain syntax and semantic information for all ODBC functions.
Function Summary
ODBC API Reference
Setup DLL API Reference
Installer DLL API Reference
Translation DLL Function Reference
ODBC Service Provider Interface (SPI) Reference
Function Summary
4/27/2022 • 2 minutes to read • Edit Online

The following sections summarize the functions used by ODBC-enabled applications and related software.
ODBC Function Summary
Setup DLL Function Summary
Installer DLL Function Summary
Translation DLL Function Summary
ODBC Service Provider Interface Summary
ODBC Function Summary
4/27/2022 • 4 minutes to read • Edit Online

The following table lists ODBC functions, grouped by type of task, and includes the conformance designation
and a brief description of the purpose of each function. For more information about conformance designations,
see ODBC and the Standard CLI. For more information about the syntax and semantics for each function, see
ODBC API Reference.
An application can call the SQLGetInfo function to obtain conformance information about a driver. To obtain
information about support for a specific function in a driver, an application can call SQLGetFunctions .

TA SK F UN C T IO N N A M E C O N F O RM A N C E P URP O SE

Connecting to a data SQLAllocHandle ISO 92 Obtains an environment,


source connection, statement, or
descriptor handle.

SQLConnect ISO 92 Connects to a specific driver


by data source name, user
ID, and password.

SQLDriverConnect ODBC Connects to a specific driver


by connection string or
requests that the Driver
Manager and driver display
connection dialog boxes for
the user.

SQLBrowseConnect ODBC Returns successive levels of


connection attributes and
valid attribute values. When
a value has been specified
for each connection
attribute, connects to the
data source.

Obtaining information SQLDataSources ISO 92 Returns the list of available


about a driver and data data sources.
source SQLDrivers ODBC
Returns the list of installed
drivers and their attributes.

SQLGetInfo ISO 92 Returns information about a


specific driver and data
source.

SQLGetFunctions ISO 92 Returns supported driver


functions.

SQLGetTypeInfo ISO 92 Returns information about


supported data types.
TA SK F UN C T IO N N A M E C O N F O RM A N C E P URP O SE

Setting and retrieving driver SQLSetConnectAttr ISO 92 Sets a connection attribute.


attributes
SQLGetConnectAttr ISO 92 Returns the value of a
connection attribute.

SQLSetEnvAttr ISO 92 Sets an environment


attribute.

SQLGetEnvAttr ISO 92 Returns the value of an


environment attribute.

SQLSetStmtAttr ISO 92 Sets a statement attribute.

SQLGetStmtAttr ISO 92 Returns the value of a


statement attribute.

Setting and retrieving SQLGetDescField ISO 92 Returns the value of a single


descriptor fields descriptor field.
SQLGetDescRec ISO 92
Returns the values of
multiple descriptor fields.

SQLSetDescField ISO 92 Sets a single descriptor field.

SQLSetDescRec ISO 92 Sets multiple descriptor


fields.

SQLCopyDesc ISO 92 Copies descriptor


information from one
descriptor handle to
another.

Preparing SQL requests SQLPrepare ISO 92 Prepares an SQL statement


for later execution.

SQLBindParameter ODBC Assigns storage for a


parameter in an SQL
statement.

SQLGetCursorName ISO 92 Returns the cursor name


associated with a statement
handle.

SQLSetCursorName ISO 92 Specifies a cursor name.

SQLSetScrollOptions ODBC Sets options that control


cursor behavior.

Submitting requests SQLExecute ISO 92 Executes a prepared


statement.
SQLExecDirect ISO 92
Executes a statement.
TA SK F UN C T IO N N A M E C O N F O RM A N C E P URP O SE

SQLNativeSql ODBC Returns the text of an SQL


statement as translated by
the driver.

SQLDescribeParam ODBC Returns the description for


a specific parameter in a
statement.

SQLNumParams ISO 92 Returns the number of


parameters in a statement.

SQLParamData ISO 92 Used in conjunction with


SQLPutData to supply
parameter data at execution
time. (Useful for long data
values.)

SQLPutData ISO 92 Sends part or all of a data


value for a parameter.
(Useful for long data
values.)

Retrieving results and SQLRowCount ISO 92 Returns the number of rows


information about results affected by an insert,
SQLNumResultCols ISO 92 update, or delete request.

Returns the number of


columns in the result set.

SQLDescribeCol ISO 92 Describes a column in the


result set.

SQLColAttribute ISO 92 Describes attributes of a


column in the result set.

SQLBindCol ISO 92 Assigns storage for a result


column and specifies the
data type.

SQLFetch ISO 92 Returns multiple result


rows.

SQLFetchScroll ISO 92 Returns scrollable result


rows.

SQLGetData ISO 92 Returns part or all of one


column of one row of a
result set. (Useful for long
data values.)

SQLSetPos ODBC Positions a cursor within a


fetched block of data and
allows an application to
refresh data in the rowset
or to update or delete data
in the result set.
TA SK F UN C T IO N N A M E C O N F O RM A N C E P URP O SE

SQLBulkOperations ODBC Performs bulk insertions


and bulk bookmark
operations, including
update, delete, and fetch by
bookmark.

SQLMoreResults ODBC Determines whether there


are more result sets
available and, if so, initializes
processing for the next
result set.

SQLGetDiagField ISO 92 Returns additional


diagnostic information (a
single field of the diagnostic
data structure).

SQLGetDiagRec ISO 92 Returns additional


diagnostic information
(multiple fields of the
diagnostic data structure).

Obtaining information SQLColumnPrivileges ODBC Returns a list of columns


about the data source's and associated privileges for
system tables (catalog SQLColumns Open Group one or more tables.
functions)
Returns the list of column
names in specified tables.

SQLForeignKeys ODBC Returns a list of column


names that make up
foreign keys, if they exist for
a specified table.

SQLPrimaryKeys ODBC Returns the list of column


names that make up the
primary key for a table.

SQLProcedureColumns ODBC Returns the list of input and


output parameters, as well
as the columns that make
up the result set for the
specified procedures.

SQLProcedures ODBC Returns the list of


procedure names stored in
a specific data source.

SQLSpecialColumns Open Group Returns information about


the optimal set of columns
that uniquely identifies a
row in a specified table, or
the columns that are
automatically updated
when any value in the row
is updated by a transaction.
TA SK F UN C T IO N N A M E C O N F O RM A N C E P URP O SE

SQLStatistics ISO 92 Returns statistics about a


single table and the list of
indexes associated with the
table.

SQLTablePrivileges ODBC Returns a list of tables and


the privileges associated
with each table.

SQLTables Open Group Returns the list of table


names stored in a specific
data source.

Terminating a statement SQLFreeStmt ISO 92 Ends statement processing,


discards pending results,
and, optionally, frees all
resources associated with
the statement handle.

SQLCloseCursor ISO 92 Closes a cursor that has


been opened on a
statement handle.

SQLCancel ISO 92 Cancels the processing on a


statement.

SQLCancelHandle ODBC Cancels the processing on a


statement or connection.

SQLEndTran ISO 92 Commits or rolls back a


transaction.

Terminating a connection SQLDisconnect ISO 92 Closes the connection.

SQLFreeHandle ISO 92 Releases an environment,


connection, statement, or
descriptor handle.
Setup DLL Function Summary
4/27/2022 • 2 minutes to read • Edit Online

The following table describes setup DLL functions. For more information about the syntax and semantics for
each function, see Setup DLL API Reference.

TA SK F UN C T IO N N A M E P URP O SE

Setting up data sources and ConfigDriver Installs or uninstalls a driver.


translators
ConfigDSN Adds, modifies, or deletes a data
source.
ConfigTranslator
Returns a default translation option.
Installer DLL Function Summary
4/27/2022 • 2 minutes to read • Edit Online

The following table describes the functions in the installer DLL. For more information about the syntax and
semantics for each function, see Installer DLL API Reference.

TA SK F UN C T IO N N A M E P URP O SE

Installing ODBC SQLConfigDriver Loads the driver-specific setup DLL.

SQLGetInstalledDrivers Returns a list of installed drivers.

SQLInstallDriverEx Adds a driver to the system


information.

SQLInstallDriverManager Returns the target directory for the


Driver Manager.

SQLInstallerError Returns error or status information for


the installer functions.

SQLInstallTranslatorEx Adds a translator to the system


information.

SQLPostInstallerError Allows a driver or translator setup


library to report errors.

SQLRemoveDriver Removes a driver from the system


information.

SQLRemoveDriverManager Removes ODBC core components from


the system information.

SQLRemoveTranslator Removes the translator from the


system information.

Configuring data sources SQLConfigDataSource Calls the driver-specific setup DLL.

SQLCreateDataSource Displays a dialog box to add a data


source.

SQLGetConfigMode Retrieves the configuration mode that


indicates where the Odbc.ini entry
listing DSN values is in the system
information.

SQLGetPrivateProfileString Writes a value to the system


information.

SQLGetTranslator Displays a dialog box to select a


translator.
TA SK F UN C T IO N N A M E P URP O SE

SQLManageDataSources Displays a dialog box to configure data


sources and drivers.

SQLReadFileDSN Reads information from file DSNs.

SQLRemoveDefaultDataSource Removes the default data source.

SQLRemoveDSNFromIni Removes a data source.

SQLSetConfigMode Sets the configuration mode that


indicates where the Odbc.ini entry
listing DSN values is in the system
information.

SQLValidDSN Checks the length and validity of the


data source name.

SQLWriteDSNToIni Adds a data source.

SQLWriteFileDSN Writes information to file DSNs.

SQLWritePrivateProfileString Gets a value from the system


information.
Translation DLL Function Summary
4/27/2022 • 2 minutes to read • Edit Online

The following table describes translation DLL functions. For more information about the syntax and semantics
for each function, see Translation DLL Function Reference.

TA SK F UN C T IO N N A M E P URP O SE

Translating data SQLDataSourceToDriver Translates all data flowing from the


data source to the driver.

SQLDriverToDataSource Translates all data flowing from the


driver to the data source.
ODBC Service Provider Interface Summary
4/27/2022 • 2 minutes to read • Edit Online

The following table describes ODBC Service Provider interface functions. For more information about the syntax
and semantics for each function, see ODBC Service Provider Interface (SPI) Reference.

F UN C T IO N N A M E P URP O SE

SQLSetConnectAttrForDbcInfo Same as SQLSetConnectAttr, but it sets the attribute on the


connection information token instead of on the connection
handle.

SQLSetDriverConnectInfo Sets the connection string into the connection info token for
an application's SQLDriverConnect call.

SQLSetConnectInfo Sets the data source, user ID, and password into the
connection info token for an application's SQLConnect call.

SQLGetPoolID Retrieves the pool ID.

SQLRateConnection Determines if a driver can reuse an existing connection in the


connection pool.

SQLPoolConnect Create a new connection if no connection in the pool can be


reused.

SQLCleanupConnectionPoolID Informs a driver that a pool ID was timed out.


ODBC API Reference
4/27/2022 • 2 minutes to read • Edit Online

The topics in this section describe each ODBC function in alphabetical order. Each function is defined as a C
programming language function. Descriptions include the following:
Purpose
ODBC version
Standard CLI conformance level
Syntax
Arguments
Return values
Diagnostics
Comments about usage and implementation
Code example
References to related functions
The standard CLI conformance level can be one of the following: ISO 92, Open Group, ODBC, or Deprecated. A
function tagged as ISO 92-conformant also appears in Open Group version 1, because Open Group is a pure
superset of ISO 92. A function tagged as Open Group-compliant also appears in ODBC 3.x, because ODBC 3.x is
a pure superset of Open Group version 1. A function tagged as ODBC-compliant appears in neither standard. A
function tagged as deprecated has been deprecated in ODBC 3.x.
Handling of diagnostic information is described in the SQLGetDiagField function description. The text associated
with SQLSTATE values is included to provide a description of the condition but is not intended to prescribe
specific text.

NOTE
For driver-specific information about ODBC functions, see the section for the driver.

This section contains topics for the following functions:


SQLAllocConnect Function
SQLAllocEnv Function
SQLAllocHandle Function
SQLAllocStmt Function
SQLBindCol Function
SQLBindParameter Function
SQLBrowseConnect Function
SQLBulkOperations Function
SQLCancel Function
SQLCancelHandle Function
SQLCloseCursor Function
SQLColAttribute Function
SQLColAttributes Function
SQLColumnPrivileges Function
SQLColumns Function
SQLCompleteAsync Function
SQLConnect Function
SQLCopyDesc Function
SQLDataSources Function
SQLDescribeCol Function
SQLDescribeParam Function
SQLDisconnect Function
SQLDriverConnect Function
SQLDrivers Function
SQLEndTran Function
SQLError Function
SQLExecDirect Function
SQLExecute Function
SQLExtendedFetch Function
SQLFetch Function
SQLFetchScroll Function
SQLForeignKeys Function
SQLFreeConnect Function
SQLFreeEnv Function
SQLFreeHandle Function
SQLFreeStmt Function
SQLGetConnectAttr Function
SQLGetConnectOption Function
SQLGetCursorName Function
SQLGetData Function
SQLGetDescField Function
SQLGetDescRec Function
SQLGetDiagField Function
SQLGetDiagRec Function
SQLGetEnvAttr Function
SQLGetFunctions Function
SQLGetInfo Function
SQLGetStmtAttr Function
SQLGetStmtOption Function
SQLGetTypeInfo Function
SQLMoreResults Function
SQLNativeSql Function
SQLNumParams Function
SQLNumResultCols Function
SQLParamData Function
SQLParamOptions Function
SQLPrepare Function
SQLPrimaryKeys Function
SQLProcedureColumns Function
SQLProcedures Function
SQLPutData Function
SQLRowCount Function
SQLSetConnectAttr Function
SQLSetConnectOption Function
SQLSetCursorName Function
SQLSetDescField Function
SQLSetDescRec Function
SQLSetEnvAttr Function
SQLSetParam Function
SQLSetPos Function
SQLSetScrollOptions Function
SQLSetStmtAttr Function
SQLSetStmtOption Function
SQLSpecialColumns Function
SQLStatistics Function
SQLTablePrivileges Function
SQLTables Function
SQLTransact Function
SQLAllocConnect Function
4/27/2022 • 2 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: Deprecated
Summar y
In ODBC 3.x, the ODBC 2.x function SQL AllocConnect has been replaced by SQL AllocHandle . For more
information, see SQLAllocHandle Function.

NOTE
For more information about what the Driver Manager maps this function to when an ODBC 2.x application is working
with an ODBC 3.x driver, see Mapping Deprecated Functions in Appendix G: Driver Guidelines for Backward Compatibility.

See Also
ODBC API Reference
ODBC Header Files
SQLAllocEnv Function
4/27/2022 • 2 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: Deprecated
Summar y
In ODBC 3.x, the ODBC 2.x function SQL AllocEnv has been replaced by SQL AllocHandle . For more
information, see SQLAllocHandle Function.

NOTE
For more information about what the Driver Manager maps this function to when an ODBC 2.x application is working
with an ODBC 3.x driver, see Mapping Deprecated Functions in Appendix G: Driver Guidelines for Backward Compatibility.

See Also
ODBC API Reference
ODBC Header Files
SQLAllocHandle Function
4/27/2022 • 14 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 3.0 Standards Compliance: ISO 92
Summar y
SQL AllocHandle allocates an environment, connection, statement, or descriptor handle.

NOTE
This function is a generic function for allocating handles that replaces the ODBC 2.0 functions SQL AllocConnect ,
SQL AllocEnv , and SQL AllocStmt . To allow applications calling SQL AllocHandle to work with ODBC 2.x drivers, a call
to SQL AllocHandle is mapped in the Driver Manager to SQL AllocConnect , SQL AllocEnv , or SQL AllocStmt , as
appropriate. For more information, see "Comments." For more information about what the Driver Manager maps this
function to when an ODBC 3.x application is working with an ODBC 2.x driver, see Mapping Replacement Functions for
Backward Compatibility of Applications.

Syntax
SQLRETURN SQLAllocHandle(
SQLSMALLINT HandleType,
SQLHANDLE InputHandle,
SQLHANDLE * OutputHandlePtr);

Arguments
HandleType
[Input] The type of handle to be allocated by SQL AllocHandle . Must be one of the following values:
SQL_HANDLE_DBC
SQL_HANDLE_DBC_INFO_TOKEN
SQL_HANDLE_DESC
SQL_HANDLE_ENV
SQL_HANDLE_STMT
SQL_HANDLE_DBC_INFO_TOKEN handle is used only by the Driver Manager and driver. Applications should not
use this handle type. For more information about SQL_HANDLE_DBC_INFO_TOKEN, see Developing
Connection-Pool Awareness in an ODBC Driver.
InputHandle
[Input] The input handle in whose context the new handle is to be allocated. If HandleType is SQL_HANDLE_ENV,
this is SQL_NULL_HANDLE. If HandleType is SQL_HANDLE_DBC, this must be an environment handle, and if it is
SQL_HANDLE_STMT or SQL_HANDLE_DESC, it must be a connection handle.
OutputHandlePtr
[Output] Pointer to a buffer in which to return the handle to the newly allocated data structure.
Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR.
When allocating a handle other than an environment handle, if SQL AllocHandle returns SQL_ERROR, it sets
OutputHandlePtr to SQL_NULL_HDBC, SQL_NULL_HSTMT, or SQL_NULL_HDESC, depending on the value of
HandleType, unless the output argument is a null pointer. The application can then obtain additional information
from the diagnostic data structure associated with the handle in the InputHandle argument.

Environment Handle Allocation Errors


Environment allocation occurs both within the Driver Manager and within each driver. The error returned by
SQL AllocHandle with a HandleType of SQL_HANDLE_ENV depends on the level in which the error occurred.
If the Driver Manager cannot allocate memory for *OutputHandlePtr when SQL AllocHandle with a
HandleType of SQL_HANDLE_ENV is called, or the application provides a null pointer for OutputHandlePtr,
SQL AllocHandle returns SQL_ERROR. The Driver Manager sets *OutputHandlePtr to SQL_NULL_HENV (unless
the application provided a null pointer, which returns SQL_ERROR). There is no handle with which to associate
additional diagnostic information.
The Driver Manager does not call the driver-level environment handle allocation function until the application
calls SQLConnect , SQLBrowseConnect , or SQLDriverConnect . If an error occurs in the driver-level
SQL AllocHandle function, then the Driver Manager-level SQLConnect , SQLBrowseConnect , or
SQLDriverConnect function returns SQL_ERROR. The diagnostic data structure contains SQLSTATE IM004
(Driver's SQL AllocHandle failed). The error is returned on a connection handle.
For more information about the flow of function calls between the Driver Manager and a driver, see SQLConnect
Function.

Diagnostics
When SQL AllocHandle returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value can
be obtained by calling SQLGetDiagRec with the appropriate HandleType and Handle set to the value of
InputHandle. SQL_SUCCESS_WITH_INFO (but not SQL_ERROR) can be returned for the OutputHandle argument.
The following table lists the SQLSTATE values typically returned by SQL AllocHandle and explains each one in
the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs returned by the Driver
Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

08003 Connection not open (DM) The HandleType argument was


SQL_HANDLE_STMT or
SQL_HANDLE_DESC, but the
connection specified by the
InputHandle argument was not open.
The connection process must be
completed successfully (and the
connection must be open) for the
driver to allocate a statement or
descriptor handle.
SQ L STAT E ERRO R DESC RIP T IO N

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.

HY001 Memory allocation error (DM) The Driver Manager was unable
to allocate memory for the specified
handle.

The driver was unable to allocate


memory for the specified handle.

HY009 Invalid use of null pointer (DM) The OutputHandlePtr argument


was a null pointer.

HY010 Function sequence error (DM) The HandleType argument was


SQL_HANDLE_DBC, and
SQLSetEnvAttr has not been called
to set the SQL_ODBC_VERSION
environment attribute.

(DM) An asynchronously executing


function was called for the
InputHandle and was still executing
when the SQL AllocHandle function
was called with HandleType set to
SQL_HANDLE_STMT or
SQL_HANDLE_DESC.

HY013 Memory management error The HandleType argument was


SQL_HANDLE_DBC,
SQL_HANDLE_STMT, or
SQL_HANDLE_DESC; and the function
call could not be processed because
the underlying memory objects could
not be accessed, possibly because of
low memory conditions.

HY014 Limit on the number of handles The driver-defined limit for the number
exceeded of handles that can be allocated for the
type of handle indicated by the
HandleType argument has been
reached.

HY092 Invalid attribute/option identifier (DM) The HandleType argument was


not: SQL_HANDLE_ENV,
SQL_HANDLE_DBC,
SQL_HANDLE_STMT, or
SQL_HANDLE_DESC.

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.
SQ L STAT E ERRO R DESC RIP T IO N

HYC00 Optional feature not implemented The HandleType argument was


SQL_HANDLE_DESC and the driver
was an ODBC 2.x driver.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The HandleType argument was
SQL_HANDLE_STMT, and the driver
was not a valid ODBC driver.

(DM) The HandleType argument was


SQL_HANDLE_DESC, and the driver
does not support allocating a
descriptor handle.

Comments
SQL AllocHandle is used to allocate handles for environments, connections, statements, and descriptors, as
described in the following sections. For general information about handles, see Handles.
More than one environment, connection, or statement handle can be allocated by an application at a time if
multiple allocations are supported by the driver. In ODBC, no limit is defined on the number of environment,
connection, statement, or descriptor handles that can be allocated at any one time. Drivers may impose a limit
on the number of a certain type of handle that can be allocated at a time; for more information, see the driver
documentation.
If the application calls SQL AllocHandle with *OutputHandlePtr set to an environment, connection, statement,
or descriptor handle that already exists, the driver overwrites the information associated with the handle, unless
the application is using connection pooling (see "Allocating an Environment Attribute for Connection Pooling"
later in this section). The Driver Manager does not check to see whether the handle entered in *OutputHandlePtr
is already being used, nor does it check the previous contents of a handle before overwriting them.

NOTE
It is incorrect ODBC application programming to call SQL AllocHandle two times with the same application variable
defined for *OutputHandlePtr without calling SQLFreeHandle to free the handle before reallocating it. Overwriting
ODBC handles in such a manner could lead to inconsistent behavior or errors on the part of ODBC drivers.

On operating systems that support multiple threads, applications can use the same environment, connection,
statement, or descriptor handle on different threads. Drivers must therefore support safe, multithread access to
this information; one way to achieve this, for example, is by using a critical section or a semaphore. For more
information about threading, see Multithreading.
SQL AllocHandle does not set the SQL_ATTR_ODBC_VERSION environment attribute when it is called to
allocate an environment handle; the environment attribute must be set by the application, or SQLSTATE HY010
(Function sequence error) will be returned when SQL AllocHandle is called to allocate a connection handle.
For standards-compliant applications, SQL AllocHandle is mapped to SQL AllocHandleStd at compile time.
The difference between these two functions is that SQL AllocHandleStd sets the SQL_ATTR_ODBC_VERSION
environment attribute to SQL_OV_ODBC3 when it is called with the HandleType argument set to
SQL_HANDLE_ENV. This is done because standards-compliant applications are always ODBC 3.x applications.
Moreover, the standards do not require the application version to be registered. This is the only difference
between these two functions; otherwise, they are identical. SQL AllocHandleStd is mapped to
SQL AllocHandle inside the driver manager. Therefore, third-party drivers do not have to implement
SQL AllocHandleStd .
ODBC 3.8 applications should use:
SQL AllocHandle and not SQL AllocHandleStd to allocate an environment handle.
SQLSetEnvAttr to set the SQL_ATTR_ODBC_VERSION environment attribute to SQL_OV_ODBC3_80.

Allocating an Environment Handle


An environment handle provides access to global information such as valid connection handles and active
connection handles. For general information about environment handles, see Environment Handles.
To request an environment handle, an application calls SQL AllocHandle with a HandleType of
SQL_HANDLE_ENV and an InputHandle of SQL_NULL_HANDLE. The driver allocates memory for the
environment information and passes the value of the associated handle back in the *OutputHandlePtr
argument. The application passes the *OutputHandle value in all subsequent calls that require an environment
handle argument. For more information, see Allocating the Environment Handle.
Under a Driver Manager's environment handle, if there already exists a driver's environment handle, then
SQL AllocHandle with a HandleType of SQL_HANDLE_ENV is not called in that driver when a connection is
made, only SQL AllocHandle with a HandleType of SQL_HANDLE_DBC. If a driver's environment handle does
not exist under the Driver Manager's environment handle, both SQLAllocHandle with a HandleType of
SQL_HANDLE_ENV and SQLAllocHandle with a HandleType of SQL_HANDLE_DBC are called in the driver when
the first connection handle of the environment is connected to the driver.
When the Driver Manager processes the SQL AllocHandle function with a HandleType of SQL_HANDLE_ENV, it
checks the Trace keyword in the [ODBC] section of the system information. If it is set to 1, the Driver Manager
enables tracing for the current application. If the trace flag is set, tracing starts when the first environment
handle is allocated and ends when the last environment handle is freed. For more information, see Configuring
Data Sources.
After allocating an environment handle, an application must call SQLSetEnvAttr on the environment handle to
set the SQL_ATTR_ODBC_VERSION environment attribute. If this attribute is not set before SQL AllocHandle is
called to allocate a connection handle on the environment, the call to allocate the connection will return
SQLSTATE HY010 (Function sequence error). For more information, see Declaring the Application's ODBC
Version.

Allocating Shared Environments for Connection Pooling


Environments can be shared among multiple components on a single process. A shared environment can be
used by more than one component at the same time. When a component uses a shared environment, it can use
pooled connections, which allow it to allocate and use an existing connection without re-creating that
connection.
Before allocating a shared environment that can be used for connection pooling, an application must call
SQLSetEnvAttr to set the SQL_ATTR_CONNECTION_POOLING environment attribute to
SQL_CP_ONE_PER_DRIVER or SQL_CP_ONE_PER_HENV. SQLSetEnvAttr in this case is called with
EnvironmentHandle set to null, which makes the attribute a process-level attribute.
After connection pooling has been enabled, an application calls SQL AllocHandle with the HandleType
argument set to SQL_HANDLE_ENV. The environment allocated by this call will be an implicit shared
environment because connection pooling has been enabled.
When a shared environment is allocated, the environment that will be used is not determined until
SQL AllocHandle with a HandleType of SQL_HANDLE_DBC is called. At that point, the Driver Manager tries to
find an existing environment that matches the environment attributes requested by the application. If no such
environment exists, one is created as a shared environment. The Driver Manager maintains a reference count for
each shared environment; the count is set to 1 when the environment is first created. If a matching environment
is found, the handle of that environment is returned to the application and the reference count is incremented.
An environment handle allocated in this manner can be used in any ODBC function that accepts an environment
handle as an input argument.

Allocating a Connection Handle


A connection handle provides access to information such as the valid statement and descriptor handles on the
connection and whether a transaction is currently open. For general information about connection handles, see
Connection Handles.
To request a connection handle, an application calls SQL AllocHandle with a HandleType of SQL_HANDLE_DBC.
The InputHandle argument is set to the environment handle that was returned by the call to SQL AllocHandle
that allocated that handle. The driver allocates memory for the connection information and passes the value of
the associated handle back in *OutputHandlePtr. The application passes the *OutputHandlePtr value in all
subsequent calls that require a connection handle. For more information, see Allocating a Connection Handle.
The Driver Manager processes the SQL AllocHandle function and calls the driver's SQL AllocHandle function
when the application calls SQLConnect , SQLBrowseConnect , or SQLDriverConnect . (For more information,
see SQLConnect Function.)
If the SQL_ATTR_ODBC_VERSION environment attribute is not set before SQL AllocHandle is called to allocate
a connection handle on the environment, the call to allocate the connection will return SQLSTATE HY010
(Function sequence error).
When an application calls SQL AllocHandle with the InputHandle argument set to SQL_HANDLE_DBC and also
set to a shared environment handle, the Driver Manager tries to find an existing shared environment that
matches the environment attributes set by the application. If no such environment exists, one is created, with a
reference count (maintained by the Driver Manager) of 1. If a matching shared environment is found, that
handle is returned to the application and its reference count is incremented.
The actual connection that will be used is not determined by the Driver Manager until SQLConnect or
SQLDriverConnect is called. The Driver Manager uses the connection options in the call to SQLConnect (or
the connection keywords in the call to SQLDriverConnect ) and the connection attributes set after connection
allocation to determine which connection in the pool should be used. For more information, see SQLConnect
Function.

Allocating a Statement Handle


A statement handle provides access to statement information, such as error messages, the cursor name, and
status information for SQL statement processing. For general information about statement handles, see
Statement Handles.
To request a statement handle, an application connects to a data source and then calls SQL AllocHandle before
it submits SQL statements. In this call, HandleType should be set to SQL_HANDLE_STMT and InputHandle should
be set to the connection handle that was returned by the call to SQL AllocHandle that allocated that handle.
The driver allocates memory for the statement information, associates the statement handle with the specified
connection, and passes the value of the associated handle back in *OutputHandlePtr. The application passes the
*OutputHandlePtr value in all subsequent calls that require a statement handle. For more information, see
Allocating a Statement Handle.
When the statement handle is allocated, the driver automatically allocates a set of four descriptors and assigns
the handles for these descriptors to the SQL_ATTR_APP_ROW_DESC, SQL_ATTR_APP_PARAM_DESC,
SQL_ATTR_IMP_ROW_DESC, and SQL_ATTR_IMP_PARAM_DESC statement attributes. These are referred to as
implicitly allocated descriptors. To allocate an application descriptor explicitly, see the following section,
"Allocating a Descriptor Handle."

Allocating a Descriptor Handle


When an application calls SQL AllocHandle with a HandleType of SQL_HANDLE_DESC, the driver allocates an
application descriptor. These are referred to as explicitly allocated descriptors. The application directs a driver to
use an explicitly allocated application descriptor instead of an automatically allocated one for a given statement
handle by calling the SQLSetStmtAttr function with the SQL_ATTR_APP_ROW_DESC or
SQL_ATTR_APP_PARAM_DESC attribute. An implementation descriptor cannot be allocated explicitly, nor can an
implementation descriptor be specified in an SQLSetStmtAttr function call.
Explicitly allocated descriptors are associated with a connection handle instead of a statement handle (as
automatically allocated descriptors are). Descriptors remain allocated only when an application is actually
connected to the database. Because explicitly allocated descriptors are associated with a connection handle, an
application can associate an explicitly allocated descriptor with more than one statement within a connection. An
implicitly allocated application descriptor, on the other hand, cannot be associated with more than one
statement handle. (It cannot be associated with any statement handle other than the one that it was allocated
for.) Explicitly allocated descriptor handles can be freed explicitly either by the application or by calling
SQLFreeHandle with a HandleType of SQL_HANDLE_DESC, or implicitly when the connection is closed.
When the explicitly allocated descriptor is freed, the implicitly allocated descriptor is again associated with the
statement. (The SQL_ATTR_APP_ROW_DESC or SQL_ATTR_APP_PARAM_DESC attribute for that statement is
again set to the implicitly allocated descriptor handle.) This is true for all statements that were associated with
the explicitly allocated descriptor on the connection.
For more information about descriptors, see Descriptors.

Code Example
See Sample ODBC Program, SQLBrowseConnect Function, SQLConnect Function, and SQLSetCursorName
Function.

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Executing an SQL statement SQLExecDirect Function

Executing a prepared SQL statement SQLExecute Function

Freeing an environment, connection, statement, or SQLFreeHandle Function


descriptor handle

Preparing a statement for execution SQLPrepare Function

Setting a connection attribute SQLSetConnectAttr Function


F O R IN F O RM AT IO N A B O UT SEE

Setting a descriptor field SQLSetDescField Function

Setting an environment attribute SQLSetEnvAttr Function

Setting a statement attribute SQLSetStmtAttr Function

See Also
ODBC API Reference
ODBC Header Files
SQLAllocStmt Function
4/27/2022 • 2 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: Deprecated
Summar y
In ODBC 3.x, the ODBC 2.x function SQL AllocStmt has been replaced by SQL AllocHandle . For more
information, see SQLAllocHandle Function.

NOTE
For more information about what the Driver Manager maps this function to when an ODBC 2.x application is working
with an ODBC 3.x driver, see Mapping Deprecated Functions in Appendix G: Driver Guidelines for Backward Compatibility.

See Also
ODBC API Reference
ODBC Header Files
SQLBindCol Function
4/27/2022 • 20 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: ISO 92
Summar y
SQLBindCol binds application data buffers to columns in the result set.

Syntax
SQLRETURN SQLBindCol(
SQLHSTMT StatementHandle,
SQLUSMALLINT ColumnNumber,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLLEN BufferLength,
SQLLEN * StrLen_or_IndPtr);

Arguments
StatementHandle
[Input] Statement handle.
ColumnNumber
[Input] Number of the result set column to bind. Columns are numbered in increasing column order starting at
0, where column 0 is the bookmark column. If bookmarks are not used - that is, the
SQL_ATTR_USE_BOOKMARKS statement attribute is set to SQL_UB_OFF - then column numbers start at 1.
TargetType
[Input] The identifier of the C data type of the *TargetValuePtr buffer. When it is retrieving data from the data
source with SQLFetch , SQLFetchScroll , SQLBulkOperations , or SQLSetPos , the driver converts the data to
this type; when it sends data to the data source with SQLBulkOperations or SQLSetPos , the driver converts
the data from this type. For a list of valid C data types and type identifiers, see the C Data Types section in
Appendix D: Data Types.
If the TargetType argument is an interval data type, the default interval leading precision (2) and the default
interval seconds precision (6), as set in the SQL_DESC_DATETIME_INTERVAL_PRECISION and
SQL_DESC_PRECISION fields of the ARD, respectively, are used for the data. If the TargetType argument is
SQL_C_NUMERIC, the default precision (driver-defined) and default scale (0), as set in the
SQL_DESC_PRECISION and SQL_DESC_SCALE fields of the ARD, are used for the data. If any default precision or
scale is not appropriate, the application should explicitly set the appropriate descriptor field by a call to
SQLSetDescField or SQLSetDescRec .
You can also specify an extended C data type. For more information, see C Data Types in ODBC.
TargetValuePtr
[Deferred Input/Output] Pointer to the data buffer to bind to the column. SQLFetch and SQLFetchScroll
return data in this buffer. SQLBulkOperations returns data in this buffer when Operation is
SQL_FETCH_BY_BOOKMARK; it retrieves data from this buffer when Operation is SQL_ADD or
SQL_UPDATE_BY_BOOKMARK. SQLSetPos returns data in this buffer when Operation is SQL_REFRESH; it
retrieves data from this buffer when Operation is SQL_UPDATE.
If TargetValuePtr is a null pointer, the driver unbinds the data buffer for the column. An application can unbind all
columns by calling SQLFreeStmt with the SQL_UNBIND option. An application can unbind the data buffer for a
column but still have a length/indicator buffer bound for the column, if the TargetValuePtr argument in the call
to SQLBindCol is a null pointer but the StrLen_or_IndPtr argument is a valid value.
BufferLength
[Input] Length of the *TargetValuePtr buffer in bytes.
The driver uses BufferLength to avoid writing past the end of the *TargetValuePtr buffer when it returns
variable-length data, such as character or binary data. Notice that the driver counts the null-termination
character when it returns character data to *TargetValuePtr. *TargetValuePtr must therefore contain space for the
null-termination character or the driver will truncate the data.
When the driver returns fixed-length data, such as an integer or a date structure, the driver ignores BufferLength
and assumes the buffer is large enough to hold the data. Therefore, it is important for the application to allocate
a large enough buffer for fixed-length data or the driver will write past the end of the buffer.
SQLBindCol returns SQLSTATE HY090 (Invalid string or buffer length) when BufferLength is less than 0 but not
when BufferLength is 0. However, if TargetType specifies a character type, an application should not set
BufferLength to 0, because ISO CLI-compliant drivers return SQLSTATE HY090 (Invalid string or buffer length) in
that case.
StrLen_or_IndPtr
[Deferred Input/Output] Pointer to the length/indicator buffer to bind to the column. SQLFetch and
SQLFetchScroll return a value in this buffer. SQLBulkOperations retrieves a value from this buffer when
Operation is SQL_ADD, SQL_UPDATE_BY_BOOKMARK, or SQL_DELETE_BY_BOOKMARK. SQLBulkOperations
returns a value in this buffer when Operation is SQL_FETCH_BY_BOOKMARK. SQLSetPos returns a value in this
buffer when Operation is SQL_REFRESH; it retrieves a value from this buffer when Operation is SQL_UPDATE.
SQLFetch , SQLFetchScroll , SQLBulkOperations , and SQLSetPos can return the following values in the
length/indicator buffer:
The length of the data available to return
SQL_NO_TOTAL
SQL_NULL_DATA
The application can put the following values in the length/indicator buffer for use with SQLBulkOperations or
SQLSetPos :
The length of the data being sent
SQL_NTS
SQL_NULL_DATA
SQL_DATA_AT_EXEC
The result of the SQL_LEN_DATA_AT_EXEC macro
SQL_COLUMN_IGNORE
If the indicator buffer and the length buffer are separate buffers, the indicator buffer can return only
SQL_NULL_DATA, whereas the length buffer can return all other values.
For more information, see SQLBulkOperations Function, SQLFetch Function, SQLSetPos Function, and Using
Length/Indicator Values.
If StrLen_or_IndPtr is a null pointer, no length or indicator value is used. This is an error when fetching data and
the data is NULL.
See ODBC 64-Bit Information, if your application will run on a 64-bit operating system.

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLBindCol returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value can be
obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a Handle of
StatementHandle. The following table lists the SQLSTATE values typically returned by SQLBindCol and explains
each one in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs returned by
the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless noted
otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

07006 Restricted data type attribute violation (DM) The ColumnNumber argument
was 0, and the TargetType argument
was not SQL_C_BOOKMARK or
SQL_C_VARBOOKMARK.

07009 Invalid descriptor index The value specified for the argument
ColumnNumber exceeded the
maximum number of columns in the
result set.

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.

HY001 Memory allocation error The driver was unable to allocate


memory that is required to support
execution or completion of the
function.

HY003 Invalid application buffer type The argument TargetType was neither
a valid data type nor SQL_C_DEFAULT.
SQ L STAT E ERRO R DESC RIP T IO N

HY010 Function sequence error (DM) An asynchronously executing


function was called for the connection
handle that is associated with the
StatementHandle. This asynchronous
function was still executing when
SQLBindCol was called.

(DM) SQLExecute , SQLExecDirect ,


or SQLMoreResults was called for
the StatementHandle and returned
SQL_PARAM_DATA_AVAILABLE. This
function was called before data was
retrieved for all streamed parameters.

(DM) An asynchronously executing


function was called for the
StatementHandle and was still
executing when this function was
called.

(DM) SQLExecute , SQLExecDirect ,


SQLBulkOperations , or SQLSetPos
was called for the StatementHandle
and returned SQL_NEED_DATA. This
function was called before data was
sent for all data-at-execution
parameters or columns.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY090 Invalid string or buffer length (DM) The value specified for the
argument BufferLength was less than
0.

(DM) The driver was an ODBC 2.x


driver, the ColumnNumber argument
was set to 0, and the value specified
for the argument BufferLength was
not equal to 4.

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.
SQ L STAT E ERRO R DESC RIP T IO N

HYC00 Optional feature not implemented The driver or data source does not
support the conversion specified by
the combination of the TargetType
argument and the driver-specific SQL
data type of the corresponding
column.

The argument ColumnNumber was 0


and the driver does not support
bookmarks.

The driver supports only ODBC 2.x


and the argument TargetType was one
of the following:

SQL_C_NUMERIC SQL_C_SBIGINT
SQL_C_UBIGINT

and any of the interval C data types


listed in C Data Types in Appendix D:
Data Types.

The driver only supports ODBC


versions prior to 3.50, and the
argument TargetType was
SQL_C_GUID.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
StatementHandle does not support
the function.

Comments
SQLBindCol is used to associate, or bind, columns in the result set to data buffers and length/indicator buffers
in the application. When the application calls SQLFetch , SQLFetchScroll , or SQLSetPos to fetch data, the
driver returns the data for the bound columns in the specified buffers; for more information, see SQLFetch
Function. When the application calls SQLBulkOperations to update or insert a row or SQLSetPos to update a
row, the driver retrieves the data for the bound columns from the specified buffers; for more information, see
SQLBulkOperations Function or SQLSetPos Function. For more information about binding, see Retrieving
Results (Basic).
Notice that columns do not have to be bound to retrieve data from them. An application can also call
SQLGetData to retrieve data from columns. Although it is possible to bind some columns in a row and call
SQLGetData for others, this is subject to some restrictions. For more information, see SQLGetData.

Binding, Unbinding, and Rebinding Columns


A column can be bound, unbound, or rebound at any time, even after data has been fetched from the result set.
The new binding takes effect the next time that a function that uses bindings is called. For example, suppose an
application binds the columns in a result set and calls SQLFetch . The driver returns the data in the bound
buffers. Now suppose the application binds the columns to a different set of buffers. The driver does not put the
data for the just-fetched row in the newly bound buffers. Instead, it waits until SQLFetch is called again and
then places the data for the next row in the newly bound buffers.

NOTE
The statement attribute SQL_ATTR_USE_BOOKMARKS should always be set before binding a column to column 0. This is
not required but is strongly recommended.

Binding Columns
To bind a column, an application calls SQLBindCol and passes the column number, type, address, and length of
a data buffer, and the address of a length/indicator buffer. For information about how these addresses are used,
see "Buffer Addresses," later in this section. For more information about binding columns, see Using
SQLBindCol.
The use of these buffers is deferred; that is, the application binds them in SQLBindCol but the driver accesses
them from other functions - namely SQLBulkOperations , SQLFetch , SQLFetchScroll , or SQLSetPos . It is
the application's responsibility to make sure that the pointers specified in SQLBindCol remain valid as long as
the binding remains in effect. If the application allows these pointers to become invalid - for example, it frees a
buffer - and then calls a function that expects them to be valid, the consequences are undefined. For more
information, see Deferred Buffers.
The binding remains in effect until it is replaced by a new binding, the column is unbound, or the statement is
freed.

Unbinding Columns
To unbind a single column, an application calls SQLBindCol with ColumnNumber set to the number of that
column and TargetValuePtr set to a null pointer. If ColumnNumber refers to an unbound column, SQLBindCol
still returns SQL_SUCCESS.
To unbind all columns, an application calls SQLFreeStmt with fOption set to SQL_UNBIND. This can also be
accomplished by setting the SQL_DESC_COUNT field of the ARD to zero.

Rebinding Columns
An application can perform either of two operations to change a binding:
Call SQLBindCol to specify a new binding for a column that is already bound. The driver overwrites the
old binding with the new one.
Specify an offset to be added to the buffer address that was specified by the binding call to SQLBindCol .
For more information, see the next section, "Binding Offsets."

Binding Offsets
A binding offset is a value that is added to the addresses of the data and length/indicator buffers (as specified in
the TargetValuePtr and StrLen_or_IndPtr argument) before they are dereferenced. When offsets are used, the
bindings are a "template" of how the application's buffers are laid out, and the application can move this
"template" to different areas of memory by changing the offset. Because the same offset is added to each
address in each binding, the relative offsets between buffers for different columns must be the same within each
set of buffers. This is always true when row-wise binding is used; the application must carefully lay out its
buffers for this to be true when column-wise binding is used.
Using a binding offset has basically the same effect as rebinding a column by calling SQLBindCol . The
difference is that a new call to SQLBindCol specifies new addresses for the data buffer and length/indicator
buffer, whereas use of a binding offset does not change the addresses but just adds an offset to them. The
application can specify a new offset whenever it wants, and this offset is always added to the originally bound
addresses. In particular, if the offset is set to 0 or if the statement attribute is set to a null pointer, the driver uses
the originally bound addresses.
To specify a binding offset, the application sets the SQL_ATTR_ROW_BIND_OFFSET_PTR statement attribute to
the address of an SQLINTEGER buffer. Before the application calls a function that uses bindings, it puts an offset
in bytes in this buffer. To determine the address of the buffer to use, the driver adds the offset to the address in
the binding. The sum of the address and the offset must be a valid address, but the address to which the offset is
added does not have to be valid. For more information about how binding offsets are used, see "Buffer
Addresses," later in this section.

Binding Arrays
If the rowset size (the value of the SQL_ATTR_ROW_ARRAY_SIZE statement attribute) is greater than 1, the
application binds arrays of buffers instead of single buffers. For more information, see Block Cursors.
The application can bind arrays in two ways:
Bind an array to each column. This is referred to as column-wise binding because each data structure
(array) contains data for a single column.
Define a structure to hold the data for a whole row and bind an array of these structures. This is referred
to as row-wise binding because each data structure contains the data for a single row.
Each array of buffers must have at least as many elements as the size of the rowset.

NOTE
An application must verify that alignment is valid. For more information about alignment considerations, see Alignment.

Column-Wise Binding
In column-wise binding, the application binds separate data and length/indicator arrays to each column.
To use column-wise binding, the application first sets the SQL_ATTR_ROW_BIND_TYPE statement attribute to
SQL_BIND_BY_COLUMN. (This is the default.) For each column to be bound, the application performs the
following steps:
1. Allocates a data buffer array.
2. Allocates an array of length/indicator buffers.

NOTE
If the application writes directly to descriptors when column-wise binding is used, separate arrays can be used for
length and indicator data.

3. Calls SQLBindCol with the following arguments:


TargetType is the type of a single element in the data buffer array.
TargetValuePtr is the address of the data buffer array.
BufferLength is the size of a single element in the data buffer array. The BufferLength argument is
ignored when the data is fixed-length data.
StrLen_or_IndPtr is the address of the length/indicator array.
For more information about how this information is used, see "Buffer Addresses," later in this section. For more
information about column-wise binding, see Column-Wise Binding.

Row-Wise Binding
In row-wise binding, the application defines a structure that contains data and length/indicator buffers for each
column to be bound.
To use row-wise binding, the application performs the following steps:
1. Defines a structure to hold a single row of data (including both data and length/indicator buffers) and
allocates an array of these structures.

NOTE
If the application writes directly to descriptors when row-wise binding is used, separate fields can be used for
length and indicator data.

2. Sets the SQL_ATTR_ROW_BIND_TYPE statement attribute to the size of the structure that contains a single
row of data or to the size of an instance of a buffer into which the results columns will be bound. The
length must include space for all the bound columns, and any padding of the structure or buffer, to make
sure that when the address of a bound column is incremented with the specified length, the result will
point to the beginning of the same column in the next row. When using the sizeof operator in ANSI C, this
behavior is guaranteed.
3. Calls SQLBindCol with the following arguments for each column to be bound:
TargetType is the type of the data buffer member to be bound to the column.
TargetValuePtr is the address of the data buffer member in the first array element.
BufferLength is the size of the data buffer member.
StrLen_or_IndPtr is the address of the length/indicator member to be bound.
For more information about how this information is used, see "Buffer Addresses," later in this section. For more
information about column-wise binding, see Row-Wise Binding.

Buffer Addresses
The buffer address is the actual address of the data or length/indicator buffer. The driver calculates the buffer
address just before it writes to the buffers (such as during fetch time). It is calculated from the following formula,
which uses the addresses specified in the TargetValuePtr and StrLen_or_IndPtr arguments, the binding offset,
and the row number:
Bound Address + Binding Offset + ((Row Number - 1) x Element Size)
where the formula's variables are defined as described in the following table.

VA RIA B L E DESC RIP T IO N


VA RIA B L E DESC RIP T IO N

Bound Address For data buffers, the address specified with the
TargetValuePtr argument in SQLBindCol.

For length/indicator buffers, the address specified with the


StrLen_or_IndPtr argument in SQLBindCol. For more
information, see "Additional Comments" in the "Descriptors
and SQLBindCol" section.

If the bound address is 0, no data value is returned, even if


the address as calculated by the previous formula is nonzero.

Binding Offset If row-wise binding is used, the value stored at the address
specified with the SQL_ATTR_ROW_BIND_OFFSET_PTR
statement attribute.

If column-wise binding is used or if the value of the


SQL_ATTR_ROW_BIND_OFFSET_PTR statement attribute is a
null pointer, Binding Offset is 0.

Row Number The 1-based number of the row in the rowset. For single-
row fetches, which are the default, this is 1.

Element Size The size of an element in the bound array.

If column-wise binding is used, this is sizeof(SQLINTEGER)


for length/indicator buffers. For data buffers, it is the value of
the BufferLength argument in SQLBindCol if the data type
is variable length, and the size of the data type if the data
type is fixed length.

If row-wise binding is used, this is the value of the


SQL_ATTR_ROW_BIND_TYPE statement attribute for both
data and length/indicator buffers.

Descriptors and SQLBindCol


The following sections describe how SQLBindCol interacts with descriptors.
Cau t i on

Calling SQLBindCol for one statement can affect other statements. This occurs when the ARD associated with
the statement is explicitly allocated and is also associated with other statements. Because SQLBindCol modifies
the descriptor, the modifications apply to all statements with which this descriptor is associated. If this is not the
required behavior, the application should dissociate this descriptor from the other statements before it calls
SQLBindCol .

Argument Mappings
Conceptually, SQLBindCol performs the following steps in sequence:
1. Calls SQLGetStmtAttr to obtain the ARD handle.
2. Calls SQLGetDescField to get this descriptor's SQL_DESC_COUNT field, and if the value in the
ColumnNumber argument exceeds the value of SQL_DESC_COUNT, calls SQLSetDescField to increase
the value of SQL_DESC_COUNT to ColumnNumber.
3. Calls SQLSetDescField multiple times to assign values to the following fields of the ARD:
Sets SQL_DESC_TYPE and SQL_DESC_CONCISE_TYPE to the value of TargetType, except that if
TargetType is one of the concise identifiers of a datetime or interval subtype, it sets
SQL_DESC_TYPE to SQL_DATETIME or SQL_INTERVAL, respectively; sets
SQL_DESC_CONCISE_TYPE to the concise identifier; and sets
SQL_DESC_DATETIME_INTERVAL_CODE to the corresponding datetime or interval subcode.
Sets one or more of SQL_DESC_LENGTH, SQL_DESC_PRECISION, SQL_DESC_SCALE, and
SQL_DESC_DATETIME_INTERVAL_PRECISION, as appropriate for TargetType.
Sets the SQL_DESC_OCTET_LENGTH field to the value of BufferLength.
Sets the SQL_DESC_DATA_PTR field to the value of TargetValuePtr.
Sets the SQL_DESC_INDICATOR_PTR field to the value of StrLen_or_IndPtr. (See the following
paragraph.)
Sets the SQL_DESC_OCTET_LENGTH_PTR field to the value of StrLen_or_IndPtr. (See the following
paragraph.)
The variable that the StrLen_or_IndPtr argument refers to is used for both indicator and length information. If a
fetch encounters a null value for the column, it stores SQL_NULL_DATA in this variable; otherwise, it stores the
data length in this variable. Passing a null pointer as StrLen_or_IndPtr keeps the fetch operation from returning
the data length but makes the fetch fail if it encounters a null value and has no way to return SQL_NULL_DATA.
If the call to SQLBindCol fails, the content of the descriptor fields that it would have set in the ARD are
undefined and the value of the SQL_DESC_COUNT field of the ARD is unchanged.

Implicit Resetting of COUNT Field


SQLBindCol sets SQL_DESC_COUNT to the value of the ColumnNumber argument only when this would
increase the value of SQL_DESC_COUNT. If the value in the TargetValuePtr argument is a null pointer and the
value in the ColumnNumber argument is equal to SQL_DESC_COUNT (that is, when unbinding the highest
bound column), then SQL_DESC_COUNT is set to the number of the highest remaining bound column.

Cautions Regarding SQL_DEFAULT


To retrieve column data successfully, the application must determine correctly the length and starting point of
the data in the application buffer. When the application specifies an explicit TargetType, application
misconceptions are easily detected. However, when the application specifies a TargetType of SQL_DEFAULT,
SQLBindCol can be applied to a column of a different data type from the one intended by the application,
either from changes to the metadata or by applying the code to a different column. In this case, the application
may not always determine the start or length of the fetched column data. This may lead to unreported data
errors or memory violations.

Code Example
In the following example, an application executes a SELECT statement on the Customers table to return a result
set of the customer IDs, names, and phone numbers, sorted by name. It then calls SQLBindCol to bind the
columns of data to local buffers. Finally, the application fetches each row of data with SQLFetch and prints each
customer's name, ID, and phone number.
For more code examples, see SQLBulkOperations Function, SQLColumns Function, SQLFetchScroll Function, and
SQLSetPos Function.

// SQLBindCol_ref.cpp
// compile with: odbc32.lib
#include <windows.h>
#include <windows.h>
#include <stdio.h>

#define UNICODE
#include <sqlext.h>

#define NAME_LEN 50
#define PHONE_LEN 60

void show_error() {
printf("error\n");
}

int main() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt = 0;
SQLRETURN retcode;
SQLWCHAR szName[NAME_LEN], szPhone[PHONE_LEN], sCustID[NAME_LEN];
SQLLEN cbName = 0, cbCustID = 0, cbPhone = 0;

// Allocate environment handle


retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

// Set the ODBC version environment attribute


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);

// Allocate connection handle


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

// Set login timeout to 5 seconds


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

// Connect to data source


retcode = SQLConnect(hdbc, (SQLWCHAR*) L"NorthWind", SQL_NTS, (SQLWCHAR*) NULL, 0, NULL, 0);

// Allocate statement handle


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

retcode = SQLExecDirect(hstmt, (SQLWCHAR *) L"SELECT CustomerID, ContactName, Phone FROM


CUSTOMERS ORDER BY 2, 1, 3", SQL_NTS);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

// Bind columns 1, 2, and 3


retcode = SQLBindCol(hstmt, 1, SQL_C_WCHAR, &sCustID, 100, &cbCustID);
retcode = SQLBindCol(hstmt, 2, SQL_C_WCHAR, szName, NAME_LEN, &cbName);
retcode = SQLBindCol(hstmt, 3, SQL_C_WCHAR, szPhone, PHONE_LEN, &cbPhone);

// Fetch and print each row of data. On an error, display a message and exit.
for (int i=0 ; ; i++) {
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
show_error();
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
//replace wprintf with printf
//%S with %ls
//warning C4477: 'wprintf' : format string '%S' requires an argument of type 'char
*'
//but variadic argument 2 has type 'SQLWCHAR *'
//wprintf(L"%d: %S %S %S\n", i + 1, sCustID, szName, szPhone);
printf("%d: %ls %ls %ls\n", i + 1, sCustID, szName, szPhone);
}
else
break;
}
}
}

// Process data
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLCancel(hstmt);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}

SQLDisconnect(hdbc);
}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
}

Also see, Sample ODBC Program.

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Returning information about a column in a result set SQLDescribeCol Function

Fetching a block of data or scrolling through a result set SQLFetchScroll Function

Fetching multiple rows of data SQLFetch Function

Releasing column buffers on the statement SQLFreeStmt Function

Fetching part or all of a column of data SQLGetData Function

Returning the number of result set columns SQLNumResultCols Function

See Also
ODBC API Reference
ODBC Header Files
SQLBindParameter Function
4/27/2022 • 40 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 2.0 Standards Compliance: ODBC
Summar y
SQLBindParameter binds a buffer to a parameter marker in an SQL statement. SQLBindParameter supports
binding to a Unicode C data type, even if the underlying driver does not support Unicode data.

NOTE
This function replaces the ODBC 1.0 function SQLSetParam . For more information, see "Comments."

Syntax
SQLRETURN SQLBindParameter(
SQLHSTMT StatementHandle,
SQLUSMALLINT ParameterNumber,
SQLSMALLINT InputOutputType,
SQLSMALLINT ValueType,
SQLSMALLINT ParameterType,
SQLULEN ColumnSize,
SQLSMALLINT DecimalDigits,
SQLPOINTER ParameterValuePtr,
SQLLEN BufferLength,
SQLLEN * StrLen_or_IndPtr);

Arguments
StatementHandle
[Input] Statement handle.
ParameterNumber
[Input] Parameter number, ordered sequentially in increasing parameter order, starting at 1.
InputOutputType
[Input] The type of the parameter. For more information, see "InputOutputType Argument" in "Comments."
ValueType
[Input] The C data type of the parameter. For more information, see "ValueType Argument" in "Comments."
ParameterType
[Input] The SQL data type of the parameter. For more information, see "ParameterType Argument" in
"Comments."
ColumnSize
[Input] The size of the column or expression of the corresponding parameter marker. For more information, see
"ColumnSize Argument" in "Comments."
If your application will run on a 64-bit Windows operating system, see ODBC 64-Bit Information.
DecimalDigits
[Input] The decimal digits of the column or expression of the corresponding parameter marker. For more
information about column size, see Column Size, Decimal Digits, Transfer Octet Length, and Display Size.
ParameterValuePtr
[Deferred Input] A pointer to a buffer for the parameter's data. For more information, see "ParameterValuePtr
Argument" in "Comments."
BufferLength
[Input/Output] Length of the ParameterValuePtr buffer in bytes. For more information, see "BufferLength
Argument" in "Comments."
See ODBC 64-Bit Information, if your application will run on a 64-bit operating system.
StrLen_or_IndPtr
[Deferred Input] A pointer to a buffer for the parameter's length. For more information, see "StrLen_or_IndPtr
Argument" in "Comments."

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLBindParameter returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value
can be obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a Handle of
StatementHandle. The following table lists the SQLSTATE values typically returned by SQLBindParameter and
explains each one in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs
returned by the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless
noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

07006 Restricted data type attribute violation The data type identified by the
ValueType argument cannot be
converted to the data type identified
by the ParameterType argument.
Notice that this error may be returned
by SQLExecDirect , SQLExecute , or
SQLPutData at execution time,
instead of by SQLBindParameter .

07009 Invalid descriptor index (DM) The value specified for the
argument ParameterNumber was less
than 1.

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.
SQ L STAT E ERRO R DESC RIP T IO N

HY001 Memory allocation error The driver was unable to allocate


memory that is required to support
execution or completion of the
function.

HY003 Invalid application buffer type The value specified by the argument
ValueType was not a valid C data type
or SQL_C_DEFAULT.

HY004 Invalid SQL data type The value specified for the argument
ParameterType was neither a valid
ODBC SQL data type identifier nor a
driver-specific SQL data type identifier
supported by the driver.

HY009 Invalid argument value (DM) The argument ParameterValuePtr


was a null pointer, the argument
StrLen_or_IndPtr was a null pointer,
and the argument InputOutputType
was not SQL_PARAM_OUTPUT.

(DM) SQL_PARAM_OUTPUT, where the


argument ParameterValuePtr was a
null pointer, the C type was char or
binary, and the BufferLength
(cbValueMax) was greater than 0.

HY010 Function sequence error (DM) An asynchronously executing


function was called for the connection
handle that is associated with the
StatementHandle. This asynchronous
function was still executing when
SQLBindParameter was called.

(DM) SQLExecute , SQLExecDirect ,


or SQLMoreResults was called for
the StatementHandle and returned
SQL_PARAM_DATA_AVAILABLE. This
function was called before data was
retrieved for all streamed parameters.

(DM) An asynchronously executing


function was called for the
StatementHandle and was still
executing when this function was
called.

(DM) SQLExecute , SQLExecDirect ,


SQLBulkOperations , or SQLSetPos
was called for the StatementHandle
and returned SQL_NEED_DATA. This
function was called before data was
sent for all data-at-execution
parameters or columns.
SQ L STAT E ERRO R DESC RIP T IO N

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY021 Inconsistent descriptor information The descriptor information checked


during a consistency check was not
consistent. (See the "Consistency
Checks" section in SQLSetDescField .)

The value specified for the argument


DecimalDigits was outside the range of
values supported by the data source
for a column of the SQL data type
specified by the ParameterType
argument.

HY090 Invalid string or buffer length (DM) The value in BufferLength was
less than 0. (See the description of the
SQL_DESC_DATA_PTR field in
SQLSetDescField .)

HY104 Invalid precision or scale value The value specified for the argument
ColumnSize or DecimalDigits was
outside the range of values supported
by the data source for a column of the
SQL data type specified by the
ParameterType argument.

HY105 Invalid parameter type (DM) The value specified for the
argument InputOutputType was
invalid. (See "Comments.")

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.
SQ L STAT E ERRO R DESC RIP T IO N

HYC00 Optional feature not implemented The driver or data source does not
support the conversion specified by
the combination of the value specified
for the argument ValueType and the
driver-specific value specified for the
argument ParameterType.

The value specified for the argument


ParameterType was a valid ODBC SQL
data type identifier for the version of
ODBC supported by the driver but
was not supported by the driver or
data source.

The driver supports only ODBC 2.x


and the argument ValueType was one
of the following:

SQL_C_NUMERIC SQL_C_SBIGINT
SQL_C_UBIGINT

and all the interval C data types listed


in C Data Types in Appendix D: Data
Types.

The driver only supports ODBC


versions prior to 3.50, and the
argument ValueType was SQL_C_GUID.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
StatementHandle does not support
the function.

Comments
An application calls SQLBindParameter to bind each parameter marker in an SQL statement. Bindings remain
in effect until the application calls SQLBindParameter again, calls SQLFreeStmt with the
SQL_RESET_PARAMS option, or calls SQLSetDescField to set the SQL_DESC_COUNT header field of the APD to
0.
For more information about parameters, see Statement Parameters. For more information about parameter data
types and parameter markers, see Parameter Data Types and Parameter Markers in Appendix C: SQL Grammar.

ParameterNumber Argument
If ParameterNumber in the call to SQLBindParameter is greater than the value of SQL_DESC_COUNT,
SQLSetDescField is called to increase the value of SQL_DESC_COUNT to ParameterNumber.

InputOutputType Argument
The InputOutputType argument specifies the type of the parameter. This argument sets the
SQL_DESC_PARAMETER_TYPE field of the IPD. All parameters in SQL statements that do not call procedures,
such as INSERT statements, are input parameters. Parameters in procedure calls can be input, input/output, or
output parameters. (An application calls SQLProcedureColumns to determine the type of a parameter in a
procedure call; parameters whose type cannot be determined are assumed to be input parameters.)
The InputOutputType argument is one of the following values:
SQL_PARAM_INPUT. The parameter marks a parameter in an SQL statement that does not call a
procedure, such as an INSERT statement, or it marks an input parameter in a procedure. For example, the
parameters in INSERT INTO Employee VALUES (?, ?, ?) are input parameters, whereas the
parameters in {call AddEmp(?, ?, ?)} can be, but are not necessarily, input parameters.
When the statement is executed, the driver sends data for the parameter to the data source; the
*ParameterValuePtr buffer must contain a valid input value, or the *StrLen_or_IndPtr buffer must contain
SQL_NULL_DATA, SQL_DATA_AT_EXEC, or the result of the SQL_LEN_DATA_AT_EXEC macro.
If an application cannot determine the type of a parameter in a procedure call, it sets InputOutputType to
SQL_PARAM_INPUT; if the data source returns a value for the parameter, the driver discards it.
SQL_PARAM_INPUT_OUTPUT. The parameter marks an input/output parameter in a procedure. For
example, the parameter in {call GetEmpDept(?)} is an input/output parameter that accepts an
employee's name and returns the name of the employee's department.
When the statement is executed, the driver sends data for the parameter to the data source; the
*ParameterValuePtr buffer must contain a valid input value, or the *StrLen_or_IndPtr buffer must contain
SQL_NULL_DATA, SQL_DATA_AT_EXEC, or the result of the SQL_LEN_DATA_AT_EXEC macro. After the
statement is executed, the driver returns data for the parameter to the application; if the data source does
not return a value for an input/output parameter, the driver sets the *StrLen_or_IndPtr buffer to
SQL_NULL_DATA.

NOTE
When an ODBC 1.0 application calls SQLSetParam in an ODBC 2.0 driver, the Driver Manager converts this to a
call to SQLBindParameter in which the InputOutputType argument is set to SQL_PARAM_INPUT_OUTPUT.

SQL_PARAM_OUTPUT. The parameter marks the return value of a procedure or an output parameter in a
procedure; in either case, these are known as output parameters. For example, the parameter in {?=call
GetNextEmpID} is an output parameter that returns the next employee ID.
After the statement is executed, the driver returns data for the parameter to the application, unless the
ParameterValuePtr and StrLen_or_IndPtr arguments are both null pointers, in which case the driver
discards the output value. If the data source does not return a value for an output parameter, the driver
sets the *StrLen_or_IndPtr buffer to SQL_NULL_DATA.
SQL_PARAM_INPUT_OUTPUT_STREAM. Indicates that an input/output parameter should be streamed.
SQLGetData can read parameter values in parts. BufferLength is ignored because the buffer length will
be determined at the call of SQLGetData . The value of the StrLen_or_IndPtr buffer must contain
SQL_NULL_DATA, SQL_DEFAULT_PARAM, SQL_DATA_AT_EXEC, or the result of the
SQL_LEN_DATA_AT_EXEC macro. A parameter must be bound as a data-at-execution (DAE) parameter at
input if it will be streamed at output. ParameterValuePtr can be any non-null pointer value that will be
returned by SQLParamData as the user-defined token whose value was passed with ParameterValuePtr
for both input and output. For more information, see Retrieving Output Parameters Using SQLGetData.
SQL_PARAM_OUTPUT_STREAM. Same as SQL_PARAM_INPUT_OUTPUT_STREAM, for an output
parameter. *StrLen_or_IndPtr is ignored at input.
The following table lists different combinations of InputOutputType and *StrLen_or_IndPtr:

REM A RK O N
IN P UTO UT P UT T Y P E * ST RL EN _O R_IN DP T R O UTC O M E PA RA M ET ERVA L UEP T R

SQL_PARAM_INPUT SQL_LEN_DATA_AT_EXEC(le Input in parts ParameterValuePtr can be


n) or SQL_DATA_AT_EXEC any pointer value that will
be returned by
SQLParamData as the
user-defined token whose
value was passed with
ParameterValuePtr.

SQL_PARAM_INPUT Not Input bound buffer ParameterValuePtr is the


SQL_LEN_DATA_AT_EXEC(le address of the input buffer.
n) or SQL_DATA_AT_EXEC

SQL_PARAM_OUTPUT Ignored at input. Output bound buffer ParameterValuePtr is the


address of the output
buffer.

SQL_PARAM_OUTPUT_STRE Ignored at input. Streamed output ParameterValuePtr can be


AM any pointer value, which will
be returned by
SQLParamData as the
user-defined token whose
value was passed with
ParameterValuePtr.

SQL_PARAM_INPUT_OUTP SQL_LEN_DATA_AT_EXEC(le Input in parts and output ParameterValuePtr is the


UT n) or SQL_DATA_AT_EXEC bound buffer address of the output
buffer, which will also be
returned by
SQLParamData as the
user-defined token whose
value was passed with
ParameterValuePtr.

SQL_PARAM_INPUT_OUTP Not Input bound buffer and ParameterValuePtr is the


UT SQL_LEN_DATA_AT_EXEC(le output bound buffer address of the shared
n) or SQL_DATA_AT_EXEC input/output buffer.

SQL_PARAM_INPUT_OUTP SQL_LEN_DATA_AT_EXEC(le Input in parts and streamed ParameterValuePtr can be


UT_STREAM n) or SQL_DATA_AT_EXEC output any non-null pointer value,
which will be returned by
SQLParamData as the
user-defined token whose
value was passed with
ParameterValuePtr for both
input and output.

NOTE
The driver must decide which SQL types are allowed when an application binds an output or input-output parameter as
streamed. The driver manager will not generate an error for an invalid SQL type.

ValueType Argument
The ValueType argument specifies the C data type of the parameter. This argument sets the SQL_DESC_TYPE,
SQL_DESC_CONCISE_TYPE, and SQL_DESC_DATETIME_INTERVAL_CODE fields of the APD. This must be one of
the values in the C Data Types section of Appendix D: Data Types.
If the ValueType argument is one of the interval data types, the SQL_DESC_TYPE field of the ParameterNumber
record of the APD is set to SQL_INTERVAL, the SQL_DESC_CONCISE_TYPE field of the APD is set to the concise
interval data type, and the SQL_DESC_DATETIME_INTERVAL_CODE field of the ParameterNumber record is set
to a subcode for the specific interval data type. (See Appendix D: Data Types.) The default interval leading
precision (2) and default interval seconds precision (6), as set in the
SQL_DESC_DATETIME_INTERVAL_PRECISION and SQL_DESC_PRECISION fields of the APD, respectively, are
used for the data. If either default precision is not appropriate, the application should explicitly set the descriptor
field by a call to SQLSetDescField or SQLSetDescRec .
If the ValueType argument is one of the datetime data types, the SQL_DESC_TYPE field of the ParameterNumber
record of the APD is set to SQL_DATETIME, the SQL_DESC_CONCISE_TYPE field of the ParameterNumber record
of the APD is set to the concise datetime C data type, and the SQL_DESC_DATETIME_INTERVAL_CODE field of the
ParameterNumber record is set to a subcode for the specific datetime data type. (See Appendix D: Data Types.)
If the ValueType argument is an SQL_C_NUMERIC data type, the default precision (which is driver-defined) and
the default scale (0), as set in the SQL_DESC_PRECISION and SQL_DESC_SCALE fields of the APD, are used for
the data. If the default precision or scale is not appropriate, the application should explicitly set the descriptor
field by a call to SQLSetDescField or SQLSetDescRec .
SQL_C_DEFAULT specifies that the parameter value be transferred from the default C data type for the SQL data
type specified with ParameterType.
You can also specify an extended C data type. For more information, see C Data Types in ODBC.
For more information, see Default C Data Types, Converting Data from C to SQL Data Types, and Converting
Data from SQL to C Data Types in Appendix D: Data Types.

ParameterType Argument
This must be one of the values listed in the SQL Data Types section of Appendix D: Data Types, or it must be a
driver-specific value. This argument sets the SQL_DESC_TYPE, SQL_DESC_CONCISE_TYPE, and
SQL_DESC_DATETIME_INTERVAL_CODE fields of the IPD.
If the ParameterType argument is one of the datetime identifiers, the SQL_DESC_TYPE field of the IPD is set to
SQL_DATETIME, the SQL_DESC_CONCISE_TYPE field of the IPD is set to the concise datetime SQL data type, and
the SQL_DESC_DATETIME_INTERVAL_CODE field is set to the appropriate datetime subcode value.
If ParameterType is one of the interval identifiers, the SQL_DESC_TYPE field of the IPD is set to SQL_INTERVAL,
the SQL_DESC_CONCISE_TYPE field of the IPD is set to the concise SQL interval data type, and the
SQL_DESC_DATETIME_INTERVAL_CODE field of the IPD is set to the appropriate interval subcode. The
SQL_DESC_DATETIME_INTERVAL_PRECISION field of the IPD is set to the interval leading precision, and the
SQL_DESC_PRECISION field is set to the interval seconds precision, if applicable. If the default value of
SQL_DESC_DATETIME_INTERVAL_PRECISION or SQL_DESC_PRECISION is not appropriate, the application
should explicitly set it by calling SQLSetDescField . For more information about any of these fields, see
SQLSetDescField.
If the ValueType argument is a SQL_NUMERIC data type, the default precision (which is driver-defined) and the
default scale (0), as set in the SQL_DESC_PRECISION and SQL_DESC_SCALE fields of the IPD, are used for the
data. If the default precision or scale is not appropriate, the application should explicitly set the descriptor field
by a call to SQLSetDescField or SQLSetDescRec .
For information about how data is converted, see Converting Data from C to SQL Data Types and Converting
Data from SQL to C Data Types in Appendix D: Data Types.
ColumnSize Argument
The ColumnSize argument specifies the size of the column or expression that corresponds to the parameter
marker, the length of that data, or both. This argument sets different fields of the IPD, depending on the SQL data
type (the ParameterType argument). The following rules apply to this mapping:
If ParameterType is SQL_CHAR, SQL_VARCHAR, SQL_LONGVARCHAR, SQL_BINARY, SQL_VARBINARY,
SQL_LONGVARBINARY, or one of the concise SQL datetime or interval data types, the
SQL_DESC_LENGTH field of the IPD is set to the value of ColumnSize. (For more information, see the
Column Size, Decimal Digits, Transfer Octet Length, and Display Size section in Appendix D: Data Types.)
If ParameterType is SQL_DECIMAL, SQL_NUMERIC, SQL_FLOAT, SQL_REAL, or SQL_DOUBLE, the
SQL_DESC_PRECISION field of the IPD is set to the value of ColumnSize.
For other data types, the ColumnSize argument is ignored.
For more information, see "Passing Parameter Values" and SQL_DATA_AT_EXEC in "StrLen_or_IndPtr Argument."

DecimalDigits Argument
If ParameterType is SQL_TYPE_TIME, SQL_TYPE_TIMESTAMP, SQL_INTERVAL_SECOND,
SQL_INTERVAL_DAY_TO_SECOND, SQL_INTERVAL_HOUR_TO_SECOND, or
SQL_INTERVAL_MINUTE_TO_SECOND, the SQL_DESC_PRECISION field of the IPD is set to DecimalDigits. If
ParameterType is SQL_NUMERIC or SQL_DECIMAL, the SQL_DESC_SCALE field of the IPD is set to
DecimalDigits. For all other data types, the DecimalDigits argument is ignored.

ParameterValuePtr Argument
The ParameterValuePtr argument points to a buffer that, when SQLExecute or SQLExecDirect is called,
contains the actual data for the parameter. The data must be in the form specified by the ValueType argument.
This argument sets the SQL_DESC_DATA_PTR field of the APD. An application can set the ParameterValuePtr
argument to a null pointer, as long as *StrLen_or_IndPtr is SQL_NULL_DATA or SQL_DATA_AT_EXEC. (This applies
only to input or input/output parameters.)
If *StrLen_or_IndPtr is the result of the SQL_LEN_DATA_AT_EXEC(length) macro or SQL_DATA_AT_EXEC, then
ParameterValuePtr is an application-defined pointer value that is associated with the parameter. It is returned to
the application through SQLParamData . For example, ParameterValuePtr might be a non-zero token such as a
parameter number, a pointer to data, or a pointer to a structure that the application used to bind input
parameters. However, note that if the parameter is an input/output parameter, ParameterValuePtr must be a
pointer to a buffer where the output value will be stored. If the value in the SQL_ATTR_PARAMSET_SIZE
statement attribute is greater than 1, the application can use the value pointed to by the
SQL_ATTR_PARAMS_PROCESSED_PTR statement attribute together with the ParameterValuePtr argument. For
example, ParameterValuePtr might point to an array of values and the application might use the value pointed to
by SQL_ATTR_PARAMS_PROCESSED_PTR to retrieve the correct value from the array. For more information, see
"Passing Parameter Values" later in this section.
If the InputOutputType argument is SQL_PARAM_INPUT_OUTPUT or SQL_PARAM_OUTPUT, ParameterValuePtr
points to a buffer in which the driver returns the output value. If the procedure returns one or more result sets,
the *ParameterValuePtr buffer is not guaranteed to be set until all result sets/row counts have been processed. If
the buffer is not set until processing is complete, the output parameters and return values are unavailable until
SQLMoreResults returns SQL_NO_DATA. Calling SQLCloseCursor or SQLFreeStmt with an Option of
SQL_CLOSE will cause these values to be discarded.
If the value in the SQL_ATTR_PARAMSET_SIZE statement attribute is greater than 1, ParameterValuePtr points to
an array. A single SQL statement processes the complete array of input values for an input or input/output
parameter and returns an array of output values for an input/output or output parameter.

BufferLength Argument
For character and binary C data, the BufferLength argument specifies the length of the *ParameterValuePtr
buffer (if it is a single element) or the length of an element in the *ParameterValuePtr array (if the value in the
SQL_ATTR_PARAMSET_SIZE statement attribute is greater than 1). This argument sets the
SQL_DESC_OCTET_LENGTH record field of the APD. If the application specifies multiple values, BufferLength is
used to determine the location of values in the *ParameterValuePtr array, both on input and on output. For
input/output and output parameters, it is used to determine whether to truncate character and binary C data on
output:
For character C data, if the number of bytes available to return is greater than or equal to BufferLength,
the data in *ParameterValuePtr is truncated to BufferLength less the length of a null-termination
character and is null-terminated by the driver.
For binary C data, if the number of bytes available to return is greater than BufferLength, the data in
*ParameterValuePtr is truncated to BufferLength bytes.
For all other types of C data, the BufferLength argument is ignored. The length of the *ParameterValuePtr buffer
(if it is a single element) or the length of an element in the *ParameterValuePtr array (if the application calls
SQLSetStmtAttr with an Attribute argument of SQL_ATTR_PARAMSET_SIZE to specify multiple values for each
parameter) is assumed to be the length of the C data type.
For streamed output or streamed input/output parameters, the BufferLength argument is ignored because the
buffer length is specified in SQLGetData .

NOTE
When an ODBC 1.0 application calls SQLSetParam in an ODBC 3.x driver, the Driver Manager converts this to a call to
SQLBindParameter in which the BufferLength argument is always SQL_SETPARAM_VALUE_MAX. Because the Driver
Manager returns an error if an ODBC 3.x application sets BufferLength to SQL_SETPARAM_VALUE_MAX, an ODBC 3.x
driver can use this to determine when it is called by an ODBC 1.0 application.

NOTE
In SQLSetParam , the way in which an application specifies the length of the *ParameterValuePtr buffer so that the driver
can return character or binary data, and the way in which an application sends an array of character or binary parameter
values to the driver, are driver-defined.

StrLen_or_IndPtr Argument
The StrLen_or_IndPtr argument points to a buffer that, when SQLExecute or SQLExecDirect is called, contains
one of the following. (This argument sets the SQL_DESC_OCTET_LENGTH_PTR and SQL_DESC_INDICATOR_PTR
record fields of the application parameter pointers.)
The length of the parameter value stored in *ParameterValuePtr. This is ignored except for character or
binary C data.
SQL_NTS. The parameter value is a null-terminated string.
SQL_NULL_DATA. The parameter value is NULL.
SQL_DEFAULT_PARAM. A procedure is to use the default value of a parameter, instead of a value retrieved
from the application. This value is valid only in a procedure called in ODBC canonical syntax, and then
only if the InputOutputType argument is SQL_PARAM_INPUT, SQL_PARAM_INPUT_OUTPUT, or
SQL_PARAM_INPUT_OUTPUT_STREAM. When *StrLen_or_IndPtr is SQL_DEFAULT_PARAM, the ValueType,
ParameterType, ColumnSize, DecimalDigits, BufferLength, and ParameterValuePtr arguments are ignored
for input parameters and are used only to define the output parameter value for input/output
parameters.
The result of the SQL_LEN_DATA_AT_EXEC(length) macro. The data for the parameter will be sent with
SQLPutData . If the ParameterType argument is SQL_LONGVARBINARY, SQL_LONGVARCHAR, or a long,
data source-specific data type, and the driver returns "Y" for the SQL_NEED_LONG_DATA_LEN
information type in SQLGetInfo , length is the number of bytes of data to be sent for the parameter;
otherwise, length must be a nonnegative value and is ignored. For more information, see "Passing
Parameter Values," later in this section.
For example, to specify that 10,000 bytes of data will be sent with SQLPutData in one or more calls, for
an SQL_LONGVARCHAR parameter, an application sets *StrLen_or_IndPtr to
SQL_LEN_DATA_AT_EXEC(10000).
SQL_DATA_AT_EXEC. The data for the parameter will be sent with SQLPutData . This value is used by
ODBC 1.0 applications when they call ODBC 3.x drivers. For more information, see "Passing Parameter
Values," later in this section.
If StrLen_or_IndPtr is a null pointer, the driver assumes that all input parameter values are non-NULL and that
character and binary data is null-terminated. If InputOutputType is SQL_PARAM_OUTPUT or
SQL_PARAM_OUTPUT_STREAM and ParameterValuePtr and StrLen_or_IndPtr are both null pointers, the driver
discards the output value.

NOTE
Application developers are strongly discouraged from specifying a null pointer for StrLen_or_IndPtr when the data type of
the parameter is SQL_C_BINARY. To make sure that a driver does not unexpectedly truncate SQL_C_BINARY data,
StrLen_or_IndPtr should contain a pointer to a valid length value.

If the InputOutputType argument is SQL_PARAM_INPUT_OUTPUT, SQL_PARAM_OUTPUT,


SQL_PARAM_INPUT_OUTPUT_STREAM, or SQL_PARAM_OUTPUT_STREAM, StrLen_or_IndPtr points to a buffer
in which the driver returns SQL_NULL_DATA, the number of bytes available to return in *ParameterValuePtr
(excluding the null-termination byte of character data), or SQL_NO_TOTAL (if the number of bytes available to
return cannot be determined). If the procedure returns one or more result sets, the *StrLen_or_IndPtr buffer is
not guaranteed to be set until all results have been fetched.
If the value in the SQL_ATTR_PARAMSET_SIZE statement attribute is greater than 1, StrLen_or_IndPtr points to an
array of SQLLEN values. These can be any of the values listed earlier in this section and are processed with a
single SQL statement.

Passing Parameter Values


An application can pass the value for a parameter either in the *ParameterValuePtr buffer or with one or more
calls to SQLPutData . Parameters whose data is passed with SQLPutData are known as data-at-execution
parameters. These are typically used to send data for SQL_LONGVARBINARY and SQL_LONGVARCHAR
parameters, and can be mixed with other parameters.
To pass parameter values, an application performs the following sequence of steps:
1. Calls SQLBindParameter for each parameter to bind buffers for the parameter's value
(ParameterValuePtr argument) and length/indicator (StrLen_or_IndPtr argument). For data-at-execution
parameters, ParameterValuePtr is an application-defined pointer value such as a parameter number or a
pointer to data. The value will be returned later and can be used to identify the parameter.
2. Places values for input and input/output parameters in the *ParameterValuePtr and *StrLen_or_IndPtr
buffers:
For normal parameters, the application places the parameter value in the *ParameterValuePtr
buffer and the length of that value in the *StrLen_or_IndPtr buffer. For more information, see
Setting Parameter Values.
For data-at-execution parameters, the application puts the result of the
SQL_LEN_DATA_AT_EXEC(length) macro (when calling an ODBC 2.0 driver) in the
*StrLen_or_IndPtr buffer.
3. Calls SQLExecute or SQLExecDirect to execute the SQL statement.
If there are no data-at-execution parameters, the process is complete.
If there are any data-at-execution parameters, the function returns SQL_NEED_DATA.
4. Calls SQLParamData to retrieve the application-defined value specified in the ParameterValuePtr
argument of SQLBindParameter for the first data-at-execution parameter to be processed.
SQLParamData returns SQL_NEED_DATA.

NOTE
Although data-at-execution parameters resemble data-at-execution columns, the value returned by
SQLParamData is different for each. Data-at-execution parameters are parameters in an SQL statement for
which data will be sent with SQLPutData when the statement is executed with SQLExecDirect or SQLExecute .
They are bound with SQLBindParameter . The value returned by SQLParamData is a pointer value passed to
SQLBindParameter in the ParameterValuePtr argument. Data-at-execution columns are columns in a rowset for
which data will be sent with SQLPutData when a row is updated or added with SQLBulkOperations or
updated with SQLSetPos . They are bound with SQLBindCol. The value returned by SQLParamData is the
address of the row in the *TargetValuePtr buffer (set by a call to SQLBindCol) that is being processed.

5. Calls SQLPutData one or more times to send data for the parameter. More than one call is needed if the
data value is larger than the *ParameterValuePtr buffer specified in SQLPutData ; multiple calls to
SQLPutData for the same parameter are allowed only when sending character C data to a column with a
character, binary, or data source-specific data type or when sending binary C data to a column with a
character, binary, or data source-specific data type.
6. Calls SQLParamData again to signal that all data has been sent for the parameter.
If there are more data-at-execution parameters, SQLParamData returns SQL_NEED_DATA and the
application-defined value for the next data-at-execution parameter to be processed. The
application repeats steps 4 and 5.
If there are no more data-at-execution parameters, the process is complete. If the statement was
successfully executed, SQLParamData returns SQL_SUCCESS or SQL_SUCCESS_WITH_INFO; if
the execution failed, it returns SQL_ERROR. At this point, SQLParamData can return any
SQLSTATE that can be returned by the function that is used to execute the statement
(SQLExecDirect or SQLExecute ).
Output values for any input/output or output parameters are available in the *ParameterValuePtr
and *StrLen_or_IndPtr buffers after the application retrieves all result sets generated by the
statement.
Calling SQLExecute or SQLExecDirect puts the statement in an SQL_NEED_DATA state. At this point, the
application can call only SQLCancel , SQLGetDiagField , SQLGetDiagRec , SQLGetFunctions ,
SQLParamData , or SQLPutData with the statement or the connection handle associated with the statement. If
it calls any other function with the statement or the connection associated with the statement, the function
returns SQLSTATE HY010 (Function sequence error). The statement leaves the SQL_NEED_DATA state when
SQLParamData or SQLPutData returns an error, SQLParamData returns SQL_SUCCESS or
SQL_SUCCESS_WITH_INFO, or the statement is canceled.
If the application calls SQLCancel while the driver still needs data for data-at-execution parameters, the driver
cancels statement execution; the application can then call SQLExecute or SQLExecDirect again.

Retrieving Streamed Output Parameters


When an application sets InputOutputType to SQL_PARAM_INPUT_OUTPUT_STREAM or
SQL_PARAM_OUTPUT_STREAM, the output parameter value must be retrieved by one or more calls to
SQLGetData . When the driver has a streamed output parameter value to return to the application, it will return
SQL_PARAM_DATA_AVAILABLE in response to a call to the following functions: SQLMoreResults , SQLExecute ,
and SQLExecDirect . An application calls SQLParamData to determine which parameter value is available.
For more information about SQL_PARAM_DATA_AVAILABLE and streamed output parameters, see Retrieving
Output Parameters Using SQLGetData.

Using Arrays of Parameters


When an application prepares a statement with parameter markers and passes in an array of parameters, there
are two different ways this can be executed. One way is for the driver to rely on the array-processing capabilities
of the back end, in which case the whole statement with the array of parameters is treated as one atomic unit.
Oracle is an example of a data source that supports array processing capabilities. Another way to implement this
feature is for the driver to generate a batch of SQL statements, one SQL statement for each set of parameters in
the parameter array, and execute the batch. Arrays of parameters cannot be used with an UPDATE WHERE
CURRENT OF statement.
When an array of parameters is processed, individual result sets/row counts (one for each parameter set) can be
available or result sets/rows counts can be rolled up into one. The SQL_PARAM_ARRAY_ROW_COUNTS option
in SQLGetInfo indicates whether row counts are available for each set of parameters (SQL_PARC_BATCH) or
only one row count is available (SQL_PARC_NO_BATCH).
The SQL_PARAM_ARRAY_SELECTS option in SQLGetInfo indicates whether a result set is available for each set
of parameters (SQL_PAS_BATCH) or only one result set is available (SQL_PAS_NO_BATCH). If the driver does not
allow a result set-generating statement to be executed with an array of parameters,
SQL_PARAM_ARRAY_SELECTS returns SQL_PAS_NO_SELECT.
For more information, see SQLGetInfo Function.
To support arrays of parameters, the SQL_ATTR_PARAMSET_SIZE statement attribute is set to specify the
number of values for each parameter. If the field is greater than 1, the SQL_DESC_DATA_PTR,
SQL_DESC_INDICATOR_PTR, and SQL_DESC_OCTET_LENGTH_PTR fields of the APD must point to arrays. The
cardinality of each array is equal to the value of SQL_ATTR_PARAMSET_SIZE.
The SQL_DESC_ROWS_PROCESSED_PTR field of the APD points to a buffer that contains the number of sets of
parameters that have been processed, including error sets. As each set of parameters is processed, the driver
stores a new value in the buffer. No number will be returned if this is a null pointer. When arrays of parameters
are used, the value pointed to by the SQL_DESC_ROWS_PROCESSED_PTR field of the APD is populated even if
SQL_ERROR is returned by the setting function. If SQL_NEED_DATA is returned, the value pointed to by the
SQL_DESC_ROWS_PROCESSED_PTR field of the APD is set to the set of parameters that is being processed.
What occurs when an array of parameters is bound and an UPDATE WHERE CURRENT OF statement is
executed is driver-defined.
Column-Wise Parameter Binding
In column-wise binding, the application binds separate parameter and length/indicator arrays to each
parameter.
To use column-wise binding, the application first sets the SQL_ATTR_PARAM_BIND_TYPE statement attribute to
SQL_PARAM_BIND_BY_COLUMN. (This is the default.) For each column to be bound, the application performs
the following steps:
1. Allocates a parameter buffer array.
2. Allocates an array of length/indicator buffers.

NOTE
If the application writes directly to descriptors when column-wise binding is used, separate arrays can be used for
length and indicator data.

3. Calls SQLBindParameter with the following arguments:


ValueType is the C type of a single element in the parameter buffer array.
ParameterType is the SQL type of the parameter.
ParameterValuePtr is the address of the parameter buffer array.
BufferLength is the size of a single element in the parameter buffer array. The BufferLength
argument is ignored when the data is fixed-length data.
StrLen_or_IndPtr is the address of the length/indicator array.
For more information about how this information is used, see "ParameterValuePtr Argument" in "Comments,"
later in this section. For more information about column-wise binding of parameters, see Binding Arrays of
Parameters.

Row-Wise Parameter Binding


In row-wise binding, the application defines a structure that contains parameter and length/indicator buffers for
each parameter to be bound.
To use row-wise binding, the application performs the following steps:
1. Defines a structure to hold a single set of parameters (including both parameter and length/indicator
buffers) and allocates an array of these structures.

NOTE
If the application writes directly to descriptors when row-wise binding is used, separate fields can be used for
length and indicator data.

2. Sets the SQL_ATTR_PARAM_BIND_TYPE statement attribute to the size of the structure that contains a
single set of parameters or to the size of an instance of a buffer into which the parameters will be bound.
The length must include space for all the bound parameters, and any padding of the structure or buffer, to
make sure that when the address of a bound parameter is incremented with the specified length, the
result will point to the beginning of the same parameter in the next row. When you use the sizeof
operator in ANSI C, this behavior is guaranteed.
3. Calls SQLBindParameter with the following arguments for each parameter to be bound:
ValueType is the type of the parameter buffer member to be bound to the column.
ParameterType is the SQL type of the parameter.
ParameterValuePtr is the address of the parameter buffer member in the first array element.
BufferLength is the size of the parameter buffer member.
StrLen_or_IndPtr is the address of the length/indicator member to be bound.
For more information about how this information is used, see "ParameterValuePtr Argument," later in this
section. For more information about row-wise binding of parameters, see the Binding Arrays of Parameters.

Error Information
If a driver does not implement parameter arrays as batches (the SQL_PARAM_ARRAY_ROW_COUNTS option is
equal to SQL_PARC_NO_BATCH), error situations are handled as if one statement were executed. If the driver
does implement parameter arrays as batches, an application can use the SQL_DESC_ARRAY_STATUS_PTR header
field of the IPD to determine which parameter of an SQL statement or which parameter in an array of
parameters caused SQLExecDirect or SQLExecute to return an error. This field contains status information for
each row of parameter values. If the field indicates that an error has occurred, fields in the diagnostic data
structure will indicate the row and parameter number of the parameter that failed. The number of elements in
the array will be defined by the SQL_DESC_ARRAY_SIZE header field in the APD, which can be set by the
SQL_ATTR_PARAMSET_SIZE statement attribute.

NOTE
The SQL_DESC_ARRAY_STATUS_PTR header field in the APD is used to ignore parameters. For more information about
ignoring parameters, see the next section, "Ignoring a Set of Parameters."

When SQLExecute or SQLExecDirect returns SQL_ERROR, the elements in the array pointed to by the
SQL_DESC_ARRAY_STATUS_PTR field in the IPD will contain SQL_PARAM_ERROR, SQL_PARAM_SUCCESS,
SQL_PARAM_SUCCESS_WITH_INFO, SQL_PARAM_UNUSED, or SQL_PARAM_DIAG_UNAVAILABLE.
For each element in this array, the diagnostic data structure contains one or more status records. The
SQL_DIAG_ROW_NUMBER field of the structure indicates the row number of the parameter values that caused
the error. If it is possible to determine the particular parameter in a row of parameters that caused the error, the
parameter number will be entered in the SQL_DIAG_COLUMN_NUMBER field.
SQL_PARAM_UNUSED is entered when a parameter has not been used because an error occurred in an earlier
parameter that forced SQLExecute or SQLExecDirect to abort. For example, if there are 50 parameters and an
error occurred while executing the fortieth set of parameters that caused SQLExecute or SQLExecDirect to
abort, then SQL_PARAM_UNUSED is entered in the status array for parameters 41 through 50.
SQL_PARAM_DIAG_UNAVAILABLE is entered when the driver treats arrays of parameters as a monolithic unit, so
it does not generate this individual parameter level of error information.
Some errors in the processing of a single set of parameters cause processing of the subsequent sets of
parameters in the array to stop. Other errors do not affect the processing of subsequent parameters. Which
errors will stop processing is driver-defined. If processing is not stopped, all parameters in the array are
processed, SQL_SUCCESS_WITH_INFO is returned as a result of the error, and the buffer defined by
SQL_ATTR_PARAMS_PROCESSED_PTR is set to the total number of sets of parameters processed (as defined by
the SQL_ATTR_PARAMSET_SIZE statement attribute), which includes error sets.
Cau t i on
ODBC behavior when an error occurs in the processing of an array of parameters is different in ODBC 3.x than it
was in ODBC 2.x. In ODBC 2.x, the function returned SQL_ERROR and processing ceased. The buffer pointed to
by the pirow argument of SQLParamOptions contained the number of the error row. In ODBC 3.x, the function
returns SQL_SUCCESS_WITH_INFO and processing may either stop or continue. If it continues, the buffer
specified by SQL_ATTR_PARAMS_PROCESSED_PTR will be set to the value of all parameters processed, including
those that resulted in an error. This change in behavior may cause problems for existing applications.
When SQLExecute or SQLExecDirect returns before completing the processing of all parameter sets in a
parameter array, such as when SQL_ERROR or SQL_NEED_DATA is returned, the status array contains statuses
for those parameters that have already been processed. The location pointed to by the
SQL_DESC_ROWS_PROCESSED_PTR field in the IPD contains the row number in the parameter array that
caused the SQL_ERROR or SQL_NEED_DATA error code. When an array of parameters is sent to a SELECT
statement, the availability of status array values is driver-defined; they may be available after the statement has
been executed or as result sets are fetched.

Ignoring a Set of Parameters


The SQL_DESC_ARRAY_STATUS_PTR field of the APD (as set by the SQL_ATTR_PARAM_STATUS_PTR statement
attribute) can be used to indicate that a set of bound parameters in an SQL statement should be ignored. To
direct the driver to ignore one or more sets of parameters during execution, an application should follow these
steps:
1. Call SQLSetDescField to set the SQL_DESC_ARRAY_STATUS_PTR header field of the APD to point to an
array of SQLUSMALLINT values to contain status information. This field can also be set by calling
SQLSetStmtAttr with an Attribute of SQL_ATTR_PARAM_OPERATION_PTR, which allows an application
to set the field without obtaining a descriptor handle.
2. Set each element of the array defined by the SQL_DESC_ARRAY_STATUS_PTR field of the APD to one of
two values:
SQL_PARAM_IGNORE, to indicate that the row is excluded from statement execution.
SQL_PARAM_PROCEED, to indicate that the row is included in statement execution.
3. Call SQLExecDirect or SQLExecute to execute the prepared statement.
The following rules apply to the array defined by the SQL_DESC_ARRAY_STATUS_PTR field of the APD:
The pointer is set to null by default.
If the pointer is null, all sets of parameters are used, as if all elements were set to SQL_ROW_PROCEED.
Setting an element to SQL_PARAM_PROCEED does not guarantee that the operation will use that
particular set of parameters.
SQL_PARAM_PROCEED is defined as 0 in the header file.
An application can set the SQL_DESC_ARRAY_STATUS_PTR field in the APD to point to the same array as that
pointed to by the SQL_DESC_ARRAY_STATUS_PTR field in the IRD. This is useful when binding parameters to row
data. Parameters can then be ignored according to the status of the row data. In addition to
SQL_PARAM_IGNORE, the following codes cause a parameter in an SQL statement to be ignored:
SQL_ROW_DELETED, SQL_ROW_UPDATED, and SQL_ROW_ERROR. In addition to SQL_PARAM_PROCEED, the
following codes cause an SQL statement to proceed: SQL_ROW_SUCCESS, SQL_ROW_SUCCESS_WITH_INFO,
and SQL_ROW_ADDED.

Rebinding Parameters
An application can perform either of two operations to change a binding:
Call SQLBindParameter to specify a new binding for a column that is already bound. The driver
overwrites the old binding with the new one.
Specify an offset to be added to the buffer address that was specified by the binding call to
SQLBindParameter . For more information, see the next section, "Rebinding with Offsets."

Rebinding with Offsets


Rebinding of parameters is especially useful when an application has a buffer area setup that can contain many
parameters but a call to SQLExecDirect or SQLExecute uses only a few of the parameters. The remaining
space in the buffer area can be used for the next set of parameters by modifying the existing binding by an
offset.
The SQL_DESC_BIND_OFFSET_PTR header field in the APD points to the binding offset. If the field is non-null,
the driver dereferences the pointer and, if none of the values in the SQL_DESC_DATA_PTR,
SQL_DESC_INDICATOR_PTR, and SQL_DESC_OCTET_LENGTH_PTR fields is a null pointer, adds the dereferenced
value to those fields in the descriptor records at execution time. The new pointer values are used when the SQL
statements are executed. The offset remains valid after rebinding. Because SQL_DESC_BIND_OFFSET_PTR is a
pointer to the offset rather than the offset itself, an application can change the offset directly, without having to
call SQLSetDescField or SQLSetDescRec to change the descriptor field. The pointer is set to null by default. The
SQL_DESC_BIND_OFFSET_PTR field of the ARD can be set by a call to SQLSetDescField or by a call to
SQLSetStmtAttrwith an fAttribute of SQL_ATTR_PARAM_BIND_OFFSET_PTR.
The binding offset is always added directly to the values in the SQL_DESC_DATA_PTR,
SQL_DESC_INDICATOR_PTR, and SQL_DESC_OCTET_LENGTH_PTR fields. If the offset is changed to a different
value, the new value is still added directly to the value in each descriptor field. The new offset is not added to the
sum of the field value and any earlier offsets.

Descriptors
How a parameter is bound is determined by fields of the APDs and IPDs. The arguments in SQLBindParameter
are used to set those descriptor fields. The fields can also be set by the SQLSetDescField functions, although
SQLBindParameter is more efficient to use because the application does not have to obtain a descriptor
handle to call SQLBindParameter .
Cau t i on

Calling SQLBindParameter for one statement can affect other statements. This occurs when the ARD
associated with the statement is explicitly allocated and is also associated with other statements. Because
SQLBindParameter modifies the fields of the APD, the modifications apply to all statements with which this
descriptor is associated. If this is not the required behavior, the application should dissociate this descriptor from
the other statements before it calls SQLBindParameter .
Conceptually, SQLBindParameter performs the following steps in sequence:
1. Calls SQLGetStmtAttr to obtain the APD handle.
2. Calls SQLGetDescField to get the APD's SQL_DESC_COUNT field, and if the value of the ColumnNumber
argument exceeds the value of SQL_DESC_COUNT, calls SQLSetDescField to increase the value of
SQL_DESC_COUNT to ColumnNumber.
3. Calls SQLSetDescField multiple times to assign values to the following fields of the APD:
Sets SQL_DESC_TYPE and SQL_DESC_CONCISE_TYPE to the value of ValueType, except that if
ValueType is one of the concise identifiers of a datetime or interval subtype, it sets
SQL_DESC_TYPE to SQL_DATETIME or SQL_INTERVAL, respectively, sets
SQL_DESC_CONCISE_TYPE to the concise identifier, and sets
SQL_DESC_DATETIME_INTERVAL_CODE to the corresponding datetime or interval subcode.
Sets the SQL_DESC_OCTET_LENGTH field to the value of BufferLength.
Sets the SQL_DESC_DATA_PTR field to the value of ParameterValue.
Sets the SQL_DESC_OCTET_LENGTH_PTR field to the value of StrLen_or_Ind.
Sets the SQL_DESC_INDICATOR_PTR field also to the value of StrLen_or_Ind.
The StrLen_or_Ind parameter specifies both the indicator information and the length for the parameter
value.
4. Calls SQLGetStmtAttr to obtain the IPD handle.
5. Calls SQLGetDescField to get the IPD's SQL_DESC_COUNT field, and if the value of the ColumnNumber
argument exceeds the value of SQL_DESC_COUNT, calls SQLSetDescField to increase the value of
SQL_DESC_COUNT to ColumnNumber.
6. Calls SQLSetDescField multiple times to assign values to the following fields of the IPD:
Sets SQL_DESC_TYPE and SQL_DESC_CONCISE_TYPE to the value of ParameterType, except that if
ParameterType is one of the concise identifiers of a datetime or interval subtype, it sets
SQL_DESC_TYPE to SQL_DATETIME or SQL_INTERVAL, respectively, sets
SQL_DESC_CONCISE_TYPE to the concise identifier, and sets
SQL_DESC_DATETIME_INTERVAL_CODE to the corresponding datetime or interval subcode.
Sets one or more of SQL_DESC_LENGTH, SQL_DESC_PRECISION, and
SQL_DESC_DATETIME_INTERVAL_PRECISION, as appropriate for ParameterType.
Sets SQL_DESC_SCALE to the value of DecimalDigits.
If the call to SQLBindParameter fails, the content of the descriptor fields that it would have set in the APD are
undefined, and the SQL_DESC_COUNT field of the APD is unchanged. In addition, the SQL_DESC_LENGTH,
SQL_DESC_PRECISION, SQL_DESC_SCALE, and SQL_DESC_TYPE fields of the appropriate record in the IPD are
undefined and the SQL_DESC_COUNT field of the IPD is unchanged.

Conversion of Calls to and from SQLSetParam


When an ODBC 1.0 application calls SQLSetParam in an ODBC 3.x driver, the ODBC 3.x Driver Manager maps
the call as shown in the following table.

C A L L B Y O DB C 1. 0 A P P L IC AT IO N C A L L TO O DB C 3. X DRIVER

SQLSetParam( StatementHandle, ParameterNumber, SQLBindParameter( StatementHandle, ParameterNumber,


ValueType, ParameterType, LengthPrecision, ParameterScale, SQL_PARAM_INPUT_OUTPUT, ValueType, ParameterType,
ParameterValuePtr, StrLen_or_IndPtr); ColumnSize, DecimalDigits, ParameterValuePtr,
SQL_SETPARAM_VALUE_MAX, StrLen_or_IndPtr);

Examples
A. Use SQLBindParameter Function
In the following example, an application prepares an SQL statement to insert data into the ORDERS table. For
each parameter in the statement, the application calls SQLBindParameter to specify the ODBC C data type and
the SQL data type of the parameter, and to bind a buffer to each parameter. For each row of data, the application
assigns data values to each parameter and calls SQLExecute to execute the statement.
The following sample assumes that you have an ODBC data source on your computer called Northwind that is
associated with the Northwind database.
For more code examples, see SQLBulkOperations Function, SQLProcedures Function, SQLPutData Function, and
SQLSetPos Function.

// SQLBindParameter_Function.cpp
// compile with: ODBC32.lib
#include <windows.h>
#include <sqltypes.h>
#include <sqlext.h>

#define EMPLOYEE_ID_LEN 10

SQLHENV henv = NULL;


SQLHDBC hdbc = NULL;
SQLRETURN retcode;
SQLHSTMT hstmt = NULL;
SQLSMALLINT sCustID;

SQLCHAR szEmployeeID[EMPLOYEE_ID_LEN];
SQL_DATE_STRUCT dsOrderDate;
SQLINTEGER cbCustID = 0, cbOrderDate = 0, cbEmployeeID = SQL_NTS;

int main() {
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);


retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

retcode = SQLConnect(hdbc, (SQLCHAR*) "Northwind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);


retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, EMPLOYEE_ID_LEN, 0,


szEmployeeID, 0, &cbEmployeeID);
retcode = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &sCustID, 0,
&cbCustID);
retcode = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TIMESTAMP,
sizeof(dsOrderDate), 0, &dsOrderDate, 0, &cbOrderDate);

retcode = SQLPrepare(hstmt, (SQLCHAR*)"INSERT INTO Orders(CustomerID, EmployeeID, OrderDate) VALUES (?,


?, ?)", SQL_NTS);

strcpy_s((char*)szEmployeeID, _countof(szEmployeeID), "BERGS");


sCustID = 5;
dsOrderDate.year = 2006;
dsOrderDate.month = 3;
dsOrderDate.day = 17;

retcode = SQLExecute(hstmt);
}

B. Execute a stored procedure using a named parameter


In the following example, an application executes a SQL Server stored procedure using a named parameter.
// SQLBindParameter_Function_2.cpp
// compile with: ODBC32.lib
// sample assumes the following stored procedure:
// use northwind
// DROP PROCEDURE SQLBindParameter
// GO
//
// CREATE PROCEDURE SQLBindParameter @quote int
// AS
// delete from orders where OrderID >= @quote
// GO
#include <windows.h>
#include <sqltypes.h>
#include <sqlext.h>

SQLHDESC hIpd = NULL;


SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
SQLRETURN retcode;
SQLHSTMT hstmt = NULL;
SQLCHAR szQuote[50] = "100084";
SQLINTEGER cbValue = SQL_NTS;

int main() {
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);


retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

retcode = SQLConnect(hdbc, (SQLCHAR*) "Northwind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);


retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

retcode = SQLPrepare(hstmt, (SQLCHAR*)"{call SQLBindParameter(?)}", SQL_NTS);


retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 50, 0, szQuote, 0, &cbValue);
retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_IMP_PARAM_DESC, &hIpd, 0, 0);
retcode = SQLSetDescField(hIpd, 1, SQL_DESC_NAME, "@quote", SQL_NTS);

retcode = SQLExecute(hstmt);
}

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Returning information about a parameter in a statement SQLDescribeParam Function

Executing an SQL statement SQLExecDirect Function

Executing a prepared SQL statement SQLExecute Function

Releasing parameter buffers on the statement SQLFreeStmt Function

Returning the number of statement parameters SQLNumParams Function

Returning the next parameter to send data for SQLParamData Function

Specifying multiple parameter values SQLParamOptions Function

Sending parameter data at execution time SQLPutData Function


See Also
ODBC API Reference
ODBC Header Files
Retrieving Output Parameters Using SQLGetData
SQLBrowseConnect Function
4/27/2022 • 15 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: ODBC
Summar y
SQLBrowseConnect supports an iterative method of discovering and enumerating the attributes and attribute
values required to connect to a data source. Each call to SQLBrowseConnect returns successive levels of
attributes and attribute values. When all levels have been enumerated, a connection to the data source is
completed and a complete connection string is returned by SQLBrowseConnect . A return code of
SQL_SUCCESS or SQL_SUCCESS_WITH_INFO indicates that all connection information has been specified and
the application is now connected to the data source.

Syntax
SQLRETURN SQLBrowseConnect(
SQLHDBC ConnectionHandle,
SQLCHAR * InConnectionString,
SQLSMALLINT StringLength1,
SQLCHAR * OutConnectionString,
SQLSMALLINT BufferLength,
SQLSMALLINT * StringLength2Ptr);

Arguments
ConnectionHandle
[Input] Connection handle.
InConnectionString
[Input] Browse request connection string (see "InConnectionString Argument" in "Comments").
StringLength1
[Input] Length of *InConnectionString in characters.
OutConnectionString
[Output] Pointer to a character buffer in which to return the browse result connection string (see
"OutConnectionString Argument" in "Comments").
If OutConnectionString is NULL, StringLength2Ptr will still return the total number of characters (excluding the
null-termination character for character data) available to return in the buffer pointed to by
OutConnectionString.
BufferLength
[Input] Length, in characters, of the *OutConnectionString buffer.
StringLength2Ptr
[Output] The total number of characters (excluding null-termination) available to return in
*OutConnectionString. If the number of characters available to return is greater than or equal to BufferLength,
the connection string in *OutConnectionString is truncated to BufferLength minus the length of a null-
termination character.
Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NEED_DATA, SQL_ERROR, SQL_INVALID_HANDLE, or
SQL_STILL_EXECUTING.

Diagnostics
When SQLBrowseConnect returns SQL_ERROR, SQL_SUCCESS_WITH_INFO, or SQL_NEED_DATA, an
associated SQLSTATE value can be obtained by calling SQLGetDiagRec with a HandleType of
SQL_HANDLE_STMT and a Handle of ConnectionHandle. The following table lists the SQLSTATE values
commonly returned by SQLBrowseConnect and explains each one in the context of this function; the notation
"(DM)" precedes the descriptions of SQLSTATEs returned by the Driver Manager. The return code associated with
each SQLSTATE value is SQL_ERROR, unless noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

01004 String data, right truncated The buffer *OutConnectionString was


not large enough to return the entire
browse result connection string, so the
string was truncated. The buffer
*StringLength2Ptr contains the length
of the untruncated browse result
connection string. (Function returns
SQL_NEED_DATA.)

01S00 Invalid connection string attribute An invalid attribute keyword was


specified in the browse request
connection string (InConnectionString).
(Function returns SQL_NEED_DATA.)

An attribute keyword was specified in


the browse request connection string
(InConnectionString) that does not
apply to the current connection level.
(Function returns SQL_NEED_DATA.)

01S02 Value changed The driver did not support the


specified value of the ValuePtr
argument in SQLSetConnectAttr
and substituted a similar value.
(Function returns
SQL_SUCCESS_WITH_INFO.)

08001 Client unable to establish connection The driver was unable to establish a
connection with the data source.

08002 Connection name in use (DM) The specified connection had


already been used to establish a
connection with a data source, and the
connection was open.

08004 Server rejected the connection The data source rejected the
establishment of the connection for
implementation-defined reasons.
SQ L STAT E ERRO R DESC RIP T IO N

08S01 Communication link failure The communication link between the


driver and the data source to which
the driver was attempting to connect
failed before the function completed
processing.

28000 Invalid authorization specification Either the user identifier or the


authorization string or both, as
specified in the browse request
connection string (InConnectionString),
violated restrictions defined by the
data source.

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.

HY001 Memory allocation error (DM) The Driver Manager was unable
to allocate memory required to
support execution or completion of
the function.

The driver was unable to allocate


memory required to support execution
or completion of the function.

HY008 Operation canceled An asynchronous operation was


canceled by calling SQLCancelHandle
Function. Then, the original function
was called again on the
ConnectionHandle.

An operation was canceled by calling


SQLCancelHandle on the
ConnectionHandle from a different
thread in a multithread application.

HY010 Function sequence error (DM) An asynchronously executing


function (not this one) was called for
the ConnectionHandle and was still
executing when this function was
called.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.
SQ L STAT E ERRO R DESC RIP T IO N

HY090 Invalid string or buffer length (DM) The value specified for argument
StringLength1 was less than 0 and was
not equal to SQL_NTS.

(DM) The value specified for argument


BufferLength was less than 0.

HY114 Driver does not support connection (DM) The application enabled the
level asynchronous function execution asynchronous operation on the
connection handle before making the
connection. However, the driver does
not support asynchronous operation
on connection handle.

HYT00 Timeout expired The login timeout period expired


before the connection to the data
source completed. The timeout period
is set through SQLSetConnectAttr ,
SQL_ATTR_LOGIN_TIMEOUT.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver corresponding to the
specified data source name does not
support the function.

IM002 Data source not found and no default (DM) The data source name specified
driver specified in the browse request connection
string (InConnectionString) was not
found in the system information, nor
was there a default driver specification.

(DM) ODBC data source and default


driver information could not be found
in the system information.

IM003 Specified driver could not be loaded (DM) The driver listed in the data
source specification in the system
information or specified by the
DRIVER keyword was not found or
could not be loaded for some other
reason.

IM004 Driver's SQL AllocHandle on (DM) During SQLBrowseConnect ,


SQL_HANDLE _ENV failed the Driver Manager called the driver's
SQL AllocHandle function with a
HandleType of SQL_HANDLE_ENV and
the driver returned an error.
SQ L STAT E ERRO R DESC RIP T IO N

IM005 Driver's SQL AllocHandle on (DM) During SQLBrowseConnect ,


SQL_HANDLE_DBC failed the Driver Manager called the driver's
SQL AllocHandle function with a
HandleType of SQL_HANDLE_DBC and
the driver returned an error.

IM006 Driver's SQLSetConnectAttr failed (DM) During SQLBrowseConnect ,


the Driver Manager called the driver's
SQLSetConnectAttr function and
the driver returned an error.

IM009 Unable to load translation DLL The driver was unable to load the
translation DLL that was specified for
the data source or for the connection.

IM010 Data source name too long (DM) The attribute value for the DSN
keyword was longer than
SQL_MAX_DSN_LENGTH characters.

IM011 Driver name too long (DM) The attribute value for the
DRIVER keyword was longer than 255
characters.

IM012 DRIVER keyword syntax error (DM) The keyword-value pair for the
DRIVER keyword contained a syntax
error.

IM014 The specified DSN contains an (DM) 32-bit application uses a DSN
architecture mismatch between the connecting to a 64-bit driver; or vice
Driver and Application versa.

IM017 Polling is disabled in asynchronous Whenever the notification model is


notification mode used, polling is disabled.

IM018 SQLCompleteAsync has not been If the previous function call on the
called to complete the previous handle returns SQL_STILL_EXECUTING
asynchronous operation on this and if notification mode is enabled,
handle. SQLCompleteAsync must be called
on the handle to do post-processing
and complete the operation.

S1118 Driver does not support asynchronous When the driver does not support
notification asynchronous notification, you cannot
set SQL_ATTR_ASYNC_DBC_EVENT or
SQL_ATTR_ASYNC_DBC_RETCODE_PTR.

InConnectionString Argument
A browse request connection string has the following syntax:
connection-string ::= attribute[ ; ] | attribute ; connection-string;
attribute ::= attribute-keyword = attribute-value | DRIVER= [ { ]attribute-value[ } ]
attribute-keyword ::= DSN | UID | PWD | driver-defined-attribute-keyword
attribute-value ::= character-string
driver-defined-attribute-keyword ::= identifier
where character-string has zero or more characters; identifier has one or more characters; attribute-keyword is
not case-sensitive; attribute-value may be case-sensitive; and the value of the DSN keyword does not consist
solely of blanks. Because of connection string and initialization file grammar, keywords and attribute values that
contain the characters []{}(),;?*=!@ should be avoided. Because of the grammar in the system information,
keywords and data source names cannot contain the backslash (\) character. For an ODBC 2.x driver, braces are
required around the attribute value for the DRIVER keyword.
If any keywords are repeated in the browse request connection string, the driver uses the value associated with
the first occurrence of the keyword. If the DSN and DRIVER keywords are included in the same browse request
connection string, the Driver Manager and driver use whichever keyword appears first.
For information about how an application chooses a data source or driver, see Choosing a Data Source or Driver.

OutConnectionString Argument
The browse result connection string is a list of connection attributes. A connection attribute consists of an
attribute keyword and a corresponding attribute value. The browse result connection string has the following
syntax:
connection-string ::= attribute[ ; ] | attribute ; connection-string
attribute ::= [ * ]attribute-keyword = attribute-value
attribute-keyword ::= ODBC-attribute-keyword | driver-defined-attribute-keyword
ODBC-attribute-keyword = { UID | PWD }[ : localized-identifier] driver-defined-attribute-keyword ::= identifier[
: localized-identifier ] attribute-value ::= { attribute-value-list } | ? (The braces are literal; they are returned
by the driver.)
attribute-value-list ::= character-string [ : localized-character string] | character-string [ : localized-character
string] , attribute-value-list
where character-string and localized-character string have zero or more characters; identifier and localized-
identifier have one or more characters; attribute-keyword is not case-sensitive; and attribute-value may be case-
sensitive. Because of connection string and initialization file grammar, keywords, localized identifiers, and
attribute values that contain the characters []{}(),;?*=!@ should be avoided. Because of the grammar in the
system information, keywords and data source names cannot contain the backslash (\) character.
The browse result connection string syntax is used according to the following semantic rules:
If an asterisk (*) precedes an attribute-keyword, the attribute is optional and can be omitted in the next
call to SQLBrowseConnect .
The attribute keywords UID and PWD have the same meaning as defined in SQLDriverConnect .
A driver-defined-attribute-keyword names the kind of attribute for which an attribute value may be
supplied. For example, it might be SERVER , DATABASE , HOST , or DBMS .
ODBC-attribute-keywords and driver-defined-attribute-keywords include a localized or user-friendly
version of the keyword. This might be used by applications as a label in a dialog box. However, UID ,
PWD , or the identifier alone must be used when passing a browse request string to the driver.
The {attribute-value-list} is an enumeration of actual values valid for the corresponding attribute-
keyword. Note that the braces ({}) do not indicate a list of choices; they are returned by the driver. For
example, it might be a list of server names or a list of database names.
If the attribute-value is a single question mark (?), a single value corresponds to the attribute-keyword.
For example, UID=JohnS; PWD=Sesame.
Each call to SQLBrowseConnect returns only the information required to satisfy the next level of the
connection process. The driver associates state information with the connection handle so that the
context can always be determined on each call.

Using SQLBrowseConnect
SQLBrowseConnect requires an allocated connection. The Driver Manager loads the driver that was specified
in or that corresponds to the data source name specified in the initial browse request connection string; for
information about when this occurs, see the "Comments" section in SQLConnect Function. The driver may
establish a connection with the data source during the browsing process. If SQLBrowseConnect returns
SQL_ERROR, outstanding connections are terminated and the connection is returned to an unconnected state.

NOTE
SQLBrowseConnect does not support connection pooling. If SQLBrowseConnect is called while connection pooling is
enabled, SQLSTATE HY000 (General error) will be returned.

When SQLBrowseConnect is called for the first time on a connection, the browse request connection string
must contain the DSN keyword or the DRIVER keyword. If the browse request connection string contains the
DSN keyword, the Driver Manager locates a corresponding data source specification in the system information:
If the Driver Manager finds the corresponding data source specification, it loads the associated driver
DLL; the driver can retrieve information about the data source from the system information.
If the Driver Manager cannot find the corresponding data source specification, it locates the default data
source specification and loads the associated driver DLL; the driver can retrieve information about the
default data source from the system information. "DEFAULT" is passed to the driver for the DSN.
If the Driver Manager cannot find the corresponding data source specification and there is no default data
source specification, it returns SQL_ERROR with SQLSTATE IM002 (Data source not found and no default
driver specified).
If the browse request connection string contains the DRIVER keyword, the Driver Manager loads the specified
driver; it does not attempt to locate a data source in the system information. Because the DRIVER keyword does
not use information from the system information, the driver must define enough keywords so that a driver can
connect to a data source using only the information in the browse request connection strings.
On each call to SQLBrowseConnect , the application specifies the connection attribute values in the browse
request connection string. The driver returns successive levels of attributes and attribute values in the browse
result connection string; it returns SQL_NEED_DATA as long as there are connection attributes that have not yet
been enumerated in the browse request connection string. The application uses the contents of the browse
result connection string to build the browse request connection string for the next call to SQLBrowseConnect .
All mandatory attributes (those not preceded by an asterisk in the OutConnectionString argument) must be
included in the next call to SQLBrowseConnect . Note that the application cannot use the contents of previous
browse result connection strings when building the current browse request connection string; that is, it cannot
specify different values for attributes set in previous levels.
When all levels of connection and their associated attributes have been enumerated, the driver returns
SQL_SUCCESS, the connection to the data source is complete, and a complete connection string is returned to
the application. The connection string is suitable to use, in conjunction with SQLDriverConnect , with the
SQL_DRIVER_NOPROMPT option to establish another connection. The complete connection string cannot be
used in another call to SQLBrowseConnect , however; if SQLBrowseConnect were called again, the entire
sequence of calls would have to be repeated.
SQLBrowseConnect also returns SQL_NEED_DATA if there are recoverable, nonfatal errors during the browse
process; for example, an invalid password or attribute keyword supplied by the application. When
SQL_NEED_DATA is returned and the browse result connection string is unchanged, an error has occurred and
the application can call SQLGetDiagRec to return the SQLSTATE for browse-time errors. This permits the
application to correct the attribute and continue the browse.
An application can terminate the browse process at any time by calling SQLDisconnect . The driver will
terminate any outstanding connections and return the connection to an unconnected state.
If asynchronous operations are enabled on the connection handle, SQLBrowseConnect might also return
SQL_STILL_EXECUTING. When it returns SQL_NEED_DATA, an application must use SQLDisconnect to cancel
the browse process. If SQLBrowseConnect returns SQL_STILL_EXECUTING, an application should use
SQLCancelHandle to cancel the operation in progress. Calling SQLCancelHandle after the function returns
SQL_NEED_DATA has no effect.
For more information, see Connecting with SQLBrowseConnect.
If a driver supports SQLBrowseConnect , the driver keyword section in the system information for the driver
must contain the ConnectFunctions keyword with the third character set to "Y."

Code Example
NOTE
If you are connecting to a data source provider that supports Windows authentication, you should specify
Trusted_Connection=yes instead of user ID and password information in the connection string.

In the following example, an application calls SQLBrowseConnect repeatedly. Each time SQLBrowseConnect
returns SQL_NEED_DATA, it passes back information about the data it needs in *OutConnectionString. The
application passes OutConnectionString to its routine GetUserInput (not shown). GetUserInput parses the
information, builds and displays a dialog box, and returns the information entered by the user in
*InConnectionString. The application passes the user's information to the driver in the next call to
SQLBrowseConnect . After the application has provided all necessary information for the driver to connect to
the data source, SQLBrowseConnect returns SQL_SUCCESS and the application proceeds.
For a more detailed example of connecting to a SQL Server driver by calling SQLBrowseConnect , see SQL
Server Browsing Example.
For example, to connect to the data source Sales, the following actions might occur. First, the application passes
the following string to SQLBrowseConnect :

"DSN=Sales"

The Driver Manager loads the driver associated with the data source Sales. It then calls the driver's
SQLBrowseConnect function with the same arguments it received from the application. The driver returns the
following string in *OutConnectionString:

"HOST:Server={red,blue,green};UID:ID=?;PWD:Password=?"

The application passes this string to its GetUserInput routine, which builds a dialog box that asks the user to
select the red, blue, or green server and to enter a user ID and password. The routine passes the following user-
specified information back in *InConnectionString, which the application passes to SQLBrowseConnect :

"HOST=red;UID=Smith;PWD=Sesame"

SQLBrowseConnect uses this information to connect to the red server as Smith with the password Sesame,
and then returns the following string in *OutConnectionString:

"*DATABASE:Database={SalesEmployees,SalesGoals,SalesOrders}"

The application passes this string to its GetUserInput routine, which builds a dialog box that asks the user to
select a database. The user selects empdata and the application calls SQLBrowseConnect a final time with this
string:

"DATABASE=SalesOrders"

This is the final piece of information the driver needs to connect to the data source; SQLBrowseConnect
returns SQL_SUCCESS, and *OutConnectionString contains the completed connection string:
// SQLBrowseConnect_Function.cpp
// compile with: odbc32.lib
#include <windows.h>
#include <sqltypes.h>
#include <sqlext.h>

#define BRWS_LEN 100


SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
SQLCHAR szConnStrIn[BRWS_LEN], szConnStrOut[BRWS_LEN];
SQLSMALLINT cbConnStrOut;

void GetUserInput(SQLCHAR * szConnStrOut, SQLCHAR * szConnStrIn) {}

int main() {
// Allocate the environment handle.
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

// Set the version environment attribute.


retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

// Allocate the connection handle.


retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
// Call SQLBrowseConnect until it returns a value other than SQL_NEED_DATA
// (pass data source name the first time). If SQL_NEED_DATA is returned, call GetUserInput
// (not shown) to build a dialog from the values in szConnStrOut. The user-supplied values
// are returned in szConnStrIn, which is passed in the next call to SQLBrowseConnect.

strcpy_s((char*)szConnStrIn, _countof(szConnStrIn), "DSN=Sales");


do {
retcode = SQLBrowseConnect(hdbc, szConnStrIn, SQL_NTS,
szConnStrOut, BRWS_LEN, &cbConnStrOut);
if (retcode == SQL_NEED_DATA)
GetUserInput(szConnStrOut, szConnStrIn);
} while (retcode == SQL_NEED_DATA);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){

// Allocate the statement handle.


retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)


// Process data after successful connection
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Allocating a connection handle SQLAllocHandle Function


F O R IN F O RM AT IO N A B O UT SEE

Connecting to a data source SQLConnect Function

Disconnecting from a data source SQLDisconnect Function

Connecting to a data source using a connection string or SQLDriverConnect Function


dialog box

Returning driver descriptions and attributes SQLDrivers Function

Freeing a connection handle SQLFreeHandle Function

See Also
ODBC API Reference
ODBC Header Files
SQLBulkOperations Function
4/27/2022 • 24 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 3.0 Standards Compliance: ODBC
Summar y
SQLBulkOperations performs bulk insertions and bulk bookmark operations, including update, delete, and
fetch by bookmark.

Syntax
SQLRETURN SQLBulkOperations(
SQLHSTMT StatementHandle,
SQLUSMALLINT Operation);

Arguments
StatementHandle
[Input] Statement handle.
Operation
[Input] Operation to perform:
SQL_ADD SQL_UPDATE_BY_BOOKMARK SQL_DELETE_BY_BOOKMARK SQL_FETCH_BY_BOOKMARK
For more information, see "Comments."

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NEED_DATA, SQL_STILL_EXECUTING, SQL_ERROR, or
SQL_INVALID_HANDLE.

Diagnostics
When SQLBulkOperations returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value
can be obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a Handle of
StatementHandle. The following table lists the SQLSTATE values typically returned by SQLBulkOperations and
explains each one in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs
returned by the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless
noted otherwise.
For all those SQLSTATEs that can return SQL_SUCCESS_WITH_INFO or SQL_ERROR (except 01xxx SQLSTATEs),
SQL_SUCCESS_WITH_INFO is returned if an error occurs on one or more, but not all, rows of a multirow
operation, and SQL_ERROR is returned if an error occurs on a single-row operation.

SQ L STAT E ERRO R DESC RIP T IO N


SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

01004 String data right truncation The Operation argument was


SQL_FETCH_BY_BOOKMARK, and
string or binary data returned for a
column or columns with a data type of
SQL_C_CHAR or SQL_C_BINARY
resulted in the truncation of nonblank
character or non-NULL binary data.

01S01 Error in row The Operation argument was


SQL_ADD, and an error occurred in
one or more rows while performing
the operation but at least one row was
successfully added. (Function returns
SQL_SUCCESS_WITH_INFO.)

(This error is raised only when an


application is working with an ODBC
2.x driver.)

01S07 Fractional truncation The Operation argument was


SQL_FETCH_BY_BOOKMARK, the data
type of the application buffer was not
SQL_C_CHAR or SQL_C_BINARY, and
the data returned to application
buffers for one or more columns was
truncated. (For numeric C data types,
the fractional part of the number was
truncated. For time, timestamp, and
interval C data types that contain a
time component, the fractional portion
of the time was truncated.)

(Function returns
SQL_SUCCESS_WITH_INFO.)

07006 Restricted data type attribute violation The Operation argument was
SQL_FETCH_BY_BOOKMARK, and the
data value of a column in the result set
could not be converted to the data
type specified by the TargetType
argument in the call to SQLBindCol.

The Operation argument was


SQL_UPDATE_BY_BOOKMARK or
SQL_ADD, and the data value in the
application buffers could not be
converted to the data type of a
column in the result set.

07009 Invalid descriptor index The argument Operation was


SQL_ADD, and a column was bound
with a column number greater than
the number of columns in the result
set.
SQ L STAT E ERRO R DESC RIP T IO N

21S02 Degree of derived table does not The argument Operation was
match column list SQL_UPDATE_BY_BOOKMARK; and no
columns were updatable because all
columns were either unbound or read-
only, or the value in the bound
length/indicator buffer was
SQL_COLUMN_IGNORE.

22001 String data right truncation The assignment of a character or


binary value to a column in the result
set resulted in the truncation of
nonblank (for characters) or non-null
(for binary) characters or bytes.

22003 Numeric value out of range The Operation argument was


SQL_ADD or
SQL_UPDATE_BY_BOOKMARK, and the
assignment of a numeric value to a
column in the result set caused the
whole (as opposed to fractional) part
of the number to be truncated.

The argument Operation was


SQL_FETCH_BY_BOOKMARK, and
returning the numeric value for one or
more bound columns would have
caused a loss of significant digits.

22007 Invalid datetime format The Operation argument was


SQL_ADD or
SQL_UPDATE_BY_BOOKMARK, and the
assignment of a date or timestamp
value to a column in the result set
caused the year, month, or day field to
be out of range.

The argument Operation was


SQL_FETCH_BY_BOOKMARK, and
returning the date or timestamp value
for one or more bound columns would
have caused the year, month, or day
field to be out of range.
SQ L STAT E ERRO R DESC RIP T IO N

22008 Date/time field overflow The Operation argument was


SQL_ADD or
SQL_UPDATE_BY_BOOKMARK, and the
performance of datetime arithmetic on
data being sent to a column in the
result set resulted in a datetime field
(the year, month, day, hour, minute, or
second field) of the result falling
outside the permissible range of values
for the field or being invalid based on
the Gregorian calendar's natural rules
for datetimes.

The Operation argument was


SQL_FETCH_BY_BOOKMARK, and the
performance of datetime arithmetic on
data being retrieved from the result
set resulted in a datetime field (the
year, month, day, hour, minute, or
second field) of the result falling
outside the permissible range of values
for the field or being invalid based on
the Gregorian calendar's natural rules
for datetimes.

22015 Interval field overflow The Operation argument was


SQL_ADD or
SQL_UPDATE_BY_BOOKMARK, and the
assignment of an exact numeric or
interval C type to an interval SQL data
type caused a loss of significant digits.

The Operation argument was


SQL_ADD or
SQL_UPDATE_BY_BOOKMARK; when
assigning to an interval SQL type,
there was no representation of the
value of the C type in the interval SQL
type.

The Operation argument was


SQL_FETCH_BY_BOOKMARK, and
assigning from an exact numeric or
interval SQL type to an interval C type
caused a loss of significant digits in the
leading field.

The Operation argument was


SQL_FETCH_BY_BOOKMARK; when
assigning to an interval C type, there
was no representation of the value of
the SQL type in the interval C type.
SQ L STAT E ERRO R DESC RIP T IO N

22018 Invalid character value for cast The Operation argument was
specification SQL_FETCH_BY_BOOKMARK; the C
type was an exact or approximate
numeric, a datetime, or an interval
data type; the SQL type of the column
was a character data type; and the
value in the column was not a valid
literal of the bound C type.

The argument Operation was


SQL_ADD or
SQL_UPDATE_BY_BOOKMARK; the
SQL type was an exact or approximate
numeric, a datetime, or an interval
data type; the C type was
SQL_C_CHAR; and the value in the
column was not a valid literal of the
bound SQL type.

23000 Integrity constraint violation The Operation argument was


SQL_ADD,
SQL_DELETE_BY_BOOKMARK, or
SQL_UPDATE_BY_BOOKMARK, and an
integrity constraint was violated.

The Operation argument was


SQL_ADD, and a column that was not
bound is defined as NOT NULL and
has no default.

The Operation argument was


SQL_ADD, the length specified in the
bound StrLen_or_IndPtr buffer was
SQL_COLUMN_IGNORE, and the
column did not have a default value.

24000 Invalid cursor state The StatementHandle was in an


executed state, but no result set was
associated with the StatementHandle.

40001 Serialization failure The transaction was rolled back


because of a resource deadlock with
another transaction.

40003 Statement completion unknown The associated connection failed


during the execution of this function,
and the state of the transaction cannot
be determined.

42000 Syntax error or access violation The driver was unable to lock the row
as needed to perform the operation
requested in the Operation argument.
SQ L STAT E ERRO R DESC RIP T IO N

44000 WITH CHECK OPTION violation The Operation argument was


SQL_ADD or
SQL_UPDATE_BY_BOOKMARK, and the
insert or update was performed on a
viewed table (or a table derived from
the viewed table) that was created by
specifying WITH CHECK OPTION, in
such a way that one or more rows
affected by the insert or update will no
longer be present in the viewed table.

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.

HY001 Memory allocation error The driver was unable to allocate


memory required to support execution
or completion of the function.

HY008 Operation canceled Asynchronous processing was enabled


for the StatementHandle. The function
was called, and before it completed
execution, SQLCancel or
SQLCancelHandle was called on the
StatementHandle. Then the function
was called again on the
StatementHandle.

The function was called, and before it


completed execution, SQLCancel or
SQLCancelHandle was called on the
StatementHandle from a different
thread in a multithread application.
SQ L STAT E ERRO R DESC RIP T IO N

HY010 Function sequence error (DM) An asynchronously executing


function was called for the connection
handle that is associated with the
StatementHandle. This asynchronous
function was still executing when the
SQLBulkOperations function was
called.

(DM) SQLExecute , SQLExecDirect ,


or SQLMoreResults was called for
the StatementHandle and returned
SQL_PARAM_DATA_AVAILABLE. This
function was called before data was
retrieved for all streamed parameters.

(DM) The specified StatementHandle


was not in an executed state. The
function was called without first calling
SQLExecDirect , SQLExecute , or a
catalog function.

(DM) An asynchronously executing


function (not this one) was called for
the StatementHandle and was still
executing when this function was
called.

(DM) SQLExecute , SQLExecDirect ,


or SQLSetPos was called for the
StatementHandle and returned
SQL_NEED_DATA. This function was
called before data was sent for all
data-at-execution parameters or
columns.

(DM) The driver was an ODBC 2.x


driver, and SQLBulkOperations was
called for a StatementHandle before
SQLFetchScroll or SQLFetch was
called.

(DM) SQLBulkOperations was called


after SQLExtendedFetch was called
on the StatementHandle.

HY011 Attribute cannot be set now (DM) The driver was an ODBC 2.x
driver, and the
SQL_ATTR_ROW_STATUS_PTR
statement attribute was set between
calls to SQLFetch or SQLFetchScroll
and SQLBulkOperations .

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.
SQ L STAT E ERRO R DESC RIP T IO N

HY090 Invalid string or buffer length The Operation argument was


SQL_ADD or
SQL_UPDATE_BY_BOOKMARK; a data
value was not a null pointer; the C
data type was SQL_C_BINARY or
SQL_C_CHAR; and the column length
value was less than 0, but not equal to
SQL_DATA_AT_EXEC,
SQL_COLUMN_IGNORE, SQL_NTS, or
SQL_NULL_DATA, or less than or equal
to SQL_LEN_DATA_AT_EXEC_OFFSET.

The value in a length/indicator buffer


was SQL_DATA_AT_EXEC; the SQL type
was either SQL_LONGVARCHAR,
SQL_LONGVARBINARY, or a long data
source-specific data type; and the
SQL_NEED_LONG_DATA_LEN
information type in SQLGetInfo was
"Y".

The Operation argument was


SQL_ADD, the
SQL_ATTR_USE_BOOKMARK statement
attribute was set to
SQL_UB_VARIABLE, and column 0 was
bound to a buffer whose length was
not equal to the maximum length for
the bookmark for this result set. (This
length is available in the
SQL_DESC_OCTET_LENGTH field of the
IRD and can be obtained by calling
SQLDescribeCol, SQLColAttribute ,
or SQLGetDescField .)

HY092 Invalid attribute identifier (DM) The value specified for the
Operation argument was invalid.

The Operation argument was


SQL_ADD,
SQL_UPDATE_BY_BOOKMARK, or
SQL_DELETE_BY_BOOKMARK, and the
SQL_ATTR_CONCURRENCY statement
attribute was set to
SQL_CONCUR_READ_ONLY.

The Operation argument was


SQL_DELETE_BY_BOOKMARK,
SQL_FETCH_BY_BOOKMARK, or
SQL_UPDATE_BY_BOOKMARK, and the
bookmark column was not bound or
the SQL_ATTR_USE_BOOKMARKS
statement attribute was set to
SQL_UB_OFF.

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.
SQ L STAT E ERRO R DESC RIP T IO N

HYC00 Optional feature not implemented The driver or data source does not
support the operation requested in
the Operation argument.

HYT00 Timeout expired The query timeout period expired


before the data source returned the
result set. The timeout period is set
through SQLSetStmtAttr with an
Attribute argument of
SQL_ATTR_QUERY_TIMEOUT.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
StatementHandle does not support
the function.

IM017 Polling is disabled in asynchronous Whenever the notification model is


notification mode used, polling is disabled.

IM018 SQLCompleteAsync has not been If the previous function call on the
called to complete the previous handle returns SQL_STILL_EXECUTING
asynchronous operation on this and if notification mode is enabled,
handle. SQLCompleteAsync must be called
on the handle to do post-processing
and complete the operation.

Comments
Cau t i on

For information about what statement states SQLBulkOperations can be called in and what it must do for
compatibility with ODBC 2.x applications, see the Block Cursors, Scrollable Cursors, and Backward Compatibility
section in Appendix G: Driver Guidelines for Backward Compatibility.
An application uses SQLBulkOperations to perform the following operations on the base table or view that
corresponds to the current query:
Add new rows.
Update a set of rows where each row is identified by a bookmark.
Delete a set of rows where each row is identified by a bookmark.
Fetch a set of rows where each row is identified by a bookmark.
After a call to SQLBulkOperations , the block cursor position is undefined. The application has to call
SQLFetchScroll to set the cursor position. An application should call SQLFetchScroll only with a
FetchOrientation argument of SQL_FETCH_FIRST, SQL_FETCH_LAST, SQL_FETCH_ABSOLUTE, or
SQL_FETCH_BOOKMARK. The cursor position is undefined if the application calls SQLFetch or SQLFetchScroll
with a FetchOrientation argument of SQL_FETCH_PRIOR, SQL_FETCH_NEXT, or SQL_FETCH_RELATIVE.
A column can be ignored in bulk operations performed by a call to SQLBulkOperations by setting the column
length/indicator buffer specified in the call to SQLBindCol , to SQL_COLUMN_IGNORE.
It is not necessary for the application to set the SQL_ATTR_ROW_OPERATION_PTR statement attribute when it
calls SQLBulkOperations because rows cannot be ignored when performing bulk operations with this
function.
The buffer pointed to by the SQL_ATTR_ROWS_FETCHED_PTR statement attribute contains the number of rows
affected by a call to SQLBulkOperations .
When the Operation argument is SQL_ADD or SQL_UPDATE_BY_BOOKMARK and the select-list of the query
specification associated with the cursor contains more than one reference to the same column, it is driver-
defined whether an error is generated or the driver ignores the duplicated references and performs the
requested operations.
For more information about how to use SQLBulkOperations , see Updating Data with SQLBulkOperations.

Performing Bulk Inserts


To insert data with SQLBulkOperations , an application performs the following sequence of steps:
1. Executes a query that returns a result set.
2. Sets the SQL_ATTR_ROW_ARRAY_SIZE statement attribute to the number of rows that it wants to insert.
3. Calls SQLBindCol to bind the data that it wants to insert. The data is bound to an array with a size equal
to the value of SQL_ATTR_ROW_ARRAY_SIZE.

NOTE
The size of the array pointed to by the SQL_ATTR_ROW_STATUS_PTR statement attribute should either be equal to
SQL_ATTR_ROW_ARRAY_SIZE or SQL_ATTR_ROW_STATUS_PTR should be a null pointer.

4. Calls SQLBulkOperations (StatementHandle, SQL_ADD) to perform the insertion.


5. If the application has set the SQL_ATTR_ROW_STATUS_PTR statement attribute, it can inspect this array to
see the result of the operation.
If an application binds column 0 before it calls SQLBulkOperations with an Operation argument of SQL_ADD,
the driver will update the bound column 0 buffers with the bookmark values for the newly inserted row. For this
to occur, the application must have set the SQL_ATTR_USE_BOOKMARKS statement attribute to
SQL_UB_VARIABLE before executing the statement. (This does not work with an ODBC 2.x driver.)
Long data can be added in parts by SQLBulkOperations, by using calls to SQLParamData and SQLPutData. For
more information, see "Providing Long Data for Bulk Inserts and Updates" later in this function reference.
It is not necessary for the application to call SQLFetch or SQLFetchScroll before it calls SQLBulkOperations
(except when going against an ODBC 2.x driver; see Backward Compatibility and Standards Compliance).
The behavior is driver-defined if SQLBulkOperations , with an Operation argument of SQL_ADD, is called on a
cursor that contains duplicate columns. The driver can return a driver-defined SQLSTATE, add the data to the first
column that appears in the result set, or perform other driver-defined behavior.

Performing Bulk Updates by Using Bookmarks


To perform bulk updates by using bookmarks with SQLBulkOperations , an application performs the following
steps in sequence:
1. Sets the SQL_ATTR_USE_BOOKMARKS statement attribute to SQL_UB_VARIABLE.
2. Executes a query that returns a result set.
3. Sets the SQL_ATTR_ROW_ARRAY_SIZE statement attribute to the number of rows that it wants to update.
4. Calls SQLBindCol to bind the data that it wants to update. The data is bound to an array with a size
equal to the value of SQL_ATTR_ROW_ARRAY_SIZE. It also calls SQLBindCol to bind column 0 (the
bookmark column).
5. Copies the bookmarks for rows that it is interested in updating into the array bound to column 0.
6. Updates the data in the bound buffers.

NOTE
The size of the array pointed to by the SQL_ATTR_ROW_STATUS_PTR statement attribute should be equal to
SQL_ATTR_ROW_ARRAY_SIZE or SQL_ATTR_ROW_STATUS_PTR should be a null pointer.

7. Calls SQLBulkOperations (StatementHandle, SQL_UPDATE_BY_BOOKMARK).

NOTE
If the application has set the SQL_ATTR_ROW_STATUS_PTR statement attribute, it can inspect this array to see the
result of the operation.

8. Optionally calls SQLBulkOperations (StatementHandle, SQL_FETCH_BY_BOOKMARK) to fetch data into


the bound application buffers to verify that the update has occurred.
9. If data has been updated, the driver changes the value in the row status array for the appropriate rows to
SQL_ROW_UPDATED.
Bulk updates performed by SQLBulkOperations can include long data by using calls to SQLParamData and
SQLPutData . For more information, see "Providing Long Data for Bulk Inserts and Updates" later in this
function reference.
If bookmarks persist across cursors, the application does not need to call SQLFetch or SQLFetchScroll before
updating by bookmarks. It can use bookmarks that it has stored from a previous cursor. If bookmarks do not
persist across cursors, the application has to call SQLFetch or SQLFetchScroll to retrieve the bookmarks.
The behavior is driver-defined if SQLBulkOperations , with an Operation argument of
SQL_UPDATE_BY_BOOKMARK, is called on a cursor that contains duplicate columns. The driver can return a
driver-defined SQLSTATE, update the first column that appears in the result set, or perform other driver-defined
behavior.

Performing Bulk Fetches Using Bookmarks


To perform bulk fetches using bookmarks with SQLBulkOperations , an application performs the following
steps in sequence:
1. Sets the SQL_ATTR_USE_BOOKMARKS statement attribute to SQL_UB_VARIABLE.
2. Executes a query that returns a result set.
3. Sets the SQL_ATTR_ROW_ARRAY_SIZE statement attribute to the number of rows that it wants to fetch.
4. Calls SQLBindCol to bind the data that it wants to fetch. The data is bound to an array with a size equal
to the value of SQL_ATTR_ROW_ARRAY_SIZE. It also calls SQLBindCol to bind column 0 (the bookmark
column).
5. Copies the bookmarks for rows that it is interested in fetching into the array bound to column 0. (This
assumes that the application has already obtained the bookmarks separately.)

NOTE
The size of the array pointed to by the SQL_ATTR_ROW_STATUS_PTR statement attribute should be equal to
SQL_ATTR_ROW_ARRAY_SIZE or SQL_ATTR_ROW_STATUS_PTR should be a null pointer.

6. Calls SQLBulkOperations (StatementHandle, SQL_FETCH_BY_BOOKMARK).


7. If the application has set the SQL_ATTR_ROW_STATUS_PTR statement attribute, it can inspect this array to
see the result of the operation.
If bookmarks persist across cursors, the application does not need to call SQLFetch or SQLFetchScroll before
fetching by bookmarks. It can use bookmarks that it has stored from a previous cursor. If bookmarks do not
persist across cursors, the application has to call SQLFetch or SQLFetchScroll one time to retrieve the
bookmarks.

Performing Bulk Deletes Using Bookmarks


To perform bulk deletes using bookmarks with SQLBulkOperations , an application performs the following
steps in sequence:
1. Sets the SQL_ATTR_USE_BOOKMARKS statement attribute to SQL_UB_VARIABLE.
2. Executes a query that returns a result set.
3. Sets the SQL_ATTR_ROW_ARRAY_SIZE statement attribute to the number of rows that it wants to delete.
4. Calls SQLBindCol to bind column 0 (the bookmark column).
5. Copies the bookmarks for rows that it is interested in deleting into the array bound to column 0.

NOTE
The size of the array pointed to by the SQL_ATTR_ROW_STATUS_PTR statement attribute should be equal to
SQL_ATTR_ROW_ARRAY_SIZE or SQL_ATTR_ROW_STATUS_PTR should be a null pointer.

6. Calls SQLBulkOperations (StatementHandle, SQL_DELETE_BY_BOOKMARK).


7. If the application has set the SQL_ATTR_ROW_STATUS_PTR statement attribute, it can inspect this array to
see the result of the operation.
If bookmarks persist across cursors, the application does not have to call SQLFetch or SQLFetchScroll before
deleting by bookmarks. It can use bookmarks that it has stored from a previous cursor. If bookmarks do not
persist across cursors, the application has to call SQLFetch or SQLFetchScroll one time to retrieve the
bookmarks.

Providing Long Data for Bulk Inserts and Updates


Long data can be provided for bulk inserts and updates performed by calls to SQLBulkOperations . To insert or
update long data, an application performs the following steps in addition to the steps described in the
"Performing Bulk Inserts" and "Performing Bulk Updates Using Bookmarks" sections earlier in this topic.
1. When it binds the data by using SQLBindCol , the application places an application-defined value, such
as the column number, in the *TargetValuePtr buffer for data-at-execution columns. The value can be used
later to identify the column.
The application places the result of the SQL_LEN_DATA_AT_EXEC(length) macro in the *StrLen_or_IndPtr
buffer. If the SQL data type of the column is SQL_LONGVARBINARY, SQL_LONGVARCHAR, or a long data
source-specific data type and the driver returns "Y" for the SQL_NEED_LONG_DATA_LEN information type
in SQLGetInfo , length is the number of bytes of data to be sent for the parameter; otherwise, it must be
a nonnegative value and is ignored.
2. When SQLBulkOperations is called, if there are data-at-execution columns, the function returns
SQL_NEED_DATA and proceeds to step 3, which follows. (If there are no data-at-execution columns, the
process is complete.)
3. The application calls SQLParamData to retrieve the address of the *TargetValuePtr buffer for the first
data-at-execution column to be processed. SQLParamData returns SQL_NEED_DATA. The application
retrieves the application-defined value from the *TargetValuePtr buffer.

NOTE
Although data-at-execution parameters resemble data-at-execution columns, the value returned by
SQLParamData is different for each.

Data-at-execution columns are columns in a rowset for which data will be sent with SQLPutData when a
row is updated or inserted with SQLBulkOperations . They are bound with SQLBindCol . The value
returned by SQLParamData is the address of the row in the *TargetValuePtr buffer that is being
processed.
4. The application calls SQLPutData one or more times to send data for the column. More than one call is
needed if all the data value cannot be returned in the *TargetValuePtr buffer specified in SQLPutData ;
multiple calls to SQLPutData for the same column are allowed only when sending character C data to a
column with a character, binary, or data source-specific data type or when sending binary C data to a
column with a character, binary, or data source-specific data type.
5. The application calls SQLParamData again to signal that all data has been sent for the column.
If there are more data-at-execution columns, SQLParamData returns SQL_NEED_DATA and the
address of the TargetValuePtr buffer for the next data-at-execution column to be processed. The
application repeats steps 4 and 5.
If there are no more data-at-execution columns, the process is complete. If the statement was
executed successfully, SQLParamData returns SQL_SUCCESS or SQL_SUCCESS_WITH_INFO; if
the execution failed, it returns SQL_ERROR. At this point, SQLParamData can return any
SQLSTATE that can be returned by SQLBulkOperations .
If the operation is canceled or an error occurs in SQLParamData or SQLPutData after SQLBulkOperations
returns SQL_NEED_DATA and before data is sent for all data-at-execution columns, the application can call only
SQLCancel , SQLGetDiagField , SQLGetDiagRec , SQLGetFunctions , SQLParamData , or SQLPutData for
the statement or the connection associated with the statement. If it calls any other function for the statement or
the connection associated with the statement, the function returns SQL_ERROR and SQLSTATE HY010 (Function
sequence error).
If the application calls SQLCancel while the driver still needs data for data-at-execution columns, the driver
cancels the operation. The application can then call SQLBulkOperations again; canceling does not affect the
cursor state or the current cursor position.

Row Status Array


The row status array contains status values for each row of data in the rowset after a call to
SQLBulkOperations . The driver sets the status values in this array after a call to SQLFetch , SQLFetchScroll ,
SQLSetPos , or SQLBulkOperations . This array is initially populated by a call to SQLBulkOperations if
SQLFetch or SQLFetchScroll has not been called before SQLBulkOperations . This array is pointed to by the
SQL_ATTR_ROW_STATUS_PTR statement attribute. The number of elements in the row status arrays must equal
the number of rows in the rowset (as defined by the SQL_ATTR_ROW_ARRAY_SIZE statement attribute). For
information about this row status array, see SQLFetch.

Code Example
The following example fetches 10 rows of data at a time from the Customers table. It then prompts the user for
an action to take. To reduce network traffic, the example buffer updates, deletes, and inserts locally in the bound
arrays, but at offsets past the rowset data. When the user chooses to send updates, deletes, and inserts to the
data source, the code sets the binding offset appropriately and calls SQLBulkOperations . For simplicity, the
user cannot buffer more than 10 updates, deletes, or inserts.

// SQLBulkOperations_Function.cpp
// compile with: ODBC32.lib
#include <windows.h>
#include <sqlext.h>
#include "stdio.h"

#define UPDATE_ROW 100


#define DELETE_ROW 101
#define ADD_ROW 102
#define SEND_TO_DATA_SOURCE 103
#define UPDATE_OFFSET 10
#define INSERT_OFFSET 20
#define DELETE_OFFSET 30

// Define structure for customer data (assume 10 byte maximum bookmark size).
typedef struct tagCustStruct {
SQLCHAR Bookmark[10];
SQLINTEGER BookmarkLen;
SQLUINTEGER CustomerID;
SQLINTEGER CustIDInd;
SQLCHAR CompanyName[51];
SQLINTEGER NameLenOrInd;
SQLCHAR Address[51];
SQLINTEGER AddressLenOrInd;
SQLCHAR Phone[11];
SQLINTEGER PhoneLenOrInd;
} CustStruct;

// Allocate 40 of these structures. Elements 0-9 are for the current rowset,
// elements 10-19 are for the buffered updates, elements 20-29 are for
// the buffered inserts, and elements 30-39 are for the buffered deletes.
CustStruct CustArray[40];
SQLUSMALLINT RowStatusArray[10], Action, RowNum, NumUpdates = 0, NumInserts = 0,
NumDeletes = 0;
SQLLEN BindOffset = 0;
SQLRETURN retcode;
SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
SQLHSTMT hstmt = NULL;

int main() {
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);

retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);


retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

retcode = SQLConnect(hdbc, (SQLCHAR*) "Northwind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);


retcode = SQLConnect(hdbc, (SQLCHAR*) "Northwind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

// Set the following statement attributes:


// SQL_ATTR_CURSOR_TYPE: Keyset-driven
// SQL_ATTR_ROW_BIND_TYPE: Row-wise
// SQL_ATTR_ROW_ARRAY_SIZE: 10
// SQL_ATTR_USE_BOOKMARKS: Use variable-length bookmarks
// SQL_ATTR_ROW_STATUS_PTR: Points to RowStatusArray
// SQL_ATTR_ROW_BIND_OFFSET_PTR: Points to BindOffset
retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN, 0);
retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(CustStruct), 0);
retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);
retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS, (SQLPOINTER)SQL_UB_VARIABLE, 0);
retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, RowStatusArray, 0);
retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, &BindOffset, 0);

// Bind arrays to the bookmark, CustomerID, CompanyName, Address, and Phone columns.
retcode = SQLBindCol(hstmt, 0, SQL_C_VARBOOKMARK, CustArray[0].Bookmark, sizeof(CustArray[0].Bookmark),
&CustArray[0].BookmarkLen);
retcode = SQLBindCol(hstmt, 1, SQL_C_ULONG, &CustArray[0].CustomerID, 0, &CustArray[0].CustIDInd);
retcode = SQLBindCol(hstmt, 2, SQL_C_CHAR, CustArray[0].CompanyName, sizeof(CustArray[0].CompanyName),
&CustArray[0].NameLenOrInd);
retcode = SQLBindCol(hstmt, 3, SQL_C_CHAR, CustArray[0].Address, sizeof(CustArray[0].Address),
&CustArray[0].AddressLenOrInd);
retcode = SQLBindCol(hstmt, 4, SQL_C_CHAR, CustArray[0].Phone, sizeof(CustArray[0].Phone),
&CustArray[0].PhoneLenOrInd);

// Execute a statement to retrieve rows from the Customers table.


retcode = SQLExecDirect(hstmt, (SQLCHAR*)"SELECT CustomerID, CompanyName, Address, Phone FROM Customers",
SQL_NTS);

// Fetch and display the first 10 rows.


retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);
// DisplayCustData(CustArray, 10);

// Call GetAction to get an action and a row number from the user.
// while (GetAction(&Action, &RowNum)) {
Action = SQL_FETCH_NEXT;
RowNum = 2;
switch (Action) {
case SQL_FETCH_NEXT:
case SQL_FETCH_PRIOR:
case SQL_FETCH_FIRST:
case SQL_FETCH_LAST:
case SQL_FETCH_ABSOLUTE:
case SQL_FETCH_RELATIVE:
// Fetch and display the requested data.
SQLFetchScroll(hstmt, Action, RowNum);
// DisplayCustData(CustArray, 10);
break;

case UPDATE_ROW:
// Check if we have reached the maximum number of buffered updates.
if (NumUpdates < 10) {
// Get the new customer data and place it in the next available element of
// the buffered updates section of CustArray, copy the bookmark of the row
// being updated to the same element, and increment the update counter.
// Checking to see we have not already buffered an update for this
// row not shown.
// GetNewCustData(CustArray, UPDATE_OFFSET + NumUpdates);
memcpy(CustArray[UPDATE_OFFSET + NumUpdates].Bookmark,
CustArray[RowNum - 1].Bookmark,
CustArray[RowNum - 1].BookmarkLen);
CustArray[UPDATE_OFFSET + NumUpdates].BookmarkLen =
CustArray[RowNum - 1].BookmarkLen;
NumUpdates++;
} else {
printf("Buffers full. Send buffered changes to the data source.");
}
}
break;
case DELETE_ROW:
// Check if we have reached the maximum number of buffered deletes.
if (NumDeletes < 10) {
// Copy the bookmark of the row being deleted to the next available element
// of the buffered deletes section of CustArray and increment the delete
// counter. Checking to see we have not already buffered an update for
// this row not shown.
memcpy(CustArray[DELETE_OFFSET + NumDeletes].Bookmark,
CustArray[RowNum - 1].Bookmark,
CustArray[RowNum - 1].BookmarkLen);

CustArray[DELETE_OFFSET + NumDeletes].BookmarkLen =
CustArray[RowNum - 1].BookmarkLen;

NumDeletes++;
} else
printf("Buffers full. Send buffered changes to the data source.");
break;

case ADD_ROW:
// reached maximum number of buffered inserts?
if (NumInserts < 10) {
// Get the new customer data and place it in the next available element of
// the buffered inserts section of CustArray and increment insert counter.
// GetNewCustData(CustArray, INSERT_OFFSET + NumInserts);
NumInserts++;
} else
printf("Buffers full. Send buffered changes to the data source.");
break;

case SEND_TO_DATA_SOURCE:
// If there are any buffered updates, inserts, or deletes, set the array size
// to that number, set the binding offset to use the data in the buffered
// update, insert, or delete part of CustArray, and call SQLBulkOperations to
// do the updates, inserts, or deletes. Because we will never have more than
// 10 updates, inserts, or deletes, we can use the same row status array.
if (NumUpdates) {
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumUpdates, 0);
BindOffset = UPDATE_OFFSET * sizeof(CustStruct);
SQLBulkOperations(hstmt, SQL_UPDATE_BY_BOOKMARK);
NumUpdates = 0;
}

if (NumInserts) {
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumInserts, 0);
BindOffset = INSERT_OFFSET * sizeof(CustStruct);
SQLBulkOperations(hstmt, SQL_ADD);
NumInserts = 0;
}

if (NumDeletes) {
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)NumDeletes, 0);
BindOffset = DELETE_OFFSET * sizeof(CustStruct);
SQLBulkOperations(hstmt, SQL_DELETE_BY_BOOKMARK);
NumDeletes = 0;
}

// If there were any updates, inserts, or deletes, reset the binding offset
// and array size to their original values.
if (NumUpdates || NumInserts || NumDeletes) {
SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)10, 0);
BindOffset = 0;
}
break;
}
// }

// Close the cursor.


// Close the cursor.
SQLFreeStmt(hstmt, SQL_CLOSE);
}

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Binding a buffer to a column in a result set SQLBindCol Function

Canceling statement processing SQLCancel Function

Fetching a block of data or scrolling through a result set SQLFetchScroll Function

Getting a single field of a descriptor SQLGetDescField Function

Getting multiple fields of a descriptor SQLGetDescRec Function

Setting a single field of a descriptor SQLSetDescField Function

Setting multiple fields of a descriptor SQLSetDescRec Function

Positioning the cursor, refreshing data in the rowset, or SQLSetPos Function


updating or deleting data in the rowset

Setting a statement attribute SQLSetStmtAttr Function

See Also
ODBC API Reference
ODBC Header Files
SQLCancel Function
4/27/2022 • 5 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: ISO 92
Summar y
SQLCancel cancels the processing on a statement.
To cancel processing on a connection or statement, use SQLCancelHandle Function.

Syntax
SQLRETURN SQLCancel(
SQLHSTMT StatementHandle);

Arguments
StatementHandle
[Input] Statement handle.

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLCancel returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value can be
obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a Handle of
StatementHandle. The following table lists the SQLSTATE values commonly returned by SQLCancel and
explains each one in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs
returned by the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless
noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the argument
*MessageText buffer describes the
error and its cause.
SQ L STAT E ERRO R DESC RIP T IO N

HY001 Memory allocation error The driver was unable to allocate


memory required to support execution
or completion of the function.

HY010 Function sequence error (DM) An asynchronously executing


function was called for the connection
handle that is associated with the
StatementHandle. This asynchronous
function was still executing when the
SQLCancel function was called.

(DM) Cancel operation failed because


an asynchronous operation is in
progress on a connection handle that
is associated with StatementHandle.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY018 Server declined cancel request The server declined the cancel request.

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
StatementHandle does not support
the function.

Comments
SQLCancel can cancel the following types of processing on a statement:
A function running asynchronously on the statement.
A function on a statement that needs data.
A function running on the statement on another thread.
In ODBC 2.x, if an application calls SQLCancel when no processing is being done on the statement, SQLCancel
has the same effect as SQLFreeStmt with the SQL_CLOSE option; this behavior is defined only for
completeness and applications should call SQLFreeStmt or SQLCloseCursor to close cursors.
When SQLCancel is called to cancel a function running asynchronously in a statement or a function on a
statement that needs data, diagnostic records posted by the function being canceled are cleared, and
SQLCancel posts its own diagnostic records; when SQLCancel is called to cancel a function running on a
statement on another thread, however, it does not clear the diagnostic records of the being canceled function
and does not post its own diagnostic records.

Canceling Asynchronous Processing


After an application calls a function asynchronously, it calls the function repeatedly to determine whether it has
finished processing. If the function is still processing, it returns SQL_STILL_EXECUTING. If the function has
finished processing, it returns a different code.
After any call to the function that returns SQL_STILL_EXECUTING, an application can call SQLCancel to cancel
the function. If the cancel request is successful, the driver returns SQL_SUCCESS. This message does not indicate
that the function was actually canceled; it indicates that the cancel request was processed. When or if the
function is actually canceled is driver-dependent and data source-dependent. The application must continue to
call the original function until the return code is not SQL_STILL_EXECUTING. If the function was successfully
canceled, the return code is SQL_ERROR and SQLSTATE HY008 (Operation canceled). If the function completed
its normal processing, the return code is SQL_SUCCESS or SQL_SUCCESS_WITH_INFO if the function succeeded
or SQL_ERROR and a SQLSTATE other than HY008 (Operation canceled) if the function failed.

NOTE
In ODBC 3.5, a call to SQLCancel when no processing is being done on the statement is not treated as SQLFreeStmt
with the SQL_CLOSE option, but has is no effect at all. To close a cursor, an application should call SQLCloseCursor , not
SQLCancel.

For more information about asynchronous processing, see Asynchronous Execution.

Canceling Functions that Need Data


After SQLExecute or SQLExecDirect returns SQL_NEED_DATA and before data has been sent for all data-at-
execution parameters, an application can call SQLCancel to cancel the statement execution. After the statement
has been canceled, the application can call SQLExecute or SQLExecDirect again. For more information, see
SQLBindParameter.
After SQLBulkOperations or SQLSetPos returns SQL_NEED_DATA and before data has been sent for all data-
at-execution columns, an application can call SQLCancel to cancel the operation. After the operation has been
canceled, the application can call SQLBulkOperations or SQLSetPos again; canceling does not affect the
cursor state or the current cursor position. For more information, see SQLBulkOperations or SQLSetPos.

Canceling Functions Executing on Another Thread


In a multithread application, the application can cancel a function that is running on another thread. To cancel
the function, the application calls SQLCancel with the same statement handle as that used by the target
function, but on a different thread. How the function is canceled depends on the driver and the operating
system. As in canceling a function running asynchronously, the return code of the SQLCancel indicates only
whether the driver processed the request successfully. Only SQL_SUCCESS or SQL_ERROR can be returned; no
diagnostic information is returned. If the original function is canceled, it returns SQL_ERROR and SQLSTATE
HY008 (Operation canceled).
If an SQL statement is being executed when SQLCancel is called on another thread to cancel the statement
execution, it is possible for the execution to succeed and return SQL_SUCCESS while the cancel is also successful.
In this case, the Driver Manager assumes that the cursor opened by the statement execution is closed by the
cancel, so the application will not be able to use the cursor.
For more information about threading, see Multithreading.
Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Binding a buffer to a parameter SQLBindParameter Function

Performing bulk insert or update operations SQLBulkOperations Function

Cancels a function running asynchronously on a connection SQLCancelHandle Function


handle, in addition to the functionality of SQLCancel.

Executing an SQL statement SQLExecDirect Function

Executing a prepared SQL statement SQLExecute Function

Freeing a statement handle SQLFreeStmt

Obtaining a field of a diagnostic record or a field of the SQLGetDiagField Function


diagnostic header

Obtaining multiple fields of a diagnostic data structure SQLGetDiagRec Function

Returning the next parameter to send data for SQLParamData Function

Sending parameter data at execution time SQLPutData Function

Positioning the cursor in a rowset, refreshing data in the SQLSetPos Function


rowset, or updating or deleting data in the result set

See Also
ODBC API Reference
ODBC Header Files
SQLCancelHandle Function
4/27/2022 • 5 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 3.8 Standards Compliance: None
It is expected that most ODBC 3.8 (and later) drivers will implement this function. If a driver does not, a call to
SQLCancelHandle with a connection handle in the Handle parameter will return SQL_ERROR with a SQLSTATE
of IM001 and message 'Driver does not support this function'' A call to SQLCancelHandle with a statement
handle as the Handle parameter will be mapped to a call to SQLCancel by the Driver Manager and can be
processed if the driver implements SQLCancel . An application can use SQLGetFunctions to determine if a
driver supports SQLCancelHandle .
Summar y
SQLCancelHandle cancels the processing on a connection or statement. The Driver Manager maps a call to
SQLCancelHandle to a call to SQLCancel when HandleType is SQL_HANDLE_STMT.

Syntax
SQLRETURN SQLCancelHandle(
SQLSMALLINT HandleType,
SQLHANDLE Handle);

Arguments
HandleType
[Input] The type of the handle on which to cacel processing. Valid values are SQL_HANDLE_DBC or
SQL_HANDLE_STMT.
Handle
[Input] The handle on which to cancel processing.
If Handle is not a valid handle of the type specified by HandleType, SQLCancelHandle returns
SQL_INVALID_HANDLE.

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLCancelHandle returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value
can be obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a statement handle
Handle or a HandleType of SQL_HANDLE_DBC and a connection handle Handle.
The following table lists the SQLSTATE values commonly returned by SQLCancelHandle and explains each one
in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs returned by the
Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless noted otherwise.
SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the argument
*MessageText buffer describes the
error and its cause.

HY001 Memory allocation error The driver was unable to allocate


memory required to support execution
or completion of the function.

HY010 Function sequence error An asynchronously executing,


statement-related function was called
for one of the statement handles
associated with the Handle, and
HandleType was set to
SQL_HANDLE_DBC. The asynchronous
function was still executing when
SQLCancelHandle was called.

(DM) The HandleType argument was


SQL_HANDLE_STMT; an
asynchronously executing function was
called on the associated connection
handle; and the function was still
executing when this function was
called.

(DM) SQLExecute , SQLExecDirect ,


or SQLMoreResults was called for
one of the statement handles
associated with the Handle and
HandleType was set to
SQL_HANDLE_DBC, and returned
SQL_PARAM_DATA_AVAILABLE. This
function was called before data was
retrieved for all streamed parameters.

SQLBrowseConnect was called for


ConnectionHandle, and returned
SQL_NEED_DATA. This function was
called before the browsing process
completed.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY092 Invalid attribute/option identifier HandleType was set to


SQL_HANDLE_ENV or
SQL_HANDLE_DESC.
SQ L STAT E ERRO R DESC RIP T IO N

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
Handle does not support the function.

If SQLCancelHandle is called with HandleType set to SQL_HANDLE_STMT, it can return any SQLSTATE that can
be returned by the function SQLCancel .

Comments
This function is similar to SQLCancel but may take either a connection or statement handle as a parameter
rather than only a statement handle. The Driver Manager maps a call to SQLCancelHandle to a call to
SQLCancel when HandleType is SQL_HANDLE_STMT. This allows applications to use SQLCancelHandle to
cancel statement operations even if the driver does not implement SQLCancelHandle .
For more information about cancelling a statement operation, see SQLCancel Function.
If there are no operations in progress on Handle the call to SQLCancelHandle has no effect.
SQLCancelHandle on a connection handle can cancel the following types of processing:
A function running asynchronously on the connection.
A function running on the connection handle on another thread.
When SQLCancelHandle is called to cancel a function running asynchronously in a connection, diagnostic
records posted by SQLCancelHandle are appended to those returned by the operation being canceled;
SQLCancelHandle does not return diagnostic records, however, when canceling a function running on a
connection on another thread.
Using SQLCancelHandle to cancel SQLEndTran may put the connection in suspended state. For more
information on suspended state, see SQLEndTran Function.

NOTE
For information about how to use SQLCancelHandle in an application that will be deployed on a Windows operating
system older than Windows 7, see Compatibility Matrix.

Canceling Connection-Related Asynchronous Processing


If a function returns SQL_STILL_EXECUTING, an application can call SQLCancelHandle to cancel the operation.
If the cancel request is successful, SQLCancelHandle returns SQL_SUCCESS. This does not mean that the
original function was canceled; it indicates that the cancel request was processed. The driver and data source
determine when or if the operation is canceled. The application must continue to call the original function until
the return code is not SQL_STILL_EXECUTING. If the original function was canceled, the return code is
SQL_ERROR and SQLSTATE HY008 (Operation canceled). If the original function completed its normal
processing (was not cancelled), the return code is SQL_SUCCESS or SQL_SUCCESS_WITH_INFO, or SQL_ERROR
and a SQLSTATE other than HY008 (Operation canceled), if the original function failed.
Canceling Functions Executing on Another Thread
In a multithread application, the application can cancel an operation that is running on another thread. To cancel
the operation, the application calls SQLCancelHandle with the handle used by the function, but on a different
thread. The driver and operating system determine how the operation is canceled. The SQLCancelHandle
return code indicates whether the driver processed the request, returning either SQL_SUCCESS or SQL_ERROR
(no diagnostic information is returned). If processing on the original function is canceled, the original function
returns SQL_ERROR and SQLSTATE HY008 (Operation cancelled).
If a function is being executed when SQLCancelHandle is called on another thread to cancel the function, it is
possible for the function to succeed and return SQL_SUCCESS before the cancel can take effect. A call to
SQLCancelHandle has no effect if the operation completed before SQLCancelHandle was able to cancel the
operation.

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Canceling a function running asynchronously on a statement SQLCancel Function


handle, canceling a function on a statement that needs data,
or canceling a function running on a statement on another
thread.

See Also
ODBC API Reference
ODBC Header Files
Asynchronous Execution (Polling Method)
SQLCloseCursor Function
4/27/2022 • 2 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 3.0 Standards Compliance: ISO 92
Summar y
SQLCloseCursor closes a cursor that has been opened on a statement and discards pending results.

Syntax
SQLRETURN SQLCloseCursor(
SQLHSTMT StatementHandle);

Arguments
StatementHandle
[Input] Statement handle.

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLCloseCursor returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value may
be obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a Handle of
StatementHandle. The following table lists the SQLSTATE values commonly returned by SQLCloseCursor and
explains each one in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs
returned by the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless
noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

24000 Invalid cursor state No cursor was open on the


StatementHandle. (This is returned
only by an ODBC 3.x driver.)

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.
SQ L STAT E ERRO R DESC RIP T IO N

HY001 Memory allocation error The driver was unable to allocate


memory required to support execution
or completion of the function.

HY010 Function sequence error (DM) An asynchronously executing


function was called for the connection
handle associated with the
StatementHandle and was still
executing when this function was
called.

(DM) An asynchronously executing


function was called for the
StatementHandle and was still
executing when this function was
called.

(DM) SQLExecute , SQLExecDirect ,


SQLBulkOperations , or SQLSetPos
was called for the StatementHandle
and returned SQL_NEED_DATA. This
function was called before data was
sent for all data-at-execution
parameters or columns.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
StatementHandle does not support
the function.

Comments
SQLCloseCursor returns SQLSTATE 24000 (Invalid cursor state) if no cursor is open. Calling SQLCloseCursor
is equivalent to calling SQLFreeStmt with the SQL_CLOSE option, with the exception that SQLFreeStmt with
SQL_CLOSE has no effect on the application if no cursor is open on the statement, while SQLCloseCursor
returns SQLSTATE 24000 (Invalid cursor state).
NOTE
If an ODBC 3.x application working with an ODBC 2.x driver calls SQLCloseCursor when no cursor is open, SQLSTATE
24000 (Invalid cursor state) is not returned, because the Driver Manager maps SQLCloseCursor to SQLFreeStmt with
SQL_CLOSE.

For more information, see Closing the Cursor.

Code Example
See SQLBrowseConnect Function and SQLConnect Function.

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Canceling statement processing SQLCancel Function

Freeing a handle SQLFreeHandle Function

Processing multiple result sets SQLMoreResults Function

See Also
ODBC API Reference
ODBC Header Files
SQLColAttribute Function
4/27/2022 • 20 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 3.0 Standards Compliance: ISO 92
Summar y
SQLColAttribute returns descriptor information for a column in a result set. Descriptor information is returned
as a character string, a descriptor-dependent value, or an integer value.

NOTE
For more information about what the Driver Manager maps this function to when an ODBC 3.x application is working
with an ODBC 2.x driver, see Mapping Replacement Functions for Backward Compatibility of Applications.

Syntax
SQLRETURN SQLColAttribute (
SQLHSTMT StatementHandle,
SQLUSMALLINT ColumnNumber,
SQLUSMALLINT FieldIdentifier,
SQLPOINTER CharacterAttributePtr,
SQLSMALLINT BufferLength,
SQLSMALLINT * StringLengthPtr,
SQLLEN * NumericAttributePtr);

Arguments
StatementHandle
[Input] Statement handle.
ColumnNumber
[Input] The number of the record in the IRD from which the field value is to be retrieved. This argument
corresponds to the column number of result data, ordered sequentially in increasing column order, starting at 1.
Columns can be described in any order.
Column 0 can be specified in this argument, but all values except SQL_DESC_TYPE and
SQL_DESC_OCTET_LENGTH will return undefined values.
FieldIdentifier
[Input] The descriptor handle. This handle defines which field in the IRD should be queried (for example,
SQL_COLUMN_TABLE_NAME).
CharacterAttributePtr
[Output] Pointer to a buffer in which to return the value in the FieldIdentifier field of the ColumnNumber row of
the IRD, if the field is a character string. Otherwise, the field is unused.
If CharacterAttributePtr is NULL, StringLengthPtr will still return the total number of bytes (excluding the null-
termination character for character data) available to return in the buffer pointed to by CharacterAttributePtr.
BufferLength
[Input] If FieldIdentifier is an ODBC-defined field and CharacterAttributePtr points to a character string or binary
buffer, this argument should be the length of *CharacterAttributePtr. If FieldIdentifier is an ODBC-defined field
and *CharacterAttributePtr is an integer, this field is ignored. If the *CharacterAttributePtr is a Unicode string
(when calling SQLColAttributeW ), the BufferLength argument must be an even number. If FieldIdentifier is a
driver-defined field, the application indicates the nature of the field to the Driver Manager by setting the
BufferLength argument. BufferLength can have the following values:
If CharacterAttributePtr is a pointer to a pointer, BufferLength should have the value SQL_IS_POINTER.
If CharacterAttributePtr is a pointer to a character string, the BufferLength is the length of the buffer.
If CharacterAttributePtr is a pointer to a binary buffer, the application places the result of the
SQL_LEN_BINARY_ATTR(length) macro in BufferLength. This places a negative value in BufferLength.
If CharacterAttributePtr is a pointer to a fixed-length data type, BufferLength must be one of the
following: SQL_IS_INTEGER, SQL_IS_UINTEGER, SQL_IS_SMALLINT, or SQL_IS_USMALLINT.
StringLengthPtr
[Output] Pointer to a buffer in which to return the total number of bytes (excluding the null-termination byte for
character data) available to return in *CharacterAttributePtr.
For character data, if the number of bytes available to return is greater than or equal to BufferLength, the
descriptor information in *CharacterAttributePtr is truncated to BufferLength minus the length of a null-
termination character and is null-terminated by the driver.
For all other types of data, the value of BufferLength is ignored and the driver assumes the size of
*CharacterAttributePtr is 32 bits.
NumericAttributePtr
[Output] Pointer to an integer buffer in which to return the value in the FieldIdentifier field of the
ColumnNumber row of the IRD, if the field is a numeric descriptor type, such as SQL_DESC_COLUMN_LENGTH.
Otherwise, the field is unused. Please note that some drivers may only write the lower 32-bit or 16-bit of a
buffer and leave the higher-order bit unchanged. Therefore, applications should initialize the value to 0 before
calling this function.

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_STILL_EXECUTING, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLColAttribute returns either SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE
value may be obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a Handle of
StatementHandle. The following table lists the SQLSTATE values commonly returned by SQLColAttribute and
explains each one in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs
returned by the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless
noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)
SQ L STAT E ERRO R DESC RIP T IO N

01004 String data, right truncated The buffer *CharacterAttributePtr was


not large enough to return the entire
string value, so the string value was
truncated. The length of the
untruncated string value is returned in
*StringLengthPtr. (Function returns
SQL_SUCCESS_WITH_INFO.)

07005 Prepared statement not a cursor- The statement associated with the
specification StatementHandle did not return a
result set and FieldIdentifier was not
SQL_DESC_COUNT. There were no
columns to describe.

07009 Invalid descriptor index (DM) The value specified for


ColumnNumber was equal to 0, and
the SQL_ATTR_USE_BOOKMARKS
statement attribute was SQL_UB_OFF.

The value specified for the argument


ColumnNumber was greater than the
number of columns in the result set.

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagField from the
diagnostic data structure describes the
error and its cause.

HY001 Memory allocation error The driver was unable to allocate


memory required to support execution
or completion of the function.

HY008 Operation canceled Asynchronous processing was enabled


for the StatementHandle. The function
was called, and before it completed
execution, SQLCancel or
SQLCancelHandle was called on the
StatementHandle. Then the function
was called again on the
StatementHandle.

The function was called, and before it


completed execution, SQLCancel or
SQLCancelHandle was called on the
StatementHandle from a different
thread in a multithread application.
SQ L STAT E ERRO R DESC RIP T IO N

HY010 Function sequence error (DM) An asynchronously executing


function was called for the connection
handle that is associated with the
StatementHandle. This aynchronous
function was still executing when
SQLColAttribute was called.

(DM) SQLExecute , SQLExecDirect ,


or SQLMoreResults was called for
the StatementHandle and returned
SQL_PARAM_DATA_AVAILABLE. This
function was called before data was
retrieved for all streamed parameters.

(DM) The function was called prior to


calling SQLPrepare , SQLExecDirect ,
or a catalog function for the
StatementHandle.

(DM) An asynchronously executing


function (not this one) was called for
the StatementHandle and was still
executing when this function was
called.

(DM) SQLExecute , SQLExecDirect ,


SQLBulkOperations , or SQLSetPos
was called for the StatementHandle
and returned SQL_NEED_DATA. This
function was called before data was
sent for all data-at-execution
parameters or columns.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY090 Invalid string or buffer length (DM) *CharacterAttributePtr is a


character string, and BufferLength was
less than 0 but not equal to SQL_NTS.

HY091 Invalid descriptor field identifier The value specified for the argument
FieldIdentifier was not one of the
defined values and was not an
implementation-defined value.

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.

HYC00 Driver not capable The value specified for the argument
FieldIdentifier was not supported by
the driver.
SQ L STAT E ERRO R DESC RIP T IO N

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
StatementHandle does not support
the function.

IM017 Polling is disabled in asynchronous Whenever the notification model is


notification mode used, polling is disabled.

IM018 SQLCompleteAsync has not been If the previous function call on the
called to complete the previous handle returns SQL_STILL_EXECUTING
asynchronous operation on this and if notification mode is enabled,
handle. SQLCompleteAsync must be called
on the handle to do post-processing
and complete the operation.

When called after SQLPrepare and before SQLExecute , SQLColAttribute can return any SQLSTATE that can
be returned by SQLPrepare or SQLExecute , depending on when the data source evaluates the SQL statement
associated with the StatementHandle.
For performance reasons, an application should not call SQLColAttribute before executing a statement.

Comments
For information about how applications use the information returned by SQLColAttribute , see Result Set
Metadata.
SQLColAttribute returns information either in *NumericAttributePtr or in *CharacterAttributePtr. Integer
information is returned in *NumericAttributePtr as a SQLLEN value; all other formats of information are
returned in *CharacterAttributePtr. When information is returned in *NumericAttributePtr, the driver ignores
CharacterAttributePtr, BufferLength, and StringLengthPtr. When information is returned in
*CharacterAttributePtr, the driver ignores NumericAttributePtr.
SQLColAttribute returns values from the descriptor fields of the IRD. The function is called with a statement
handle rather than a descriptor handle. The values returned by SQLColAttribute for the FieldIdentifier values
listed later in this section can also be retrieved by calling SQLGetDescField with the appropriate IRD handle.
The currently defined descriptor fields, the version of ODBC in which they were introduced, and the arguments
in which information is returned for them are shown later in this section; more descriptor types may be defined
by drivers to take advantage of different data sources.
An ODBC 3.x driver must return a value for each of the descriptor fields. If a descriptor field does not apply to a
driver or data source and unless otherwise stated, the driver returns 0 in *StringLengthPtr or an empty string in
*CharacterAttributePtr.

Backward Compatibility
The ODBC 3.x function SQLColAttribute replaces the deprecated ODBC 2.x function SQLColAttributes . When
mapping SQLColAttributes to SQLColAttribute (when an ODBC 2.x application is working with an ODBC 3.x
driver), or mapping SQLColAttribute to SQLColAttributes (when an ODBC 3.x application is working with an
ODBC 2.x driver), the Driver Manager either passes the value of FieldIdentifier through, maps it to a new value,
or returns an error, as follows:

NOTE
The prefix used in FieldIdentifier values in ODBC 3.x has been changed from that used in ODBC 2.x. The new prefix is
"SQL_DESC"; the old prefix was "SQL_COLUMN".

If the #define value of the ODBC 2.x FieldIdentifier is the same as the #define value of the ODBC 3.x
FieldIdentifier, the value in the function call is just passed through.
The #define values of the ODBC 2.x FieldIdentifiers SQL_COLUMN_LENGTH, SQL_COLUMN_PRECISION,
and SQL_COLUMN_SCALE are different from the #define values of the ODBC 3.x FieldIdentifiers
SQL_DESC_PRECISION, SQL_DESC_SCALE, and SQL_DESC_LENGTH. An ODBC 2.x driver need only
support the ODBC 2.x values. An ODBC 3.x driver must support both "SQL_COLUMN" and "SQL_DESC"
values for these three FieldIdentifiers. These values are different because precision, scale, and length are
defined differently in ODBC 3.x than they were in ODBC 2.x. For more information, see Column Size,
Decimal Digits, Transfer Octet Length, and Display Size.
If the #define value of the ODBC 2.x FieldIdentifier is different from the #define value of the ODBC 3.x
FieldIdentifier, as occurs with the COUNT, NAME, and NULLABLE values, the value in the function call is
mapped to the corresponding value. For example, SQL_COLUMN_COUNT is mapped to
SQL_DESC_COUNT, and SQL_DESC_COUNT is mapped to SQL_COLUMN_COUNT, depending on the
direction of the mapping.
If FieldIdentifier is a new value in ODBC 3.x, for which there was no corresponding value in ODBC 2.x, it
will not be mapped when an ODBC 3.x application uses it in a call to SQLColAttribute in an ODBC 2.x
driver, and the call will return SQLSTATE HY091 (Invalid descriptor field identifier).
The following table lists the descriptor types returned by SQLColAttribute . The type for NumericAttributePtr
values is SQLLEN * .

IN F O RM AT IO N

FIEL DIDEN T IFIER RET URN ED IN DESC RIP T IO N

SQL_DESC_AUTO_UNIQUE_VALUE NumericAttributePtr SQL_TRUE if the column is an


(ODBC 1.0) autoincrementing column.

SQL_FALSE if the column is not an


autoincrementing column or is not
numeric.

This field is valid for numeric data type


columns only. An application can insert
values into a row containing an
autoincrement column, but typically
cannot update values in the column.

When an insert is made into an


autoincrement column, a unique value
is inserted into the column at insert
time. The increment is not defined, but
is data source-specific. An application
should not assume that an
autoincrement column starts at any
particular point or increments by any
particular value.
IN F O RM AT IO N

FIEL DIDEN T IFIER RET URN ED IN DESC RIP T IO N

SQL_DESC_BASE_COLUMN_NAME CharacterAttributePtr The base column name for the result


(ODBC 3.0) set column. If a base column name
does not exist (as in the case of
columns that are expressions), then
this variable contains an empty string.

This information is returned from the


SQL_DESC_BASE_COLUMN_NAME
record field of the IRD, which is a read-
only field.

SQL_DESC_BASE_TABLE_NAME (ODBC CharacterAttributePtr The name of the base table that


3.0) contains the column. If the base table
name cannot be defined or is not
applicable, then this variable contains
an empty string.

This information is returned from the


SQL_DESC_BASE_TABLE_NAME record
field of the IRD, which is a read-only
field.

SQL_DESC_CASE_SENSITIVE (ODBC NumericAttributePtr SQL_TRUE if the column is treated as


1.0) case-sensitive for collations and
comparisons.

SQL_FALSE if the column is not treated


as case-sensitive for collations and
comparisons or is noncharacter.

SQL_DESC_CATALOG_NAME (ODBC CharacterAttributePtr The catalog of the table that contains


2.0) the column. The returned value is
implementation-defined if the column
is an expression or if the column is
part of a view. If the data source does
not support catalogs or the catalog
name cannot be determined, an empty
string is returned. This VARCHAR
record field is not limited to 128
characters.

SQL_DESC_CONCISE_TYPE (ODBC 1.0) NumericAttributePtr The concise data type.

For the datetime and interval data


types, this field returns the concise
data type; for example,
SQL_TYPE_TIME or
SQL_INTERVAL_YEAR. (For more
information, see Data Type Identifiers
and Descriptors in Appendix D: Data
Types.)

This information is returned from the


SQL_DESC_CONCISE_TYPE record field
of the IRD.
IN F O RM AT IO N

FIEL DIDEN T IFIER RET URN ED IN DESC RIP T IO N

SQL_DESC_COUNT (ODBC 1.0) NumericAttributePtr The number of columns available in


the result set. This returns 0 if there
are no columns in the result set. The
value in the ColumnNumber argument
is ignored.

This information is returned from the


SQL_DESC_COUNT header field of the
IRD.

SQL_DESC_DISPLAY_SIZE (ODBC 1.0) NumericAttributePtr Maximum number of characters


required to display data from the
column. For more information about
display size, see Column Size, Decimal
Digits, Transfer Octet Length, and
Display Size in Appendix D: Data Types.

SQL_DESC_FIXED_PREC_SCALE (ODBC NumericAttributePtr SQL_TRUE if the column has a fixed


1.0) precision and nonzero scale that are
data source-specific.

SQL_FALSE if the column does not


have a fixed precision and nonzero
scale that are data source-specific.

SQL_DESC_LABEL (ODBC 2.0) CharacterAttributePtr The column label or title. For example,
a column named EmpName might be
labeled Employee Name or might be
labeled with an alias.

If a column does not have a label, the


column name is returned. If the
column is unlabeled and unnamed, an
empty string is returned.

SQL_DESC_LENGTH (ODBC 3.0) NumericAttributePtr A numeric value that is either the


maximum or actual character length of
a character string or binary data type.
It is the maximum character length for
a fixed-length data type, or the actual
character length for a variable-length
data type. Its value always excludes the
null-termination byte that ends the
character string.

This information is returned from the


SQL_DESC_LENGTH record field of the
IRD.

For more information about length,


see Column Size, Decimal Digits,
Transfer Octet Length, and Display Size
in Appendix D: Data Types.
IN F O RM AT IO N

FIEL DIDEN T IFIER RET URN ED IN DESC RIP T IO N

SQL_DESC_LITERAL_PREFIX (ODBC CharacterAttributePtr This VARCHAR(128) record field


3.0) contains the character or characters
that the driver recognizes as a prefix
for a literal of this data type. This field
contains an empty string for a data
type for which a literal prefix is not
applicable. For more information, see
Literal Prefixes and Suffixes.

SQL_DESC_LITERAL_SUFFIX (ODBC CharacterAttributePtr This VARCHAR(128) record field


3.0) contains the character or characters
that the driver recognizes as a suffix
for a literal of this data type. This field
contains an empty string for a data
type for which a literal suffix is not
applicable. For more information, see
Literal Prefixes and Suffixes.

SQL_DESC_LOCAL_TYPE_NAME CharacterAttributePtr This VARCHAR(128) record field


(ODBC 3.0) contains any localized (native
language) name for the data type that
may be different from the regular
name of the data type. If there is no
localized name, then an empty string is
returned. This field is for display
purposes only. The character set of the
string is locale-dependent and is
typically the default character set of
the server.

SQL_DESC_NAME (ODBC 3.0) CharacterAttributePtr The column alias, if it applies. If the


column alias does not apply, the
column name is returned. In either
case, SQL_DESC_UNNAMED is set to
SQL_NAMED. If there is no column
name or a column alias, an empty
string is returned and
SQL_DESC_UNNAMED is set to
SQL_UNNAMED.

This information is returned from the


SQL_DESC_NAME record field of the
IRD.

SQL_DESC_NULLABLE (ODBC 3.0) NumericAttributePtr SQL_ NULLABLE if the column can


have NULL values; SQL_NO_NULLS if
the column does not have NULL
values; or SQL_NULLABLE_UNKNOWN
if it is not known whether the column
accepts NULL values.

This information is returned from the


SQL_DESC_NULLABLE record field of
the IRD.
IN F O RM AT IO N

FIEL DIDEN T IFIER RET URN ED IN DESC RIP T IO N

SQL_DESC_NUM_PREC_RADIX (ODBC NumericAttributePtr If the data type in the SQL_DESC_TYPE


3.0) field is an approximate numeric data
type, this SQLINTEGER field contains a
value of 2 because the
SQL_DESC_PRECISION field contains
the number of bits. If the data type in
the SQL_DESC_TYPE field is an exact
numeric data type, this field contains a
value of 10 because the
SQL_DESC_PRECISION field contains
the number of decimal digits. This field
is set to 0 for all non-numeric data
types.

SQL_DESC_OCTET_LENGTH (ODBC NumericAttributePtr The length, in bytes, of a character


3.0) string or binary data type. For fixed-
length character or binary types, this is
the actual length in bytes. For variable-
length character or binary types, this is
the maximum length in bytes. This
value does not include the null
terminator.

This information is returned from the


SQL_DESC_OCTET_LENGTH record
field of the IRD.

For more information about length,


see Column Size, Decimal Digits,
Transfer Octet Length, and Display Size
in Appendix D: Data Types.

SQL_DESC_PRECISION (ODBC 3.0) NumericAttributePtr A numeric value that for a numeric


data type denotes the applicable
precision. For data types
SQL_TYPE_TIME,
SQL_TYPE_TIMESTAMP, and all the
interval data types that represent a
time interval, its value is the applicable
precision of the fractional seconds
component.

This information is returned from the


SQL_DESC_PRECISION record field of
the IRD.

SQL_DESC_SCALE (ODBC 3.0) NumericAttributePtr A numeric value that is the applicable


scale for a numeric data type. For
DECIMAL and NUMERIC data types,
this is the defined scale. It is undefined
for all other data types.

This information is returned from the


SCALE record field of the IRD.
IN F O RM AT IO N

FIEL DIDEN T IFIER RET URN ED IN DESC RIP T IO N

SQL_DESC_SCHEMA_NAME (ODBC CharacterAttributePtr The schema of the table that contains


2.0) the column. The returned value is
implementation-defined if the column
is an expression or if the column is
part of a view. If the data source does
not support schemas or the schema
name cannot be determined, an empty
string is returned. This VARCHAR
record field is not limited to 128
characters.

SQL_DESC_SEARCHABLE (ODBC 1.0) NumericAttributePtr SQL_PRED_NONE if the column cannot


be used in a WHERE clause. (This is the
same as the SQL_UNSEARCHABLE
value in ODBC 2.x.)

SQL_PRED_CHAR if the column can be


used in a WHERE clause but only with
the LIKE predicate. (This is the same as
the SQL_LIKE_ONLY value in ODBC
2.x.)

SQL_PRED_BASIC if the column can be


used in a WHERE clause with all the
comparison operators except LIKE.
(This is the same as the
SQL_EXCEPT_LIKE value in ODBC 2.x.)

SQL_PRED_SEARCHABLE if the column


can be used in a WHERE clause with
any comparison operator.

Columns of type SQL_LONGVARCHAR


and SQL_LONGVARBINARY usually
return SQL_PRED_CHAR.

SQL_DESC_TABLE_NAME (ODBC 2.0) CharacterAttributePtr The name of the table that contains
the column. The returned value is
implementation-defined if the column
is an expression or if the column is
part of a view.

If the table name cannot be


determined, an empty string is
returned.
IN F O RM AT IO N

FIEL DIDEN T IFIER RET URN ED IN DESC RIP T IO N

SQL_DESC_TYPE (ODBC 3.0) NumericAttributePtr A numeric value that specifies the SQL
data type.

When ColumnNumber is equal to 0,


SQL_BINARY is returned for variable-
length bookmarks and SQL_INTEGER is
returned for fixed-length bookmarks.

For the datetime and interval data


types, this field returns the verbose
data type: SQL_DATETIME or
SQL_INTERVAL. (For more information,
see Data Type Identifiers and
Descriptors in Appendix D: Data Types.

This information is returned from the


SQL_DESC_TYPE record field of the
IRD. Note: To work against ODBC 2.x
drivers, use SQL_DESC_CONCISE_TYPE
instead.

SQL_DESC_TYPE_NAME (ODBC 1.0) CharacterAttributePtr Data source-dependent data type


name; for example, "CHAR",
"VARCHAR", "MONEY", "LONG
VARBINARY", or "CHAR ( ) FOR BIT
DATA".

If the type is unknown, an empty


string is returned.

SQL_DESC_UNNAMED (ODBC 3.0) NumericAttributePtr SQL_NAMED or SQL_UNNAMED. If the


SQL_DESC_NAME field of the IRD
contains a column alias or a column
name, SQL_NAMED is returned. If
there is no column name or column
alias, SQL_UNNAMED is returned.

This information is returned from the


SQL_DESC_UNNAMED record field of
the IRD.

SQL_DESC_UNSIGNED (ODBC 1.0) NumericAttributePtr SQL_TRUE if the column is unsigned


(or not numeric).

SQL_FALSE if the column is signed.


IN F O RM AT IO N

FIEL DIDEN T IFIER RET URN ED IN DESC RIP T IO N

SQL_DESC_UPDATABLE (ODBC 1.0) NumericAttributePtr Column is described by the values for


the defined constants:

SQL_ATTR_READONLY
SQL_ATTR_WRITE
SQL_ATTR_READWRITE_UNKNOWN

SQL_DESC_UPDATABLE describes the


updatability of the column in the result
set, not the column in the base table.
The updatability of the base column on
which the result set column is based
may be different from the value in this
field. Whether a column is updatable
can be based on the data type, user
privileges, and the definition of the
result set itself. If it is unclear whether
a column is updatable,
SQL_ATTR_READWRITE_UNKNOWN
should be returned.

SQLColAttribute is an extensible alternative to SQLDescribeCol . SQLDescribeCol returns a fixed set of


descriptor information based on ANSI-89 SQL. SQLColAttribute allows access to the more extensive set of
descriptor information available in ANSI SQL-92 and DBMS vendor extensions.

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Binding a buffer to a column in a result set SQLBindCol Function

Canceling statement processing SQLCancel Function

Returning information about a column in a result set SQLDescribeCol Function

Fetching a block of data or scrolling through a result set SQLFetchScroll Function

Fetching multiple rows of data SQLFetch Function

Example
The following sample code does not free handles and connections. See SQLFreeHandle Function, Sample ODBC
Program, and SQLFreeStmt Function for code samples to free handles and statements.

// SQLColAttibute.cpp
// compile with: user32.lib odbc32.lib

#define UNICODE

#include <windows.h>
#include <sqlext.h>
#include <strsafe.h>

struct DataBinding {
SQLSMALLINT TargetType;
SQLSMALLINT TargetType;
SQLPOINTER TargetValuePtr;
SQLINTEGER BufferLength;
SQLLEN StrLen_or_Ind;
};

void printStatementResult(SQLHSTMT hstmt) {


int bufferSize = 1024, i;
SQLRETURN retCode;
SQLSMALLINT numColumn = 0, bufferLenUsed;

retCode = SQLNumResultCols(hstmt, &numColumn);

SQLPOINTER* columnLabels = (SQLPOINTER *)malloc( numColumn * sizeof(SQLPOINTER*) );


struct DataBinding* columnData = (struct DataBinding*)malloc( numColumn * sizeof(struct DataBinding) );

printf( "Columns from that table:\n" );


for ( i = 0 ; i < numColumn ; i++ ) {
columnLabels[i] = (SQLPOINTER)malloc( bufferSize*sizeof(char) );

retCode = SQLColAttribute(hstmt, (SQLUSMALLINT)i + 1, SQL_DESC_LABEL, columnLabels[i],


(SQLSMALLINT)bufferSize, &bufferLenUsed, NULL);
wprintf( L"Column %d: %s\n", i, (wchar_t*)columnLabels[i] );
}

// allocate memory for the binding


for ( i = 0 ; i < numColumn ; i++ ) {
columnData[i].TargetType = SQL_C_CHAR;
columnData[i].BufferLength = (bufferSize+1);
columnData[i].TargetValuePtr = malloc( sizeof(unsigned char)*columnData[i].BufferLength );
}

// setup the binding


for ( i = 0 ; i < numColumn ; i++ ) {
retCode = SQLBindCol(hstmt, (SQLUSMALLINT)i + 1, columnData[i].TargetType,
columnData[i].TargetValuePtr, columnData[i].BufferLength, &(columnData[i].StrLen_or_Ind));
}

printf( "Data from that table:\n" );


// fetch the data and print out the data
for ( retCode = SQLFetch(hstmt) ; retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO ; retCode =
SQLFetch(hstmt) ) {
int j;
for ( j = 0 ; j < numColumn ; j++ )
wprintf( L"%s: %hs\n", columnLabels[j], columnData[j].TargetValuePtr );
printf( "\n" );
}
printf( "\n" );
}

int main() {
int bufferSize = 1024, i, count = 1, numCols = 5;
wchar_t firstTableName[1024], * dbName = (wchar_t *)malloc( sizeof(wchar_t)*bufferSize ), * userName =
(wchar_t *)malloc( sizeof(wchar_t)*bufferSize );
HWND desktopHandle = GetDesktopWindow(); // desktop's window handle
SQLWCHAR connStrbuffer[1024];
SQLSMALLINT connStrBufferLen, bufferLen;
SQLRETURN retCode;

SQLHENV henv = NULL; // Environment


SQLHDBC hdbc = NULL; // Connection handle
SQLHSTMT hstmt = NULL; // Statement handle

struct DataBinding* catalogResult = (struct DataBinding*) malloc( numCols * sizeof(struct DataBinding) );


SQLWCHAR* selectAllQuery = (SQLWCHAR *)malloc( sizeof(SQLWCHAR) * bufferSize );

// connect to database
retCode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
retCode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLCHAR *)(void*)SQL_OV_ODBC3, -1);
retCode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
retCode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
retCode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)10, 0);
retCode = SQLDriverConnect(hdbc, desktopHandle, L"Driver={SQL Server}", SQL_NTS, connStrbuffer, 1025,
&connStrBufferLen, SQL_DRIVER_PROMPT);
retCode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

// display the database information


retCode = SQLGetInfo(hdbc, SQL_DATABASE_NAME, dbName, (SQLSMALLINT)bufferSize, (SQLSMALLINT
*)&bufferLen);
retCode = SQLGetInfo(hdbc, SQL_USER_NAME, userName, (SQLSMALLINT)bufferSize, &bufferLen);

for ( i = 0 ; i < numCols ; i++ ) {


catalogResult[i].TargetType = SQL_C_CHAR;
catalogResult[i].BufferLength = (bufferSize + 1);
catalogResult[i].TargetValuePtr = malloc( sizeof(unsigned char)*catalogResult[i].BufferLength );
}

// Set up the binding. This can be used even if the statement is closed by closeStatementHandle
for ( i = 0 ; i < numCols ; i++ )
retCode = SQLBindCol(hstmt, (SQLUSMALLINT)i + 1, catalogResult[i].TargetType,
catalogResult[i].TargetValuePtr, catalogResult[i].BufferLength, &(catalogResult[i].StrLen_or_Ind));

retCode = SQLTables( hstmt, (SQLWCHAR*)SQL_ALL_CATALOGS, SQL_NTS, L"", SQL_NTS, L"", SQL_NTS, L"",
SQL_NTS );
retCode = SQLFreeStmt(hstmt, SQL_CLOSE);

retCode = SQLTables( hstmt, dbName, SQL_NTS, userName, SQL_NTS, L"%", SQL_NTS, L"TABLE", SQL_NTS );

for ( retCode = SQLFetch(hstmt) ; retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO ; retCode =


SQLFetch(hstmt), ++count )
if ( count == 1 )
StringCchPrintfW( firstTableName, 1024, L"%hs", catalogResult[2].TargetValuePtr );
retCode = SQLFreeStmt(hstmt, SQL_CLOSE);

wprintf( L"Select all data from the first table (%s)\n", firstTableName );
StringCchPrintfW( selectAllQuery, bufferSize, L"SELECT * FROM %s", firstTableName );

retCode = SQLExecDirect(hstmt, selectAllQuery, SQL_NTS);


printStatementResult(hstmt);
}

See Also
ODBC API Reference
ODBC Header Files
Sample ODBC Program
SQLColAttributes Function
4/27/2022 • 2 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: Deprecated
Summar y
In ODBC 3.x, the ODBC 2.0 function SQLColAttributes has been replaced by SQLColAttribute . For more
information, see SQLColAttribute Function.

NOTE
For more information about what the Driver Manager maps this function to when an ODBC 2.x application is working
with an ODBC 3.x driver, see Mapping Deprecated Functions in Appendix G: Driver Guidelines for Backward Compatibility.

See ODBC 64-Bit Information, if your application will run on a 64-bit operating system.

See Also
ODBC API Reference
ODBC Header Files
SQLColumnPrivileges Function
4/27/2022 • 9 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: ODBC
Summar y
SQLColumnPrivileges returns a list of columns and associated privileges for the specified table. The driver
returns the information as a result set on the specified StatementHandle.

Syntax
SQLRETURN SQLColumnPrivileges(
SQLHSTMT StatementHandle,
SQLCHAR * CatalogName,
SQLSMALLINT NameLength1,
SQLCHAR * SchemaName,
SQLSMALLINT NameLength2,
SQLCHAR * TableName,
SQLSMALLINT NameLength3,
SQLCHAR * ColumnName,
SQLSMALLINT NameLength4);

Arguments
StatementHandle
[Input] Statement handle.
CatalogName
[Input] Catalog name. If a driver supports names for some catalogs but not for others,such as when the driver
retrieves data from different DBMSs, an empty string ("") denotes those catalogs that do not have names.
CatalogName cannot contain a string search pattern.
If the SQL_ATTR_METADATA_ID statement attribute is set to SQL_TRUE, CatalogName is treated as an identifier
and its case is not significant. If it is SQL_FALSE, CatalogName is an ordinary argument; it is treated literally, and
its case is significant. For more information, see Arguments in Catalog Functions.
NameLength1
[Input] Length in characters of *CatalogName.
SchemaName
[Input] Schema name. If a driver supports schemas for some tables but not for others, such as when the driver
retrieves data from different DBMSs, an empty string ("") denotes those tables that do not have schemas.
SchemaName cannot contain a string search pattern.
If the SQL_ATTR_METADATA_ID statement attribute is set to SQL_TRUE, SchemaName is treated as an identifier. If
it is SQL_FALSE, SchemaName is an ordinary argument; it is treated literally, and its case is significant.
NameLength2
[Input] Length in characters of *SchemaName.
TableName
[Input] Table name. This argument cannot be a null pointer. TableName cannot contain a string search pattern.
If the SQL_ATTR_METADATA_ID statement attribute is set to SQL_TRUE, TableName is treated as an identifier and
its case is not significant. If it is SQL_FALSE, TableName is an ordinary argument; it is treated literally, and its case
is significant.
NameLength3
[Input] Length in characters of *TableName.
ColumnName
[Input] String search pattern for column names.
If the SQL_ATTR_METADATA_ID statement attribute is set to SQL_TRUE, ColumnName is treated as an identifier
and its case is not significant. If it is SQL_FALSE, ColumnName is a pattern value argument; it is treated literally,
and its case is significant.
NameLength4
[Input] Length in characters of *ColumnName.

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_STILL_EXECUTING, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLColumnPrivileges returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE
value may be obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a Handle of
StatementHandle. The following table lists the SQLSTATE values commonly returned by SQLColumnPrivileges
and explains each one in the context of this function; the notation "(DM)" precedes the descriptions of
SQLSTATEs returned by the Driver Manager. The return code associated with each SQLSTATE value is
SQL_ERROR, unless noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

08S01 Communication link failure The communication link between the


driver and the data source to which
the driver was connected failed before
the function completed processing.

24000 Invalid cursor state A cursor was open on the


StatementHandle, and SQLFetch or
SQLFetchScroll had been called. This
error is returned by the Driver
Manager if SQLFetch or
SQLFetchScroll has not returned
SQL_NO_DATA, and is returned by the
driver if SQLFetch or
SQLFetchScroll has returned
SQL_NO_DATA.

A cursor was open on the


StatementHandle, but SQLFetch or
SQLFetchScroll had not been called.
SQ L STAT E ERRO R DESC RIP T IO N

40001 Serialization failure The transaction was rolled back due to


a resource deadlock with another
transaction.

40003 Statement completion unknown The associated connection failed


during the execution of this function,
and the state of the transaction cannot
be determined.

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.

HY001 Memory allocation error The driver was unable to allocate


memory required to support execution
or completion of the function.

HY008 Operation canceled Asynchronous processing was enabled


for the StatementHandle. The function
was called, and before it completed
execution, SQLCancel or
SQLCancelHandle was called on the
StatementHandle. Then the function
was called again on the
StatementHandle.

The function was called, and before it


completed execution, SQLCancel or
SQLCancelHandle was called on the
StatementHandle from a different
thread in a multithread application.

HY009 Invalid use of null pointer The TableName argument was a null
pointer.

The SQL_ATTR_METADATA_ID
statement attribute was set to
SQL_TRUE, the CatalogName
argument was a null pointer, and the
SQL_CATALOG_NAME InfoType returns
that catalog names are supported.

(DM) The SQL_ATTR_METADATA_ID


statement attribute was set to
SQL_TRUE, and the SchemaName or
ColumnName argument was a null
pointer.
SQ L STAT E ERRO R DESC RIP T IO N

HY010 Function sequence error (DM) An asynchronously executing


function was called for the connection
handle that is associated with the
StatementHandle. This asynchronous
function was still executing when this
function was called.

(DM) SQLExecute , SQLExecDirect ,


or SQLMoreResults was called for
the StatementHandle and returned
SQL_PARAM_DATA_AVAILABLE. This
function was called before data was
retrieved for all streamed parameters.

(DM) An asynchronously executing


function (not this one) was called for
the StatementHandle and was still
executing when this function was
called.

(DM) SQLExecute , SQLExecDirect ,


SQLBulkOperations , or SQLSetPos
was called for the StatementHandle
and returned SQL_NEED_DATA. This
function was called before data was
sent for all data-at-execution
parameters or columns.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY090 Invalid string or buffer length (DM) The value of one of the name
length arguments was less than 0 but
not equal to SQL_NTS.

The value of one of the name length


arguments exceeded the maximum
length value for the corresponding
name. (See "Comments.")

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.
SQ L STAT E ERRO R DESC RIP T IO N

HYC00 Optional feature not implemented A catalog name was specified, and the
driver or data source does not support
catalogs.

A schema name was specified, and the


driver or data source does not support
schemas.

A string search pattern was specified


for the column name, and the data
source does not support search
patterns for that argument.

The combination of the current


settings of the SQL_CONCURRENCY
and SQL_CURSOR_TYPE statement
attributes was not supported by the
driver or data source.

The SQL_ATTR_USE_BOOKMARKS
statement attribute was set to
SQL_UB_VARIABLE, and the
SQL_ATTR_CURSOR_TYPE statement
attribute was set to a cursor type for
which the driver does not support
bookmarks.

HYT00 Timeout expired The query timeout period expired


before the data source returned the
result set. The timeout period is set
through SQLSetStmtAttr ,
SQL_ATTR_QUERY_TIMEOUT.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
StatementHandle does not support
the function.

IM017 Polling is disabled in asynchronous Whenever the notification model is


notification mode used, polling is disabled.

IM018 SQLCompleteAsync has not been If the previous function call on the
called to complete the previous handle returns SQL_STILL_EXECUTING
asynchronous operation on this and if notification mode is enabled,
handle. SQLCompleteAsync must be called
on the handle to do post-processing
and complete the operation.

Comments
SQLColumnPrivileges returns the results as a standard result set, ordered by TABLE_CAT, TABLE_SCHEM,
TABLE_NAME, COLUMN_NAME, and PRIVILEGE.
NOTE
SQLColumnPrivileges might not return privileges for all columns. For example, a driver might not return information
about privileges for pseudo-columns, such as Oracle ROWID. Applications can use any valid column, regardless of whether
it is returned by SQLColumnPrivileges .

The lengths of VARCHAR columns are not shown in the table; the actual lengths depend on the data source. To
determine the actual lengths of the CATALOG_NAME, SCHEMA_NAME, TABLE_NAME, and COLUMN_NAME
columns, an application can call SQLGetInfo with the SQL_MAX_CATALOG_NAME_LEN,
SQL_MAX_SCHEMA_NAME_LEN, SQL_MAX_TABLE_NAME_LEN, and SQL_MAX_COLUMN_NAME_LEN options.

NOTE
For more information about the general use, arguments, and returned data of ODBC catalog functions, see Catalog
Functions.

The following columns have been renamed for ODBC 3.x. The column name changes do not affect backward
compatibility because applications bind by column number.

O DB C 2. 0 C O L UM N O DB C 3. X C O L UM N

TABLE_QUALIFIER TABLE_CAT

TABLE_OWNER TABLE_SCHEM

The following table lists the columns in the result set. Additional columns beyond column 8 (IS_GRANTABLE) can
be defined by the driver. An application should gain access to driver-specific columns by counting down from
the end of the result set rather than specifying an explicit ordinal position. For more information, see Data
Returned by Catalog Functions.

C O L UM N N A M E C O L UM N N UM B ER DATA T Y P E C O M M EN T S

TABLE_CAT (ODBC 1.0) 1 Varchar Catalog identifier; NULL if


not applicable to the data
source. If a driver supports
catalogs for some tables
but not for others, such as
when the driver retrieves
data from different DBMSs,
it returns an empty string
("") for those tables that do
not have catalogs.

TABLE_SCHEM (ODBC 1.0) 2 Varchar Schema identifier; NULL if


not applicable to the data
source. If a driver supports
schemas for some tables
but not for others, such as
when the driver retrieves
data from different DBMSs,
it returns an empty string
("") for those tables that do
not have schemas.

TABLE_NAME (ODBC 1.0) 3 Varchar not NULL Table identifier.


C O L UM N N A M E C O L UM N N UM B ER DATA T Y P E C O M M EN T S

COLUMN_NAME (ODBC 4 Varchar not NULL Column name. The driver


1.0) returns an empty string for
a column that does not
have a name.

GRANTOR (ODBC 1.0) 5 Varchar Name of the user who


granted the privilege; NULL
if not applicable to the data
source.

For all rows in which the


value in the GRANTEE
column is the owner of the
object, the GRANTOR
column will be "_SYSTEM".

GRANTEE (ODBC 1.0) 6 Varchar not NULL Name of the user to whom
the privilege was granted.

PRIVILEGE (ODBC 1.0) 7 Varchar not NULL Identifies the column


privilege. May be one of the
following (or others
supported by the data
source when
implementation-defined):

SELECT: The grantee is


permitted to retrieve data
for the column.

INSERT: The grantee is


permitted to provide data
for the column in new rows
that are inserted into the
associated table.

UPDATE: The grantee is


permitted to update data in
the column.

REFERENCES: The grantee is


permitted to refer to the
column within a constraint
(for example, a unique,
referential, or table check
constraint).
C O L UM N N A M E C O L UM N N UM B ER DATA T Y P E C O M M EN T S

IS_GRANTABLE (ODBC 1.0) 8 Varchar Indicates whether the


grantee is permitted to
grant the privilege to other
users; "YES", "NO", or
"NULL" if unknown or not
applicable to the data
source.

A privilege is either
grantable or not grantable,
but not both. The result set
returned by
SQLColumnPrivileges will
never contain two rows for
which all columns except
the IS_GRANTABLE column
contain the same value.

Code Example
For a code example of a similar function, see SQLColumns Function.

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Binding a buffer to a column in a result set SQLBindCol Function

Canceling statement processing SQLCancel Function

Returning the columns in a table or tables SQLColumns Function

Fetching a block of data or scrolling through a result set SQLFetchScroll Function

Fetching multiple rows of data SQLFetch Function

Returning privileges for a table or tables SQLTablePrivileges Function

Returning a list of tables in a data source SQLTables Function

See Also
ODBC API Reference
ODBC Header Files
SQLColumns Function
4/27/2022 • 16 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: Open Group
Summar y
SQLColumns returns the list of column names in specified tables. The driver returns this information as a result
set on the specified StatementHandle.

Syntax
SQLRETURN SQLColumns(
SQLHSTMT StatementHandle,
SQLCHAR * CatalogName,
SQLSMALLINT NameLength1,
SQLCHAR * SchemaName,
SQLSMALLINT NameLength2,
SQLCHAR * TableName,
SQLSMALLINT NameLength3,
SQLCHAR * ColumnName,
SQLSMALLINT NameLength4);

Arguments
StatementHandle
[Input] Statement handle.
CatalogName
[Input] Catalog name. If a driver supports catalogs for some tables but not for others, such as when the driver
retrieves data from different DBMSs, an empty string ("") indicates those tables that do not have catalogs.
CatalogName cannot contain a string search pattern.

NOTE
If the SQL_ATTR_METADATA_ID statement attribute is set to SQL_TRUE, CatalogName is treated as an identifier and its
case is not significant. If it is SQL_FALSE, CatalogName is an ordinary argument; it is treated literally, and its case is
significant. For more information, see Arguments in Catalog Functions.

NameLength1
[Input] Length in characters of *CatalogName.
SchemaName
[Input] String search pattern for schema names. If a driver supports schemas for some tables but not for others,
such as when the driver retrieves data from different DBMSs, an empty string ("") indicates those tables that do
not have schemas.
NOTE
If the SQL_ATTR_METADATA_ID statement attribute is set to SQL_TRUE, SchemaName is treated as an identifier and its
case is not significant. If it is SQL_FALSE, SchemaName is a pattern value argument; it is treated literally, and its case is
significant.

NameLength2
[Input] Length in characters of *SchemaName.
TableName
[Input] String search pattern for table names.

NOTE
If the SQL_ATTR_METADATA_ID statement attribute is set to SQL_TRUE, TableName is treated as an identifier and its case
is not significant. If it is SQL_FALSE, TableName is a pattern value argument; it is treated literally, and its case is significant.

NameLength3
[Input] Length in characters of *TableName.
ColumnName
[Input] String search pattern for column names.

NOTE
If the SQL_ATTR_METADATA_ID statement attribute is set to SQL_TRUE, ColumnName is treated as an identifier and its
case is not significant. If it is SQL_FALSE, ColumnName is a pattern value argument; it is treated literally, and its case is
significant.

NameLength4
[Input] Length in characters of *ColumnName.

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_STILL_EXECUTING, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLColumns returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value can be
obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a Handle of
StatementHandle. The following table lists the SQLSTATE values typically returned by SQLColumns and
explains each one in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs
returned by the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless
noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)
SQ L STAT E ERRO R DESC RIP T IO N

08S01 Communication link failure The communication link between the


driver and the data source to which
the driver was connected failed before
the function completed processing.

24000 Invalid cursor state A cursor was open on the


StatementHandle, and SQLFetch or
SQLFetchScroll had been called. This
error is returned by the Driver
Manager if SQLFetch or
SQLFetchScroll has not returned
SQL_NO_DATA, and is returned by the
driver if SQLFetch or
SQLFetchScroll has returned
SQL_NO_DATA.

A cursor was open on the


StatementHandle but SQLFetch or
SQLFetchScroll had not been called.

40001 Serialization failure The transaction was rolled back


because of a resource deadlock with
another transaction.

40003 Statement completion unknown The associated connection failed


during the execution of this function,
and the state of the transaction cannot
be determined.

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.

HY001 Memory allocation error The driver was unable to allocate


memory that is required to support
execution or completion of the
function.

HY008 Operation canceled Asynchronous processing was enabled


for the StatementHandle. The function
was called, and before it completed
execution, SQLCancel or
SQLCancelHandle was called on the
StatementHandle. Then the function
was called again on the
StatementHandle.

The function was called, and before it


completed execution, SQLCancel or
SQLCancelHandle was called on the
StatementHandle from a different
thread in a multithread application.
SQ L STAT E ERRO R DESC RIP T IO N

HY009 Invalid use of null pointer The SQL_ATTR_METADATA_ID


statement attribute was set to
SQL_TRUE, the CatalogName
argument was a null pointer, and the
SQL_CATALOG_NAME InfoType returns
that catalog names are supported.

(DM) The SQL_ATTR_METADATA_ID


statement attribute was set to
SQL_TRUE, and the SchemaName,
TableName, or ColumnName argument
was a null pointer.

HY010 Function sequence error (DM) An asynchronously executing


function was called for the connection
handle that is associated with the
StatementHandle. This asynchronous
function was still executing when the
SQLColumns function was called.

(DM) SQLExecute , SQLExecDirect ,


or SQLMoreResults was called for
the StatementHandle and returned
SQL_PARAM_DATA_AVAILABLE. This
function was called before data was
retrieved for all streamed parameters.

(DM) An asynchronously executing


function (not this one) was called for
the StatementHandle and was still
executing when this function was
called.

(DM) SQLExecute , SQLExecDirect ,


SQLBulkOperations , or SQLSetPos
was called for the StatementHandle
and returned SQL_NEED_DATA. This
function was called before data was
sent for all data-at-execution
parameters or columns.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY090 Invalid string or buffer length (DM) The value of one of the name
length arguments was less than 0 but
not equal to SQL_NTS.

The value of one of the name length


arguments exceeded the maximum
length value for the corresponding
catalog or name. The maximum length
of each catalog or name can be
obtained by calling SQLGetInfo with
the InfoType values. (See "Comments.")
SQ L STAT E ERRO R DESC RIP T IO N

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.

HYC00 Optional feature not implemented A catalog name was specified, and the
driver or data source does not support
catalogs.

A schema name was specified, and the


driver or data source does not support
schemas.

A string search pattern was specified


for the schema name, table name, or
column name, and the data source
does not support search patterns for
one or more of those arguments.

The combination of the current


settings of the
SQL_ATTR_CONCURRENCY and
SQL_ATTR_CURSOR_TYPE statement
attributes was not supported by the
driver or data source.

The SQL_ATTR_USE_BOOKMARKS
statement attribute was set to
SQL_UB_VARIABLE, and the
SQL_ATTR_CURSOR_TYPE statement
attribute was set to a cursor type for
which the driver does not support
bookmarks.

HYT00 Timeout expired The query timeout period expired


before the data source returned the
result set. The timeout period is set
through SQLSetStmtAttr ,
SQL_ATTR_QUERY_TIMEOUT.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
StatementHandle does not support
the function.

IM017 Polling is disabled in asynchronous Whenever the notification model is


notification mode used, polling is disabled.
SQ L STAT E ERRO R DESC RIP T IO N

IM018 SQLCompleteAsync has not been If the previous function call on the
called to complete the previous handle returns SQL_STILL_EXECUTING
asynchronous operation on this and if notification mode is enabled,
handle. SQLCompleteAsync must be called
on the handle to do post-processing
and complete the operation.

Comments
This function typically is used before statement execution to retrieve information about columns for a table or
tables from the data source's catalog. SQLColumns can be used to retrieve data for all types of items returned
by SQLTables . In addition to base tables, this may include (but is not limited to) views, synonyms, system tables,
and so on. By contrast, the functions SQLColAttribute and SQLDescribeCol describe the columns in a result
set and the function SQLNumResultCols returns the number of columns in a result set. For more information,
see Uses of Catalog Data.

NOTE
For more information about the general use, arguments, and returned data of ODBC catalog functions, see Catalog
Functions.

SQLColumns returns the results as a standard result set, ordered by TABLE_CAT, TABLE_SCHEM, TABLE_NAME,
and ORDINAL_POSITION.

NOTE
When an application works with an ODBC 2.x driver, no ORDINAL_POSITION column is returned in the result set. As a
result, when working with ODBC 2.x drivers, the order of the columns in the column list returned by SQLColumns is not
necessarily the same as the order of the columns returned when the application performs a SELECT statement on all
columns in that table.

NOTE
SQLColumns might not return all columns. For example, a driver might not return information about pseudo-columns,
such as Oracle ROWID. Applications can use any valid column, whether it is returned by SQLColumns .
Some columns that can be returned by SQLStatistics are not returned by SQLColumns . For example, SQLColumns
does not return the columns in an index created over an expression or filter, such as SALARY + BENEFITS or DEPT = 0012.

The lengths of VARCHAR columns are not shown in the table; the actual lengths depend on the data source. To
determine the actual lengths of the TABLE_CAT, TABLE_SCHEM, TABLE_NAME, and COLUMN_NAME columns, an
application can call SQLGetInfo with the SQL_MAX_CATALOG_NAME_LEN, SQL_MAX_SCHEMA_NAME_LEN,
SQL_MAX_TABLE_NAME_LEN, and SQL_MAX_COLUMN_NAME_LEN options.
The following columns have been renamed for ODBC 3.x. The column name changes do not affect backward
compatibility because applications bind by column number.

O DB C 2. 0 C O L UM N O DB C 3. X C O L UM N

TABLE_QUALIFIER TABLE_CAT
O DB C 2. 0 C O L UM N O DB C 3. X C O L UM N

TABLE_OWNER TABLE_SCHEM

PRECISION COLUMN_SIZE

LENGTH BUFFER_LENGTH

SCALE DECIMAL_DIGITS

RADIX NUM_PREC_RADIX

The following columns have been added to the result set returned by SQLColumns for ODBC 3.x:
CHAR_OCTET_LENGTH
COLUMN_DEF
IS_NULLABLE
ORDINAL_POSITION
SQL_DATA_TYPE
SQL_DATETIME_SUB
The following table lists the columns in the result set. Additional columns beyond column 18 (IS_NULLABLE) can
be defined by the driver. An application should gain access to driver-specific columns by counting down from
the end of the result set instead of specifying an explicit ordinal position. For more information, see Data
Returned by Catalog Functions.

C O L UM N

C O L UM N N A M E N UM B ER DATA T Y P E C O M M EN T S

TABLE_CAT (ODBC 1.0) 1 Varchar Catalog name; NULL if not


applicable to the data
source. If a driver supports
catalogs for some tables
but not for others, such as
when the driver retrieves
data from different DBMSs,
it returns an empty string
("") for those tables that do
not have catalogs.

TABLE_SCHEM (ODBC 1.0) 2 Varchar Schema name; NULL if not


applicable to the data
source. If a driver supports
schemas for some tables
but not for others, such as
when the driver retrieves
data from different DBMSs,
it returns an empty string
("") for those tables that do
not have schemas.

TABLE_NAME (ODBC 1.0) 3 Varchar not NULL Table name.


C O L UM N

C O L UM N N A M E N UM B ER DATA T Y P E C O M M EN T S

COLUMN_NAME (ODBC 4 Varchar not NULL Column name. The driver


1.0) returns an empty string for
a column that does not
have a name.

DATA_TYPE (ODBC 1.0) 5 Smallint not NULL SQL data type. This can be
an ODBC SQL data type or
a driver-specific SQL data
type. For datetime and
interval data types, this
column returns the concise
data type (such as
SQL_TYPE_DATE or
SQL_INTERVAL_YEAR_TO_M
ONTH, instead of the
nonconcise data type such
as SQL_DATETIME or
SQL_INTERVAL). For a list of
valid ODBC SQL data types,
see SQL Data Types in
Appendix D: Data Types. For
information about driver-
specific SQL data types, see
the driver's documentation.

The data types returned for


ODBC 3.x and ODBC 2.x
applications may be
different. For more
information, see Backward
Compatibility and Standards
Compliance.

TYPE_NAME (ODBC 1.0) 6 Varchar not NULL Data source-dependent


data type name; for
example, "CHAR",
"VARCHAR", "MONEY",
"LONG VARBINAR", or
"CHAR ( ) FOR BIT DATA".
C O L UM N

C O L UM N N A M E N UM B ER DATA T Y P E C O M M EN T S

COLUMN_SIZE (ODBC 1.0) 7 Integer If DATA_TYPE is SQL_CHAR


or SQL_VARCHAR, this
column contains the
maximum length in
characters of the column.
For datetime data types,
this is the total number of
characters required to
display the value when it is
converted to characters. For
numeric data types, this is
either the total number of
digits or the total number
of bits allowed in the
column, according to the
NUM_PREC_RADIX column.
For interval data types, this
is the number of characters
in the character
representation of the
interval literal (as defined by
the interval leading
precision, see Interval Data
Type Length in Appendix D:
Data Types). For more
information, see Column
Size, Decimal Digits, Transfer
Octet Length, and Display
Size in Appendix D: Data
Types.

BUFFER_LENGTH (ODBC 8 Integer The length in bytes of data


1.0) transferred on an
SQLGetData, SQLFetch, or
SQLFetchScroll operation if
SQL_C_DEFAULT is
specified. For numeric data,
this size may differ from the
size of the data stored on
the data source. This value
might differ from
COLUMN_SIZE column for
character data. For more
information about length,
see Column Size, Decimal
Digits, Transfer Octet
Length, and Display Size in
Appendix D: Data Types.
C O L UM N

C O L UM N N A M E N UM B ER DATA T Y P E C O M M EN T S

DECIMAL_DIGITS (ODBC 9 Smallint The total number of


1.0) significant digits to the right
of the decimal point. For
SQL_TYPE_TIME and
SQL_TYPE_TIMESTAMP, this
column contains the
number of digits in the
fractional seconds
component. For the other
data types, this is the
decimal digits of the column
on the data source. For
interval data types that
contain a time component,
this column contains the
number of digits to the
right of the decimal point
(fractional seconds). For
interval data types that do
not contain a time
component, this column is
0. For more information
about decimal digits, see
Column Size, Decimal Digits,
Transfer Octet Length, and
Display Size in Appendix D:
Data Types. NULL is
returned for data types
where DECIMAL_DIGITS is
not applicable.
C O L UM N

C O L UM N N A M E N UM B ER DATA T Y P E C O M M EN T S

NUM_PREC_RADIX (ODBC 10 Smallint For numeric data types,


1.0) either 10 or 2. If it is 10, the
values in COLUMN_SIZE
and DECIMAL_DIGITS give
the number of decimal
digits allowed for the
column. For example, a
DECIMAL(12,5) column
would return a
NUM_PREC_RADIX of 10, a
COLUMN_SIZE of 12, and a
DECIMAL_DIGITS of 5; a
FLOAT column could return
a NUM_PREC_RADIX of 10,
a COLUMN_SIZE of 15, and
a DECIMAL_DIGITS of
NULL.

If it is 2, the values in
COLUMN_SIZE and
DECIMAL_DIGITS give the
number of bits allowed in
the column. For example, a
FLOAT column could return
a RADIX of 2, a
COLUMN_SIZE of 53, and a
DECIMAL_DIGITS of NULL.

NULL is returned for data


types where
NUM_PREC_RADIX is not
applicable.
C O L UM N

C O L UM N N A M E N UM B ER DATA T Y P E C O M M EN T S

NULLABLE (ODBC 1.0) 11 Smallint not NULL SQL_NO_NULLS if the


column could not include
NULL values.

SQL_NULLABLE if the
column accepts NULL
values.

SQL_NULLABLE_UNKNOW
N if it is not known whether
the column accepts NULL
values.

The value returned for this


column differs from the
value returned for the
IS_NULLABLE column. The
NULLABLE column indicates
with certainty that a
column can accept NULLs,
but cannot indicate with
certainty that a column
does not accept NULLs. The
IS_NULLABLE column
indicates with certainty that
a column cannot accept
NULLs, but cannot indicate
with certainty that a
column accepts NULLs.

REMARKS (ODBC 1.0) 12 Varchar A description of the column.

COLUMN_DEF (ODBC 3.0) 13 Varchar The default value of the


column. The value in this
column should be
interpreted as a string if it is
enclosed in quotation
marks.

If NULL was specified as the


default value, this column is
the word NULL, not
enclosed in quotation
marks. If the default value
cannot be represented
without truncation, this
column contains
TRUNCATED, without
enclosing single quotation
marks. If no default value
was specified, this column is
NULL.

The value of COLUMN_DEF


can be used in generating a
new column definition,
except when it contains the
value TRUNCATED.
C O L UM N

C O L UM N N A M E N UM B ER DATA T Y P E C O M M EN T S

SQL_DATA_TYPE (ODBC 14 Smallint not NULL SQL data type, as it appears


3.0) in the SQL_DESC_TYPE
record field in the IRD. This
can be an ODBC SQL data
type or a driver-specific SQL
data type. This column is
the same as the DATA_TYPE
column, except for datetime
and interval data types. This
column returns the
nonconcise data type (such
as SQL_DATETIME or
SQL_INTERVAL), instead of
the concise data type (such
as SQL_TYPE_DATE or
SQL_INTERVAL_YEAR_TO_M
ONTH) for datetime and
interval data types. If this
column returns
SQL_DATETIME or
SQL_INTERVAL, the specific
data type can be
determined from the
SQL_DATETIME_SUB
column. For a list of valid
ODBC SQL data types, see
SQL Data Types in Appendix
D: Data Types. For
information about driver-
specific SQL data types, see
the driver's documentation.

The data types returned for


ODBC 3.x and ODBC 2.x
applications may be
different. For more
information, see Backward
Compatibility and Standards
Compliance.

SQL_DATETIME_SUB (ODBC 15 Smallint The subtype code for


3.0) datetime and interval data
types. For other data types,
this column returns a NULL.
For more information about
datetime and interval
subcodes, see
"SQL_DESC_DATETIME_INTE
RVAL_CODE" in
SQLSetDescField.

CHAR_OCTET_LENGTH 16 Integer The maximum length in


(ODBC 3.0) bytes of a character or
binary data type column.
For all other data types, this
column returns a NULL.
C O L UM N

C O L UM N N A M E N UM B ER DATA T Y P E C O M M EN T S

ORDINAL_POSITION 17 Integer not NULL The ordinal position of the


(ODBC 3.0) column in the table. The
first column in the table is
number 1.

IS_NULLABLE (ODBC 3.0) 18 Varchar "NO" if the column does


not include NULLs.

"YES" if the column could


include NULLs.

This column returns a zero-


length string if nullability is
unknown.

ISO rules are followed to


determine nullability. An
ISO SQL-compliant DBMS
cannot return an empty
string.

The value returned for this


column differs from the
value returned for the
NULLABLE column. (See the
description of the
NULLABLE column.)

Code Example
In the following example, an application declares buffers for the result set returned by SQLColumns . It calls
SQLColumns to return a result set that describes each column in the EMPLOYEE table. It then calls
SQLBindCol to bind the columns in the result set to the buffers. Finally, the application fetches each row of data
with SQLFetch and processes it.

// SQLColumns_Function.cpp
// compile with: ODBC32.lib
#include <windows.h>
#include <sqlext.h>
#define STR_LEN 128 + 1
#define REM_LEN 254 + 1

// Declare buffers for result set data


SQLCHAR szSchema[STR_LEN];
SQLCHAR szCatalog[STR_LEN];
SQLCHAR szColumnName[STR_LEN];
SQLCHAR szTableName[STR_LEN];
SQLCHAR szTypeName[STR_LEN];
SQLCHAR szRemarks[REM_LEN];
SQLCHAR szColumnDefault[STR_LEN];
SQLCHAR szIsNullable[STR_LEN];

SQLINTEGER ColumnSize;
SQLINTEGER BufferLength;
SQLINTEGER CharOctetLength;
SQLINTEGER OrdinalPosition;

SQLSMALLINT DataType;
SQLSMALLINT DecimalDigits;
SQLSMALLINT DecimalDigits;
SQLSMALLINT NumPrecRadix;
SQLSMALLINT Nullable;
SQLSMALLINT SQLDataType;
SQLSMALLINT DatetimeSubtypeCode;

SQLHSTMT hstmt = NULL;

// Declare buffers for bytes available to return


SQLINTEGER cbCatalog;
SQLINTEGER cbSchema;
SQLINTEGER cbTableName;
SQLINTEGER cbColumnName;
SQLINTEGER cbDataType;
SQLINTEGER cbTypeName;
SQLINTEGER cbColumnSize;
SQLLEN cbBufferLength;
SQLINTEGER cbDecimalDigits;
SQLINTEGER cbNumPrecRadix;
SQLINTEGER cbNullable;
SQLINTEGER cbRemarks;
SQLINTEGER cbColumnDefault;
SQLINTEGER cbSQLDataType;
SQLINTEGER cbDatetimeSubtypeCode;
SQLINTEGER cbCharOctetLength;
SQLINTEGER cbOrdinalPosition;
SQLINTEGER cbIsNullable;

int main() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt = 0;
SQLRETURN retcode;

retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);


retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
retcode = SQLConnect(hdbc, (SQLCHAR*) "Northwind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLColumns(hstmt, NULL, 0, NULL, 0, (SQLCHAR*)"CUSTOMERS", SQL_NTS, NULL, 0);

if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {


// Bind columns in result set to buffers
SQLBindCol(hstmt, 1, SQL_C_CHAR, szCatalog, STR_LEN,&cbCatalog);
SQLBindCol(hstmt, 2, SQL_C_CHAR, szSchema, STR_LEN, &cbSchema);
SQLBindCol(hstmt, 3, SQL_C_CHAR, szTableName, STR_LEN,&cbTableName);
SQLBindCol(hstmt, 4, SQL_C_CHAR, szColumnName, STR_LEN, &cbColumnName);
SQLBindCol(hstmt, 5, SQL_C_SSHORT, &DataType, 0, &cbDataType);
SQLBindCol(hstmt, 6, SQL_C_CHAR, szTypeName, STR_LEN, &cbTypeName);
SQLBindCol(hstmt, 7, SQL_C_SLONG, &ColumnSize, 0, &cbColumnSize);
SQLBindCol(hstmt, 8, SQL_C_SLONG, &BufferLength, 0, &cbBufferLength);
SQLBindCol(hstmt, 9, SQL_C_SSHORT, &DecimalDigits, 0, &cbDecimalDigits);
SQLBindCol(hstmt, 10, SQL_C_SSHORT, &NumPrecRadix, 0, &cbNumPrecRadix);
SQLBindCol(hstmt, 11, SQL_C_SSHORT, &Nullable, 0, &cbNullable);
SQLBindCol(hstmt, 12, SQL_C_CHAR, szRemarks, REM_LEN, &cbRemarks);
SQLBindCol(hstmt, 13, SQL_C_CHAR, szColumnDefault, STR_LEN, &cbColumnDefault);
SQLBindCol(hstmt, 14, SQL_C_SSHORT, &SQLDataType, 0, &cbSQLDataType);
SQLBindCol(hstmt, 15, SQL_C_SSHORT, &DatetimeSubtypeCode, 0, &cbDatetimeSubtypeCode);
SQLBindCol(hstmt, 16, SQL_C_SLONG, &CharOctetLength, 0, &cbCharOctetLength);
SQLBindCol(hstmt, 17, SQL_C_SLONG, &OrdinalPosition, 0, &cbOrdinalPosition);
SQLBindCol(hstmt, 18, SQL_C_CHAR, szIsNullable, STR_LEN, &cbIsNullable);

while (SQL_SUCCESS == retcode) {


retcode = SQLFetch(hstmt);
/*
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
0; // show_error();
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
0; // Process fetched data
0; // Process fetched data
else
break;
*/
}
}
}

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Binding a buffer to a column in a result set SQLBindCol Function

Canceling statement processing SQLCancel Function

Returning privileges for a column or columns SQLColumnPrivileges Function

Fetching a block of data or scrolling through a result set SQLFetchScroll Function

Fetching multiple rows of data SQLFetch Function

Returning columns that uniquely identify a row, or columns SQLSpecialColumns Function


automatically updated by a transaction

Returning table statistics and indexes SQLStatistics Function

Returning a list of tables in a data source SQLTables Function

Returning privileges for a table or tables SQLTablePrivileges Function

See Also
ODBC API Reference
ODBC Header Files
SQLCompleteAsync Function
4/27/2022 • 2 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 3.8 Standards Compliance: None
Summar y
SQLCompleteAsync can be used to determine when an asynchronous function is complete using either
notification- or polling-based processing. For more information about asynchronous operations, see
Asynchronous Execution.
SQLCompleteAsync is only implemented in the ODBC Driver Manager.
In notification based asynchronous processing mode, SQLCompleteAsync must be called after the Driver
Manager raises the event object used for notification. SQLCompleteAsync completes the asynchronous
processing and the asynchronous function will generate a return code.
In polling based asynchronous processing mode, SQLCompleteAsync is an alternative to calling the original
asynchronous function, without needing to specify the arguments in the original asynchronous function call.
SQLCompleteAsync can be used regardless whether the ODBC Cursor Library is enabled.

Syntax
SQLRETURN SQLCompleteAsync(
SQLSMALLINT HandleType,
SQLHANDLE Handle,
RETCODE * AsyncRetCodePtr);

Arguments
HandleType
[Input] The type of the handle on which to complete asynchronous processing. Valid values are
SQL_HANDLE_DBC or SQL_HANDLE_STMT.
Handle
[Input] The handle on which to complete asynchronous processing. If Handle is not a valid handle of the type
specified by HandleType, SQLCompleteAsync returns SQL_INVALID_HANDLE.
If Handle is not a valid handle of the type specified by HandleType, SQLCompleteAsync returns
SQL_INVALID_HANDLE.
AsyncRetCodePtr
[Output] Pointer to a buffer that will contain the return code of the asynchronous API. If AsyncRetCodePtr is
NULL, SQLCompleteAsync returns SQL_ERROR.

Returns
SQL_SUCCESS, SQL_ERROR, SQL_NO_DATA, or SQL_INVALID_HANDLE.

Diagnostics
If SQLCompleteAsync returns SQL_SUCCESS, an application should get the return code of the asynchronous
function from the buffer pointed to by AsyncRetCodePtr. The associated SQLSTATE, if any, can be obtained by
calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a statement handle or a HandleType of
SQL_HANDLE_DBC and a connection handle. Those diagnostic records are associated with the asynchronous
function, not this SQLCompleteAsync function.
SQLCompleteAsync returns a code other than SQL_SUCCESS to indicate that SQLCompleteAsync is not
called correctly. SQLCompleteAsync will not post any diagnostic record in this case. Possible return codes are:
SQL_INVALID_HANDLE: The handle indicated by HandleType and Handle is not a valid handle.
SQL_ERROR: AsyncRetCodePtr is NULL or asynchronous processing is not enabled on the handle.
SQL_NO_DATA: In notification mode, an asynchronous operation is not in progress or the Driver Manager
has not notified the application. In polling mode, an asynchronous operation is not in progress.

Comments
In polling based asynchronous processing mode, AsyncRetCodePtr might be SQL_STILL_EXECUTING when
SQLCompleteAsync returns SQL_SUCCESS. Application should keep polling until AsyncRetCodePtr is not
SQL_STILL_EXECUTING. In notification based asynchronous processing mode, AsyncRetCodePtr will never be
SQL_STILL_EXECUTING.

See Also
Asynchronous Execution (Polling Method)
SQLConnect Function
4/27/2022 • 14 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: ISO 92
Summar y
SQLConnect establishes connections to a driver and a data source. The connection handle references storage
of all information about the connection to the data source, including status, transaction state, and error
information.

Syntax
SQLRETURN SQLConnect(
SQLHDBC ConnectionHandle,
SQLCHAR * ServerName,
SQLSMALLINT NameLength1,
SQLCHAR * UserName,
SQLSMALLINT NameLength2,
SQLCHAR * Authentication,
SQLSMALLINT NameLength3);

Arguments
ConnectionHandle
[Input] Connection handle.
ServerName
[Input] Data source name. The data might be located on the same computer as the program, or on another
computer somewhere on a network. For information about how an application chooses a data source, see
Choosing a Data Source or Driver.
NameLength1
[Input] Length of *ServerName in characters.
UserName
[Input] User identifier.
NameLength2
[Input] Length of *UserName in characters.
Authentication
[Input] Authentication string (typically the password).
NameLength3
[Input] Length of *Authentication in characters.

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, SQL_INVALID_HANDLE, or SQL_STILL_EXECUTING.
Diagnostics
When SQLConnect returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value can be
obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_DBC and a Handle of
ConnectionHandle. The following table lists the SQLSTATE values typically returned by SQLConnect and
explains each one in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs
returned by the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless
noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

01S02 Option value changed The driver did not support the
specified value of the ValuePtr
argument in SQLSetConnectAttr
and substituted a similar value.
(Function returns
SQL_SUCCESS_WITH_INFO.)

08001 Client unable to establish connection The driver was unable to establish a
connection with the data source.

08002 Connection name in use (DM) The specified ConnectionHandle


had already been used to establish a
connection with a data source, and the
connection was still open or the user
was browsing for a connection.

08004 Server rejected the connection The data source rejected the
establishment of the connection for
implementation-defined reasons.

08S01 Communication link failure The communication link between the


driver and the data source to which
the driver was trying to connect failed
before the function completed
processing.

28000 Invalid authorization specification The value specified for the argument
UserName or the value specified for
the argument Authentication violated
restrictions defined by the data source.

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.

HY001 Memory allocation error (DM) The Driver Manager was unable
to allocate memory that is required to
support execution or completion of
the function.
SQ L STAT E ERRO R DESC RIP T IO N

HY008 Operation canceled Asynchronous processing was enabled


for the ConnectionHandle. The
SQLConnect function was called, and
before it completed execution,
SQLCancelHandle Function was called
on the ConnectionHandle, and then
the SQLConnect function was called
again on the ConnectionHandle.

Or, the SQLConnect function was


called, and before it completed
execution, SQLCancelHandle was
called on the ConnectionHandle from a
different thread in a multithread
application.

HY010 Function sequence error (DM) An asynchronously executing


function (not this one) was called for
the ConnectionHandle and was still
executing when this function was
called.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY090 Invalid string or buffer length (DM) The value specified for argument
NameLength1, NameLength2, or
NameLength3 was less than 0 but not
equal to SQL_NTS.

(DM) The value specified for argument


NameLength1 exceeded the maximum
length for a data source name.

HYT00 Timeout expired The query timeout period expired


before the connection to the data
source completed. The timeout period
is set through SQLSetConnectAttr ,
SQL_ATTR_LOGIN_TIMEOUT.

HY114 Driver does not support connection (DM) The application enabled the
level asynchronous function execution asynchronous operation on the
connection handle before making the
connection. However, the driver does
not support asynchronous operations
on the connection handle.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.
SQ L STAT E ERRO R DESC RIP T IO N

IM001 Driver does not support this function (DM) The driver specified by the data
source name does not support the
function.

IM002 Data source not found and no default (DM) The data source name specified
driver specified in the argument ServerName was not
found in the system information, nor
was there a default driver specification.

IM003 Specified driver could not be (DM) The driver listed in the data
connected to source specification in system
information was not found or could
not be connected to for some other
reason.

IM004 Driver's SQLAllocHandle on (DM) During SQLConnect , the Driver


SQL_HANDLE_ENV failed Manager called the driver's
SQL AllocHandle function with a
HandleType of SQL_HANDLE_ENV and
the driver returned an error.

IM005 Driver's SQLAllocHandle on (DM) During SQLConnect , the Driver


SQL_HANDLE_DBC failed Manager called the driver's
SQL AllocHandle function with a
HandleType of SQL_HANDLE_DBC and
the driver returned an error.

IM006 Driver's SQLSetConnectAttr failed During SQLConnect , the Driver


Manager called the driver's
SQLSetConnectAttr function and
the driver returned an error. (Function
returns SQL_SUCCESS_WITH_INFO.)

IM009 Unable to connect to translation DLL The driver was unable to connect to
the translation DLL that was specified
for the data source.

IM010 Data source name too long (DM) *ServerName was longer than
SQL_MAX_DSN_LENGTH characters.

IM014 The specified DSN contains an (DM) 32-bit application uses a DSN
architecture mismatch between the connecting to a 64-bit driver; or vice
Driver and Application versa.

IM015 Driver's SQLConnect on If a driver returns SQL_ERROR, the


SQL_HANDLE_DBC_INFO_HANDLE Driver Manager will return SQL_ERROR
failed to the application and the connection
will fail.

For more information about


SQL_HANDLE_DBC_INFO_TOKEN, see
Developing Connection-Pool
Awareness in an ODBC Driver.

IM017 Polling is disabled in asynchronous Whenever the notification model is


notification mode used, polling is disabled.
SQ L STAT E ERRO R DESC RIP T IO N

IM018 SQLCompleteAsync has not been If the previous function call on the
called to complete the previous handle returns SQL_STILL_EXECUTING
asynchronous operation on this and if notification mode is enabled,
handle. SQLCompleteAsync must be called
on the handle to do post-processing
and complete the operation.

S1118 Driver does not support asynchronous When the driver does not support
notification asynchronous notification, you cannot
set SQL_ATTR_ASYNC_DBC_EVENT or
SQL_ATTR_ASYNC_DBC_RETCODE_PTR.

Comments
For information about why an application uses SQLConnect , see Connecting with SQLConnect.
The Driver Manager does not connect to a driver until the application calls a function (SQLConnect ,
SQLDriverConnect , or SQLBrowseConnect ) to connect to the driver. Until that point, the Driver Manager
works with its own handles and manages connection information. When the application calls a connection
function, the Driver Manager checks whether a driver is currently connected to for the specified
ConnectionHandle:
If a driver is not connected to, the Driver Manager connects to the driver and calls SQL AllocHandle with
a HandleType of SQL_HANDLE_ENV, SQL AllocHandle with a HandleType of SQL_HANDLE_DBC,
SQLSetConnectAttr (if the application specified any connection attributes), and the connection function
in the driver. The Driver Manager returns SQLSTATE IM006 (Driver's SQLSetConnectOption failed) and
SQL_SUCCESS_WITH_INFO for the connection function if the driver returned an error for
SQLSetConnectAttr . For more information, see Connecting to a Data Source or Driver.
If the specified driver is already connected to on the ConnectionHandle, the Driver Manager calls only the
connection function in the driver. In this case, the driver must make sure that all connection attributes for
the ConnectionHandle maintain their current settings.
If a different driver is connected to, the Driver Manager calls SQLFreeHandle with a HandleType of
SQL_HANDLE_DBC, and then, if no other driver is connected to in that environment, it calls
SQLFreeHandle with a HandleType of SQL_HANDLE_ENV in the connected driver and then disconnects
that driver. It then performs the same operations as when a driver is not connected to.
The driver then allocates handles and initializes itself.
When the application calls SQLDisconnect , the Driver Manager calls SQLDisconnect in the driver. However, it
does not disconnect the driver. This keeps the driver in memory for applications that repeatedly connect to and
disconnect from a data source. When the application calls SQLFreeHandle with a HandleType of
SQL_HANDLE_DBC, the Driver Manager calls SQLFreeHandle with a HandleType of SQL_HANDLE_DBC and
then SQLFreeHandle with a HandleType of SQL_HANDLE_ENV in the driver, and then disconnects the driver.
An ODBC application can establish more than one connection.

Driver Manager Guidelines


The contents of *ServerName affect how the Driver Manager and a driver work together to establish a
connection to a data source.
If *ServerName contains a valid data source name, the Driver Manager locates the corresponding data
source specification in the system information and connects to the associated driver. The Driver Manager
passes each SQLConnect argument to the driver.
If the data source name cannot be found or ServerName is a null pointer, the Driver Manager locates the
default data source specification and connects to the associated driver. The Driver Manager passes to the
driver the UserName and Authentication arguments unmodified, and "DEFAULT" for the ServerName
argument.
If the ServerName argument is "DEFAULT", the Driver Manager locates the default data source
specification and connects to the associated driver. The Driver Manager passes each SQLConnect
argument to the driver.
If the data source name cannot be found or ServerName is a null pointer, and the default data source
specification does not exist, the Driver Manager returns SQL_ERROR with SQLSTATE IM002 (Data source
name not found and no default driver specified).
After it is connected to by the Driver Manager, a driver can locate its corresponding data source specification in
the system information and use driver-specific information from the specification to complete its set of required
connection information.
If a default translation library is specified in the system information for the data source, the driver connects to it.
A different translation library can be connected to by calling SQLSetConnectAttr with the
SQL_ATTR_TRANSLATE_LIB attribute. A translation option can be specified by calling SQLSetConnectAttr with
the SQL_ATTR_TRANSLATE_OPTION attribute.
If a driver supports SQLConnect , the driver keyword section of the system information for the driver must
contain the ConnectFunctions keyword with the first character set to "Y."
Connection Pooling
Connection pooling allows an application to reuse a connection that has already been created. When connection
pooling is enabled and SQLConnect is called, the Driver Manager tries to make the connection using a
connection that is part of a pool of connections in an environment that has been designated for connection
pooling. This environment is a shared environment that is used by all applications that use the connections in
the pool.
Connection pooling is enabled before the environment is allocated by calling SQLSetEnvAttr to set
SQL_ATTR_CONNECTION_POOLING to SQL_CP_ONE_PER_DRIVER (which specifies a maximum of one pool per
driver) or SQL_CP_ONE_PER_HENV (which specifies a maximum of one pool per environment). SQLSetEnvAttr
in this case is called with EnvironmentHandle set to null, which makes the attribute a process-level attribute. If
SQL_ATTR_CONNECTION_POOLING is set to SQL_CP_OFF, connection pooling is disabled.
After connection pooling has been enabled, SQL AllocHandle with a HandleType of SQL_HANDLE_ENV is called
to allocate an environment. The environment allocated by this call is a shared environment because connection
pooling has been enabled. However, the environment that will be used is not determined until
SQL AllocHandle with a HandleType of SQL_HANDLE_DBC is called.
SQL AllocHandle with a HandleType of SQL_HANDLE_DBC is called to allocate a connection. The Driver
Manager tries to find an existing shared environment that matches the environment attributes set by the
application. If no such environment exists, one is created as an implicit shared environment. If a matching shared
environment is found, the environment handle is returned to the application and its reference count is
incremented.
However, the connection that will be used is not determined until SQLConnect is called. At that point, the Driver
Manager tries to find an existing connection in the connection pool that matches the criteria requested by the
application. These criteria include the connection options requested in the call to SQLConnect (the values of the
ServerName, UserName, and Authentication keywords) and any connection attributes set since
SQL AllocHandle with a HandleType of SQL_HANDLE_DBC was called. The Driver Manager checks these
criteria against the corresponding connection keywords and attributes in connections in the pool. If a match is
found, the connection in the pool is used. If no match is found, a new connection is created.
If the SQL_ATTR_CP_MATCH environment attribute is set to SQL_CP_STRICT_MATCH, the match must be exact
for a connection in the pool to be used. If the SQL_ATTR_CP_MATCH environment attribute is set to
SQL_CP_RELAXED_MATCH, the connection options in the call to SQLConnect must match but not all the
connection attributes must match.
The following rules are applied when a connection attribute, as set by the application before SQLConnect is
called, does not match the connection attribute of the connection in the pool:
If the connection attribute must be set before the connection is made:
If SQL_ATTR_CP_MATCH is SQL_CP_STRICT_MATCH, SQL_ATTR_PACKET_SIZE in the pooled connection
must be identical to the attribute set by the application. If SQL_CP_RELAXED_MATCH, the values of
SQL_ATTR_PACKET_SIZE can be different.
The value of SQL_ATTR_LOGIN_VALUE does not affect the match.
If the connection attribute can be set either before or after the connection is made:
If the connection attribute has not been set by the application but has been set on the connection in the
pool, and there is a default, the connection attribute in the pooled connection is set back to the default
and a match is declared. If there is no default, the pooled connection is not considered a match.
If the connection attribute has been set by the application but has not been set on the connection in the
pool, the connection attribute on the pool is changed to that set by the application and a match is
declared.
If the connection attribute has been set by the application, and has also been set on the connection in the
pool but the values are different, the value of the application's connection attribute is used and a match is
declared.
If the values of driver-specific connection attributes are not identical and SQL_ATTR_CP_MATCH is set to
SQL_CP_STRICT_MATCH, the connection in the pool is not used.
When the application calls SQLDisconnect to disconnect, the connection is returned to the connection pool
and is available for reuse.
Optimizing Connection Pooling Performance
When distributed transactions are involved, it is possible to optimize connection pooling performance by using
SQL_DTC_TRANSITION_COST , which is a SQLUINTEGER bitmask. The transitions referred to are the
transitions of the connection attribute SQL_ATTR_ENLIST_IN_DTC going from value 0 to nonzero, and vice versa.
This is a connection going from not enlisted in a distributed transaction to enlisted in a distributed transaction,
and vice versa. Depending on how the driver has implemented enlistment (setting connection attribute
SQL_ATTR_ENLIST_IN_DTC), these transitions may be expensive and should therefore be avoided for best
performance.
The value returned by the driver contains any combination of the following bits:
SQL_DTC_ENLIST_EXPENSIVE , when set, implies the zero to nonzero transition is significantly more
expensive than a transition from nonzero to another nonzero value (enlisting a previously enlisted
connection in its next transaction).
SQL_DTC_UNENLIST_EXPENSIVE , when set, implies the nonzero to zero transition is significantly
more expensive than using a connection whose SQL_ATTR_ENLIST_IN_DTC attribute is already set to zero.
There is a performance versus connection usage tradeoff. If a driver indicates that one or more of these
transitions are expensive, the driver manager's connection pooler responds to this by keeping more connections
in the pool. Some of the connections in the pool are preferred for nontransactional use, and some are preferred
for transactional use. However, if the driver indicates that these transitions are not expensive, fewer connections
can be used, perhaps alternating between nontransactional and transactional use.
Drivers that do not support SQL_ATTR_ENLIST_IN_DTC do not need to support SQL_DTC_TRANSITION_COST.
For drivers that support SQL_ATTR_ENLIST_IN_DTC but not SQL_DTC_TRANSITION_COST, it is assumed that the
transitions are not expensive, as if the driver returned 0 (no bits set) for this value.
Although SQL_DTC_TRANSITION_COST was introduced in ODBC 3.5, an ODBC 2.x driver can also support it
because the driver manager will query this information regardless of the driver version.
Code Example
In the following example, an application allocates environment and connection handles. It then connects to the
SalesOrders data source with the user ID JohnS and the password Sesame and processes data. When it has
finished processing data, it disconnects from the data source and frees the handles.
// SQLConnect_ref.cpp
// compile with: odbc32.lib
#include <windows.h>
#include <sqlext.h>

int main() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;

SQLCHAR * OutConnStr = (SQLCHAR * )malloc(255);


SQLSMALLINT * OutConnStrLen = (SQLSMALLINT *)malloc(255);

// Allocate environment handle


retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

// Set the ODBC version environment attribute


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

// Allocate connection handle


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

// Set login timeout to 5 seconds


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

// Connect to data source


retcode = SQLConnect(hdbc, (SQLCHAR*) "NorthWind", SQL_NTS, (SQLCHAR*) NULL, 0, NULL, 0);

// Allocate statement handle


if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

// Process data
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}

SQLDisconnect(hdbc);
}

SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
}

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Allocating a handle SQLAllocHandle Function

Discovering and enumerating values required to connect to SQLBrowseConnect Function


a data source

Disconnecting from a data source SQLDisconnect Function


F O R IN F O RM AT IO N A B O UT SEE

Connecting to a data source using a connection string or SQLDriverConnect Function


dialog box

Returning the setting of a connection attribute SQLGetConnectAttr Function

Setting a connection attribute SQLSetConnectAttr Function

See Also
ODBC API Reference
ODBC Header Files
SQLCopyDesc Function
4/27/2022 • 9 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 3.0 Standards Compliance: ISO 92
Summar y
SQLCopyDesc copies descriptor information from one descriptor handle to another.

Syntax
SQLRETURN SQLCopyDesc(
SQLHDESC SourceDescHandle,
SQLHDESC TargetDescHandle);

Arguments
SourceDescHandle
[Input] Source descriptor handle.
TargetDescHandle
[Input] Target descriptor handle. The TargetDescHandle argument can be a handle to an application descriptor or
an IPD. TargetDescHandle cannot be set to a handle to an IRD, or SQLCopyDesc will return SQLSTATE HY016
(Cannot modify an implementation row descriptor).

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLCopyDesc returns SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value can be
obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_DESC and a Handle of
TargetDescHandle. If an invalid SourceDescHandle was passed in the call, SQL_INVALID_HANDLE will be
returned but no SQLSTATE will be returned. The following table lists the SQLSTATE values commonly returned by
SQLCopyDesc and explains each one in the context of this function; the notation "(DM)" precedes the
descriptions of SQLSTATEs returned by the Driver Manager. The return code associated with each SQLSTATE
value is SQL_ERROR, unless noted otherwise.
When an error is returned, the call to SQLCopyDesc is immediately aborted, and the contents of the fields in
the TargetDescHandle descriptor are undefined.
Because SQLCopyDesc may be implemented by calling SQLGetDescField and SQLSetDescField ,
SQLCopyDesc may return SQLSTATEs returned by SQLGetDescField or SQLSetDescField .

SQ L STAT E ERRO R DESC RIP T IO N


SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning Driver-specific informational message.


(Function returns
SQL_SUCCESS_WITH_INFO.)

08S01 Communication link failure The communication link between the


driver and the data source to which
the driver was connected failed before
the function completed processing.

HY000 General error An error occurred for which there was


no specific SQLSTATE and for which no
implementation-specific SQLSTATE was
defined. The error message returned
by SQLGetDiagRec in the
*MessageText buffer describes the
error and its cause.

HY001 Memory allocation error The driver was unable to allocate the
memory required to support execution
or completion of the function.

HY007 Associated statement is not prepared SourceDescHandle was associated with


an IRD, and the associated statement
handle was not in the prepared or
executed state.
SQ L STAT E ERRO R DESC RIP T IO N

HY010 Function sequence error (DM) The descriptor handle in


SourceDescHandle or
TargetDescHandle was associated with
a StatementHandle for which an
asynchronously executing function
(not this one) was called and was still
executing when this function was
called.

(DM) The descriptor handle in


SourceDescHandle or
TargetDescHandle was associated with
a StatementHandle for which
SQLExecute , SQLExecDirect ,
SQLBulkOperations , or SQLSetPos
was called and returned
SQL_NEED_DATA. This function was
called before data was sent for all
data-at-execution parameters or
columns.

(DM) An asynchronously executing


function was called for the connection
handle that is associated with the
SourceDescHandle or
TargetDescHandle. This asynchronous
function was still executing when the
SQLCopyDesc function was called.

(DM) SQLExecute , SQLExecDirect ,


or SQLMoreResults was called for
one of the statement handles
associated with the SourceDescHandle
or TargetDescHandle and returned
SQL_PARAM_DATA_AVAILABLE. This
function was called before data was
retrieved for all streamed parameters.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY016 Cannot modify an implementation row TargetDescHandle was associated with


descriptor an IRD.

HY021 Inconsistent descriptor information The descriptor information checked


during a consistency check was not
consistent. For more information, see
"Consistency Checks" in
SQLSetDescField .

HY092 Invalid attribute/option identifier The call to SQLCopyDesc prompted a


call to SQLSetDescField , but
*ValuePtr was not valid for the
FieldIdentifier argument on
TargetDescHandle.
SQ L STAT E ERRO R DESC RIP T IO N

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.
allowed.

HYT01 Connection timeout expired The connection timeout period expired


before the data source responded to
the request. The connection timeout
period is set through
SQLSetConnectAttr ,
SQL_ATTR_CONNECTION_TIMEOUT.

IM001 Driver does not support this function (DM) The driver associated with the
SourceDescHandle or
TargetDescHandle does not support
the function.

Comments
A call to SQLCopyDesc copies the fields of the source descriptor handle to the target descriptor handle. Fields
can be copied only to an application descriptor or an IPD, but not to an IRD. Fields can be copied from either an
application or an implementation descriptor.
Fields can be copied from an IRD only if the statement handle is in the prepared or executed state; otherwise, the
function returns SQLSTATE HY007 (Associated statement is not prepared).
Fields can be copied from an IPD whether or not a statement has been prepared. If an SQL statement with
dynamic parameters has been prepared and automatic population of the IPD is supported and enabled, then the
IPD is populated by the driver. When SQLCopyDesc is called with the IPD as the SourceDescHandle, the
populated fields are copied. If the IPD is not populated by the driver, the contents of the fields originally in the
IPD are copied.
All fields of the descriptor, except SQL_DESC_ALLOC_TYPE (which specifies whether the descriptor handle was
automatically or explicitly allocated), are copied, whether or not the field is defined for the destination descriptor.
Copied fields overwrite the existing fields.
The driver copies all descriptor fields if the SourceDescHandle and TargetDescHandle arguments are associated
with the same driver, even if the drivers are on two different connections or environments. If the
SourceDescHandle and TargetDescHandle arguments are associated with different drivers, the Driver Manager
copies ODBC-defined fields, but does not copy driver-defined fields or fields that are not defined by ODBC for
the type of descriptor.
The call to SQLCopyDesc is aborted immediately if an error occurs.
When the SQL_DESC_DATA_PTR field is copied, a consistency check is performed on the target descriptor. If the
consistency check fails, SQLSTATE HY021 (Inconsistent descriptor information) is returned and the call to
SQLCopyDesc is immediately aborted. For more information on consistency checks, see "Consistency Checks"
in SQLSetDescRec Function.
Descriptor handles can be copied across connections even if the connections are under different environments.
If the Driver Manager detects that the source and the destination descriptor handles do not belong to the same
connection and the two connections belong to separate drivers, it implements SQLCopyDesc by performing a
field-by-field copy using SQLGetDescField and SQLSetDescField .
When SQLCopyDesc is called with a SourceDescHandle on one driver and a TargetDescHandle on another
driver, the error queue of the SourceDescHandle is cleared. This occurs because SQLCopyDesc in this case is
implemented by calls to SQLGetDescField and SQLSetDescField .

NOTE
An application might be able to associate an explicitly allocated descriptor handle with a StatementHandle, rather than
calling SQLCopyDesc to copy fields from one descriptor to another. An explicitly allocated descriptor can be associated
with another StatementHandle on the same ConnectionHandle by setting the SQL_ATTR_APP_ROW_DESC or
SQL_ATTR_APP_PARAM_DESC statement attribute to the handle of the explicitly allocated descriptor. When this is done,
SQLCopyDesc does not have to be called to copy descriptor field values from one descriptor to another. A descriptor
handle cannot be associated with a StatementHandle on another ConnectionHandle, however; to use the same descriptor
field values on StatementHandles on different ConnectionHandles, SQLCopyDesc has to be called.

For a description of the fields in a descriptor header or record, see SQLSetDescField Function. For more
information on descriptors, see Descriptors.

Copying Rows Between Tables


An application may copy data from one table to another without copying the data at the application level. To do
this, the application binds the same data buffers and descriptor information to a statement that fetches the data
and the statement that inserts the data into a copy. This can be accomplished either by sharing an application
descriptor (binding an explicitly allocated descriptor as both the ARD to one statement and the APD in another)
or by using SQLCopyDesc to copy the bindings between the ARD and the APD of the two statements. If the
statements are on different connections, SQLCopyDesc must be used. In addition, SQLCopyDesc has to be
called to copy the bindings between the IRD and the IPD of the two statements. When copying across
statements on the same connection, the SQL_ACTIVE_STATEMENTS information type returned by the driver for a
call to SQLGetInfo must be greater than 1 for this operation to succeed. (This is not the case when copying
across connections.)
Code Example
In the following example, descriptor operations are used to copy the fields of the PartsSource table into the
PartsCopy table. The contents of the PartsSource table are fetched into rowset buffers in hstmt0. These values
are used as parameters of an INSERT statement on hstmt1 to populate the columns of the PartsCopy table. To do
so, the fields of the IRD of hstmt0 are copied to the fields of the IPD of hstmt1, and the fields of the ARD of
hstmt0 are copied to the fields of the APD of hstmt1. Use SQLSetDescField to set the IPD's
SQL_DESC_PARAMETER_TYPE attribute to SQL_PARAM_INPUT when you copy IRD fields from a statement with
output parameters to IPD fields that need to be input parameters.

#define ROWS 100


#define DESC_LEN 50
#define SQL_SUCCEEDED(rc) (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

// Template for a row


typedef struct {
SQLINTEGER sPartID;
SQLINTEGER cbPartID;
SQLUCHAR szDescription[DESC_LENGTH];
SQLINTEGER cbDescription;
REAL sPrice;
SQLINTEGER cbPrice;
} PartsSource;

PartsSource rget[ROWS]; // rowset buffer


SQLUSMALLINT sts_ptr[ROWS]; // status pointer
SQLHSTMT hstmt0, hstmt1;
SQLHDESC hArd0, hIrd0, hApd1, hIpd1;

// ARD and IRD of hstmt0


// ARD and IRD of hstmt0
SQLGetStmtAttr(hstmt0, SQL_ATTR_APP_ROW_DESC, &hArd0, 0, NULL);
SQLGetStmtAttr(hstmt0, SQL_ATTR_IMP_ROW_DESC, &hIrd0, 0, NULL);

// APD and IPD of hstmt1


SQLGetStmtAttr(hstmt1, SQL_ATTR_APP_PARAM_DESC, &hApd1, 0, NULL);
SQLGetStmtAttr(hstmt1, SQL_ATTR_IMP_PARAM_DESC, &hIpd1, 0, NULL);

// Use row-wise binding on hstmt0 to fetch rows


SQLSetStmtAttr(hstmt0, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER) sizeof(PartsSource), 0);

// Set rowset size for hstmt0


SQLSetStmtAttr(hstmt0, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) ROWS, 0);

// Execute a select statement


SQLExecDirect(hstmt0, "SELECT PARTID, DESCRIPTION, PRICE FROM PARTS ORDER BY 3, 1, 2"",
SQL_NTS);

// Bind
SQLBindCol(hstmt0, 1, SQL_C_SLONG, rget[0].sPartID, 0,
&rget[0].cbPartID);
SQLBindCol(hstmt0, 2, SQL_C_CHAR, &rget[0].szDescription, DESC_LEN,
&rget[0].cbDescription);
SQLBindCol(hstmt0, 3, SQL_C_FLOAT, rget[0].sPrice,
0, &rget[0].cbPrice);

// Perform parameter bindings on hstmt1.


SQLCopyDesc(hArd0, hApd1);
SQLCopyDesc(hIrd0, hIpd1);

// Set the array status pointer of IRD


SQLSetStmtAttr(hstmt0, SQL_ATTR_ROW_STATUS_PTR, sts_ptr, SQL_IS_POINTER);

// Set the ARRAY_STATUS_PTR field of APD to be the same


// as that in IRD.
SQLSetStmtAttr(hstmt1, SQL_ATTR_PARAM_OPERATION_PTR, sts_ptr, SQL_IS_POINTER);

// Set the hIpd1 records as input parameters


rc = SQLSetDescField(hIpd1, 1, SQL_DESC_PARAMETER_TYPE, (SQLPOINTER)SQL_PARAM_INPUT, SQL_IS_INTEGER);
rc = SQLSetDescField(hIpd1, 2, SQL_DESC_PARAMETER_TYPE, (SQLPOINTER)SQL_PARAM_INPUT, SQL_IS_INTEGER);
rc = SQLSetDescField(hIpd1, 3, SQL_DESC_PARAMETER_TYPE, (SQLPOINTER)SQL_PARAM_INPUT, SQL_IS_INTEGER);

// Prepare an insert statement on hstmt1. PartsCopy is a copy of


// PartsSource
SQLPrepare(hstmt1, "INSERT INTO PARTS_COPY VALUES (?, ?, ?)", SQL_NTS);

// In a loop, fetch a rowset, and copy the fetched rowset to PARTS_COPY

rc = SQLFetchScroll(hstmt0, SQL_FETCH_NEXT, 0);


while (SQL_SUCCEEDED(rc)) {

// After the call to SQLFetchScroll, the status array has row


// statuses. This array is used as input status in the APD
// and hence determines which elements of the rowset buffer
// are inserted.
SQLExecute(hstmt1);

rc = SQLFetchScroll(hstmt0, SQL_FETCH_NEXT, 0);


} // while

Related Functions
F O R IN F O RM AT IO N A B O UT SEE

Getting multiple descriptor fields SQLGetDescRec Function


F O R IN F O RM AT IO N A B O UT SEE

Setting a single descriptor field SQLSetDescField Function

Setting multiple descriptor fields SQLSetDescRec Function

See Also
ODBC API Reference
ODBC Header Files
SQLDataSources Function
4/27/2022 • 4 minutes to read • Edit Online

Conformance
Version Introduced: ODBC 1.0 Standards Compliance: ISO 92
Summar y
SQLDataSources returns information about a data source. This function is implemented only by the Driver
Manager.

Syntax
SQLRETURN SQLDataSources(
SQLHENV EnvironmentHandle,
SQLUSMALLINT Direction,
SQLCHAR * ServerName,
SQLSMALLINT BufferLength1,
SQLSMALLINT * NameLength1Ptr,
SQLCHAR * Description,
SQLSMALLINT BufferLength2,
SQLSMALLINT * NameLength2Ptr);

Arguments
EnvironmentHandle
[Input] Environment handle.
Direction
[Input] Determines which data source the Driver Manager returns information about. Can be:
SQL_FETCH_NEXT (to fetch the next data source name in the list), SQL_FETCH_FIRST (to fetch from the beginning
of the list), SQL_FETCH_FIRST_USER (to fetch the first user DSN), or SQL_FETCH_FIRST_SYSTEM (to fetch the first
system DSN).
When Direction is set to SQL_FETCH_FIRST, subsequent calls to SQLDataSources with Direction set to
SQL_FETCH_NEXT return both user and system DSNs. When Direction is set to SQL_FETCH_FIRST_USER, all
subsequent calls to SQLDataSources with Direction set to SQL_FETCH_NEXT return only user DSNs. When
Direction is set to SQL_FETCH_FIRST_SYSTEM, all subsequent calls to SQLDataSources with Direction set to
SQL_FETCH_NEXT return only system DSNs.
ServerName
[Output] Pointer to a buffer in which to return the data source name.
If ServerName is NULL, NameLength1Ptr will still return the total number of characters (excluding the null-
termination character for character data) available to return in the buffer pointed to by ServerName.
BufferLength1
[Input] Length of the *ServerName buffer, in characters; this does not need to be longer than
SQL_MAX_DSN_LENGTH plus the null-termination character.
NameLength1Ptr
[Output] Pointer to a buffer in which to return the total number of characters (excluding the null-termination
character) available to return in *ServerName. If the number of characters available to return is greater than or
equal to BufferLength1, the data source name in *ServerName is truncated to BufferLength1 minus the length
of a null-termination character.
Description
[Output] Pointer to a buffer in which to return the description of the driver associated with the data source. For
example, dBASE or SQL Server.
If Description is NULL, NameLength2Ptr will still return the total number of characters (excluding the null-
termination character for character data) available to return in the buffer pointed to by Description.
BufferLength2
[Input] Length in characters of the *Description buffer.
NameLength2Ptr
[Output] Pointer to a buffer in which to return the total number of characters (excluding the null-termination
character) available to return in *Description. If the number of characters available to return is greater than or
equal to BufferLength2, the driver description in *Description is truncated to BufferLength2 minus the length of
a null-termination character.

Returns
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics
When SQLDataSources returns either SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE
value can be obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_ENV and a Handle of
EnvironmentHandle. The following table lists the SQLSTATE values typically returned by SQLDataSources and
explains each one in the context of this function; the notation "(DM)" precedes the descriptions of SQLSTATEs
returned by the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless
noted otherwise.

SQ L STAT E ERRO R DESC RIP T IO N

01000 General warning (DM) Driver Manager-specific


informational message. (Function
returns SQL_SUCCESS_WITH_INFO.)

01004 String data, right truncated (DM) The buffer *ServerName was not
large enough to return the complete
data source name. Therefore, the name
was truncated. The length of the entire
data source name is returned in
*NameLength1Ptr. (Function returns
SQL_SUCCESS_WITH_INFO.)

(DM) The buffer *Description was not


large enough to return the complete
driver description. Therefore, the
description was truncated. The length
of the untruncated data source
description is returned in
*NameLength2Ptr. (Function returns
SQL_SUCCESS_WITH_INFO.)
SQ L STAT E ERRO R DESC RIP T IO N

HY000 General error (DM) An error occurred for which there


was no specific SQLSTATE and for
which no implementation-specific
SQLSTATE was defined. The error
message returned by
SQLGetDiagRec in the *MessageText
buffer describes the error and its
cause.

HY001 Memory allocation error (DM) The Driver Manager was unable
to allocate memory that is required to
support execution or completion of
the function.

HY010 Function sequence error (DM) SQLExecute , SQLExecDirect ,


or SQLMoreResults was called for
the StatementHandle and returned
SQL_PARAM_DATA_AVAILABLE. This
function was called before data was
retrieved for all streamed parameters.

HY013 Memory management error The function call could not be


processed because the underlying
memory objects could not be
accessed, possibly because of low
memory conditions.

HY090 Invalid string or buffer length (DM) The value specified for argument
BufferLength1 was less than 0.

(DM) The value specified for argument


BufferLength2 was less than 0.

HY103 Invalid retrieval code (DM) The value specified for the
argument Direction was not equal to
SQL_FETCH_FIRST,
SQL_FETCH_FIRST_USER,
SQL_FETCH_FIRST_SYSTEM, or
SQL_FETCH_NEXT.

HY117 Connection is suspended due to (DM) For more information about


unknown transaction state. Only suspended state, see SQLEndTran
disconnect and read-only functions are Function.

You might also like