From 8eae32f0d7fee5cfd76a261c5b70ab4570858e80 Mon Sep 17 00:00:00 2001 From: asardesai2 Date: Thu, 9 Nov 2023 20:46:10 +0530 Subject: [PATCH] Allow parameter binding Arrays and Tuples Signed-off-by: asardesai2 --- comdb2/_ccdb2.pyx | 56 +++++++++++++++++++++++++++++++++++++++++---- comdb2/_cdb2api.pxd | 3 ++- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/comdb2/_ccdb2.pyx b/comdb2/_ccdb2.pyx index a439d91..f41df27 100644 --- a/comdb2/_ccdb2.pyx +++ b/comdb2/_ccdb2.pyx @@ -100,13 +100,15 @@ cdef _bind_datetime(obj, client_datetime *val): cdef class _ParameterValue(object): - cdef int type + cdef lib.cdb2_coltype type cdef int size cdef void *data cdef object owner + cdef int list_size def __cinit__(self, obj, param_name): try: + self.list_size = -1 if obj is None: self.type = lib.CDB2_INTEGER self.owner = None @@ -153,6 +155,48 @@ cdef class _ParameterValue(object): self.data = PyMem_Malloc(self.size) _bind_datetime(obj, self.data) return + elif isinstance(obj, (list, tuple)): + # Size of the list. + self.list_size = len(obj) + # Check if all elements are integers + if all(isinstance(ele, six.integer_types) for ele in obj): + self.type = lib.CDB2_INTEGER + self.size = sizeof(long long) + self.owner = None + self.data = PyMem_Malloc(self.list_size*self.size) + for l_index in range(self.list_size): + (self.data)[l_index] = obj[l_index] + return + # Check all elements are floats + elif all(isinstance(ele, float) for ele in obj): + self.type = lib.CDB2_REAL + self.size = sizeof(double) + self.owner = None + self.data = PyMem_Malloc(self.list_size*self.size) + for l_index in range(self.list_size): + (self.data)[l_index] = obj[l_index] + return + # Check all elements are bytes + elif all(isinstance(ele, bytes) for ele in obj): + self.type = lib.CDB2_BLOB + self.size = sizeof(size_t) + sizeof(char*) + self.owner = obj + self.data = PyMem_Malloc(self.list_size*self.size) + for l_index in range(self.list_size): + (self.data)[2 * l_index] = len(self.owner[l_index]) + (self.data)[2 * l_index + 1] = (self.owner[l_index]) + return + # Check all elements are unicode + elif all(isinstance(ele, unicode) for ele in obj): + self.type = lib.CDB2_CSTRING + self.size = sizeof(char*) + # Strings need to be converted to bytes + self.owner = [x.encode('utf-8') for x in obj] + self.data = PyMem_Malloc(self.list_size*self.size) + for l_index in range(self.list_size): + (self.data)[l_index] = (self.owner[l_index]) + return + except Exception as e: exc = e else: @@ -178,7 +222,7 @@ cdef class _ParameterValue(object): def __dealloc__(self): - if self.owner is None: + if self.owner is None or self.list_size != -1: PyMem_Free(self.data) @@ -344,8 +388,12 @@ cdef class Handle(object): cval = _ParameterValue(val, key) param_guards.append(ckey) param_guards.append(cval) - rc = lib.cdb2_bind_param(self.hndl, ckey, - cval.type, cval.data, cval.size) + if cval.list_size == -1: + rc = lib.cdb2_bind_param(self.hndl, ckey, + cval.type, cval.data, cval.size) + else: + # Bind Array if cval is an array + rc = lib.cdb2_bind_array(self.hndl, ckey, cval.type, cval.data, cval.list_size, cval.size) _errchk(rc, self.hndl) with nogil: diff --git a/comdb2/_cdb2api.pxd b/comdb2/_cdb2api.pxd index 40c84ab..afae380 100644 --- a/comdb2/_cdb2api.pxd +++ b/comdb2/_cdb2api.pxd @@ -18,7 +18,7 @@ cdef extern from "cdb2api.h" nogil: CDB2ERR_NOTSUPPORTED CDB2ERR_CONV_FAIL - enum: + enum cdb2_coltype: CDB2_INTEGER CDB2_REAL CDB2_CSTRING @@ -75,5 +75,6 @@ cdef extern from "cdb2api.h" nogil: void* cdb2_column_value(cdb2_hndl_tp* hndl, int col); const char* cdb2_errstr(cdb2_hndl_tp* hndl); int cdb2_bind_param(cdb2_hndl_tp *hndl, const char *name, int type, const void *varaddr, int length); + int cdb2_bind_array(cdb2_hndl_tp *hndl, const char *name, cdb2_coltype, const void *varaddr, size_t count, size_t typelen); int cdb2_clearbindings(cdb2_hndl_tp *hndl); int cdb2_clear_ack(cdb2_hndl_tp *hndl);