Is Golang's SQL Package Incapable of Ad Hoc/Exploratory Queries

Is Golang's SQL package incapable of ad hoc / exploratory queries?

The sql.Rows type has a Columns method that will give you a list of the result column names. That can be used to determine the number of columns for unknown queries.

In the docs for the Scan method, it says:

If an argument has type *[]byte, Scan saves in that argument a copy of
the corresponding data. The copy is owned by the caller and can be
modified and held indefinitely. The copy can be avoided by using an
argument of type *RawBytes instead; see the documentation for RawBytes
for restrictions on its use.

If an argument has type *interface{}, Scan copies the value provided by
the underlying driver without conversion. If the value is of type
[]byte, a copy is made and the caller owns the result.

So we also have support for scanning column values when we don't know their type: either in their raw form, or as Go types.

Putting these two together, you could do something like the following using the ... syntax to call variadic functions:

columnNames, err := rows.Columns()
if err != nil {
log.Fatalln(err) // or whatever error handling is appropriate
}
columns := make([]interface{}, len(columnNames))
columnPointers := make([]interface{}, len(columnNames))
for i := 0; i < len(columnNames); i++ {
columnPointers[i] = &columns[i]
}
if err := rows.Scan(columnPointers...); err != nil {
log.Fatalln(err)
}

Now the columns slice should contain the decoded versions of all the column values for the current result row.

If you have extra knowledge about the table (e.g. expected types, or know the number of columns ahead of time), you could probably simplify the logic a little.

Is there a way to get the Type for a Column using package database/sql in golang?

You should be able to do it this way:

func printRows(rows *sql.Rows){

colTypes, err := rows.ColumnTypes()
for _,s := range colTypes {
log.Println("cols type:", s.DatabaseTypeName());
}
}

Scan row into slice

You can do it this way:

cols, err := rows.Columns() // Remember to check err afterwards
vals := make([]interface{}, len(cols))
for i, _ := range cols {
vals[i] = new(string)
}

for rows.Next() {
err = rows.Scan(vals...)
}

on the internet they say you can use:

    vals[i] = new(sql.RawBytes)

instead of

    vals[i] = new(string)

but I think (string) is fine, idk



Related Topics



Leave a reply



Submit