1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
/*
Copyright 2014 SAP SE
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package driver_test
import (
"bufio"
"bytes"
"database/sql"
"fmt"
"io"
"log"
"os"
"sync"
"github.com/SAP/go-hdb/driver"
)
// ExampleLobRead reads data from a largs data object database field into a bytes.Buffer.
// Precondition: the test database table with one field of type BLOB, CLOB or NCLOB must exist.
// For illustrative purposes we assume, that the database table has exactly one record, so
// that we can use db.QueryRow.
func ExampleLob_read() {
b := new(bytes.Buffer)
db, err := sql.Open("hdb", "hdb://user:password@host:port")
if err != nil {
log.Fatal(err)
}
defer db.Close()
lob := new(driver.Lob)
lob.SetWriter(b) // SetWriter sets the io.Writer object, to which the database content of the lob field is written.
if err := db.QueryRow("select * from test").Scan(lob); err != nil {
log.Fatal(err)
}
}
// ExampleLobWrite inserts data read from a file into a database large object field.
// Precondition: the test database table with one field of type BLOB, CLOB or NCLOB and the
// test.txt file in the working directory must exist.
// Lob fields cannot be written in hdb auto commit mode - therefore the insert has to be
// executed within a transaction.
func ExampleLob_write() {
file, err := os.Open("test.txt") // Open file.
if err != nil {
log.Fatal(err)
}
defer file.Close()
db, err := sql.Open("hdb", "hdb://user:password@host:port")
if err != nil {
log.Fatal(err)
}
defer db.Close()
tx, err := db.Begin() // Start Transaction to avoid database error: SQL Error 596 - LOB streaming is not permitted in auto-commit mode.
if err != nil {
log.Fatal(err)
}
stmt, err := tx.Prepare("insert into test values(?)")
if err != nil {
log.Fatal(err)
}
lob := new(driver.Lob)
lob.SetReader(file) // SetReader sets the io.Reader object, which content is written to the database lob field.
if _, err := stmt.Exec(lob); err != nil {
log.Fatal(err)
}
stmt.Close()
if err := tx.Commit(); err != nil {
log.Fatal(err)
}
}
/*
ExampleLobPipe:
- inserts data read from a file into a database large object field
- and retrieves the data afterwards
An io.Pipe is used to insert and retrieve Lob data in chunks.
*/
func ExampleLob_pipe() {
// Open test file.
file, err := os.Open("example_lob_test.go")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// Open Test database.
connector, err := driver.NewDSNConnector(driver.TestDSN)
if err != nil {
log.Fatal(err)
}
db := sql.OpenDB(connector)
defer db.Close()
tx, err := db.Begin() // Start Transaction to avoid database error: SQL Error 596 - LOB streaming is not permitted in auto-commit mode.
if err != nil {
log.Fatal(err)
}
// Create table.
table := driver.RandomIdentifier("fileLob")
if _, err := tx.Exec(fmt.Sprintf("create table %s (file nclob)", table)); err != nil {
log.Fatalf("create table failed: %s", err)
}
stmt, err := tx.Prepare(fmt.Sprintf("insert into %s values (?)", table))
if err != nil {
log.Fatal(err)
}
lob := &driver.Lob{} // Lob field.
pipeReader, pipeWriter := io.Pipe() // Create pipe for writing Lob.
lob.SetReader(pipeReader) // Use PipeReader as reader for Lob.
// Use sync.WaitGroup to wait for go-routines to be ended.
wg := new(sync.WaitGroup)
wg.Add(1) // Select statement.
// Start sql insert in own go-routine.
// The go-routine is going to be ended when the data write via the PipeWriter is finalized.
go func() {
if _, err := stmt.Exec(lob); err != nil {
log.Fatal(err)
}
fmt.Println("exec finalized")
wg.Done()
}()
// Read file line by line and write data to pipe.
scanner := bufio.NewScanner(file)
for scanner.Scan() {
pipeWriter.Write(scanner.Bytes())
pipeWriter.Write([]byte{'\n'}) // Write nl which was stripped off by scanner.
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
// Close pipeWriter (end insert into db).
pipeWriter.Close()
// Wait until exec go-routine is ended.
wg.Wait()
stmt.Close()
if err := tx.Commit(); err != nil {
log.Fatal(err)
}
pipeReader, pipeWriter = io.Pipe() // Create pipe for reading Lob.
lob.SetWriter(pipeWriter) // Use PipeWriter as writer for Lob.
wg.Add(1) // Exec statement.
// Start sql select in own go-routine.
// The go-routine is going to be ended when the data read via the PipeReader is finalized.
go func() {
if err := db.QueryRow(fmt.Sprintf("select * from %s", table)).Scan(lob); err != nil {
log.Fatal(err)
}
fmt.Println("scan finalized")
wg.Done()
}()
// Read Lob line by line via bufio.Scanner.
scanner = bufio.NewScanner(pipeReader)
for scanner.Scan() {
// Do something with scan result.
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
pipeReader.Close()
// Wait until select go-routine is ended.
wg.Wait()
// output: exec finalized
// scan finalized
}
|