示例#1
0
文件: ses.go 项目: rjammala/ora
// 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
}
示例#2
0
// 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
}