Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BLOB, LOB, TEXT and BINTEXT returned in unexported struct #38

Closed
xhit opened this issue Jan 20, 2020 · 5 comments
Closed

BLOB, LOB, TEXT and BINTEXT returned in unexported struct #38

xhit opened this issue Jan 20, 2020 · 5 comments
Labels

Comments

@xhit
Copy link

xhit commented Jan 20, 2020

BLOB and LOB are returned with unexported variable *protocol.binaryLobChunkWriter and cannot be used.

Also TEXT and BINTEXT are returned with unexported variable *protocol.charLobChunkWriter and cannot be used.

If I print the value in the []interface{} I can see the returned value in the column in this style &{0xc0003ba000 445873439899649 8 8 0 true 0 <nil> [115 97 110 116 105 97 103 111]} where the array is []bytes (driver.Value returned in []uint8, but doesn't matter) and this can be converted to santiago easily.

In this case, I think is better return it like BINARY and VARBINARY datatypes are returned.

@xhit xhit changed the title Dynamic query with LOB restrict driver usage BLOB, LOB, TEXT and BINTEXT returned in unexported type Jan 22, 2020
@xhit xhit changed the title BLOB, LOB, TEXT and BINTEXT returned in unexported type BLOB, LOB, TEXT and BINTEXT returned in unexported struct Jan 24, 2020
@xhit
Copy link
Author

xhit commented Jan 24, 2020

How deal with this?

This function can return the Value of the field

// get the value of unexported struct
func getUnexportedHDBStruct(field interface{}) reflect.Value {
	rs := reflect.Indirect(reflect.ValueOf(field))
	return rs.Field(8)
}

The index 8 is the value and you need to specify return the []byte

v := getUnexportedHDBStruct(field)
fmt.Print(v.Bytes())

@stfnmllr
Copy link
Contributor

Please double check on
https://github.com/SAP/go-hdb/blob/master/driver/lobexample_test.go
as explanation how to deal with LOB types. In essence the Go lob type needs to provide a Reader resp a Writer interface for good reasons. LOB is 'large objects' which shouldn't necessarily be allocated as strings or bytes. If needed a strings or bytes Buffer can be used for conversion to string and / or byte[].

@xhit
Copy link
Author

xhit commented Jan 28, 2020

Ok, but I have a problem getting the value of the BLOB column.

Look this example of how I manage the decimal and blob types. Is you ExampleLob_read but for many columns.

        db, err := sql.Open("hdb", connstring)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	query := "select decimal_column, blob_column from test"

	rows, err := db.Query(query)
	if err != nil {
		log.Fatal(err)
	}

	defer rows.Close()

	//The 2 is the total columns returned in query
	recordPointers := make([]interface{}, 2)

	//For Decimal Column
	var t driver.Decimal
	recordPointers[0] = &t

	//For BLOB Column
	b := new(bytes.Buffer)
	var lob driver.Lob
	lob.SetWriter(b)
	recordPointers[1] = &lob

	for rows.Next() {

		// Scan the result into the column pointers...
		if err := rows.Scan(recordPointers...); err != nil {
			log.Fatal(err)
		}

		for _, v := range recordPointers {
			switch x := v.(type) {
			case *driver.Lob:
				//How deal with this? I need the value
			case *driver.Decimal:
				d := (*big.Rat)(x)
				log.Print(d.FloatString(6))
			default:
				log.Print("is not BLOB or Decimal")
			}
		}
	}

@stfnmllr
Copy link
Contributor

Scan is going to take care, that the data of the BLOB is written to the bytes.Buffer. To access the data any method of bytes.Buffer can be used, e.g. b.Bytes(), b.String()...
Please be aware that the driver is not going to clear (refresh) the buffer implicitly, so in the example each iteration (rows.Next()) is going to append the BLOB record data to buffer b.

@xhit
Copy link
Author

xhit commented Jan 28, 2020

Tested and works. Thanks for help.

Code for documentation:

        db, err := sql.Open("hdb", connstring)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	query := "select decimal_column, blob_column from test"

	rows, err := db.Query(query)
	if err != nil {
		log.Fatal(err)
	}

	defer rows.Close()

	//The 2 is the total columns returned in query
	recordPointers := make([]interface{}, 2)

	//For Decimal Column
	var t driver.Decimal
	recordPointers[0] = &t

	//For BLOB Column
	b := new(bytes.Buffer)
	var lob driver.NullLob
	lob.Lob = new(driver.Lob)
	lob.Lob.SetWriter(b)
	recordPointers[1] = &lob

	for rows.Next() {

		// Scan the result into the column pointers...
		if err := rows.Scan(recordPointers...); err != nil {
			log.Fatal(err)
		}

		for _, v := range recordPointers {
			switch x := v.(type) {
			case *driver.NullLob:
				if x.Valid {
					log.Print(b.Bytes())
				} else {
					log.Print("NULL")
				}
				b.Reset()
			case *driver.Decimal:
				d := (*big.Rat)(x)
				log.Print(d.FloatString(6))
			default:
				log.Print("is not BLOB or Decimal")
			}
		}
	}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants