Как вставить изображение как BLOB в базу данных Oracle - PullRequest
1 голос
/ 30 октября 2019

У меня есть база данных с таблицей A_LOB_TABLE:

enter image description here

Я хочу вставить изображение как BLOB с любым (скажем, '1') идентификатором вA_LOB_TABLE с использованием пакета goracle.

Вот мой код:

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// To have a valid LOB locator, we have to keep the Stmt around.
qry := `DECLARE tmp BLOB;
BEGIN
  DBMS_LOB.createtemporary(tmp, TRUE, DBMS_LOB.SESSION);
  :1 := tmp;
END;`
    tx, err := testDb.BeginTx(ctx, nil)
    if err != nil {
        fmt.Println(err)
    }
    defer tx.Rollback()

stmt, err := tx.PrepareContext(ctx, qry)
if err != nil {
    fmt.Printf("%s: %w", qry, err)
}
defer stmt.Close()
var tmp goracle.Lob
if _, err := stmt.ExecContext(ctx, goracle.LobAsReader(), sql.Out{Dest: &tmp}); err != nil {
    fmt.Printf("Failed to create temporary lob: %+v", err)
}
fmt.Printf("tmp: %#v", tmp)

// Get file as bytes (it needs to be in the same dir as code is)
dat, err := ioutil.ReadFile("./sample.png")
if err != nil {
    fmt.Println(".....Error Opening File")
    fmt.Println(err)
    return
}

if _, err := tx.ExecContext(ctx,
    "BEGIN dbms_lob.append(:1, :2); END;",
    tmp, goracle.Lob{Reader: bytes.NewReader(dat[:])},
); err != nil {
    fmt.Printf("Failed to write buffer(%v) to lob(%v): %+v", dat, tmp, err)
}

// INSERTING LOB - starting....
_, err = testDb.Exec("insert into A_LOB_TABLE(id, image) VALUES(:1, :2)",  1, tmp)
if err != nil {
    fmt.Println(".....Error Inserting data - BLOB")
    fmt.Println(err)
    return
}
// INSERTING LOB - ended.

Хотя это не работает. Он выдает ошибку в строке

_, err = testDb.Exec("insert into A_LOB_TABLE(id, image) VALUES(:1, :2)",  1, tmp)

, говоря:

dpiStmt_execute (mode = 32 arrLen = -1): ORA-22922: несуществующее значение большого объекта

1 Ответ

1 голос
/ 01 ноября 2019

После десятков часов попыток выяснить, как выполнить вставку BLOB в OracleDB с помощью драйвера Goracle Go, я получил ответ.

TL; DR

Полный код (очевидно, адаптируются переменные, такие как DBподключение и местоположение файла && имя файла в соответствии с вашими потребностями):

package main

import (
    "bytes"
    "context"
    "database/sql"
    "fmt"
    "io/ioutil"
    "time"
goracle "gopkg.in/goracle.v2"
)

func main() {
    fmt.Println("... Setting up Database Connection")
    testDb, err := sql.Open("goracle",
        "sys" +
            "/" +
            "Oracle18" +
            "@" +
            "localhost:32118" +
            "/" +
            "XE as sysdba")
    if err != nil {
        fmt.Println("... DB Setup Failed")
        fmt.Println(err)
        return
    }
    defer testDb.Close()

// Get file as bytes
dat, err := ioutil.ReadFile("./sample.png")
if err != nil {
    fmt.Println(".....Error Opening File")
    fmt.Println(err)
    return
}

// BLOB creation && passing file into it
directLob := goracle.Lob{ Reader: bytes.NewReader(dat[:])}

fmt.Println("\nINSERTING BLOB - starting....")
// Working BLOB insertion - INSERT COMMAND
_, err = testDb.Exec("insert into AA_LIVE_FRAMES(id, frame) VALUES(:1, :2)",  1, directLob)
if err != nil {
    fmt.Println(".....Error Inserting BLOB")
    fmt.Println(err)
    return
}
fmt.Println("\nINSERTING BLOB - ended.")

fmt.Println("\nSuccess")
}

Это рабочий файл main.go.

ОТЛИЧНАЯ ВЕРСИЯ ОТВЕТ

Почему это заняло так много времени, если код так прост?

Когда я начал работать с этой проблемой, я не нашел ни одного учебника или примеров в документации goracle, показывающих, какВСТАВИТЬ BLOB в OracleDB. Конечно, была эта структура goracle.Lob с хорошей функцией - Read (). Это была моя первая попытка, объявить этот goracle.Lob и использовать его функцию Read (), но это дало мне ошибки - нулевой адрес и так далее. Я не знал почему, пытался его отладить - безрезультатно. Затем я углубился, вытащил несколько тестовых кодов из пакета goracle, показывающих, как создать временный большой объект - часть этого кода показана в моем ответе на вопрос. Опять без успеха. Затем я пробовал сырой SQL, но снова потерпел неудачу (я думаю, потому что мой OracleDB - это каталог для создания докеров, который необходим для вставки BLOB в OracleDB, не работал; nvm).

И, наконец, я неконечно, почему, я пробовал struct literal:

directLob := goracle.Lob{ Reader: bytes.NewReader(dat[:])}

и работал.

Хорошо, почему я все это печатаю? Потому что, AFAIK, делает это:

directLob := goracle.Lob{ Reader: bytes.NewReader(dat[:])}

и это:

directLob := goracle.Lob{}
directLob.Read(dat[:])

должно быть одинаковым? Или я совершенно не прав?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...