diff --git a/src/asyncresults.jl b/src/asyncresults.jl index b2a0c5ba..5710d7bd 100644 --- a/src/asyncresults.jl +++ b/src/asyncresults.jl @@ -251,7 +251,8 @@ function async_execute( string_params = string_parameters(parameters) pointer_params = parameter_pointers(string_params) - async_result = _async_execute(jl_conn; binary_format=binary_format, kwargs...) do jl_conn + async_result = + _async_execute(jl_conn; binary_format=binary_format, kwargs...) do jl_conn GC.@preserve string_params _async_submit( jl_conn, query, pointer_params; binary_format=binary_format ) diff --git a/test/runtests.jl b/test/runtests.jl index 6a018f64..22f21edd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -40,7 +40,8 @@ function count_allocs(f, args...) return Base.gc_alloc_count(stats.gcstats) end -@testset "LibPQ" begin +usenonblocking = get(ENV, "usenonblocking", false) +@testset "LibPQ $(usenonblocking ? "(nonblocking connection)" : "")" begin @testset "ConninfoDisplay" begin @test parse(LibPQ.ConninfoDisplay, "") == LibPQ.Normal @@ -82,6 +83,7 @@ end @testset "Example SELECT" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=false) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) @test conn isa LibPQ.Connection @test isopen(conn) @test status(conn) == LibPQ.libpq_c.CONNECTION_OK @@ -190,6 +192,7 @@ end @testset "Example INSERT and DELETE" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER") + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, """ CREATE TEMPORARY TABLE libpqjl_test ( @@ -333,6 +336,7 @@ end @testset "load!" begin @testset "issue #204" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER") + LibPQ.setnonblocking(conn, nonblock=usenonblocking) close(execute(conn, """ CREATE TEMPORARY TABLE libpqjl_test ( @@ -357,6 +361,7 @@ end @testset "COPY FROM" begin @testset "Example COPY FROM" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER") + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, """ CREATE TEMPORARY TABLE libpqjl_test ( @@ -401,6 +406,7 @@ end @testset "Wrong column order" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER") + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, """ CREATE TEMPORARY TABLE libpqjl_test ( @@ -458,6 +464,7 @@ end local saved_conn was_open = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) do jl_conn + LibPQ.setnonblocking(jl_conn, nonblock=usenonblocking) saved_conn = jl_conn return isopen(jl_conn) end @@ -466,6 +473,7 @@ end @test !isopen(saved_conn) @test_throws LibPQ.Errors.PQConnectionError LibPQ.Connection("dbname=123fake user=$DATABASE_USER"; throw_error=true) do jl_conn + LibPQ.setnonblocking(conn, nonblock=usenonblocking) saved_conn = jl_conn @test false end @@ -475,6 +483,7 @@ end @testset "Version Numbers" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) # update this test before PostgreSQL 20.0 ;) @test LibPQ.pqv"7" <= LibPQ.server_version(conn) <= LibPQ.pqv"20" @@ -482,6 +491,7 @@ end @testset "Encoding" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) @test LibPQ.encoding(conn) == "UTF8" @@ -513,6 +523,7 @@ end throw_error=true, type_map=Dict(:interval => String), ) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) conn_info = LibPQ.conninfo(conn) options = first(filter(conn_info) do conn_opt @@ -632,6 +643,8 @@ end @testset "Finalizer" begin closed_flags = map(1:50) do _ conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER") + LibPQ.setnonblocking(conn, nonblock=usenonblocking) + closed = conn.closed finalize(conn) return closed @@ -646,6 +659,8 @@ end closed_flags = map(1:50) do _ conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER") + LibPQ.setnonblocking(conn, nonblock=usenonblocking) + push!(results, execute(conn, "SELECT 1;")) return conn.closed end @@ -661,6 +676,8 @@ end # with AsyncResults, which hold a reference to Connection closed_flags = asyncmap(1:50) do _ conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER") + LibPQ.setnonblocking(conn, nonblock=usenonblocking) + wait(async_execute(conn, "SELECT pg_sleep(1);")) return conn.closed end @@ -707,6 +724,8 @@ end @testset "throw_error=false" begin conn = LibPQ.Connection("dbname=123fake user=$DATABASE_USER"; throw_error=false) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) + @test conn isa LibPQ.Connection @test status(conn) == LibPQ.libpq_c.CONNECTION_BAD @test isopen(conn) @@ -725,6 +744,8 @@ end @test_throws LibPQ.Errors.PQConnectionError LibPQ.Connection("dbname=123fake user=$DATABASE_USER"; throw_error=true) conn = LibPQ.Connection("dbname=123fake user=$DATABASE_USER"; throw_error=false) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) + @test conn isa LibPQ.Connection @test status(conn) == LibPQ.libpq_c.CONNECTION_BAD @test isopen(conn) @@ -740,6 +761,7 @@ end @testset "Results" begin @testset "Nulls" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, "SELECT NULL"; throw_error=true) @test status(result) == LibPQ.libpq_c.PGRES_TUPLES_OK @@ -824,6 +846,7 @@ end @testset "Not Nulls" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, "SELECT NULL"; not_null=[false], throw_error=true) @test status(result) == LibPQ.libpq_c.PGRES_TUPLES_OK @@ -949,6 +972,7 @@ end @testset "Tables.jl" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, """ SELECT no_nulls, yes_nulls FROM ( @@ -991,6 +1015,7 @@ end @testset "Duplicate names" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, "SELECT 1 AS col, 2 AS col;", not_null=true, throw_error=true) columns = Tables.columns(result) @@ -1007,6 +1032,7 @@ end @testset "Uppercase Columns" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, "SELECT 1 AS \"Column\";") @test num_columns(result) == 1 @@ -1025,6 +1051,7 @@ end @testset "PQResultError" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) try execute(conn, "SELECT log(-1);") @@ -1072,6 +1099,7 @@ end @testset "Type Conversions" begin @testset "Deprecations" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, "SELECT 'infinity'::timestamp;") @@ -1089,6 +1117,7 @@ end @testset "Automatic" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, """ SELECT oid, typname, typlen, typbyval, typcategory @@ -1120,6 +1149,7 @@ end @testset "Overrides" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, "SELECT 4::bigint;") @test first(first(result)) === Int64(4) @@ -1169,6 +1199,7 @@ end @testset for binary_format in (LibPQ.TEXT, LibPQ.BINARY) @testset "Default Types" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) test_data = [ ("3", Cint(3)), @@ -1335,6 +1366,7 @@ end @testset "Specified Types" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) test_data = [ ("3", UInt, UInt(3)), @@ -1428,6 +1460,7 @@ end @testset "Parameters" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) @testset "Arrays" begin tests = ( @@ -1542,6 +1575,7 @@ end @testset "SQLString" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER") + LibPQ.setnonblocking(conn, nonblock=usenonblocking) execute(conn, sql``` CREATE TEMPORARY TABLE libpq_test_users ( @@ -1577,6 +1611,7 @@ end @testset "Query Errors" begin @testset "Syntax Errors" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, "SELORCT NUUL;"; throw_error=false) @test status(result) == LibPQ.libpq_c.PGRES_FATAL_ERROR @@ -1595,6 +1630,7 @@ end @testset "Wrong No. Parameters" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute(conn, "SELORCT \$1;", String[]; throw_error=false) @test status(result) == LibPQ.libpq_c.PGRES_FATAL_ERROR @@ -1619,6 +1655,7 @@ end @testset "Interface Errors" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = execute( conn, @@ -1652,6 +1689,7 @@ end # Establish connection and construct temporary table. conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER") + LibPQ.setnonblocking(conn, nonblock=usenonblocking) # Get the column. result = execute( @@ -1678,6 +1716,7 @@ end @testset "Statements" begin @testset "No Params, Output" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) stmt = prepare(conn, "SELECT oid, typname FROM pg_type") @@ -1699,6 +1738,7 @@ end @testset "Params, Output" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) stmt = prepare(conn, "SELECT oid, typname FROM pg_type WHERE oid = \$1") @@ -1723,11 +1763,13 @@ end end end - @testset "AsyncResults" begin + @testset "AsyncResults (usenonblocking connection=$usenonblocking)" for usenonblocking in [true, false] + @info "usenonblocking" usenonblocking trywait(ar::LibPQ.AsyncResult) = (try wait(ar) catch end; nothing) @testset "Basic" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) ar = async_execute(conn, "SELECT pg_sleep(2);"; throw_error=false) yield() @@ -1750,6 +1792,7 @@ end @testset "Parameters" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) ar = async_execute( conn, @@ -1782,6 +1825,7 @@ end # Ensures queries wait for previous query completion before starting @testset "Wait in line to complete" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) first_ar = async_execute(conn, "SELECT pg_sleep(4);") yield() @@ -1811,6 +1855,7 @@ end @testset "Cancel" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) # final query needs to be one that actually does something # on Windows, first query also needs to do something @@ -1843,6 +1888,7 @@ end @testset "Canceled by closing connection" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) # final query needs to be one that actually does something # on Windows, first query also needs to do something @@ -1875,6 +1921,7 @@ end @testset "FDWatcher: bad file descriptor (EBADF)" begin conn = LibPQ.Connection("dbname=postgres user=$DATABASE_USER"; throw_error=true) + LibPQ.setnonblocking(conn, nonblock=usenonblocking) ar = async_execute(conn, "SELECT pg_sleep(3); SELECT * FROM pg_type;") yield() @@ -1898,6 +1945,7 @@ end @testset "DBInterface integration" begin conn = DBInterface.connect(LibPQ.Connection, "dbname=postgres user=$DATABASE_USER") @test conn isa LibPQ.Connection + LibPQ.setnonblocking(conn, nonblock=usenonblocking) result = DBInterface.execute( conn,