parseRow calls rows.Scan to retrieve the current row, and convert each cell value from {}interface to an accuracy value. It then writes the converted row into wr.
(columns []string, columnTypes []*sql.ColumnType, rows *sql.Rows, wr *pipe.Writer)
| 92 | // each cell value from {}interface to an accuracy value. It then |
| 93 | // writes the converted row into wr. |
| 94 | func parseRow(columns []string, columnTypes []*sql.ColumnType, rows *sql.Rows, wr *pipe.Writer) error { |
| 95 | // Since we don't know the table schema in advance, we create |
| 96 | // a slice of empty interface and add column types at |
| 97 | // runtime. Some databases support dynamic types between rows, |
| 98 | // such as sqlite's affinity. So we move columnTypes inside |
| 99 | // the row.Next() loop. |
| 100 | count := len(columns) |
| 101 | values := make([]interface{}, count) |
| 102 | for i, ct := range columnTypes { |
| 103 | // NOTE(typhoonzero): Hive TIMESTAMP_TYPE column will return string value, but ct.ScanType() returns int64 |
| 104 | // https://github.com/sql-machine-learning/sqlflow/issues/1256 |
| 105 | if ct.DatabaseTypeName() == "TIMESTAMP_TYPE" { |
| 106 | values[i] = new(string) |
| 107 | continue |
| 108 | } |
| 109 | values[i] = newZeroValue(ct.ScanType()) |
| 110 | } |
| 111 | |
| 112 | if err := rows.Scan(values...); err != nil { |
| 113 | return err |
| 114 | } |
| 115 | |
| 116 | row := make([]interface{}, count) |
| 117 | for i, val := range values { |
| 118 | v, e := fieldValue(val) |
| 119 | if e != nil { |
| 120 | return e |
| 121 | } |
| 122 | row[i] = v |
| 123 | } |
| 124 | if e := wr.Write(row); e != nil { |
| 125 | return e |
| 126 | } |
| 127 | return nil |
| 128 | } |
| 129 | |
| 130 | func runExec(wr *pipe.Writer, slct string, db *database.DB) error { |
| 131 | res, e := db.Exec(slct) |
no test coverage detected