// Next is called to populate the next row of data into the provided slice func (rows *rows) Next(dest []driver.Value) error { //If this is the first time rows has been read, setup necessary field level information if rows.isBeforeFirst { for index, resultColumnDef := range rows.resultColumnDefs { //Set precision and scale for numeric fields if resultColumnDef.DataType == odbc.SQL_NUMERIC || resultColumnDef.DataType == odbc.SQL_DECIMAL { colIndex := odbc.SQLSMALLINT(index + 1) odbc.SQLSetDescField(rows.descHandle, colIndex, odbc.SQL_DESC_TYPE, uintptr(odbc.SQL_C_NUMERIC), 0) odbc.SQLSetDescField(rows.descHandle, colIndex, odbc.SQL_DESC_PRECISION, uintptr(resultColumnDef.Precision), 0) odbc.SQLSetDescField(rows.descHandle, colIndex, odbc.SQL_DESC_SCALE, uintptr(resultColumnDef.Scale), 0) } } //Update isBeforeFirst rows.isBeforeFirst = false } //Fetch a row of data ret := odbc.SQLFetch(rows.handle) if ret == odbc.SQL_NO_DATA { //No more data to read return io.EOF } else if isError(ret) { return errorStatement(rows.handle, rows.sqlStmt) } //Get a row of data err := rows.getRow(dest) if err != nil { return err } return nil }
func (stmt *statement) bindDate(index int, value time.Time, direction ParameterDirection) error { var bindVal odbc.SQL_DATE_STRUCT bindVal.Year = odbc.SQLSMALLINT(value.Year()) bindVal.Month = odbc.SQLUSMALLINT(value.Month()) bindVal.Day = odbc.SQLUSMALLINT(value.Day()) stmt.bindValues[index] = &bindVal ret := odbc.SQLBindParameter(stmt.handle, odbc.SQLUSMALLINT(index), direction.SQLBindParameterType(), odbc.SQL_C_DATE, odbc.SQL_DATE, 10, 0, odbc.SQLPOINTER(unsafe.Pointer(stmt.bindValues[index].(*odbc.SQL_DATE_STRUCT))), 6, nil) if isError(ret) { return errorStatement(stmt.handle, fmt.Sprintf("Bind index: %v, Value: %v", index, bindVal)) } return nil }
func handleError(handleType odbc.SQLSMALLINT, handle odbc.SQLHandle, driverInfo string) error { statusRecords := make([]StatusRecord, 0) if handle != 0 { for recNum := 1; ; recNum++ { sqlState := make([]uint16, sqlStateLength+1) var nativeError odbc.SQLINTEGER message := make([]uint16, errorMaxMessageLength+1) ret := odbc.SQLGetDiagRec(handleType, handle, odbc.SQLSMALLINT(recNum), uintptr(unsafe.Pointer(&sqlState[0])), &nativeError, uintptr(unsafe.Pointer(&message[0])), errorMaxMessageLength, nil) if ret == odbc.SQL_NO_DATA { break } else if !isError(ret) { sr := StatusRecord{State: syscall.UTF16ToString(sqlState), NativeError: int(nativeError), Message: syscall.UTF16ToString(message), DriverInfo: driverInfo} statusRecords = append(statusRecords, sr) } else { break } } } return &ODBCError{StatusRecords: statusRecords} }
// Returns a new connection to the database func (d *lodbcDriver) Open(name string) (driver.Conn, error) { // Allocate the connection handle var connHandle odbc.SQLHandle ret := odbc.SQLAllocHandle(odbc.SQL_HANDLE_DBC, envHandle, &connHandle) if isError(ret) { return nil, errorEnvironment(envHandle) } // Establish the connection with the database nameSqlPtr := (*odbc.SQLCHAR)(unsafe.Pointer(syscall.StringToUTF16Ptr(name))) ret = odbc.SQLDriverConnect(connHandle, 0, nameSqlPtr, odbc.SQLSMALLINT(odbc.SQL_NTS), nil, 0, nil, odbc.SQL_DRIVER_NOPROMPT) if isError(ret) { return nil, errorConnection(connHandle) } // Create new connection var conn = &connection{handle: connHandle, isTransactionActive: false, statements: make(map[driver.Stmt]bool, 0)} //Add a finalizer runtime.SetFinalizer(conn, (*connection).Close) return conn, nil }
// Build metadata for each result column func buildResultColumnDefinitions(stmtHandle odbc.SQLHandle, sqlStmt string) ([]resultColumnDef, odbc.SQLReturn) { //Get number of result columns var numColumns odbc.SQLSMALLINT ret := odbc.SQLNumResultCols(stmtHandle, &numColumns) if isError(ret) { errorStatement(stmtHandle, sqlStmt) } resultColumnDefs := make([]resultColumnDef, 0, numColumns) for colNum, lNumColumns := odbc.SQLSMALLINT(1), numColumns; colNum <= lNumColumns; colNum++ { //Get odbc.SQL type var sqlType odbc.SQLLEN ret := odbc.SQLColAttribute(stmtHandle, odbc.SQLUSMALLINT(colNum), odbc.SQL_COLUMN_TYPE, 0, 0, nil, &sqlType) if isError(ret) { errorStatement(stmtHandle, sqlStmt) } /* Disabled because it is no longer needed //Get length var length odbc.SQLLEN ret = odbc.SQLColAttribute(stmtHandle, odbc.SQLUSMALLINT(colNum), odbc.SQL_COLUMN_LENGTH, 0, 0, nil, &length) if isError(ret) { errorStatement(stmtHandle, sqlStmt) } //If the type is a CHAR or VARCHAR, add 4 to the length if odbc.SQLDataType(sqlType) == odbc.SQL_CHAR || odbc.SQLDataType(sqlType) == odbc.SQL_VARCHAR || odbc.SQLDataType(sqlType) == odbc.SQL_WCHAR || odbc.SQLDataType(sqlType) == odbc.SQL_WVARCHAR { length = length + 4 } */ //Get name const namelength = 1000 nameArr := make([]uint16, namelength) ret = odbc.SQLColAttribute(stmtHandle, odbc.SQLUSMALLINT(colNum), odbc.SQL_DESC_LABEL, uintptr(unsafe.Pointer(&nameArr[0])), namelength, nil, nil) if isError(ret) { errorStatement(stmtHandle, sqlStmt) } name := syscall.UTF16ToString(nameArr) //For numeric and decimal types, get the precision var precision odbc.SQLLEN if odbc.SQLDataType(sqlType) == odbc.SQL_NUMERIC || odbc.SQLDataType(sqlType) == odbc.SQL_DECIMAL { ret = odbc.SQLColAttribute(stmtHandle, odbc.SQLUSMALLINT(colNum), odbc.SQL_COLUMN_PRECISION, 0, 0, nil, &precision) if isError(ret) { errorStatement(stmtHandle, sqlStmt) } } //For numeric and decimal types, get the scale var scale odbc.SQLLEN if odbc.SQLDataType(sqlType) == odbc.SQL_NUMERIC || odbc.SQLDataType(sqlType) == odbc.SQL_DECIMAL { ret = odbc.SQLColAttribute(stmtHandle, odbc.SQLUSMALLINT(colNum), odbc.SQL_COLUMN_SCALE, 0, 0, nil, &scale) if isError(ret) { errorStatement(stmtHandle, sqlStmt) } } col := resultColumnDef{RecNum: colNum, DataType: odbc.SQLDataType(sqlType), Name: name, Precision: precision, Scale: scale} resultColumnDefs = append(resultColumnDefs, col) } return resultColumnDefs, odbc.SQL_SUCCESS }