add cursor support
[m6w6/ext-pq] / src / php_pq_callback.c
index 1a4a91731f166eefe6cbf96a6f3c5f1583e2cde1..63f2edc4bab570523b133bcf027c1a4bb94e9b95 100644 (file)
 #endif
 
 #include <php.h>
+#include <Zend/zend_closures.h>
 
 #include "php_pq_callback.h"
 
 void php_pq_callback_dtor(php_pq_callback_t *cb)
 {
+       if (cb->recursion) {
+               php_pq_callback_dtor(cb->recursion);
+               efree(cb->recursion);
+               cb->recursion = NULL;
+       }
        if (cb->fci.size > 0) {
                zend_fcall_info_args_clear(&cb->fci, 1);
                zval_ptr_dtor(&cb->fci.function_name);
                if (cb->fci.object_ptr) {
                        zval_ptr_dtor(&cb->fci.object_ptr);
                }
+               cb->fci.size = 0;
        }
-       cb->fci.size = 0;
 }
 
 void php_pq_callback_addref(php_pq_callback_t *cb)
@@ -55,6 +61,41 @@ zval *php_pq_callback_to_zval(php_pq_callback_t *cb)
 
        return zcb;
 }
+
+zend_bool php_pq_callback_is_locked(php_pq_callback_t *cb TSRMLS_DC)
+{
+       if (cb->fci.size > 0 && Z_TYPE_P(cb->fci.function_name) == IS_OBJECT) {
+               const zend_function *closure = zend_get_closure_method_def(cb->fci.function_name TSRMLS_CC);
+
+               if (closure->type == ZEND_USER_FUNCTION) {
+                       zend_execute_data *ex = EG(current_execute_data);
+
+                       while (ex) {
+                               if (ex->op_array == &closure->op_array) {
+                                       return 1;
+                               }
+                               ex = ex->prev_execute_data;
+                       }
+               }
+       }
+       return 0;
+}
+
+void php_pq_callback_recurse(php_pq_callback_t *old, php_pq_callback_t *new TSRMLS_DC)
+{
+       if (new && new->fci.size > 0 && php_pq_callback_is_locked(old TSRMLS_CC)) {
+               new->recursion = emalloc(sizeof(*old));
+               memcpy(new->recursion, old, sizeof(*old));
+       } else if (new && new->fci.size > 0) {
+               php_pq_callback_dtor(old);
+               php_pq_callback_addref(new);
+               memcpy(old, new, sizeof(*old));
+               new->fci.size = 0;
+       } else {
+               php_pq_callback_dtor(old);
+       }
+}
+
 /*
  * Local variables:
  * tab-width: 4