Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpredis/phpredis.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormichael-grunder <michael-grunder@github.com>2012-05-10 04:48:11 +0400
committermichael-grunder <michael-grunder@github.com>2012-05-10 04:48:11 +0400
commit9c9c63fb46ad6129d09a70c08dcd18d830f039d9 (patch)
treec08f87f2e4b6fd938b09e7f6e68670a75389a0ab /library.c
parentb61ae6ab45fbb0153ec1601059e8fca97e31455a (diff)
Initial commit of EVAL and EVALSHA
Diffstat (limited to 'library.c')
-rw-r--r--library.c276
1 files changed, 274 insertions, 2 deletions
diff --git a/library.c b/library.c
index 930244a9..3bfee32d 100644
--- a/library.c
+++ b/library.c
@@ -222,6 +222,30 @@ integer_length(int i) {
}
int
+redis_cmd_format_header(char **ret, char *keyword, int arg_count) {
+ // Our return buffer
+ smart_str buf = {0};
+
+ // Keyword length
+ int l = strlen(keyword);
+
+ smart_str_appendc(&buf, '*');
+ smart_str_append_long(&buf, arg_count + 1);
+ smart_str_appendl(&buf, _NL, sizeof(_NL) -1);
+ smart_str_appendc(&buf, '$');
+ smart_str_append_long(&buf, l);
+ smart_str_appendl(&buf, _NL, sizeof(_NL) -1);
+ smart_str_appendl(&buf, keyword, l);
+ smart_str_appendl(&buf, _NL, sizeof(_NL) - 1);
+
+ // Set our return pointer
+ *ret = buf.c;
+
+ // Return the length
+ return buf.len;
+}
+
+int
redis_cmd_format_static(char **ret, char *keyword, char *format, ...) {
char *p = format;
@@ -302,7 +326,7 @@ redis_cmd_format_static(char **ret, char *keyword, char *format, ...) {
/**
* This command behave somehow like printf, except that strings need 2 arguments:
* Their data and their size (strlen).
- * Supported formats are: %d, %i, %s
+ * Supported formats are: %d, %i, %s, %l
*/
int
redis_cmd_format(char **ret, char *format, ...) {
@@ -360,6 +384,46 @@ redis_cmd_format(char **ret, char *format, ...) {
return buf.len;
}
+/*
+ * Append a command sequence to a Redis command
+ */
+int redis_cmd_append_str(char **cmd, int cmd_len, char *append, int append_len) {
+ // Smart string buffer
+ smart_str buf = {0};
+
+ // Append the current command to our smart_str
+ smart_str_appendl(&buf, *cmd, cmd_len);
+
+ // Append our new command sequence
+ smart_str_appendc(&buf, '$');
+ smart_str_append_long(&buf, append_len);
+ smart_str_appendl(&buf, _NL, sizeof(_NL) -1);
+ smart_str_appendl(&buf, append, append_len);
+ smart_str_appendl(&buf, _NL, sizeof(_NL) -1);
+
+ // Free our old command
+ efree(*cmd);
+
+ // Set our return pointer
+ *cmd = buf.c;
+
+ // Return new command length
+ return buf.len;
+}
+
+/*
+ * Append an integer command to a Redis command
+ */
+int redis_cmd_append_int(char **cmd, int cmd_len, int append) {
+ char int_buf[32];
+
+ // Conver to an int, capture length
+ int int_len = snprintf(int_buf, sizeof(int_buf), "%d", append);
+
+ // Return the new length
+ return redis_cmd_append_str(cmd, cmd_len, int_buf, int_len);
+}
+
PHPAPI void redis_bulk_double_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
char *response;
@@ -595,7 +659,6 @@ PHPAPI int redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PA
if(php_stream_gets(redis_sock->stream, inbuf, 1024) == NULL) {
redis_stream_close(redis_sock TSRMLS_CC);
redis_sock->stream = NULL;
- redis_sock->stream = NULL;
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
redis_sock->mode = ATOMIC;
redis_sock->watching = 0;
@@ -1242,5 +1305,214 @@ redis_key_prefix(RedisSock *redis_sock, char **key, int *key_len TSRMLS_DC) {
return 1;
}
+/*
+ * Processing for variant reply types (think EVAL)
+ */
+
+PHPAPI int
+redis_sock_gets(RedisSock *redis_sock, char *buf, int buf_size, int *line_size) {
+ // Handle EOF
+ if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) {
+ return -1;
+ }
+
+ if(php_stream_get_line(redis_sock->stream, buf, buf_size, line_size) == NULL) {
+ // Close, put our socket state into error
+ redis_stream_close(redis_sock TSRMLS_CC);
+ redis_sock->stream = NULL;
+ redis_sock->status = REDIS_SOCK_STATUS_FAILED;
+ redis_sock->mode = ATOMIC;
+ redis_sock->watching = 0;
+
+ // Throw a read error exception
+ zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
+ }
+
+ // Success!
+ return 0;
+}
+
+PHPAPI int
+redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, int *reply_info) {
+ // Make sure we haven't lost the connection, even trying to reconnect
+ if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) {
+ // Failure
+ return -1;
+ }
+
+ // Attempt to read the reply-type byte
+ if((*reply_type = php_stream_getc(redis_sock->stream)) == EOF) {
+ zend_throw_exception(redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC);
+ }
+
+ // If this is a BULK, MULTI BULK, or simply an INTEGER response, we can extract the value or size info here
+ if(*reply_type == TYPE_INT || *reply_type == TYPE_BULK || *reply_type == TYPE_MULTIBULK) {
+ // Buffer to hold size information
+ char inbuf[255];
+
+ // Read up to our newline
+ if(php_stream_gets(redis_sock->stream, inbuf, sizeof(inbuf)) < 0) {
+ return -1;
+ }
+
+ // Set our size response
+ *reply_info = atoi(inbuf);
+ }
+
+ // Success!
+ return 0;
+}
+
+/*
+ * Read a single line response, having already consumed the reply-type byte
+ */
+PHPAPI int
+redis_read_variant_line(RedisSock *redis_sock, REDIS_REPLY_TYPE reply_type, zval **z_ret) {
+ // Buffer to read our single line reply
+ char inbuf[1024];
+ int line_size;
+
+ // Attempt to read our single line reply
+ if(redis_sock_gets(redis_sock, inbuf, sizeof(inbuf), &line_size) < 0) {
+ return -1;
+ }
+
+ // If this is an error response, check if it is a SYNC error, and throw in that case
+ if(reply_type == TYPE_ERR) {
+ if(memcmp(inbuf, "ERR SYNC", 9) == 0) {
+ zend_throw_exception(redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC);
+ }
+
+ // Set our response to FALSE
+ ZVAL_FALSE(*z_ret);
+ } else {
+ // Set our response to TRUE
+ ZVAL_TRUE(*z_ret);
+ //ZVAL_STRINGL(*z_ret, inbuf, line_size, 1);
+ }
+
+ return 0;
+}
+
+PHPAPI int
+redis_read_variant_bulk(RedisSock *redis_sock, int size, zval **z_ret) {
+ // Attempt to read the bulk reply
+ char *bulk_resp = redis_sock_read_bulk_reply(redis_sock, size);
+
+ // Set our reply to FALSE on failure, and the string on success
+ if(bulk_resp == NULL) {
+ ZVAL_FALSE(*z_ret);
+ return -1;
+ } else {
+ ZVAL_STRINGL(*z_ret, bulk_resp, size, 0);
+ return 0;
+ }
+}
+
+PHPAPI int
+redis_read_multibulk_recursive(RedisSock *redis_sock, int elements, zval **z_ret) {
+ int reply_info;
+ REDIS_REPLY_TYPE reply_type;
+ zval *z_subelem;
+
+ // Iterate while we have elements
+ while(elements > 0) {
+ // Attempt to read our reply type
+ if(redis_read_reply_type(redis_sock, &reply_type, &reply_info) < 0) {
+ zend_throw_exception_ex(redis_exception_ce, 0 TSRMLS_CC, "protocol error, couldn't parse MULTI-BULK response\n", reply_type);
+ return -1;
+ }
+
+ // Switch on our reply-type byte
+ switch(reply_type) {
+ case TYPE_ERR:
+ case TYPE_LINE:
+ ALLOC_INIT_ZVAL(z_subelem);
+ redis_read_variant_line(redis_sock, reply_type, &z_subelem);
+ add_next_index_zval(*z_ret, z_subelem);
+ break;
+ case TYPE_INT:
+ // Add our long value
+ add_next_index_long(*z_ret, reply_info);
+ break;
+ case TYPE_BULK:
+ // Init a zval for our bulk response, read and add it
+ ALLOC_INIT_ZVAL(z_subelem);
+ redis_read_variant_bulk(redis_sock, reply_info, &z_subelem);
+ add_next_index_zval(*z_ret, z_subelem);
+ break;
+ case TYPE_MULTIBULK:
+ // Construct an array for our sub element, and add it, and recurse
+ ALLOC_INIT_ZVAL(z_subelem);
+ array_init(z_subelem);
+ add_next_index_zval(*z_ret, z_subelem);
+ redis_read_multibulk_recursive(redis_sock, reply_info, &z_subelem);
+ break;
+ }
+
+ // Decrement our element counter
+ elements--;
+ }
+
+ return 0;
+}
+
+PHPAPI int
+redis_read_variant_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab) {
+ // Reply type, and reply size vars
+ REDIS_REPLY_TYPE reply_type;
+ int reply_info;
+ //char *bulk_resp;
+ zval *z_ret;
+
+ // Attempt to read our header
+ if(redis_read_reply_type(redis_sock, &reply_type, &reply_info) < 0) {
+ return -1;
+ }
+
+ // Our return ZVAL
+ MAKE_STD_ZVAL(z_ret);
+
+ // Switch based on our top level reply type
+ switch(reply_type) {
+ case TYPE_ERR:
+ case TYPE_LINE:
+ redis_read_variant_line(redis_sock, reply_type, &z_ret);
+ break;
+ case TYPE_INT:
+ ZVAL_LONG(z_ret, reply_info);
+ break;
+ case TYPE_BULK:
+ redis_read_variant_bulk(redis_sock, reply_info, &z_ret);
+ break;
+ case TYPE_MULTIBULK:
+ // Initialize an array for our multi-bulk response
+ array_init(z_ret);
+
+ // If we've got more than zero elements, parse our multi bulk respoinse recursively
+ if(reply_info > -1) {
+ redis_read_multibulk_recursive(redis_sock, reply_info, &z_ret);
+ }
+ break;
+ default:
+ // Protocol error
+ zend_throw_exception_ex(redis_exception_ce, 0 TSRMLS_CC, "protocol error, got '%c' as reply-type byte\n", reply_type);
+ break;
+ }
+
+ IF_MULTI_OR_PIPELINE() {
+ add_next_index_zval(z_tab, z_ret);
+ } else {
+ // Set our return value
+ *return_value = *z_ret;
+ zval_copy_ctor(return_value);
+ zval_dtor(z_ret);
+ efree(z_ret);
+ }
+
+ // Success
+ return 0;
+}
+
/* vim: set tabstop=4 softtabstop=4 noexpandtab shiftwidth=4: */