def _from_python(param, value, encoding): is_null = ffi.new('unsigned int *', value is None) param.value.is_null = is_null if is_null[0]: value = 0 if param.value.type == lib.A_INVALID_TYPE: param.value.type = _infer_type(param, value) fmt = _FORMATS[param.value.type] if fmt == 'x': if isinstance(value, bytes): size = length = len(value) elif isinstance(value, str): param.value.type = lib.A_NCHAR value = value.encode('utf-16') size = length = len(value) + 2 # +2 for the BOM chars else: try: value = str(value).encode('ascii') except UnicodeEncodeError: raise DataError('Cannot convert value {}'.format(value)) size = length = len(value) else: value = struct.pack(fmt, value) size = length = struct.calcsize(fmt) buf = ffi.new('char[]', value) param.value.buffer = buf param.value.buffer_size = size l = ffi.new('unsigned int *', length) param.value.length = l _ref_bucket[param] = (is_null, buf, l)
def bind(self, i, value): param = ffi.new('struct a_ads_bind_param *') if not lib.ads_describe_bind_param(self.stmt, i, param): raise DatabaseError(*_error(self.handler)) _from_python(param, value, self.encoding) if not lib.ads_bind_param(self.stmt, i, param): raise DatabaseError(*_error(self.handler))
def column_info(self, i): info = ffi.new('struct a_ads_column_info *') lib.ads_get_column_info(self.stmt, i, info) if info.native_type in _UNICODE_FIELD: # Precision and size here are in bytes, so convert it to chars # for unicode fields info.precision = info.precision // 2 info.max_size = info.max_size // 2 return (ffi.string(info.name).decode('ascii', 'ignore'), info.native_type, None, info.max_size, info.precision, info.scale, info.nullable)
def _error(handler): buflength = lib.ADS_MAX_ERROR_LEN buf = ffi.new('char[]', buflength + 1) errno = lib.ads_error(handler, buf, buflength) if errno == 0: return 'internal error: success', 0 msg = ffi.string(buf, buflength + 1).decode('ascii', 'ignore').rstrip() if errno == 7200: # because 7200 seems to be a generic error we look for a more specific # error code and we report that instead matchobj = _NATIVE_ERROR_RE.search(msg) if matchobj is not None: errno = int(matchobj.group('errno') or 0) return msg, errno
def iter_columns(self): data_value = ffi.new('struct a_ads_data_value *') for i in range(self.num_cols()): if not lib.ads_get_column(self.stmt, i, data_value): raise DatabaseError(*_error(self.handler)) yield _to_python(data_value, self.encoding)
def _transaction_count(self): c = ffi.new('unsigned int *') if lib.AdsGetTransactionCount(self._handler.handle, c): raise OperationalError(*_error(self._handler)) return c[0]
def _in_transaction(self): in_trans = ffi.new('unsigned short int[1]') if lib.AdsInTransaction(self._handler.handle, in_trans): raise OperationalError(*_error(self._handler)) return bool(in_trans[0])
_MAX_INT32 = 2**31 - 1 _MIN_INT64 = -(2**63) _MAX_INT64 = 2**63 - 1 _TIME_RE = re.compile(r'^' r'(?P<hour>\d{2})' r':' r'(?P<minute>\d{2})' r':' r'(?P<second>\d{2})' r'(?P<microsecond>\.\d+)?' r'(?: (?P<ampm>AM|PM))?' r'$') _NATIVE_ERROR_RE = re.compile(r'NativeError\s+=\s+(?P<errno>\d+);') _ref_bucket = weakref.WeakKeyDictionary() ver = ffi.new('unsigned int[1]', [API_VERSION]) if not lib.ads_init(b'adsdb3', API_VERSION, ver): raise ImportError('Error initializing libace') if ver[0] != API_VERSION: lib.ads_fini() raise ImportError('Incompatible libace version %s. Required %s' % (ver[0], API_VERSION)) del ver class DBAPITypeObject: def __init__(self, *values): self.values = frozenset(values) def __eq__(self, other): if other in self.values:
def test_init(self): ver = ffi.new('unsigned int[1]', [1]) try: self.assertEqual(lib.ads_init(b'test', 1, ver), 1) finally: lib.ads_fini()