duanshang9426 2018-04-19 11:32
浏览 110
已采纳

如何使用pgx控制已准备好的SQL语句中的参数类型?

I'm using jackc/pgx for postgresql-10 connections in a web application. Prepared statement syntax is slightly different than the database/sql standard library, but the issue remains the same.

Prepared statement and execution:

_, err := conn.Prepare("listContacts", `
    select id, name, phonenumber, email from contacts
        order by name
        limit $1
        offset $2
`)
....
//ParseUint caches invalid negative input, returns uint64
page, err := strconv.ParseUint(r.FormValue("page"), 10, 8)
if err != nil {
    http.Error(w, "Invalid argument", http.StatusBadRequest)
    return
}
limit := 27
offset := (page - 1) * l //Forgot parentheses here, caused Error
rows, err := pool.Query("listContacts", limit, offset)
if err != nil {
    http.Error(w, "Internal server error", http.StatusInternalServerError)
    return
}
....

This parameters should and appears to be of an integer type. However, due to an error my code calculated offset to a gigantic value. This resulted in a query error: 18446744073709551591 is greater than maximum value for Int8. I rectified the original error.

However, it does make me wonder... Why Int8? And how to have some control over this decision? According postgresql documentation for prepared statements this can be set in a parameter:

...A corresponding list of parameter data types can optionally be specified. When a parameter's data type is not specified or is declared as unknown, the type is inferred from the context in which the parameter is used (if possible)....

Since the table doesn't have too many entries, I guess postgresql choose Int8.

data_type

The data type of a parameter to the prepared statement. If the data type of a particular parameter is unspecified or is specified as unknown, it will be inferred from the context in which the parameter is used. To refer to the parameters in the prepared statement itself, use $1, $2, etc.

I can't find the data_type option in jackc/pgx or database/sql documentation.

I see the problem as follows:

  • I use strconv.ParseUint to convert and sanitize user input to a positive-only value.
  • I could modify the code to use strconv.ParseInt, do the multiplication and test if the resulting value is positive fits in int8. Reply with Http.StatusBadRequest if it doesn't
  • If the database will grow in production I will have to update my code!?
  • Or allow for a bigger values with int32 or int64 and throw nasty Http.StatusInternalServerError to the client when the query fails

But, the solution I'm really looking for: tell postgresql to expect Uint64 and deal with the empty result set towards the client in a fashionable way.

  • 写回答

1条回答 默认 最新

  • duanhuanyou6478 2018-04-19 12:46
    关注

    Why Int8?

    error: 18446744073709551591 is greater than maximum value for Int8


    PostgreSQL tries to find an integer type that is large enough to represent the constant value 18446744073709551591. The largest integer type PostgreSQL has is int8 (8 bytes or 64 bits) or bigint, which has a maximum value of 9223372036854775807. The error message says 18446744073709551591 is greater than 9223372036854775807, which is correct.

    Reference: Chapter 8. Data Types, PostgreSQL 10

    Name    Aliases     Description
    bigint  int8        signed eight-byte integer
    

    I use strconv.ParseUint to convert and sanitize user input to a positive-only value.


    That is a bad idea. Use strconv.ParseInt, check that input value is within the valid range, and write correct code.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料
  • ¥15 使用R语言marginaleffects包进行边际效应图绘制