You are on page 1of 65

Table of Contents

Microsoft ODBC Driver for SQL Server on Linux


Release Notes for the Microsoft ODBC Driver for SQL Server on Linux
Known Issues in this Version of the Driver
System Requirements
Installing the Microsoft ODBC Driver for SQL Server on Linux
Installing the Driver Manager
Connection String Keywords and Data Source Names (DSNs)
Using Integrated Authentication
ODBC Driver on Linux Support for High Availability, Disaster Recovery
Using Transparent Network IP Resolution
Using Always Encrypted with the Linux ODBC Driver
Custom Keystore Providers
Connecting with sqlcmd
Connecting with bcp
Data Access Tracing with the ODBC Driver on Linux
Programming Guidelines
Frequently Asked Questions (FAQ) for ODBC Linux
Microsoft ODBC Driver for SQL Server on Linux
3/14/2017 • 1 min to read • Edit Online

Download ODBC Driver


The ODBC driver for SQL Server allows native applications (C/C++) running on Linux to connect to SQL Server
2008, SQL Server 2008 R2, SQL Server 2012, SQL Server 2014, SQL Server 2016, and Microsoft Azure SQL
Database.

Documentation
The documentation for the ODBC driver on Linux includes:
Release Notes for the Microsoft ODBC Driver for SQL Server on Linux
Known Issues in this Version of the Driver
System Requirements
Installing the Microsoft ODBC Driver for SQL Server on Linux
Connection String Keywords and Data Source Names (DSNs)
Using Integrated Authentication
ODBC Driver on Linux Support for High Availability, Disaster Recovery
Connecting with sqlcmd
Connecting with bcp
Programming Guidelines
Frequently Asked Questions (FAQ) for ODBC Linux

Community
Microsoft ODBC Driver For SQL Server Team blog
SQL Server Data Access Forum
Release Notes for the Microsoft ODBC Driver for
SQL Server on Linux
3/14/2017 • 2 min to read • Edit Online

Download ODBC Driver


Release Notes for Microsoft ODBC Driver for SQL Server on Linux.

What's New in the Microsoft ODBC Driver 13.1 for SQL Server on Linux
With Microsoft ODBC Driver 13.1 for SQL Server.
New distributions supported: Ubuntu 16.10 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 Microsoft ODBC
Driver for SQL Server on Linux for installation instructions.
unixODBC Driver Manager 2.3.1 Support changes: The ODBC driver no longer depends on custom packaging
for the unixODBC driver manager (except on RedHat 6), and instead relies on the distribution package manager to
resolve the UnixODBC dependency from the distribution's repositories.
BCP API Support: The Linux ODBC driver now supports the use of the BCP API functions (bcp_init, etc.)

What's New in the Microsoft ODBC Driver 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 supported: 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 Microsoft ODBC
Driver for SQL Server on Linux for installation instructions.
unixODBC Driver Manager 2.3.1 Support: In addition to a newer driver manager, there is also a package for
installing this dependency that eases installation and configuration.
Transparent Network IP Resolution: TransparentNetwork IP Resolution is a revision of the existing MultiSubnet
Failover feature 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.
TLS 1.2 Support: The Microsoft ODBC Driver 13.0 for SQL Server on Linux now supports TLS 1.2 when secure
communications with SQL Server are used.

What's New in the Microsoft ODBC Driver 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 AlwaysOn Availability Groups. For more information, see ODBC Driver on Linux
Support for High Availability, Disaster Recovery.
The ODBC driver on Linux supports connections to Microsoft Azure SQL Database. For more information, see How
to: Connect to Windows Azure SQL Database Using ODBC.
The driver supports tracing of ODBC API call entry and exit. For more information, see Data Access Tracing with the
ODBC Driver on Linux.
The -l option has been added to bcp. For more information, see Connecting with bcp.
Known Issues in this Version of the Driver
3/14/2017 • 1 min to read • Edit Online

Download ODBC Driver


This topic contains a list of known issues with the Microsoft ODBC Driver 11 and 13 for SQL Server on Linux.
Additional issues will be posted on the Microsoft ODBC driver team blog.
Windows and Linux can 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 Linux conversion library. Each library might produce different
results when performing the conversions. For more information, see End-User-Defined and Private Use Area
Characters.
The driver manager does not always correctly convert from UTF-8 to UTF-16. Currently, data corruption will
occur when 1 or more characters in the string is not a valid UTF-8 character. ASCII characters will be mapped
correctly. The driver manager will attempt this conversion when calling the SQLCHAR versions of the ODBC
API (for example, SQLDriverConnectA). The driver manager will not 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. However, if the SQL
data type is varchar(n) or char(n) and the application binds the parameter as SQL_C_CHAR or
SQL_C_VARCHAR and if the client uses code page 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 server. This error
can occur when one character in some code pages, such as CP-1252, could be a different number of bytes in
UTF-8. For example, a right apostrophe character encoded in CP-1252 as 0x92 is encoded as the sequence
0xe2 0x80 0x99 in UTF-8, which has 3 bytes.
So, if you specify 1 for ColumnSize in SQLBindParameter for such a character, the driver 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, use the value of BufferLength (and not converted length)
in ColumnSize. ColumnSize cannot be greater than 8000 for varchar(n) type.

See Also
Microsoft ODBC Driver for SQL Server on Linux
System Requirements
3/14/2017 • 1 min to read • Edit Online

Download ODBC Driver


This topic lists the requirements to use the Microsoft ODBC Driver 13 and 11 for SQL Server on Linux.

System Requirements for Microsoft ODBC Driver 13 for SQL Server


The installation packages for the Microsoft ODBC Driver 13.1 for SQL Server on Linux resolves the driver's
dependencies automatically when installed using the package management system of your distribution, as
described on Installing the Microsoft ODBC Driver for SQL Server on Linux.

System Requirements for 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 Service 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
Microsoft ODBC Driver for SQL Server on Linux
Installing the Microsoft ODBC Driver for SQL Server
on Linux
3/14/2017 • 6 min to read • Edit Online

Download ODBC Driver


This topic explains how to install the Microsoft ODBC Driver 13.1 and 11 for SQL Server on Linux.

Installing the Microsoft ODBC Driver 13.1 for SQL Server on Linux
RedHat 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-13.1.4.0-1 mssql-tools-14.0.3.0-1 unixODBC-devel
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc

RedHat 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-13.1.4.0-1 mssql-tools-14.0.3.0-1 unixODBC-devel
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc

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=13.1.4.0-1 mssql-tools-14.0.3.0-1 unixodbc-dev
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc

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=13.1.4.0-1 mssql-tools-14.0.3.0-1 unixodbc-dev
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc

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-13.1.4.0-1 mssql-tools-14.0.3.0-1 unixODBC-devel
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc

Installing the Microsoft ODBC Driver 13 for SQL Server on Linux


RedHat6

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

RedHat 7

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
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

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

SUSE12

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
will 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: Redhat, Ubuntu, and
Suse
It is 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.
Redhat Linux Enterprise Server 7
Download the latest msodbcsql rpm from here: http://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
Download the latest msodbcsql deb from here:
http://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


Download the latest msodbcsql rpm from here: http://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

Once you have 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-*

Installing the Microsoft ODBC Driver 11 for SQL Server on Linux


Before you can begin to use the driver, install the unixODBC driver manager. See Installing the Driver Manager for
more information.
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 ODBC driver on Linux 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 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 are 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".
Use Existing MSDN C++ ODBC Samples for the ODBC Driver on Linux shows a code sample that connects to SQL
Server using the ODBC driver on Linux.
Uninstalling
You can uninstall the ODBC driver 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"

Troubleshooting Connection Problems


If you are unable to make a connection to SQL Server using the ODBC driver on Linux, 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. If you see the UnixODBC Driver Manager
installed package when you execute (on Red Hat) the command yum list unixODBC, delete the package.
Enable the connection log by verifying that your odbcinst.ini file contains the section and these items:

[ODBC]
Trace = Yes
TraceFile = (your log file)

If you get another connection failure and do not see a log file, there (possibly) are two copies of the driver
manager on your computer. Otherwise, the log output should be similar to the following:

[ODBC][28783][1321576347.077780][SQLDriverConnectW.c][290]
Entry:
Connection = 0x17c858e0
Window Hdl = (nil)
Str In = [DRIVER={ODBC Driver 11 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 character encoding is not UTF-8, for example:


UNICODE Using encoding ASCII 'ISO8859-1' and UNICODE 'UCS-2LE'

There is more than one Driver Manager installed and your application is using the wrong one. Or, the Driver
Manager was not built correctly.
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
Error details (http://www.microsoft.com/products/ee/transform.aspx?
ProdName=Microsoft+SQL+Server&EvtSrc=MSSQLServer&EvtID=11001)
The error number specified in the URL (11001) should be changed to match the error that you see.

See Also
Microsoft ODBC Driver for SQL Server on Linux
Installing the Driver Manager
3/14/2017 • 3 min to read • Edit Online

Download ODBC Driver


This topic contains instructions to install the unixODBC Driver Manager for use with Microsoft ODBC Driver 11 for
SQL Server on Linux.

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.0 for SQL
Server
The driver manager dependency is resolved automatically by the package management system when you install
the Microsoft ODBC Driver 13.0 for SQL Server on Linux by following these instructions: Installing the Microsoft
ODBC Driver for SQL Server on Linux.

Installing the Driver Manager for Microsoft ODBC Driver 11 for SQL
Server
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 Microsoft SQL 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 5 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. See Installing the Microsoft ODBC Driver for SQL Server on Linux for more
information.
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: CPPFLAGS="-DSIZEOF_LONG_INT=8".
6. At a command prompt, execute the command: export CPPFLAGS.
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. See Installing the Microsoft ODBC Driver for SQL Server on Linux for more
information.

See Also
Microsoft ODBC Driver for SQL Server on Linux
Connection String Keywords and Data Source Names
(DSNs)
3/14/2017 • 3 min to read • Edit Online

Download ODBC Driver


This topic discusses how you can create a connection to a SQL Server database.

Connection Properties
For this release of the Microsoft ODBC Driver for SQL Server on Linux, you can use the following connection
keywords:

Addr Address ApplicationIntent AutoTranslate Database

Driver DSN Encrypt FileDSN MARS_Connection

MultiSubnetFailover PWD Server Trusted_Connection TrustServerCertificate

UID WSID

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 usedatabase_name command to connect to the database before executing your
queries.

For more information about these keywords, see the ODBC section of Using Connection String Keywords with SQL
Server Native Client.
The value passed to the Driver keyword can either be:
The name you used when you installed the driver. Or,
The path to the driver, which was specified in the template .ini file used to install the driver.
To create a DSN, create (if necessary) and edit the file ~/.odbc.ini (odbc.ini in your home directory). The following
is a sample file that shows the required entries for a DSN:

[MSSQLTest]
Driver = ODBC Driver 11 for SQL Server
Server = [protocol:]server[,port]
#
# Note:
# Port is not a valid keyword in the ~/.odbc.ini file
# for the Microsoft ODBC driver on Linux
#

You can optionally specify the protocol and port to connect to the server. For example, Server =
tcp:servername,12345.
To connect to a named instance on a static port, use Server = servername,port_number. Connecting to a dynamic
port is not supported.
Optionally, you can add the DSN information to a template file and execute the following command: odbcinst -i -s
-f template_file
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 -U -P

Using Secure Sockets Layer (SSL)


You can use Secure Sockets Layer (SSL) to encrypt connections to SQL Server. SSL protects SQL Server user names
and passwords over the network. SSL 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.
Regardless of the settings for Encrypt and TrustServerCertificate, the server login credentials (user name and
password) are always encrypted. The following table shows the effect of the Encrypt and TrustServerCertificate
settings.

TRUSTSERVERCERTIFICATE=FALSE TRUSTSERVERCERTIFICATE=TRUE

Encrypt=no Server certificate is not checked. Server certificate is not checked.

Data sent between client and server is Data sent between client and server is
not encrypted. not encrypted.

Encrypt=yes Server certificate is checked. Server certificate is not checked.

Data sent between client and server is Data sent between client and server is
encrypted. encrypted.

The name (or IP address) in a Subject


Common Name (CN) or Subject
Alternative Name (SAN) in a SQL Server
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, also add the TrustServerCertificateOption:

Driver='ODBC Driver 13 for SQL Server';Server=ServerNameHere;Encrypt=YES;TrustServerCertificate=YES

SSL uses the OpenSSL library. The following table shows the minimum supported versions of OpenSSL and the
default Certificate Trust Store locations for each platform:

DEFAULT CERTIFICATE TRUST STORE


PLATFORM MINIMUM OPENSSL VERSION LOCATION

Red Hat Enterprise Linux 6 1.0.0-10 /etc/pki/tls/cert.pem

Red Hat Enterprise Linux 7 1.0.1e /etc/pki/tls/cert.pem


DEFAULT CERTIFICATE TRUST STORE
PLATFORM MINIMUM OPENSSL VERSION LOCATION

SuSE Linux Enterprise 12 1.0.1i /etc/ssl/certs

Ubuntu 15.10 1.0.2d /etc/ssl/certs

Ubuntu 16.04 1.0.2g /etc/ssl/certs

Ubuntu 16.10 1.0.2g /etc/ssl/certs

You can use SQLDriverConnect to specify encryption in the connection string.

See Also
Microsoft ODBC Driver for SQL Server on Linux
Installing the Microsoft ODBC Driver for SQL Server on Linux
Using Integrated Authentication
3/14/2017 • 4 min to read • Edit Online

Download ODBC Driver


The Microsoft ODBC Driver for SQL Server on Linux supports connections that use Kerberos integrated
authentication. The ODBC driver on Linux supports MIT Kerberos Key Distribution Center (KDC), and works with
Generic Security Services Application Program Interface (GSSAPI) and Kerberos libraries.

Using Integrated Authentication to Connect to SQL Server from an


ODBC Application
You can enable Kerberos Windows integrated authentication by specifying Trusted_Connection=yes in the
connection string of SQLDriverConnect or SQLConnect. For example:

Driver='ODBC Driver 11 for SQL Server';Server=your_server;Trusted_Connection=yes

You can also add Trusted_Connection=yes in the DSN entry of the ODBC.ini.
You can also use the -E option in sqlcmd and the -T option in bcp; see Connecting with sqlcmd for more
information.
Ensure that the Linux principal server that is going to connect to SQL Server is already authenticated with the
Kerberos KDC.
ServerSPN and FailoverPartnerSPN are not supported.

Deploying an ODBC Driver on Linux 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 Linux computer 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:
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, that
ktutil created.
Ensure that the login to the system was done using PAM (Pluggable Authentication Module).
Because an application runs as a service and Kerberos credentials, by design, expire, renew the credentials to
ensure continued service availability. The ODBC driver on Linux does not provide the renewal of the credentials.
Ensure that there is a cron job or script that periodically runs to renew the credentials before the expiration. To
avoid requiring the password for each renewal in this case you can use the keytab file, created earlier.
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 system account, the application must use Transact-
SQLEXECUTE 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 Unix ODBC 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.

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 that 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 sqlcmd option. Ensure that the account that runs
sqlcmd is associated with the default Kerberos principal server.

Integrated Authentication and bcp


To access SQL Server using integrated authentication, use the -T bcp option. Ensure that the account that runs bcp
is associated with the default Kerberos principal server.
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 connection string or connection attributes is as follows:

SYNTAX DESCRIPTION

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 Computer with Active Directory
(For more information about authenticating your Linux computer with Active Directory, see Authenticate Linux
Clients with Active Directory.)
Enter data into the krb5.conf file. krb5.conf is in /etc/ but you can refer to another file (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 computer uses Dynamic Host Configuration Protocol (DHCP) and the Windows DHCP server provides
the DNS servers to use, you can use dns_lookup_kdc=true. Now, you can use Kerberos to sign in to your domain,
as follows: kinit alias@YYYY.CORP.CONTOSO.COM . Parameters passed to kinit are case-sensitive and the SQL Server
computer configured to be in the domain must have that user alias@YYYY.CORP.CONTOSO.COM added for login.
The ODBC driver for SQL Server on Linux does not support generating Kerberos credentials via a keytab file. Now,
you can use trusted connections (Trusted_Connection=YES in a connection string or sqlcmd -E).
The time on the Linux computer and the time on the Kerberos Domain Controller (KDC) must be close. Ensure that
your system time is set correctly and equivalent to the Network Time Protocol (NTP).
If Kerberos authentication fails, the ODBC driver on Linux does not use NTLM authentication.

See Also
Microsoft ODBC Driver for SQL Server on Linux
ODBC Driver on Linux Support for High Availability,
Disaster Recovery
3/14/2017 • 4 min to read • Edit Online

Download ODBC Driver


The ODBC driver for Linux supports AlwaysOn Availability Groups. For more information about AlwaysOn
Availability Groups, see:
Availability Group Listeners, Client Connectivity, and Application Failover (SQL Server)
Creation and Configuration of Availability Groups (SQL Server)
Failover Clustering and AlwaysOn Availability Groups (SQL Server)
Active Secondaries: Readable Secondary Replicas (AlwaysOn Availability Groups)
You can specify the availability group listener of a given availability group in the connection string. If an ODBC
driver on Linux application is connected to a database in an availability group that fails over, the original
connection is broken. Then the application must open a new connection to continue work after the failover.
The ODBC driver on Linux iterates sequentially through all IP addresses associated with a DNS entry if:
You are not connecting to an availability group listener. And,
Multiple IP addresses are associated with a hostname.
If the DNS server's first returned IP address by is not bound to any network interface card (NIC), these iterations
can be time consuming. When connecting to an availability group listener, the ODBC driver on Linux attempts to
establish connections to all IP addresses in parallel. If a connection attempt succeeds, the driver discards any
pending connection attempts.

NOTE
Increasing connection timeout and implementing connection retry logic increases the chance of connecting to an availability
group. Also, because a connection can fail because of an availability group failover, implement connection retry logic; retry a
failed connection until it reconnects.

Connecting With MultiSubnetFailover


Always specify MultiSubnetFailover=Yes (or =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 failover cluster instance in SQL Server 2012. MultiSubnetFailover also significantly
reduces failover time for single and multisubnet AlwaysOn topologies. During a multisubnet failover, the client
attempts connections in parallel. During a subnet failover, the ODBC driver on Linux 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 ODBC driver on Linux tries to connect to the database on the primary SQL
Server instance by trying to connect to all the IP addresses. When connecting 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 AlwaysOn Availability Group or
an AlwaysOn Failover Cluster Instance. MultiSubnetFailover=Yes applies to both single- and multisubnet
Availability Groups and Failover Cluster Instances.
Use MultiSubnetFailover=Yes when connecting to an availability group listener or Failover Cluster Instance.
Otherwise, your application' performance can be negatively affected.
To connect to a server in an availability group or Failover Cluster Instance:
MultiSubnetFailover improves performance when connecting to a single subnet or multisubnet.
To connect to an availability group, specify the availability group listener of the availability group as the
server in your connection string.
You cannot connect to a SQL Server instance configured with more than 64 IP addresses.
Behavior of an application that uses the MultiSubnetFailover connection property is not affected based on
the type of authentication: SQL Server Authentication or Kerberos Authentication.
You can increase the value of loginTimeout to accommodate for failover time and reduce the application's
connection retry attempts.
Distributed transactions are not supported.
If read-only routing is not in effect, connecting to a secondary replica location in an availability group fails in the
following situations:
1. If the secondary replica location is not configured to accept connections.
2. 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.

Specifying Application Intent


When ApplicationIntent=ReadOnly, the client requests a read workload when connecting to an AlwaysOn
enabled database. The server enforces 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. (Use the
ALLOW_CONNECTIONS clause of the PRIMARY_ROLE and SECONDARY_ROLETransact-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:
1. Connect to an Always On Availability Group availability group listener.
2. The ApplicationIntent connection string keyword must be set to ReadOnly.
3. The database administrator must configure the Availability Group to enable read-only routing.
It is possible for multiple connections that use read-only routing to connect to different read-only replicas.
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 Server connection keyword. Instead, specify the name of
the read-only instance.
Expect longer connection times with read-only routing than connecting to the primary. Therefore, increase your
login timeout. Read-only routing first connects to the primary and then looks for the best available readable
secondary.

ODBC Syntax
Two ODBC connection string keywords support AlwaysOn 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 properties are:
SQL_COPT_SS_APPLICATION_INTENT
SQL_COPT_SS_MULTISUBNET_FAILOVER
For more information about ODBC connection properties, see SQLSetConnectAttr.
An ODBC driver on Linux application that uses AlwaysOn Availability Groups can use one of two functions to make
the connection:

FUNCTION DESCRIPTION

SQLConnect Function SQLConnect supports both ApplicationIntent and


MultiSubnetFailover via a data source name (DSN) or
connection properties.

SQLDriverConnect Function SQLDriverConnect supports ApplicationIntent and


MultiSubnetFailover via connection string keywords,
connection properties, or DSN.

See Also
Microsoft ODBC Driver for SQL Server on Linux
Using Transparent Network IP Resolution
3/14/2017 • 1 min to read • Edit Online

Download ODBC Driver


TransparentNetworkIPResolution is a revision of the existing MultiSubnetFailover feature, available in Microsoft
ODBC Driver 13 for SQL Server on Linux, 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

TRANSPARENT NETWORK IP RESOLUTION MULTISUBNETFAILOVER BEHAVIOUR

(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.

CONNECTION STRING KEYWORD VALUES DEFAULT

TransparentNetworkIPResolution Yes/No Yes

The SQL_COPT_SS_TNIR pre-connection attribute allows an application to control this setting programmatically:

CONNECTION
ATTRIBUTE SIZE/TYPE DEFAULT VALUE DESCRIPTION

SQL_COPT_SS_TNIR SQL_IS_INTEGER or SQL_IS_ON (1)/ SQL_IS_ON (1) Enables or disables


(1249) SQL_IS_UINTEGER SQL_IS_OFF (0) TNIR.
See Also
Microsoft ODBC Driver for SQL Server on Windows
SQL Server Multi-Subnet Clustering (SQL Server)
Using Always Encrypted with the Linux ODBC Driver
3/14/2017 • 30 min to read • Edit Online

Download ODBC Driver


This article provides information on how to develop ODBC applications using Always Encrypted (Database Engine) and the ODBC Driver 13.1 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 13.1 for SQL Server, achieves this 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. For more information,
see Always Encrypted (Database Engine).
Prerequisites
Configure Always Encrypted in your database. This involves provisioning Always Encrypted keys and setting up encryption for selected
database columns. If you do not already have a database with Always Encrypted configured, follow the directions in Getting Started with
Always Encrypted.
Enabling Always Encrypted for application queries
The easiest way to enable the encryption of parameters, and the decryption of query results targeting the encrypted columns, is by setting the
value of the ColumnEncryption connection string keyword to Enabled .
The following is an example of a connection string that enables Always Encrypted:

SQLWCHAR *connString = L"Driver={ODBC Driver 13 for SQL Server};Server={myServer};Trusted_Connection=yes;ColumnEncryption=Enabled;";

And, the following is an equivalent example using the SQLSetConnectAttr function to set the connection attribute programatically. Setting it this
way overrides the value set in the connection string

SQLSetConnectAttr(hdbc, SQL_COPT_SS_COLUMN_ENCRYPTION, (SQLPOINTER)SQL_COLUMN_ENCRYPTION_ENABLE, 0);

Always Encrypted can also be enabled for individual queries. See the Controlling performance impact of Always Encrypted section below.
Note that, enabling Always Encrypted is not 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 section in Always
Encrypted (Database Engine).
The application can access the column master key that protects the column encryption keys, encrypting the queried database columns.
Retrieving and Modifying Data in Encrypted Columns
Once you enable Always Encrypted for application queries, you can use standard ODBC APIs (see ODBC sample code or ODBC Programmer's
Reference), to retrieve or modify data in encrypted database columns. Assuming your application has the required database permissions and can
access the column master key, the ODBC Driver 13.1 for SQL Server will encrypt any query parameters that target encrypted columns, and will
decrypt data retrieved from encrypted columns, returning plaintext values of ODBC types corresponding to the SQL Server data types set for the
columns in the database schema. If Always Encrypted is not 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 ODBC Driver 13.1
for SQL Server will not attempt to decrypt any values retrieved from encrypted columns and the application will receive binary encrypted data
(as byte arrays).
The below table summarizes the behavior of queries, depending on whether Always Encrypted is enabled or not:

ALWAYS ENCRYPTED IS ENABLED AND ALWAYS ENCRYPTED IS ENABLED AND


APPLICATION CAN ACCESS THE KEYS APPLICATION CANNOT ACCESS THE
QUERY CHARACTERISTIC AND KEY METADATA KEYS OR KEY METADATA ALWAYS ENCRYPTED IS DISABLED

Queries with parameters targeting Parameter values are transparently Error Error
encrypted columns. encrypted.
ALWAYS ENCRYPTED IS ENABLED AND ALWAYS ENCRYPTED IS ENABLED AND
APPLICATION CAN ACCESS THE KEYS APPLICATION CANNOT ACCESS THE
QUERY CHARACTERISTIC AND KEY METADATA KEYS OR KEY METADATA ALWAYS ENCRYPTED IS DISABLED

Queries retrieving data from Results from encrypted columns are Error Results from encrypted columns are
encrypted columns, without transparently decrypted. The not decrypted. The application
parameters targeting encrypted application receives plaintext values receives encrypted values as byte
columns. of the ODBC datatypes 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. Note that 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:
There is nothing specific to encryption in the sample code. The ODBC Driver 13.1 for SQL Server automatically detects and encrypts the the
values of the SSN and date parameters that target encrypted columns. This 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 is highly recommended because it
helps prevent SQL injection), it is 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 ODBC Driver 13.1 for SQL Server would not be
able to determine the values in the target encrypted columns, so it would not 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 ( 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 a Unicode string, which maps to nchar/nvarchar, the query would fail, as Always Encrypted does not support
conversions from encrypted nchar/nvarchar values to encrypted char/varchar 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);

Retrieving Plaintext Data Example


The following example demonstrates filtering data based on encrypted values, and retrieving plaintext data from encrypted columns. Note the
following:
The value used in the WHERE clause to filter on the SSN column needs to be passed using SQLBindParameter, so that the ODBC Driver 13.1
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 ODBC Driver 13.1 for SQL Server will transparently decrypt the data retrieved
from the SSN and BirthDate columns.

NOTE
Queries can perform equality comparisons on columns if they are encrypted using deterministic encryption. For more information, see the Selecting
Deterministic or Randomized encryption section of Always Encrypted (Database Engine).
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);
}

Retrieving Encrypted Data Example


If Always Encrypted is not enabled, a query can still retrieve data from encrypted columns, as long as the query has no parameters targeting
encrypted columns.
The following examples illustrates retrieving binary encrypted data from encrypted columns. Note the following:
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 is not 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);
}

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 set the types of parameters targeting encrypted columns, so that 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.
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 is not greater than the precision
for the target column, in queries that modify values of 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 inside the application. An attempt to insert/modify or to filter by a plaintext
value on an encrypted column will result in an error. To prevent such errors, make sure:
Always Encrypted is enabled for application queries targeting encrypted columns (in the connection string or by setting the
SQL_COPT_SS_COLUMN_ENCRYPTION attribute for a specific connection or the SQL_SOPT_SS_COLUMN_ENCRYPTION for a specific statement).
you use SQLBindParameter to send data targeting encrypted columns. The below example 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. Due to the asymmetric padding behavior of encrypted fixed-length types, it is 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 read more about padding for fixed length types with AE, see Always Encrypted (Database Engine) and SQLSetPos
Function reference.
To mitigate this behavior, use the SQL_COLUMN_IGNORE flag to ignore columns that will not 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.
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 does not correctly return the
plaintext metadata for encrypted columns. To avoid this issue, call SQLDescribeCol on prepared statements before calling SQLMoreResults .

Controlling 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:
Additional 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 13.1 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 ODBC Driver 13.1 for SQL Server 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_encryption analyzes the query statement to find out if any parameters need to be encrypted, and if so, returns the
encryption-related information for each that will allow the ODBC Driver 13.1 for SQL Server to encrypt parameter values. The above behavior
ensures a high-level of transparency to the client application. The application (and the application developer) does not need to be aware of which
queries access encrypted columns, as long as the values targeting encrypted columns are passed to the ODBC Driver 13.1 for SQL Server in
parameters.
Setting Always Encrypted on a Statement
To control the performance impact of retrieving encryption metadata for parameterized queries, you can alter Always Encrypted behavior for
individual queries after 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 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 on a statement, you need to call SQLSetStmtAttr with and set the SQL_SOPT_SS_COLUMN_ENCRYPTION flag
to one of the following:

VALUE DESCRIPTION

SQL_CE_DISABLED (0) Always Encrypted is disabled for the statement

SQL_CE_RESULTSETONLY (1) Decryption Only. Resultsets and return values are decrypted, and parameters
are not encrypted

SQL_CE_ENABLED (3) Always Encrypted is enabled and used for both parameters and results

If most queries a client application sends over a database connection access encrypted columns:
Set the ColumnEncryption connection string keyword to Enabled .
Set the SQL_SOPT_SS_COLUMN_ENCRYPTION attribute to SQL_CE_DISABLED on statements that do not access any encrypted columns. This will
disable both calling sys.sp_describe_parameter_encryption as well as attempts to decrypt any values in the result set.
Set the SQL_SOPT_SS_COLUMN_ENCRYPTION attribute to SQL_CE_RESULTSETONLY on statements that do not have any parameters requiring
encryption, but retrieve data from encrypted columns. This will disable calling sys.sp_describe_parameter_encryption and parameter
encryption. The query will be able to decrypt the results from encrypted columns.

Controlling behavior of Always Encrypted security settings


Force Column Encryption setting
Enforces encryption of a parameter when using Always Encrypted. If SQL Server informs the driver that the parameter does not need to be
encrypted, the query using the parameter will fail. This property provides additional protection against security attacks that involve a
compromised SQL Server providing incorrect encryption metadata to the client, which may lead to data disclosure.
To control this behavior in the driver, set the SQL_CA_SS_FORCE_ENCRYPT descriptor 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, 1, SQL_CA_SS_FORCE_ENCRYPT, (SQLPOINTER)TRUE, SQL_IS_SMALLINT);
Column encryption key caching
To reduce the number of calls to a column master key store to decrypt column encryption keys, the ODBC Driver 13.1 for SQL Server caches the
plaintext column encryption keys in memory. After receiving the encrypted column encryption key value from database metadata, the driver first
tries to find the plaintext column encryption key corresponding to the encrypted key value in the cache. The driver calls the key store containing
the column master key only if it cannot find the encrypted column encryption key value in the cache.
Note: In ODBC Driver 13.1 for SQL Server, the column encryption key entries in the cache are evicted after a two hour timeout. This means that
for a given encrypted column encryption key, the driver contacts the key store only once during the lifetime of the application or every two
hours, whichever is less.

Working with Column Master Key Stores


To encrypt a parameter value or to decrypt data in query results, the ODBC Driver 13.1 for SQL Server 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 does not
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 ODBC Driver 13.1 for SQL Server first obtains the metadata about both the column
encryption key and its corresponding column master key, and 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 ODBC Driver 13.1 for SQL Server communicates with a key
store using a column master key store provider.
Using Built-in Column Master Key Store Provider for AKV
The ODBC Driver 13.1 for SQL Server comes with the following built-in column master key store provider, is pre-registered with the specific
provider name (used to look up the provider).

NAME DESCRIPTION PROVIDER (LOOKUP) NAME

Azure Key Vault A provider for a key store that is based in an Azure AZURE_KEY_VAULT
Key Vault

You do not need to make any application code changes to use these providers but note the following:
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 is 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.
You need to ensure your application can access the key in the key store. This 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 an Azure Key
Vault, you need to make sure to provide correct credentials to the key store in the connection string.
Using 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 ODBC Driver 13.1 for SQL Server includes a built-in column master key store provider for Azure Key Vault. See Azure Key Vault –
Step by Step, Getting Started with Key Vault, and Creating Column Master Keys in Azure Key Vault
ODBC Driver 13.1 for SQL Server contains new connection string keywords which are used to enable seamless integration for Azure Key Vault.
We support the following mechanisms to authenticate to Azure and acquire a token for Azure Key Vault:
1. Username/Password – with this method, the credentials redeemed for an Azure Active Directory issued token are the name of an Azure
Active Directory user and a user password.
2. Client ID/Secret – with this method, the credentials redeemed for an Azure Active Directory issued token are an application client ID and
an application secret.
The below table captures how the new keywords support the above 4 authentication mechanisms for Azure Key Vault.

AUTHENTICATION MECHANISM KEYSTOREAUTHENTICATION KEYSTOREPRINCIPALID KEYSTORESECRET

Username/password KeyVaultPassword Azure Active Directory User Principle Azure Active Directory password
Name

Client ID/secret KeyVaultClientSecret Azure Active Directory Application Application Secret


Client ID

Example Connection Strings


1. Authenticate Azure Key Vault CMK store with ClientID/Secret
L"DRIVER=ODBC Driver 13 for SQL
Server;SERVER=myServer;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultClientSecret;KeyStorePrincipalId=
<clientId>;KeyStoreSecret=<secret>";
2. Authenticate Azure Key Vault CMK store with Username/Password
L"DRIVER=ODBC Driver 13 for SQL
Server;SERVER=myServer;Trusted_Connection=Yes;DATABASE=myDB;ColumnEncryption=Enabled;KeyStoreAuthentication=KeyVaultPassword;KeyStorePrincipalId=
<username>;KeyStoreSecret=<password>";

Controlling 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:
Additional 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 13.1 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 ODBC Driver 13.1 for SQL Server 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_encryption analyzes the query statement to find out if any parameters need to be encrypted, and if so, returns the
encryption-related information for each that will allow the ODBC Driver 13.1 for SQL Server to encrypt parameter values. The above behavior
ensures a high-level of transparency to the client application. The application (and the application developer) does not need to be aware of which
queries access encrypted columns, as long as the values targeting encrypted columns are passed to the ODBC Driver 13.1 for SQL Server in
parameters.
Setting Always Encrypted on a Statement
To control performance impact of retrieving encryption metadata for parameterized queries, you can alter Always Encrypted behavior for
individual queries, after 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 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 on a statement, you need to set call SQLSetStmtAttr with and set the SQL_SOPT_SS_COLUMN_ENCRYPTION
flag to one of the following:

VALUE DESCRIPTION

SQL_CE_DISABLED (0) Always Encrypted is disabled for the statement

SQL_CE_RESULTSETONLY (1) Decryption Only. Resultsets and return values are decrypted, and parameters
are not encrypted

SQL_CE_ENABLED (3) Always Encrypted is enabled and used for both parameters and results

If most queries a client application sends over a database connection access encrypted columns:
Set the ColumnEncryption connection string keyword to Enabled .
Set the SQL_SOPT_SS_COLUMN_ENCRYPTION attribute to SQL_CE_DISABLED on statements that do not access any encrypted columns. This will
disable both calling sys.sp_describe_parameter_encryption as well as an attempt to decrypt any values in the result set.
Set the SQL_SOPT_SS_COLUMN_ENCRYPTION attribute to SQL_CE_RESULTSETONLY on statements that do not have any parameters requiring
encryption, but retrieve data from encrypted columns. This will disable calling sys.sp_describe_parameter_encryption and parameter
encryption. The query will be able to decrypt the results from encrypted columns.

Controlling behavior of Always Encrypted security settings


Force Column Encryption setting
Enforces encryption of a parameter when using Always Encrypted. If SQL Server informs the driver that the parameter does not need to be
encrypted, the query using the parameter will fail. This property provides additional protection against security attacks that involve a
compromised SQL Server providing incorrect encryption metadata to the client, which may lead to data disclosure.
To control this behavior in the driver, set the SQL_CA_SS_FORCE_ENCRYPT 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, 1, SQL_CA_SS_FORCE_ENCRYPT, (SQLPOINTER)TRUE, SQL_IS_SMALLINT);
Column encryption key caching
To reduce the number of calls to a column master key store to decrypt column encryption keys, the ODBC Driver 13.1 for SQL Server caches the
plaintext column encryption keys in memory. After receiving the encrypted column encryption key value from database metadata, the driver first
tries to find the plaintext column encryption key corresponding to the encrypted key value in the cache. The driver calls the key store containing
the column master key only if it cannot find the encrypted column encryption key value in the cache.
Note: In ODBC Driver 13.1 for SQL Server, the column encryption key entries in the cache are evicted after a two hour timeout. This means that
for a given encrypted column encryption key, the driver contacts the key store only once during the lifetime of the application or every two
hours, whichever is less.

Using custom Column Master Key stores with ODBC


From the ODBC client perspective, Column Encryption Keystore Provider interactions occur using Set and Get operations on two connection
attributes, and a separate CLI specifically for programmatic encryption. The two connection attributes are:
SQL_COPT_SS_CEKEYSTOREPROVIDER

SQL_COPT_SS_CEKEYSTOREDATA

The former is used to load and query 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 does not involve
communication with SQL Server.
The use of the encrypt CLI, EncryptCEK , which is used to allow application programmers to encrypt CEKs for storage in SQL Server, is described
in Custom Keystore Providers.
Loading a Column Encryption Keystore Provider for use with the ODBC driver
Setting the SQL_COPT_SS_CEKEYSTOREPROVIDER attribute
Setting the SQL_COPT_SS_CEKEYSTOREPROVIDER connection attribute enables a client application to load a CEKeyStoreProvider library, making
available for use the CEKeyStoreProviders contained therein.

SQLRETURN SQLSetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);

ARGUMENT DESCRIPTION

ConnectionHandle [Input] Connection handle. Must be a valid connection handle, but


CEKeyStoreProvders loaded via one connection handle are accessible from any
other as CEKeyStoreProviders are loaded per-driver.

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 CEKeyStoreProvider library. For SQLSetConnectAttrA, this is an ANSI
(multibyte) string. For SQLSetConnectAttrW, this is a Unicode (wchar_t) string.

StringLength [Input] The length of the ValuePtr string, or SQL_NTS.

The driver attempts to load the CEKeyStoreProvider library identified by the ValuePtr parameter using the platform-defined dynamic library
loading mechanism (dlopen() on *nix, LoadLibrary() on Windows), and adds any CEKeyStoreProviders defined therein to the list of
CEKeyStoreProviders known to the driver. The following errors may occur:

ERROR DESCRIPTION

CE203 The dynamic library could not be loaded.

CE203 The "CEKeyStoreProvider" exported symbol was not found in the library.

CE203 One or more CEKeyStoreProviders in the library are already loaded.

SQLSetConnectAttr returns the usual error or success values, and additional information is available for any errors which occurred via the
standard ODBC diagnostic mechanism.
NOTE: The application programmer must ensure that any custom CEKeyStoreProviders are registered before any query requiring them is sent
over any connection. Failure to do so results in the error:
ERROR DESCRIPTION

CE200 Keystore provider %1 not found. Ensure that the appropriate Keystore provider
library has been loaded.

NOTE: CEKeyStoreProvider 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 CEKeyStoreProviders. Using this term in the name of a custom CEKeyStoreProvider
will result in an ODBC warning.
Getting the SQL_COPT_SS_CEKEYSTOREPROVIDER attribute
Getting this connection attribute enables a client application to determine the CEKeyStoreProviders currently loaded in the driver.

SQLRETURN SQLGetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER BufferLength, SQLINTEGER *
StringLengthPtr);

ARGUMENT DESCRIPTION

ConnectionHandle [Input] Connection handle. Must be a valid connection handle, but


CEKeyStoreProviders loaded via one connection handle are accessible from any
other as CEKeyStoreProviders are loaded per-driver.

Attribute [Input] Attribute to retrieve: the SQL_COPT_SS_CEKEYSTOREPROVIDER constant.

ValuePtr [Output] A pointer to memory in which to return the next loaded


CEKeyStoreProvider 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 enable enumeration of multiple CEKeyStoreProviders, every Get operation returns the current CEKeyStoreProvider 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 next Get operation will then
retrieve the first CEKeyStoreProvider in the list, the one after that the next, etc.
Interacting with CEKeyStoreProvider implementations using ODBC
The SQL_COPT_SS_CEKEYSTOREDATA connection attribute enables a client application to communicate with loaded CEKeystoreProviders, for
establishing additional parameters, keying material, etc. The communication between a client application and a Column Encryption Keystore
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. See CONTEXTS section for more information
Column Encryption Keystore Provider data is communicated between the driver and application, in packet form, via the CEKeystoreData
structure:

typedef struct CEKeystoreData {


wchar_t *name;
unsigned int dataSize;
char data[];
} CEKEYSTOREDATA;

ARGUMENT DESCRIPTION

name [Input] Upon Set, the name of the Column Encryption Keystore 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.
ARGUMENT DESCRIPTION

data [InOut] Upon Set, the data to be sent to the Column Encryption Keystore
Provider. This may be arbitrary data as the driver makes no attempt to
interpret it. Upon Get, the buffer to receive the data read from the Column
Encryption Keystore Provider.

Setting data in a CEKeyStoreProvider via ODBC


A SQLSetConnectAttr call using the SQL_COPT_SS_CEKEYSTOREDATA attribute writes the "packet" of data to the specified Column Encryption Keystore
Provider.

SQLRETURN SQLSetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);

ARGUMENT DESCRIPTION

ConnectionHandle [Input] Connection handle. Must be a valid connection handle, but


CEKeystoreProviders loaded via one connection handle are accessible from any
other as CEKeyStoreProviders are loaded per-driver.

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 Column Encryption Keystore Provider to which the data is
intended.

StringLength [Input] SQL_IS_POINTER constant

Additional detailed error information may be obtained via SQLGetDiacRec. See SQLGetDiagRec for more information
NOTE: It is up to the provider to decide how to treat the CEKeystoreData. The two possible cases would be:
1. CEKeystoreData is connection specific.
2. CEKeystoreData is global.
Because the caller of SqlSetConnectAttr provides a valid connection handle, the provider can use that information and associate the
CEKeystoreData with the connection context. On the other hand, the provider can ignore it and make CEKeystoreData shared. See the Context
Management section the Custom Keystore topic for more information.
Getting data in a CEKeyStoreProvider via ODBC
Reading data from a CEKeyStoreProvider via ODBC's SQLGetConnectAttr function using the SQL_COPT_SS_CEKEYSTOREDATA attribute reads a
"packet" of data from the last-written-to Column Encryption Keystore Provider. If no Column Encryption Keystore Provider was written to, 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.
NOTE: This API is provided for ODBC parity. Application developers wishing to read configuration or other data from a CEKeyStoreProvider
should use the CLI.

SQLRETURN SQLGetConnectAttr( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER BufferLength, SQLINTEGER *
StringLengthPtr);

ARGUMENT DESCRIPTION

ConnectionHandle [Input] Connection handle. Must be a valid connection handle, but


CEKeystoreProviders loaded via one connection handle are accessible from any
other as they are loaded per-driver.

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 Column Encryption Keystore 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 Column Encryption
Keystore Provider to write into. Upon return, its dataSize field is updated with the actual length of data read from the Column Encryption
Keystore Provider. Additional detailed error information may be obtained via SQLGetDiacRec. See SQLGetDiagRec for more information
This specification places no additional requirements on the format of data transferred between an application and a Column Encryption Keystore
Provider. Each Column Encryption Keystore Provider is expected to define its own protocol per its needs.
For an example of implementing your own Column Encryption Keystore Provider, see Custom Keystore Providers

Limitations on ODBC when using Always Encrypted


Bulk Copy Function Usage
Use of the SQL Bulk Copy functions is not supported when using the ODBC driver with Always Encrypted. No transparent encryption/decryption
will occur on encrypted columns that are used with the SQL Bulk Copy functions.
Asynchronous Operations
While the ODBC driver will allow the use of asynchronous connections with Always Encrypted, there is 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 while metadata is retrieved from the server for Always Encrypted columns before returning
SQL_STILL_EXECUTING .

Always Encrypted API reference


ODBC Connection String as provided to SQLDriverConnect Function

NAME DESCRIPTION

ColumnEncryption Accepted values are Enabled / Disabled .


Enabled -- enables Always Encrypted functionality for the connection.
Disabled -- disable Always Encrypted functionality for the connection.

The default is Disabled .

KeyStoreAuthentication Valid Values: KeyVaultPassword , KeyVaultClientSecret

KeyStorePrincipalId When KeyStoreAuthentication = KeyVaultPassword , set this value to a


valid Azure Active Directory User Principle Name.
When KeyStoreAuthetication = KeyVaultClientSecret set this value to a
valid Azure Active Directory Application Client ID

KeyStoreSecret When KeyStoreAuthentication = KeyVaultPassword set this value to the


password for a valid Azure Active Directory User Principle Name.
When KeyStoreAuthentication = KeyVaultClientSecret set this value to
the Application Secret associated with a valid Azure Active Directory
Application Client ID

ODBC Connection Attributes as provided to SQLSetConnectAttr Function

NAME DESCRIPTION

SQL_COPT_SS_COLUMN_ENCRYPTION SQL_COLUMN_ENCRYPTION_DISABLE (0) -- Disable Always Encrypted


SQL_COLUMN_ENCRYPTION_ENABLE (1) -- Enable Always Encrypted

SQL_COPT_SS_CEKEYSTOREPROVIDER [Input] Pointer to a null-terminated character string specifying the filename of


the CEKeyStoreProvider library. For SQLSetConnectAttrA, this is an ANSI
(multibyte) string. For SQLSetConnectAttrW, this is a Unicode (wchar_t) string.

[Output] A pointer to a CEKeystoreData structure in which the data read from


the Column Encryption Keystore Provider is placed.

SQL_COPT_SS_CEKEYSTOREDATA [Input] Pointer to a CEKeystoreData structure. The name field of the structure
identifies the Column Encryption Keystore Provider to which the data is
intended.

[Output] A pointer to a CEKeystoreData structure in which the data read from


the Column Encryption Keystore Provider is placed.

ODBC Statement Attributes as provided to SQLSetStmtAttr Function


NAME DESCRIPTION

SQL_SOPT_SS_COLUMN_ENCRYPTION SQL_CE_DISABLED(0) -- Always Encrypted is disabled for the statement


SQL_CE_RESULTSETONLY (1) -- Decryption Only. Resultsets and return values
are decrypted, and parameters are not encrypted
SQL_CE_ENABLED (3) -- Always Encrypted is enabled and used for both
parameters and results

ODBC Parameter Descriptors as provided to SQLSetDescField Function

IPD FIELD SIZE/TYPE DEFAULT VALUE DESCRIPTION

SQL_CA_SS_FORCE_ENCRYPT (1236) WORD (2 bytes) 0 When 0 (default): decision to encrypt


this parameter is determined by
availability of encryption metadata.

When nonzero: if encryption


metadata is available for this
parameter, it is encrypted. Otherwise,
the request fails with error [CE300]
[Microsoft][ODBC Driver 13 for SQL
Server]Mandatory encryption was
specified for a parameter but no
encryption metadata was provided
by the server.

See Also
Always Encrypted (Database Engine)
Always Encrypted blog
Custom Keystore Providers
3/14/2017 • 17 min to read • Edit Online

Download ODBC Driver

Overview
The column encryption feature of SQL Server 2016 requires that the Encrypted Column Encryption Keys stored on
the server be retrieved by the client and then decrypted to Column Encryption Keys in order to access the data
stored in encrypted columns. Encrypted Column Encryption Keys are encrypted by Column Master Keys, and the
security of the Column Master Key is important to the security of column encryption. Thus, the Column Master Key
should be stored in a secure location; the purpose of a Column Encryption Key Store Provider is to provide an
interface to allow the ODBC driver to access these securely stored Column Master Keys. For users with their own
secure storage, the Custom Keystore Provider Interface provides a framework for implementing access to secure
storage of the Column Master Key for the ODBC driver, which can then be used to perform Column Encryption Key
encryption and decryption.
Each keystore provider contains and manages one or more Column Master Keys (CMKs), which are identified by
key paths - strings of a format defined by the provider. This, along with the encryption algorithm, can be used to
perform the encryption of a Column Encryption Key (CEK), and the decryption of an Encrypted Column Encryption
Key (ECEK). The algorithm, along with the ECEK and the name of the Keystore Provider are stored in the database's
encryption metadata. The operation of the ODBC driver can be fundamentally expressed as:

CEK = DecryptViaCEKeystoreProvider(CEKeystoreProvider_name, Key_path, Key_algorithm, Encrypted Column


Encryption Key)

-and-

ECEK = EncryptViaCEKeystoreProvider(CEKeyStoreProvider_name, Key_path, Key_algorithm, Column Encryption Key)

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
Encrypted Column Encryption Key. Multiple keystore providers may be present alongside the default built-in
provider(s). Upon performing an operation which requires the Column Encryption Key, the driver finds the
appropriate keystore provider and executes its decryption operation:

CEK = CEKeyStoreProvider_specific_decrypt(Key_path, Key_algorithm, ECEK)

-or-

ECEK = CEKeyStoreProvider_specific_encrypt(Key_path, Key_algorithm, CEK)

CEKeyStoreProvider interface
The rest of this document will describe in detail the CEKeyStoreProvider interface for developing custom key store
providers with error handling and context association. CEKeyStoreProvider implementers can use this guide to
develop their Custom Keystore Providers for the Microsoft ODBC Driver for Linux for SQL Server.
A keystore provider library is a dynamic-link library which can be loaded by the ODBC driver, and contains one or
more keystore providers. The symbol "CEKeystoreProvider" must be exported by a keystore 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;

FIELD NAME DESCRIPTION

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 The driver calls this function once, upon the first time the
keystore provider is used. Use this function to perform any
initialisation it needs. If an initialisation function is not
required, this field may be null.

Read Supports the application-provider communication interface,


allowing the application to read arbitrary data from the
CEKeyStoreProvider. May be null if not required. E.g., current
status, configuration, or authentication-related data as
implemented in the CEKeyStoreProvider such as retry
configuration, authentication mode, and token expiry, etc.

Write Supports the application-provider communication interface,


allowing the application to write arbitrary data to the keystore
provider. May be null if not required, but must be present if
Read is also required.

DecryptCEK The driver calls this function to decrypt an ECEK into a CEK.
This function is the reason for existence of a keystore
provider, and must not be null.
FIELD NAME DESCRIPTION

EncryptCEK Normal (data) driver operations never cause this function to


be called, so it may be null for a provider library intended to
only be used by the ODBC driver. It is provided for
CEKeyStoreProvider implementers to use to allow
programmatic access to ECEK creation through directly calling
it on their CEKSP implementation.

Free The driver may call this function upon normal termination of
the process. May be null if not required.

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.

ARGUMENT DESCRIPTION

ctx [Input] Opaque context pointer, to be passed to the error-


handling function.

onError [Input] Error-handling function. See "CEKeystoreProvider Error


Handling" for more information.

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.

ARGUMENT DESCRIPTION

ctx [Input] Opaque context pointer, to be passed to the error-


handling function.

onError [Input] Error-handling function. See "CEKeystoreProvider Error


Handling" for more information.

data [Output] Pointer to a buffer in which the provider writes data


to be read by the application. This corresponds to the data
field of the application-interface CEKEYSTOREDATA structure.

len [InOut] Pointer to a length value; upon input, this 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 actually written
to data.

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.

ARGUMENT DESCRIPTION

ctx [Input] Opaque context pointer, to be passed to the error-


handling function.

onError [Input] Error-handling function. See "CEKeystoreProvider Error


Handling" for more information.

data [Input] Pointer to a buffer containing the data for the provider
to read. This corresponds to the data field of the application-
interface CEKEYSTOREDATA structure. The provider must not
read more than len bytes from this buffer.

len [In] The number of bytes available in data. This corresponds to


the dataSize field of the application-interface
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 that has been identified as using this keystore provider.

ARGUMENT DESCRIPTION

ctx [Input] Opaque context pointer, to be passed to the error-


handling function.

onError [Input] Error-handling function. See "CEKeyStoreProvider Error


Handling" for more information.

keyPath [Input] The value of the key_path metadata attribute for the
CMK referenced by the given ECEK. Null-terminated wide-
character* string. This is intended to identify a CMK handled
by this provider.

alg [Input] The value of the encryption_algorithm_name metadata


attribute for the given ECEK. Null-terminated wide-character*
string. This 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.


ARGUMENT DESCRIPTION

cekOut [Output] The provider shall allocate memory for the decrypted
CEK and write its address to the pointer pointed to by
cekOut. It must be possible to free this block of memory
using the LocalFree 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 CEK that it has written to
**cekOut.

Return Value Return nonzero to indicate success, or zero to indicate failure.

NB: Wide-character strings are 2-byte characters (UTF-16) due to how SQL Server stores them.

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. It is provided to allow provider implementers to
expose programmatic key management to application developers. App developers must use the
CEKeyStoreProvider CLI functions to access this functionality, the driver does not call this function nor expose its
functionality through the ODBC interface described above.

ARGUMENT DESCRIPTION

ctx [Input] Opaque context pointer, to be passed to the error-


handling function.

onError [Input] Error-handling function. See "CEKeyStoreProvider Error


Handling" for more information.

keyPath [Input] The value of the key_path metadata attribute for the
CMK referenced by the given ECEK. Null-terminated wide-
character* string. This is intended to identify a CMK handled
by this provider.

alg [Input] The value of the encryption_algorithm_name metadata


attribute for the given ECEK. Null-terminated wide-character*
string. This is intended to identify the encryption algorithm
used to encrypt the given ECEK.

cek [Input] Pointer to the CEK to be decrypted.

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) function. If no
memory was allocated due to an error or otherwise, the
provider shall set *ecekOut to a null pointer.
ARGUMENT DESCRIPTION

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.

NB: Wide-character strings are 2-byte characters (UTF-16) due to how SQL Server stores them.
CEKeystoreProvider Error Handling
As errors may occur during a provider's processing, a mechanism is provided to allow CEKeyStoreProvider
implementations 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.
CEKEYSTORECONTEXT *ctx;

This is a set of 3 opaque pointers which the driver uses to determine the context of the operation in which the
error occurred, and can also be used to identify the context used for the operation. It must be passed unchanged to
the onError function in the same invocation of the function which caused the error.
typedef void errFunc(CEKEYSTORECONTEXT *ctx, const wchar_t *msg, …);

A pointer to a function of this type is passed into provider-implemented functions and called by the provider to
report when an error has occurred. The provider may call this function multiple times to post multiple error
messages consecutively within one provider-function invocation.

ARGUMENT DESCRIPTION

ctx [Input] The context parameter which was passed into the
provider-implemented function along with this function
pointer.

msg [Input] The error message to report. Null-terminated wide-


character string. To allow parameterized information to be
present, 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] Additional variadic parameters to fit format specifiers


in msg, as appropriate.

The msg parameter is ordinarily a wide-character string, but additional extensions are available:
By using one of the special predefined values with the IDS_MSG macro, generic error messages already existing
and in a localised form in the driver may be utilized. For example, a CEKeyStoreProvider may report a memory
allocation failure using the IDS_S1_001 "Memory allocation failure" message:;
onError(ctx, IDS_MSG(IDS_S1_001));

For a keystore provider function encountering an error to be recognized by the driver, it shall call the error-
callback function with the appropriate message and parameters as many times as necessary, then return failure.
When this is performed 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/SQLGetDiagField ).
CEKeystoreProvider 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 allows a provider to associate data to
each of these contexts, e.g. to implement per-connection configuration.

typedef struct CEKeystoreContext


{
void *envCtx;
void *dbcCtx;
void *stmtCtx;
} CEKEYSTORECONTEXT;

ARGUMENT DESCRIPTION

envCtx The opaque environment handle. It corresponds to, but is not,


the ODBC environment handle.

dbcCtx The opaque connection handle. It corresponds to, but is not,


the ODBC connection handle.

stmtCtx The opaque statement handle. It corresponds to, but is not,


the ODBC statement handle. If the operation being
accomplished is in the scope of a connection (e.g.
SQLSetConnectAttr calls to load and configure providers), this
field is null as there is no associated statement handle.

Example
Custom KeyStore Provider Implementation Sample
Keystore Provider

/* Custom Keystore Provider Example */

#include <stdlib.h>
#include <sqltypes.h>
#include <msodbcsql.h>
#include <sql.h>
#include <sqlext.h>

int KeystoreInit(CEKEYSTORECONTEXT *ctx, errFunc *onError) {


printf("KSP Init() function called\n");
return 1;
}

static unsigned char *g_encryptKey;


static unsigned int g_encryptKeyLen;

int 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 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 initialised with key");
return 0;
}
*cekOut = malloc(ecekLen);
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 proposed 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.)
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 initialised with key");
return 0;
}
*ecekOut = malloc(cekLen);
if (!*ecekOut) {
onError(ctx, L"Memory Allocation Error");
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
};

CEKEYSTOREPROVIDER *CEKeystoreProvider[] = {
&MyCustomKSPName_desc,
0
};
Using the Custom Keystore Provider with ODBC

/*
Example application for demonstration of custom keystore provider usage

usage: kspapp connstr

*/

#define PROV_ENCRYPT_KEY "JHKCWYT06N3RG98J0MBLG4E3"

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <sqltypes.h>
#include <msodbcsql.h>
#include <sql.h>
#include <sqlext.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) {
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;
void* hProvLib;
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 */


if (!(hProvLib = dlopen("MyKSP.so", RTLD_LAZY))) {
fprintf(stderr, "Error loading KSP library\n");
return 2;
}

/* Check that the loaded library contains the CEKeyStoreProvider entry point */
if (!(ppKsp = (CEKEYSTOREPROVIDER**)GetProcAddress(hProvLib, "CEKeystoreProvider"))) {
fprintf(stderr, "The export CEKeystoreProvider was not found in the KSP library\n");
return 3;
}

/* Iterate the CEKeyStoreProviders in the library, looking for the custom one MyCustomKSPName */
bool foundProv = false;
while (pKsp = *ppKsp++) {
if (!wcscmp(L"MyCustomKSPName", pKsp->Name)){
foundProv = true;
break;
}
}

if (!foundProv) {
fprintf(stderr, "Could not find provider in the library\n");
return 4;
}

/* Initialize Provider */
if (pKsp->Init && !pKsp->Init(&ctx, postKspError)) {
fprintf(stderr, "Could not initialise provider\n");
return 5;
}

/* Determine Provider capabilities */


if (!(pEncryptCEK = (void*)GetProcAddress(hProvLib, "KeystoreEncrypt"))) {
fprintf(stderr, "The export KeystoreEncrypt was not found in the KSP library\n");
return 6;
}
if (!pKsp->Write) {
fprintf(stderr, "Sample Custom 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);
free(ECEK);
}

FreeLibrary(hProvLib);

/* 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);
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREPROVIDER, "MyKSP.dll", SQL_NTS);
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);
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;
}
Connecting with sqlcmd
3/14/2017 • 5 min to read • Edit Online

Download ODBC Driver


The sqlcmd utility is available in the Microsoft ODBC Driver for SQL Server on Linux.
The following commands show first how to use Windows Authentication and second, how to use SQL Server
Authentication.

sqlcmd –E –Sxxx.xxx.xxx.xxx
sqlcmd –Sxxx.xxx.xxx.xxx –Uxxx -Pxxx

sqlcmd Options that are Available


In the current release, the following sqlcmd options are available:
-?
Display sqlcmd usage.
-a
Request a packet size.
-b
Terminate batch job if there is 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 topic.
-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 client:
Native LDAP, native Kerberos, and Windows Server 2003 R2 AD Services and schema for cross platform
identity management
Authenticate Linux Clients with Active Directory
Linux Creating or Adding New Network Alias To a Network Card (NIC)
-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.
-Kapplication_intent
Declares the application workload type when connecting to a server. The only currently supported value is
ReadOnly. If -K is not specified, sqlcmd does not support connectivity to a secondary replica in an AlwaysOn
availability group. For more information, see ODBC Driver on Linux Support for High Availability, Disaster
Recovery.

NOTE
-K is not 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 topic.

-l
Specify the number of seconds before a sqlcmd login to the ODBC driver times out when you try to connect to a
server.
-m error_level
Control which error messages are sent to stdout.
-Mmultisubnet_failover
Always specify -M when connecting to the availability group listener of a SQL Server 2012 availability group or a
SQL Server 2012 Failover Cluster Instance. -M provides for faster detection of and connection to the (currently)
active server. If –M is not specified, -M is off. For more information about AlwaysOn Availability Groups, see ODBC
Driver on Linux Support for High Availability, Disaster Recovery.

NOTE
-M is not 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 topic.

-N
Encrypt connection.
-o output_file
Identify the file that receives output from sqlcmd.
-p
Print performance statistics for every result set.
-P
Specify a user password.
-q commandline_query
Execute a query when sqlcmd starts, but does not exit sqlcmd 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 which to connect. Or, if -D is used, a DSN. The ODBC driver on Linux requires
-S. For the ODBC driver on Linux, tcp is the only valid protocol.
-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, regardless of 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.
In the current release, the following sqlcmd commands are available:
[:]!!
:Connect
:Error
[:]EXIT
GO [count]
:Help
:List
:Listvar
:On Error
:Out
:Perftrace
[:]QUIT
:r
:RESET
:setvar

sqlcmd Options that are Not Available


In the current release, the following sqlcmd options are not 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.
-f code_page
Specify the input and output code pages.
-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 will help you use a
parameter file to replace the values. Create a file called a.sql (the parameter file) with the following content:

:setvar ColumnName object_id


:setvar TableName sys.objects

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:
slqcmd -S<…> -P<..> –U<..> -I c.sql
-z password
Change password.
-Z password
Change password and exit.
In the current release, the following sqlcmd commands are not available:
:ED
:ServerList
: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 the -S option to retrieve the specified DSN. sqlcmd or bcp
connect to the server specified in the DSN.
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).
The following entries are supported in a DSN on Linux:
ApplicationIntent=ReadOnly
Database=database_name
Driver=ODBC Driver 11 for SQL Server
MultiSubnetFailover=Yes
Server=server_name_or_IP_address
Trusted_Connection=yes|no
In a DSN, only the DRIVER entry is required, but to connect to a server, sqlcmd or bcp need the value in the
SERVER entry.
If the same option is specified in both the DSN and the sqlcmd or bcp command line, the sqlcmd or bcp 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, is ignored.
Existing scripts that invoke isql can be modified to use sqlcmd by defining the following alias: alias isql="sqlcmd
–D".

See Also
Microsoft ODBC Driver for SQL Server on Linux
Connecting with bcp
3/14/2017 • 3 min to read • Edit Online

Download ODBC Driver


The bcp utility is available in the Microsoft ODBC Driver for SQL Server on Linux.
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 do not 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 is a sample 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

bcp Options That are Available


In the current release, the following bcp 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 cannot 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.
-k
Specifies that empty columns should retain 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 bcp login to SQL Server times out
when you try to connect to a server. The default bcp time-out for login to SQL Server is 15 seconds. The login time-
out must be a number between 0 and 65534. If the value supplied is not numeric or does not fall into that range,
bcp generates an error message. A value of 0 specifies time-out to be infinite.
-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 cancelled.
-n
Uses the native (database) data types of the data to perform the bulk-copy operation.
-P password
Specifies the password for the login ID.
-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 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 perform the bulk copy operation.
In this release, Latin-1 and UTF-16 characters are supported.
bcp Options That are Not Available
In the current release, the following bcp syntax and options are not 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
Microsoft ODBC Driver for SQL Server on Linux
Data Access Tracing with the ODBC Driver on Linux
3/14/2017 • 1 min to read • Edit Online

Download ODBC Driver


The ODBC Driver for SQL Server on Linux supports tracing of ODBC API call entry and exit.
To trace your application behavior, first add the following line to the odbcinst.ini file:

Trace=Yes

Then start your application with strace. For example:

strace -t -f -o trace_out.txt executable

After you finish tracing your application, remove Trace=Yes from the odbcinst.ini file to avoid the performance
penalty of tracing.
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 by providing it 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 11 for SQL Server] section of
/home/myappuser/odbcinst.ini.

Determining Which odbc.ini File The Driver Is Using


The Linux ODBC Driver does not know which odbc.ini is in use, or the path to the odbc.ini file. However,
information about which odbc.ini file is in use is available, from the unixODBC tools odbc_config and odbcinst, and
from the unixODBC Driver Manager documentation.
For example, the following command prints (among other information) the location of system and user odbc.ini
files that may contain, respectively, system and user 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

The unixODBC documentation explains how the user vs. system DSN decision is made. Specifically:
User DSN. These are your personal Data Sources. You are able to add new ones, remove existing ones, and
configure existing ones. User DSN information is stored in a secret location where only you can access them.
Keeping your User DSNs separate from other User DSNs allows you a great deal of flexibility and control over
creating and working with data sources which are only important to you.
System DSN. These are created by the System Administrator. They act very much like the User DSNs but with three
important differences:
Only the System Administrator can add, remove, and configure System DSNs.
System DSNs will be used only if the DSN does not exist as a User DSN. In other words, your User DSN has
precedence over the System DSN.
Everyone shares the same list of System DSNs.
3/14/2017 • 3 min to read • Edit Online

s--- title: "Programming Guidelines | Microsoft Docs" ms.custom: "" ms.date: "01/19/2017" ms.prod: "sql-non-
specified" ms.reviewer: "" ms.suite: "" ms.technology:
"drivers" ms.tgt_pltfrm: "" ms.topic: "article" ms.assetid: 0cc8686c-e27b-4963-b674-dc420fcbd3d2
caps.latest.revision: 39 author: "MightyPen" ms.author: "genemi"

manager: "jhubbard"
Programming Guidelines
Download ODBC Driver
The programming features of the Microsoft ODBC Driver 11 for SQL Server on 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).

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 CTP for SUSE Linux, the file name is msodbcsql-11.0.2260.0.tar.gz.

An ODBC application can use Multiple Active Result Sets (MARS) and other SQL Server specific features by
including /opt/microsoft/msodbcsql/11.0.2270.0/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 in your Windows ODBC applications.

Available Features
The following sections in from the SQL Server Native Client documentation for ODBC (SQL Server Native Client
(ODBC)) are valid when using the ODBC driver on 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)
SSL encryption
UTF-8 and UTF-16 for command and data API
Using Catalog Functions

Features That Are Not Available


The following features are not available in this release of the ODBC driver on Linux:
bulk copy functions (bcp_batch, for example)
distributed transactions (SQL_ATTR_ENLIST_IN_DTC attribute is not supported)
database mirroring
FILESTREAM
profiling ODBC driver performance, discussed in SQLSetConnectAttr, 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
table-valued parameters (TVPs)
C interval types such as SQL_C_INTERVAL_YEAR_TO_MONTH (documented in Data Type Identifiers and
Descriptors) are not currently supported.
Not supported: the SQL_CUR_USE_ODBC value of the SQL_ATTR_ODBC_CURSORS attribute of the
SQLSetConnectAttr function.

Character Support
SQLCHAR data must be UTF-8. SQLWCHAR data must be UTF-16LE (Little Endian).
If SQLDescribeParameter does not specify a SQL type on the server, the driver uses the SQL type specified in the
ParameterType parameter of SQLBindParameter. If a narrow character SQL type, such as SQL_VARCHAR, is
specified in SQLBindParameter, the driver converts the supplied UTF-8 data to the default SQL Server code page.
(The default SQL Server code page is typically 1252.) However, data loss is possible. If code page 1252 cannot
represent a character, the driver converts the character to a question mark ('?'). To avoid this data loss, specify a
Unicode SQL character type, such as SQL_NVARCHAR, in SQLBindParameter. In this case, the driver converts the
supplied Unicode data in UTF-8 encoding to UTF-16 without loss of precision.
There is a text-encoding conversion difference between Windows and the iconv library on Linux. Text data that is
encoded in codepage 1255 (Hebrew) has one code point (0xCA) that behaves differently on the two platforms.
Converting to Unicode on Windows produces a UTF-16 code point of 0x05BA. Converting to Unicode on Linux
produces a UTF-16 code point of 0x00CA. Code point 0xCA in codepage 1255 is not defined to be a character. An
application should not include logic that uses the (undefined) code point 0xCA.
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 do not end in partial character encodings.

Other Issues
1. You can make a dedicated administrator connection (DAC) using SQL Server authentication and host,port.
A member of the Sysadmin role first needs to discover the DAC port. 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

2. The UnixODBC driver manager returns "invalid attribute/option identifier" for all statement attributes when
they are passed through SQLSetConnectAttr. On Windows, when SQLSetConnectAttr receives a statement
attribute value, it causes the driver to set that value on all active statements that are children of the
connection handle.

NOTE
DAC connections must use SQL Server Authentication.

See Also
Microsoft ODBC Driver for SQL Server on Linux
Frequently Asked Questions (FAQ) for ODBC Linux
3/14/2017 • 1 min to read • Edit Online

Download ODBC Driver


The following are answers to questions about the ODBC Driver for SQL Server on Linux.

Frequently Asked Questions


How do existing ODBC applications on Linux work with the driver?
You should be able to compile and run the ODBC applications that you have been compiling and running on Linux
using other drivers.
Which features of SQL Server 2012 does this version of the driver support? The ODBC driver on Linux
supports all server features in SQL Server 2012 except LocalDB. For more information about SQL Server supported
features, see Programming Guidelines.
Does the driver support Kerberos authentication?
Yes, for more information, see Using Integrated Authentication.
Which Unicode encoding should an application use?
UTF-8 for SQL_CHAR data and UTF-16 for SQL_WCHAR data.
Are there ODBC samples that I can download and run with the driver to experiment with it or evaluate it?
See Use Existing MSDN C++ ODBC Samples for the ODBC Driver on Linux for a sample.
Is the ODBC driver on Linux open source?
No, the ODBC driver on Linux is not an open source product.

You might also like