2828import java .sql .SQLException ;
2929import java .sql .Statement ;
3030import java .util .Map ;
31+ import java .util .concurrent .CompletableFuture ;
32+ import java .util .concurrent .ExecutionException ;
33+ import java .util .concurrent .TimeUnit ;
34+ import java .util .concurrent .TimeoutException ;
3135
3236public class LibSqlConnection extends AbstractJdbcConnection {
3337
@@ -40,6 +44,7 @@ public class LibSqlConnection extends AbstractJdbcConnection {
4044 @ NotNull
4145 private final Map <String , Object > driverProperties ;
4246 private LibSqlDatabaseMetaData databaseMetaData ;
47+ private volatile boolean closed = false ;
4348
4449 public LibSqlConnection (
4550 @ NotNull LibSqlDriver driver ,
@@ -108,12 +113,47 @@ private LibSqlPreparedStatement prepareStatementImpl(String sql) throws SQLExcep
108113
109114 @ Override
110115 public void close () throws SQLException {
111- client .close ();
116+ if (!closed ) {
117+ client .close ();
118+ closed = true ;
119+ }
112120 }
113121
114122 @ Override
115123 public boolean isClosed () {
116- return false ;
124+ return closed ;
125+ }
126+
127+ @ Override
128+ public boolean isValid (int timeout ) throws SQLException {
129+ if (timeout < 0 ) {
130+ throw new SQLException ("Invalid timeout value: " + timeout );
131+ }
132+ if (closed ) {
133+ return false ;
134+ }
135+ CompletableFuture <Boolean > ping = CompletableFuture .supplyAsync (() -> {
136+ try {
137+ LibSqlUtils .executeQuery (this , "SELECT 1" );
138+ return Boolean .TRUE ;
139+ } catch (Exception e ) {
140+ return Boolean .FALSE ;
141+ }
142+ });
143+ try {
144+ if (timeout == 0 ) {
145+ return ping .get ();
146+ }
147+ return ping .get (timeout , TimeUnit .SECONDS );
148+ } catch (TimeoutException e ) {
149+ ping .cancel (true );
150+ return false ;
151+ } catch (InterruptedException e ) {
152+ Thread .currentThread ().interrupt ();
153+ return false ;
154+ } catch (ExecutionException e ) {
155+ return false ;
156+ }
117157 }
118158
119159 @ Override
0 commit comments