diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 94c2a9c14652d..901f0dd75d9c1 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -56,3 +56,8 @@ PHP 8.1 INTERNALS UPGRADE NOTES of returning a boolean, and the quoted string as a pair of out params. Similarly the unquoted string is now a zend_string* instead of a pair of char* and size_t length. + - The doer handler now accepts a zend_string* instead of char* + size_t + pair for the SQL statement. + - The last_id handler now returns a zend_string* instead of returning a + char* and the lengths as an out param, and accepts a zend_string* instead + of char* for the optional sequence/table name. diff --git a/ext/pdo/pdo.c b/ext/pdo/pdo.c index a66596ee54472..d0e77c703b180 100644 --- a/ext/pdo/pdo.c +++ b/ext/pdo/pdo.c @@ -248,8 +248,9 @@ PDO_API int php_pdo_parse_data_source(const char *data_source, zend_ulong data_s } /* }}} */ +/* TODO Refactor */ static const char digit_vec[] = "0123456789"; -PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64) /* {{{ */ +PDO_API zend_string *php_pdo_int64_to_str(pdo_int64_t i64) /* {{{ */ { char buffer[65]; char outbuf[65] = ""; @@ -257,17 +258,15 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64) /* {{{ */ zend_long long_val; char *dst = outbuf; + if (i64 == 0) { + return ZSTR_CHAR('0');; + } + if (i64 < 0) { i64 = -i64; *dst++ = '-'; } - if (i64 == 0) { - *dst++ = '0'; - *dst++ = '\0'; - return estrdup(outbuf); - } - p = &buffer[sizeof(buffer)-1]; *p = '\0'; @@ -286,7 +285,7 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64) /* {{{ */ while ((*dst++ = *p++) != 0) ; *dst = '\0'; - return estrdup(outbuf); + return zend_string_init(outbuf, strlen(outbuf), 0); } /* }}} */ diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index e5159bd64d0da..c1b3495a1b30f 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -913,23 +913,22 @@ PHP_METHOD(PDO, getAttribute) PHP_METHOD(PDO, exec) { pdo_dbh_t *dbh = Z_PDO_DBH_P(ZEND_THIS); - char *statement; - size_t statement_len; + zend_string *statement; zend_long ret; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STRING(statement, statement_len) + Z_PARAM_STR(statement) ZEND_PARSE_PARAMETERS_END(); - if (statement_len == 0) { + if (ZSTR_LEN(statement) == 0) { zend_argument_value_error(1, "cannot be empty"); RETURN_THROWS(); } PDO_DBH_CLEAR_ERR(); PDO_CONSTRUCT_CHECK; - ret = dbh->methods->doer(dbh, statement, statement_len); - if(ret == -1) { + ret = dbh->methods->doer(dbh, statement); + if (ret == -1) { PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } else { @@ -942,12 +941,12 @@ PHP_METHOD(PDO, exec) PHP_METHOD(PDO, lastInsertId) { pdo_dbh_t *dbh = Z_PDO_DBH_P(ZEND_THIS); - char *name = NULL; - size_t namelen; + zend_string *name = NULL; + zend_string *last_id = NULL; ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL - Z_PARAM_STRING_OR_NULL(name, namelen) + Z_PARAM_STR_OR_NULL(name) ZEND_PARSE_PARAMETERS_END(); PDO_CONSTRUCT_CHECK; @@ -957,19 +956,13 @@ PHP_METHOD(PDO, lastInsertId) if (!dbh->methods->last_id) { pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support lastInsertId()"); RETURN_FALSE; - } else { - size_t id_len; - char *id; - id = dbh->methods->last_id(dbh, name, &id_len); - if (!id) { - PDO_HANDLE_DBH_ERR(); - RETURN_FALSE; - } else { - //??? use zend_string ? - RETVAL_STRINGL(id, id_len); - efree(id); - } } + last_id = dbh->methods->last_id(dbh, name); + if (!last_id) { + PDO_HANDLE_DBH_ERR(); + RETURN_FALSE; + } + RETURN_STR(last_id); } /* }}} */ diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index e31ea7ed1d719..775ffd240f946 100644 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -33,7 +33,7 @@ typedef unsigned __int64 pdo_uint64_t; typedef long long int pdo_int64_t; typedef unsigned long long int pdo_uint64_t; #endif -PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64); +PDO_API zend_string *php_pdo_int64_to_str(pdo_int64_t i64); #ifndef TRUE # define TRUE 1 @@ -232,8 +232,9 @@ typedef void (*pdo_dbh_close_func)(pdo_dbh_t *dbh); * return true on success, false otherwise */ typedef bool (*pdo_dbh_prepare_func)(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *stmt, zval *driver_options); -/* execute a statement (that does not return a result set) */ -typedef zend_long (*pdo_dbh_do_func)(pdo_dbh_t *dbh, const char *sql, size_t sql_len); +/* execute a statement (that does not return a result set) + * Return -1 on failure, otherwise the number of affected rows */ +typedef zend_long (*pdo_dbh_do_func)(pdo_dbh_t *dbh, const zend_string *sql); /* quote a string */ typedef zend_string* (*pdo_dbh_quote_func)(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype); @@ -246,9 +247,9 @@ typedef bool (*pdo_dbh_txn_func)(pdo_dbh_t *dbh); * Return true on success and false in case of failure */ typedef bool (*pdo_dbh_set_attr_func)(pdo_dbh_t *dbh, zend_long attr, zval *val); -/* return last insert id. NULL indicates error condition, otherwise, the return value - * MUST be an emalloc'd NULL terminated string. */ -typedef char *(*pdo_dbh_last_id_func)(pdo_dbh_t *dbh, const char *name, size_t *len); +/* return last insert id. NULL indicates error condition. + * name MIGHT be NULL */ +typedef zend_string *(*pdo_dbh_last_id_func)(pdo_dbh_t *dbh, const zend_string *name); /* Fetch error information. * If stmt is not null, fetch information pertaining to the statement, diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index 824e055565d64..ae45da6beb425 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -106,14 +106,14 @@ static bool dblib_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t * return true; } -static zend_long dblib_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_len) +static zend_long dblib_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) { pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; RETCODE ret, resret; dbsetuserdata(H->link, (BYTE*)&H->err); - if (FAIL == dbcmd(H->link, sql)) { + if (FAIL == dbcmd(H->link, ZSTR_VAL(sql))) { return -1; } @@ -222,12 +222,14 @@ static bool dblib_handle_rollback(pdo_dbh_t *dbh) return pdo_dblib_transaction_cmd("ROLLBACK TRANSACTION", dbh); } -char *dblib_handle_last_id(pdo_dbh_t *dbh, const char *name, size_t *len) +zend_string *dblib_handle_last_id(pdo_dbh_t *dbh, const zend_string *name) { pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; RETCODE ret; char *id = NULL; + size_t len; + zend_string *ret_id; /* * Would use scope_identity() but it's not implemented on Sybase @@ -260,10 +262,12 @@ char *dblib_handle_last_id(pdo_dbh_t *dbh, const char *name, size_t *len) } id = emalloc(32); - *len = dbconvert(NULL, (dbcoltype(H->link, 1)) , (dbdata(H->link, 1)) , (dbdatlen(H->link, 1)), SQLCHAR, (BYTE *)id, (DBINT)-1); - + len = dbconvert(NULL, (dbcoltype(H->link, 1)) , (dbdata(H->link, 1)) , (dbdatlen(H->link, 1)), SQLCHAR, (BYTE *)id, (DBINT)-1); dbcancel(H->link); - return id; + + ret_id = zend_string_init(id, len, 0); + efree(id); + return ret_id; } static bool dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val) diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 02c6dfc4eec24..338aa88ec95e8 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -29,7 +29,7 @@ #include "php_pdo_firebird.h" #include "php_pdo_firebird_int.h" -static int firebird_alloc_prepare_stmt(pdo_dbh_t*, const char*, size_t, XSQLDA*, isc_stmt_handle*, +static int firebird_alloc_prepare_stmt(pdo_dbh_t*, const zend_string*, XSQLDA*, isc_stmt_handle*, HashTable*); const char CHR_LETTER = 1; @@ -291,13 +291,13 @@ static FbTokenType getToken(const char** begin, const char* end) return ret; } -int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_params) +int preprocess(const zend_string* sql, char* sql_out, HashTable* named_params) { bool passAsIs = 1, execBlock = 0; zend_long pindex = -1; char pname[254], ident[253], ident2[253]; unsigned int l; - const char* p = sql, * end = sql + sql_len; + const char* p = ZSTR_VAL(sql), * end = ZSTR_VAL(sql) + ZSTR_LEN(sql); const char* start = p; FbTokenType tok = getToken(&p, end); @@ -363,7 +363,7 @@ int preprocess(const char* sql, int sql_len, char* sql_out, HashTable* named_par if (passAsIs) { - strcpy(sql_out, sql); + strcpy(sql_out, ZSTR_VAL(sql)); return 1; } @@ -522,7 +522,7 @@ static bool firebird_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, /* {{{ */ zend_hash_init(np, 8, NULL, NULL, 0); /* allocate and prepare statement */ - if (!firebird_alloc_prepare_stmt(dbh, ZSTR_VAL(sql), ZSTR_LEN(sql), &num_sqlda, &s, np)) { + if (!firebird_alloc_prepare_stmt(dbh, sql, &num_sqlda, &s, np)) { break; } @@ -587,7 +587,7 @@ static bool firebird_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, /* {{{ */ /* }}} */ /* called by PDO to execute a statement that doesn't produce a result set */ -static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_len) /* {{{ */ +static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) /* {{{ */ { pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; isc_stmt_handle stmt = PDO_FIREBIRD_HANDLE_INITIALIZER; @@ -602,7 +602,7 @@ static zend_long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sq out_sqlda.sqln = 1; /* allocate and prepare statement */ - if (!firebird_alloc_prepare_stmt(dbh, sql, sql_len, &out_sqlda, &stmt, 0)) { + if (!firebird_alloc_prepare_stmt(dbh, sql, &out_sqlda, &stmt, 0)) { return -1; } @@ -767,14 +767,14 @@ static bool firebird_handle_rollback(pdo_dbh_t *dbh) /* {{{ */ /* }}} */ /* used by prepare and exec to allocate a statement handle and prepare the SQL */ -static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const char *sql, size_t sql_len, /* {{{ */ +static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const zend_string *sql, XSQLDA *out_sqlda, isc_stmt_handle *s, HashTable *named_params) { pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; char *new_sql; /* Firebird allows SQL statements up to 64k, so bail if it doesn't fit */ - if (sql_len > 65536) { + if (ZSTR_LEN(sql) > 65536) { strcpy(dbh->error_code, "01004"); return 0; } @@ -797,9 +797,9 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const char *sql, size_t s /* in order to support named params, which Firebird itself doesn't, we need to replace :foo by ?, and store the name we just replaced */ - new_sql = emalloc(sql_len+1); + new_sql = emalloc(ZSTR_LEN(sql)+1); new_sql[0] = '\0'; - if (!preprocess(sql, sql_len, new_sql, named_params)) { + if (!preprocess(sql, new_sql, named_params)) { strcpy(dbh->error_code, "07000"); efree(new_sql); return 0; @@ -815,7 +815,6 @@ static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const char *sql, size_t s efree(new_sql); return 1; } -/* }}} */ /* called by PDO to set a driver-specific dbh attribute */ static bool firebird_handle_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val) /* {{{ */ diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c index ad27937febb5c..6b42335878da8 100644 --- a/ext/pdo_mysql/mysql_driver.c +++ b/ext/pdo_mysql/mysql_driver.c @@ -249,14 +249,14 @@ static bool mysql_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t * /* }}} */ /* {{{ mysql_handle_doer */ -static zend_long mysql_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_len) +static zend_long mysql_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) { pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data; PDO_DBG_ENTER("mysql_handle_doer"); PDO_DBG_INF_FMT("dbh=%p", dbh); - PDO_DBG_INF_FMT("sql=%.*s", (int)sql_len, sql); + PDO_DBG_INF_FMT("sql=%.*s", (int)ZSTR_LEN(sql), ZSTR_VAL(sql)); - if (mysql_real_query(H->server, sql, sql_len)) { + if (mysql_real_query(H->server, ZSTR_VAL(sql), ZSTR_LEN(sql))) { pdo_mysql_error(dbh); PDO_DBG_RETURN(-1); } else { @@ -285,13 +285,11 @@ static zend_long mysql_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_l /* }}} */ /* {{{ pdo_mysql_last_insert_id */ -static char *pdo_mysql_last_insert_id(pdo_dbh_t *dbh, const char *name, size_t *len) +static zend_string *pdo_mysql_last_insert_id(pdo_dbh_t *dbh, const zend_string *name) { pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data; - char *id = php_pdo_int64_to_str(mysql_insert_id(H->server)); PDO_DBG_ENTER("pdo_mysql_last_insert_id"); - *len = strlen(id); - PDO_DBG_RETURN(id); + PDO_DBG_RETURN(php_pdo_int64_to_str(mysql_insert_id(H->server))); } /* }}} */ @@ -348,9 +346,16 @@ static zend_string* mysql_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo /* {{{ mysql_handle_begin */ static bool mysql_handle_begin(pdo_dbh_t *dbh) { + zend_long return_value; + zend_string *command; + PDO_DBG_ENTER("mysql_handle_quoter"); PDO_DBG_INF_FMT("dbh=%p", dbh); - PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("START TRANSACTION"))); + + command = zend_string_init("START TRANSACTION", strlen("START TRANSACTION"), 0); + return_value = mysql_handle_doer(dbh, command); + zend_string_release_ex(command, 0); + PDO_DBG_RETURN(0 <= return_value); } /* }}} */ diff --git a/ext/pdo_oci/oci_driver.c b/ext/pdo_oci/oci_driver.c index 68a52051f6921..dd4a7bb171318 100644 --- a/ext/pdo_oci/oci_driver.c +++ b/ext/pdo_oci/oci_driver.c @@ -306,7 +306,7 @@ static bool oci_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *st } /* }}} */ -static zend_long oci_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_len) /* {{{ */ +static zend_long oci_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) /* {{{ */ { pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data; OCIStmt *stmt; @@ -316,7 +316,7 @@ static zend_long oci_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_len OCIHandleAlloc(H->env, (dvoid*)&stmt, OCI_HTYPE_STMT, 0, NULL); - H->last_err = OCIStmtPrepare(stmt, H->err, (text*)sql, (ub4) sql_len, OCI_NTV_SYNTAX, OCI_DEFAULT); + H->last_err = OCIStmtPrepare(stmt, H->err, (text*)ZSTR_VAL(sql), (ub4) ZSTR_LEN(sql), OCI_NTV_SYNTAX, OCI_DEFAULT); if (H->last_err) { H->last_err = oci_drv_error("OCIStmtPrepare"); OCIHandleFree(stmt, OCI_HTYPE_STMT); @@ -696,7 +696,7 @@ static const struct pdo_dbh_methods oci_methods = { oci_handle_commit, oci_handle_rollback, oci_handle_set_attribute, - NULL, + NULL, /* last_id not supported */ pdo_oci_fetch_error_func, oci_handle_get_attribute, pdo_oci_check_liveness, /* check_liveness */ diff --git a/ext/pdo_odbc/odbc_driver.c b/ext/pdo_odbc/odbc_driver.c index d2e40d5de592c..719aa36219a29 100644 --- a/ext/pdo_odbc/odbc_driver.c +++ b/ext/pdo_odbc/odbc_driver.c @@ -212,7 +212,7 @@ static bool odbc_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *s return true; } -static zend_long odbc_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_len) +static zend_long odbc_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) { pdo_odbc_db_handle *H = (pdo_odbc_db_handle *)dbh->driver_data; RETCODE rc; @@ -225,7 +225,7 @@ static zend_long odbc_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_le return -1; } - rc = SQLExecDirect(stmt, (SQLCHAR *) sql, sql_len); + rc = SQLExecDirect(stmt, (SQLCHAR *) ZSTR_VAL(sql), ZSTR_LEN(sql)); if (rc == SQL_NO_DATA) { /* If SQLExecDirect executes a searched update or delete statement that diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index d2cda8572df5b..5f2827334a86e 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -288,14 +288,14 @@ static bool pgsql_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t * return true; } -static zend_long pgsql_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_len) +static zend_long pgsql_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) { pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; PGresult *res; zend_long ret = 1; ExecStatusType qs; - if (!(res = PQexec(H->server, sql))) { + if (!(res = PQexec(H->server, ZSTR_VAL(sql)))) { /* fatal error */ pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); return -1; @@ -352,10 +352,10 @@ static zend_string* pgsql_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo return quoted_str; } -static char *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const char *name, size_t *len) +static zend_string *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const zend_string *name) { pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; - char *id = NULL; + zend_string *id = NULL; PGresult *res; ExecStatusType status; @@ -363,15 +363,14 @@ static char *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const char *name, size_t * res = PQexec(H->server, "SELECT LASTVAL()"); } else { const char *q[1]; - q[0] = name; + q[0] = ZSTR_VAL(name); res = PQexecParams(H->server, "SELECT CURRVAL($1)", 1, NULL, q, NULL, NULL, 0); } status = PQresultStatus(res); if (res && (status == PGRES_TUPLES_OK)) { - id = estrdup((char *)PQgetvalue(res, 0, 0)); - *len = PQgetlength(res, 0, 0); + id = zend_string_init((char *)PQgetvalue(res, 0, 0), PQgetlength(res, 0, 0), 0); } else { pdo_pgsql_error(dbh, status, pdo_pgsql_sqlstate(res)); } diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 97363ff0fee10..a48c77f9e88bc 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -200,12 +200,12 @@ static bool sqlite_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t return false; } -static zend_long sqlite_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_len) +static zend_long sqlite_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) { pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data; char *errmsg = NULL; - if (sqlite3_exec(H->db, sql, NULL, NULL, &errmsg) != SQLITE_OK) { + if (sqlite3_exec(H->db, ZSTR_VAL(sql), NULL, NULL, &errmsg) != SQLITE_OK) { pdo_sqlite_error(dbh); if (errmsg) sqlite3_free(errmsg); @@ -216,14 +216,11 @@ static zend_long sqlite_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_ } } -static char *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const char *name, size_t *len) +static zend_string *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const zend_string *name) { pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data; - char *id; - id = php_pdo_int64_to_str(sqlite3_last_insert_rowid(H->db)); - *len = strlen(id); - return id; + return php_pdo_int64_to_str(sqlite3_last_insert_rowid(H->db)); } /* NB: doesn't handle binary strings... use prepared stmts for that */