How does if condition works in golang

I am trying to develop a go driver for IBM (db2) database.
For windows the API definition is : -
(i will load the dll and use the functions)

func SQLColAttribute(statementHandle SQLHSTMT, ColumnNumber SQLUSMALLINT, FieldIdentifier SQLUSMALLINT, CharacterAttributePtr SQLPOINTER, BufferLength SQLSMALLINT, StringLengthPtr *SQLSMALLINT, NumericAttributePtr *SQLLEN) (ret SQLRETURN) {
	r0, _, _ := syscall.Syscall9(procSQLColAttribute.Addr(), 7, uintptr(statementHandle), uintptr(ColumnNumber), uintptr(FieldIdentifier), uintptr(CharacterAttributePtr), uintptr(BufferLength), uintptr(unsafe.Pointer(StringLengthPtr)), uintptr(unsafe.Pointer(NumericAttributePtr)), 0, 0)
	ret = SQLRETURN(r0)
	return
}

For other platforms it is : -
(using cgo that means i will include the sqlcli.h file and then import C)

func SQLColAttribute(statementHandle SQLHSTMT, ColumnNumber SQLUSMALLINT, FieldIdentifier SQLUSMALLINT, CharacterAttributePtr SQLPOINTER, BufferLength SQLSMALLINT, StringLengthPtr *SQLSMALLINT, NumericAttributePtr SQLPOINTER) (ret SQLRETURN) {
        r := C.SQLColAttribute(C.SQLHSTMT(statementHandle),C.SQLUSMALLINT(ColumnNumber),C.SQLUSMALLINT(FieldIdentifier),C.SQLPOINTER(CharacterAttributePtr),C.SQLSMALLINT(BufferLength),(*C.SQLSMALLINT)(StringLengthPtr),(C.SQLPOINTER)(NumericAttributePtr))
        return SQLRETURN(r)
}

My Code of using the functions:-

func (r *Rows) ColumnTypeLength(index int) (length int64, ok bool) {
	if runtime.GOOS == "windows" {
	    ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), (*api.SQLLEN)(&length)))
	   if IsError(ret) {
		fmt.Println(ret)
		return 0, false
	   }
	 return length, true
 } else {
	ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), api.SQLPOINTER(unsafe.Pointer(&length)))
	if IsError(ret) {
		fmt.Println(ret)
		return 0, false
	}
	return length, true
    }
}

Error:
when i run the code in windows it produces that

# github.com/ibmdb/go_ibm_db
C:\Users\rakhil\go\src\github.com\ibmdb\go_ibm_db\rows.go:55:165: cannot use api.SQLPOINTER(unsafe.Pointer(&length)) (type api.SQLPOINTER) as type *api.SQLLEN in argument to api.SQLColAttribute

when i run the code in linux it produces that

cannot convert &length (type *int64) to type *api.SQLLEN

why is that go compiling the code without checking the if condition or else is there any other way to run the code.

Thanks.

Which is line 55 in rows.go?

line 55

ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), api.SQLPOINTER(unsafe.Pointer(&length)))

So your question is why this

is not true under Windows?

My Question is

In SQLColAttribute the last parameter(NumericAttributePtr) is SQLLEN in windows and SQLPOINTER in other platforms.
So, I have used if condition to take care of it but, it runs both if and else code and produces the error.

That’s impossible if/else never run both.

1 Like

How to take care of it ? as i cannot write two functions because the decleration is in sql package(database/sql).

if and runtime.GOOS work as expected:

package main

import (
	"fmt"
	"runtime"
)

func main() {
	if runtime.GOOS == "linux" {
		fmt.Println("This is Linux: " + runtime.GOOS)
	} else {
		fmt.Println("This is not Linux: " + runtime.GOOS)
	}
}

See https://play.golang.org/p/wVdvlIf4-ON

suppose this is rows.go file:-

// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package go_ibm_db

import (
	"database/sql/driver"
	"fmt"
	"io"
	"reflect"
	"unsafe"

	"github.com/ibmdb/go_ibm_db/api"
)

type Rows struct {
	os *ODBCStmt
}

func (r *Rows) Columns() []string {
	names := make([]string, len(r.os.Cols))
	for i := 0; i < len(names); i++ {
		names[i] = r.os.Cols[i].Name()
	}
	return names
}

func (r *Rows) ColumnTypeLength(index int) (length int64, ok bool) {
       if runtime.GOOS == "windows" {
        ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), (*api.SQLLEN)(&length)))
	    if IsError(ret) {
		    fmt.Println(ret)
		    return 0, false
	}
	return length, true
    } else {
	ret := api.SQLColAttribute(r.os.h, api.SQLUSMALLINT(index+1), api.SQL_DESC_LENGTH, api.SQLPOINTER(unsafe.Pointer(nil)), 0, (*api.SQLSMALLINT)(nil), api.SQLPOINTER(unsafe.Pointer(&length)))
	if IsError(ret) {
		fmt.Println(ret)
		return 0, false
	}
	return length, true
    }
}


func (r *Rows) Next(dest []driver.Value) error {
	ret := api.SQLFetch(r.os.h)
	if ret == api.SQL_NO_DATA {
		return io.EOF
	}
	if IsError(ret) {
		return NewError("SQLFetch", r.os.h)
	}
	for i := range dest {
		v, err := r.os.Cols[i].Value(r.os.h, i)
		if err != nil {
			return err
		}
		dest[i] = v
	}
	return nil
}

func (r *Rows) Close() error {
	return r.os.closeByRows()
}

For normal file it was running perfectly when it comes to that rows.go file it is running weirdly.

BTW, did you look at https://github.com/golang/go/wiki/SQLDrivers#drivers for DB2 drivers?

None of them will support SQLColAttribute api.
github.com/ibmdb/go_ibm_db is ours and we are trying to support that api then we got this kind of error.

@NobbZ can u help me on this.

Thanks

I’m not sure how.

np. Thanks.

Is there any way to detect the OS at compile time @lutzhorn
because runtime.GOOS will detect it at runtime.

Which OS? The one you compile on?

YES. where my program will run.

The OS you compile on is not necessarily the one you run the application on. So which one:

  • A: the OS you compile the application on
  • B: the OS you run the compiled application on

option A