Skip to content

Commit bf48daa

Browse files
committed
Version 1 of PDO_FETCH_LAZY
1 parent 126531a commit bf48daa

File tree

5 files changed

+219
-6
lines changed

5 files changed

+219
-6
lines changed

ext/pdo/pdo.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ PDO_API zend_class_entry *php_pdo_get_exception(void)
5151
return pdo_exception_ce;
5252
}
5353

54-
zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce;
54+
zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce, *pdo_row_ce;
5555

5656
/* {{{ pdo_functions[] */
5757
function_entry pdo_functions[] = {
@@ -258,6 +258,9 @@ PHP_MINIT_FUNCTION(pdo)
258258
ce.create_object = pdo_dbstmt_new;
259259
pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
260260

261+
INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
262+
ce.create_object = pdo_row_new;
263+
pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
261264

262265
return SUCCESS;
263266
}

ext/pdo/pdo_dbh.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ static PHP_METHOD(PDO, prepare)
242242
stmt->database_object_handle = *getThis();
243243
zend_objects_store_add_ref(getThis() TSRMLS_CC);
244244
stmt->dbh = dbh;
245+
246+
/* we haven't created a lazy object yet */
247+
ZVAL_NULL(&stmt->lazy_object_ref);
245248
return;
246249
}
247250
efree(stmt);

ext/pdo/pdo_stmt.c

Lines changed: 201 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@ static int describe_columns(pdo_stmt_t *stmt TSRMLS_DC)
163163
return 1;
164164
}
165165

166+
static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value TSRMLS_DC)
167+
{
168+
if (Z_TYPE(stmt->lazy_object_ref) == IS_NULL) {
169+
Z_TYPE(stmt->lazy_object_ref) = IS_OBJECT;
170+
Z_OBJ_HANDLE(stmt->lazy_object_ref) = zend_objects_store_put(stmt, NULL, pdo_row_free_storage, NULL TSRMLS_CC);
171+
Z_OBJ_HT(stmt->lazy_object_ref) = &pdo_row_object_handlers;
172+
}
173+
Z_TYPE_P(return_value) = IS_OBJECT;
174+
Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE(stmt->lazy_object_ref);
175+
Z_OBJ_HT_P(return_value) = Z_OBJ_HT(stmt->lazy_object_ref);
176+
}
177+
166178
static void param_dtor(void *data)
167179
{
168180
struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)data;
@@ -428,12 +440,15 @@ static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, enum pdo_
428440
if (return_value) {
429441
int i;
430442

443+
if (how == PDO_FETCH_LAZY) {
444+
get_lazy_object(stmt, return_value TSRMLS_CC);
445+
return 1;
446+
}
447+
431448
array_init(return_value);
432449

433450
if (how == PDO_FETCH_OBJ) {
434451
how = PDO_FETCH_ASSOC;
435-
} else if (how == PDO_FETCH_LAZY) {
436-
how = PDO_FETCH_BOTH;
437452
}
438453

439454
for (i = 0; i < stmt->column_count; i++) {
@@ -698,12 +713,12 @@ static int dbstmt_dim_exists(zval *object, zval *member, int check_empty TSRMLS_
698713

699714
static void dbstmt_prop_delete(zval *object, zval *offset TSRMLS_DC)
700715
{
701-
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDO STMT");
716+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDOStatement");
702717
}
703718

704719
static void dbstmt_dim_delete(zval *object, zval *offset TSRMLS_DC)
705720
{
706-
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete dimensions from a PDO STMT");
721+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete dimensions from a PDOStatement");
707722
}
708723

709724
static HashTable *dbstmt_get_properties(zval *object TSRMLS_DC)
@@ -793,10 +808,16 @@ void pdo_dbstmt_free_storage(zend_object *object TSRMLS_DC)
793808
if (stmt->methods && stmt->methods->dtor) {
794809
stmt->methods->dtor(stmt TSRMLS_CC);
795810
}
796-
if(stmt->query_string) {
811+
if (stmt->query_string) {
797812
efree(stmt->query_string);
798813
}
799814
zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
815+
#if 0
816+
/* declared in the header, but not implemented... */
817+
zend_objects_store_delete_obj(&stmt->lazy_object_ref TSRMLS_CC);
818+
#else
819+
zend_objects_store_del_ref(&stmt->lazy_object_ref TSRMLS_CC);
820+
#endif
800821

801822
efree(stmt);
802823
}
@@ -812,6 +833,181 @@ zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)
812833
}
813834
/* }}} */
814835

836+
/* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
837+
838+
function_entry pdo_row_functions[] = {
839+
{NULL, NULL, NULL}
840+
};
841+
842+
static zval *row_prop_or_dim_read(zval *object, zval *member, int type TSRMLS_DC)
843+
{
844+
zval *return_value;
845+
pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
846+
int colno = -1;
847+
848+
MAKE_STD_ZVAL(return_value);
849+
convert_to_string(member);
850+
851+
/* look up the column */
852+
/* TODO: replace this with a hash of available column names to column
853+
* numbers */
854+
for (colno = 0; colno < stmt->column_count; colno++) {
855+
if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
856+
fetch_value(stmt, return_value, colno TSRMLS_CC);
857+
break;
858+
}
859+
}
860+
861+
return return_value;
862+
}
863+
864+
static void row_prop_or_dim_write(zval *object, zval *member, zval *value TSRMLS_DC)
865+
{
866+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
867+
}
868+
869+
static int row_prop_or_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
870+
{
871+
pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
872+
int colno = -1;
873+
874+
convert_to_string(member);
875+
876+
/* TODO: replace this with a hash of available column names to column
877+
* numbers */
878+
for (colno = 0; colno < stmt->column_count; colno++) {
879+
if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
880+
return 1;
881+
}
882+
}
883+
884+
return 0;
885+
}
886+
887+
static void row_prop_or_dim_delete(zval *object, zval *offset TSRMLS_DC)
888+
{
889+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
890+
}
891+
892+
static HashTable *row_get_properties(zval *object TSRMLS_DC)
893+
{
894+
zval *tmp;
895+
pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
896+
int i;
897+
HashTable *ht;
898+
899+
MAKE_STD_ZVAL(tmp);
900+
array_init(tmp);
901+
902+
for (i = 0; i < stmt->column_count; i++) {
903+
zval *val;
904+
MAKE_STD_ZVAL(val);
905+
fetch_value(stmt, val, i TSRMLS_CC);
906+
907+
add_assoc_zval(tmp, stmt->columns[i].name, val);
908+
}
909+
910+
ht = Z_ARRVAL_P(tmp);
911+
912+
ZVAL_NULL(tmp);
913+
FREE_ZVAL(tmp);
914+
915+
return ht;
916+
}
917+
918+
static union _zend_function *row_method_get(zval *object, char *method_name, int method_len TSRMLS_DC)
919+
{
920+
zend_function *fbc;
921+
char *lc_method_name;
922+
923+
lc_method_name = do_alloca(method_len + 1);
924+
zend_str_tolower_copy(lc_method_name, method_name, method_len);
925+
926+
if (zend_hash_find(&pdo_row_ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
927+
free_alloca(lc_method_name);
928+
return NULL;
929+
}
930+
931+
free_alloca(lc_method_name);
932+
return fbc;
933+
}
934+
935+
static int row_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
936+
{
937+
return FAILURE;
938+
}
939+
940+
static union _zend_function *row_get_ctor(zval *object TSRMLS_DC)
941+
{
942+
static zend_internal_function ctor = {0};
943+
944+
ctor.type = ZEND_INTERNAL_FUNCTION;
945+
ctor.function_name = "__construct";
946+
ctor.scope = pdo_row_ce;
947+
ctor.handler = ZEND_FN(dbstmt_constructor);
948+
949+
return (union _zend_function*)&ctor;
950+
}
951+
952+
static zend_class_entry *row_get_ce(zval *object TSRMLS_DC)
953+
{
954+
return pdo_dbstmt_ce;
955+
}
956+
957+
static int row_get_classname(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
958+
{
959+
*class_name = estrndup("PDORow", sizeof("PDORow")-1);
960+
*class_name_len = sizeof("PDORow")-1;
961+
return 0;
962+
}
963+
964+
static int row_compare(zval *object1, zval *object2 TSRMLS_DC)
965+
{
966+
return -1;
967+
}
968+
969+
zend_object_handlers pdo_row_object_handlers = {
970+
ZEND_OBJECTS_STORE_HANDLERS,
971+
row_prop_or_dim_read,
972+
row_prop_or_dim_write,
973+
row_prop_or_dim_read,
974+
row_prop_or_dim_write,
975+
NULL,
976+
NULL,
977+
NULL,
978+
row_prop_or_dim_exists,
979+
row_prop_or_dim_delete,
980+
row_prop_or_dim_exists,
981+
row_prop_or_dim_delete,
982+
row_get_properties,
983+
row_method_get,
984+
row_call_method,
985+
row_get_ctor,
986+
row_get_ce,
987+
row_get_classname,
988+
row_compare,
989+
NULL, /* cast */
990+
NULL
991+
};
992+
993+
void pdo_row_free_storage(zend_object *object TSRMLS_DC)
994+
{
995+
pdo_stmt_t *stmt = (pdo_stmt_t*)object;
996+
997+
/* nothing to do here */
998+
}
999+
1000+
zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC)
1001+
{
1002+
zend_object_value retval;
1003+
1004+
retval.handle = zend_objects_store_put(NULL, NULL, pdo_row_free_storage, NULL TSRMLS_CC);
1005+
retval.handlers = &pdo_row_object_handlers;
1006+
1007+
return retval;
1008+
}
1009+
/* }}} */
1010+
8151011
/*
8161012
* Local variables:
8171013
* tab-width: 4

ext/pdo/php_pdo_driver.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ struct _pdo_stmt_t {
352352

353353
/* the cursor specific error code. */
354354
enum pdo_error_type error_code;
355+
356+
/* for lazy fetches, we always return the same lazy object handle.
357+
* Let's keep it here. */
358+
zval lazy_object_ref;
355359
};
356360

357361
/* call this in MINIT to register your PDO driver */

ext/pdo/php_pdo_int.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ extern zend_class_entry *pdo_dbstmt_ce;
3434
void pdo_dbstmt_free_storage(zend_object *object TSRMLS_DC);
3535
extern zend_object_handlers pdo_dbstmt_object_handlers;
3636

37+
extern zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC);
38+
extern function_entry pdo_row_functions[];
39+
extern zend_class_entry *pdo_row_ce;
40+
void pdo_row_free_storage(zend_object *object TSRMLS_DC);
41+
extern zend_object_handlers pdo_row_object_handlers;
42+
43+
3744
extern pdo_driver_t *pdo_find_driver(const char *name, int namelen);
3845

3946
extern void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC);

0 commit comments

Comments
 (0)