代码拉取完成,页面将自动刷新
//-----------------------------------------------------------------------------
// Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
//
// Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
//
// Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
// Canada. All rights reserved.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// cxoVar.c
// Defines Python types for Oracle variables.
//-----------------------------------------------------------------------------
#include "cxoModule.h"
//-----------------------------------------------------------------------------
// cxoVar_new()
// Allocate a new variable.
//-----------------------------------------------------------------------------
cxoVar *cxoVar_new(cxoCursor *cursor, Py_ssize_t numElements,
cxoTransformNum transformNum, Py_ssize_t size, int isArray,
cxoObjectType *objType)
{
dpiObjectType *typeHandle = NULL;
dpiOracleTypeNum oracleTypeNum;
cxoVar *var;
// attempt to allocate the object
var = (cxoVar*) cxoPyTypeVar.tp_alloc(&cxoPyTypeVar, 0);
if (!var)
return NULL;
// perform basic initialization
Py_INCREF(cursor->connection);
var->connection = cursor->connection;
if (objType) {
Py_INCREF(objType);
var->objectType = objType;
typeHandle = objType->handle;
}
if (numElements == 0)
numElements = 1;
var->allocatedElements = (uint32_t) numElements;
var->transformNum = transformNum;
var->size = (uint32_t) size;
if (var->size == 0)
var->size = cxoTransform_getDefaultSize(transformNum);
var->isArray = isArray;
// determine database type
var->dbType = cxoDbType_fromTransformNum(var->transformNum);
if (!var->dbType) {
Py_DECREF(var);
return NULL;
}
Py_INCREF(var->dbType);
// acquire and initialize DPI variable
cxoTransform_getTypeInfo(transformNum, &oracleTypeNum,
&var->nativeTypeNum);
if (dpiConn_newVar(cursor->connection->handle, oracleTypeNum,
var->nativeTypeNum, var->allocatedElements, var->size, 0, isArray,
typeHandle, &var->handle, &var->data) < 0) {
cxoError_raiseAndReturnNull();
Py_DECREF(var);
return NULL;
}
// get buffer size for information
if (dpiVar_getSizeInBytes(var->handle, &var->bufferSize) < 0) {
cxoError_raiseAndReturnNull();
Py_DECREF(var);
return NULL;
}
return var;
}
//-----------------------------------------------------------------------------
// cxoVar_free()
// Free an existing variable.
//-----------------------------------------------------------------------------
static void cxoVar_free(cxoVar *var)
{
if (var->handle) {
Py_BEGIN_ALLOW_THREADS
dpiVar_release(var->handle);
Py_END_ALLOW_THREADS
var->handle = NULL;
}
if (var->encodingErrors)
PyMem_Free((void*) var->encodingErrors);
Py_CLEAR(var->connection);
Py_CLEAR(var->inConverter);
Py_CLEAR(var->outConverter);
Py_CLEAR(var->objectType);
Py_CLEAR(var->dbType);
Py_TYPE(var)->tp_free((PyObject*) var);
}
//-----------------------------------------------------------------------------
// cxoVar_check()
// Returns a boolean indicating if the object is a variable.
//-----------------------------------------------------------------------------
int cxoVar_check(PyObject *object)
{
return (Py_TYPE(object) == &cxoPyTypeVar);
}
//-----------------------------------------------------------------------------
// cxoVar_newByValue()
// Allocate a new variable by looking at the type of the data.
//-----------------------------------------------------------------------------
cxoVar *cxoVar_newByValue(cxoCursor *cursor, PyObject *value,
Py_ssize_t numElements)
{
PyObject *result, *inputTypeHandler = NULL;
cxoObjectType *objType = NULL;
cxoTransformNum transformNum;
Py_ssize_t size;
cxoObject *obj;
int isArray;
// determine if an input type handler should be used; an input type handler
// defined on the cursor takes precedence over one defined on the
// connection to which the cursor belongs; the input type handler should
// return a variable or None; the value None implies that the default
// processing should take place just as if no input type handler was
// defined
if (cursor->inputTypeHandler && cursor->inputTypeHandler != Py_None)
inputTypeHandler = cursor->inputTypeHandler;
else if (cursor->connection->inputTypeHandler &&
cursor->connection->inputTypeHandler != Py_None)
inputTypeHandler = cursor->connection->inputTypeHandler;
if (inputTypeHandler) {
result = PyObject_CallFunction(inputTypeHandler, "OOn", cursor, value,
numElements);
if (!result)
return NULL;
if (result != Py_None) {
if (!cxoVar_check(result)) {
Py_DECREF(result);
PyErr_SetString(PyExc_TypeError,
"expecting variable from input type handler");
return NULL;
}
return (cxoVar*) result;
}
Py_DECREF(result);
}
// default processing
if (cxoTransform_getNumFromValue(value, &isArray, &size, &numElements,
cursor->stmtInfo.isPLSQL, &transformNum) < 0)
return NULL;
if (transformNum == CXO_TRANSFORM_OBJECT) {
obj = (cxoObject*) value;
objType = obj->objectType;
}
return cxoVar_new(cursor, numElements, transformNum, size, isArray,
objType);
}
//-----------------------------------------------------------------------------
// cxoVar_newArrayByType()
// Allocate a new PL/SQL array by looking at the Python data type.
//-----------------------------------------------------------------------------
static cxoVar *cxoVar_newArrayByType(cxoCursor *cursor,
PyObject *value)
{
PyObject *typeObj, *numElementsObj;
cxoTransformNum transformNum;
cxoObjectType *objType;
uint32_t numElements;
int ok;
// validate parameters
ok = (PyList_GET_SIZE(value) == 2);
if (ok) {
typeObj = PyList_GET_ITEM(value, 0);
numElementsObj = PyList_GET_ITEM(value, 1);
ok = PyLong_Check(numElementsObj);
}
if (!ok) {
cxoError_raiseFromString(cxoProgrammingErrorException,
"expecting an array of two elements [type, numelems]");
return NULL;
}
// create variable
if (cxoTransform_getNumFromType(typeObj, &transformNum, &objType) < 0)
return NULL;
numElements = PyLong_AsLong(numElementsObj);
if (PyErr_Occurred())
return NULL;
return cxoVar_new(cursor, numElements, transformNum, 0, 1, objType);
}
//-----------------------------------------------------------------------------
// cxoVar_newByType()
// Allocate a new variable by looking at the Python data type.
//-----------------------------------------------------------------------------
cxoVar *cxoVar_newByType(cxoCursor *cursor, PyObject *value,
uint32_t numElements)
{
cxoTransformNum transformNum;
cxoObjectType *objType;
long size;
// passing an integer is assumed to be a string
if (PyLong_Check(value)) {
size = PyLong_AsLong(value);
if (PyErr_Occurred())
return NULL;
return cxoVar_new(cursor, numElements, CXO_TRANSFORM_STRING, size, 0,
NULL);
}
// passing an array of two elements to define an array
if (PyList_Check(value))
return cxoVar_newArrayByType(cursor, value);
// handle directly bound variables
if (cxoVar_check(value)) {
Py_INCREF(value);
return (cxoVar*) value;
}
// everything else ought to be a Python type, database type constant or
// object type
if (cxoTransform_getNumFromType(value, &transformNum, &objType) < 0)
return NULL;
return cxoVar_new(cursor, numElements, transformNum, 0, 0, objType);
}
//-----------------------------------------------------------------------------
// cxoVar_bind()
// Allocate a variable and bind it to the given statement.
//-----------------------------------------------------------------------------
int cxoVar_bind(cxoVar *var, cxoCursor *cursor, PyObject *name, uint32_t pos)
{
cxoBuffer nameBuffer;
int status;
// perform the bind
if (name) {
if (cxoBuffer_fromObject(&nameBuffer, name,
cursor->connection->encodingInfo.encoding) < 0)
return -1;
status = dpiStmt_bindByName(cursor->handle, (char*) nameBuffer.ptr,
nameBuffer.size, var->handle);
cxoBuffer_clear(&nameBuffer);
} else {
status = dpiStmt_bindByPos(cursor->handle, pos, var->handle);
}
if (status < 0)
return cxoError_raiseAndReturnInt();
// set flag if bound to a DML returning statement and no data set
if (cursor->stmtInfo.isReturning && !var->isValueSet)
var->getReturnedData = 1;
return 0;
}
//-----------------------------------------------------------------------------
// cxoVar_getArrayValue()
// Return the value of the variable as an array.
//-----------------------------------------------------------------------------
static PyObject *cxoVar_getArrayValue(cxoVar *var, uint32_t numElements,
dpiData *data)
{
PyObject *value, *singleValue;
uint32_t i;
value = PyList_New(numElements);
if (!value)
return NULL;
for (i = 0; i < numElements; i++) {
singleValue = cxoVar_getSingleValue(var, data, i);
if (!singleValue) {
Py_DECREF(value);
return NULL;
}
PyList_SET_ITEM(value, i, singleValue);
}
return value;
}
//-----------------------------------------------------------------------------
// cxoVar_getSingleValue()
// Return the value of the variable at the given position.
//-----------------------------------------------------------------------------
PyObject *cxoVar_getSingleValue(cxoVar *var, dpiData *data, uint32_t arrayPos)
{
PyObject *value, *result;
uint32_t numReturnedRows;
dpiData *returnedData;
// handle DML returning
if (!data && var->getReturnedData) {
if (dpiVar_getReturnedData(var->handle, arrayPos, &numReturnedRows,
&returnedData) < 0)
return cxoError_raiseAndReturnNull();
return cxoVar_getArrayValue(var, numReturnedRows, returnedData);
}
// in all other cases, just get the value stored at specified position
if (data)
data = &data[arrayPos];
else data = &var->data[arrayPos];
if (data->isNull)
Py_RETURN_NONE;
value = cxoTransform_toPython(var->transformNum, var->connection,
var->objectType, &data->value, var->encodingErrors);
if (value) {
switch (var->transformNum) {
case CXO_TRANSFORM_BFILE:
case CXO_TRANSFORM_BLOB:
case CXO_TRANSFORM_CLOB:
case CXO_TRANSFORM_NCLOB:
dpiLob_addRef(data->value.asLOB);
break;
case CXO_TRANSFORM_OBJECT:
dpiObject_addRef(data->value.asObject);
break;
default:
break;
}
if (var->outConverter && var->outConverter != Py_None) {
result = PyObject_CallFunctionObjArgs(var->outConverter, value,
NULL);
Py_DECREF(value);
return result;
}
}
return value;
}
//-----------------------------------------------------------------------------
// cxoVar_getValue()
// Return the value of the variable.
//-----------------------------------------------------------------------------
PyObject *cxoVar_getValue(cxoVar *var, uint32_t arrayPos)
{
uint32_t numElements;
if (var->isArray) {
if (dpiVar_getNumElementsInArray(var->handle, &numElements) < 0)
return cxoError_raiseAndReturnNull();
return cxoVar_getArrayValue(var, numElements, var->data);
}
if (arrayPos >= var->allocatedElements && !var->getReturnedData) {
PyErr_SetString(PyExc_IndexError,
"cxoVar_getSingleValue: array size exceeded");
return NULL;
}
return cxoVar_getSingleValue(var, NULL, arrayPos);
}
//-----------------------------------------------------------------------------
// cxoVar_setValueBytes()
// Set a value in the variable from a byte string of some sort.
//-----------------------------------------------------------------------------
static int cxoVar_setValueBytes(cxoVar *var, uint32_t pos, dpiData *data,
cxoBuffer *buffer)
{
dpiData *tempVarData, *sourceData;
dpiOracleTypeNum oracleTypeNum;
dpiNativeTypeNum nativeTypeNum;
uint32_t i, numElements;
dpiVar *tempVarHandle;
int status;
if (buffer->size > var->bufferSize) {
cxoTransform_getTypeInfo(var->transformNum, &oracleTypeNum,
&nativeTypeNum);
if (dpiConn_newVar(var->connection->handle, oracleTypeNum,
nativeTypeNum, var->allocatedElements, buffer->size, 0,
var->isArray, NULL, &tempVarHandle, &tempVarData) < 0)
return cxoError_raiseAndReturnInt();
if (var->isArray) {
if (dpiVar_getNumElementsInArray(var->handle, &numElements) < 0) {
cxoError_raiseAndReturnInt();
dpiVar_release(tempVarHandle);
return -1;
}
if (dpiVar_setNumElementsInArray(tempVarHandle, numElements) < 0) {
cxoError_raiseAndReturnInt();
dpiVar_release(tempVarHandle);
return -1;
}
}
for (i = 0; i < var->allocatedElements; i++) {
sourceData = &var->data[i];
if (i == pos || sourceData->isNull)
continue;
if (dpiVar_setFromBytes(tempVarHandle, i,
sourceData->value.asBytes.ptr,
sourceData->value.asBytes.length) < 0) {
cxoError_raiseAndReturnInt();
dpiVar_release(tempVarHandle);
return -1;
}
}
dpiVar_release(var->handle);
var->handle = tempVarHandle;
var->data = tempVarData;
var->size = buffer->numCharacters;
var->bufferSize = buffer->size;
}
status = dpiVar_setFromBytes(var->handle, pos, buffer->ptr, buffer->size);
if (status < 0)
return cxoError_raiseAndReturnInt();
return 0;
}
//-----------------------------------------------------------------------------
// cxoVar_setValueCursor()
// Set the value of the variable (which is assumed to be a cursor).
//-----------------------------------------------------------------------------
static int cxoVar_setValueCursor(cxoVar *var, uint32_t pos, dpiData *data,
PyObject *value)
{
cxoCursor *cursor;
dpiStmtInfo info;
if (!PyObject_IsInstance(value, (PyObject*) &cxoPyTypeCursor)) {
PyErr_SetString(PyExc_TypeError, "expecting cursor");
return -1;
}
// if the cursor already has a handle, use it directly
cursor = (cxoCursor *) value;
if (cursor->handle) {
if (dpiVar_setFromStmt(var->handle, pos, cursor->handle) < 0)
return cxoError_raiseAndReturnInt();
// otherwise, make use of the statement handle allocated by the variable
// BUT, make sure the statement handle is still valid as it may have been
// closed by some other code; the call to dpiStmt_getInfo() will ensure the
// statement is still open; if an error occurs, this bind will be discarded
// and a second attempt will be made with a new cursor
} else {
if (dpiStmt_getInfo(data->value.asStmt, &info) < 0)
return cxoError_raiseAndReturnInt();
cursor->handle = data->value.asStmt;
dpiStmt_addRef(cursor->handle);
}
if (dpiStmt_setPrefetchRows(cursor->handle, cursor->prefetchRows) < 0)
return cxoError_raiseAndReturnInt();
cursor->fixupRefCursor = 1;
return 0;
}
//-----------------------------------------------------------------------------
// cxoVar_setSingleValue()
// Set a single value in the variable.
//-----------------------------------------------------------------------------
static int cxoVar_setSingleValue(cxoVar *var, uint32_t arrayPos,
PyObject *value)
{
dpiDataBuffer tempDbValue, *dbValue;
PyObject *convertedValue = NULL;
dpiNativeTypeNum nativeTypeNum;
cxoBuffer buffer;
int result = 0;
dpiData *data;
// ensure we do not exceed the number of allocated elements
if (arrayPos >= var->allocatedElements) {
PyErr_SetString(PyExc_IndexError,
"cxoVar_setSingleValue: array size exceeded");
return -1;
}
// convert value, if necessary
if (var->inConverter && var->inConverter != Py_None) {
convertedValue = PyObject_CallFunctionObjArgs(var->inConverter, value,
NULL);
if (!convertedValue)
return -1;
value = convertedValue;
}
// transform value from Python to value expected by ODPI-C
data = &var->data[arrayPos];
data->isNull = (value == Py_None);
if (!data->isNull) {
if (var->transformNum == CXO_TRANSFORM_CURSOR)
result = cxoVar_setValueCursor(var, arrayPos, data, value);
else {
cxoBuffer_init(&buffer);
if (var->nativeTypeNum == DPI_NATIVE_TYPE_BYTES)
dbValue = &tempDbValue;
else dbValue = &data->value;
result = cxoTransform_fromPython(var->transformNum,
&nativeTypeNum, value, dbValue, &buffer,
var->connection->encodingInfo.encoding,
var->connection->encodingInfo.nencoding, var, arrayPos);
if (result == 0 && var->nativeTypeNum == DPI_NATIVE_TYPE_BYTES)
result = cxoVar_setValueBytes(var, arrayPos, data, &buffer);
cxoBuffer_clear(&buffer);
}
}
Py_CLEAR(convertedValue);
return result;
}
//-----------------------------------------------------------------------------
// cxoVar_setArrayValue()
// Set all of the array values for the variable.
//-----------------------------------------------------------------------------
static int cxoVar_setArrayValue(cxoVar *var, PyObject *value)
{
Py_ssize_t numElements, i;
// ensure we have an array to set
if (!PyList_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expecting array data");
return -1;
}
// set the number of actual elements
numElements = PyList_GET_SIZE(value);
if (dpiVar_setNumElementsInArray(var->handle, (uint32_t) numElements) < 0)
return cxoError_raiseAndReturnInt();
// set all of the values
for (i = 0; i < numElements; i++) {
if (cxoVar_setSingleValue(var, i, PyList_GET_ITEM(value, i)) < 0)
return -1;
}
return 0;
}
//-----------------------------------------------------------------------------
// cxoVar_setValue()
// Set the value of the variable.
//-----------------------------------------------------------------------------
int cxoVar_setValue(cxoVar *var, uint32_t arrayPos, PyObject *value)
{
var->isValueSet = 1;
if (var->isArray) {
if (arrayPos > 0) {
cxoError_raiseFromString(cxoNotSupportedErrorException,
"arrays of arrays are not supported by the OCI");
return -1;
}
return cxoVar_setArrayValue(var, value);
}
return cxoVar_setSingleValue(var, arrayPos, value);
}
//-----------------------------------------------------------------------------
// cxoVar_externalCopy()
// Copy the contents of the source variable to the destination variable.
//-----------------------------------------------------------------------------
static PyObject *cxoVar_externalCopy(cxoVar *targetVar, PyObject *args)
{
uint32_t sourcePos, targetPos;
cxoVar *sourceVar;
if (!PyArg_ParseTuple(args, "Oii", &sourceVar, &sourcePos, &targetPos))
return NULL;
if (Py_TYPE(targetVar) != Py_TYPE(sourceVar))
return cxoError_raiseFromString(cxoProgrammingErrorException,
"source and target variable type must match");
if (dpiVar_copyData(targetVar->handle, targetPos, sourceVar->handle,
sourcePos) < 0)
return cxoError_raiseAndReturnNull();
Py_RETURN_NONE;
}
//-----------------------------------------------------------------------------
// cxoVar_externalSetValue()
// Set the value of the variable at the given position.
//-----------------------------------------------------------------------------
static PyObject *cxoVar_externalSetValue(cxoVar *var, PyObject *args)
{
PyObject *value;
uint32_t pos;
if (!PyArg_ParseTuple(args, "iO", &pos, &value))
return NULL;
if (cxoVar_setValue(var, pos, value) < 0)
return NULL;
Py_RETURN_NONE;
}
//-----------------------------------------------------------------------------
// cxoVar_externalGetValue()
// Return the value of the variable at the given position.
//-----------------------------------------------------------------------------
static PyObject *cxoVar_externalGetValue(cxoVar *var, PyObject *args,
PyObject *keywordArgs)
{
static char *keywordList[] = { "pos", NULL };
uint32_t pos = 0;
if (!PyArg_ParseTupleAndKeywords(args, keywordArgs, "|i", keywordList,
&pos))
return NULL;
return cxoVar_getValue(var, pos);
}
//-----------------------------------------------------------------------------
// cxoVar_externalGetActualElements()
// Return the values of the variable at all positions as a list.
//-----------------------------------------------------------------------------
static PyObject *cxoVar_externalGetActualElements(cxoVar *var,
void *unused)
{
uint32_t numElements = var->allocatedElements;
if (var->isArray &&
dpiVar_getNumElementsInArray(var->handle, &numElements) < 0)
return cxoError_raiseAndReturnNull();
return PyLong_FromLong(numElements);
}
//-----------------------------------------------------------------------------
// cxoVar_externalGetValues()
// Return the values of the variable at all positions as a list.
//-----------------------------------------------------------------------------
static PyObject *cxoVar_externalGetValues(cxoVar *var, void *unused)
{
uint32_t numElements = var->allocatedElements;
if (var->isArray &&
dpiVar_getNumElementsInArray(var->handle, &numElements) < 0)
return cxoError_raiseAndReturnNull();
return cxoVar_getArrayValue(var, numElements, NULL);
}
//-----------------------------------------------------------------------------
// cxoVar_getType()
// Return the type associated with the variable. This is either an object
// type or one of the database type constants.
//-----------------------------------------------------------------------------
static PyObject *cxoVar_getType(cxoVar *var, void *unused)
{
if (var->objectType) {
Py_INCREF(var->objectType);
return (PyObject*) var->objectType;
}
Py_INCREF(var->dbType);
return (PyObject*) var->dbType;
}
//-----------------------------------------------------------------------------
// cxoVar_repr()
// Return a string representation of the variable.
//-----------------------------------------------------------------------------
static PyObject *cxoVar_repr(cxoVar *var)
{
PyObject *value, *module, *name, *result, *typeName;
uint32_t numElements;
if (var->isArray) {
if (dpiVar_getNumElementsInArray(var->handle, &numElements) < 0)
return cxoError_raiseAndReturnNull();
value = cxoVar_getArrayValue(var, numElements, var->data);
} else if (var->allocatedElements == 1)
value = cxoVar_getSingleValue(var, NULL, 0);
else value = cxoVar_getArrayValue(var, var->allocatedElements, NULL);
if (!value)
return NULL;
typeName = PyUnicode_DecodeASCII(var->dbType->name,
strlen(var->dbType->name), NULL);
if (!typeName) {
Py_DECREF(value);
return NULL;
}
if (cxoUtils_getModuleAndName(Py_TYPE(var), &module, &name) < 0) {
Py_DECREF(typeName);
Py_DECREF(value);
return NULL;
}
result = cxoUtils_formatString("<%s.%s of type %s with value %r>",
PyTuple_Pack(4, module, name, typeName, value));
Py_DECREF(module);
Py_DECREF(name);
Py_DECREF(value);
Py_DECREF(typeName);
return result;
}
//-----------------------------------------------------------------------------
// declaration of members
//-----------------------------------------------------------------------------
static PyMemberDef cxoMembers[] = {
{ "buffer_size", T_INT, offsetof(cxoVar, bufferSize), READONLY },
{ "bufferSize", T_INT, offsetof(cxoVar, bufferSize), READONLY },
{ "inconverter", T_OBJECT, offsetof(cxoVar, inConverter), 0 },
{ "numElements", T_INT, offsetof(cxoVar, allocatedElements), READONLY },
{ "num_elements", T_INT, offsetof(cxoVar, allocatedElements), READONLY },
{ "outconverter", T_OBJECT, offsetof(cxoVar, outConverter), 0 },
{ "size", T_INT, offsetof(cxoVar, size), READONLY },
{ NULL }
};
//-----------------------------------------------------------------------------
// declaration of calculated members
//-----------------------------------------------------------------------------
static PyGetSetDef cxoCalcMembers[] = {
{ "actual_elements", (getter) cxoVar_externalGetActualElements, 0, 0, 0 },
{ "actualElements", (getter) cxoVar_externalGetActualElements, 0, 0, 0 },
{ "type", (getter) cxoVar_getType, 0, 0, 0 },
{ "values", (getter) cxoVar_externalGetValues, 0, 0, 0 },
{ NULL }
};
//-----------------------------------------------------------------------------
// declaration of methods
//-----------------------------------------------------------------------------
static PyMethodDef cxoVarMethods[] = {
{ "copy", (PyCFunction) cxoVar_externalCopy, METH_VARARGS },
{ "setvalue", (PyCFunction) cxoVar_externalSetValue, METH_VARARGS },
{ "getvalue", (PyCFunction) cxoVar_externalGetValue,
METH_VARARGS | METH_KEYWORDS },
{ NULL }
};
//-----------------------------------------------------------------------------
// declaration of Python type
//-----------------------------------------------------------------------------
PyTypeObject cxoPyTypeVar = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "cx_Oracle.Var",
.tp_basicsize = sizeof(cxoVar),
.tp_dealloc = (destructor) cxoVar_free,
.tp_repr = (reprfunc) cxoVar_repr,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_methods = cxoVarMethods,
.tp_members = cxoMembers,
.tp_getset = cxoCalcMembers
};
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。