sql - 如何解决Golang中的错误 "ORA-00911: invalid character"?

标签 sql oracle go bind-variables

我在调用以下函数时遇到错误“ORA-00911:无效字符”。如果我使用带有硬编码值的 SQL 查询(截至目前,它已在下面的代码片段中注释掉),那么我可以在 postman 中以 JSON 响应获取数据库记录,没有任何问题。所以,看起来我的论点做错了。仅供引用,我正在使用“github.com/sijms/go-ora/v2”包连接到 oracle db。 另外,“DashboardRecordsRequest”结构位于数据模型包中,但我已将其粘贴到下面的代码片段中以供引用。 请注意,当我进行 POC 时,我们将使用存储过程与 Oracle 交互。

postman 请求负载:

{
    "username": "UserABC",
    "startindex": 0,
    "pagesize": 10,
    "sortby": "requestnumber",
    "sortorder": "DESC"
}

执行代码:

type DashboardRecordsRequest struct {
    Username                string `json:"username"`    
    StartIndex              int    `json:"startindex"`
    PageSize                int    `json:"pagesize"`
    SortBy                  string `json:"sortby"`
    SortOrder               string `json:"sortorder"`
}

func GetDashboardActiveRequestRecords(request datamodel.DashboardRecordsRequest) ([]datamodel.ActiveRequestRecord, error) {
    sortby := request.SortBy
    sortorder := request.SortOrder
    startindex := request.StartIndex
    pagesize := request.PageSize
    activerecords := []datamodel.ActiveRequestRecord{}

    slog.Info("Verify values", slog.String("sortby", sortby), slog.String("sortorder", sortorder), slog.Int("startindex", startindex), slog.Int("pagesize", pagesize))

    dbconn, err := getDBConnection()
    if err != nil {
        logger.Error("Could not connect to database")
        return activerecords, err
    }
    stmt, err := dbconn.Prepare("SELECT requestnumber, requeststatus, NVL(requestor, 'N/A'), NVL(pendingwith, 'N/A'), NVL(processtype, 'N/A'), actiondate FROM requests WHERE requeststatus = 'PENDINGAPPROVAL' ORDER BY ? ? OFFSET ? ROWS FETCH NEXT ? ROWS ONLY")
    /*stmt, err := dbconn.Prepare("SELECT requestnumber, requeststatus, NVL(requestor, 'N/A'), NVL(pendingwith, 'N/A'), NVL(processtype, 'N/A'), actiondate FROM requests WHERE requeststatus = 'PENDINGAPPROVAL' ORDER BY requestnumber DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY")*/
    if err != nil {
        logger.Error("Error while building prepared statement for retrieving dashboard active records", slog.String("Error", err.Error()))
        return activerecords, err
    }
    rows, err := stmt.Query(sortby, sortorder, startindex, pagesize)
    //rows, err := stmt.Query()
    if err != nil {
        logger.Error("Error while executing prepared statement for retrieving dashboard active records", slog.String("Error", err.Error()))
        return activerecords, err
    }
    defer rows.Close()

    for rows.Next() {
        var rec datamodel.ActiveRequestRecord
        err = rows.Scan(&rec.RequestNumber, &rec.RequestStatus, &rec.RequestorName, &rec.PendingWith, &rec.ProcessType, &rec.LastActionDate)
        if err != nil {
            logger.Error("Error while processing database resultset for dashboard active records", slog.String("Error", err.Error()))
            return activerecords, err
        }
        activerecords = append(activerecords, rec)
    }
    return activerecords, err
}

请求表结构:

CREATE TABLE "REQUESTS" (
    "REQUESTNUMBER"          VARCHAR2(64 CHAR) NOT NULL ENABLE,
    "REQUESTSTATUS"          VARCHAR2(128 CHAR) NOT NULL ENABLE,
    "SUBMISSIONDATE"         TIMESTAMP(6),
    "PROCESSTYPE"            VARCHAR2(256 CHAR),
    "SUBMITTER"              VARCHAR2(256 CHAR) NOT NULL ENABLE,
    "REQUESTOR"              VARCHAR2(512 CHAR),
    "PENDINGWITH"            VARCHAR2(512 CHAR),
    "ACTIONDATE"             TIMESTAMP(6),
    "RESUBMISSIONDATE"       TIMESTAMP(6),
    PRIMARY KEY ( "REQUESTNUMBER" ),
    FOREIGN KEY ( "SUBMITTER" )
        REFERENCES "SUBMITTERS" ( "USERNAME" )
)

错误:

time=2023-10-04T06:43:06.304Z level=INFO source=C:/code/tutorials/myapp/internal/storage/dashboard.go:19 msg="Verify values" sortby=requestnumber sortorder=DESC startindex=0 pagesize=10
time=2023-10-04T06:43:06.603Z level=ERROR source=C:/code/tutorials/myapp/internal/storage/dashboard.go:34 msg="Error while executing prepared statement for retrieving dashboard active records" Error="ORA-00911: invalid character\n"

最佳答案

直接的问题是您使用的是 JDBC 样式的 ? 绑定(bind)占位符,而不是预期的 :var 形式。来自 documentation for the go-ora package你说你正在使用:

parameters in oracle should start with : for example :pr1

所以你的stmt应该是:

SELECT requestnumber, requeststatus, NVL(requestor, 'N/A'), NVL(pendingwith, 'N/A'), NVL(processtype, 'N/A'), actiondate
FROM requests WHERE requeststatus = 'PENDINGAPPROVAL'
ORDER BY :sortby :sortorder OFFSET :startindex ROWS FETCH NEXT :pagesize ROWS ONLY

但是除了变量之外你不能绑定(bind)任何东西,所以它根本不允许你将 sortorder 作为变量,如果你只是删除它并执行以下操作:

ORDER BY :sortby OFFSET :startindex ROWS FETCH NEXT :pagesize ROWS ONLY

这似乎可以工作,但即使这样也不能完全达到您想要的效果,因为排序将按文字列名称而不是它的值进行排序;因此它的运行方式相当于 ORDER BY 'requestnumber' 而不是 ORDER BY requestnumber。并且按该常量字符串排序不会实现任何目标。

您需要在语句中嵌入订购标准:

"... ORDER BY " + sortby + " " + sortorder + " OFFSET :startindex ROWS FETCH NEXT :pagesize ROWS ONLY"

db<>fiddle使用 PL/SQL 动态游标作为简化的等效项,显示三个版本 - 一个出错,一个未按预期排序,最后正确排序。

但是您还需要清理这些输入以再次防止 SQL 注入(inject)。

关于sql - 如何解决Golang中的错误 "ORA-00911: invalid character"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77227390/

相关文章:

sql - 运行时错误: Invalid parameter 1 specified for datepart - VBA - SQL

oracle - PIVOT 的替代方法 - IN 支持子查询

oracle - 为什么Oracle 的v$reserved_words View 中有两个 "null"关键字?

go - 通过引用更改 slice

go - 仅当 []struct 不为空时才继续

sql - 生成优惠券代码时感到困惑

sql - 在防止 SQL 注入(inject)时,PG::Connection#exec_params 是否与使用准备好的语句相同?

sql - 如何根据字段值加入变量表?

添加默认不可为空列时的 Oracle 错误

go - strings.Split 从不返回 nil 或零长度 slice ?