#include "dpiImpl.h"
static int dpiStmt__getQueryInfo(dpiStmt *stmt, uint32_t pos,
dpiQueryInfo *info, dpiError *error);
static int dpiStmt__getQueryInfoFromParam(dpiStmt *stmt, void *param,
dpiQueryInfo *info, dpiError *error);
static int dpiStmt__postFetch(dpiStmt *stmt, dpiError *error);
static int dpiStmt__beforeFetch(dpiStmt *stmt, dpiError *error);
static int dpiStmt__reExecute(dpiStmt *stmt, uint32_t numIters,
uint32_t mode, dpiError *error);
int dpiStmt__allocate(dpiConn *conn, int scrollable, dpiStmt **stmt,
dpiError *error)
{
dpiStmt *tempStmt;
*stmt = NULL;
if (dpiGen__allocate(DPI_HTYPE_STMT, conn->env, (void**) &tempStmt,
error) < 0)
return DPI_FAILURE;
dpiGen__setRefCount(conn, error, 1);
tempStmt->conn = conn;
tempStmt->fetchArraySize = DPI_DEFAULT_FETCH_ARRAY_SIZE;
tempStmt->prefetchRows = DPI_DEFAULT_PREFETCH_ROWS;
tempStmt->scrollable = scrollable;
*stmt = tempStmt;
return DPI_SUCCESS;
}
static int dpiStmt__bind(dpiStmt *stmt, dpiVar *var, uint32_t pos,
const char *name, uint32_t nameLength, dpiError *error)
{
dpiBindVar *bindVars, *entry = NULL;
int found, dynamicBind, status;
void *bindHandle = NULL;
uint32_t i;
if (pos == 0 && nameLength == 0)
return dpiError__set(error, "bind zero length name",
DPI_ERR_NOT_SUPPORTED);
if (var->type->oracleTypeNum == DPI_ORACLE_TYPE_STMT) {
for (i = 0; i < var->buffer.maxArraySize; i++) {
if (var->buffer.externalData[i].value.asStmt == stmt) {
return dpiError__set(error, "bind to self",
DPI_ERR_NOT_SUPPORTED);
}
}
}
found = 0;
for (i = 0; i < stmt->numBindVars; i++) {
entry = &stmt->bindVars[i];
if (entry->pos == pos && entry->nameLength == nameLength) {
if (nameLength > 0 && strncmp(entry->name, name, nameLength) != 0)
continue;
found = 1;
break;
}
}
if (found) {
if (entry->var == var)
return DPI_SUCCESS;
else if (entry->var) {
dpiGen__setRefCount(entry->var, error, -1);
entry->var = NULL;
}
} else {
if (stmt->numBindVars == stmt->allocatedBindVars) {
if (dpiUtils__allocateMemory(stmt->allocatedBindVars + 8,
sizeof(dpiBindVar), 1, "allocate bind vars",
(void**) &bindVars, error) < 0)
return DPI_FAILURE;
if (stmt->bindVars) {
for (i = 0; i < stmt->numBindVars; i++)
bindVars[i] = stmt->bindVars[i];
dpiUtils__freeMemory(stmt->bindVars);
}
stmt->bindVars = bindVars;
stmt->allocatedBindVars += 8;
}
entry = &stmt->bindVars[stmt->numBindVars];
entry->var = NULL;
entry->pos = pos;
if (name) {
if (dpiUtils__allocateMemory(1, nameLength, 0,
"allocate memory for name", (void**) &entry->name,
error) < 0)
return DPI_FAILURE;
entry->nameLength = nameLength;
memcpy( (void*) entry->name, name, nameLength);
}
stmt->numBindVars++;
}
if (var->isDynamic && (stmt->statementType == DPI_STMT_TYPE_BEGIN ||
stmt->statementType == DPI_STMT_TYPE_DECLARE ||
stmt->statementType == DPI_STMT_TYPE_CALL)) {
if (dpiVar__convertToLob(var, error) < 0)
return DPI_FAILURE;
}
dpiGen__setRefCount(var, error, 1);
entry->var = var;
dynamicBind = stmt->isReturning || var->isDynamic;
if (pos > 0) {
if (stmt->env->versionInfo->versionNum < 12)
status = dpiOci__bindByPos(stmt, &bindHandle, pos, dynamicBind,
var, error);
else status = dpiOci__bindByPos2(stmt, &bindHandle, pos, dynamicBind,
var, error);
} else {
if (stmt->env->versionInfo->versionNum < 12)
status = dpiOci__bindByName(stmt, &bindHandle, name,
(int32_t) nameLength, dynamicBind, var, error);
else status = dpiOci__bindByName2(stmt, &bindHandle, name,
(int32_t) nameLength, dynamicBind, var, error);
}
if (status < 0) {
if (error->buffer->code == 1036) {
if (stmt->statementType == DPI_STMT_TYPE_CREATE ||
stmt->statementType == DPI_STMT_TYPE_DROP ||
stmt->statementType == DPI_STMT_TYPE_ALTER)
dpiError__set(error, error->buffer->action,
DPI_ERR_NO_BIND_VARS_IN_DDL);
}
return DPI_FAILURE;
}
if (var->type->charsetForm != DPI_SQLCS_IMPLICIT) {
if (dpiOci__attrSet(bindHandle, DPI_OCI_HTYPE_BIND,
(void*) &var->type->charsetForm, 0, DPI_OCI_ATTR_CHARSET_FORM,
"set charset form", error) < 0)
return DPI_FAILURE;
}
if (var->type->sizeInBytes == 0 && !var->isDynamic) {
if (dpiOci__attrSet(bindHandle, DPI_OCI_HTYPE_BIND,
(void*) &var->sizeInBytes, 0, DPI_OCI_ATTR_MAXDATA_SIZE,
"set max data size", error) < 0)
return DPI_FAILURE;
}
if (var->buffer.objectIndicator &&
dpiOci__bindObject(var, bindHandle, error) < 0)
return DPI_FAILURE;
if (dynamicBind && dpiOci__bindDynamic(var, bindHandle, error) < 0)
return DPI_FAILURE;
return DPI_SUCCESS;
}
static int dpiStmt__check(dpiStmt *stmt, const char *fnName, dpiError *error)
{
if (dpiGen__startPublicFn(stmt, DPI_HTYPE_STMT, fnName, error) < 0)
return DPI_FAILURE;
if (!stmt->handle || (stmt->parentStmt && !stmt->parentStmt->handle))
return dpiError__set(error, "check closed", DPI_ERR_STMT_CLOSED);
if (dpiConn__checkConnected(stmt->conn, error) < 0)
return DPI_FAILURE;
if (stmt->statementType == 0 && dpiStmt__init(stmt, error) < 0)
return DPI_FAILURE;
return DPI_SUCCESS;
}
static void dpiStmt__clearBatchErrors(dpiStmt *stmt)
{
if (stmt->batchErrors) {
dpiUtils__freeMemory(stmt->batchErrors);
stmt->batchErrors = NULL;
}
stmt->numBatchErrors = 0;
}
static void dpiStmt__clearBindVars(dpiStmt *stmt, dpiError *error)
{
uint32_t i;
if (stmt->bindVars) {
for (i = 0; i < stmt->numBindVars; i++) {
if (stmt->bindVars[i].var)
dpiGen__setRefCount(stmt->bindVars[i].var, error, -1);
if (stmt->bindVars[i].name)
dpiUtils__freeMemory( (void*) stmt->bindVars[i].name);
}
dpiUtils__freeMemory(stmt->bindVars);
stmt->bindVars = NULL;
}
stmt->numBindVars = 0;
stmt->allocatedBindVars = 0;
}
static void dpiStmt__clearQueryVars(dpiStmt *stmt, dpiError *error)
{
dpiDataTypeInfo *typeInfo;
uint32_t i;
if (stmt->queryVars) {
for (i = 0; i < stmt->numQueryVars; i++) {
if (stmt->queryVars[i]) {
dpiGen__setRefCount(stmt->queryVars[i], error, -1);
stmt->queryVars[i] = NULL;
}
typeInfo = &stmt->queryInfo[i].typeInfo;
if (typeInfo->objectType) {
dpiGen__setRefCount(typeInfo->objectType, error, -1);
typeInfo->objectType = NULL;
}
if (typeInfo->annotations) {
dpiUtils__freeMemory(typeInfo->annotations);
typeInfo->annotations = NULL;
}
}
dpiUtils__freeMemory(stmt->queryVars);
stmt->queryVars = NULL;
}
if (stmt->queryInfo) {
dpiUtils__freeMemory(stmt->queryInfo);
stmt->queryInfo = NULL;
}
stmt->numQueryVars = 0;
}
int dpiStmt__close(dpiStmt *stmt, const char *tag, uint32_t tagLength,
int propagateErrors, dpiError *error)
{
int closing, status = DPI_SUCCESS;
if (stmt->env->threaded)
dpiMutex__acquire(stmt->env->mutex);
closing = stmt->closing;
stmt->closing = 1;
if (stmt->env->threaded)
dpiMutex__release(stmt->env->mutex);
if (closing)
return DPI_SUCCESS;
dpiStmt__clearBatchErrors(stmt);
dpiStmt__clearBindVars(stmt, error);
dpiStmt__clearQueryVars(stmt, error);
if (stmt->lastRowid)
dpiGen__setRefCount(stmt->lastRowid, error, -1);
if (stmt->handle) {
if (stmt->parentStmt) {
dpiGen__setRefCount(stmt->parentStmt, error, -1);
stmt->parentStmt = NULL;
} else if (!stmt->conn->deadSession && stmt->conn->handle) {
if (stmt->isOwned)
dpiOci__handleFree(stmt->handle, DPI_OCI_HTYPE_STMT);
else status = dpiOci__stmtRelease(stmt, tag, tagLength,
propagateErrors, error);
}
if (!stmt->conn->closing && !stmt->parentStmt)
dpiHandleList__removeHandle(stmt->conn->openStmts,
stmt->openSlotNum);
stmt->handle = NULL;
}
if (status < 0) {
if (stmt->env->threaded)
dpiMutex__acquire(stmt->env->mutex);
stmt->closing = 0;
if (stmt->env->threaded)
dpiMutex__release(stmt->env->mutex);
}
return status;
}
static int dpiStmt__createBindVar(dpiStmt *stmt,
dpiNativeTypeNum nativeTypeNum, dpiData *data, dpiVar **var,
uint32_t pos, const char *name, uint32_t nameLength, dpiError *error)
{
dpiOracleTypeNum oracleTypeNum;
dpiObjectType *objType;
dpiData *varData;
dpiVar *tempVar;
uint32_t size;
int status;
size = 0;
objType = NULL;
switch (nativeTypeNum) {
case DPI_NATIVE_TYPE_INT64:
case DPI_NATIVE_TYPE_UINT64:
case DPI_NATIVE_TYPE_FLOAT:
case DPI_NATIVE_TYPE_DOUBLE:
oracleTypeNum = DPI_ORACLE_TYPE_NUMBER;
break;
case DPI_NATIVE_TYPE_BYTES:
oracleTypeNum = DPI_ORACLE_TYPE_VARCHAR;
size = data->value.asBytes.length;
break;
case DPI_NATIVE_TYPE_TIMESTAMP:
oracleTypeNum = DPI_ORACLE_TYPE_TIMESTAMP;
break;
case DPI_NATIVE_TYPE_INTERVAL_DS:
oracleTypeNum = DPI_ORACLE_TYPE_INTERVAL_DS;
break;
case DPI_NATIVE_TYPE_INTERVAL_YM:
oracleTypeNum = DPI_ORACLE_TYPE_INTERVAL_YM;
break;
case DPI_NATIVE_TYPE_OBJECT:
oracleTypeNum = DPI_ORACLE_TYPE_OBJECT;
if (data->value.asObject)
objType = data->value.asObject->type;
break;
case DPI_NATIVE_TYPE_ROWID:
oracleTypeNum = DPI_ORACLE_TYPE_ROWID;
break;
case DPI_NATIVE_TYPE_BOOLEAN:
oracleTypeNum = DPI_ORACLE_TYPE_BOOLEAN;
break;
default:
return dpiError__set(error, "create bind var",
DPI_ERR_UNHANDLED_CONVERSION, 0, nativeTypeNum);
}
if (dpiVar__allocate(stmt->conn, oracleTypeNum, nativeTypeNum, 1, size, 1,
0, objType, &tempVar, &varData, error) < 0)
return DPI_FAILURE;
if (dpiVar__copyData(tempVar, 0, data, error) < 0)
return DPI_FAILURE;
status = dpiStmt__bind(stmt, tempVar, pos, name, nameLength, error);
dpiGen__setRefCount(tempVar, error, -1);
if (status == DPI_SUCCESS)
*var = tempVar;
return status;
}
static int dpiStmt__createQueryVars(dpiStmt *stmt, dpiError *error)
{
uint32_t numQueryVars, i;
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT,
(void*) &numQueryVars, 0, DPI_OCI_ATTR_PARAM_COUNT,
"get parameter count", error) < 0)
return DPI_FAILURE;
if (stmt->numQueryVars > 0 && stmt->numQueryVars != numQueryVars)
dpiStmt__clearQueryVars(stmt, error);
if (numQueryVars != stmt->numQueryVars) {
if (dpiUtils__allocateMemory(numQueryVars, sizeof(dpiVar*), 1,
"allocate query vars", (void**) &stmt->queryVars, error) < 0)
return DPI_FAILURE;
if (dpiUtils__allocateMemory(numQueryVars, sizeof(dpiQueryInfo), 1,
"allocate query info", (void**) &stmt->queryInfo, error) < 0) {
dpiStmt__clearQueryVars(stmt, error);
return DPI_FAILURE;
}
stmt->numQueryVars = numQueryVars;
for (i = 0; i < numQueryVars; i++) {
if (dpiStmt__getQueryInfo(stmt, i + 1, &stmt->queryInfo[i],
error) < 0) {
dpiStmt__clearQueryVars(stmt, error);
return DPI_FAILURE;
}
}
}
stmt->bufferRowIndex = stmt->fetchArraySize;
stmt->hasRowsToFetch = 1;
return DPI_SUCCESS;
}
static int dpiStmt__define(dpiStmt *stmt, uint32_t pos, dpiVar *var,
dpiError *error)
{
void *defineHandle = NULL;
dpiQueryInfo *queryInfo;
int tempBool;
if (stmt->queryVars[pos - 1] == var)
return DPI_SUCCESS;
queryInfo = &stmt->queryInfo[pos - 1];
if (var->objectType && queryInfo->typeInfo.objectType &&
var->objectType->tdo != queryInfo->typeInfo.objectType->tdo)
return dpiError__set(error, "check type", DPI_ERR_WRONG_TYPE,
var->objectType->schemaLength, var->objectType->schema,
var->objectType->nameLength, var->objectType->name,
queryInfo->typeInfo.objectType->schemaLength,
queryInfo->typeInfo.objectType->schema,
queryInfo->typeInfo.objectType->nameLength,
queryInfo->typeInfo.objectType->name);
if (stmt->env->versionInfo->versionNum < 12) {
if (dpiOci__defineByPos(stmt, &defineHandle, pos, var, error) < 0)
return DPI_FAILURE;
} else {
if (dpiOci__defineByPos2(stmt, &defineHandle, pos, var, error) < 0)
return DPI_FAILURE;
}
if (var->type->charsetForm != DPI_SQLCS_IMPLICIT) {
if (dpiOci__attrSet(defineHandle, DPI_OCI_HTYPE_DEFINE,
(void*) &var->type->charsetForm, 0, DPI_OCI_ATTR_CHARSET_FORM,
"set charset form", error) < 0)
return DPI_FAILURE;
}
if (var->nativeTypeNum == DPI_NATIVE_TYPE_LOB) {
tempBool = 1;
if (dpiOci__attrSet(defineHandle, DPI_OCI_HTYPE_DEFINE,
(void*) &tempBool, 0, DPI_OCI_ATTR_LOBPREFETCH_LENGTH,
"set lob prefetch length", error) < 0)
return DPI_FAILURE;
}
if (var->buffer.objectIndicator && dpiOci__defineObject(var, defineHandle,
error) < 0)
return DPI_FAILURE;
if (var->isDynamic && dpiOci__defineDynamic(var, defineHandle, error) < 0)
return DPI_FAILURE;
if (stmt->queryVars[pos - 1])
dpiGen__setRefCount(stmt->queryVars[pos - 1], error, -1);
dpiGen__setRefCount(var, error, 1);
stmt->queryVars[pos - 1] = var;
return DPI_SUCCESS;
}
static int dpiStmt__execute(dpiStmt *stmt, uint32_t numIters,
uint32_t mode, int reExecute, dpiError *error)
{
uint16_t tempOffset;
uint32_t i, j, temp;
dpiData *data;
dpiVar *var;
for (i = 0; i < stmt->numBindVars; i++) {
var = stmt->bindVars[i].var;
if (var->isArray && numIters > 1)
return dpiError__set(error, "bind array var",
DPI_ERR_ARRAY_VAR_NOT_SUPPORTED);
for (j = 0; j < var->buffer.maxArraySize; j++) {
data = &var->buffer.externalData[j];
if (dpiVar__setValue(var, &var->buffer, j, data, error) < 0)
return DPI_FAILURE;
if (var->dynBindBuffers)
var->dynBindBuffers[j].actualArraySize = 0;
}
if (stmt->isReturning || var->isDynamic)
var->error = error;
}
if (stmt->statementType == DPI_STMT_TYPE_SELECT) {
if (dpiOci__attrSet(stmt->handle, DPI_OCI_HTYPE_STMT,
&stmt->prefetchRows, sizeof(stmt->prefetchRows),
DPI_OCI_ATTR_PREFETCH_ROWS, "set prefetch rows", error) < 0)
return DPI_FAILURE;
}
dpiStmt__clearBatchErrors(stmt);
if (stmt->scrollable)
mode |= DPI_OCI_STMT_SCROLLABLE_READONLY;
if (dpiOci__stmtExecute(stmt, numIters, mode, error) < 0) {
dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, &tempOffset, 0,
DPI_OCI_ATTR_PARSE_ERROR_OFFSET, "set parse offset", error);
error->buffer->offset = tempOffset;
switch (error->buffer->code) {
case 932:
case 1007:
if (reExecute && stmt->statementType == DPI_STMT_TYPE_SELECT)
return dpiStmt__reExecute(stmt, numIters, mode, error);
stmt->deleteFromCache = 1;
break;
case 1:
case 1400:
case 1438:
case 1461:
case 2290:
case 2291:
case 2292:
case 21525:
break;
default:
stmt->deleteFromCache = 1;
}
return DPI_FAILURE;
}
if (stmt->statementType == DPI_STMT_TYPE_SELECT) {
temp = 0;
if (dpiOci__attrSet(stmt->handle, DPI_OCI_HTYPE_STMT, &temp,
sizeof(temp), DPI_OCI_ATTR_PREFETCH_ROWS,
"reset prefetch rows", error) < 0)
return DPI_FAILURE;
}
if (stmt->isReturning || stmt->statementType == DPI_STMT_TYPE_BEGIN ||
stmt->statementType == DPI_STMT_TYPE_DECLARE ||
stmt->statementType == DPI_STMT_TYPE_CALL) {
for (i = 0; i < stmt->numBindVars; i++) {
var = stmt->bindVars[i].var;
for (j = 0; j < var->buffer.maxArraySize; j++) {
if (dpiVar__getValue(var, &var->buffer, j, 0, error) < 0)
return DPI_FAILURE;
}
var->error = NULL;
}
}
if (stmt->statementType == DPI_STMT_TYPE_SELECT) {
stmt->rowCount = 0;
if (!(mode & DPI_MODE_EXEC_PARSE_ONLY) &&
dpiStmt__createQueryVars(stmt, error) < 0)
return DPI_FAILURE;
}
return DPI_SUCCESS;
}
static int dpiStmt__fetch(dpiStmt *stmt, dpiError *error)
{
if (dpiStmt__beforeFetch(stmt, error) < 0)
return DPI_FAILURE;
if (dpiOci__stmtFetch2(stmt, stmt->fetchArraySize, DPI_MODE_FETCH_NEXT, 0,
error) < 0)
return DPI_FAILURE;
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT,
&stmt->bufferRowCount, 0, DPI_OCI_ATTR_ROWS_FETCHED,
"get rows fetched", error) < 0)
return DPI_FAILURE;
stmt->bufferMinRow = stmt->rowCount + 1;
stmt->bufferRowIndex = 0;
if (dpiStmt__postFetch(stmt, error) < 0)
return DPI_FAILURE;
return DPI_SUCCESS;
}
void dpiStmt__free(dpiStmt *stmt, dpiError *error)
{
dpiStmt__close(stmt, NULL, 0, 0, error);
if (stmt->parentStmt) {
dpiGen__setRefCount(stmt->parentStmt, error, -1);
stmt->parentStmt = NULL;
}
if (stmt->conn) {
dpiGen__setRefCount(stmt->conn, error, -1);
stmt->conn = NULL;
}
dpiUtils__freeMemory(stmt);
}
static int dpiStmt__getBatchErrors(dpiStmt *stmt, dpiError *error)
{
void *batchErrorHandle, *localErrorHandle;
dpiError localError;
int overallStatus;
int32_t rowOffset;
uint32_t i;
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT,
&stmt->numBatchErrors, 0, DPI_OCI_ATTR_NUM_DML_ERRORS,
"get batch error count", error) < 0)
return DPI_FAILURE;
if (dpiUtils__allocateMemory(stmt->numBatchErrors, sizeof(dpiErrorBuffer),
1, "allocate errors", (void**) &stmt->batchErrors, error) < 0) {
stmt->numBatchErrors = 0;
return DPI_FAILURE;
}
if (dpiOci__handleAlloc(stmt->env->handle, &localErrorHandle,
DPI_OCI_HTYPE_ERROR, "allocate parameter error handle",
error) < 0) {
dpiStmt__clearBatchErrors(stmt);
return DPI_FAILURE;
}
if (dpiOci__handleAlloc(stmt->env->handle, &batchErrorHandle,
DPI_OCI_HTYPE_ERROR, "allocate batch error handle", error) < 0) {
dpiStmt__clearBatchErrors(stmt);
dpiOci__handleFree(localErrorHandle, DPI_OCI_HTYPE_ERROR);
return DPI_FAILURE;
}
overallStatus = DPI_SUCCESS;
localError.buffer = error->buffer;
localError.env = error->env;
for (i = 0; i < stmt->numBatchErrors; i++) {
if (dpiOci__paramGet(error->handle, DPI_OCI_HTYPE_ERROR,
&batchErrorHandle, i, "get batch error", error) < 0) {
overallStatus = dpiError__set(error, "get batch error",
DPI_ERR_INVALID_INDEX, i);
break;
}
localError.handle = localErrorHandle;
if (dpiOci__attrGet(batchErrorHandle, DPI_OCI_HTYPE_ERROR, &rowOffset,
0, DPI_OCI_ATTR_DML_ROW_OFFSET, "get row offset",
&localError) < 0) {
overallStatus = dpiError__set(error, "get row offset",
DPI_ERR_CANNOT_GET_ROW_OFFSET);
break;
}
localError.buffer = &stmt->batchErrors[i];
localError.handle = batchErrorHandle;
dpiError__setFromOCI(&localError, DPI_OCI_ERROR, stmt->conn,
"get batch error");
if (error->buffer->errorNum) {
overallStatus = DPI_FAILURE;
break;
}
localError.buffer->fnName = error->buffer->fnName;
localError.buffer->offset = (uint32_t) rowOffset;
}
dpiOci__handleFree(localErrorHandle, DPI_OCI_HTYPE_ERROR);
dpiOci__handleFree(batchErrorHandle, DPI_OCI_HTYPE_ERROR);
if (overallStatus < 0)
dpiStmt__clearBatchErrors(stmt);
return overallStatus;
}
static int dpiStmt__getRowCount(dpiStmt *stmt, uint64_t *count,
dpiError *error)
{
uint32_t rowCount32;
if (stmt->statementType == DPI_STMT_TYPE_SELECT)
*count = stmt->rowCount;
else if (stmt->statementType != DPI_STMT_TYPE_INSERT &&
stmt->statementType != DPI_STMT_TYPE_UPDATE &&
stmt->statementType != DPI_STMT_TYPE_DELETE &&
stmt->statementType != DPI_STMT_TYPE_MERGE &&
stmt->statementType != DPI_STMT_TYPE_CALL &&
stmt->statementType != DPI_STMT_TYPE_BEGIN &&
stmt->statementType != DPI_STMT_TYPE_DECLARE) {
*count = 0;
} else if (stmt->env->versionInfo->versionNum < 12) {
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, &rowCount32, 0,
DPI_OCI_ATTR_ROW_COUNT, "get row count", error) < 0)
return DPI_FAILURE;
*count = rowCount32;
} else {
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, count, 0,
DPI_OCI_ATTR_UB8_ROW_COUNT, "get row count", error) < 0)
return DPI_FAILURE;
}
return DPI_SUCCESS;
}
static int dpiStmt__getQueryInfo(dpiStmt *stmt, uint32_t pos,
dpiQueryInfo *info, dpiError *error)
{
void *param;
int status;
if (dpiOci__paramGet(stmt->handle, DPI_OCI_HTYPE_STMT, ¶m, pos,
"get parameter", error) < 0)
return DPI_FAILURE;
status = dpiStmt__getQueryInfoFromParam(stmt, param, info, error);
dpiOci__descriptorFree(param, DPI_OCI_DTYPE_PARAM);
return status;
}
static int dpiStmt__getQueryInfoFromParam(dpiStmt *stmt, void *param,
dpiQueryInfo *info, dpiError *error)
{
uint8_t ociNullOk;
if (dpiOci__attrGet(param, DPI_OCI_HTYPE_DESCRIBE, (void*) &info->name,
&info->nameLength, DPI_OCI_ATTR_NAME, "get name", error) < 0)
return DPI_FAILURE;
if (dpiOracleType__populateTypeInfo(stmt->conn, param,
DPI_OCI_HTYPE_DESCRIBE, &info->typeInfo, error) < 0)
return DPI_FAILURE;
if (dpiOci__attrGet(param, DPI_OCI_HTYPE_DESCRIBE, (void*) &ociNullOk, 0,
DPI_OCI_ATTR_IS_NULL, "get null ok", error) < 0)
return DPI_FAILURE;
info->nullOk = ociNullOk;
return DPI_SUCCESS;
}
int dpiStmt__init(dpiStmt *stmt, dpiError *error)
{
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT,
(void*) &stmt->statementType, 0, DPI_OCI_ATTR_STMT_TYPE,
"get statement type", error) < 0)
return DPI_FAILURE;
if (stmt->statementType == DPI_STMT_TYPE_SELECT)
stmt->hasRowsToFetch = 1;
else if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT,
(void*) &stmt->isReturning, 0, DPI_OCI_ATTR_STMT_IS_RETURNING,
"get is returning", error) < 0)
return DPI_FAILURE;
return DPI_SUCCESS;
}
static int dpiStmt__postFetch(dpiStmt *stmt, dpiError *error)
{
uint32_t i, j;
dpiVar *var;
for (i = 0; i < stmt->numQueryVars; i++) {
var = stmt->queryVars[i];
for (j = 0; j < stmt->bufferRowCount; j++) {
if (dpiVar__getValue(var, &var->buffer, j, 1, error) < 0)
return DPI_FAILURE;
if (var->type->requiresPreFetch)
var->requiresPreFetch = 1;
}
var->error = NULL;
}
return DPI_SUCCESS;
}
static int dpiStmt__beforeFetch(dpiStmt *stmt, dpiError *error)
{
dpiQueryInfo *queryInfo;
dpiData *data;
dpiVar *var;
uint32_t i;
if (!stmt->queryInfo && dpiStmt__createQueryVars(stmt, error) < 0)
return DPI_FAILURE;
for (i = 0; i < stmt->numQueryVars; i++) {
var = stmt->queryVars[i];
if (!var) {
queryInfo = &stmt->queryInfo[i];
if (dpiVar__allocate(stmt->conn, queryInfo->typeInfo.oracleTypeNum,
queryInfo->typeInfo.defaultNativeTypeNum,
stmt->fetchArraySize,
queryInfo->typeInfo.clientSizeInBytes, 1, 0,
queryInfo->typeInfo.objectType, &var, &data, error) < 0)
return DPI_FAILURE;
if (dpiStmt__define(stmt, i + 1, var, error) < 0)
return DPI_FAILURE;
dpiGen__setRefCount(var, error, -1);
}
var->error = error;
if (stmt->fetchArraySize > var->buffer.maxArraySize)
return dpiError__set(error, "check array size",
DPI_ERR_ARRAY_SIZE_TOO_SMALL, var->buffer.maxArraySize);
if (var->requiresPreFetch && dpiVar__extendedPreFetch(var,
&var->buffer, error) < 0)
return DPI_FAILURE;
}
return DPI_SUCCESS;
}
int dpiStmt__prepare(dpiStmt *stmt, const char *sql, uint32_t sqlLength,
const char *tag, uint32_t tagLength, dpiError *error)
{
if (sql && dpiDebugLevel & DPI_DEBUG_LEVEL_SQL)
dpiDebug__print("SQL %.*s\n", sqlLength, sql);
if (dpiOci__stmtPrepare2(stmt, sql, sqlLength, tag, tagLength, error) < 0)
return DPI_FAILURE;
if (dpiHandleList__addHandle(stmt->conn->openStmts, stmt,
&stmt->openSlotNum, error) < 0) {
dpiOci__stmtRelease(stmt, NULL, 0, 0, error);
stmt->handle = NULL;
return DPI_FAILURE;
}
return dpiStmt__init(stmt, error);
}
static int dpiStmt__reExecute(dpiStmt *stmt, uint32_t numIters,
uint32_t mode, dpiError *error)
{
void *origHandle, *newHandle;
uint32_t sqlLength, i;
dpiError localError;
dpiBindVar *bindVar;
dpiVar *var;
int status;
char *sql;
localError.buffer = error->buffer;
localError.env = error->env;
localError.handle = error->handle;
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, (void*) &sql,
&sqlLength, DPI_OCI_ATTR_STATEMENT, "get statement",
&localError) < 0)
return DPI_FAILURE;
origHandle = stmt->handle;
status = dpiOci__stmtPrepare2(stmt, sql, sqlLength, NULL, 0, &localError);
newHandle = stmt->handle;
stmt->handle = origHandle;
stmt->deleteFromCache = 1;
if (dpiOci__stmtRelease(stmt, NULL, 0, 1, &localError) < 0 || status < 0)
return DPI_FAILURE;
stmt->handle = newHandle;
dpiStmt__clearBatchErrors(stmt);
dpiStmt__clearQueryVars(stmt, error);
for (i = 0; i < stmt->numBindVars; i++) {
bindVar = &stmt->bindVars[i];
if (!bindVar->var)
continue;
var = bindVar->var;
bindVar->var = NULL;
if (dpiStmt__bind(stmt, var, bindVar->pos, bindVar->name,
bindVar->nameLength, error) < 0) {
dpiGen__setRefCount(var, error, -1);
return DPI_FAILURE;
}
}
return dpiStmt__execute(stmt, numIters, mode, 0, error);
}
int dpiStmt_addRef(dpiStmt *stmt)
{
return dpiGen__addRef(stmt, DPI_HTYPE_STMT, __func__);
}
int dpiStmt_bindByName(dpiStmt *stmt, const char *name, uint32_t nameLength,
dpiVar *var)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, name)
if (dpiGen__checkHandle(var, DPI_HTYPE_VAR, "bind by name", &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
status = dpiStmt__bind(stmt, var, 0, name, nameLength, &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_bindByPos(dpiStmt *stmt, uint32_t pos, dpiVar *var)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (dpiGen__checkHandle(var, DPI_HTYPE_VAR, "bind by pos", &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
status = dpiStmt__bind(stmt, var, pos, NULL, 0, &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_bindValueByName(dpiStmt *stmt, const char *name,
uint32_t nameLength, dpiNativeTypeNum nativeTypeNum, dpiData *data)
{
dpiVar *var = NULL;
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, name)
DPI_CHECK_PTR_NOT_NULL(stmt, data)
status = dpiStmt__createBindVar(stmt, nativeTypeNum, data, &var, 0, name,
nameLength, &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_bindValueByPos(dpiStmt *stmt, uint32_t pos,
dpiNativeTypeNum nativeTypeNum, dpiData *data)
{
dpiVar *var = NULL;
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, data)
status = dpiStmt__createBindVar(stmt, nativeTypeNum, data, &var, pos, NULL,
0, &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_close(dpiStmt *stmt, const char *tag, uint32_t tagLength)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_AND_LENGTH(stmt, tag)
status = dpiStmt__close(stmt, tag, tagLength, 1, &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_define(dpiStmt *stmt, uint32_t pos, dpiVar *var)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (!stmt->queryInfo && dpiStmt__createQueryVars(stmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (pos == 0 || pos > stmt->numQueryVars) {
dpiError__set(&error, "check query position",
DPI_ERR_QUERY_POSITION_INVALID, pos);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
if (dpiGen__checkHandle(var, DPI_HTYPE_VAR, "check variable", &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
status = dpiStmt__define(stmt, pos, var, &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_defineValue(dpiStmt *stmt, uint32_t pos,
dpiOracleTypeNum oracleTypeNum, dpiNativeTypeNum nativeTypeNum,
uint32_t size, int sizeIsBytes, dpiObjectType *objType)
{
dpiError error;
dpiData *data;
dpiVar *var;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (!stmt->queryInfo && dpiStmt__createQueryVars(stmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (pos == 0 || pos > stmt->numQueryVars) {
dpiError__set(&error, "check query position",
DPI_ERR_QUERY_POSITION_INVALID, pos);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
if (dpiVar__allocate(stmt->conn, oracleTypeNum, nativeTypeNum,
stmt->fetchArraySize, size, sizeIsBytes, 0, objType, &var, &data,
&error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (dpiStmt__define(stmt, pos, var, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
dpiGen__setRefCount(var, &error, -1);
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_execute(dpiStmt *stmt, dpiExecMode mode, uint32_t *numQueryColumns)
{
uint32_t numIters;
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
numIters = (stmt->statementType == DPI_STMT_TYPE_SELECT) ? 0 : 1;
if (dpiStmt__execute(stmt, numIters, mode, 1, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (numQueryColumns)
*numQueryColumns = stmt->numQueryVars;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_executeMany(dpiStmt *stmt, dpiExecMode mode, uint32_t numIters)
{
dpiError error;
uint32_t i;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (stmt->statementType == DPI_STMT_TYPE_SELECT) {
dpiError__set(&error, "check statement type", DPI_ERR_NOT_SUPPORTED);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
if ((mode & DPI_MODE_EXEC_BATCH_ERRORS ||
mode & DPI_MODE_EXEC_ARRAY_DML_ROWCOUNTS) &&
stmt->statementType != DPI_STMT_TYPE_INSERT &&
stmt->statementType != DPI_STMT_TYPE_UPDATE &&
stmt->statementType != DPI_STMT_TYPE_DELETE &&
stmt->statementType != DPI_STMT_TYPE_MERGE) {
dpiError__set(&error, "check mode", DPI_ERR_EXEC_MODE_ONLY_FOR_DML);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
for (i = 0; i < stmt->numBindVars; i++) {
if (stmt->bindVars[i].var->buffer.maxArraySize < numIters) {
dpiError__set(&error, "check array size",
DPI_ERR_ARRAY_SIZE_TOO_SMALL,
stmt->bindVars[i].var->buffer.maxArraySize);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
}
dpiStmt__clearBatchErrors(stmt);
if (dpiStmt__execute(stmt, numIters, mode, 0, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (mode & DPI_MODE_EXEC_BATCH_ERRORS) {
if (dpiStmt__getBatchErrors(stmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_fetch(dpiStmt *stmt, int *found, uint32_t *bufferRowIndex)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, found)
DPI_CHECK_PTR_NOT_NULL(stmt, bufferRowIndex)
if (stmt->bufferRowIndex >= stmt->bufferRowCount) {
if (stmt->hasRowsToFetch && dpiStmt__fetch(stmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (stmt->bufferRowIndex >= stmt->bufferRowCount) {
*found = 0;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
}
*found = 1;
*bufferRowIndex = stmt->bufferRowIndex;
stmt->bufferRowIndex++;
stmt->rowCount++;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_fetchRows(dpiStmt *stmt, uint32_t maxRows,
uint32_t *bufferRowIndex, uint32_t *numRowsFetched, int *moreRows)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, bufferRowIndex)
DPI_CHECK_PTR_NOT_NULL(stmt, numRowsFetched)
DPI_CHECK_PTR_NOT_NULL(stmt, moreRows)
if (stmt->bufferRowIndex >= stmt->bufferRowCount) {
if (stmt->hasRowsToFetch && dpiStmt__fetch(stmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (stmt->bufferRowIndex >= stmt->bufferRowCount) {
*moreRows = 0;
*bufferRowIndex = 0;
*numRowsFetched = 0;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
}
*bufferRowIndex = stmt->bufferRowIndex;
*numRowsFetched = stmt->bufferRowCount - stmt->bufferRowIndex;
*moreRows = stmt->hasRowsToFetch;
if (*numRowsFetched > maxRows) {
*numRowsFetched = maxRows;
*moreRows = 1;
}
stmt->bufferRowIndex += *numRowsFetched;
stmt->rowCount += *numRowsFetched;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getBatchErrorCount(dpiStmt *stmt, uint32_t *count)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, count)
*count = stmt->numBatchErrors;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getBatchErrors(dpiStmt *stmt, uint32_t numErrors,
dpiErrorInfo *errors)
{
dpiError error, tempError;
uint32_t i;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, errors)
if (numErrors < stmt->numBatchErrors) {
dpiError__set(&error, "check num errors", DPI_ERR_ARRAY_SIZE_TOO_SMALL,
numErrors);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
for (i = 0; i < stmt->numBatchErrors; i++) {
tempError.buffer = &stmt->batchErrors[i];
dpiError__getInfo(&tempError, &errors[i]);
}
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getBindCount(dpiStmt *stmt, uint32_t *count)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, count)
status = dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, (void*) count,
0, DPI_OCI_ATTR_BIND_COUNT, "get bind count", &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_getBindNames(dpiStmt *stmt, uint32_t *numBindNames,
const char **bindNames, uint32_t *bindNameLengths)
{
uint8_t bindNameLengthsBuffer[8], indNameLengthsBuffer[8], isDuplicate[8];
uint32_t startLoc, i, numThisPass, numActualBindNames;
char *bindNamesBuffer[8], *indNamesBuffer[8];
void *bindHandles[8];
int32_t numFound;
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, numBindNames)
DPI_CHECK_PTR_NOT_NULL(stmt, bindNames)
DPI_CHECK_PTR_NOT_NULL(stmt, bindNameLengths)
startLoc = 1;
numActualBindNames = 0;
while (1) {
if (dpiOci__stmtGetBindInfo(stmt, 8, startLoc, &numFound,
bindNamesBuffer, bindNameLengthsBuffer, indNamesBuffer,
indNameLengthsBuffer, isDuplicate, bindHandles, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (numFound == 0)
break;
numThisPass = abs(numFound) - startLoc + 1;
if (numThisPass > 8)
numThisPass = 8;
for (i = 0; i < numThisPass; i++) {
startLoc++;
if (isDuplicate[i])
continue;
if (numActualBindNames == *numBindNames) {
dpiError__set(&error, "check num bind names",
DPI_ERR_ARRAY_SIZE_TOO_SMALL, *numBindNames);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
bindNames[numActualBindNames] = bindNamesBuffer[i];
bindNameLengths[numActualBindNames] = bindNameLengthsBuffer[i];
numActualBindNames++;
}
if (numFound > 0)
break;
}
*numBindNames = numActualBindNames;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getFetchArraySize(dpiStmt *stmt, uint32_t *arraySize)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, arraySize)
*arraySize = stmt->fetchArraySize;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getImplicitResult(dpiStmt *stmt, dpiStmt **implicitResult)
{
dpiStmt *tempStmt;
dpiError error;
void *handle;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, implicitResult)
if (dpiUtils__checkClientVersion(stmt->env->versionInfo, 12, 1,
&error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (dpiOci__stmtGetNextResult(stmt, &handle, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
*implicitResult = NULL;
if (handle) {
if (dpiStmt__allocate(stmt->conn, 0, &tempStmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
tempStmt->handle = handle;
dpiGen__setRefCount(stmt, &error, 1);
tempStmt->parentStmt = stmt;
if (dpiStmt__createQueryVars(tempStmt, &error) < 0) {
dpiStmt__free(tempStmt, &error);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
*implicitResult = tempStmt;
}
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getInfo(dpiStmt *stmt, dpiStmtInfo *info)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, info)
info->isQuery = (stmt->statementType == DPI_STMT_TYPE_SELECT);
info->isPLSQL = (stmt->statementType == DPI_STMT_TYPE_BEGIN ||
stmt->statementType == DPI_STMT_TYPE_DECLARE ||
stmt->statementType == DPI_STMT_TYPE_CALL);
info->isDDL = (stmt->statementType == DPI_STMT_TYPE_CREATE ||
stmt->statementType == DPI_STMT_TYPE_DROP ||
stmt->statementType == DPI_STMT_TYPE_ALTER);
info->isDML = (stmt->statementType == DPI_STMT_TYPE_INSERT ||
stmt->statementType == DPI_STMT_TYPE_UPDATE ||
stmt->statementType == DPI_STMT_TYPE_DELETE ||
stmt->statementType == DPI_STMT_TYPE_MERGE);
info->statementType = stmt->statementType;
info->isReturning = stmt->isReturning;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getLastRowid(dpiStmt *stmt, dpiRowid **rowid)
{
uint64_t rowCount;
uint32_t tempSize;
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, rowid)
*rowid = NULL;
if (stmt->statementType == DPI_STMT_TYPE_INSERT ||
stmt->statementType == DPI_STMT_TYPE_UPDATE ||
stmt->statementType == DPI_STMT_TYPE_DELETE ||
stmt->statementType == DPI_STMT_TYPE_MERGE) {
if (dpiStmt__getRowCount(stmt, &rowCount, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (rowCount > 0) {
if (stmt->lastRowid) {
dpiGen__setRefCount(stmt->lastRowid, &error, -1);
stmt->lastRowid = NULL;
}
if (dpiRowid__allocate(stmt->conn, &stmt->lastRowid, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT,
stmt->lastRowid->handle, &tempSize, DPI_OCI_ATTR_ROWID,
"get last rowid", &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (tempSize)
*rowid = stmt->lastRowid;
}
}
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getNumQueryColumns(dpiStmt *stmt, uint32_t *numQueryColumns)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, numQueryColumns)
if (stmt->statementType == DPI_STMT_TYPE_SELECT &&
stmt->numQueryVars == 0 &&
dpiStmt__createQueryVars(stmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
*numQueryColumns = stmt->numQueryVars;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getOciAttr(dpiStmt *stmt, uint32_t attribute, dpiDataBuffer *value,
uint32_t *valueLength)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, value)
DPI_CHECK_PTR_NOT_NULL(stmt, valueLength)
status = dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, &value->asRaw,
valueLength, attribute, "generic get OCI attribute", &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_getPrefetchRows(dpiStmt *stmt, uint32_t *numRows)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, numRows)
*numRows = stmt->prefetchRows;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getQueryInfo(dpiStmt *stmt, uint32_t pos, dpiQueryInfo *info)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, info)
if (!stmt->queryInfo && dpiStmt__createQueryVars(stmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (pos == 0 || pos > stmt->numQueryVars) {
dpiError__set(&error, "check query position",
DPI_ERR_QUERY_POSITION_INVALID, pos);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
if (stmt->env->context->dpiMinorVersion > 1) {
memcpy(info, &stmt->queryInfo[pos - 1], sizeof(dpiQueryInfo));
} else if (stmt->env->context->dpiMinorVersion == 1) {
memcpy(info, &stmt->queryInfo[pos - 1], sizeof(dpiQueryInfo__v51));
} else {
memcpy(info, &stmt->queryInfo[pos - 1], sizeof(dpiQueryInfo__v50));
}
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getQueryValue(dpiStmt *stmt, uint32_t pos,
dpiNativeTypeNum *nativeTypeNum, dpiData **data)
{
dpiError error;
dpiVar *var;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, nativeTypeNum)
DPI_CHECK_PTR_NOT_NULL(stmt, data)
if (!stmt->queryVars) {
dpiError__set(&error, "check query vars", DPI_ERR_QUERY_NOT_EXECUTED);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
if (pos == 0 || pos > stmt->numQueryVars) {
dpiError__set(&error, "check query position",
DPI_ERR_QUERY_POSITION_INVALID, pos);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
var = stmt->queryVars[pos - 1];
if (!var || stmt->bufferRowIndex == 0 ||
stmt->bufferRowIndex > stmt->bufferRowCount) {
dpiError__set(&error, "check fetched row", DPI_ERR_NO_ROW_FETCHED);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
*nativeTypeNum = var->nativeTypeNum;
*data = &var->buffer.externalData[stmt->bufferRowIndex - 1];
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_getRowCount(dpiStmt *stmt, uint64_t *count)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, count)
status = dpiStmt__getRowCount(stmt, count, &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_getRowCounts(dpiStmt *stmt, uint32_t *numRowCounts,
uint64_t **rowCounts)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, numRowCounts)
DPI_CHECK_PTR_NOT_NULL(stmt, rowCounts)
if (dpiUtils__checkClientVersion(stmt->env->versionInfo, 12, 1,
&error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
status = dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, rowCounts,
numRowCounts, DPI_OCI_ATTR_DML_ROW_COUNT_ARRAY, "get row counts",
&error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_getSubscrQueryId(dpiStmt *stmt, uint64_t *queryId)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, queryId)
status = dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, queryId, 0,
DPI_OCI_ATTR_CQ_QUERYID, "get query id", &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_release(dpiStmt *stmt)
{
return dpiGen__release(stmt, DPI_HTYPE_STMT, __func__);
}
int dpiStmt_scroll(dpiStmt *stmt, dpiFetchMode mode, int32_t offset,
int32_t rowCountOffset)
{
uint32_t numRows, currentPosition;
uint64_t desiredRow = 0;
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
switch (mode) {
case DPI_MODE_FETCH_NEXT:
desiredRow = stmt->rowCount + rowCountOffset + 1;
break;
case DPI_MODE_FETCH_PRIOR:
desiredRow = stmt->rowCount + rowCountOffset - 1;
break;
case DPI_MODE_FETCH_FIRST:
desiredRow = 1;
break;
case DPI_MODE_FETCH_LAST:
break;
case DPI_MODE_FETCH_ABSOLUTE:
desiredRow = (uint64_t) offset;
break;
case DPI_MODE_FETCH_RELATIVE:
desiredRow = stmt->rowCount + rowCountOffset + offset;
offset = (int32_t) (desiredRow -
(stmt->bufferMinRow + stmt->bufferRowCount - 1));
break;
default:
dpiError__set(&error, "scroll mode", DPI_ERR_NOT_SUPPORTED);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
if (mode != DPI_MODE_FETCH_LAST && desiredRow >= stmt->bufferMinRow &&
desiredRow < stmt->bufferMinRow + stmt->bufferRowCount) {
stmt->bufferRowIndex = (uint32_t) (desiredRow - stmt->bufferMinRow);
stmt->rowCount = desiredRow - 1;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
if (dpiStmt__beforeFetch(stmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
numRows = (mode == DPI_MODE_FETCH_LAST) ? 1 : stmt->fetchArraySize;
if (dpiOci__stmtFetch2(stmt, numRows, mode, offset, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT,
&stmt->bufferRowCount, 0, DPI_OCI_ATTR_ROWS_FETCHED,
"get rows fetched", &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (stmt->bufferRowCount == 0) {
if (mode != DPI_MODE_FETCH_FIRST && mode != DPI_MODE_FETCH_LAST) {
dpiError__set(&error, "check result set bounds",
DPI_ERR_SCROLL_OUT_OF_RS);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
stmt->hasRowsToFetch = 0;
stmt->rowCount = 0;
stmt->bufferRowIndex = 0;
stmt->bufferMinRow = 0;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
if (dpiOci__attrGet(stmt->handle, DPI_OCI_HTYPE_STMT, ¤tPosition, 0,
DPI_OCI_ATTR_CURRENT_POSITION, "get current pos", &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
stmt->rowCount = currentPosition - stmt->bufferRowCount;
stmt->bufferMinRow = stmt->rowCount + 1;
stmt->bufferRowIndex = 0;
if (dpiStmt__postFetch(stmt, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_setFetchArraySize(dpiStmt *stmt, uint32_t arraySize)
{
dpiError error;
dpiVar *var;
uint32_t i;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
if (arraySize == 0)
arraySize = DPI_DEFAULT_FETCH_ARRAY_SIZE;
for (i = 0; i < stmt->numQueryVars; i++) {
var = stmt->queryVars[i];
if (var && var->buffer.maxArraySize < arraySize) {
dpiError__set(&error, "check array size",
DPI_ERR_ARRAY_SIZE_TOO_BIG, arraySize);
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
}
}
stmt->fetchArraySize = arraySize;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_setOciAttr(dpiStmt *stmt, uint32_t attribute, void *value,
uint32_t valueLength)
{
dpiError error;
int status;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
DPI_CHECK_PTR_NOT_NULL(stmt, value)
status = dpiOci__attrSet(stmt->handle, DPI_OCI_HTYPE_STMT, value,
valueLength, attribute, "generic set OCI attribute", &error);
return dpiGen__endPublicFn(stmt, status, &error);
}
int dpiStmt_setPrefetchRows(dpiStmt *stmt, uint32_t numRows)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
stmt->prefetchRows = numRows;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}
int dpiStmt_deleteFromCache(dpiStmt *stmt)
{
dpiError error;
if (dpiStmt__check(stmt, __func__, &error) < 0)
return dpiGen__endPublicFn(stmt, DPI_FAILURE, &error);
stmt->deleteFromCache = 1;
return dpiGen__endPublicFn(stmt, DPI_SUCCESS, &error);
}