gpt4 book ai didi

postgresql - go 插入复合类型数组不支持的类型

转载 作者:行者123 更新时间:2023-12-02 22:21:37 26 4
gpt4 key购买 nike

sql

CREATE TABLE public.tiantang_page (
href varchar NOT NULL,
status int4 NOT NULL,
description varchar NOT NULL,
urls url[] NULL
);

CREATE TYPE url AS (
url varchar,
status int4);

插入复合类型数组

type url  struct {
url string
status int
}
var urls [1]url
urls[0] = url{
url: "",
status: 0,
}
update := "UPDATE \"public\".\"tiantang_page\" SET \"urls\"=$1 where \"href\"=$2;"
r, err := db.Exec(update, pq.Array(urls),href)
if err != nil {
log.Fatal(err)
}

错误

sql: converting argument $1 type: unsupported type parsetest.url, a struct

图书馆

https://godoc.org/github.com/lib/pq

最佳答案

请注意,lib/pq完全支持自定义复合类型。

如果您想要的只是能够存储 url,那么最简单的方法是在 url 类型上实现 driver.Valuer 接口(interface),然后使用它正如您对 pq.Array 所做的那样:

func (u url) Value() (driver.Value, error) {
return fmt.Sprintf("(%s,%d)", u.url, u.status), nil
}

// ...
r, err := db.Exec(update, pq.Array(urls), href)

更多信息可以在这里找到:https://github.com/lib/pq/issues/544

请注意,我没有尝试过使用数组,仅使用 slice ,因此您可能必须从使用数组切换到使用 slice ,即而不是 var urls [1]url 您将使用 var urls = make([]url, 1)

<小时/>

如果您还希望能够从数据库检索 url 数组,那么您必须实现 sql.Scanner 接口(interface),但是这里的 pq.Array 不太可靠,您必须在 slice 类型上实现扫描器并自己完成所有解析。

复合类型的一般格式为(val1, val2, ...) 请注意,您必须在包含逗号或括号的值两边加上双引号。例如,要构造 url 类型的值,您可以使用文字表达式:(http://example.com,4)。更多信息在docs .

复合类型数组的格式为{"(val1, val2, ...)"[, ...]},请注意,在此如果您需要将双引号括在需要转义的值的情况下。例如 {"(http://example.com,4)","(\"http://example.com/?list=foo,bar,baz\",3)"}

因此,正如您所看到的,复合类型中的数据越复杂,解析也就越复杂。

这是一个粗略的示例(不处理带引号的值):

type urlslice []url

func (s *urlslice) Scan(src interface{}) error {
var a []byte // the pq array as bytes
switch v := src.(type) {
case []byte:
a = v
case string:
a = []byte(v)
case nil:
*s = nil
return nil
default:
return fmt.Errorf("urlslice.Scan unexpected src type %T", src)
}

a = a[1 : len(a)-1] // drop curly braces
for i := 0; i < len(a); i++ {
if a[i] == '"' && (len(a) > (i+1) && a[i+1] == '(') { // element start?
i += 2 // move past `"(`
j := i // start of url.url
u := url{}

for ; i < len(a) && a[i] != ','; i++ {
}
u.url = string(a[j:i])

i += 1 // move past `,`
j = i // start of url.status
for ; i < len(a) && a[i] != ')'; i++ {
}
i64, err := strconv.ParseInt(string(a[j:i]), 10, 64)
if err != nil {
return err
}
u.status = int(i64)
*s = append(*s, u)

i += 2 // move past `)",`
}
}
return nil
}

为了完整起见,这里是 slice 类型实现的 Valuer 接口(interface),同样没有处理可能需要它的值的正确引用:

func (s urlslice) Value() (driver.Value, error) {
data := []byte{'{'}
for _, url := range s {
data = append(data, '"', '(')
data = append(data, []byte(url.url)...)
data = append(data, ',')
data = strconv.AppendInt(data, int64(url.status), 10)
data = append(data, ')', '"', ',')
}
data[len(data)-1] = '}' // replace last ',' with '}' to close the array
return data, nil
}

通过直接实现两个接口(interface)的urlslice,您可以停止使用pq.Array

var urls = urlslice{{
url: "http://example.com",
status: 4,
}}
update := `UPDATE "public"."tiantang_page" SET "urls"=$1 where "href"=$2`
r, err := db.Exec(update, urls, href)
if err != nil {
log.Fatal(err)
}

var urls2 urlslice
selurls := `SELECT "urls" FROM "public"."tiantang_page" where "href" = $1`
if err := db.QueryRow(selurls, href).Scan(&urls2); err != nil {
log.Fatal(err)
}
<小时/>

请记住,上述两个示例仅应被视为解决此问题的方向的提示。这两个示例不仅不完整,因为它们不处理带引号的值,而且它们也不是非常优雅的实现。

关于postgresql - go 插入复合类型数组不支持的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59353838/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com