ComPrepareParsed implements the Handler interface.
(ctx context.Context, c *mysql.Conn, query string, parsed tree.Statement)
| 131 | |
| 132 | return err |
| 133 | } |
| 134 | |
| 135 | // ComPrepareParsed implements the Handler interface. |
| 136 | func (h *DuckHandler) ComPrepareParsed(ctx context.Context, c *mysql.Conn, query string, parsed tree.Statement) (*duckdb.Stmt, []uint32, []pgproto3.FieldDescription, error) { |
| 137 | if err := h.rejectReadOnly(ConvertedStatement{String: query, AST: parsed}); err != nil { |
| 138 | return nil, nil, nil, err |
| 139 | } |
| 140 | // DuckDB's official Go binding exposes prepared statement parameter types but not result types. |
| 141 | // 1. For SELECT statements, we will supply all NULL values as parameters |
| 142 | // to execute the query with a LIMIT 0 to get the result types. |
| 143 | // 2. For SHOW/CALL/PRAGMA statements, we will just execute the query and get the result types |
| 144 | // because they usually don't have parameters and are efficient to execute. |
| 145 | // 3. For other statements (DDLs and DMLs), we just return the "affected rows" field. |
| 146 | sqlCtx, err := h.sm.NewContextWithQuery(ctx, c, query) |
| 147 | if err != nil { |
| 148 | return nil, nil, nil, err |
| 149 | } |
| 150 | |
| 151 | conn, err := adapter.GetConn(sqlCtx) |
| 152 | if err != nil { |
| 153 | return nil, nil, nil, err |
| 154 | } |
| 155 | |
| 156 | var ( |
| 157 | stmt *duckdb.Stmt |
| 158 | stmtType duckdb.StmtType |
| 159 | paramTypes []duckdb.Type |
| 160 | ) |
| 161 | // This is a bit of a hack to get DuckDB's underlying prepared statement. |
| 162 | // But we know that the connection is a DuckDB connection and it is kept alive. |
| 163 | err = conn.Raw(func(driverConn interface{}) error { |
| 164 | dc := driverConn.(*duckdb.Conn) |
| 165 | s, err := dc.PrepareContext(sqlCtx, query) |
| 166 | if err != nil { |
| 167 | return err |
| 168 | } |
| 169 | n := s.NumInput() |
| 170 | stmt = s.(*duckdb.Stmt) |
| 171 | stmtType, err = stmt.StatementType() |
| 172 | if err != nil { |
| 173 | return err |
| 174 | } |
| 175 | paramTypes = make([]duckdb.Type, n) |
| 176 | for i := 0; i < n; i++ { |
| 177 | paramTypes[i], err = stmt.ParamType(i + 1) // 1-based index |
| 178 | if err != nil { |
| 179 | return err |
| 180 | } |
| 181 | } |
| 182 | return nil |
| 183 | }) |
| 184 | if err != nil { |
| 185 | logrus.WithField("query", query).Errorf("unable to prepare query: %s", err.Error()) |
| 186 | return nil, nil, nil, err |
| 187 | } |
| 188 | |
| 189 | paramOIDs := make([]uint32, len(paramTypes)) |
| 190 | for i, t := range paramTypes { |
nothing calls this directly
no test coverage detected