Beispiel #1
0
static PyObject *checker_standard(PyObject *self, PyObject *args) {
	PyObject *expected, *actual, *result;

	UNREFERENCED_PARAMETER(self);
	if (!PyArg_ParseTuple(args, "OO:standard", &expected, &actual))
		return NULL;

	if (!PyStr_Check(expected) || !PyStr_Check(actual)) {
		PyErr_SetString(PyExc_ValueError, "expected strings");
		return NULL;
	}

	Py_INCREF(expected);
	Py_INCREF(actual);
	Py_BEGIN_ALLOW_THREADS
	result = check_standard(PyStr_AsString(expected), PyStr_Size(expected),
							PyStr_AsString(actual), PyStr_Size(actual)) ?
			Py_True : Py_False;
	Py_END_ALLOW_THREADS
	Py_DECREF(expected);
	Py_DECREF(actual);
	Py_INCREF(result);
	return result;
}
/**
 *******************************************************************************************************
 * Callback for as_info_foreach().
 *
 * @param err                   The as_error to be populated by the function
 *                              with the encountered error if any.
 * @param node                  The current as_node object for which the
 *                              callback is fired by c client.
 * @param req                   The info request string.
 * @param res                   The info response string for current node.
 * @pram udata                  The callback udata containing the host_lookup
 *                              array and the return zval to be populated with
 *                              an entry for current node's info response with
 *                              the node's ID as the key.
 *
 * Returns true if callback is successful, Otherwise false.
 *******************************************************************************************************
 */
static bool AerospikeClient_Info_each(as_error * err, const as_node * node, const char * req, char * res, void * udata)
{
	PyObject * py_err = NULL;
	PyObject * py_ustr = NULL;
	PyObject * py_out = NULL;
	foreach_callback_info_udata* udata_ptr = (foreach_callback_info_udata *) udata;
	struct sockaddr_in* addr = NULL;


	if ( err && err->code != AEROSPIKE_OK ) {
		as_error_update(err, err->code, NULL);
        goto CLEANUP;
	}
	else if ( res != NULL ) {
		char * out = strchr(res,'\t');
		if ( out != NULL ) {
			out++;
			py_out = PyStr_FromString(out);
		}
		else {
			py_out = PyStr_FromString(res);
		}
	}

	if ( py_err == NULL ) {
		Py_INCREF(Py_None);
		py_err = Py_None;
	}

	if ( py_out == NULL ) {
		Py_INCREF(Py_None);
		py_out = Py_None;
	}

	PyObject * py_res = PyTuple_New(2);
	PyTuple_SetItem(py_res, 0, py_err);
	PyTuple_SetItem(py_res, 1, py_out);

	if(udata_ptr->host_lookup_p) {
		PyObject * py_hosts = (PyObject *)udata_ptr->host_lookup_p;
			if ( py_hosts && PyList_Check(py_hosts) ) {
				addr = as_node_get_address((as_node *)node);
				int size = (int) PyList_Size(py_hosts);
				for ( int i = 0; i < size && i < AS_CONFIG_HOSTS_SIZE; i++ ) {
					char * host_addr = NULL;
					int port = -1;
					PyObject * py_host = PyList_GetItem(py_hosts, i);
					if ( PyTuple_Check(py_host) && PyTuple_Size(py_host) == 2 ) {
						PyObject * py_addr = PyTuple_GetItem(py_host,0);
						PyObject * py_port = PyTuple_GetItem(py_host,1);
						if ( PyStr_Check(py_addr) ) {
							host_addr = PyStr_AsString(py_addr);
						}
						else if (PyUnicode_Check(py_addr)) {
							py_ustr = PyUnicode_AsUTF8String(py_addr);
							host_addr = PyStr_AsString(py_ustr);
						} else {
							as_error_update(&udata_ptr->error, AEROSPIKE_ERR_PARAM, "Host address is of type incorrect");
							if (py_res) {
								Py_DECREF(py_res);
							}
							return false;
						}
						if ( PyInt_Check(py_port) ) {
							port = (uint16_t) PyInt_AsLong(py_port);
						}
						else if ( PyLong_Check(py_port) ) {
							port = (uint16_t) PyLong_AsLong(py_port);
						} else {
							break;
						}
						char ip_port[IP_PORT_MAX_LEN];
						inet_ntop(addr->sin_family, &(addr->sin_addr), ip_port, INET_ADDRSTRLEN);
						if( (!strcmp(host_addr,ip_port)) && (port
												== ntohs(addr->sin_port))) {
							PyObject * py_nodes = (PyObject *) udata_ptr->udata_p;
							PyDict_SetItemString(py_nodes, node->name, py_res);
						}	
					}
				}
			} else if ( !PyList_Check( py_hosts )){
				as_error_update(&udata_ptr->error, AEROSPIKE_ERR_PARAM, "Hosts should be specified in a list.");
				goto CLEANUP;
			}
	} else {
		PyObject * py_nodes = (PyObject *) udata_ptr->udata_p;
		PyDict_SetItemString(py_nodes, node->name, py_res);
	}
	Py_DECREF(py_res);
CLEANUP:
	if ( udata_ptr->error.code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject( &udata_ptr->error, &py_err);
		PyObject *exception_type = raise_exception(&udata_ptr->error);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}
	if ( err->code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(err, &py_err);
		PyObject *exception_type = raise_exception(err);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}
	return true;
}
/**
 *******************************************************************************************************
 * Sends an info request to all the nodes in a cluster.
 *
 * @param self                  AerospikeClient object
 * @param args                  The args is a tuple object containing an argument
 *                              list passed from Python to a C function
 * @param kwds                  Dictionary of keywords
 *
 * Returns a server response for the particular request string.
 * In case of error,appropriate exceptions will be raised.
 *******************************************************************************************************
 */
PyObject * AerospikeClient_Info(AerospikeClient * self, PyObject * args, PyObject * kwds)
{
	PyObject * py_req = NULL;
	PyObject * py_policy = NULL;
	PyObject * py_hosts = NULL;
	PyObject * py_nodes = NULL;
	PyObject * py_ustr = NULL;
	foreach_callback_info_udata info_callback_udata;

	static char * kwlist[] = {"command", "hosts", "policy", NULL};

	if ( PyArg_ParseTupleAndKeywords(args, kwds, "O|OO:info", kwlist, &py_req, &py_hosts, &py_policy) == false ) {
		return NULL;
	}

	as_error err;
	as_error_init(&err);

	as_policy_info info_policy;
	as_policy_info* info_policy_p = NULL;
	py_nodes = PyDict_New();
	info_callback_udata.udata_p = py_nodes;
	info_callback_udata.host_lookup_p = py_hosts;
	as_error_init(&info_callback_udata.error);

	if (!self || !self->as) {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object");
		goto CLEANUP;
	}
	if (!self->is_conn_16) {
		as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
		goto CLEANUP;
	}

	// Convert python policy object to as_policy_info
	pyobject_to_policy_info(&err, py_policy, &info_policy, &info_policy_p,
					&self->as->config.policies.info);
	if ( err.code != AEROSPIKE_OK ) {
		goto CLEANUP;
	}
	char * req = NULL;
	if ( PyUnicode_Check(py_req)) {
		py_ustr = PyUnicode_AsUTF8String(py_req);
		req = PyStr_AsString(py_ustr);
	} else if( PyStr_Check(py_req) ) {
		req = PyStr_AsString(py_req);
	} else {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Request must be a string");
		goto CLEANUP;
	}
	aerospike_info_foreach(self->as, &err, info_policy_p, req,
					(aerospike_info_foreach_callback)AerospikeClient_Info_each,
					&info_callback_udata);

	if (&info_callback_udata.error.code != AEROSPIKE_OK) {
		as_error_update(&err, err.code, NULL);
		goto CLEANUP;
	}
CLEANUP:
	if (py_ustr) {
		Py_DECREF(py_ustr);
	}
	if ( info_callback_udata.error.code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(&info_callback_udata.error, &py_err);
		PyObject *exception_type = raise_exception(&info_callback_udata.error);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		if (py_nodes) {
			Py_DECREF(py_nodes);
		}
		return NULL;
	}
	if ( err.code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(&err, &py_err);
		PyObject *exception_type = raise_exception(&err);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		if (py_nodes) {
			Py_DECREF(py_nodes);
		}
		return NULL;
	}

	return info_callback_udata.udata_p;
}
/**
 ******************************************************************************************************
 * Removes a bin from a record.
 *
 * @param self                  AerospikeClient object
 * @prama py_key                The key for the record.
 * @pram py_binList             The name of the bins to be removed from the record.
 * @param py_policy             The optional policies.
 * @param err                   The C client's as_error to be set to the encountered error.
 *
 * Returns an integer status. 0(Zero) is success value.
 * In case of error,appropriate exceptions will be raised.
 *******************************************************************************************************
 */
static
PyObject * AerospikeClient_RemoveBin_Invoke(
		AerospikeClient * self,
		PyObject * py_key,PyObject* py_binList ,PyObject * py_policy, PyObject * py_meta, as_error *err)
{

	// Aerospike Client Arguments
	as_policy_write write_policy;
	as_policy_write * write_policy_p = NULL;
	as_key key;
	as_record rec;
	char* binName = NULL;
	int count = 0;
	PyObject * py_ustr = NULL;

	// Get the bin list size;
	Py_ssize_t size = PyList_Size(py_binList);
	// Initialize record
	as_record_inita(&rec, size);

	// Convert python key object to as_key
	pyobject_to_key(err, py_key, &key);
	if ( err->code != AEROSPIKE_OK ) {
		goto CLEANUP;
	}

	// Convert python policy object to as_policy_write
	pyobject_to_policy_write(err, py_policy, &write_policy, &write_policy_p,
			&self->as->config.policies.write);
	if ( err->code != AEROSPIKE_OK ) {
		as_error_update(err, AEROSPIKE_ERR_CLIENT, "Incorrect policy");
		goto CLEANUP;
	}

	// Invoke operation

	for ( count = 0; count < size; count++ ) {
		PyObject * py_val = PyList_GetItem(py_binList, count);
		if( PyUnicode_Check(py_val) ){
			py_ustr = PyUnicode_AsUTF8String(py_val);
			binName = PyStr_AsString(py_ustr);
		}
		else if( PyStr_Check(py_val) ) {
			binName = PyStr_AsString(py_val);
		}
		else
		{
			as_error_update(err, AEROSPIKE_ERR_CLIENT, "Invalid bin name, bin name should be a string or unicode string")
			goto CLEANUP;
		}
		if (!as_record_set_nil(&rec, binName)){
			goto CLEANUP;
		}
		if (py_ustr) {
			Py_DECREF(py_ustr);
			py_ustr = NULL;
		}
	}

	if ( py_meta && PyDict_Check(py_meta) ) {
		PyObject * py_gen = PyDict_GetItemString(py_meta, "gen");
		PyObject * py_ttl = PyDict_GetItemString(py_meta, "ttl");

		if( py_ttl != NULL ){
			if ( PyInt_Check(py_ttl) ) {
				rec.ttl = (uint32_t) PyInt_AsLong(py_ttl);
			}
			else if ( PyLong_Check(py_ttl) ) {
				rec.ttl = (uint32_t) PyLong_AsLongLong(py_ttl);
                if((uint32_t)-1 == rec.ttl) {
				    as_error_update(err, AEROSPIKE_ERR_PARAM, "integer value for ttl exceeds sys.maxsize");
			        goto CLEANUP;
                }
			}
			else
			{
				as_error_update(err, AEROSPIKE_ERR_PARAM, "Ttl should be an int or long");
			    goto CLEANUP;
			}
		}

		if( py_gen != NULL ){
			if ( PyInt_Check(py_gen) ) {
				rec.gen = (uint16_t) PyInt_AsLong(py_gen);
			}
			else if ( PyLong_Check(py_gen) ) {
				rec.gen = (uint16_t) PyLong_AsLongLong(py_gen);
                if((uint16_t)-1 == rec.gen) {
                    as_error_update(err, AEROSPIKE_ERR_PARAM, "integer value for gen exceeds sys.maxsize");
			        goto CLEANUP;
                }
			}
			else
			{
				as_error_update(err, AEROSPIKE_ERR_PARAM, "Generation should be an int or long");
			    goto CLEANUP;
			}
		}
	}

    Py_BEGIN_ALLOW_THREADS
	aerospike_key_put(self->as, err, write_policy_p, &key, &rec);
    Py_END_ALLOW_THREADS
    if (err->code != AEROSPIKE_OK)
	{
		as_error_update(err, err->code, NULL);
		goto CLEANUP;
	}

CLEANUP:

	as_record_destroy(&rec);

	if ( err->code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(err, &py_err);
		PyObject *exception_type = raise_exception(err);
		if(PyObject_HasAttrString(exception_type, "key")) {
			PyObject_SetAttrString(exception_type, "key", py_key);
		} 
		if(PyObject_HasAttrString(exception_type, "bin")) {
			PyObject_SetAttrString(exception_type, "bin", Py_None);
		}
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}
	return PyLong_FromLong(0);
}
AerospikeQuery * AerospikeQuery_Apply(AerospikeQuery * self, PyObject * args, PyObject * kwds)
{

	// Python function arguments
	PyObject * py_module = NULL;
	PyObject * py_function = NULL;
	PyObject * py_args = NULL;
	PyObject * py_policy = NULL;

	PyObject * py_umodule   = NULL;
	PyObject * py_ufunction = NULL;
	// Python function keyword arguments
	static char * kwlist[] = {"module", "function", "arguments", "policy", NULL};

	if ( PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO:apply", kwlist, &py_module, &py_function, &py_args, &py_policy) == false ){
		return NULL;
	}

	// Aerospike error object
	as_error err;
	// Initialize error object
	as_error_init(&err);

	if ( !self || !self->client->as ){
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid query object");
		goto CLEANUP;
	}

	if (!self->client->is_conn_16) {
		as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
		goto CLEANUP;
	}

	// Aerospike API Arguments
	char * module = NULL;
	char * function = NULL;
	as_arraylist * arglist = NULL;

	if ( PyUnicode_Check(py_module) ){
		py_umodule = PyUnicode_AsUTF8String(py_module);
		module = PyStr_AsString(py_umodule);
	}
	else if ( PyStr_Check(py_module) ) {
		module = PyStr_AsString(py_module);
	}
	else {
		as_error_update(&err, AEROSPIKE_ERR_CLIENT, "udf module argument must be a string or unicode string");
		goto CLEANUP;
	}

	if ( PyUnicode_Check(py_function) ){
		py_ufunction = PyUnicode_AsUTF8String(py_function);
		function = PyStr_AsString(py_ufunction);
	}
	else if ( PyStr_Check(py_function) ) {
		function = PyStr_AsString(py_function);
	}
	else {
		as_error_update(&err, AEROSPIKE_ERR_CLIENT, "udf function argument must be a string or unicode string");
		goto CLEANUP;
	}

	if ( py_args && PyList_Check(py_args) ){
		Py_ssize_t size = PyList_Size(py_args);

		arglist = as_arraylist_new(size, 0);

		for ( int i = 0; i < size; i++ ) {
			PyObject * py_val = PyList_GetItem(py_args, (Py_ssize_t)i);
			as_val * val = NULL;
			pyobject_to_val(self->client, &err, py_val, &val, &self->static_pool, SERIALIZER_PYTHON);
			if ( err.code != AEROSPIKE_OK ) {
				as_error_update(&err, err.code, NULL);
				goto CLEANUP;
			}
			else {
				as_arraylist_append(arglist, val);
			}
		}
	}


	as_query_apply(&self->query, module, function, (as_list *) arglist);

CLEANUP:

	if (py_ufunction) {
		Py_DECREF(py_ufunction);
	}

	if (py_umodule) {
		Py_DECREF(py_umodule);
	}

	if ( err.code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(&err, &py_err);
		PyObject *exception_type = raise_exception(&err);
		if(PyObject_HasAttrString(exception_type, "module")) {
			PyObject_SetAttrString(exception_type, "module", py_module);
		} 
		if(PyObject_HasAttrString(exception_type, "func")) {
			PyObject_SetAttrString(exception_type, "func", py_function);
		}
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}

	Py_INCREF(self);
	return self;
}
/**
 *******************************************************************************************************
 * This function applies a registered udf module on a particular record.
 *
 * @param self                  AerospikeClient object
 * @param py_key                The key under which to store the record.
 * @param py_module             The module name.
 * @param py_function           The UDF function to be applied on a record.
 * @param py_arglist            The arguments to the UDF function
 * @param py_policy             The optional policy parameters
 *
 * Returns the result of UDF function.
 *******************************************************************************************************
 */
PyObject * AerospikeClient_Apply_Invoke(
    AerospikeClient * self,
    PyObject * py_key, PyObject * py_module, PyObject * py_function,
    PyObject * py_arglist, PyObject * py_policy)
{
    // Python Return Value
    PyObject * py_result = NULL;

    // Aerospike Client Arguments
    as_error err;
    as_policy_apply apply_policy;
    as_policy_apply * apply_policy_p = NULL;
    as_key key;
    char * module = NULL;
    char * function = NULL;
    as_list * arglist = NULL;
    as_val * result = NULL;

    PyObject * py_umodule   = NULL;
    PyObject * py_ufunction = NULL;

    // Initialisation flags
    bool key_initialised = false;

    // Initialize error
    as_error_init(&err);

    if( !PyList_Check(py_arglist) ) {
        PyErr_SetString(PyExc_TypeError, "expected UDF method arguments in a 'list'");
        return NULL;
    }

    if (!self || !self->as) {
        as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object");
        goto CLEANUP;
    }

    if (!self->is_conn_16) {
        as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
        goto CLEANUP;
    }

    // Convert python key object to as_key
    pyobject_to_key(&err, py_key, &key);
    if ( err.code != AEROSPIKE_OK ) {
        goto CLEANUP;
    }
    // Key is initialiased successfully
    key_initialised = true;

    // Convert python list to as_list
    pyobject_to_list(self, &err, py_arglist, &arglist, NULL, -1);
    if ( err.code != AEROSPIKE_OK ) {
        goto CLEANUP;
    }

    // Convert python policy object to as_policy_apply
    pyobject_to_policy_apply(&err, py_policy, &apply_policy, &apply_policy_p,
                             &self->as->config.policies.apply);
    if ( err.code != AEROSPIKE_OK ) {
        goto CLEANUP;
    }

    if ( PyUnicode_Check(py_module) ) {
        py_umodule = PyUnicode_AsUTF8String(py_module);
        module = PyStr_AsString(py_umodule);
    }
    else if ( PyStr_Check(py_module) ) {
        module = PyStr_AsString(py_module);
    }
    else {
        as_error_update(&err, AEROSPIKE_ERR_CLIENT, "udf module argument must be a string or unicode string");
        goto CLEANUP;
    }

    if ( PyUnicode_Check(py_function) ) {
        py_ufunction = PyUnicode_AsUTF8String(py_function);
        function = PyStr_AsString(py_ufunction);
    }
    else if ( PyStr_Check(py_function) ) {
        function = PyStr_AsString(py_function);
    }
    else {
        as_error_update(&err, AEROSPIKE_ERR_CLIENT, "function name must be a string or unicode string");
        goto CLEANUP;
    }

    // Invoke operation
    aerospike_key_apply(self->as, &err, apply_policy_p, &key, module, function, arglist, &result);

    if ( err.code == AEROSPIKE_OK ) {
        val_to_pyobject(&err, result, &py_result);
    } else {
        as_error_update(&err, err.code, NULL);
    }

CLEANUP:

    if (py_umodule) {
        Py_DECREF(py_umodule);
    }

    if (py_ufunction) {
        Py_DECREF(py_ufunction);
    }

    if (key_initialised == true) {
        // Destroy the key if it is initialised successfully.
        as_key_destroy(&key);
    }
    as_list_destroy(arglist);
    as_val_destroy(result);

    if ( err.code != AEROSPIKE_OK ) {
        PyObject * py_err = NULL;
        error_to_pyobject(&err, &py_err);
        PyObject *exception_type = raise_exception(&err);
        if(PyObject_HasAttrString(exception_type, "key")) {
            PyObject_SetAttrString(exception_type, "key", py_key);
        }
        if(PyObject_HasAttrString(exception_type, "bin")) {
            PyObject_SetAttrString(exception_type, "bin", Py_None);
        }
        if(PyObject_HasAttrString(exception_type, "module")) {
            PyObject_SetAttrString(exception_type, "module", py_module);
        }
        if(PyObject_HasAttrString(exception_type, "func")) {
            PyObject_SetAttrString(exception_type, "func", py_function);
        }
        PyErr_SetObject(exception_type, py_err);
        Py_DECREF(py_err);
        return NULL;
    }

    return py_result;
}
/*
static char * pyobject_to_str(PyObject * py_obj)
{
	if ( PyStr_Check(py_obj) ) {
		return PyStr_AsString(py_obj);
	}
	else {
		return NULL;
	}
}
*/
static int AerospikeQuery_Where_Add(AerospikeQuery * self, as_predicate_type predicate, as_index_datatype in_datatype, PyObject * py_bin, PyObject * py_val1, PyObject * py_val2, int index_type)

{
	as_error err;
	char * val = NULL, * bin = NULL;
	PyObject * py_ubin = NULL;

	switch (predicate) {
		case AS_PREDICATE_EQUAL: {
			if ( in_datatype == AS_INDEX_STRING ){
				if (PyUnicode_Check(py_bin)){
					py_ubin = PyUnicode_AsUTF8String(py_bin);
					bin = PyStr_AsString(py_ubin);
				} else if (PyStr_Check(py_bin) ){
					bin = PyStr_AsString(py_bin);
				}
				else {
					return 1;
				}

				if (PyUnicode_Check(py_val1)){ 
					val = strdup(PyStr_AsString(
							StoreUnicodePyObject( self,
								PyUnicode_AsUTF8String(py_val1) )));

				} else if (PyStr_Check(py_val1) ){
					val = strdup(PyStr_AsString(py_val1));
				}
				else {
					return 1;
				}

				as_query_where_init(&self->query, 1);
				if(index_type == 0) {
					as_query_where(&self->query, bin, as_equals( STRING, val ));
				} else if(index_type == 1) {
					as_query_where(&self->query, bin, as_contains( LIST, STRING, val ));
				} else if(index_type == 2) {
					as_query_where(&self->query, bin, as_contains( MAPKEYS, STRING, val ));
				} else if(index_type == 3) {
					as_query_where(&self->query, bin, as_contains( MAPVALUES, STRING, val ));
				} else {
					return 1;
				}
				if (py_ubin){
					Py_DECREF(py_ubin);
					py_ubin = NULL;
				}
			}
			else if ( in_datatype == AS_INDEX_NUMERIC ){
				if (PyUnicode_Check(py_bin)){
					py_ubin = PyUnicode_AsUTF8String(py_bin);
					bin = PyStr_AsString(py_ubin);
				} else if (PyStr_Check(py_bin) ){
					bin = PyStr_AsString(py_bin);
				}
				else {
					return 1;
				}
				int64_t val = pyobject_to_int64(py_val1);

				as_query_where_init(&self->query, 1);
				if(index_type == 0) {
					as_query_where(&self->query, bin, as_equals( NUMERIC, val ));
				} else if(index_type == 1) {
					as_query_where(&self->query, bin, as_contains( LIST, NUMERIC, val ));
				} else if(index_type == 2) {
					as_query_where(&self->query, bin, as_contains( MAPKEYS, NUMERIC, val ));
				} else if(index_type == 3) {
					as_query_where(&self->query, bin, as_contains( MAPVALUES, NUMERIC, val ));
				} else {
					return 1;
				}
				if (py_ubin){
					Py_DECREF(py_ubin);
					py_ubin = NULL;
				}
			}
			else {
				// If it ain't expected, raise and error
				as_error_update(&err, AEROSPIKE_ERR_PARAM, "predicate 'equals' expects a string or integer value.");
				PyObject * py_err = NULL;
				error_to_pyobject(&err, &py_err);
				PyErr_SetObject(PyExc_Exception, py_err);
				return 1;
			}

			break;
		}
		case AS_PREDICATE_RANGE: {
			if ( in_datatype == AS_INDEX_NUMERIC) {
				if (PyUnicode_Check(py_bin)){
					py_ubin = PyUnicode_AsUTF8String(py_bin);
					bin = PyStr_AsString(py_ubin);
				} else if (PyStr_Check(py_bin)){
					bin = PyStr_AsString(py_bin);
				}
				else {
					return 1;
				}
				int64_t min = pyobject_to_int64(py_val1);
				int64_t max = pyobject_to_int64(py_val2);

				as_query_where_init(&self->query, 1);
				if(index_type == 0) {
					as_query_where(&self->query, bin, as_range( DEFAULT, NUMERIC, min, max ));
				} else if(index_type == 1) {
					as_query_where(&self->query, bin, as_range( LIST, NUMERIC, min, max ));
				} else if(index_type == 2) {
					as_query_where(&self->query, bin, as_range( MAPKEYS, NUMERIC, min, max ));
				} else if(index_type == 3) {
					as_query_where(&self->query, bin, as_range( MAPVALUES, NUMERIC, min, max ));
				} else {
					return 1;
				}
				if (py_ubin){
					Py_DECREF(py_ubin);
					py_ubin = NULL;
				}
			}
			else if ( in_datatype == AS_INDEX_STRING) {
				// NOT IMPLEMENTED
			}
			else {
				// If it ain't right, raise and error
				as_error_update(&err, AEROSPIKE_ERR_PARAM, "predicate 'between' expects two integer values.");
				PyObject * py_err = NULL;
				error_to_pyobject(&err, &py_err);
				PyErr_SetObject(PyExc_Exception, py_err);
				return 1;
			}
			break;
		}
		default: {
			// If it ain't supported, raise and error
			as_error_update(&err, AEROSPIKE_ERR_PARAM, "unknown predicate type");
			PyObject * py_err = NULL;
			error_to_pyobject(&err, &py_err);
			PyErr_SetObject(PyExc_Exception, py_err);
			return 1;
		}
	}
	return 0;
}
AerospikeQuery * AerospikeQuery_Where(AerospikeQuery * self, PyObject * args)
{
	as_error err;
	int rc = 0;

	PyObject * py_arg1 = NULL;
	PyObject * py_arg2 = NULL;
	PyObject * py_arg3 = NULL;
	PyObject * py_arg4 = NULL;
	PyObject * py_arg5 = NULL;
	PyObject * py_arg6 = NULL;

	if ( PyArg_ParseTuple(args, "O|OOOOO:where", &py_arg1, &py_arg2, &py_arg3, &py_arg4, &py_arg5, &py_arg6) == false ) {
		return NULL;
	}

	as_error_init(&err);

	if (!self || !self->client->as) {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object");
		goto CLEANUP;
	}

	if (!self->client->is_conn_16) {
		as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
		goto CLEANUP;
	}

	if ( PyTuple_Check(py_arg1) ) {

		Py_ssize_t size = PyTuple_Size(py_arg1);
		if ( size < 1 ) {
			// If it ain't atleast 1, then raise error
			return NULL;
		}

		PyObject * py_op = PyTuple_GetItem(py_arg1, 0);
		PyObject * py_op_data = PyTuple_GetItem(py_arg1, 1);

		if ( PyInt_Check(py_op) && PyInt_Check(py_op_data)) {
			as_predicate_type op = (as_predicate_type) PyInt_AsLong(py_op);
			as_index_datatype op_data = (as_index_datatype) PyInt_AsLong(py_op_data);
			rc = AerospikeQuery_Where_Add(
				self,
				op,
				op_data,
				size > 2 ? PyTuple_GetItem(py_arg1, 2) : Py_None,
				size > 3 ? PyTuple_GetItem(py_arg1, 3) : Py_None,
				size > 4 ? PyTuple_GetItem(py_arg1, 4) : Py_None,
				size > 5 ? PyInt_AsLong(PyTuple_GetItem(py_arg1, 5)) : 0
			);
		}
	}
	else if ( (py_arg1) && PyStr_Check(py_arg1) && (py_arg2) && PyStr_Check(py_arg2) ) {

		char * op = PyStr_AsString(py_arg2);

		if ( strcmp(op, "equals") == 0 ) {
			if ( PyInt_Check(py_arg3) || PyLong_Check(py_arg3) ) {
				rc = AerospikeQuery_Where_Add(
					self,
					AS_PREDICATE_EQUAL,
					AS_INDEX_NUMERIC,
					py_arg1,
					py_arg3,
					Py_None,
					0
				);
			}
			else if ( PyStr_Check(py_arg3) || PyUnicode_Check(py_arg3) ) {
				rc = AerospikeQuery_Where_Add(
					self,
					AS_PREDICATE_EQUAL,
					AS_INDEX_STRING,
					py_arg1,
					py_arg3,
					Py_None,
					0
				);
			}
			else {
				as_error_update(&err, AEROSPIKE_ERR_PARAM, "predicate 'equals' expects a bin and string value.");
				PyObject * py_err = NULL;
				error_to_pyobject(&err, &py_err);
				PyErr_SetObject(PyExc_Exception, py_err);
				rc = 1;
			}
		}
		else if ( strcmp(op, "between") == 0 ) {
			rc = AerospikeQuery_Where_Add(
				self,
				AS_PREDICATE_RANGE,
				AS_INDEX_NUMERIC,
				py_arg1,
				py_arg3,
				py_arg4,
				0
			);
		}
		else if ( strcmp(op, "contains") == 0 ) {
			int index_type = 0;
			int type = 0;
			if(PyInt_Check(py_arg3)) {
				index_type = PyInt_AsLong(py_arg3);
			} else if (PyLong_Check(py_arg3)) {
				index_type = PyLong_AsLongLong(py_arg3);
                if(-1 == index_type) {
                    as_error_update(&err, AEROSPIKE_ERR_PARAM, "integer value exceeds sys.maxsize");
                    goto CLEANUP;
                }
			}

			if(PyInt_Check(py_arg4)) {
				type = PyInt_AsLong(py_arg4);
			} else if ( PyLong_Check(py_arg4) ) {
				type = PyLong_AsLongLong(py_arg4);
                if(-1 == type) {
                    as_error_update(&err, AEROSPIKE_ERR_PARAM, "integer value exceeds sys.maxsize");
                    goto CLEANUP;
                }
			}
			if ( (PyInt_Check(py_arg5) || PyLong_Check(py_arg5)) && type == 1) {
				rc = AerospikeQuery_Where_Add(
					self,
					AS_PREDICATE_EQUAL,
					AS_INDEX_NUMERIC,
					py_arg1,
					py_arg5,
					Py_None,
					index_type
				);
			}
			else if ( (PyStr_Check(py_arg5) || PyUnicode_Check(py_arg5)) && type == 0) {
				rc = AerospikeQuery_Where_Add(
					self,
					AS_PREDICATE_EQUAL,
					AS_INDEX_STRING,
					py_arg1,
					py_arg5,
					Py_None,
					index_type
				);
			}
			else {
				as_error_update(&err, AEROSPIKE_ERR_PARAM, "predicate 'contains' expects a bin and a string or int value.");
				PyObject * py_err = NULL;
				error_to_pyobject(&err, &py_err);
				PyErr_SetObject(PyExc_Exception, py_err);
				rc = 1;
			}
		}
		else if ( strcmp(op, "range") == 0 ) {
			int index_type = 0;
			if(PyInt_Check(py_arg3)) {
				index_type = PyInt_AsLong(py_arg3);
			} else if (PyLong_Check(py_arg3)) {
				index_type = PyLong_AsLongLong(py_arg3);
                if(-1 == index_type) {
                    as_error_update(&err, AEROSPIKE_ERR_PARAM, "integer value exceeds sys.maxsize");
                    goto CLEANUP;
                }
			}

			if ( PyInt_Check(py_arg4) || PyLong_Check(py_arg4)) {
				rc = AerospikeQuery_Where_Add(
					self,
					AS_PREDICATE_RANGE,
					AS_INDEX_NUMERIC,
					py_arg1,
					py_arg5,
					py_arg6,
					index_type
				);
			}
			else {
				as_error_update(&err, AEROSPIKE_ERR_PARAM, "predicate 'range' expects a bin and two numeric values.");
				PyObject * py_err = NULL;
				error_to_pyobject(&err, &py_err);
				PyErr_SetObject(PyExc_Exception, py_err);
				rc = 1;
			}
		}
		else {
			as_error_update(&err, AEROSPIKE_ERR_PARAM, "predicate '%s' is invalid.", op);
			PyObject * py_err = NULL;
			error_to_pyobject(&err, &py_err);
			PyErr_SetObject(PyExc_Exception, py_err);
			rc = 1;
		}

		// if ( PyInt_Check(py_op) ) {
		// 	rc = AerospikeQuery_Where_Add(
		// 		&self->query,
		// 		PyInt_AsLong(py_op),
		// 		size > 1 ? PyTuple_GetItem(py_predicate, 1) : Py_None,
		// 		size > 2 ? PyTuple_GetItem(py_predicate, 2) : Py_None,
		// 		size > 3 ? PyTuple_GetItem(py_predicate, 3) : Py_None
		// 	);
		// }
	}
	else {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "predicate is invalid.");
		PyObject * py_err = NULL;
		error_to_pyobject(&err, &py_err);
		PyObject *exception_type = raise_exception(&err);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		as_query_destroy(&self->query);
		rc = 1;
	}
CLEANUP:
	if ( rc == 1 ) {
		return NULL;
	}

	if ( err.code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(&err, &py_err);
		PyObject *exception_type = raise_exception(&err);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		TRACE();
		return NULL;
	}

	Py_INCREF(self);
	return self;
}
/**
 ******************************************************************************************************
 * Returns data for a particular request string to AerospikeClient_InfoNode
 *
 * @param self                  AerospikeClient object
 * @param request_str_p         Request string sent from the python client
 * @param py_host               Optional host sent from the python client
 * @param py_policy             The policy sent from the python client
 *
 * Returns information about a host.
 ********************************************************************************************************/
static PyObject * AerospikeClient_InfoNode_Invoke(
	AerospikeClient * self,
	PyObject * py_request_str, PyObject * py_host, PyObject * py_policy) {

	PyObject * py_response = NULL;
	PyObject * py_ustr = NULL;
	PyObject * py_ustr1 = NULL;
	as_policy_info info_policy;
	as_policy_info* info_policy_p = NULL;
	char* address = (char *) self->as->config.hosts[0].addr;
	long port_no = self->as->config.hosts[0].port;
	char* response_p = NULL;
	as_status status = AEROSPIKE_OK;

	as_error err;
	as_error_init(&err);

	if (!self || !self->as) {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object");
		goto CLEANUP;
	}

	if (!self->is_conn_16) {
		as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
		goto CLEANUP;
	}

	if (py_policy) {
		if( PyDict_Check(py_policy) ) {
			pyobject_to_policy_info(&err, py_policy, &info_policy, &info_policy_p,
					&self->as->config.policies.info);
			if (err.code != AEROSPIKE_OK) {
				goto CLEANUP;
			}
		} else {
			as_error_update(&err, AEROSPIKE_ERR_PARAM, "Policy should be a dictionary");
			goto CLEANUP;
		}
	}

	if ( py_host ) {
		if ( PyTuple_Check(py_host) && PyTuple_Size(py_host) == 2) {
			PyObject * py_addr = PyTuple_GetItem(py_host,0);
			PyObject * py_port = PyTuple_GetItem(py_host,1);

			if ( PyStr_Check(py_addr) ) {
				address = PyStr_AsString(py_addr);
			} else if (PyUnicode_Check(py_addr)) {
				py_ustr = PyUnicode_AsUTF8String(py_addr);
				address = PyStr_AsString(py_ustr);
			}
			if ( PyInt_Check(py_port) ) {
				port_no = (uint16_t) PyInt_AsLong(py_port);
			}
			else if ( PyLong_Check(py_port) ) {
				port_no = (uint16_t) PyLong_AsLong(py_port);
			}
		} else if ( !PyTuple_Check(py_host)){
			as_error_update(&err, AEROSPIKE_ERR_PARAM, "Host should be a specified in form of Tuple.");
			goto CLEANUP;
		}
	}

	char * request_str_p = NULL;
	if (PyUnicode_Check(py_request_str)) {
		py_ustr1 = PyUnicode_AsUTF8String(py_request_str);
		request_str_p = PyStr_AsString(py_ustr1);
	} else if (PyStr_Check(py_request_str)) {
		request_str_p = PyStr_AsString(py_request_str);
	} else {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Request should be of string type");
		goto CLEANUP;
	}

    Py_BEGIN_ALLOW_THREADS
	status = aerospike_info_host(self->as, &err, info_policy_p,
		(const char *) address, (uint16_t) port_no, request_str_p,
		&response_p);
    Py_END_ALLOW_THREADS
	if( err.code == AEROSPIKE_OK ) {
		if (response_p && status == AEROSPIKE_OK){
			py_response = PyStr_FromString(response_p);
			free(response_p);
		} else if ( response_p == NULL){
			as_error_update(&err, AEROSPIKE_ERR_CLIENT, "Invalid info operation");
			goto CLEANUP;
		} else if ( status != AEROSPIKE_OK ){
			as_error_update(&err, status, "Info operation failed");
			goto CLEANUP;
		}
	} else {
		as_error_update(&err, err.code, NULL);
		goto CLEANUP;
	}

CLEANUP:

	if (py_ustr) {
		Py_DECREF(py_ustr);
	}
	if (py_ustr1) {
		Py_DECREF(py_ustr1);
	}

	if ( err.code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(&err, &py_err);
		PyObject *exception_type = raise_exception(&err);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}
	return py_response;
}
/**
 ******************************************************************************************************
 * Iterates over the hosts in the cluster and creates the list to be returned to the python client.
 *
 * @param err                   as_error object
 * @param command               Request string sent from the python client
 * @param nodes_tuple           List containing details of each host
 * @param return_value          List t o be returned back to the python client
 * @param host_index            Index of the list nodes_tuple
 * @param index                 Index of the list to be returned.
 *
 * Returns information about a host.
 ********************************************************************************************************/
static PyObject * AerospikeClient_GetNodes_Returnlist(as_error* err,
	PyObject * command, PyObject * nodes_tuple[], PyObject * return_value,
	uint32_t host_index, Py_ssize_t index) {

	char* tok = NULL;
	char* saved = NULL;
	PyObject * value_tok = NULL;
	bool break_flag = false;

	tok = strtok_r(PyStr_AsString(command), INFO_REQUEST_RESPONSE_DELIMITER, &saved);
	if (tok == NULL) {
		as_error_update(err, AEROSPIKE_ERR_CLIENT, "Unable to get addr in service");
		goto CLEANUP;
	}
	while (tok != NULL && (host_index < MAX_HOST_COUNT)) {
		tok = strtok_r(NULL, IP_PORT_DELIMITER, &saved);
#if defined(__APPLE__)
		if (tok == NULL || saved == NULL) {
#else
		if (tok == NULL || *saved == '\0') {
#endif
			goto CLEANUP;
		}

		nodes_tuple[host_index] = PyTuple_New(2);

		value_tok = PyStr_FromString(tok);
		PyTuple_SetItem(nodes_tuple[host_index], 0 , value_tok);
		//Py_DECREF(value_tok);

		if(strcmp(PyStr_AsString(command),"response_services_p")) {
			tok = strtok_r(NULL, HOST_DELIMITER, &saved);
			if (tok == NULL) {
				as_error_update(err, AEROSPIKE_ERR_CLIENT, "Unable to get port");
				goto CLEANUP;
			}

			if (strstr(tok, INFO_RESPONSE_END)) {
				tok = strtok_r(tok, INFO_RESPONSE_END, &saved);
				break_flag = true;
			}
		} else {
			tok = strtok_r(NULL, INFO_RESPONSE_END, &saved);
			if (tok == NULL) {
				as_error_update(err, AEROSPIKE_ERR_CLIENT, "Unable to get port in service");
				goto CLEANUP;
			}
		}

		value_tok = PyInt_FromString(tok, NULL, 10);
		PyTuple_SetItem(nodes_tuple[host_index], 1 , value_tok);
		PyList_Insert(return_value, index , nodes_tuple[host_index]);
		Py_DECREF(nodes_tuple[host_index]);
		index++;
		host_index++;

		if (break_flag == true) {
			goto CLEANUP;
		}

	}
CLEANUP:

	if ( err->code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(err, &py_err);
		PyObject *exception_type = raise_exception(err);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}
	return return_value;
}
/**
 ******************************************************************************************************
 * Returns data about the nodes to AerospikeClient_GetNodes.
 *
 * @param self                  AerospikeClient object
 *
 * Returns a list containing the details of the nodes.
 ********************************************************************************************************/
static PyObject * AerospikeClient_GetNodes_Invoke(
	AerospikeClient * self) {

	PyObject * response_services_p = NULL;
	PyObject * response_service_p = NULL;
	PyObject * nodes_tuple[MAX_HOST_COUNT] = {0};
	PyObject * return_value = PyList_New(0);

	as_error err;
	as_error_init(&err);

	if (!self || !self->as) {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object");
		goto CLEANUP;
	}

	if (!self->is_conn_16) {
		as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
		goto CLEANUP;
	}

	PyObject * py_req_str = NULL;
	py_req_str = PyStr_FromString("services");
	response_services_p = AerospikeClient_InfoNode_Invoke(self, py_req_str, NULL, NULL);
	Py_DECREF(py_req_str);
	if(!response_services_p) {
		as_error_update(&err, AEROSPIKE_ERR_CLIENT, "Services call returned an error");
		goto CLEANUP;
	}

	py_req_str = PyStr_FromString("service");
	response_service_p = AerospikeClient_InfoNode_Invoke(self, py_req_str, NULL, NULL);
	Py_DECREF(py_req_str);
	if(!response_service_p) {
		as_error_update(&err, AEROSPIKE_ERR_CLIENT, "Service call returned an error");
		goto CLEANUP;
	}

	return_value = AerospikeClient_GetNodes_Returnlist(&err, response_service_p, nodes_tuple, return_value, 0, 0);
	if( return_value )
		return_value = AerospikeClient_GetNodes_Returnlist(&err, response_services_p, nodes_tuple, return_value, 1, 1);

CLEANUP:

	if(response_services_p) {
		Py_DECREF(response_services_p);
	}

	if(response_service_p) {
		Py_DECREF(response_service_p);
	}

	if ( err.code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(&err, &py_err);
		PyObject *exception_type = raise_exception(&err);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}

	return return_value;
}
/**
 *********************************************************************
 * This function will invoke aerospike_batch_get_bins to get filtered
 * bins from all the records in a batches.
 *
 * @param self                    AerospikeClient object
 * @param py_keys                 List of keys passed on by user
 * @param py_bins                 List of filter bins passed on by user
 * @param py_policy               User specified Policy dictionary
 *
 *********************************************************************
 **/
static
PyObject * AerospikeClient_Select_Many_Invoke(
    AerospikeClient * self,
    PyObject * py_keys, PyObject * py_bins, PyObject * py_policy)
{
    // Python Return Value
    PyObject * py_recs = NULL;

    // Aerospike Client Arguments
    as_error err;
    as_policy_batch policy;
    as_policy_batch * batch_policy_p = NULL;
    Py_ssize_t bins_size = 0;
    char **filter_bins = NULL;
    bool has_batch_index = false;

    // Unicode object's pool
    UnicodePyObjects u_objs;
    u_objs.size = 0;
    int i = 0;

    // Initialize error
    as_error_init(&err);

    if (!self || !self->as) {
        as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object");
        goto CLEANUP;
    }

    if (!self->is_conn_16) {
        as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
        goto CLEANUP;
    }

    // Check the type of bins and get it's size
    // i.e. number of bins provided
    if (py_bins != NULL && PyList_Check(py_bins)) {
        bins_size    = PyList_Size(py_bins);
    }
    else if (py_bins != NULL && PyTuple_Check(py_bins)) {
        bins_size    = PyTuple_Size(py_bins);
    }
    else {
        as_error_update(&err, AEROSPIKE_ERR_PARAM, "Filter bins should be specified as a list or tuple.");
        goto CLEANUP;
    }

    filter_bins = (char **)malloc(sizeof(long int) * bins_size);

    for (i = 0; i < bins_size; i++) {
        PyObject *py_bin = NULL;
        if(PyList_Check(py_bins)) {
            py_bin = PyList_GetItem(py_bins, i);
        }
        if(PyTuple_Check(py_bins)) {
            py_bin = PyTuple_GetItem(py_bins, i);
        }
        if (PyUnicode_Check(py_bin)) {
            // Store the unicode object into a pool
            // It is DECREFed at later stages
            // So, no need of DECREF here.
            filter_bins[i] = PyStr_AsString(
                                 store_unicode_bins(&u_objs, PyUnicode_AsUTF8String(py_bin)));
        }
        else if (PyStr_Check(py_bin)) {
            filter_bins[i]    = PyStr_AsString(py_bin);
        }
        else {
            as_error_update(&err, AEROSPIKE_ERR_PARAM, "Bin name should be a string or unicode string.");
            goto CLEANUP;
        }
    }

    // Convert python policy object to as_policy_batch
    pyobject_to_policy_batch(&err, py_policy, &policy, &batch_policy_p,
                             &self->as->config.policies.batch);
    if ( err.code != AEROSPIKE_OK ) {
        goto CLEANUP;
    }

    has_batch_index = aerospike_has_batch_index(self->as);
    if (has_batch_index) {
        py_recs = batch_select_aerospike_batch_read(&err, self, py_keys, batch_policy_p, filter_bins, bins_size);
    } else {
        py_recs = batch_select_aerospike_batch_get(&err, self, py_keys, batch_policy_p, filter_bins, bins_size);
    }

CLEANUP:

    if (filter_bins != NULL) {
        free(filter_bins);
    }

    // DECREFed all the unicode objects stored in Pool
    for ( i = 0; i< u_objs.size; i++) {
        Py_DECREF(u_objs.ob[i]);
    }

    if ( err.code != AEROSPIKE_OK ) {
        PyObject * py_err = NULL;
        error_to_pyobject(&err, &py_err);
        PyObject *exception_type = raise_exception(&err);
        if(PyObject_HasAttrString(exception_type, "key")) {
            PyObject_SetAttrString(exception_type, "key", py_keys);
        }
        if(PyObject_HasAttrString(exception_type, "bin")) {
            PyObject_SetAttrString(exception_type, "bin", Py_None);
        }
        PyErr_SetObject(exception_type, py_err);
        Py_DECREF(py_err);
        return NULL;
    }
    return py_recs;
}
/*
 *******************************************************************************************************
 * Checks serializer_policy.
 * Serializes Py_Object (value) into as_bytes using serialization logic
 * based on serializer_policy.
 *
 * @param serializer_policy         The serializer_policy to be used to handle
 *                                  the serialization.
 * @param bytes                     The as_bytes to be set.
 * @param value                     The value to be serialized.
 * @param error_p                   The as_error to be populated by the function
 *                                  with encountered error if any.
 *******************************************************************************************************
 */
extern PyObject * serialize_based_on_serializer_policy(AerospikeClient * self,
        int32_t serializer_policy,
		as_bytes **bytes,
		PyObject *value,
		as_error *error_p)
{
    uint8_t use_client_serializer = true;
	PyObject* initresult = NULL;

    if (self->is_client_put_serializer) {
        if (serializer_policy == SERIALIZER_USER) {
            if (!self->user_serializer_call_info.callback) {
                use_client_serializer = false;
            }
        }
    } else if (self->user_serializer_call_info.callback) {
        serializer_policy = SERIALIZER_USER;
    }

	switch(serializer_policy) {
		case SERIALIZER_NONE:
			as_error_update(error_p, AEROSPIKE_ERR_PARAM,
					"Cannot serialize: SERIALIZER_NONE selected");
			goto CLEANUP;
		case SERIALIZER_PYTHON:
			{
				/*
				 * Serialize bytearray as is and store them into database with
				 * type AS_BYTES_BLOB, unlike other values in case of 
				 * SERIALIZER_PYTHON.
				 * This is a special case.
				 * Refer: AER-3589 for more details.
				 */
				if (PyByteArray_Check(value)) {
					uint8_t *bytes_array = (uint8_t *) PyByteArray_AsString(value);
					uint32_t bytes_array_len  = (uint32_t)  PyByteArray_Size(value);

					set_as_bytes(bytes, bytes_array, bytes_array_len, AS_BYTES_BLOB, error_p);

				} else {

					/* get the sys.modules dictionary */
					PyObject* sysmodules = PyImport_GetModuleDict();
					PyObject* cpickle_module = NULL;
					if(PyMapping_HasKeyString(sysmodules, "cPickle")) {
						cpickle_module = PyMapping_GetItemString(sysmodules, "cPickle");
					} else {
						cpickle_module = PyImport_ImportModule("cPickle");
					}

					if(!cpickle_module) {
						/* insert error handling here! and exit this function */
						as_error_update(error_p, AEROSPIKE_ERR_CLIENT, "Unable to load cpickle module");
						goto CLEANUP;
					} else {
						PyObject * py_funcname = PyStr_FromString("dumps");

						Py_INCREF(cpickle_module);
						initresult = PyObject_CallMethodObjArgs(cpickle_module,
								py_funcname, value, NULL);
						Py_DECREF(cpickle_module);
						Py_DECREF(py_funcname);

						if(!initresult) {
							/* more error handling &c */
							as_error_update(error_p, AEROSPIKE_ERR_CLIENT, "Unable to call dumps function");
							goto CLEANUP;
						} else {
							Py_INCREF(initresult);
							char *return_value = PyStr_AsString(initresult);
							Py_ssize_t len = PyBytes_GET_SIZE(initresult);
                            set_as_bytes(bytes, (uint8_t *) return_value,
									len, AS_BYTES_PYTHON, error_p);
							Py_DECREF(initresult);
						}
					}
					Py_XDECREF(cpickle_module);
				}
			}
			break;
		case SERIALIZER_JSON:
			/*
			 *   TODO:
			 *     Handle JSON serialization after support for AS_BYTES_JSON
			 *     is added in aerospike-client-c
			 */
			as_error_update(error_p, AEROSPIKE_ERR,
					"Unable to serialize using standard json serializer");
			goto CLEANUP;

		case SERIALIZER_USER:
            if (use_client_serializer) {
                execute_user_callback(&self->user_serializer_call_info, bytes, &value, true, error_p);
				if (AEROSPIKE_OK != (error_p->code)) {
					goto CLEANUP;
				}
            } else {
			    if (is_user_serializer_registered) {
                    execute_user_callback(&user_serializer_call_info, bytes, &value, true, error_p);
				    if (AEROSPIKE_OK != (error_p->code)) {
					    goto CLEANUP;
				    }
			    } else if (self->user_serializer_call_info.callback) {
                    execute_user_callback(&self->user_serializer_call_info, bytes, &value, true, error_p);
				    if (AEROSPIKE_OK != (error_p->code)) {
					    goto CLEANUP;
				    }
                } else {
				    as_error_update(error_p, AEROSPIKE_ERR,
						"No serializer callback registered");
				    goto CLEANUP;
			    }
            }
		    break;
		default:
			as_error_update(error_p, AEROSPIKE_ERR,
					"Unsupported serializer");
			goto CLEANUP;
	}

CLEANUP:

	Py_XDECREF(initresult);
  	if ( error_p->code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(error_p, &py_err);
		PyObject *exception_type = raise_exception(error_p);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}

	return PyLong_FromLong(0);
}
/*
 *******************************************************************************************************
 * If serialize_flag == true, executes the passed user_serializer_callback,
 * by creating as_bytes (bytes) from the passed Py_Object (value).
 * Else executes the passed user_deserializer_callback,
 * by passing the as_bytes (bytes) to the deserializer and getting back
 * the corresponding Py_Object (value).
 *
 * @param user_callback_info            The user_serializer_callback for the user
 *                                      callback to be executed.
 * @param bytes                         The as_bytes to be stored/retrieved.
 * @param value                         The value to be retrieved/stored.
 * @param serialize_flag                The flag which indicates
 *                                      serialize/deserialize.
 * @param error_p                       The as_error to be populated by the
 *                                      function with encountered error if any.
 *******************************************************************************************************
 */
void execute_user_callback(user_serializer_callback *user_callback_info,
		as_bytes **bytes,
		PyObject **value,
		bool serialize_flag,
		as_error *error_p)
{
	PyObject * py_return = NULL;
	PyObject * py_value = NULL;
	PyObject * py_arglist = PyTuple_New(1);
	int len;

	if (serialize_flag) {
		Py_XINCREF(*value);
		if( PyTuple_SetItem(py_arglist, 0 , *value) != 0){
			Py_DECREF(py_arglist);
			goto CLEANUP;
		}
	} else {
		as_bytes * bytes_pointer = *bytes;
		char*       bytes_val_p = (char*)bytes_pointer->value;
		py_value = PyStr_FromStringAndSize(bytes_val_p, as_bytes_size(*bytes));
		if (PyTuple_SetItem(py_arglist, 0 , py_value) != 0){
			Py_DECREF(py_arglist);
			goto CLEANUP;
		}
	}

	Py_INCREF(user_callback_info -> callback);
	py_return = PyEval_CallObject(user_callback_info->callback, py_arglist);
	Py_DECREF(user_callback_info -> callback);
	Py_DECREF(py_arglist);

	if (py_return) {

		if (serialize_flag) {
			char * py_val = PyStr_AsString(py_return);
			len = PyBytes_Size(py_return);
			set_as_bytes(bytes, (uint8_t *) py_val,
					len, AS_BYTES_BLOB, error_p);
			Py_DECREF(py_return);
		} else {
			*value = py_return;
		}
	} else {
		if (serialize_flag) {
			as_error_update(error_p, AEROSPIKE_ERR,
					"Unable to call user's registered serializer callback");
			goto CLEANUP;
		} else {
			as_error_update(error_p, AEROSPIKE_ERR,
					"Unable to call user's registered deserializer callback");
			goto CLEANUP;
		}
	}

CLEANUP:
  if ( error_p->code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL;
		error_to_pyobject(error_p, &py_err);
		PyObject *exception_type = raise_exception(error_p);
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
    }
}
/**
 ********************************************************************************************************
 * Select values from a begin key to end key corresponding to a value up to a maximum count applying a lua filter.
 *
 * @param self                  AerospikeLList object
 * @param args                  The args is a tuple object containing an argument
 *                              list passed from Python to a C function
 * @param kwds                  Dictionary of keywords
 * 
 * Returns a list of ldt contents.
 * In case of error,appropriate exceptions will be raised.
 ********************************************************************************************************
 */
PyObject * AerospikeLList_Range_Limit(AerospikeLList * self, PyObject * args, PyObject * kwds)
{
	char* filter_name = NULL;
	PyObject* py_count = NULL;
	PyObject * py_args = NULL; 
	PyObject* py_policy = NULL;
	PyObject* py_from_value = NULL;
	PyObject* py_end_value = NULL;
	PyObject* py_elements_list = NULL;
	PyObject* py_filter_name = NULL;
	as_policy_apply apply_policy;
	as_policy_apply* apply_policy_p = NULL;
	as_list* arg_list = NULL;
	as_list* elements_list = NULL;
	as_val* from_val = NULL;
	as_val* end_val = NULL;

	as_static_pool static_pool;
	memset(&static_pool, 0, sizeof(static_pool));

	as_error err;
	as_error_init(&err);

	static char * kwlist[] = {"start_value", "end_value", "count", "function", "args", "policy", NULL};

	// Python Function Argument Parsing
	if ( PyArg_ParseTupleAndKeywords(args, kwds, "OOO|OOO:range_limit", kwlist, 
				&py_from_value, &py_end_value, &py_count, &py_filter_name, &py_args, &py_policy)== false ) {
		return NULL;
	}

	if (!self || !self->client->as) {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object");
		goto CLEANUP;
	}

	if (!self->client->is_conn_16) {
		as_error_update(&err, AEROSPIKE_ERR_CLUSTER, "No connection to aerospike cluster");
		goto CLEANUP;
	}

	// Convert python policy object to as_policy_apply
	pyobject_to_policy_apply(&err, py_policy, &apply_policy, &apply_policy_p,
			&self->client->as->config.policies.apply);
	if ( err.code != AEROSPIKE_OK ) {
		goto CLEANUP;
	}

	uint32_t count = 0;
	if (PyInt_Check(py_count)) {
		count = PyInt_AsLong(py_count);
	} else if (PyLong_Check(py_count)) {
		count = PyLong_AsLong(py_count);
		if (count == (uint32_t)-1 && PyErr_Occurred()) {
			if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
				as_error_update(&err, AEROSPIKE_ERR_PARAM, "integer value exceeds sys.maxsize");
				goto CLEANUP;
			}
		}
	} else {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Count should be an integer or long");
		goto CLEANUP;
	}

	if(py_filter_name) {
		if(PyStr_Check(py_filter_name)) {
			filter_name = PyStr_AsString(py_filter_name);
		} else if(py_filter_name != Py_None) {
			as_error_update(&err, AEROSPIKE_ERR_PARAM, "Filter name should be string or None");
			goto CLEANUP;
		}
	}
	if ( py_args && !py_filter_name) {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Filter arguments without filter name");
		goto CLEANUP;
	}

	if ( !PyList_Check(py_args) && (py_args != Py_None)) {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid filter argument(type)");
		goto CLEANUP;
	}

	if (py_args != Py_None) {
		pyobject_to_list(self->client, &err, py_args, &arg_list, &static_pool, SERIALIZER_PYTHON);
	}

	if( py_from_value != Py_None && py_end_value != Py_None ) {
		pyobject_to_val(self->client, &err, py_from_value, &from_val, &static_pool, SERIALIZER_PYTHON);
		pyobject_to_val(self->client, &err, py_end_value, &end_val, &static_pool, SERIALIZER_PYTHON);
	} else {
		as_error_update(&err, AEROSPIKE_ERR_PARAM, "Begin or end key cannot be None");
		goto CLEANUP;
	}

	Py_BEGIN_ALLOW_THREADS
	aerospike_llist_range_limit(self->client->as, &err, apply_policy_p, &self->key, &self->llist, from_val, end_val, count, filter_name, arg_list, &elements_list);
	Py_END_ALLOW_THREADS
	if(err.code != AEROSPIKE_OK) {
		goto CLEANUP;
	}

	list_to_pyobject(self->client, &err, elements_list, &py_elements_list);

CLEANUP:
	if (elements_list) {
		as_list_destroy(elements_list);
	}

	if(from_val) {
		as_val_destroy(from_val);
	}
	if(end_val) {
		as_val_destroy(end_val);
	}

	if ( err.code != AEROSPIKE_OK ) {
		PyObject * py_err = NULL, *py_key = NULL;
		PyObject *exception_type = raise_exception(&err);
		error_to_pyobject(&err, &py_err);
		if (PyObject_HasAttrString(exception_type, "key")) {
			key_to_pyobject(&err, &self->key, &py_key);
			PyObject_SetAttrString(exception_type, "key", py_key);
			Py_DECREF(py_key);
		} 
		if (PyObject_HasAttrString(exception_type, "bin")) {
			PyObject *py_bins = PyStr_FromString((char *)&self->bin_name);
			PyObject_SetAttrString(exception_type, "bin", py_bins);
			Py_DECREF(py_bins);
		}
		PyErr_SetObject(exception_type, py_err);
		Py_DECREF(py_err);
		return NULL;
	}

	return py_elements_list;
}