2

Estoy haciendo un WS, en donde realizo una consulta a la base de datos, como la base de datos a la cual realizo la consulta es Informix, la conexión la realizo por medio de ODBC, el problema que tengo es al momento de crear el json debido a los tipos de variable, agradezco la ayuda.

Para realizar la consulta y extraer el mapeo, estoy guiandome por este ejemplo que de entra me da el siguiente resultado:

-Paquetes importados:

import (
    _"unicode/utf8"
    _"os"
    _ "github.com/alexbrainman/odbc"
    "database/sql"
    "fmt"
    "os"
    "time"
    "reflect"
    "log"
)

-código:

db, err := sql.Open("odbc", "DSN=" + host)
    if err != nil {
        fmt.Println("Could not connect to db:", err)
        os.Exit(1)
    }

    err = db.Ping()
    if err != nil {
        fmt.Println("got an error:", err)
        os.Exit(1)
    }
    /*SELECT*/
rows, err := db.Query("SELECT su.coduser AS id , TRIM(su.nomuser) AS user, s.fchven AS fch_ven, s.fecreg AS fch_registro FROM suser su JOIN sinfo s ON s.coduser = su.coduser WHERE su.nomuser=? AND su.pass=?",user_login,pass_login)
    cols, _ := rows.Columns()

    for rows.Next() {
        // Create a slice of interface{}'s to represent each column,
        // and a second slice to contain pointers to each item in the columns slice.
        columns := make([]interface{}, len(cols))
        columnPointers := make([]interface{}, len(cols))
        for i, _ := range columns {
            columnPointers[i] = &columns[i]
        }

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

        // Create our map, and retrieve the value for each column from the pointers slice,
        // storing it in the map with the name of the column as the key.
        m := make(map[string]interface{})
        for i, colName := range cols {
            val := columnPointers[i].(*interface{})
            m[colName] = *val
        }

        // Outputs: map[columnName:value columnName2:value2 columnName3:value3 ...]
        fmt.Print(m)
    }

La consulta esta bien, efectivamente me realiza el ciclo en caso de ser varios registros, pero cuando imprimo el map para verlo en consola, me muestra el siguiente resultado:

map[id:769244 user:[65 100 109 105 110 95 117 115 101 114] fch_ven:2019-11-06 00:00:00 -0500 -05 fch_registro:2017-04-15 05:05:29 -0500 -05]2018/05/25 15:06:42 {0  <nil>  0   0 0   0 0                           0 0   0      }

se que puedo hacer esto:

 var name string
        if err := rows.Scan(&name); err != nil {
                log.Fatal(err)
        }

Crear las variables y asociarlas, pero tengo problemas con los campos que son de tipo DATE y DATETIME, simplemente no me retorna la información, por eso opte por usar el ejemplo mencionado pero tengo problemas con los string, aparte que cuando realizo el almacenamiento en una variable var test string = m["user"].(string). Simplemente me da error en la linea cuando lo estoy ejecutando, solo me dice que hay error mas no me especifica.

Andrés
  • 1,107
  • 1
  • 6
  • 26

1 Answers1

2

A juzgar por el valor mostrado en la consola cuando imprimes la variable m los campos tipo fecha son retornados como string o posiblemente time.Time, una manera de confirmarlo seria:

import "reflect"
// ... codigo ...
for k, v := range m {
   fmt.Println(k, ":", v, " -> ", reflect.TypeOf(v))
}

Podríamos saber más si mencionaras el package que estas usando para interfazar con ODBC.

ACTUALIZACIÓN

En base a tu commentario, podrías obtener los campos fecha asi:

// ... codigo ...
var fechaVen, fechaReg time.Time
// ... 

I assignándolos a columnPointers asi: columnPointers = append(columnPointers, fechaVen, fechaReg)

SEGUNDA ACTUALIZACIÓN

Tambien se pueden utilizar structs para realizar el escaneo:

package main

import (
    "database/sql"
    "log"
    "time"

    _ "github.com/alexbrainman/odbc"
)

type userRecord struct {
    ID       string
    Nombre   string
    FechaVen time.Time
    FechaReg time.Time
}

func main() {

    const (
        host      = ""
        userLogin = ""
        passLogin = ""
    )

    db, err := sql.Open("odbc", "DSN="+host)
    if err != nil {
        log.Fatal("Could not connect to db:", err)
    }

    if err = db.Ping(); err != nil {
        log.Fatal("got an error:", err)
    }

    /*SELECT*/
    rows, err := db.Query(`
    SELECT 
        su.coduser AS id,
        TRIM(su.nomuser) AS user,
        s.fchven AS fch_ven,
        s.fecreg AS fch_registro
    FROM 
        suser su JOIN sinfo s ON s.coduser = su.coduser 
    WHERE 
        su.nomuser=? AND su.pass=?`,
        userLogin, passLogin)

    for rows.Next() {
        user := &userRecord{}

        // Scan the result into the column pointers...
        if err := rows.Scan(&user.ID, &user.Nombre, &user.FechaVen, &user.FechaReg); err != nil {
            log.Fatal(err)
        }

        // This will print each user
        log.Println(user)
    }
}
Tristian
  • 186
  • 7
  • `fch_registro:2017-04-15 05:05:29 -0500 -05 -> time.Time id:769244 -> int32 user:[65 100 109 105 110 95 117 115 101 114] -> []uint8 fch_ven:2009-11-06 00:00:00 -0500 -05 -> time.Time {0 0 0 0 0 0 0 0 0 }` , Ese es el valor que imprime. – Andrés May 25 '18 at 22:01
  • No comprendo porque si User en la BD es Varchar, porque en el Map es uint8 y no string, ya actualice la pregunta y puse los paquetes – Andrés May 25 '18 at 22:02
  • En Go, los `uint8` son aliases de `byte` asi que en si puedes hacer esta conversion directamente: `string([]byte{1,2,3})` es decir puedes tomar el valor de `user` y convertirlo a un `string` `string([]byte{65 100 109 105 110 95 117 115 101 114})` – Tristian May 25 '18 at 22:09
  • Vale comprendo, podrías mostrarme como hacerlo o el enlace donde este un ejemplo para implementarlo, estoy buscando y no lo comprendo muy bien la verdad, disculpa la molestia. – Andrés May 25 '18 at 22:26
  • Me sale este error: `Cannot use 'v' (type interface{}) as type []byte Reports incompatible types.` , estaba usando esta función para realizar la conversión: `func BytesToString(data []byte) string { return string(data[:]) }` – Andrés May 25 '18 at 22:29
  • Si, el problema es que estas intentando obtener cada campo dinámicamente, Go es un lenguaje de tipos estáticos; es decir en este caso si _ya_ sabes de antemano el tipo de los datos que vas a extraer de la DB, uno puede utilizar variables (o miembros) del tipo correspondiente. He agregado otro ejemplo, para ilustrarlo mejor. – Tristian May 25 '18 at 22:59
  • Muchísimas Gracias me funciono sin problemas, si tengo algún problema, me gustaría poder contar con tu apoyo, muchísimas gracias nuevamente. – Andrés May 25 '18 at 23:05
  • Excelente, gracias!. suerte y mucho éxito. – Tristian May 25 '18 at 23:06
  • Una pregunta, lo que pasa es que tengo un problema mas, el campo esta null y me sale el siguiente error: `sql: Scan error on column index 12: converting driver.Value type ("") to a int: invalid syntax` no se si me podrías ayudar, vi que uno puede utilizar `sql.NullInt64` en el caso de los enteros pero aun así, también como aria uno en el caso de las fechas.? – Andrés May 28 '18 at 16:06
  • Hola!, si el campo de la tabla puede ser null ese caso declara el miembro del Go struct como `sql.NullInt64` en vez de `int`: https://golang.org/pkg/database/sql/#NullInt64 – Tristian May 28 '18 at 18:58
  • Me podrías ayudar en esta pregunta: https://es.stackoverflow.com/questions/168818/utf8-encode-y-decode-en-go-golang – Andrés May 29 '18 at 13:51
  • Hola tristian, queria saber si me podias ayudar a desarrollar la lectura de un WS soap WSDL – Andrés Jul 25 '18 at 03:08
  • Hola!, algún punto en particular en el cual estés teniendo problemas? – Tristian Jul 25 '18 at 03:27
  • lo que pasa es que necesito consumir un WS soap WSDL, estuve mirando el paquete wsdl2go, que se ve sencillo de implementar, pero, el problema es que el WSDL que necesito utilizar tiene parametros de seguridad que debo enviar por el header y la verdad me pierdo un poco con el ejemplo que publica el paquete – Andrés Jul 25 '18 at 03:33
  • hmmm, pues habría que ver, tienes el enlace al ejemplo que estas siguiendo. Crea una cuenta aquí: https://gitter.im usando tu Github o Twitter y podemos verlo como chat en vez de comentarios – Tristian Jul 25 '18 at 03:58
  • ya quedo, me parece que te agrege – Andrés Jul 25 '18 at 04:03