@@ -506,6 +506,133 @@ def test_server_cursor_scroll():
506506 except Exception as e :
507507 return jsonify ({"error" : str (e )}), 500
508508
509+ @app .route ("/test/cursor-reuse" )
510+ def test_cursor_reuse ():
511+ """Test reusing cursor for multiple queries.
512+
513+ Tests whether the instrumentation correctly handles reusing a cursor for multiple execute() calls.
514+ """
515+ try :
516+ with psycopg .connect (get_conn_string ()) as conn , conn .cursor () as cur :
517+ # First query
518+ cur .execute ("SELECT id, name FROM users WHERE id = 1" )
519+ row1 = cur .fetchone ()
520+
521+ # Second query on same cursor
522+ cur .execute ("SELECT id, name FROM users WHERE id = 2" )
523+ row2 = cur .fetchone ()
524+
525+ # Third query
526+ cur .execute ("SELECT COUNT(*) FROM users" )
527+ count = cur .fetchone ()[0 ]
528+
529+ return jsonify ({
530+ "row1" : {"id" : row1 [0 ], "name" : row1 [1 ]} if row1 else None ,
531+ "row2" : {"id" : row2 [0 ], "name" : row2 [1 ]} if row2 else None ,
532+ "count" : count
533+ })
534+ except Exception as e :
535+ return jsonify ({"error" : str (e )}), 500
536+
537+ @app .route ("/test/sql-composed" )
538+ def test_sql_composed ():
539+ """Test psycopg.sql.SQL() composed queries."""
540+ try :
541+ from psycopg import sql
542+
543+ with psycopg .connect (get_conn_string ()) as conn , conn .cursor () as cur :
544+ table = sql .Identifier ("users" )
545+ columns = sql .SQL (", " ).join ([
546+ sql .Identifier ("id" ),
547+ sql .Identifier ("name" ),
548+ sql .Identifier ("email" )
549+ ])
550+
551+ query = sql .SQL ("SELECT {} FROM {} ORDER BY id LIMIT 3" ).format (columns , table )
552+ cur .execute (query )
553+ rows = cur .fetchall ()
554+
555+ return jsonify ({
556+ "count" : len (rows ),
557+ "data" : [{"id" : r [0 ], "name" : r [1 ], "email" : r [2 ]} for r in rows ]
558+ })
559+ except Exception as e :
560+ return jsonify ({"error" : str (e )}), 500
561+
562+
563+
564+
565+ # ===== BUG HUNTING TEST ENDPOINTS =====
566+ # These endpoints expose confirmed bugs in the psycopg instrumentation
567+ # Endpoints that passed tests have been removed
568+
569+ @app .route ("/test/binary-uuid" )
570+ def test_binary_uuid ():
571+ """Test binary UUID data type.
572+
573+ BUG HYPOTHESIS: UUID types may not serialize/deserialize correctly
574+ during RECORD/REPLAY because they are binary.
575+ """
576+ try :
577+ import uuid
578+
579+ with psycopg .connect (get_conn_string ()) as conn , conn .cursor () as cur :
580+ # Create a temp table with UUID column
581+ cur .execute ("CREATE TEMP TABLE uuid_test (id UUID PRIMARY KEY, name TEXT)" )
582+
583+ # Insert a UUID
584+ test_uuid = uuid .uuid4 ()
585+ cur .execute (
586+ "INSERT INTO uuid_test (id, name) VALUES (%s, %s) RETURNING id, name" ,
587+ (test_uuid , "UUID Test" )
588+ )
589+ inserted = cur .fetchone ()
590+
591+ # Query it back
592+ cur .execute ("SELECT id, name FROM uuid_test WHERE id = %s" , (test_uuid ,))
593+ queried = cur .fetchone ()
594+
595+ conn .commit ()
596+
597+ return jsonify ({
598+ "inserted_uuid" : str (inserted [0 ]) if inserted else None ,
599+ "queried_uuid" : str (queried [0 ]) if queried else None ,
600+ "match" : str (inserted [0 ]) == str (queried [0 ]) if inserted and queried else False
601+ })
602+ except Exception as e :
603+ return jsonify ({"error" : str (e )}), 500
604+
605+
606+ @app .route ("/test/binary-bytea" )
607+ def test_binary_bytea ():
608+ """Test binary bytea data type.
609+
610+ BUG HYPOTHESIS: Binary data (bytea) may not serialize/deserialize
611+ correctly during RECORD/REPLAY.
612+ """
613+ try :
614+ with psycopg .connect (get_conn_string ()) as conn , conn .cursor () as cur :
615+ # Create a temp table with bytea column
616+ cur .execute ("CREATE TEMP TABLE bytea_test (id SERIAL, data BYTEA)" )
617+
618+ # Insert binary data
619+ test_data = b'\x00 \x01 \x02 \x03 \xff \xfe \xfd '
620+ cur .execute (
621+ "INSERT INTO bytea_test (data) VALUES (%s) RETURNING id, data" ,
622+ (test_data ,)
623+ )
624+ inserted = cur .fetchone ()
625+
626+ conn .commit ()
627+
628+ # Convert bytes to hex for JSON serialization
629+ return jsonify ({
630+ "inserted_id" : inserted [0 ] if inserted else None ,
631+ "data_hex" : inserted [1 ].hex () if inserted and inserted [1 ] else None ,
632+ "data_length" : len (inserted [1 ]) if inserted and inserted [1 ] else 0
633+ })
634+ except Exception as e :
635+ return jsonify ({"error" : str (e )}), 500
509636
510637if __name__ == "__main__" :
511638 sdk .mark_app_as_ready ()
0 commit comments