Что нужно для доступа к базе 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 - имя и пароль пользователя

Enter your comment. Wiki syntax is allowed:
 
  • linux_faq/настроика-доступа-к-базе-ms-sql-из-проекта-на-go-lang.txt
  • Last modified: 2019/02/11 09:13
  • by 127.0.0.1