master
go 102 lines 2.47 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 //go:build !windows && cgo
4
5 package odbcwrapper
6
7 /*
8 // Force use of system unixODBC headers, not IBM headers
9 #cgo CFLAGS: -I/usr/include -DSQL_NOUNICODEMAP
10 #cgo LDFLAGS: -lodbc
11
12 // Include system unixODBC headers explicitly
13 #include "/usr/include/sql.h"
14 #include "/usr/include/sqlext.h"
15 #include <stdlib.h>
16 #include <string.h>
17
18 // Simple ODBC wrapper functions
19 SQLRETURN simple_alloc_env(SQLHENV *env) {
20 return SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, env);
21 }
22
23 SQLRETURN simple_set_version(SQLHENV env) {
24 return SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
25 }
26
27 SQLRETURN simple_data_sources(SQLHENV env, SQLUSMALLINT direction, char *dsn, SQLSMALLINT dsn_len, SQLSMALLINT *dsn_ret, char *desc, SQLSMALLINT desc_len, SQLSMALLINT *desc_ret) {
28 return SQLDataSources(env, direction, (SQLCHAR*)dsn, dsn_len, dsn_ret, (SQLCHAR*)desc, desc_len, desc_ret);
29 }
30
31 void simple_free_env(SQLHENV env) {
32 SQLFreeHandle(SQL_HANDLE_ENV, env);
33 }
34 */
35 import "C"
36
37 import (
38 "database/sql"
39 "database/sql/driver"
40 "fmt"
41 "unsafe"
42 )
43
44 // Simple ODBC driver implementation
45 type odbcDriver struct{}
46
47 func (d *odbcDriver) Open(dsn string) (driver.Conn, error) {
48 return nil, fmt.Errorf("ODBC connections via DSN: %s (custom wrapper not implemented - use github.com/alexbrainman/odbc)", dsn)
49 }
50
51 func init() {
52 sql.Register("odbc", &odbcDriver{})
53 }
54
55 // Drivers returns available ODBC data sources
56 func Drivers() ([]string, error) {
57 var env C.SQLHENV
58
59 // Allocate environment handle
60 if ret := C.simple_alloc_env(&env); ret != C.SQL_SUCCESS {
61 return nil, fmt.Errorf("failed to allocate environment handle")
62 }
63 defer C.simple_free_env(env)
64
65 // Set ODBC version
66 if ret := C.simple_set_version(env); ret != C.SQL_SUCCESS {
67 return nil, fmt.Errorf("failed to set ODBC version")
68 }
69
70 var drivers []string
71 direction := C.SQL_FETCH_FIRST
72
73 for {
74 var dsn [256]C.char
75 var dsnLen C.SQLSMALLINT
76 var desc [256]C.char
77 var descLen C.SQLSMALLINT
78
79 ret := C.simple_data_sources(env, C.SQLUSMALLINT(direction),
80 &dsn[0], C.SQLSMALLINT(len(dsn)), &dsnLen,
81 &desc[0], C.SQLSMALLINT(len(desc)), &descLen)
82
83 if ret == C.SQL_NO_DATA {
84 break
85 }
86
87 if ret != C.SQL_SUCCESS {
88 break
89 }
90
91 driverName := C.GoString((*C.char)(unsafe.Pointer(&dsn[0])))
92 drivers = append(drivers, driverName)
93 direction = C.SQL_FETCH_NEXT
94 }
95
96 return drivers, nil
97 }
98
99 // Open wraps sql.Open for ODBC connections
100 func Open(dsn string) (*sql.DB, error) {
101 return sql.Open("odbc", dsn)
102 }