NumberVar.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. //-----------------------------------------------------------------------------
  2. // NumberVar.c
  3. // Defines the routines for handling numeric variables.
  4. //-----------------------------------------------------------------------------
  5. //-----------------------------------------------------------------------------
  6. // Number types
  7. //-----------------------------------------------------------------------------
  8. typedef struct {
  9. Variable_HEAD
  10. OCINumber *data;
  11. } udt_NumberVar;
  12. typedef struct {
  13. Variable_HEAD
  14. double *data;
  15. } udt_NativeFloatVar;
  16. //-----------------------------------------------------------------------------
  17. // Declaration of number variable functions.
  18. //-----------------------------------------------------------------------------
  19. static int NumberVar_PreDefine(udt_NumberVar*, OCIParam*);
  20. static int NumberVar_SetValue(udt_NumberVar*, unsigned, PyObject*);
  21. static PyObject *NumberVar_GetValue(udt_NumberVar*, unsigned);
  22. static int NativeFloatVar_SetValue(udt_NativeFloatVar*, unsigned, PyObject*);
  23. static PyObject *NativeFloatVar_GetValue(udt_NativeFloatVar*, unsigned);
  24. //-----------------------------------------------------------------------------
  25. // Python type declaration
  26. //-----------------------------------------------------------------------------
  27. static PyTypeObject g_NumberVarType = {
  28. PyVarObject_HEAD_INIT(NULL, 0)
  29. "cx_Oracle.NUMBER", // tp_name
  30. sizeof(udt_NumberVar), // tp_basicsize
  31. 0, // tp_itemsize
  32. 0, // tp_dealloc
  33. 0, // tp_print
  34. 0, // tp_getattr
  35. 0, // tp_setattr
  36. 0, // tp_compare
  37. 0, // tp_repr
  38. 0, // tp_as_number
  39. 0, // tp_as_sequence
  40. 0, // tp_as_mapping
  41. 0, // tp_hash
  42. 0, // tp_call
  43. 0, // tp_str
  44. 0, // tp_getattro
  45. 0, // tp_setattro
  46. 0, // tp_as_buffer
  47. Py_TPFLAGS_DEFAULT, // tp_flags
  48. 0 // tp_doc
  49. };
  50. static PyTypeObject g_NativeFloatVarType = {
  51. PyVarObject_HEAD_INIT(NULL, 0)
  52. "cx_Oracle.NATIVE_FLOAT", // tp_name
  53. sizeof(udt_NativeFloatVar), // tp_basicsize
  54. 0, // tp_itemsize
  55. 0, // tp_dealloc
  56. 0, // tp_print
  57. 0, // tp_getattr
  58. 0, // tp_setattr
  59. 0, // tp_compare
  60. 0, // tp_repr
  61. 0, // tp_as_number
  62. 0, // tp_as_sequence
  63. 0, // tp_as_mapping
  64. 0, // tp_hash
  65. 0, // tp_call
  66. 0, // tp_str
  67. 0, // tp_getattro
  68. 0, // tp_setattro
  69. 0, // tp_as_buffer
  70. Py_TPFLAGS_DEFAULT, // tp_flags
  71. 0 // tp_doc
  72. };
  73. //-----------------------------------------------------------------------------
  74. // variable type declarations
  75. //-----------------------------------------------------------------------------
  76. static udt_VariableType vt_Float = {
  77. (InitializeProc) NULL,
  78. (FinalizeProc) NULL,
  79. (PreDefineProc) NumberVar_PreDefine,
  80. (PostDefineProc) NULL,
  81. (PreFetchProc) NULL,
  82. (IsNullProc) NULL,
  83. (SetValueProc) NumberVar_SetValue,
  84. (GetValueProc) NumberVar_GetValue,
  85. (GetBufferSizeProc) NULL,
  86. &g_NumberVarType, // Python type
  87. SQLT_VNU, // Oracle type
  88. SQLCS_IMPLICIT, // charset form
  89. sizeof(OCINumber), // element length
  90. 0, // is character data
  91. 0, // is variable length
  92. 1, // can be copied
  93. 1 // can be in array
  94. };
  95. static udt_VariableType vt_NativeFloat = {
  96. (InitializeProc) NULL,
  97. (FinalizeProc) NULL,
  98. (PreDefineProc) NULL,
  99. (PostDefineProc) NULL,
  100. (PreFetchProc) NULL,
  101. (IsNullProc) NULL,
  102. (SetValueProc) NativeFloatVar_SetValue,
  103. (GetValueProc) NativeFloatVar_GetValue,
  104. (GetBufferSizeProc) NULL,
  105. &g_NativeFloatVarType, // Python type
  106. SQLT_BDOUBLE, // Oracle type
  107. SQLCS_IMPLICIT, // charset form
  108. sizeof(double), // element length
  109. 0, // is character data
  110. 0, // is variable length
  111. 1, // can be copied
  112. 1 // can be in array
  113. };
  114. static udt_VariableType vt_Integer = {
  115. (InitializeProc) NULL,
  116. (FinalizeProc) NULL,
  117. (PreDefineProc) NumberVar_PreDefine,
  118. (PostDefineProc) NULL,
  119. (PreFetchProc) NULL,
  120. (IsNullProc) NULL,
  121. (SetValueProc) NumberVar_SetValue,
  122. (GetValueProc) NumberVar_GetValue,
  123. (GetBufferSizeProc) NULL,
  124. &g_NumberVarType, // Python type
  125. SQLT_VNU, // Oracle type
  126. SQLCS_IMPLICIT, // charset form
  127. sizeof(OCINumber), // element length
  128. 0, // is character data
  129. 0, // is variable length
  130. 1, // can be copied
  131. 1 // can be in array
  132. };
  133. static udt_VariableType vt_LongInteger = {
  134. (InitializeProc) NULL,
  135. (FinalizeProc) NULL,
  136. (PreDefineProc) NumberVar_PreDefine,
  137. (PostDefineProc) NULL,
  138. (PreFetchProc) NULL,
  139. (IsNullProc) NULL,
  140. (SetValueProc) NumberVar_SetValue,
  141. (GetValueProc) NumberVar_GetValue,
  142. (GetBufferSizeProc) NULL,
  143. &g_NumberVarType, // Python type
  144. SQLT_VNU, // Oracle type
  145. SQLCS_IMPLICIT, // charset form
  146. sizeof(OCINumber), // element length
  147. 0, // is character data
  148. 0, // is variable length
  149. 1, // can be copied
  150. 1 // can be in array
  151. };
  152. static udt_VariableType vt_NumberAsString = {
  153. (InitializeProc) NULL,
  154. (FinalizeProc) NULL,
  155. (PreDefineProc) NumberVar_PreDefine,
  156. (PostDefineProc) NULL,
  157. (PreFetchProc) NULL,
  158. (IsNullProc) NULL,
  159. (SetValueProc) NumberVar_SetValue,
  160. (GetValueProc) NumberVar_GetValue,
  161. (GetBufferSizeProc) NULL,
  162. &g_NumberVarType, // Python type
  163. SQLT_VNU, // Oracle type
  164. SQLCS_IMPLICIT, // charset form
  165. sizeof(OCINumber), // element length
  166. 0, // is character data
  167. 0, // is variable length
  168. 1, // can be copied
  169. 1 // can be in array
  170. };
  171. #if ORACLE_VERSION_HEX < ORACLE_VERSION(12, 1)
  172. static udt_VariableType vt_Boolean = {
  173. (InitializeProc) NULL,
  174. (FinalizeProc) NULL,
  175. (PreDefineProc) NumberVar_PreDefine,
  176. (PostDefineProc) NULL,
  177. (PreFetchProc) NULL,
  178. (IsNullProc) NULL,
  179. (SetValueProc) NumberVar_SetValue,
  180. (GetValueProc) NumberVar_GetValue,
  181. (GetBufferSizeProc) NULL,
  182. &g_NumberVarType, // Python type
  183. SQLT_VNU, // Oracle type
  184. SQLCS_IMPLICIT, // charset form
  185. sizeof(OCINumber), // element length
  186. 0, // is character data
  187. 0, // is variable length
  188. 1, // can be copied
  189. 1 // can be in array
  190. };
  191. #endif
  192. //-----------------------------------------------------------------------------
  193. // NumberVar_PreDefine()
  194. // Set the type of value (integer, float or string) that will be returned
  195. // when values are fetched from this variable.
  196. //-----------------------------------------------------------------------------
  197. static int NumberVar_PreDefine(
  198. udt_NumberVar *var, // variable to initialize
  199. OCIParam *param) // parameter handle
  200. {
  201. static int maxLongSafeDigits = sizeof(long) >= 8 ? 18 : 9;
  202. sb2 precision;
  203. sword status;
  204. sb1 scale;
  205. // if the return type has not already been specified, check to see if the
  206. // number can fit inside an integer by looking at the precision and scale
  207. if (var->type == &vt_Float) {
  208. scale = 0;
  209. precision = 0;
  210. status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &scale, 0,
  211. OCI_ATTR_SCALE, var->environment->errorHandle);
  212. if (Environment_CheckForError(var->environment, status,
  213. "NumberVar_PreDefine(): scale") < 0)
  214. return -1;
  215. status = OCIAttrGet(param, OCI_HTYPE_DESCRIBE, (dvoid*) &precision, 0,
  216. OCI_ATTR_PRECISION, var->environment->errorHandle);
  217. if (Environment_CheckForError(var->environment, status,
  218. "NumberVar_PreDefine(): precision") < 0)
  219. return -1;
  220. if (scale == 0 || (scale == -127 && precision == 0)) {
  221. var->type = &vt_LongInteger;
  222. if (precision > 0 && precision <= maxLongSafeDigits)
  223. var->type = &vt_Integer;
  224. }
  225. }
  226. return 0;
  227. }
  228. //-----------------------------------------------------------------------------
  229. // NumberVar_SetValueFromBoolean()
  230. // Set the value of the variable from a Python boolean.
  231. //-----------------------------------------------------------------------------
  232. static int NumberVar_SetValueFromBoolean(
  233. udt_NumberVar *var, // variable to set value for
  234. unsigned pos, // array position to set
  235. PyObject *value) // value to set
  236. {
  237. long integerValue;
  238. sword status;
  239. integerValue = (value == Py_True);
  240. status = OCINumberFromInt(var->environment->errorHandle, &integerValue,
  241. sizeof(long), OCI_NUMBER_SIGNED, &var->data[pos]);
  242. return Environment_CheckForError(var->environment, status,
  243. "NumberVar_SetValueFromBoolean()");
  244. }
  245. #if PY_MAJOR_VERSION < 3
  246. //-----------------------------------------------------------------------------
  247. // NumberVar_SetValueFromInteger()
  248. // Set the value of the variable from a Python integer.
  249. //-----------------------------------------------------------------------------
  250. static int NumberVar_SetValueFromInteger(
  251. udt_NumberVar *var, // variable to set value for
  252. unsigned pos, // array position to set
  253. PyObject *value) // value to set
  254. {
  255. long integerValue;
  256. sword status;
  257. integerValue = PyInt_AS_LONG(value);
  258. status = OCINumberFromInt(var->environment->errorHandle, &integerValue,
  259. sizeof(long), OCI_NUMBER_SIGNED, &var->data[pos]);
  260. return Environment_CheckForError(var->environment, status,
  261. "NumberVar_SetValueFromInteger()");
  262. }
  263. #endif
  264. //-----------------------------------------------------------------------------
  265. // NumberVar_SetValueFromFloat()
  266. // Set the value of the variable from a Python float.
  267. //-----------------------------------------------------------------------------
  268. static int NumberVar_SetValueFromFloat(
  269. udt_NumberVar *var, // variable to set value for
  270. unsigned pos, // array position to set
  271. PyObject *value) // value to set
  272. {
  273. double doubleValue;
  274. sword status;
  275. doubleValue = PyFloat_AS_DOUBLE(value);
  276. status = OCINumberFromReal(var->environment->errorHandle, &doubleValue,
  277. sizeof(double), &var->data[pos]);
  278. return Environment_CheckForError(var->environment, status,
  279. "NumberVar_SetValueFromFloat()");
  280. }
  281. //-----------------------------------------------------------------------------
  282. // NumberVar_SetValueFromLong()
  283. // Set the value of the variable from a Python long.
  284. //-----------------------------------------------------------------------------
  285. static int NumberVar_SetValueFromLong(
  286. udt_NumberVar *var, // variable to set value for
  287. unsigned pos, // array position to set
  288. PyObject *value) // value to set
  289. {
  290. udt_Buffer textBuffer;
  291. PyObject *textValue;
  292. sword status;
  293. textValue = PyObject_Str(value);
  294. if (!textValue)
  295. return -1;
  296. if (cxBuffer_FromObject(&textBuffer, textValue,
  297. var->environment->encoding) < 0)
  298. return -1;
  299. status = OCINumberFromText(var->environment->errorHandle,
  300. (text*) textBuffer.ptr, textBuffer.size,
  301. (text*) var->environment->numberFromStringFormatBuffer.ptr,
  302. var->environment->numberFromStringFormatBuffer.size, NULL, 0,
  303. &var->data[pos]);
  304. cxBuffer_Clear(&textBuffer);
  305. Py_DECREF(textValue);
  306. return Environment_CheckForError(var->environment, status,
  307. "NumberVar_SetValueFromLong()");
  308. }
  309. //-----------------------------------------------------------------------------
  310. // NumberVar_GetFormatAndTextFromDecimal()
  311. // Return the number format and text to use for the Decimal object.
  312. //-----------------------------------------------------------------------------
  313. static int NumberVar_GetFormatAndTextFromDecimal(
  314. PyObject *tupleValue, // decimal as_tuple() value
  315. PyObject **textObj, // text string for conversion
  316. PyObject **formatObj) // format for conversion
  317. {
  318. long numDigits, scale, i, sign, length, digit;
  319. char *textValue, *format, *textPtr, *formatPtr;
  320. PyObject *digits;
  321. // acquire basic information from the value tuple
  322. sign = PyInt_AsLong(PyTuple_GET_ITEM(tupleValue, 0));
  323. if (PyErr_Occurred())
  324. return -1;
  325. digits = PyTuple_GET_ITEM(tupleValue, 1);
  326. scale = PyInt_AsLong(PyTuple_GET_ITEM(tupleValue, 2));
  327. if (PyErr_Occurred())
  328. return -1;
  329. numDigits = PyTuple_GET_SIZE(digits);
  330. // allocate memory for the string and format to use in conversion
  331. length = numDigits + abs(scale) + 3;
  332. textValue = textPtr = PyMem_Malloc(length);
  333. if (!textValue) {
  334. PyErr_NoMemory();
  335. return -1;
  336. }
  337. format = formatPtr = PyMem_Malloc(length);
  338. if (!format) {
  339. PyMem_Free(textValue);
  340. PyErr_NoMemory();
  341. return -1;
  342. }
  343. // populate the string and format
  344. if (sign)
  345. *textPtr++ = '-';
  346. for (i = 0; i < numDigits + scale; i++) {
  347. *formatPtr++ = '9';
  348. if (i < numDigits) {
  349. digit = PyInt_AsLong(PyTuple_GetItem(digits, i));
  350. if (PyErr_Occurred()) {
  351. PyMem_Free(textValue);
  352. return -1;
  353. }
  354. }
  355. else digit = 0;
  356. *textPtr++ = '0' + (char) digit;
  357. }
  358. if (scale < 0) {
  359. *formatPtr++ = 'D';
  360. *textPtr++ = '.';
  361. for (i = scale; i < 0; i++) {
  362. *formatPtr++ = '9';
  363. if (numDigits + i < 0)
  364. digit = 0;
  365. else {
  366. digit = PyInt_AsLong(PyTuple_GetItem(digits, numDigits + i));
  367. if (PyErr_Occurred()) {
  368. PyMem_Free(textValue);
  369. return -1;
  370. }
  371. }
  372. *textPtr++ = '0' + (char) digit;
  373. }
  374. }
  375. *formatPtr = '\0';
  376. *textPtr = '\0';
  377. *textObj = cxString_FromAscii(textValue);
  378. PyMem_Free(textValue);
  379. if (!*textObj) {
  380. PyMem_Free(format);
  381. return -1;
  382. }
  383. *formatObj = cxString_FromAscii(format);
  384. PyMem_Free(format);
  385. if (!*formatObj) {
  386. Py_DECREF(*textObj);
  387. return -1;
  388. }
  389. return 0;
  390. }
  391. //-----------------------------------------------------------------------------
  392. // NumberVar_SetValueFromDecimal()
  393. // Set the value of the variable from a Python decimal.Decimal object.
  394. //-----------------------------------------------------------------------------
  395. static int NumberVar_SetValueFromDecimal(
  396. udt_NumberVar *var, // variable to set value for
  397. unsigned pos, // array position to set
  398. PyObject *value) // value to set
  399. {
  400. PyObject *textValue, *format, *tupleValue;
  401. udt_Buffer textBuffer, formatBuffer;
  402. sword status;
  403. tupleValue = PyObject_CallMethod(value, "as_tuple", NULL);
  404. if (!tupleValue)
  405. return -1;
  406. if (NumberVar_GetFormatAndTextFromDecimal(tupleValue, &textValue,
  407. &format) < 0) {
  408. Py_DECREF(tupleValue);
  409. return -1;
  410. }
  411. Py_DECREF(tupleValue);
  412. if (cxBuffer_FromObject(&textBuffer, textValue,
  413. var->environment->encoding) < 0)
  414. return -1;
  415. if (cxBuffer_FromObject(&formatBuffer, format,
  416. var->environment->encoding) < 0) {
  417. cxBuffer_Clear(&textBuffer);
  418. return -1;
  419. }
  420. status = OCINumberFromText(var->environment->errorHandle,
  421. (text*) textBuffer.ptr, textBuffer.size, (text*) formatBuffer.ptr,
  422. formatBuffer.size,
  423. var->environment->nlsNumericCharactersBuffer.ptr,
  424. var->environment->nlsNumericCharactersBuffer.size,
  425. &var->data[pos]);
  426. cxBuffer_Clear(&textBuffer);
  427. cxBuffer_Clear(&formatBuffer);
  428. Py_DECREF(textValue);
  429. Py_DECREF(format);
  430. return Environment_CheckForError(var->environment, status,
  431. "NumberVar_SetValueFromDecimal()");
  432. }
  433. //-----------------------------------------------------------------------------
  434. // NumberVar_SetValue()
  435. // Set the value of the variable.
  436. //-----------------------------------------------------------------------------
  437. static int NumberVar_SetValue(
  438. udt_NumberVar *var, // variable to set value for
  439. unsigned pos, // array position to set
  440. PyObject *value) // value to set
  441. {
  442. #if PY_MAJOR_VERSION < 3
  443. if (PyInt_Check(value))
  444. return NumberVar_SetValueFromInteger(var, pos, value);
  445. #endif
  446. if (PyBool_Check(value))
  447. return NumberVar_SetValueFromBoolean(var, pos, value);
  448. if (PyLong_Check(value))
  449. return NumberVar_SetValueFromLong(var, pos, value);
  450. if (PyFloat_Check(value))
  451. return NumberVar_SetValueFromFloat(var, pos, value);
  452. if (Py_TYPE(value) == g_DecimalType)
  453. return NumberVar_SetValueFromDecimal(var, pos, value);
  454. PyErr_SetString(PyExc_TypeError, "expecting numeric data");
  455. return -1;
  456. }
  457. //-----------------------------------------------------------------------------
  458. // NumberVar_GetValue()
  459. // Returns the value stored at the given array position.
  460. //-----------------------------------------------------------------------------
  461. static PyObject *NumberVar_GetValue(
  462. udt_NumberVar *var, // variable to determine value for
  463. unsigned pos) // array position
  464. {
  465. PyObject *result, *stringObj;
  466. char stringValue[200];
  467. long integerValue;
  468. ub4 stringLength;
  469. sword status;
  470. if (var->type == &vt_Boolean || var->type == &vt_Integer) {
  471. status = OCINumberToInt(var->environment->errorHandle, &var->data[pos],
  472. sizeof(long), OCI_NUMBER_SIGNED, (dvoid*) &integerValue);
  473. if (Environment_CheckForError(var->environment, status,
  474. "NumberVar_GetValue(): as integer") < 0)
  475. return NULL;
  476. if (var->type == &vt_Boolean)
  477. return PyBool_FromLong(integerValue);
  478. #if PY_MAJOR_VERSION >= 3
  479. return PyLong_FromLong(integerValue);
  480. #else
  481. return PyInt_FromLong(integerValue);
  482. #endif
  483. }
  484. if (var->type == &vt_NumberAsString || var->type == &vt_LongInteger) {
  485. stringLength = sizeof(stringValue);
  486. status = OCINumberToText(var->environment->errorHandle,
  487. &var->data[pos],
  488. (text*) var->environment->numberToStringFormatBuffer.ptr,
  489. var->environment->numberToStringFormatBuffer.size, NULL, 0,
  490. &stringLength, (unsigned char*) stringValue);
  491. if (Environment_CheckForError(var->environment, status,
  492. "NumberVar_GetValue(): as string") < 0)
  493. return NULL;
  494. stringObj = cxString_FromEncodedString(stringValue, stringLength,
  495. var->environment->encoding);
  496. if (!stringObj)
  497. return NULL;
  498. if (var->type == &vt_NumberAsString)
  499. return stringObj;
  500. #if PY_MAJOR_VERSION >= 3
  501. result = PyNumber_Long(stringObj);
  502. #else
  503. result = PyNumber_Int(stringObj);
  504. #endif
  505. Py_DECREF(stringObj);
  506. if (result || !PyErr_ExceptionMatches(PyExc_ValueError))
  507. return result;
  508. PyErr_Clear();
  509. }
  510. return OracleNumberToPythonFloat(var->environment, &var->data[pos]);
  511. }
  512. //-----------------------------------------------------------------------------
  513. // NativeFloatVar_GetValue()
  514. // Returns the value stored at the given array position as a float.
  515. //-----------------------------------------------------------------------------
  516. static PyObject *NativeFloatVar_GetValue(
  517. udt_NativeFloatVar *var, // variable to determine value for
  518. unsigned pos) // array position
  519. {
  520. return PyFloat_FromDouble(var->data[pos]);
  521. }
  522. //-----------------------------------------------------------------------------
  523. // NativeFloatVar_SetValue()
  524. // Set the value of the variable which should be a native double.
  525. //-----------------------------------------------------------------------------
  526. static int NativeFloatVar_SetValue(
  527. udt_NativeFloatVar *var, // variable to set value for
  528. unsigned pos, // array position to set
  529. PyObject *value) // value to set
  530. {
  531. if (!PyFloat_Check(value)) {
  532. PyErr_SetString(PyExc_TypeError, "expecting float");
  533. return -1;
  534. }
  535. var->data[pos] = PyFloat_AS_DOUBLE(value);
  536. return 0;
  537. }