Что нужно для доступа к базе MS SQL из проекта Go
Нужно установить unixODBC и SQL Driver.
А потом проверить что все работает.
Тут описана процедура, позволившая работать с MS SQL 2008 R2.
unixODBC
Нужно обновить unixODBC.
Удаляем старую версию unixODBC.
sudo apt-get remove libodbc1 unixodbc unixodbc-dev
Скачиваем текущую, не ниже 2.3.1:
wget ftp://ftp.unixodbc.org/pub/unixODBC/unixODBC-2.3.2.tar.gz
Распаковываем:
tar xf unixODBC-2.3.2.tar.gz
Конфигурируем и устанавливаем:
cd unixODBC-2.3.2 ./configure --disable-gui --disable-drivers --enable-iconv --with-iconv-char-enc=UTF8 --with-iconv-ucode-enc=UTF16LE make sudo make install sudo ldconfig
SQL Driver
Есть два варианта SQL-драйверов - FreeTDS и MS SQL.
Будем использовать FreeTDS.
Скачиваем и распаковываем:
wget ftp://ftp.astron.com/pub/freetds/stable/freetds-stable.tgz tar xf freetds-stable.tgz
Компилируем и устанавливаем:
cd freetds-0.91/ ./configure #Optionally specify TDS version here with --with-tdsver=VER make sudo make install
ВНИМАНИЕ! Важно помнить, что по-умолчанию, конфигурационные файлы odbcinst.ini, odbc.ini и freetds.conf лежат в папке /usr/local/etc, а библиотеки драйверов в /usr/local/lib/. Текущие параметры настройки можно посмотреть с помощью команды:
tsql -C
Теперь оповестим ODBC о существовании драйвера.
Для этого создадим текстовый файлик tds.driver.template такого содержания:
[FreeTDS] Description = Open source FreeTDS driver Driver =/usr/local/lib/libtdsodbc.so
А затем выполним:
sudo odbcinst -i -d -f tds.driver.template odbcinst: Driver installed. Usage count increased to 1. Target directory is /usr/local/etc
Информация о драйвере баз данных пропишется в /usr/local/etc/odbcinst.ini в том же виде, что записано в файле tds.driver.template. В квадратных скобках - имя драйвера, которое можно использовать в дальнейшем.
Теперь можно прописать параметры сервера MS-SQL в конец конфигурационного файлика /usr/local/etc/freetds.conf:
[ms-sql] host = 192.168.122.145 port = 1433 tds version = auto instance = MSSQLSERVER
В начале секции указывается имя сервера, которое потом можно использовать для проверки, например в утилите tsql. Затем - хост (имя или IP), порт (можно не указывать. по умолчанию - 1433), версия tds (при значении auto перебираются разные версии) и имя инстанса MS SQL.
Более подробная информация тут: http://www.freetds.org/userguide/freetdsconf.htm
Теперь можно прописать DSN (DataSourceName). Они прописываются в файле /usr/local/etc/odbc.ini:
[freetds-test] Driver = /usr/local/lib/libtdsodbc.so Servername = ms-sql Port = 1433 Database = test TDS_Version = 8.0
В квадратных скобках - имя DSN, которое используется при обращении к нему. Затем указывается используемый драйвер (путь к файлу драйвера или имя записи из /usr/local/etc/odbcinst.ini), Servername - это имя сервера из /usr/local/etc/freetds.conf, Database - имя базы данных.
Проверяем что все работает
Во-первых смотрим текущую конфигурацию ODBC:
$ odbcinst -j
Вывод будет примерно таким:
unixODBC 2.3.2 DRIVERS............: /usr/local/etc/odbcinst.ini SYSTEM DATA SOURCES: /usr/local/etc/odbc.ini FILE DATA SOURCES..: /usr/local/etc/ODBCDataSources USER DATA SOURCES..: /home/user/.odbc.ini SQLULEN Size.......: 8 SQLLEN Size........: 8 SQLSETPOSIROW Size.: 8
И драйвера баз данных - FreeTDS:
$ tsql -C Compile-time settings (established with the "configure" script) Version: freetds v0.91 freetds.conf directory: /usr/local/etc MS db-lib source compatibility: no Sybase binary compatibility: no Thread safety: yes iconv library: yes TDS version: 5.0 iODBC: no unixodbc: yes SSPI "trusted" logins: no Kerberos: no
Дальше можем проверить что мы можем подключиться к базе как по IP адресу (имени хоста) из /usr/local/etc/freetds.conf:
$ isql freetds-test sa 1qaz@WSX +---------------------------------------+ | Connected! | | | | sql-statement | | help [tablename] | | quit | | | +---------------------------------------+ SQL>
Тут последовательно указывается ServerName, Username, Password.
Так и с помощью DSN из /usr/local/etc/odbc.ini:
$ tsql -H ms-sql -p 1433 -U sa -P 1qaz@WSX -D test locale is "en_US.UTF-8" locale charset is "UTF-8" using default charset "UTF-8" Default database being set to test 1>
Тут можно указывать как имя DSN, так и IP-адрес сервера.
Важно! Если сервер отвечает что:
Error 20017 (severity 9): Unexpected EOF from the server OS error 115, "Operation now in progress" Error 20002 (severity 9): Adaptive Server connection failed There was a problem connecting to the server
Это означает несоответствие версии TDS, используемой при подключении и версии TDS, поддерживаемой сервером SQL.
Лечится это указанием версии протокола в файле /usr/local/etc/freetds.conf:
[global] # TDS protocol version tds version = 8.0
Проверка работоспособности из Go
Переходим в директорию с исходниками и пакетами Go и получаем пакет для работы с SQL:
cd ~/go/src go get code.google.com/p/odbc
По умолчанию, в этом пакете в тестах пропиcано использование драйвера freetds.
Затем можно попытаться запустить тесты:
go test -mssrv=SERVERNAME.COM -msdb=DATABASENAME -msuser=USERNAME -mspass=YOURPASSWORD -v -run=MS
тут -mssrv - это имя хоста или IP-адрес. Остальное понятно что.
Но сокрее всего тесты не пройдут и везде будет FAIL. Причина - несоотвествие версии TDS.
Для исправления этой неприятности нужно отредактировать файлик ./mssql_test.go.
Там нужно найти такой кусочек:
func mssqlConnect() (db *sql.DB, stmtCount int, err error) { params := map[string]string{ "driver": *msdriver, "server": *mssrv, "database": *msdb, } if isFreeTDS() { params["uid"] = *msuser params["pwd"] = *mspass params["port"] = *msport params["TDS_Version"] = "8.0"
И добавить туда в конце строчку:
params[["TDS_Version"]] = "8.0"**
В результате выполнения тестов должно быть так:
$ /usr/local/go/bin/go test -mssrv=192.168.122.145 -msport=1433 -msdriver=freetds -msdb=test -msuser=sa -mspass=1qaz@WSX -v -run=MS === RUN TestMSSQLCreateInsertDelete --- PASS: TestMSSQLCreateInsertDelete (0.08s) === RUN TestMSSQLTransactions --- PASS: TestMSSQLTransactions (0.14s) === RUN TestMSSQLTypes --- PASS: TestMSSQLTypes (0.09s) === RUN TestMSSQLIntAfterText --- PASS: TestMSSQLIntAfterText (0.01s) === RUN TestMSSQLStmtAndRows --- PASS: TestMSSQLStmtAndRows (0.15s) === RUN TestMSSQLIssue5 --- PASS: TestMSSQLIssue5 (0.19s) === RUN TestMSSQLDeleteNonExistent --- PASS: TestMSSQLDeleteNonExistent (0.06s) === RUN TestMSSQLDatetime2Param --- SKIP: TestMSSQLDatetime2Param (0.01s) mssql_test.go:1006: skipping test; needs MS SQL Server 2008 or later === RUN TestMSSQLMerge --- SKIP: TestMSSQLMerge (0.00s) mssql_test.go:1038: skipping test; needs MS SQL Server 2008 or later === RUN TestMSSQLSelectInt --- PASS: TestMSSQLSelectInt (0.00s) === RUN TestMSSQLTextColumnParam --- PASS: TestMSSQLTextColumnParam (0.48s) === RUN TestMSSQLTextColumnParamTypes --- PASS: TestMSSQLTextColumnParamTypes (0.29s) === RUN TestMSSQLLongColumnNames --- PASS: TestMSSQLLongColumnNames (0.00s) === RUN TestMSSQLRawBytes --- PASS: TestMSSQLRawBytes (0.02s) === RUN TestMSSQLUTF16ToUTF8 --- PASS: TestMSSQLUTF16ToUTF8 (0.00s) === RUN TestMSSQLExecStoredProcedure --- PASS: TestMSSQLExecStoredProcedure (0.02s) === RUN TestMSSQLSingleCharParam --- PASS: TestMSSQLSingleCharParam (0.02s) PASS ok code.google.com/p/odbc 1.565s
Пример кода на Go lang, получающего данные из базы MS-SQL
Вот кусочек кода, который читает из таблицы строки и выводит их на экран.
package main import ( _ "code.google.com/p/odbc" "database/sql" "fmt" "log" ) var ( title string content string query string ) func main() { db, err := sql.Open("odbc", "DRIVER=FreeTDS;SERVER=x.x.x.x;UID=sa;PWD=YourPassword;DATABASE=DbName;TDS_Version=8.0;PORT=1433;") if err != nil { fmt.Println("Error in connect DB") log.Fatal(err) } query = "select Content from dbo.PageContent where Revision = -1" rows, err := db.Query(query) if err != nil { log.Fatal(err) } for rows.Next() { if err := rows.Scan(&content); err != nil { log.Fatal(err) } fmt.Println(content) } defer rows.Close() }
В документации написано, что в sql.Open передаются пара параметров - имя драйвера и строка подключения.
Так вот на первый взгляд непонятно - что именно является именем драйвера и что должно входить в строку подключения.
В нашем случае - драйвер odbc.
А в качестве строки подключения документация предлагает указывать имя DSN, который прописан в /usr/local/etc/odbc.ini. Примерно так: “DSN=dsn_name”.
В такой конфигурации я неизменно получал ошибку:
SQLDriverConnect: {08001} [unixODBC][FreeTDS][SQL Server]Unable to connect to data source {01000} [unixODBC][FreeTDS][SQL Server]Adaptive Server connection failed exit status 1
То есть соединение начинало устанавливаться, выбирался правильный драйвер, указанный в odbc.ini, но в логах было:
detected flag 2 login packet rejected
Тут еще надо разобраться.
Но при этом все нормально подключалось, когда в качестве connection string передается строка с параметрами, а не имя DSN:
db, err := sql.Open("odbc", "DRIVER=FreeTDS;SERVER=x.x.x.x;UID=sa;PWD=YourPassword;DATABASE=DbName;TDS_Version=8.0;PORT=1433;")
Тут:
DRIVER=FreeTDS - имя драйвера из freetds.conf
SERVER= - DNS-имя или IP-адрес сервера
UID и PWD - имя и пароль пользователя
Discussion