@@ -680,6 +680,97 @@ public function testPDOStatementExceptionPeerServiceEnabled()
680680 ]);
681681 }
682682
683+ public function testPreparedStatementExecuteIsChildOfPrepare ()
684+ {
685+ $ query = "SELECT * FROM tests WHERE id = ? " ;
686+ $ traces = $ this ->isolateTracer (function () use ($ query ) {
687+ $ pdo = $ this ->pdoInstance ();
688+ $ stmt = $ pdo ->prepare ($ query );
689+ $ stmt ->execute ([1 ]);
690+ $ results = $ stmt ->fetchAll ();
691+ $ this ->assertEquals ('Tom ' , $ results [0 ]['name ' ]);
692+ $ stmt ->closeCursor ();
693+ $ stmt = null ;
694+ $ pdo = null ;
695+ });
696+
697+ // Get the raw spans to check parent-child relationship
698+ $ spans = $ traces [0 ];
699+
700+ // Find prepare and execute spans
701+ $ constructSpan = null ;
702+ $ prepareSpan = null ;
703+ $ executeSpan = null ;
704+
705+ foreach ($ spans as $ span ) {
706+ if ($ span ['name ' ] === 'PDO.__construct ' ) {
707+ $ constructSpan = $ span ;
708+ } elseif ($ span ['name ' ] === 'PDO.prepare ' ) {
709+ $ prepareSpan = $ span ;
710+ } elseif ($ span ['name ' ] === 'PDOStatement.execute ' ) {
711+ $ executeSpan = $ span ;
712+ }
713+ }
714+
715+ $ this ->assertNotNull ($ constructSpan , 'PDO.__construct span should exist ' );
716+ $ this ->assertNotNull ($ prepareSpan , 'PDO.prepare span should exist ' );
717+ $ this ->assertNotNull ($ executeSpan , 'PDOStatement.execute span should exist ' );
718+
719+ // Verify that execute span's parent is the prepare span
720+ $ this ->assertEquals (
721+ $ prepareSpan ['span_id ' ],
722+ $ executeSpan ['parent_id ' ],
723+ 'PDOStatement.execute should be a child of PDO.prepare '
724+ );
725+ }
726+
727+ public function testDirectQueryHasNoParentIssues ()
728+ {
729+ $ query = "SELECT * FROM tests WHERE id=1 " ;
730+ $ traces = $ this ->isolateTracer (function () use ($ query ) {
731+ $ pdo = $ this ->pdoInstance ();
732+ $ pdo ->query ($ query );
733+ $ pdo = null ;
734+ });
735+
736+ // Get the raw spans
737+ $ spans = $ traces [0 ];
738+
739+ // Find construct and query spans
740+ $ constructSpan = null ;
741+ $ querySpan = null ;
742+
743+ foreach ($ spans as $ span ) {
744+ if ($ span ['name ' ] === 'PDO.__construct ' ) {
745+ $ constructSpan = $ span ;
746+ } elseif ($ span ['name ' ] === 'PDO.query ' ) {
747+ $ querySpan = $ span ;
748+ }
749+ }
750+
751+ $ this ->assertNotNull ($ constructSpan , 'PDO.__construct span should exist ' );
752+ $ this ->assertNotNull ($ querySpan , 'PDO.query span should exist ' );
753+
754+ // Verify that query span has a parent (should be root or construct)
755+ $ this ->assertTrue (
756+ isset ($ querySpan ['parent_id ' ]),
757+ 'PDO.query should have a parent_id '
758+ );
759+
760+ // Verify spans are created correctly with proper structure
761+ $ this ->assertSpans ($ traces , [
762+ SpanAssertion::exists ('PDO.__construct ' ),
763+ SpanAssertion::build ('PDO.query ' , 'pdo ' , 'sql ' , $ query )
764+ ->withExactTags ($ this ->baseTags ())
765+ ->withExactMetrics ([
766+ Tag::DB_ROW_COUNT => 1.0 ,
767+ Tag::ANALYTICS_KEY => 1.0 ,
768+ '_dd.agent_psr ' => 1.0 ,
769+ '_sampling_priority_v1 ' => 1.0 ,
770+ ]),
771+ ]);
772+ }
773+
683774 public function testLimitedTracerPDO ()
684775 {
685776 $ query = "SELECT * FROM tests WHERE id = ? " ;
0 commit comments