Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(agent): don't skip arguments when calling mysqli::real_connect #976

Merged
merged 7 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions agent/php_mysqli.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,18 +403,22 @@ static nr_status_t nr_php_mysqli_link_real_connect(
zval* retval = NULL;

#define ADD_IF_INT_SET(args, argc, value) \
args[argc] = nr_php_zval_alloc(); \
if (value) { \
args[argc] = nr_php_zval_alloc(); \
ZVAL_LONG(args[argc], value); \
argc++; \
}
} else { \
ZVAL_NULL(args[argc]); \
} \
argc++;

#define ADD_IF_STR_SET(args, argc, value) \
args[argc] = nr_php_zval_alloc(); \
if (value) { \
args[argc] = nr_php_zval_alloc(); \
nr_php_zval_str(args[argc], value); \
argc++; \
}
} else { \
ZVAL_NULL(args[argc]); \
} \
argc++;

ADD_IF_STR_SET(argv, argc,
nr_php_mysqli_strip_persistent_prefix(metadata->host));
Expand All @@ -430,7 +434,13 @@ static nr_status_t nr_php_mysqli_link_real_connect(
ADD_IF_STR_SET(argv, argc, metadata->database);
ADD_IF_INT_SET(argv, argc, metadata->port);
ADD_IF_STR_SET(argv, argc, metadata->socket);
ADD_IF_INT_SET(argv, argc, metadata->flags);

/*
* Avoid defaulting the final $flags argument to null.
*/
if (metadata->flags) {
zsistla marked this conversation as resolved.
Show resolved Hide resolved
zsistla marked this conversation as resolved.
Show resolved Hide resolved
ADD_IF_INT_SET(argv, argc, metadata->flags);
}
}

retval = nr_php_call_user_func(link, "real_connect", argc, argv TSRMLS_CC);
Expand Down
9 changes: 9 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ services:
retries: 3
start_period: 20s
container_name: mysqldb
volumes:
- var-run-mysqld:/var/run/mysqld
redisdb:
image: redis
restart: always
Expand Down Expand Up @@ -56,6 +58,7 @@ services:
MYSQL_USER: admin
MYSQL_PASSWD: admin
MYSQL_HOST: mysqldb
MYSQL_SOCKET: /var/run/mysqld/mysqld.sock

PG_HOST: postgres
PG_PORT: 5432
Expand All @@ -67,6 +70,7 @@ services:

volumes:
- ${AGENT_CODE:-$PWD}:/usr/local/src/newrelic-php-agent
- var-run-mysqld:/var/run/mysqld
entrypoint: tail
command: -f /dev/null
container_name: nr-php
Expand All @@ -83,6 +87,7 @@ services:
MYSQL_USER: admin
MYSQL_PASSWD: admin
MYSQL_HOST: mysqldb
MYSQL_SOCKET: /var/run/mysqld/mysqld.sock

PG_HOST: postgres
PG_PORT: 5432
Expand All @@ -97,8 +102,12 @@ services:
NEWRELIC_LICENSE_KEY: ${NEW_RELIC_LICENSE_KEY}
volumes:
- ${PWD}:/usr/src/myapp
- var-run-mysqld:/var/run/mysqld
working_dir: /usr/src/myapp
stdin_open: true
tty: true
container_name: agent-devenv
profiles: ["dev"]

volumes:
var-run-mysqld:
148 changes: 148 additions & 0 deletions tests/integration/mysqli/test_explain_connect_socket.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php
/*
* Copyright 2020 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

/*DESCRIPTION
The agent should generate explain plans when connections are made with
mysqli_connect() when connecting to the database via socket.
*/

/*SKIPIF
<?php require("skipif.inc");
*/

/*INI
error_reporting = E_ALL & ~E_DEPRECATED
newrelic.transaction_tracer.explain_enabled = true
newrelic.transaction_tracer.explain_threshold = 0
newrelic.transaction_tracer.record_sql = obfuscated
*/

/*EXPECT
STATISTICS
*/

/*EXPECT_METRICS
[
"?? agent run id",
"?? start time",
"?? stop time",
[
[{"name":"DurationByCaller/Unknown/Unknown/Unknown/Unknown/all"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"DurationByCaller/Unknown/Unknown/Unknown/Unknown/allOther"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/all"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/allOther"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/MySQL/all"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/MySQL/allOther"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/statement/MySQL/tables/select"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/statement/MySQL/tables/select",
"scope":"OtherTransaction/php__FILE__"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/operation/MySQL/select"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"OtherTransaction/all"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"OtherTransaction/php__FILE__"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]]
]
]
*/



/*EXPECT_SLOW_SQLS
[
[
[
"OtherTransaction/php__FILE__",
"<unknown>",
"?? SQL ID",
"SELECT TABLE_NAME FROM information_schema.tables WHERE table_name=?",
"Datastore/statement/MySQL/tables/select",
1,
"?? total time",
"?? min time",
"?? max time",
{
"explain_plan": [
[
"id",
"select_type",
"table",
"type",
"possible_keys",
"key",
"key_len",
"ref",
"rows",
"Extra"
],
[
[
1,
"SIMPLE",
"tables",
"ALL",
null,
"TABLE_NAME",
null,
null,
null,
"Using where; Skip_open_table; Scanned 1 database"
]
]
],
"backtrace": [
" in mysqli_stmt_execute called at __FILE__ (??)",
" in test_prepare called at __FILE__ (??)"
]
}
]
]
]
*/

/*EXPECT_TRACED_ERRORS
null
*/

require_once(realpath (dirname ( __FILE__ )) . '/../../include/config.php');

function test_prepare($link)
{
$query = "SELECT TABLE_NAME FROM information_schema.tables WHERE table_name='STATISTICS'";

$stmt = mysqli_prepare($link, $query);
if (FALSE === $stmt) {
echo mysqli_error($link) . "\n";
return;
}

if (FALSE === mysqli_stmt_execute($stmt)) {
echo mysqli_stmt_error($stmt) . "\n";
return;
}

if (FALSE === mysqli_stmt_bind_result($stmt, $value)) {
echo mysqli_stmt_error($stmt) . "\n";
return;
}

while (mysqli_stmt_fetch($stmt)) {
echo $value . "\n";
}

mysqli_stmt_close($stmt);
}

$link = mysqli_connect('localhost', $MYSQL_USER, $MYSQL_PASSWD, $MYSQL_DB, null, $MYSQL_SOCKET);
if (mysqli_connect_errno()) {
echo mysqli_connect_error() . "\n";
exit(1);
}

test_prepare($link);
mysqli_close($link);
150 changes: 150 additions & 0 deletions tests/integration/mysqli/test_explain_construct_socket.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<?php
/*
* Copyright 2020 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

/*DESCRIPTION
The agent should generate explain plans when connections are made with new
mysqli() when connecting to the database via socket.
*/

/*SKIPIF
<?php
require("skipif.inc");
*/

/*INI
error_reporting = E_ALL & ~E_DEPRECATED
newrelic.transaction_tracer.explain_enabled = true
newrelic.transaction_tracer.explain_threshold = 0
newrelic.transaction_tracer.record_sql = obfuscated
*/

/*EXPECT
STATISTICS
*/

/*EXPECT_METRICS
[
"?? agent run id",
"?? start time",
"?? stop time",
[
[{"name":"DurationByCaller/Unknown/Unknown/Unknown/Unknown/all"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"DurationByCaller/Unknown/Unknown/Unknown/Unknown/allOther"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/all"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/allOther"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/MySQL/all"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/MySQL/allOther"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/statement/MySQL/tables/select"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/statement/MySQL/tables/select",
"scope":"OtherTransaction/php__FILE__"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Datastore/operation/MySQL/select"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"OtherTransaction/all"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"OtherTransaction/php__FILE__"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]],
[{"name":"Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]]
]
]
*/



/*EXPECT_SLOW_SQLS
[
[
[
"OtherTransaction/php__FILE__",
"<unknown>",
"?? SQL ID",
"SELECT TABLE_NAME FROM information_schema.tables WHERE table_name=?",
"Datastore/statement/MySQL/tables/select",
1,
"?? total time",
"?? min time",
"?? max time",
{
"explain_plan": [
[
"id",
"select_type",
"table",
"type",
"possible_keys",
"key",
"key_len",
"ref",
"rows",
"Extra"
],
[
[
1,
"SIMPLE",
"tables",
"ALL",
null,
"TABLE_NAME",
null,
null,
null,
"Using where; Skip_open_table; Scanned 1 database"
]
]
],
"backtrace": [
" in mysqli_stmt_execute called at __FILE__ (??)",
" in test_prepare called at __FILE__ (??)"
]
}
]
]
]
*/

/*EXPECT_TRACED_ERRORS
null
*/

require_once(realpath (dirname ( __FILE__ )) . '/../../include/config.php');

function test_prepare($link)
{

$query = "SELECT TABLE_NAME FROM information_schema.tables WHERE table_name='STATISTICS'";

$stmt = mysqli_prepare($link, $query);
if (FALSE === $stmt) {
echo mysqli_error($link) . "\n";
return;
}

if (FALSE === mysqli_stmt_execute($stmt)) {
echo mysqli_stmt_error($stmt) . "\n";
return;
}

if (FALSE === mysqli_stmt_bind_result($stmt, $value)) {
echo mysqli_stmt_error($stmt) . "\n";
return;
}

while (mysqli_stmt_fetch($stmt)) {
echo $value . "\n";
}

mysqli_stmt_close($stmt);
}

$link = new mysqli('localhost', $MYSQL_USER, $MYSQL_PASSWD, $MYSQL_DB, null, $MYSQL_SOCKET);
if (mysqli_connect_errno()) {
echo mysqli_connect_error() . "\n";
exit(1);
}

test_prepare($link);
mysqli_close($link);
Loading