// Prep prepares a sql statement returning a *Stmt and possible error. func (ses *Ses) Prep(sql string, gcts ...GoColumnType) (stmt *Stmt, err error) { ses.mu.Lock() defer ses.mu.Unlock() defer func() { if value := recover(); value != nil { err = errR(value) } }() ses.log(_drv.cfg.Log.Ses.Prep, sql) err = ses.checkClosed() if err != nil { return nil, errE(err) } // allocate statement handle upOciStmt, err := ses.srv.env.allocOciHandle(C.OCI_HTYPE_STMT) if err != nil { return nil, errE(err) } ocistmt := (*C.OCIStmt)(upOciStmt) cSql := C.CString(sql) // prepare sql text with statement handle defer C.free(unsafe.Pointer(cSql)) r := C.OCIStmtPrepare2( ses.srv.ocisvcctx, // OCISvcCtx *svchp, &ocistmt, // OCIStmt *stmtp, ses.srv.env.ocierr, // OCIError *errhp, (*C.OraText)(unsafe.Pointer(cSql)), // const OraText *stmt, C.ub4(len(sql)), // ub4 stmt_len, nil, // const OraText *key, C.ub4(0), // ub4 keylen, C.OCI_NTV_SYNTAX, // ub4 language, C.OCI_DEFAULT) // ub4 mode ); if r == C.OCI_ERROR { return nil, errE(ses.srv.env.ociError()) } // set stmt struct stmt = _drv.stmtPool.Get().(*Stmt) stmt.ses = ses stmt.ocistmt = (*C.OCIStmt)(ocistmt) stmtCfg := ses.cfg.StmtCfg if stmtCfg == nil { stmtCfg = NewStmtCfg() } if !ses.srv.dbIsUTF8 && stmtCfg.stringPtrBufferSize > 1000 { stmtCfg.stringPtrBufferSize = 1000 } stmt.cfg = *stmtCfg stmt.sql = sql stmt.gcts = gcts if stmt.id == 0 { stmt.id = _drv.stmtId.nextId() } err = stmt.attr(unsafe.Pointer(&stmt.stmtType), 4, C.OCI_ATTR_STMT_TYPE) // determine statement type if err != nil { return nil, errE(err) } ses.openStmts.add(stmt) return stmt, nil }
// Internal method for preparing a statement for execution. func (cur *Cursor) internalPrepare(statement string, statementTag string) error { // make sure we don't get a situation where nothing is to be executed if statement == "" && cur.statement == nil { return ProgrammingError("no statement specified and no prior statement prepared") } // but go ahead and prepare anyway for create, alter and drop statments if statement == "" || statement == string(cur.statement) { // FIXME why would double prepare be good?? if statementTag == "" || statementTag == string(cur.statementTag) { return nil } if !cur.IsDDL() { return nil } if statement == "" { statement = string(cur.statement) } } // keep track of the statement cur.statement = []byte(statement) if statementTag == "" { cur.statementTag = hashTag(cur.statement) } else { cur.statementTag = []byte(statementTag) } // release existing statement, if necessary if err := cur.freeHandle(); err != nil { return err } // prepare statement cur.isOwned = false debug(`%p.Prepare2 for "%s" [%x]`, cur, cur.statement, cur.statementTag) // Py_BEGIN_ALLOW_THREADS if CTrace { ctrace("OCIStmtPrepare2", cur.connection.handle, &cur.handle, cur.environment.errorHandle, string(bytes.Replace(cur.statement, []byte{'\n'}, []byte("\\n"), -1)), len(cur.statement), cur.statementTag, len(cur.statementTag), "NTV_SYNTAX", "DEFAULT") } if err := cur.environment.CheckStatus( C.OCIStmtPrepare2(cur.connection.handle, &cur.handle, cur.environment.errorHandle, (*C.OraText)(unsafe.Pointer(&cur.statement[0])), C.ub4(len(cur.statement)), (*C.OraText)(unsafe.Pointer(&cur.statementTag[0])), C.ub4(len(cur.statementTag)), C.OCI_NTV_SYNTAX, C.OCI_DEFAULT), "internalPrepare"); err != nil { // Py_END_ALLOW_THREADS // this is needed to avoid "invalid handle" errors since Oracle doesn't // seem to leave the pointer alone when an error is raised but the // resulting handle is still invalid cur.handle = nil return err } // debug("prepared") // clear bind variables, if applicable if cur.setInputSizes < 0 { cur.bindVarsArr = nil cur.bindVarsMap = nil } // clear row factory, if applicable // cur.rowFactory = nil // determine if statement is a query if err := cur.getStatementType(); err != nil { return err } return nil }