text: //-----------------------------------------------------------------------------
  // Copyright 2018, Oracle and/or its affiliates. All rights reserved.
  //-----------------------------------------------------------------------------
  
  //-----------------------------------------------------------------------------
  // cxoVarType.c
  //   Defines variable types for various transformations.
  //-----------------------------------------------------------------------------
  
  #include "cxoModule.h"
  
  // define variable types for each of the supported transforms
  static cxoVarType cxoAllVarTypes[] = {
      {
          CXO_TRANSFORM_NONE,
          &cxoPyTypeStringVar,
          1
      },
      {
          CXO_TRANSFORM_BINARY,
          &cxoPyTypeBinaryVar,
          4000
      },
      {
          CXO_TRANSFORM_BFILE,
          &cxoPyTypeBfileVar,
          0
      },
      {
          CXO_TRANSFORM_BLOB,
          &cxoPyTypeBlobVar,
          0
      },
      {
          CXO_TRANSFORM_BOOLEAN,
          &cxoPyTypeBooleanVar,
          0
      },
      {
          CXO_TRANSFORM_CLOB,
          &cxoPyTypeClobVar,
          0
      },
      {
          CXO_TRANSFORM_CURSOR,
          &cxoPyTypeCursorVar,
          0
      },
      {
          CXO_TRANSFORM_DATE,
          &cxoPyTypeDateTimeVar,
          0
      },
      {
          CXO_TRANSFORM_DATETIME,
          &cxoPyTypeDateTimeVar,
          0
      },
      {
          CXO_TRANSFORM_DECIMAL,
          &cxoPyTypeNumberVar,
          1000
      },
      {
          CXO_TRANSFORM_FIXED_CHAR,
          &cxoPyTypeFixedCharVar,
          2000
      },
      {
          CXO_TRANSFORM_FIXED_NCHAR,
          &cxoPyTypeFixedNcharVar,
          2000
      },
      {
          CXO_TRANSFORM_FLOAT,
          &cxoPyTypeNumberVar,
          0
      },
      {
          CXO_TRANSFORM_INT,
          &cxoPyTypeNumberVar,
          0
      },
      {
          CXO_TRANSFORM_LONG_BINARY,
          &cxoPyTypeLongBinaryVar,
          128 * 1024
      },
      {
          CXO_TRANSFORM_LONG_INT,
          &cxoPyTypeNumberVar,
          250,
      },
      {
          CXO_TRANSFORM_LONG_STRING,
          &cxoPyTypeLongStringVar,
          128 * 1024
      },
      {
          CXO_TRANSFORM_NATIVE_DOUBLE,
          &cxoPyTypeNativeFloatVar,
          0
      },
      {
          CXO_TRANSFORM_NATIVE_FLOAT,
          &cxoPyTypeNativeFloatVar,
          0
      },
      {
          CXO_TRANSFORM_NATIVE_INT,
          &cxoPyTypeNativeIntVar,
          0
      },
      {
          CXO_TRANSFORM_NCLOB,
          &cxoPyTypeNclobVar,
          0
      },
      {
          CXO_TRANSFORM_NSTRING,
          &cxoPyTypeNcharVar,
          4000
      },
      {
          CXO_TRANSFORM_OBJECT,
          &cxoPyTypeObjectVar,
          0
      },
      {
          CXO_TRANSFORM_ROWID,
          &cxoPyTypeRowidVar,
          0
      },
      {
          CXO_TRANSFORM_STRING,
          &cxoPyTypeStringVar,
          4000
      },
      {
          CXO_TRANSFORM_TIMEDELTA,
          &cxoPyTypeIntervalVar,
          0
      },
      {
          CXO_TRANSFORM_TIMESTAMP,
          &cxoPyTypeTimestampVar,
          0
      },
      {
          CXO_TRANSFORM_TIMESTAMP_LTZ,
          &cxoPyTypeTimestampVar,
          0
      }
  };
  
  
  //-----------------------------------------------------------------------------
  // cxoVarType_fromDataTypeInfo()
  //   Return a variable type given query metadata, or NULL indicating that the
  // data indicated by the query metadata is not supported.
  //-----------------------------------------------------------------------------
  cxoVarType *cxoVarType_fromDataTypeInfo(dpiDataTypeInfo *info)
  {
      cxoTransformNum transformNum;
      char message[120];
  
      transformNum = cxoTransform_getNumFromDataTypeInfo(info);
      if (transformNum == CXO_TRANSFORM_UNSUPPORTED) {
          snprintf(message, sizeof(message), "Oracle type %d not supported.",
                  info->oracleTypeNum);
          cxoError_raiseFromString(cxoNotSupportedErrorException, message);
          return NULL;
      }
      return &cxoAllVarTypes[transformNum];
  }
  
  
  //-----------------------------------------------------------------------------
  // cxoVarType_fromPythonType()
  //   Return a variable type given a Python type object or NULL if the Python
  // type does not have a corresponding variable type.
  //-----------------------------------------------------------------------------
  cxoVarType *cxoVarType_fromPythonType(PyTypeObject *type)
  {
      cxoTransformNum transformNum;
      char message[250];
  
      transformNum = cxoTransform_getNumFromType(type);
      if (transformNum == CXO_TRANSFORM_UNSUPPORTED) {
          snprintf(message, sizeof(message), "Python type %s not supported.",
                  type->tp_name);
          cxoError_raiseFromString(cxoNotSupportedErrorException, message);
          return NULL;
      }
      return &cxoAllVarTypes[transformNum];
  }
  
  
  //-----------------------------------------------------------------------------
  // cxoVarType_calculateSize()
  //   Calculate the size to use with the specified transform and Python value.
  // This function is only called by cxoVarType_fromPythonValue() and no attempt
  // is made to verify the value further.
  //-----------------------------------------------------------------------------
  static Py_ssize_t cxoVarType_calculateSize(PyObject *value,
          cxoTransformNum transformNum)
  {
      Py_ssize_t size = 0;
  #if PY_MAJOR_VERSION < 3
      const void *ptr;
  #endif
  
      switch (transformNum) {
          case CXO_TRANSFORM_NONE:
              return 1;
          case CXO_TRANSFORM_BINARY:
  #if PY_MAJOR_VERSION >= 3
              return PyBytes_GET_SIZE(value);
  #else
              PyObject_AsReadBuffer(value, &ptr, &size);
              return size;
  #endif
          case CXO_TRANSFORM_NSTRING:
              size = PyUnicode_GET_SIZE(value);
              return (size == 0) ? 1 : size;
          case CXO_TRANSFORM_STRING:
  #if PY_MAJOR_VERSION >= 3
              size = PyUnicode_GET_SIZE(value);
  #else
              size = PyString_GET_SIZE(value);
  #endif
              return (size == 0) ? 1 : size;
          default:
              break;
      }
      return 0;
  }
  
  
  //-----------------------------------------------------------------------------
  // cxoVarType_fromPythonValue()
  //   Return a variable type given a Python object or NULL if the Python object
  // does not have a corresponding variable type.
  //-----------------------------------------------------------------------------
  cxoVarType *cxoVarType_fromPythonValue(PyObject *value, int *isArray,
          Py_ssize_t *size, Py_ssize_t *numElements, int plsql)
  {
      cxoTransformNum transformNum, tempTransformNum;
      PyObject *elementValue;
      Py_ssize_t i, tempSize;
      char message[250];
  
      // initialization (except numElements which always has a valid value and is
      // only overridden when a an array is encountered)
      *size = 0;
      *isArray = 0;
  
      // handle arrays
      if (PyList_Check(value)) {
          transformNum = CXO_TRANSFORM_NONE;
          for (i = 0; i < PyList_GET_SIZE(value); i++) {
              elementValue = PyList_GET_ITEM(value, i);
              tempTransformNum = cxoTransform_getNumFromValue(elementValue, 1);
              if (tempTransformNum == CXO_TRANSFORM_UNSUPPORTED) {
                  snprintf(message, sizeof(message),
                          "element %u value is unsupported", (unsigned) i);
                  cxoError_raiseFromString(cxoNotSupportedErrorException,
                          message);
                  return NULL;
              } else if (transformNum == CXO_TRANSFORM_NONE) {
                  transformNum = tempTransformNum;
              } else if (transformNum != tempTransformNum) {
                  snprintf(message, sizeof(message),
                          "element %u value is not the same type as previous "
                          "elements", (unsigned) i);
                  cxoError_raiseFromString(cxoNotSupportedErrorException,
                          message);
                  return NULL;
              }
              tempSize = cxoVarType_calculateSize(elementValue,
                      tempTransformNum);
              if (tempSize > *size)
                  *size = tempSize;
          }
          *isArray = 1;
          *numElements = PyList_GET_SIZE(value);
          return &cxoAllVarTypes[transformNum];
      }
  
      // handle scalar values
      transformNum = cxoTransform_getNumFromValue(value, plsql);
      if (transformNum == CXO_TRANSFORM_UNSUPPORTED) {
          snprintf(message, sizeof(message),
                  "Python value of type %s not supported.",
                  Py_TYPE(value)->tp_name);
          cxoError_raiseFromString(cxoNotSupportedErrorException, message);
          return NULL;
      }
      *size = cxoVarType_calculateSize(value, transformNum);
      return &cxoAllVarTypes[transformNum];
  }
  
  