@@ -924,6 +924,40 @@ inline void tl_debug(const char *s __attribute__((unused)), int n __attribute__(
924924
925925/* {{{ Interface functions */
926926
927+ // returns 0 if no typedStore was found, otherwise returns allocated ZVAL with fetcher instance
928+ bool store_function2 (VK_ZVAL_API_P arr, zval *fetcher) {
929+ ADD_CNT (store_function2)
930+ START_TIMER (store_function2)
931+ assert (arr);
932+ if (Z_TYPE_P (arr) != IS_OBJECT) {
933+ END_TIMER (store_function2)
934+ return false ;
935+ }
936+ vk_zend_call_known_instance_method (arr, " typedStore" , strlen (" typedStore" ), fetcher, 0 , NULL );
937+ if (EG (exception)) {
938+ // This behavior is consistent with old code, in this case, query_one will return qid 0
939+ fprintf (stderr, " typedStore exception\n " );
940+ _zend_object* old_exception = EG (exception);
941+ EG (exception) = NULL ;
942+ OBJ_RELEASE (old_exception);
943+ END_TIMER (store_function2)
944+ return false ;
945+ }
946+ if (Z_TYPE_P (fetcher) != IS_OBJECT) {
947+ // returned null or function not found (undef) or function returned something unexpected
948+ if (Z_TYPE_P (fetcher) != IS_NULL) {
949+ fprintf (stderr, " typedStore fetcher unexpected type is %d\n " , Z_TYPE_P (fetcher));
950+ }
951+ END_TIMER (store_function2)
952+ return false ;
953+ }
954+ fprintf (stderr, " typedStore user-defined success\n " );
955+ // when using fetcher, tl_current_function_name will not be accessed. But we set it anyway in case we forgot something.
956+ tl_current_function_name = " typedStore" ;
957+ END_TIMER (store_function2)
958+ return false ;
959+ }
960+
927961struct tl_tree *store_function (VK_ZVAL_API_P arr) {
928962 ADD_CNT (store_function)
929963 START_TIMER (store_function)
@@ -1103,6 +1137,29 @@ void _extra_dec_ref(struct rpc_query *q) {
11031137struct rpc_query *vk_rpc_tl_query_one_impl (struct rpc_connection *c, double timeout, VK_ZVAL_API_P arr, int ignore_answer) {
11041138 do_rpc_clean ();
11051139 START_TIMER (tmp);
1140+ zval fetcher;
1141+ ZVAL_NULL (&fetcher);
1142+ bool fetcher_found = store_function2 (arr, &fetcher);
1143+ END_TIMER (tmp);
1144+ if (fetcher_found) {
1145+ struct rpc_query *q;
1146+ if (!(q = do_rpc_send_noflush (c, timeout, ignore_answer))) {
1147+ zval_ptr_dtor (&fetcher);
1148+ vkext_error (VKEXT_ERROR_NETWORK, " Can't send packet" );
1149+ return 0 ;
1150+ }
1151+ if (q == (struct rpc_query *)1 ) { // answer is ignored
1152+ assert (ignore_answer);
1153+ zval_ptr_dtor (&fetcher);
1154+ return q;
1155+ }
1156+ assert (!ignore_answer);
1157+ ZVAL_COPY_VALUE (&q->fetcher , &fetcher);
1158+ q->extra_free = _extra_dec_ref;
1159+ total_tl_working++;
1160+ return q;
1161+ }
1162+ START_TIMER (tmp);
11061163 void *res = store_function (arr);
11071164 END_TIMER (tmp);
11081165 if (!res) {
0 commit comments