diff --git a/src/include/conversions.h b/src/include/conversions.h index 91504bf629..a314b689dc 100644 --- a/src/include/conversions.h +++ b/src/include/conversions.h @@ -222,9 +222,37 @@ PyObject *create_class_instance_from_module(as_error *error_p, // We return an unsigned long long because it should be able to fit all fixed-width int types up to uint64_t // Returns -1 on error. Error indicator can be checked to verify if error occurred // TODO: replace this with new API calls in Python 3.14 -unsigned long long -convert_pyobject_to_fixed_width_integer_type(PyObject *pyobject, - unsigned long long max_bound); +unsigned long long convert_pyobject_to_unsigned_fixed_width_integer_type( + PyObject *pyobject, unsigned long long max_bound); + +uint64_t convert_unsigned_long_long_into_uint64_t(as_error *err, + PyObject *pyobject, + const char *component); + +int64_t convert_long_long_into_int64_t(as_error *err, PyObject *pyobject, + const char *component); + +uint32_t convert_unsigned_long_into_uint32_t(as_error *err, PyObject *pyobject, + const char *component); + +int32_t convert_long_into_int32_t(as_error *err, PyObject *pyobject, + const char *component); + +int convert_long_into_int(as_error *err, PyObject *pyobject, + const char *component); + +unsigned int convert_unsigned_long_into_enum(as_error *err, PyObject *py_long, + unsigned int max_enum_value, + const char *component); + +uint16_t convert_unsigned_long_into_uint16_t(as_error *err, PyObject *pyobject, + const char *component); + +int16_t convert_long_into_int16_t(as_error *err, PyObject *pyobject, + const char *component); + +int64_t convert_pyobject_to_int64_t(PyObject *pyobject); + uint8_t convert_pyobject_to_uint8_t(PyObject *pyobject); uint16_t convert_pyobject_to_uint16_t(PyObject *pyobject); diff --git a/src/include/query.h b/src/include/query.h index a2a6c65cb8..0f8df56b38 100644 --- a/src/include/query.h +++ b/src/include/query.h @@ -146,8 +146,6 @@ PyObject *AerospikeQuery_Get_Partitions_status(AerospikeQuery *self); */ PyObject *StoreUnicodePyObject(AerospikeQuery *self, PyObject *obj); -int64_t pyobject_to_int64(PyObject *py_obj); - // We need to share this with src/main/client/query.c because this function is no longer assigned // to the query type's tp_new slot. We are trying to prevent users from using the query type's constructor directly // to create a query instance. diff --git a/src/main/client/cdt_operation_utils.c b/src/main/client/cdt_operation_utils.c index 2d7a2da6d9..5bd9933e64 100644 --- a/src/main/client/cdt_operation_utils.c +++ b/src/main/client/cdt_operation_utils.c @@ -136,19 +136,11 @@ as_status get_optional_int64_t(as_error *err, const char *key, return AEROSPIKE_OK; } - if (!PyLong_Check(py_val)) { - return as_error_update(err, AEROSPIKE_ERR_PARAM, - "%s must be an integer", key); - } - - *i64_valptr = (int64_t)PyLong_AsLongLong(py_val); - if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - return as_error_update(err, AEROSPIKE_ERR_PARAM, "%s too large", - key); - } - return as_error_update(err, AEROSPIKE_ERR_PARAM, "Failed to convert %s", - key); + *i64_valptr = convert_pyobject_to_int64_t(py_val); + if (err->code != AEROSPIKE_OK) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "Unable to convert Python object to int64_t"); + return err->code; } *found = true; diff --git a/src/main/client/operate.c b/src/main/client/operate.c index b743252b83..974b0974fe 100644 --- a/src/main/client/operate.c +++ b/src/main/client/operate.c @@ -544,7 +544,10 @@ as_status add_op(AerospikeClient *self, as_error *err, goto CLEANUP; } if (PyLong_Check(py_index)) { - index = PyLong_AsLong(py_index); + index = convert_long_into_int(err, py_index, "py_index"); + if (err->code != AEROSPIKE_OK) { + goto CLEANUP; + } } else { as_error_update(err, AEROSPIKE_ERR_PARAM, @@ -680,13 +683,10 @@ as_status add_op(AerospikeClient *self, as_error *err, break; case AS_OPERATOR_INCR: if (PyLong_Check(py_value)) { - offset = PyLong_AsLong(py_value); - if (offset == -1 && PyErr_Occurred() && self->strict_types) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); - goto CLEANUP; - } + offset = convert_unsigned_long_long_into_uint64_t( + err, py_value, "AS_OPERATOR_INCR"); + if (err->code != AEROSPIKE_OK) { + goto CLEANUP; } as_operations_add_incr(ops, bin, offset); } diff --git a/src/main/client/query.c b/src/main/client/query.c index 5f7f7c88eb..d63d2d0d4f 100644 --- a/src/main/client/query.c +++ b/src/main/client/query.c @@ -134,8 +134,11 @@ static int query_where_add(as_query **query, as_predicate_type predicate, "Bin must be a string or unicode"); return 1; } - int64_t val = pyobject_to_int64(py_val1); - + int64_t val = convert_long_long_into_int64_t(err, py_val1, + "query numeric index"); + if (err->code != AEROSPIKE_OK) { + return 1; + } as_query_where_init(*query, 1); if (index_type == 0) { as_query_where(*query, bin, as_equals(NUMERIC, val)); @@ -193,7 +196,11 @@ static int query_where_add(as_query **query, as_predicate_type predicate, return 1; } if (PyLong_Check(py_val1)) { - min = pyobject_to_int64(py_val1); + min = convert_unsigned_long_long_into_uint64_t(err, py_val1, + "predicate max"); + if (err->code != AEROSPIKE_OK) { + return 1; + } } else { Py_XDECREF(py_ubin); @@ -203,7 +210,11 @@ static int query_where_add(as_query **query, as_predicate_type predicate, } if (PyLong_Check(py_val2)) { - max = pyobject_to_int64(py_val2); + max = convert_unsigned_long_long_into_uint64_t(err, py_val2, + "predicate max"); + if (err->code != AEROSPIKE_OK) { + return 1; + } } else { Py_XDECREF(py_ubin); @@ -405,7 +416,7 @@ static PyObject *AerospikeClient_QueryApply_Invoke( } long op = PyLong_AsLong(py_op); - if (op == -1 && PyErr_Occurred()) { + if (PyErr_Occurred()) { as_error_update(&err, AEROSPIKE_ERR_PARAM, "unknown predicate type"); goto CLEANUP; @@ -413,7 +424,7 @@ static PyObject *AerospikeClient_QueryApply_Invoke( as_index_datatype op_data = (as_index_datatype)PyLong_AsLong(py_op_data); - if (op == -1 && PyErr_Occurred()) { + if (PyErr_Occurred()) { as_error_update(&err, AEROSPIKE_ERR_PARAM, "unknown index data type"); goto CLEANUP; diff --git a/src/main/client/remove.c b/src/main/client/remove.c index 78162c6001..b54e3150f6 100644 --- a/src/main/client/remove.c +++ b/src/main/client/remove.c @@ -93,16 +93,9 @@ PyObject *AerospikeClient_Remove_Invoke(AerospikeClient *self, PyObject *py_key, if (py_gen) { if (PyLong_Check(py_gen)) { remove_policy_p->generation = - (uint16_t)PyLong_AsLong(py_gen); - } - else if (PyLong_Check(py_gen)) { - remove_policy_p->generation = - (uint16_t)PyLong_AsLongLong(py_gen); - if ((uint16_t)-1 == remove_policy_p->generation && - PyErr_Occurred()) { - as_error_update( - &err, AEROSPIKE_ERR_PARAM, - "integer value for gen exceeds sys.maxsize"); + convert_unsigned_long_into_uint16_t(&err, py_gen, + "generation"); + if (err.code != AEROSPIKE_OK) { goto CLEANUP; } } diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 1b22db2257..9482876d43 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -30,8 +30,9 @@ #include "exceptions.h" #include "policy.h" -static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, - as_error *err); +static bool getTypeFromPyObject(PyObject *py_datatype, + unsigned int *idx_datatype, + unsigned int max_enum_value, as_error *err); static PyObject *createIndexWithCollectionType( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, @@ -244,11 +245,13 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, return NULL; } - if (!getTypeFromPyObject(py_indextype, (int *)&index_type, &err)) { + if (!getTypeFromPyObject(py_indextype, (unsigned int *)&index_type, + AS_INDEX_TYPE_MAPVALUES, &err)) { goto CLEANUP; } - if (!getTypeFromPyObject(py_datatype, (int *)&data_type, &err)) { + if (!getTypeFromPyObject(py_datatype, (unsigned int *)&data_type, + AS_INDEX_BLOB, &err)) { goto CLEANUP; } @@ -513,19 +516,18 @@ PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, /* * Convert a PyObject into an as_index_datatype, return False if the conversion fails for any reason. */ -static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, - as_error *err) +static bool getTypeFromPyObject(PyObject *py_datatype, + unsigned int *idx_datatype, + unsigned int max_enum_value, as_error *err) { long type = 0; if (PyLong_Check(py_datatype)) { - type = PyLong_AsLong(py_datatype); - if (type == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); - goto CLEANUP; - } + + *idx_datatype = convert_unsigned_long_into_enum( + err, py_datatype, max_enum_value, "for getTypeFromPyObject"); + if (err->code != AEROSPIKE_OK) { + goto CLEANUP; } } else { @@ -534,7 +536,7 @@ static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, goto CLEANUP; } - *idx_datatype = type; + *idx_datatype = (unsigned int)type; CLEANUP: if (err->code != AEROSPIKE_OK) { @@ -558,7 +560,8 @@ static PyObject *createIndexWithCollectionType( as_error err; as_error_init(&err); - if (!getTypeFromPyObject(py_datatype, (int *)&data_type, &err)) { + if (!getTypeFromPyObject(py_datatype, (unsigned int *)&data_type, + (unsigned int)AS_INDEX_BLOB, &err)) { return NULL; } diff --git a/src/main/client/truncate.c b/src/main/client/truncate.c index 141ecdc5ac..ce968012a4 100644 --- a/src/main/client/truncate.c +++ b/src/main/client/truncate.c @@ -65,7 +65,6 @@ PyObject *AerospikeClient_Truncate(AerospikeClient *self, PyObject *args, PyObject *py_nanos = NULL; PyObject *py_policy = NULL; PyObject *ret_val = NULL; - long long temp_long; as_error err; uint64_t nanos = 1; // If assignment fails, this will cause an error char *namespace = NULL; @@ -126,21 +125,9 @@ PyObject *AerospikeClient_Truncate(AerospikeClient *self, PyObject *args, // Start conversion of the nanosecond parameter if (PyLong_Check(py_nanos)) { - - temp_long = PyLong_AsLongLong(py_nanos); - // There was a negative number outside of the range of - 2 ^ 63 - if (temp_long < 0 && !PyErr_Occurred()) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Nanoseconds must be a positive value"); - goto CLEANUP; - } - // Its possible that this is a valid uint64 between 2 ^ 63 and 2^64 -1 - PyErr_Clear(); - nanos = (uint64_t)PyLong_AsUnsignedLongLong(py_nanos); - - if (PyErr_Occurred()) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Nanoseconds value too large"); + nanos = convert_unsigned_long_long_into_uint64_t(&err, py_nanos, + "truncate"); + if (err.code) { goto CLEANUP; } } diff --git a/src/main/client/type.c b/src/main/client/type.c index 842f4cd90c..fb9ed43ea7 100644 --- a/src/main/client/type.c +++ b/src/main/client/type.c @@ -758,7 +758,11 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, py_port = PyTuple_GetItem(py_host, 1); if (PyLong_Check(py_port)) { - port = (uint16_t)PyLong_AsLong(py_port); + port = convert_unsigned_long_into_uint16_t( + &constructor_err, py_port, "config.port"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } else { as_error_update(&constructor_err, AEROSPIKE_ERR_PARAM, @@ -827,11 +831,19 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_shm_max_nodes = PyDict_GetItemString(py_shm, "shm_max_nodes"); if (py_shm_max_nodes && PyLong_Check(py_shm_max_nodes)) { - config.shm_max_nodes = PyLong_AsLong(py_shm_max_nodes); + config.shm_max_nodes = convert_unsigned_long_into_uint32_t( + &constructor_err, py_shm_max_nodes, "config.shm_max_nodes"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } py_shm_max_nodes = PyDict_GetItemString(py_shm, "max_nodes"); if (py_shm_max_nodes && PyLong_Check(py_shm_max_nodes)) { - config.shm_max_nodes = PyLong_AsLong(py_shm_max_nodes); + config.shm_max_nodes = convert_unsigned_long_into_uint32_t( + &constructor_err, py_shm_max_nodes, "config.max_nodes"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } // This does not match documentation (wrong name and location in dict), @@ -839,11 +851,21 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_shm_max_namespaces = PyDict_GetItemString(py_shm, "shm_max_namespaces"); if (py_shm_max_namespaces && PyLong_Check(py_shm_max_namespaces)) { - config.shm_max_namespaces = PyLong_AsLong(py_shm_max_namespaces); + config.shm_max_nodes = convert_unsigned_long_into_uint32_t( + &constructor_err, py_shm_max_namespaces, + "config.shm_max_namespaces"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } py_shm_max_namespaces = PyDict_GetItemString(py_shm, "max_namespaces"); if (py_shm_max_namespaces && PyLong_Check(py_shm_max_namespaces)) { - config.shm_max_namespaces = PyLong_AsLong(py_shm_max_namespaces); + config.shm_max_namespaces = convert_unsigned_long_into_uint32_t( + &constructor_err, py_shm_max_namespaces, + "config.max_namespaces"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } // This does not match documentation (wrong name and location in dict), @@ -853,20 +875,34 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, if (py_shm_takeover_threshold_sec && PyLong_Check(py_shm_takeover_threshold_sec)) { config.shm_takeover_threshold_sec = - PyLong_AsLong(py_shm_takeover_threshold_sec); + (uint32_t)convert_unsigned_long_into_uint32_t( + &constructor_err, py_shm_takeover_threshold_sec, + "config.shm_takeover_threshold_sec"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } py_shm_takeover_threshold_sec = PyDict_GetItemString(py_shm, "takeover_threshold_sec"); if (py_shm_takeover_threshold_sec && PyLong_Check(py_shm_takeover_threshold_sec)) { config.shm_takeover_threshold_sec = - PyLong_AsLong(py_shm_takeover_threshold_sec); + (uint32_t)convert_unsigned_long_into_uint32_t( + &constructor_err, py_shm_takeover_threshold_sec, + "config.takeover_threshold_sec"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } PyObject *py_shm_cluster_key = PyDict_GetItemString(py_shm, "shm_key"); if (py_shm_cluster_key && PyLong_Check(py_shm_cluster_key)) { user_shm_key = true; - config.shm_key = PyLong_AsLong(py_shm_cluster_key); + config.shm_key = (int)convert_unsigned_long_into_uint32_t( + &constructor_err, py_shm_cluster_key, "config.shm_key"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } } @@ -917,7 +953,13 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, //global defaults setting PyObject *py_key_policy = PyDict_GetItemString(py_policies, "key"); if (py_key_policy && PyLong_Check(py_key_policy)) { - long long_key_policy = PyLong_AsLong(py_key_policy); + as_policy_key long_key_policy = + (as_policy_key)convert_unsigned_long_into_enum( + &constructor_err, py_key_policy, + (unsigned int)AS_POLICY_KEY_SEND, "config.policy.key"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } config.policies.read.key = long_key_policy; config.policies.write.key = long_key_policy; config.policies.apply.key = long_key_policy; @@ -928,71 +970,122 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_sock_timeout = PyDict_GetItemString(py_policies, "socket_timeout"); if (py_sock_timeout && PyLong_Check(py_sock_timeout)) { - long long_timeout = PyLong_AsLong(py_sock_timeout); - - config.policies.write.base.socket_timeout = long_timeout; - config.policies.read.base.socket_timeout = long_timeout; - config.policies.apply.base.socket_timeout = long_timeout; - config.policies.operate.base.socket_timeout = long_timeout; - config.policies.query.base.socket_timeout = long_timeout; - config.policies.scan.base.socket_timeout = long_timeout; - config.policies.remove.base.socket_timeout = long_timeout; - config.policies.batch.base.socket_timeout = long_timeout; + uint32_t socket_timeout = convert_unsigned_long_into_uint32_t( + &constructor_err, py_sock_timeout, + "config.policy.socket_timeout"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.policies.write.base.socket_timeout = socket_timeout; + config.policies.read.base.socket_timeout = socket_timeout; + config.policies.apply.base.socket_timeout = socket_timeout; + config.policies.operate.base.socket_timeout = socket_timeout; + config.policies.query.base.socket_timeout = socket_timeout; + config.policies.scan.base.socket_timeout = socket_timeout; + config.policies.remove.base.socket_timeout = socket_timeout; + config.policies.batch.base.socket_timeout = socket_timeout; + } + + PyObject *py_timeout_delay = + PyDict_GetItemString(py_policies, "timeout_delay"); + if (py_sock_timeout && PyLong_Check(py_sock_timeout)) { + uint32_t timeout_delay = convert_unsigned_long_into_uint32_t( + &constructor_err, py_timeout_delay, + "config.policy.timeout_delay"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.policies.write.base.timeout_delay = timeout_delay; + config.policies.read.base.timeout_delay = timeout_delay; + config.policies.apply.base.timeout_delay = timeout_delay; + config.policies.operate.base.timeout_delay = timeout_delay; + config.policies.query.base.timeout_delay = timeout_delay; + config.policies.scan.base.timeout_delay = timeout_delay; + config.policies.remove.base.timeout_delay = timeout_delay; + config.policies.batch.base.timeout_delay = timeout_delay; } PyObject *py_total_timeout = PyDict_GetItemString(py_policies, "total_timeout"); if (py_total_timeout && PyLong_Check(py_total_timeout)) { - long long_total_timeout = PyLong_AsLong(py_total_timeout); - - config.policies.write.base.total_timeout = long_total_timeout; - config.policies.read.base.total_timeout = long_total_timeout; - config.policies.apply.base.total_timeout = long_total_timeout; - config.policies.operate.base.total_timeout = long_total_timeout; - config.policies.query.base.total_timeout = long_total_timeout; - config.policies.scan.base.total_timeout = long_total_timeout; - config.policies.remove.base.total_timeout = long_total_timeout; - config.policies.batch.base.total_timeout = long_total_timeout; + uint32_t total_timeout = convert_unsigned_long_into_uint32_t( + &constructor_err, py_total_timeout, + "config.policy.total_timeout"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.policies.write.base.total_timeout = total_timeout; + config.policies.read.base.total_timeout = total_timeout; + config.policies.apply.base.total_timeout = total_timeout; + config.policies.operate.base.total_timeout = total_timeout; + config.policies.query.base.total_timeout = total_timeout; + config.policies.scan.base.total_timeout = total_timeout; + config.policies.remove.base.total_timeout = total_timeout; + config.policies.batch.base.total_timeout = total_timeout; } PyObject *py_max_retry = PyDict_GetItemString(py_policies, "max_retries"); if (py_max_retry && PyLong_Check(py_max_retry)) { - long long_max_retries = PyLong_AsLong(py_max_retry); - config.policies.write.base.max_retries = long_max_retries; - config.policies.read.base.max_retries = long_max_retries; - config.policies.apply.base.max_retries = long_max_retries; - config.policies.operate.base.max_retries = long_max_retries; - config.policies.query.base.max_retries = long_max_retries; - config.policies.scan.base.max_retries = long_max_retries; - config.policies.remove.base.max_retries = long_max_retries; - config.policies.batch.base.max_retries = long_max_retries; + uint32_t max_retries = convert_unsigned_long_into_uint32_t( + &constructor_err, py_max_retry, "config.policy.max_retries"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.policies.write.base.max_retries = max_retries; + config.policies.read.base.max_retries = max_retries; + config.policies.apply.base.max_retries = max_retries; + config.policies.operate.base.max_retries = max_retries; + config.policies.query.base.max_retries = max_retries; + config.policies.scan.base.max_retries = max_retries; + config.policies.remove.base.max_retries = max_retries; + config.policies.batch.base.max_retries = max_retries; } PyObject *py_exists = PyDict_GetItemString(py_policies, "exists"); if (py_exists && PyLong_Check(py_exists)) { - long long_exists = PyLong_AsLong(py_exists); - config.policies.write.exists = long_exists; + as_policy_exists exists = + (as_policy_exists)convert_unsigned_long_into_enum( + &constructor_err, py_exists, + (unsigned int)AS_POLICY_EXISTS_CREATE_OR_REPLACE, + "config.policy.exists"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.policies.write.exists = exists; } PyObject *py_replica = PyDict_GetItemString(py_policies, "replica"); if (py_replica && PyLong_Check(py_replica)) { - long long_replica = PyLong_AsLong(py_replica); - config.policies.read.replica = long_replica; - config.policies.write.replica = long_replica; - config.policies.apply.replica = long_replica; - config.policies.operate.replica = long_replica; - config.policies.remove.replica = long_replica; - config.policies.batch.replica = long_replica; - config.policies.scan.replica = long_replica; - config.policies.query.replica = long_replica; + as_policy_exists replica = + (as_policy_exists)convert_unsigned_long_into_enum( + &constructor_err, py_replica, + (unsigned int)AS_POLICY_REPLICA_RANDOM, + "config.policy.replica"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.policies.read.replica = replica; + config.policies.write.replica = replica; + config.policies.apply.replica = replica; + config.policies.operate.replica = replica; + config.policies.remove.replica = replica; + config.policies.batch.replica = replica; + config.policies.scan.replica = replica; + config.policies.query.replica = replica; } PyObject *py_ap_read_mode = PyDict_GetItemString(py_policies, "read_mode_ap"); if (py_ap_read_mode && PyLong_Check(py_ap_read_mode)) { as_policy_read_mode_ap ap_read_mode = - (as_policy_read_mode_ap)PyLong_AsLong(py_ap_read_mode); + (as_policy_read_mode_ap)convert_unsigned_long_into_enum( + &constructor_err, py_ap_read_mode, + (unsigned int)AS_POLICY_READ_MODE_AP_ALL, + "config.policy.read_mode_ap"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } config.policies.read.read_mode_ap = ap_read_mode; config.policies.operate.read_mode_ap = ap_read_mode; config.policies.batch.read_mode_ap = ap_read_mode; @@ -1002,7 +1095,13 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyDict_GetItemString(py_policies, "read_mode_sc"); if (py_sc_read_mode && PyLong_Check(py_sc_read_mode)) { as_policy_read_mode_sc sc_read_mode = - (as_policy_read_mode_sc)PyLong_AsLong(py_sc_read_mode); + (as_policy_read_mode_sc)convert_unsigned_long_into_enum( + &constructor_err, py_sc_read_mode, + (unsigned int)AS_POLICY_READ_MODE_SC_ALLOW_UNAVAILABLE, + "config.policy.read_mode_sc"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } config.policies.read.read_mode_sc = sc_read_mode; config.policies.operate.read_mode_sc = sc_read_mode; config.policies.batch.read_mode_sc = sc_read_mode; @@ -1011,11 +1110,18 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_commit_level = PyDict_GetItemString(py_policies, "commit_level"); if (py_commit_level && PyLong_Check(py_commit_level)) { - long long_commit_level = PyLong_AsLong(py_commit_level); - config.policies.write.commit_level = long_commit_level; - config.policies.apply.commit_level = long_commit_level; - config.policies.operate.commit_level = long_commit_level; - config.policies.remove.commit_level = long_commit_level; + as_policy_commit_level commit_level = + (as_policy_commit_level)convert_unsigned_long_into_enum( + &constructor_err, py_commit_level, + (unsigned int)AS_POLICY_COMMIT_LEVEL_MASTER, + "config.policy.commit_level"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.policies.write.commit_level = commit_level; + config.policies.apply.commit_level = commit_level; + config.policies.operate.commit_level = commit_level; + config.policies.remove.commit_level = commit_level; } // This does not match documentation (should not be in policies), @@ -1023,7 +1129,12 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_max_threads = PyDict_GetItemString(py_policies, "max_threads"); if (py_max_threads && PyLong_Check(py_max_threads)) { - config.max_conns_per_node = PyLong_AsLong(py_max_threads); + uint32_t max_conns_per_node = convert_unsigned_long_into_uint32_t( + &constructor_err, py_max_threads, "config.policy.max_threads"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.max_conns_per_node = max_conns_per_node; } // This does not match documentation (should not be in policies), @@ -1031,7 +1142,13 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_thread_pool_size = PyDict_GetItemString(py_policies, "thread_pool_size"); if (py_thread_pool_size && PyLong_Check(py_thread_pool_size)) { - config.thread_pool_size = PyLong_AsLong(py_thread_pool_size); + uint32_t thread_pool_size = convert_unsigned_long_into_uint32_t( + &constructor_err, py_thread_pool_size, + "config.policy.thread_pool_size"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.thread_pool_size = thread_pool_size; } /* @@ -1099,7 +1216,13 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_login_timeout = PyDict_GetItemString(py_policies, "login_timeout_ms"); if (py_login_timeout && PyLong_Check(py_login_timeout)) { - config.login_timeout_ms = PyLong_AsLong(py_login_timeout); + uint32_t login_timeout_ms = convert_unsigned_long_into_uint32_t( + &constructor_err, py_login_timeout, + "config.policy.login_timeout_ms"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } + config.login_timeout_ms = login_timeout_ms; } PyObject *py_auth_mode = PyDict_GetItemString(py_policies, "auth_mode"); @@ -1129,26 +1252,34 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_thread_pool_size = PyDict_GetItemString(py_config, "thread_pool_size"); if (py_thread_pool_size && PyLong_Check(py_thread_pool_size)) { - config.thread_pool_size = PyLong_AsLong(py_thread_pool_size); - } - - // max_threads (backward compatibility) - PyObject *py_max_threads = PyDict_GetItemString(py_config, "max_threads"); - if (py_max_threads && PyLong_Check(py_max_threads)) { - config.max_conns_per_node = PyLong_AsLong(py_max_threads); + config.thread_pool_size = convert_unsigned_long_into_uint32_t( + &constructor_err, py_thread_pool_size, + "config.policy.thread_pool_size"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } PyObject *py_min_conns_per_node = PyDict_GetItemString(py_config, "min_conns_per_node"); if (py_min_conns_per_node && PyLong_Check(py_min_conns_per_node)) { - config.min_conns_per_node = PyLong_AsLong(py_min_conns_per_node); + config.min_conns_per_node = convert_unsigned_long_into_uint32_t( + &constructor_err, py_min_conns_per_node, + "config.policy.min_conns_per_node"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } // max_conns_per_node PyObject *py_max_conns = PyDict_GetItemString(py_config, "max_conns_per_node"); if (py_max_conns && PyLong_Check(py_max_conns)) { - config.max_conns_per_node = PyLong_AsLong(py_max_conns); + config.max_conns_per_node = convert_unsigned_long_into_uint32_t( + &constructor_err, py_max_conns, "config.policy.max_conns_per_node"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } // max_error_rate @@ -1156,7 +1287,12 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyDict_GetItemString(py_config, "max_error_rate"); Py_XINCREF(py_max_error_rate); if (py_max_error_rate && PyLong_Check(py_max_error_rate)) { - config.max_error_rate = PyLong_AsLong(py_max_error_rate); + config.max_error_rate = convert_unsigned_long_into_uint32_t( + &constructor_err, py_max_error_rate, + "config.policy.max_error_rate"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } Py_XDECREF(py_max_error_rate); @@ -1165,7 +1301,12 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyDict_GetItemString(py_config, "error_rate_window"); Py_XINCREF(py_error_rate_window); if (py_error_rate_window && PyLong_Check(py_error_rate_window)) { - config.error_rate_window = PyLong_AsLong(py_error_rate_window); + config.error_rate_window = convert_unsigned_long_into_uint32_t( + &constructor_err, py_error_rate_window, + "config.policy.error_rate_window"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } Py_XDECREF(py_error_rate_window); @@ -1173,7 +1314,12 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_connect_timeout = PyDict_GetItemString(py_config, "connect_timeout"); if (py_connect_timeout && PyLong_Check(py_connect_timeout)) { - config.conn_timeout_ms = PyLong_AsLong(py_connect_timeout); + config.conn_timeout_ms = convert_unsigned_long_into_uint32_t( + &constructor_err, py_connect_timeout, + "config.policy.connect_timeout"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } //Whether to utilize shared connection @@ -1185,10 +1331,11 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_send_bool_as = PyDict_GetItemString(py_config, "send_bool_as"); if (py_send_bool_as != NULL && PyLong_Check(py_send_bool_as)) { - int send_bool_as_temp = PyLong_AsLong(py_send_bool_as); - if (send_bool_as_temp >= SEND_BOOL_AS_INTEGER && - send_bool_as_temp <= SEND_BOOL_AS_AS_BOOL) { - self->send_bool_as = send_bool_as_temp; + self->send_bool_as = (uint8_t)convert_unsigned_long_into_enum( + &constructor_err, py_send_bool_as, + (unsigned int)SEND_BOOL_AS_AS_BOOL, "config.policy.send_bool_as"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; } } @@ -1196,12 +1343,11 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_compression_threshold = PyDict_GetItemString(py_config, "compression_threshold"); if (py_compression_threshold && PyLong_Check(py_compression_threshold)) { - int compression_value = PyLong_AsLong(py_compression_threshold); - if (compression_value >= 0) { - config.policies.write.compression_threshold = compression_value; - } - else { - error_code = INIT_COMPRESSION_ERR; + config.policies.write.compression_threshold = + convert_unsigned_long_into_uint32_t( + &constructor_err, py_compression_threshold, + "config.policy.write.compression_threshold"); + if (constructor_err.code != AEROSPIKE_OK) { goto CONSTRUCTOR_ERROR; } } @@ -1209,7 +1355,11 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_tend_interval = PyDict_GetItemString(py_config, "tend_interval"); if (py_tend_interval && PyLong_Check(py_tend_interval)) { - config.tender_interval = PyLong_AsLong(py_tend_interval); + config.tender_interval = convert_unsigned_long_into_uint32_t( + &constructor_err, py_tend_interval, "config.tend_interval"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } PyObject *py_cluster_name = PyDict_GetItemString(py_config, "cluster_name"); @@ -1257,10 +1407,16 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_max_socket_idle = NULL; py_max_socket_idle = PyDict_GetItemString(py_config, "max_socket_idle"); if (py_max_socket_idle && PyLong_Check(py_max_socket_idle)) { + long max_socket_idle = PyLong_AsLong(py_max_socket_idle); if (max_socket_idle >= 0) { config.max_socket_idle = (uint32_t)max_socket_idle; } + config.max_socket_idle = convert_unsigned_long_into_uint32_t( + &constructor_err, py_max_socket_idle, "config.max_socket_idle"); + if (constructor_err.code != AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } } bool *bool_config_refs[] = {&config.force_single_node, @@ -1384,7 +1540,10 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, static int set_rack_aware_config(as_config *conf, PyObject *config_dict) { PyObject *py_config_value; - long rack_id; + + as_error err; + as_error_init(&err); + py_config_value = PyDict_GetItemString(config_dict, "rack_aware"); if (py_config_value) { if (PyBool_Check(py_config_value)) { @@ -1398,19 +1557,12 @@ static int set_rack_aware_config(as_config *conf, PyObject *config_dict) py_config_value = PyDict_GetItemString(config_dict, "rack_id"); if (py_config_value) { if (PyLong_Check(py_config_value)) { - rack_id = PyLong_AsLong(py_config_value); - } - else { - return INIT_POLICY_PARAM_ERR; // A non integer passed in. - } - if (rack_id == -1 && PyErr_Occurred()) { - return INIT_POLICY_PARAM_ERR; // We had overflow. - } - - if (rack_id > INT_MAX || rack_id < INT_MIN) { - return INIT_POLICY_PARAM_ERR; // Magnitude too great for an integer in C. + conf->rack_id = + convert_long_into_int(&err, py_config_value, "config.rack_id"); + if (err.code != AEROSPIKE_OK) { + return INIT_POLICY_PARAM_ERR; + } } - conf->rack_id = (int)rack_id; } PyObject *rack_ids_pylist = PyDict_GetItemString(config_dict, "rack_ids"); @@ -1438,14 +1590,15 @@ static int set_rack_aware_config(as_config *conf, PyObject *config_dict) goto PARAM_ERROR; } - long rack_id = PyLong_AsLong(rack_id_pyobj); - if (rack_id == -1) { + int rack_id = + convert_long_into_int(&err, py_config_value, "config.rack_id"); + if (err.code != AEROSPIKE_OK) { // Error occurred Py_DECREF(rack_id_pyobj); goto PARAM_ERROR; } - as_config_add_rack_id(conf, (int)rack_id); + as_config_add_rack_id(conf, rack_id); Py_DECREF(rack_id_pyobj); } diff --git a/src/main/conversions.c b/src/main/conversions.c index 23065d51c7..2cc4ab6e3d 100644 --- a/src/main/conversions.c +++ b/src/main/conversions.c @@ -1283,14 +1283,12 @@ as_status as_val_new_from_pyobject(AerospikeClient *self, as_error *err, } } else if (PyLong_Check(py_obj)) { - int64_t i = (int64_t)PyLong_AsLongLong(py_obj); - if (i == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - return as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); - } + int64_t int_val = convert_long_long_into_int64_t( + err, py_obj, "as_val_new_from_pyobject"); + if (err->code != AEROSPIKE_OK) { + return err->code; } - *val = (as_val *)as_integer_new(i); + *val = (as_val *)as_integer_new(int_val); } else if (PyUnicode_Check(py_obj)) { PyObject *py_ustr = PyUnicode_AsUTF8String(py_obj); @@ -1556,14 +1554,12 @@ as_status pyobject_to_key(as_error *err, PyObject *py_keytuple, as_key *key) Py_DECREF(py_ustr); } else if (PyLong_Check(py_key)) { - int64_t k = (int64_t)PyLong_AsLongLong(py_key); - if (-1 == k && PyErr_Occurred()) { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value for KEY exceeds sys.maxsize"); - } - else { - returnResult = as_key_init_int64(key, ns, set, k); + int64_t int_val = + convert_long_long_into_int64_t(err, py_key, "KEY"); + if (err->code != AEROSPIKE_OK) { + return err->code; } + returnResult = as_key_init_int64(key, ns, set, int_val); } else if (PyByteArray_Check(py_key)) { uint32_t sz = (uint32_t)PyByteArray_Size(py_key); @@ -2220,8 +2216,9 @@ void initialize_bin_for_strictypes(AerospikeClient *self, as_error *err, as_bin *binop_bin = &binop->bin; if (PyLong_Check(py_value)) { - int val = PyLong_AsLong(py_value); - as_integer_init((as_integer *)&binop_bin->value, val); + int64_t int_val = convert_long_long_into_int64_t( + err, py_value, "initialize_bin_for_strictypes"); + as_integer_init((as_integer *)&binop_bin->value, (int64_t)int_val); binop_bin->valuep = &binop_bin->value; } else if (PyUnicode_Check(py_value)) { @@ -2324,23 +2321,19 @@ as_status check_and_set_meta(PyObject *py_meta, uint32_t *ttl_ref, PyObject *py_gen = PyDict_GetItemString(py_meta, "gen"); PyObject *py_ttl = PyDict_GetItemString(py_meta, "ttl"); - uint32_t ttl = 0; - uint16_t gen = 0; if (py_ttl) { if (PyLong_Check(py_ttl)) { - ttl = (uint32_t)PyLong_AsLong(py_ttl); + *ttl_ref = + convert_unsigned_long_into_uint32_t(err, py_ttl, "Ttl"); + + if (err->code != AEROSPIKE_OK) { + return err->code; + } } else { return as_error_update(err, AEROSPIKE_ERR_PARAM, "Ttl should be an int or long"); } - - if ((uint32_t)-1 == ttl && PyErr_Occurred()) { - return as_error_update( - err, AEROSPIKE_ERR_PARAM, - "integer value for ttl exceeds sys.maxsize"); - } - *ttl_ref = ttl; } else { // Metadata dict was present, but ttl field did not exist @@ -2349,20 +2342,16 @@ as_status check_and_set_meta(PyObject *py_meta, uint32_t *ttl_ref, if (py_gen) { if (PyLong_Check(py_gen)) { - // TODO: Needs to check value doesn't go past unsigned 16 bit limit - gen = (uint16_t)PyLong_AsLong(py_gen); + *gen_ref = convert_unsigned_long_into_uint16_t(err, py_gen, + "Generation"); + if (err->code != AEROSPIKE_OK) { + return err->code; + } } else { return as_error_update(err, AEROSPIKE_ERR_PARAM, "Generation should be an int or long"); } - - if ((uint16_t)-1 == gen && PyErr_Occurred()) { - return as_error_update( - err, AEROSPIKE_ERR_PARAM, - "integer value for gen exceeds sys.maxsize"); - } - *gen_ref = gen; } } else if (py_meta && (py_meta != Py_None)) { @@ -2381,10 +2370,11 @@ as_status pyobject_to_index(AerospikeClient *self, as_error *err, { if (PyLong_Check(py_value)) { *long_val = PyLong_AsLong(py_value); - if (*long_val == -1 && PyErr_Occurred() && self->strict_types) { + if (PyErr_Occurred() && self->strict_types) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - return as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); + return as_error_update( + err, AEROSPIKE_ERR_PARAM, + "integer value for pyobject_to_index exceeds LONG_MAX"); } } } @@ -2664,24 +2654,11 @@ as_status get_int_from_py_int(as_error *err, PyObject *py_long, "%s must be an integer.", py_object_name); } - int int_to_return = PyLong_AsLong(py_long); - if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - return as_error_update(err, AEROSPIKE_ERR_PARAM, - "%s too large for C long.", py_object_name); - } - - return as_error_update(err, AEROSPIKE_ERR_PARAM, - "Failed to convert %s.", py_object_name); - } - - if (int_to_return > INT_MAX || int_to_return < INT_MIN) { - return as_error_update(err, AEROSPIKE_ERR_PARAM, - "%s too large for C int.", py_object_name); + *int_pointer = convert_long_into_int(err, py_long, py_object_name); + if (err->code != AEROSPIKE_OK) { + return err->code; } - *int_pointer = int_to_return; - return AEROSPIKE_OK; } @@ -2729,11 +2706,38 @@ as_status as_batch_result_to_BatchRecord(AerospikeClient *self, as_error *err, return err->code; } +long long convert_pyobject_to_signed_fixed_width_integer_type( + PyObject *pyobject, long long min_bound, long long max_bound) +{ + if (!PyLong_Check(pyobject)) { + PyErr_Format(PyExc_TypeError, "%S must be an integer", pyobject); + goto error; + } + long long value = PyLong_AsLongLong(pyobject); + if (PyErr_Occurred()) { + goto error; + } + + if (value > max_bound) { + PyErr_Format(PyExc_ValueError, "%S exceeds %lli", pyobject, max_bound); + goto error; + } + + if (value < min_bound) { + PyErr_Format(PyExc_ValueError, "%S exceeds %lli", pyobject, max_bound); + goto error; + } + + return value; + +error: + return -1; +} + // TODO: There's a helper function in the Python client wrapper code called // get_uint32_value, but this can replace it. -unsigned long long -convert_pyobject_to_fixed_width_integer_type(PyObject *pyobject, - unsigned long long max_bound) +unsigned long long convert_pyobject_to_unsigned_fixed_width_integer_type( + PyObject *pyobject, unsigned long long max_bound) { if (!PyLong_Check(pyobject)) { PyErr_Format(PyExc_TypeError, "%S must be an integer", pyobject); @@ -2755,28 +2759,259 @@ convert_pyobject_to_fixed_width_integer_type(PyObject *pyobject, return -1; } +uint64_t convert_unsigned_long_long_into_uint64_t(as_error *err, + PyObject *py_long, + const char *component) +{ + unsigned long long long_value = PyLong_AsUnsignedLongLong(py_long); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds ULLONG_MAX", + component); + } + else { + as_error_update( + err, AEROSPIKE_ERR_PARAM, + "Failed to convert integer value for %s to unsigned long long", + component) + } + return 0; + } + if (long_value > (unsigned long long)UINT64_MAX) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds UINT64_MAX", component); + return 0; + } + + return (uint64_t)long_value; +} + +int64_t convert_long_long_into_int64_t(as_error *err, PyObject *py_long, + const char *component) +{ + long long long_value = PyLong_AsLongLong(py_long); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds LLONG_MAX", + component); + } + else { + as_error_update( + err, AEROSPIKE_ERR_PARAM, + "Failed to convert integer value for %s to long long", + component) + } + return 0; + } + if (long_value > (long long)INT64_MAX) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds INT64_MAX", component); + return 0; + } + else if (long_value < (long long)INT64_MIN) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds INT64_MIN", component); + return 0; + } + return (int64_t)long_value; +} + +uint32_t convert_unsigned_long_into_uint32_t(as_error *err, PyObject *py_long, + const char *component) +{ + unsigned long long_value = PyLong_AsUnsignedLong(py_long); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds ULONG_MAX", + component); + } + else { + as_error_update( + err, AEROSPIKE_ERR_PARAM, + "Failed to convert integer value for %s to unsigned long", + component) + } + return 0; + } + if (long_value > (unsigned long)UINT32_MAX) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds UINT32_MAX", component); + return 0; + } + return (uint32_t)long_value; +} + +int32_t convert_long_into_int32_t(as_error *err, PyObject *py_long, + const char *component) +{ + long long_value = PyLong_AsLong(py_long); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds LONG_MAX", component); + } + else { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "Failed to convert integer value for %s to long", + component) + } + return 0; + } + if (long_value > (long)INT32_MAX) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds INT32_MAX", component); + return 0; + } + else if (long_value < (long)INT32_MIN) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds INT32_MIN", component); + return 0; + } + return (int32_t)long_value; +} + +uint16_t convert_unsigned_long_into_uint16_t(as_error *err, PyObject *py_long, + const char *component) +{ + unsigned long long_value = PyLong_AsUnsignedLong(py_long); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds LONG_MAX", component); + } + else { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "Failed to convert integer value for %s to long", + component) + } + return 0; + } + if (long_value > (unsigned long)UINT16_MAX) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds UINT16_MAX", component); + return 0; + } + return (uint16_t)long_value; +} + +int16_t convert_long_into_int16_t(as_error *err, PyObject *py_long, + const char *component) +{ + long long_value = PyLong_AsLong(py_long); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds LONG_MAX", component); + } + else { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "Failed to convert integer value for %s to long", + component) + } + return 0; + } + if (long_value > (long)INT16_MAX) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds INT16_MAX", component); + return 0; + } + else if (long_value < (long)INT16_MIN) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds INT16_MIN", component); + return 0; + } + return (int16_t)long_value; +} + +int convert_long_into_int(as_error *err, PyObject *py_long, + const char *component) +{ + // CHECK ALL CONVERSION TO LONG VALUE AND MAKE SURE FUNCTION SIGNATURE IS CORRECT + long long_value = PyLong_AsLong(py_long); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds LONG_MAX", component); + } + else { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "Failed to convert integer value for %s to long", + component) + } + return 0; + } + if (long_value > (long)INT_MAX) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds INT_MAX", component); + return 0; + } + else if (long_value < (long)INT_MIN) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds INT_MIN", component); + return 0; + } + return (int)long_value; +} + +unsigned int convert_unsigned_long_into_enum(as_error *err, PyObject *py_long, + unsigned int max_enum_value, + const char *component) +{ + unsigned long long_value = PyLong_AsUnsignedLong(py_long); + + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds LONG_MAX", component); + } + else { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "Failed to convert integer value for %s to long", + component) + } + return 0; + } + if (long_value > (unsigned long)max_enum_value) { + as_error_update( + err, AEROSPIKE_ERR_PARAM, + "integer value for %s exceeds value for the enumeration", + component); + return 0; + } + return (unsigned int)long_value; +} + +int64_t convert_pyobject_to_int64_t(PyObject *pyobject) +{ + return (int64_t)convert_pyobject_to_signed_fixed_width_integer_type( + pyobject, INT64_MIN, INT64_MAX); +} + uint8_t convert_pyobject_to_uint8_t(PyObject *pyobject) { - return (uint8_t)convert_pyobject_to_fixed_width_integer_type(pyobject, - UINT8_MAX); + return (uint8_t)convert_pyobject_to_unsigned_fixed_width_integer_type( + pyobject, UINT8_MAX); } uint16_t convert_pyobject_to_uint16_t(PyObject *pyobject) { - return (uint16_t)convert_pyobject_to_fixed_width_integer_type(pyobject, - UINT16_MAX); + return (uint16_t)convert_pyobject_to_unsigned_fixed_width_integer_type( + pyobject, UINT16_MAX); } uint32_t convert_pyobject_to_uint32_t(PyObject *pyobject) { - return (uint32_t)convert_pyobject_to_fixed_width_integer_type(pyobject, - UINT32_MAX); + return (uint32_t)convert_pyobject_to_unsigned_fixed_width_integer_type( + pyobject, UINT32_MAX); } uint64_t convert_pyobject_to_uint64_t(PyObject *pyobject) { - return (uint64_t)convert_pyobject_to_fixed_width_integer_type(pyobject, - UINT64_MAX); + return (uint64_t)convert_pyobject_to_unsigned_fixed_width_integer_type( + pyobject, UINT64_MAX); } const char *convert_pyobject_to_str(PyObject *py_obj) diff --git a/src/main/convert_expressions.c b/src/main/convert_expressions.c index 8bf1caf07f..2b29a55b9b 100644 --- a/src/main/convert_expressions.c +++ b/src/main/convert_expressions.c @@ -489,12 +489,11 @@ get_exp_val_from_pyval(AerospikeClient *self, as_static_pool *static_pool, tmp_entry; //TODO use as_exp_val((as_val *) bytes); here, might need a cast, not blocker } else if (PyLong_Check(py_obj)) { - int64_t l = (int64_t)PyLong_AsLongLong(py_obj); - if (l == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - return as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); - } + int64_t l = convert_long_long_into_int64_t(err, py_obj, + "get_exp_val_from_pyval"); + if (err->code == AEROSPIKE_OK) { + as_exp_entry tmp_entry = as_exp_int(l); + *new_entry = tmp_entry; } as_exp_entry tmp_entry = as_exp_int(l); diff --git a/src/main/convert_partition_filter.c b/src/main/convert_partition_filter.c index a5ff85f8f6..0ed148958b 100644 --- a/src/main/convert_partition_filter.c +++ b/src/main/convert_partition_filter.c @@ -92,9 +92,13 @@ as_status convert_partition_filter(AerospikeClient *self, goto ERROR_CLEANUP; } - long tmp_begin = 0; + uint16_t tmp_begin = 0; if (begin && PyLong_Check(begin)) { - tmp_begin = PyLong_AsLong(begin); + tmp_begin = convert_unsigned_long_into_uint16_t( + err, begin, "partition_filter.begin"); + if (err->code) { + goto ERROR_CLEANUP; + } } else if (begin) { as_error_update(err, AEROSPIKE_ERR_PARAM, @@ -104,27 +108,23 @@ as_status convert_partition_filter(AerospikeClient *self, goto ERROR_CLEANUP; } - if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_OverflowError)) { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "invalid begin for partition id: %d, \ - begin must fit in long", - ps->part_id); - goto ERROR_CLEANUP; - } - - if (tmp_begin >= CLUSTER_NPARTITIONS || tmp_begin < 0) { + if (tmp_begin >= (uint16_t)CLUSTER_NPARTITIONS || tmp_begin < (uint16_t)0) { as_error_update(err, AEROSPIKE_ERR_PARAM, "invalid partition_filter policy begin, begin must \ - be an int between 0 and %d inclusive", + be an int between 0 and %d inclusive", CLUSTER_NPARTITIONS - 1); goto ERROR_CLEANUP; } filter->begin = tmp_begin; - long tmp_count = CLUSTER_NPARTITIONS; + uint16_t tmp_count = CLUSTER_NPARTITIONS; if (count && PyLong_Check(count)) { - tmp_count = PyLong_AsLong(count); + tmp_count = convert_unsigned_long_into_uint16_t( + err, count, "partition_filter.count"); + if (err->code) { + goto ERROR_CLEANUP; + } } else if (count) { as_error_update(err, AEROSPIKE_ERR_PARAM, @@ -160,13 +160,13 @@ as_status convert_partition_filter(AerospikeClient *self, goto ERROR_CLEANUP; } - filter->digest.init = 0; + filter->digest.init = false; if (digest && PyDict_Check(digest)) { // TODO check these for overflow PyObject *init = PyDict_GetItemString(digest, "init"); - if (init && PyLong_Check(init)) { - filter->digest.init = PyLong_AsLong(init); + if (init && PyBool_Check(init)) { + filter->digest.init = (init == Py_True); } PyObject *value = PyDict_GetItemString(digest, "value"); @@ -191,8 +191,8 @@ as_status convert_partition_filter(AerospikeClient *self, goto ERROR_CLEANUP; } - if (PyLong_Check(py_done)) { - parts_all->done = (bool)PyLong_AsLong(py_done); + if (PyBool_Check(py_done)) { + parts_all->done = (py_done == Py_True); } else { as_error_update(err, AEROSPIKE_ERR_PARAM, @@ -210,8 +210,8 @@ as_status convert_partition_filter(AerospikeClient *self, goto ERROR_CLEANUP; } - if (PyLong_Check(py_retry)) { - parts_all->retry = (bool)PyLong_AsLong(py_retry); + if (PyBool_Check(py_retry)) { + parts_all->retry = (py_retry == Py_True); } else { as_error_update(err, AEROSPIKE_ERR_PARAM, @@ -233,8 +233,8 @@ as_status convert_partition_filter(AerospikeClient *self, } PyObject *init = PyTuple_GetItem(status_dict, 1); - if (init && PyLong_Check(init)) { - ps->digest.init = PyLong_AsLong(init); + if (init && PyBool_Check(init)) { + ps->digest.init = (init == Py_True); } else if (init) { as_error_update(err, AEROSPIKE_ERR_PARAM, @@ -243,8 +243,8 @@ as_status convert_partition_filter(AerospikeClient *self, } PyObject *retry = PyTuple_GetItem(status_dict, 2); - if (retry && PyLong_Check(retry)) { - ps->retry = (bool)PyLong_AsLong(retry); + if (retry && PyBool_Check(retry)) { + ps->retry = (retry == Py_True); } else if (retry) { as_error_update(err, AEROSPIKE_ERR_PARAM, @@ -274,13 +274,9 @@ as_status convert_partition_filter(AerospikeClient *self, } if (py_bval && PyLong_Check(py_bval)) { - ps->bval = PyLong_AsUnsignedLongLong(py_bval); - if (PyErr_Occurred() && - PyErr_ExceptionMatches(PyExc_OverflowError)) { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "invalid bval for partition id: %d, bval " - "must fit in unsigned long long", - ps->part_id); + ps->bval = convert_unsigned_long_long_into_uint64_t( + err, py_bval, "partition_status.bval"); + if (err->code != AEROSPIKE_OK) { goto ERROR_CLEANUP; } } diff --git a/src/main/log.c b/src/main/log.c index ba646cae1c..9d9e28256e 100644 --- a/src/main/log.c +++ b/src/main/log.c @@ -122,12 +122,18 @@ PyObject *Aerospike_Set_Log_Level(PyObject *parent, PyObject *args, } long log_level = PyLong_AsLong(py_log_level); - if (log_level == -1 && PyErr_Occurred()) { + if (PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update( + &err, AEROSPIKE_ERR_PARAM, + "integer value for Aerospike_Set_Log_Level exceeds ULLONG_MAX"); + } + else { as_error_update(&err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); - goto CLEANUP; + "Failed to convert integer value for " + "Aerospike_Set_Log_Level to unsigned long long") } + goto CLEANUP; } is_current_log_level_off = log_level == LOG_LEVEL_OFF; diff --git a/src/main/policy.c b/src/main/policy.c index f80cf2e9c0..8e4ff8c757 100644 --- a/src/main/policy.c +++ b/src/main/policy.c @@ -96,6 +96,158 @@ } \ } +#define POLICY_SET_FIELD_UINT_64T(__field) \ + { \ + PyObject *py_field_name = PyUnicode_FromString(#__field); \ + if (py_field_name == NULL) { \ + PyErr_Clear(); \ + return as_error_update(err, AEROSPIKE_ERR_CLIENT, \ + "Unable to create Python unicode object"); \ + } \ + PyObject *py_field = \ + PyDict_GetItemWithError(py_policy, py_field_name); \ + if (py_field == NULL && PyErr_Occurred()) { \ + PyErr_Clear(); \ + Py_DECREF(py_field_name); \ + return as_error_update( \ + err, AEROSPIKE_ERR_CLIENT, \ + "Unable to fetch field from policy dictionary"); \ + } \ + Py_DECREF(py_field_name); \ + \ + if (py_field) { \ + if (PyLong_Check(py_field)) { \ + uint64_t field_val = convert_unsigned_long_long_into_uint64_t( \ + err, py_field, "POLICY_SET_FIELD"); \ + if (err->code != AEROSPIKE_OK) { \ + PyErr_Clear(); \ + return as_error_update( \ + err, AEROSPIKE_ERR_CLIENT, \ + "Unable to fetch long value from policy field"); \ + } \ + policy->__field = field_val; \ + } \ + else { \ + return as_error_update(err, AEROSPIKE_ERR_PARAM, \ + "%s is invalid", #__field); \ + } \ + } \ + } + +#define POLICY_SET_FIELD_UINT_32T(__field) \ + { \ + PyObject *py_field_name = PyUnicode_FromString(#__field); \ + if (py_field_name == NULL) { \ + PyErr_Clear(); \ + return as_error_update(err, AEROSPIKE_ERR_CLIENT, \ + "Unable to create Python unicode object"); \ + } \ + PyObject *py_field = \ + PyDict_GetItemWithError(py_policy, py_field_name); \ + if (py_field == NULL && PyErr_Occurred()) { \ + PyErr_Clear(); \ + Py_DECREF(py_field_name); \ + return as_error_update( \ + err, AEROSPIKE_ERR_CLIENT, \ + "Unable to fetch field from policy dictionary"); \ + } \ + Py_DECREF(py_field_name); \ + \ + if (py_field) { \ + if (PyLong_Check(py_field)) { \ + uint32_t field_val = convert_unsigned_long_into_uint32_t( \ + err, py_field, "POLICY_SET_FIELD"); \ + if (err->code != AEROSPIKE_OK) { \ + PyErr_Clear(); \ + return as_error_update( \ + err, AEROSPIKE_ERR_CLIENT, \ + "Unable to fetch long value from policy field"); \ + } \ + policy->__field = field_val; \ + } \ + else { \ + return as_error_update(err, AEROSPIKE_ERR_PARAM, \ + "%s is invalid", #__field); \ + } \ + } \ + } + +#define POLICY_SET_FIELD_UINT_16T(__field) \ + { \ + PyObject *py_field_name = PyUnicode_FromString(#__field); \ + if (py_field_name == NULL) { \ + PyErr_Clear(); \ + return as_error_update(err, AEROSPIKE_ERR_CLIENT, \ + "Unable to create Python unicode object"); \ + } \ + PyObject *py_field = \ + PyDict_GetItemWithError(py_policy, py_field_name); \ + if (py_field == NULL && PyErr_Occurred()) { \ + PyErr_Clear(); \ + Py_DECREF(py_field_name); \ + return as_error_update( \ + err, AEROSPIKE_ERR_CLIENT, \ + "Unable to fetch field from policy dictionary"); \ + } \ + Py_DECREF(py_field_name); \ + \ + if (py_field) { \ + if (PyLong_Check(py_field)) { \ + uint16_t field_val = convert_unsigned_long_into_uint16_t( \ + err, py_field, "POLICY_SET_FIELD"); \ + if (err->code != AEROSPIKE_OK) { \ + PyErr_Clear(); \ + return as_error_update( \ + err, AEROSPIKE_ERR_CLIENT, \ + "Unable to fetch long value from policy field"); \ + } \ + policy->__field = field_val; \ + } \ + else { \ + return as_error_update(err, AEROSPIKE_ERR_PARAM, \ + "%s is invalid", #__field); \ + } \ + } \ + } + +#define POLICY_SET_FIELD_ENUM(__field, __max) \ + { \ + PyObject *py_field_name = PyUnicode_FromString(#__field); \ + if (py_field_name == NULL) { \ + PyErr_Clear(); \ + return as_error_update(err, AEROSPIKE_ERR_CLIENT, \ + "Unable to create Python unicode object"); \ + } \ + PyObject *py_field = \ + PyDict_GetItemWithError(py_policy, py_field_name); \ + if (py_field == NULL && PyErr_Occurred()) { \ + PyErr_Clear(); \ + Py_DECREF(py_field_name); \ + return as_error_update( \ + err, AEROSPIKE_ERR_CLIENT, \ + "Unable to fetch field from policy dictionary"); \ + } \ + Py_DECREF(py_field_name); \ + \ + if (py_field) { \ + if (PyLong_Check(py_field)) { \ + uint16_t field_val = convert_unsigned_long_into_enum( \ + err, py_field, __max, "POLICY_SET_FIELD"); \ + if (err->code != AEROSPIKE_OK) { \ + PyErr_Clear(); \ + return as_error_update( \ + err, AEROSPIKE_ERR_CLIENT, \ + "Unable to fetch long value from policy field"); \ + } \ + policy->__field = field_val; \ + } \ + else { \ + return as_error_update(err, AEROSPIKE_ERR_PARAM, \ + "%s is invalid", #__field); \ + } \ + } \ + } + #define POLICY_SET_EXPRESSIONS_FIELD() \ { \ PyObject *py_field_name = PyUnicode_FromString("expressions"); \ @@ -264,7 +416,7 @@ as_status pyobject_to_policy_admin(AerospikeClient *self, as_error *err, } // Set policy fields - POLICY_SET_FIELD(timeout, uint32_t); + POLICY_SET_FIELD_UINT_32T(timeout); } // Update the policy POLICY_UPDATE(); @@ -315,13 +467,13 @@ static inline as_status pyobject_to_policy_base(AerospikeClient *self, as_policy_base *policy, as_exp **exp_list_p) { - POLICY_SET_FIELD(total_timeout, uint32_t); - POLICY_SET_FIELD(socket_timeout, uint32_t); - POLICY_SET_FIELD(timeout_delay, uint32_t); - POLICY_SET_FIELD(max_retries, uint32_t); - POLICY_SET_FIELD(sleep_between_retries, uint32_t); + POLICY_SET_FIELD_UINT_32T(total_timeout); + POLICY_SET_FIELD_UINT_32T(socket_timeout); + POLICY_SET_FIELD_UINT_32T(timeout_delay); + POLICY_SET_FIELD_UINT_32T(max_retries); + POLICY_SET_FIELD_UINT_32T(sleep_between_retries); POLICY_SET_FIELD(compress, bool); - POLICY_SET_FIELD(connect_timeout, uint32_t); + POLICY_SET_FIELD_UINT_32T(connect_timeout); // Setting txn field to a non-NULL value in a query or scan policy is a no-op, // so this is safe to call for a scan/query policy's base policy @@ -375,12 +527,12 @@ as_status pyobject_to_policy_apply(AerospikeClient *self, as_error *err, return retval; } - POLICY_SET_FIELD(key, as_policy_key); - POLICY_SET_FIELD(replica, as_policy_replica); + POLICY_SET_FIELD_ENUM(key, AS_POLICY_KEY_SEND); + POLICY_SET_FIELD_ENUM(replica, AS_POLICY_REPLICA_RANDOM); //POLICY_SET_FIELD(gen, as_policy_gen); removed - POLICY_SET_FIELD(commit_level, as_policy_commit_level); + POLICY_SET_FIELD_ENUM(commit_level, AS_POLICY_COMMIT_LEVEL_MASTER); POLICY_SET_FIELD(durable_delete, bool); - POLICY_SET_FIELD(ttl, uint32_t); + POLICY_SET_FIELD_UINT_32T(ttl); POLICY_SET_FIELD(on_locking_only, bool); } @@ -438,7 +590,7 @@ pyobject_to_policy_info(as_error *err, PyObject *py_policy, } // Set policy fields - POLICY_SET_FIELD(timeout, uint32_t); + POLICY_SET_FIELD_UINT_32T(timeout); // POLICY_SET_FIELD(timeout_delay, uint32_t); POLICY_SET_FIELD(send_as_is, bool); POLICY_SET_FIELD(check_bounds, bool); @@ -490,12 +642,13 @@ as_status pyobject_to_policy_query(AerospikeClient *self, as_error *err, return retval; } POLICY_SET_FIELD(deserialize, bool); - POLICY_SET_FIELD(replica, as_policy_replica); + POLICY_SET_FIELD_ENUM(replica, AS_POLICY_REPLICA_RANDOM); // C client 6.0.0 POLICY_SET_FIELD(short_query, bool); - POLICY_SET_FIELD(expected_duration, as_query_duration); + POLICY_SET_FIELD_ENUM(expected_duration, + AS_QUERY_DURATION_LONG_RELAX_AP); } // Update the policy @@ -546,14 +699,15 @@ as_status pyobject_to_policy_read(AerospikeClient *self, as_error *err, return retval; } - POLICY_SET_FIELD(key, as_policy_key); - POLICY_SET_FIELD(replica, as_policy_replica); + POLICY_SET_FIELD_ENUM(key, AS_POLICY_KEY_SEND); + POLICY_SET_FIELD_ENUM(replica, AS_POLICY_REPLICA_RANDOM); POLICY_SET_FIELD(deserialize, bool); POLICY_SET_FIELD(read_touch_ttl_percent, int); // 4.0.0 new policies - POLICY_SET_FIELD(read_mode_ap, as_policy_read_mode_ap); - POLICY_SET_FIELD(read_mode_sc, as_policy_read_mode_sc); + POLICY_SET_FIELD_ENUM(read_mode_ap, AS_POLICY_READ_MODE_AP_ALL); + POLICY_SET_FIELD_ENUM(read_mode_sc, + AS_POLICY_READ_MODE_SC_ALLOW_UNAVAILABLE); } // Update the policy @@ -604,12 +758,12 @@ as_status pyobject_to_policy_remove(AerospikeClient *self, as_error *err, return retval; } - POLICY_SET_FIELD(generation, uint16_t); + POLICY_SET_FIELD_UINT_16T(generation); - POLICY_SET_FIELD(key, as_policy_key); - POLICY_SET_FIELD(gen, as_policy_gen); - POLICY_SET_FIELD(commit_level, as_policy_commit_level); - POLICY_SET_FIELD(replica, as_policy_replica); + POLICY_SET_FIELD_ENUM(key, AS_POLICY_KEY_SEND); + POLICY_SET_FIELD_ENUM(gen, AS_POLICY_GEN_GT); + POLICY_SET_FIELD_ENUM(commit_level, AS_POLICY_COMMIT_LEVEL_MASTER); + POLICY_SET_FIELD_ENUM(replica, AS_POLICY_REPLICA_RANDOM); POLICY_SET_FIELD(durable_delete, bool); } @@ -669,10 +823,10 @@ pyobject_to_policy_scan(AerospikeClient *self, as_error *err, } POLICY_SET_FIELD(durable_delete, bool); - POLICY_SET_FIELD(records_per_second, uint32_t); - POLICY_SET_FIELD(max_records, uint64_t); - POLICY_SET_FIELD(replica, as_policy_replica); - POLICY_SET_FIELD(ttl, uint32_t); + POLICY_SET_FIELD_UINT_32T(records_per_second); + POLICY_SET_FIELD_UINT_64T(max_records); + POLICY_SET_FIELD_ENUM(replica, AS_POLICY_REPLICA_RANDOM); + POLICY_SET_FIELD_UINT_32T(ttl); } // Update the policy @@ -729,14 +883,14 @@ as_status pyobject_to_policy_write( return retval; } - POLICY_SET_FIELD(key, as_policy_key); - POLICY_SET_FIELD(gen, as_policy_gen); - POLICY_SET_FIELD(exists, as_policy_exists); - POLICY_SET_FIELD(commit_level, as_policy_commit_level); + POLICY_SET_FIELD_ENUM(key, AS_POLICY_KEY_SEND); + POLICY_SET_FIELD_ENUM(gen, AS_POLICY_GEN_GT); + POLICY_SET_FIELD_ENUM(exists, AS_POLICY_EXISTS_CREATE_OR_REPLACE); + POLICY_SET_FIELD_ENUM(commit_level, AS_POLICY_COMMIT_LEVEL_MASTER); POLICY_SET_FIELD(durable_delete, bool); - POLICY_SET_FIELD(replica, as_policy_replica); - POLICY_SET_FIELD(ttl, uint32_t); - POLICY_SET_FIELD(compression_threshold, uint32_t); + POLICY_SET_FIELD_ENUM(replica, AS_POLICY_REPLICA_RANDOM); + POLICY_SET_FIELD_UINT_32T(ttl); + POLICY_SET_FIELD_UINT_32T(compression_threshold); POLICY_SET_FIELD(on_locking_only, bool); } @@ -787,20 +941,21 @@ as_status pyobject_to_policy_operate(AerospikeClient *self, as_error *err, return retval; } - POLICY_SET_FIELD(key, as_policy_key); - POLICY_SET_FIELD(gen, as_policy_gen); - POLICY_SET_FIELD(commit_level, as_policy_commit_level); - POLICY_SET_FIELD(replica, as_policy_replica); + POLICY_SET_FIELD_ENUM(key, AS_POLICY_KEY_SEND); + POLICY_SET_FIELD_ENUM(gen, AS_POLICY_GEN_GT); + POLICY_SET_FIELD_ENUM(commit_level, AS_POLICY_COMMIT_LEVEL_MASTER); + POLICY_SET_FIELD_ENUM(replica, AS_POLICY_REPLICA_RANDOM); POLICY_SET_FIELD(durable_delete, bool); POLICY_SET_FIELD(deserialize, bool); - POLICY_SET_FIELD(exists, as_policy_exists); + POLICY_SET_FIELD_ENUM(exists, AS_POLICY_EXISTS_CREATE_OR_REPLACE); POLICY_SET_FIELD(read_touch_ttl_percent, int); POLICY_SET_FIELD(on_locking_only, bool); - POLICY_SET_FIELD(ttl, uint32_t); + POLICY_SET_FIELD_UINT_32T(ttl); // 4.0.0 new policies - POLICY_SET_FIELD(read_mode_ap, as_policy_read_mode_ap); - POLICY_SET_FIELD(read_mode_sc, as_policy_read_mode_sc); + POLICY_SET_FIELD_ENUM(read_mode_ap, AS_POLICY_READ_MODE_AP_ALL); + POLICY_SET_FIELD_ENUM(read_mode_sc, + AS_POLICY_READ_MODE_SC_ALLOW_UNAVAILABLE); } // Update the policy @@ -852,12 +1007,13 @@ as_status pyobject_to_policy_batch(AerospikeClient *self, as_error *err, POLICY_SET_FIELD(concurrent, bool); POLICY_SET_FIELD(allow_inline, bool); POLICY_SET_FIELD(deserialize, bool); - POLICY_SET_FIELD(replica, as_policy_replica); + POLICY_SET_FIELD_ENUM(replica, AS_POLICY_REPLICA_RANDOM); POLICY_SET_FIELD(read_touch_ttl_percent, int); // 4.0.0 new policies - POLICY_SET_FIELD(read_mode_ap, as_policy_read_mode_ap); - POLICY_SET_FIELD(read_mode_sc, as_policy_read_mode_sc); + POLICY_SET_FIELD_ENUM(read_mode_ap, AS_POLICY_READ_MODE_AP_ALL); + POLICY_SET_FIELD_ENUM(read_mode_sc, + AS_POLICY_READ_MODE_SC_ALLOW_UNAVAILABLE); // C client 6.0.0 (batch writes) POLICY_SET_FIELD(allow_inline_ssd, bool); @@ -894,13 +1050,13 @@ as_status pyobject_to_batch_write_policy(AerospikeClient *self, as_error *err, } // Set policy fields - POLICY_SET_FIELD(key, as_policy_key); - POLICY_SET_FIELD(commit_level, as_policy_commit_level); - POLICY_SET_FIELD(gen, as_policy_gen); - POLICY_SET_FIELD(exists, as_policy_exists); + POLICY_SET_FIELD_ENUM(key, AS_POLICY_KEY_SEND); + POLICY_SET_FIELD_ENUM(commit_level, AS_POLICY_COMMIT_LEVEL_MASTER); + POLICY_SET_FIELD_ENUM(gen, AS_POLICY_GEN_GT); + POLICY_SET_FIELD_ENUM(exists, AS_POLICY_EXISTS_CREATE_OR_REPLACE); POLICY_SET_FIELD(durable_delete, bool); POLICY_SET_FIELD(on_locking_only, bool); - POLICY_SET_FIELD(ttl, uint32_t); + POLICY_SET_FIELD_UINT_32T(ttl); // C client 5.0 new expressions POLICY_SET_EXPRESSIONS_FIELD(); @@ -934,8 +1090,9 @@ as_status pyobject_to_batch_read_policy(AerospikeClient *self, as_error *err, } // Set policy fields - POLICY_SET_FIELD(read_mode_ap, as_policy_read_mode_ap); - POLICY_SET_FIELD(read_mode_sc, as_policy_read_mode_sc); + POLICY_SET_FIELD_ENUM(read_mode_ap, AS_POLICY_READ_MODE_AP_ALL); + POLICY_SET_FIELD_ENUM(read_mode_sc, + AS_POLICY_READ_MODE_SC_ALLOW_UNAVAILABLE); POLICY_SET_FIELD(read_touch_ttl_percent, int); // C client 5.0 new expressions @@ -970,9 +1127,9 @@ as_status pyobject_to_batch_apply_policy(AerospikeClient *self, as_error *err, } // Set policy fields - POLICY_SET_FIELD(key, as_policy_key); - POLICY_SET_FIELD(commit_level, as_policy_commit_level); - POLICY_SET_FIELD(ttl, uint32_t); + POLICY_SET_FIELD_ENUM(key, AS_POLICY_KEY_SEND); + POLICY_SET_FIELD_ENUM(commit_level, AS_POLICY_COMMIT_LEVEL_MASTER); + POLICY_SET_FIELD_UINT_32T(ttl); POLICY_SET_FIELD(durable_delete, bool); POLICY_SET_FIELD(on_locking_only, bool); @@ -1008,11 +1165,11 @@ as_status pyobject_to_batch_remove_policy(AerospikeClient *self, as_error *err, } // Set policy fields - POLICY_SET_FIELD(key, as_policy_key); - POLICY_SET_FIELD(commit_level, as_policy_commit_level); - POLICY_SET_FIELD(gen, as_policy_gen); + POLICY_SET_FIELD_ENUM(key, AS_POLICY_KEY_SEND); + POLICY_SET_FIELD_ENUM(commit_level, AS_POLICY_COMMIT_LEVEL_MASTER); + POLICY_SET_FIELD_ENUM(gen, AS_POLICY_GEN_GT); POLICY_SET_FIELD(durable_delete, bool); - POLICY_SET_FIELD(generation, uint16_t); + POLICY_SET_FIELD_UINT_16T(generation); // C client 5.0 new expressions POLICY_SET_EXPRESSIONS_FIELD(); diff --git a/src/main/policy_config.c b/src/main/policy_config.c index 6a76b45818..4b9195a8f3 100644 --- a/src/main/policy_config.c +++ b/src/main/policy_config.c @@ -16,6 +16,7 @@ #include #include "policy_config.h" +#include "conversions.h" #include "types.h" #include "policy.h" @@ -961,25 +962,16 @@ as_status set_base_policy(as_policy_base *base_policy, PyObject *py_policy) as_status get_uint32_value(PyObject *py_policy_val, uint32_t *return_uint32) { - long long int uint32_max = 0xFFFFFFFF; + as_error err; + as_error_init(&err); if (!py_policy_val) { return AEROSPIKE_ERR_PARAM; } if (PyLong_Check(py_policy_val)) { - long int_value = PyLong_AsLong(py_policy_val); - - if (int_value == -1 && PyErr_Occurred()) { - PyErr_Clear(); - return AEROSPIKE_ERR_PARAM; - } - - if (int_value < 0 || int_value > uint32_max) { - return AEROSPIKE_ERR_PARAM; - } - - *return_uint32 = (uint32_t)int_value; - return AEROSPIKE_OK; + *return_uint32 = convert_unsigned_long_into_uint32_t( + &err, py_policy_val, "get_uint32_value"); + return err.code; } return AEROSPIKE_ERR_PARAM; } @@ -987,8 +979,10 @@ as_status get_uint32_value(PyObject *py_policy_val, uint32_t *return_uint32) as_status set_optional_uint32_property(uint32_t *target_ptr, PyObject *py_policy, const char *name) { + as_error err; + as_error_init(&err); + PyObject *py_policy_val = NULL; - long long int uint32_max = 0xFFFFFFFF; if (!py_policy || !PyDict_Check(py_policy)) { return AEROSPIKE_OK; } @@ -998,22 +992,9 @@ as_status set_optional_uint32_property(uint32_t *target_ptr, return AEROSPIKE_OK; } if (PyLong_Check(py_policy_val)) { - long int_value = PyLong_AsLong(py_policy_val); - - if (int_value == -1 && PyErr_Occurred()) { - // This wasn't a valid int, or was too large - // We are handling the error ourselves, so clear the overflow error - PyErr_Clear(); - return AEROSPIKE_ERR_PARAM; - - /* If the number was less than zero, or would not fit in a uint32, error */ - } - if (int_value < 0 || int_value > uint32_max) { - return AEROSPIKE_ERR_PARAM; - } - - *target_ptr = (uint32_t)int_value; - return AEROSPIKE_OK; + *target_ptr = convert_unsigned_long_into_uint32_t(&err, py_policy_val, + "get_uint32_value"); + return err.code; } return AEROSPIKE_ERR_PARAM; } @@ -1021,6 +1002,8 @@ as_status set_optional_uint32_property(uint32_t *target_ptr, as_status set_optional_uint16_property(uint16_t *target_ptr, PyObject *py_policy, const char *name) { + as_error err; + as_error_init(&err); // Assume py_policy is a Python dictionary PyObject *py_policy_val = PyDict_GetItemString(py_policy, name); if (!py_policy_val) { @@ -1033,21 +1016,9 @@ as_status set_optional_uint16_property(uint16_t *target_ptr, return AEROSPIKE_ERR_PARAM; } - long int_value = PyLong_AsLong(py_policy_val); - if (int_value == -1 && PyErr_Occurred()) { - // This wasn't a valid int, or was too large - // We are handling the error ourselves, so clear the overflow error - PyErr_Clear(); - return AEROSPIKE_ERR_PARAM; - - /* If the number was less than zero, or would not fit in a uint16, error */ - } - if (int_value < 0 || int_value > UINT16_MAX) { - return AEROSPIKE_ERR_PARAM; - } - - *target_ptr = (uint16_t)int_value; - return AEROSPIKE_OK; + *target_ptr = convert_unsigned_long_into_uint16_t(&err, py_policy_val, + "get_uint32_value"); + return err.code; } as_status set_optional_bool_property(bool *target_ptr, PyObject *py_policy, @@ -1226,10 +1197,17 @@ as_status set_optional_exists(as_policy_exists *target_ptr, PyObject *py_policy, as_status set_optional_int_property(int *property_ptr, PyObject *py_policy, const char *field_name) { + as_error err; + as_error_init(&err); + PyObject *py_field = PyDict_GetItemString(py_policy, field_name); if (py_field) { if (PyLong_Check(py_field)) { - *property_ptr = (int)PyLong_AsLong(py_field); + *property_ptr = convert_long_into_int(&err, py_field, + "set_optional_int_property"); + if (err.code != AEROSPIKE_OK) { + return err.code; + } } else { return AEROSPIKE_ERR_PARAM; diff --git a/src/main/query/where.c b/src/main/query/where.c index f9eb0e37d5..fd22a92e3c 100644 --- a/src/main/query/where.c +++ b/src/main/query/where.c @@ -31,17 +31,6 @@ #undef TRACE #define TRACE() -// TODO: replace with helper function from conversions.c -int64_t pyobject_to_int64(PyObject *py_obj) -{ - if (PyLong_Check(py_obj)) { - return PyLong_AsLongLong(py_obj); - } - else { - return 0; - } -} - #define CTX_PARSE_ERROR_MESSAGE "Unable to parse ctx" // py_bin, py_val1, pyval2 are guaranteed to be non-NULL @@ -158,16 +147,21 @@ static int AerospikeQuery_Where_Add(AerospikeQuery *self, PyObject *py_ctx, val1 = (void *)val1_str; } else if (in_datatype == AS_INDEX_NUMERIC) { - val1_int = pyobject_to_int64(py_val1); - if (PyErr_Occurred()) { - PyErr_Clear(); - val1_int = 0; + + if (PyLong_Check(py_val2)) { + val1_int = convert_long_long_into_int64_t( + &err, py_val1, "query where numeric val1"); + if (err.code != AEROSPIKE_OK) { + PyErr_Clear(); + val1_int = 0; + } } val1 = (void *)val1_int; if (PyLong_Check(py_val2)) { - val2_int = pyobject_to_int64(py_val2); - if (PyErr_Occurred()) { + val2_int = convert_long_long_into_int64_t( + &err, py_val2, "query where numeric val2"); + if (err.code != AEROSPIKE_OK) { PyErr_Clear(); val2_int = 0; } diff --git a/src/main/transaction/type.c b/src/main/transaction/type.c index 61f2b00c14..4fec166b99 100644 --- a/src/main/transaction/type.c +++ b/src/main/transaction/type.c @@ -111,8 +111,9 @@ static PyObject *AerospikeTransaction_get_timeout(AerospikeTransaction *self, static int AerospikeTransaction_set_timeout(AerospikeTransaction *self, PyObject *py_value, void *closure) { - uint32_t timeout = (uint32_t)convert_pyobject_to_fixed_width_integer_type( - py_value, UINT32_MAX); + uint32_t timeout = + (uint32_t)convert_pyobject_to_unsigned_fixed_width_integer_type( + py_value, UINT32_MAX); if (PyErr_Occurred()) { return -1; } diff --git a/test/config.conf.template b/test/config.conf.template index 511288add0..c4f696159c 100644 --- a/test/config.conf.template +++ b/test/config.conf.template @@ -1,10 +1,7 @@ [input-validation] validate_keys: true -[community-edition] -hosts: 127.0.0.1:3000 - [enterprise-edition] -hosts : +hosts :localhost:3000 user : password : diff --git a/test/new_tests/test_dynamic_config.py b/test/new_tests/test_dynamic_config.py index 857ded21e0..d8555519c4 100644 --- a/test/new_tests/test_dynamic_config.py +++ b/test/new_tests/test_dynamic_config.py @@ -12,7 +12,7 @@ class TestDynamicConfig: def test_config_provider_defaults(self): provider = aerospike.ConfigProvider(path="path") - assert provider.interval == 60000 + assert provider.interval == 5000 def test_config_provider_class(self): provider = aerospike.ConfigProvider(path="path", interval=30000) diff --git a/test/new_tests/test_get_put.py b/test/new_tests/test_get_put.py index 628078a5bd..d8f48f7853 100644 --- a/test/new_tests/test_get_put.py +++ b/test/new_tests/test_get_put.py @@ -824,15 +824,12 @@ def test_edge_put_with_integer_greater_than_maxisze(self): key = ("test", "demo", 1) bins = {"no": 111111111111111111111111111111111111111111111} - - try: + + with pytest.raises(e.ParamError) as err_info: assert 0 == self.as_connection.put(key, bins) - except e.ParamError as exception: - assert exception.code == -2 - assert exception.msg == "integer value exceeds sys.maxsize" - except SystemError: - pass + assert err_info.value.code == -2 + assert err_info.value.msg == "integer value for as_val_new_from_pyobject exceeds LLONG_MAX" def test_edge_put_with_key_as_an_integer_greater_than_maxsize(self): """ @@ -842,9 +839,12 @@ def test_edge_put_with_key_as_an_integer_greater_than_maxsize(self): bins = {"no": 11} - with pytest.raises(e.ParamError): + with pytest.raises(e.ParamError) as err_info: assert 0 == self.as_connection.put(key, bins) + assert err_info.value.code == -2 + assert err_info.value.msg == "integer value for KEY exceeds LLONG_MAX" + def test_unhashable_type_with_put_get(self): """ Invoke put() with bytes which used to be read as bytearray off server diff --git a/test/new_tests/test_query_partition.py b/test/new_tests/test_query_partition.py index 05a5ffbe9a..8596494746 100644 --- a/test/new_tests/test_query_partition.py +++ b/test/new_tests/test_query_partition.py @@ -465,7 +465,7 @@ def callback(part_id, input_tuple): query_obj.foreach(callback, policy) err_code = err_info.value.code assert err_code == AerospikeStatus.AEROSPIKE_ERR_PARAM - assert "invalid partition_filter policy begin" in err_info.value.msg + assert "integer value for partition_filter.begin exceeds UINT16_MAX" in err_info.value.msg @pytest.mark.parametrize( "count", @@ -487,7 +487,7 @@ def callback(part_id, input_tuple): query_obj.foreach(callback, policy) err_code = err_info.value.code assert err_code == AerospikeStatus.AEROSPIKE_ERR_PARAM - assert "invalid partition_filter policy count" in err_info.value.msg + assert "integer value for partition_filter.count exceeds UINT16_MAX" in err_info.value.msg @pytest.mark.parametrize( "begin, count", diff --git a/test/new_tests/test_truncate.py b/test/new_tests/test_truncate.py index 40eeb283d4..5b7487f6bc 100644 --- a/test/new_tests/test_truncate.py +++ b/test/new_tests/test_truncate.py @@ -173,9 +173,13 @@ def test_nanos_argument_too_large(self): def test_nanos_argument_between_int64_and_uint64(self): # This may stop raising a client error in 2264 # as the value will no longer be in the future then - with pytest.raises(e.InvalidRequest): + with pytest.raises(e.ParamError) as err_info: self.as_connection.truncate("test", "truncate", 2**63 + 1) + assert err_info.value.code == -2 + assert err_info.value.msg == "integer value for truncate exceeds ULLONG_MAX" + + # TODO: this server's actual error message doesn't make sense to me def test_nanos_argument_between_int32_and_uint32(self): with pytest.raises(e.InvalidRequest):