Beispiel #1
0
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
}
Beispiel #2
0
func (stmt *statement) bindByteArray(index int, value []byte, direction ParameterDirection) error {
	// Store both value and lenght, because we need a pointer to the lenght in
	// the last parameter of SQLBindParamter. Otherwise the data is assumed to
	// be a null terminated string.
	bindVal := &struct {
		value  []byte
		length int
	}{
		value,
		len(value),
	}
	sqlType := odbc.SQL_VARBINARY
	if bindVal.length > 4000 {
		sqlType = odbc.SQL_LONGVARBINARY
	}

	// Protect against index out of range on &bindVal.value[0] when value is zero-length.
	// We can't pass NULL to SQLBindParameter so this is needed, it will still
	// write a zero length value to the database since the length parameter is
	// zero.
	if bindVal.length == 0 {
		bindVal.value = []byte{'\x00'}
	}

	ret := odbc.SQLBindParameter(stmt.handle, odbc.SQLUSMALLINT(index), direction.SQLBindParameterType(), odbc.SQL_C_BINARY, sqlType, odbc.SQLULEN(bindVal.length), 0, odbc.SQLPOINTER(unsafe.Pointer(&bindVal.value[0])), 0, (*odbc.SQLLEN)(unsafe.Pointer(&bindVal.length)))
	if isError(ret) {
		return errorStatement(stmt.handle, fmt.Sprintf("Bind index: %v, Value: %v", index, value))
	}
	return nil
}
Beispiel #3
0
func (stmt *statement) bindBool(index int, value bool, direction ParameterDirection) error {
	stmt.bindValues[index] = &value
	ret := odbc.SQLBindParameter(stmt.handle, odbc.SQLUSMALLINT(index), direction.SQLBindParameterType(), odbc.SQL_C_BIT, odbc.SQL_BIT, 0, 0, odbc.SQLPOINTER(unsafe.Pointer(stmt.bindValues[index].(*bool))), 0, nil)
	if isError(ret) {
		return errorStatement(stmt.handle, fmt.Sprintf("Bind index: %v, Value: %v", index, value))
	}
	return nil
}
Beispiel #4
0
func (stmt *statement) bindNullParam(index int, paramType odbc.SQLDataType, direction ParameterDirection) error {
	nullDataInd := odbc.SQL_NULL_DATA
	stmt.bindValues[index] = &nullDataInd
	ret := odbc.SQLBindParameter(stmt.handle, odbc.SQLUSMALLINT(index), direction.SQLBindParameterType(), odbc.SQL_C_DEFAULT, paramType, 1, 0, 0, 0, &nullDataInd)
	if isError(ret) {
		return errorStatement(stmt.handle, fmt.Sprintf("Bind index: %v, Value: nil", index))
	}
	return nil
}
Beispiel #5
0
func (stmt *statement) bindNumeric(index int, value float64, precision int, scale int, direction ParameterDirection) error {
	stmt.bindValues[index] = &value
	ret := odbc.SQLBindParameter(stmt.handle, odbc.SQLUSMALLINT(index), direction.SQLBindParameterType(), odbc.SQL_C_DOUBLE, odbc.SQL_DOUBLE, 0, 0, odbc.SQLPOINTER(unsafe.Pointer(stmt.bindValues[index].(*float64))), 0, nil)
	/* Must convert to SQL_NUMERIC_STRUCT for decimal to work - http://support.microsoft.com/kb/181254
	 ret := odbc.SQLBindParameter(stmt.handle, uint16(index), direction.SQLBindParameterType(), odbc.SQL_C_NUMERIC, odbc.SQL_DECIMAL, uint64(precision), int16(scale), uintptr(unsafe.Pointer(&bindVal)), 0, nil)
	odbc.SQLSetDescField(stmt.stmtDescHandle, odbc.SQLSMALLINT(index), odbc.SQL_DESC_TYPE, odbc.SQL_NUMERIC, 0)
	odbc.SQLSetDescField(stmt.stmtDescHandle, odbc.SQLSMALLINT(index), odbc.SQL_DESC_PRECISION, int32(precision), 0)
	odbc.SQLSetDescField(stmt.stmtDescHandle, odbc.SQLSMALLINT(index), odbc.SQL_DESC_SCALE, int32(scale), 0) */
	if isError(ret) {
		return errorStatement(stmt.handle, fmt.Sprintf("Bind index: %v, Value: %v", index, value))
	}
	return nil
}
Beispiel #6
0
func (stmt *statement) bindString(index int, value string, length int, direction ParameterDirection) error {
	if length == 0 {
		length = len(value)
	}
	stmt.bindValues[index] = syscall.StringToUTF16(value)
	var sqlType odbc.SQLDataType
	if length < 4000 {
		sqlType = odbc.SQL_VARCHAR
	} else {
		sqlType = odbc.SQL_LONGVARCHAR
	}
	ret := odbc.SQLBindParameter(stmt.handle, odbc.SQLUSMALLINT(index), direction.SQLBindParameterType(), odbc.SQL_C_WCHAR, sqlType, odbc.SQLULEN(length), 0, odbc.SQLPOINTER(unsafe.Pointer(&stmt.bindValues[index].([]uint16)[0])), 0, nil)
	if isError(ret) {
		return errorStatement(stmt.handle, fmt.Sprintf("Bind index: %v, Value: %v", index, value))
	}
	return nil
}
Beispiel #7
0
// Return a single column of data
func (rows *rows) getField(index int) (v interface{}, ret odbc.SQLReturn) {
	columnDef := rows.resultColumnDefs[index-1]
	var fieldInd odbc.SQLLEN
	switch columnDef.DataType {
	case odbc.SQL_BIT:
		var value bool
		valuePtr := uintptr(unsafe.Pointer(&value))
		ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_C_BIT, valuePtr, 0, &fieldInd)
		return formatGetFieldReturn(value, fieldInd, ret)
	case odbc.SQL_INTEGER, odbc.SQL_SMALLINT, odbc.SQL_TINYINT:
		var value int
		valuePtr := uintptr(unsafe.Pointer(&value))
		ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_C_LONG, valuePtr, 0, &fieldInd)
		return formatGetFieldReturn(value, fieldInd, ret)
	case odbc.SQL_BIGINT:
		var value int64
		valuePtr := uintptr(unsafe.Pointer(&value))
		ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_C_LONG, valuePtr, 0, &fieldInd)
		return formatGetFieldReturn(value, fieldInd, ret)
	case odbc.SQL_FLOAT:
		var value float64
		valuePtr := uintptr(unsafe.Pointer(&value))
		ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_C_FLOAT, valuePtr, 0, &fieldInd)
		return formatGetFieldReturn(value, fieldInd, ret)
	case odbc.SQL_DOUBLE, odbc.SQL_REAL:
		var value float64
		valuePtr := uintptr(unsafe.Pointer(&value))
		ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_C_DOUBLE, valuePtr, 0, &fieldInd)
		return formatGetFieldReturn(value, fieldInd, ret)
	case odbc.SQL_NUMERIC, odbc.SQL_DECIMAL:
		var value odbc.SQL_NUMERIC_STRUCT
		valuePtr := uintptr(unsafe.Pointer(&value))
		ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_ARD_TYPE, valuePtr, 0, &fieldInd)
		return formatGetFieldReturn(numericToFloat(value), fieldInd, ret)
	case odbc.SQL_CHAR, odbc.SQL_VARCHAR, odbc.SQL_LONGVARCHAR, odbc.SQL_WCHAR, odbc.SQL_WVARCHAR, odbc.SQL_SS_XML:
		//Must read string in chunks
		stringParts := make([]string, 0)
		for {
			chunkSize := 4096
			valueChunk := make([]uint16, chunkSize*2)
			valueChunkPtr := uintptr(unsafe.Pointer(&valueChunk[0]))
			ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_C_WCHAR, valueChunkPtr, odbc.SQLLEN(chunkSize*2*2), &fieldInd)
			if isError(ret) || odbc.SQLLEN(ret) == odbc.SQL_NULL_DATA {
				return formatGetFieldReturn(nil, fieldInd, ret)
			} else if ret == odbc.SQL_NO_DATA {
				//All data has been retrieved
				break
			} else if ret == odbc.SQL_SUCCESS {
				stringParts = append(stringParts, syscall.UTF16ToString(valueChunk))
				break
			}
			stringParts = append(stringParts, syscall.UTF16ToString(valueChunk))
		}
		return formatGetFieldReturn(strings.Join(stringParts, ""), odbc.SQLLEN(0), odbc.SQL_SUCCESS)
	case odbc.SQL_VARBINARY:
		var binaryData []byte
		chunkSize := 4096
		valueChunk := make([]byte, chunkSize)
		valueChunkPtr := uintptr(unsafe.Pointer(&valueChunk[0]))
		for {
			ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_C_BINARY, valueChunkPtr, odbc.SQLLEN(chunkSize), &fieldInd)
			if isError(ret) || odbc.SQLLEN(ret) == odbc.SQL_NULL_DATA {
				return formatGetFieldReturn(nil, fieldInd, ret)
			} else if ret == odbc.SQL_NO_DATA {
				//All data has been retrieved
				break
			} else if ret == odbc.SQL_SUCCESS {
				partSize := int(fieldInd) % chunkSize
				if partSize == 0 {
					partSize = chunkSize
				}
				binaryData = append(binaryData, valueChunk[0:partSize]...)
				break
			}
			binaryData = append(binaryData, valueChunk...)
		}
		return formatGetFieldReturn(binaryData, odbc.SQLLEN(0), odbc.SQL_SUCCESS)
	case odbc.SQL_TYPE_DATE:
		var value odbc.SQL_DATE_STRUCT
		valuePtr := uintptr(unsafe.Pointer(&value))
		ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_C_DATE, valuePtr, 0, &fieldInd)
		time := time.Date(int(value.Year), time.Month(value.Month), int(value.Day), 0, 0, 0, 0, time.UTC)
		return formatGetFieldReturn(time, fieldInd, ret)
	case odbc.SQL_TYPE_TIMESTAMP:
		var value odbc.SQL_TIMESTAMP_STRUCT
		valuePtr := uintptr(unsafe.Pointer(&value))
		ret = odbc.SQLGetData(rows.handle, odbc.SQLUSMALLINT(index), odbc.SQL_C_TIMESTAMP, valuePtr, 0, &fieldInd)
		time := time.Date(int(value.Year), time.Month(value.Month), int(value.Day), int(value.Hour), int(value.Minute), int(value.Second), int(value.Faction), time.UTC)
		return formatGetFieldReturn(time, fieldInd, ret)
	default:
		panic(fmt.Sprintf("ODBC type not supported: {%v}. Column name: %v", columnDef.DataType, columnDef.Name))
	}

	return nil, odbc.SQL_SUCCESS

}
Beispiel #8
0
// 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
}