Skip to content
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) {
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