File: SQLSessionContextTest.java

package info (click to toggle)
derby 10.14.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 78,896 kB
  • sloc: java: 691,930; sql: 42,686; xml: 20,511; sh: 3,373; sed: 96; makefile: 60
file content (747 lines) | stat: -rw-r--r-- 25,259 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
/*

   Derby - Class org.apache.derbyTesting.functionTests.tests.lang.SQLSessionContextTest

   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to you under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

 */

package org.apache.derbyTesting.functionTests.tests.lang;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import junit.framework.Test;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.BaseTestSuite;
import org.apache.derbyTesting.junit.DatabasePropertyTestSetup;
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.TestConfiguration;

/**
 * SQLSessionContextTest tests the SQL session context stacking,
 * cf. SQL 4.37.3. The testing of one of the SQL session state
 * variable, the current role, relies on sqlAuthorization being set,
 * so use sqlAuthorization=true.
 *
 * State variables tested:
 *   current role            (SET ROLE <role>, CURRENT_ROLE)
 *   current default schema  (SET SCHEMA <schema>, CURRENT SCHEMA)
 *
 * SET SCHEMA and SET ROLE are SQL SESSION statements and are not
 * transaction-initiating, cf. SQL section 4.33.
 *
 * The tests are run in the cross product:
 *
 *    {client/server, embedded} x
 *    {data base owner}
 *
 * See also RoutinesDefinersRightsTest, which tests the current user part of
 * the SQLSessionContext.
 */
public class SQLSessionContextTest extends BaseJDBCTestCase
{
    /* internal state */
    private Connection _conn;
    private Statement _stm;

    private final static String pwSuffix = "pwSuffix";

    /**
     * SQL states used by test
     */
    private final static String userException = "38000";

    /**
     * The TestConfiguration.sqlAuthorizationDecorator decorator presumes
     * TEST_DBO as dbo, so add it to set of valid users. It uses a fresh db
     * 'dbsqlauth', not 'wombat'.
     */
    private final static String[] users = {"TEST_DBO"};

    /**
     * SQL keywords for session context state variables
     */
    private final static String[] variableKeywords =
        new String[]{"role", "schema"};

    /**
     * SQL prefix used to retrieve current value of a session context
     * state variable. Cf. variableKeywords.
     */
    private final static String[] currentPrefix =
        new String[]{"current_", "current "};

    /**
     * Create a new instance of SQLSessionContextTest.
     *
     * @param name Fixture name
     */

    public SQLSessionContextTest(String name)
    {
        super(name);
    }


    /**
     * Construct top level suite in this JUnit test
     *
     * @return A suite containing embedded and client suites.
     *         Client/server suite commented out to speed up this test as
     *         it does not add much value given the nature of the changes
     *         (SQL language only).
     */
    public static Test suite()
    {
        BaseTestSuite suite = new BaseTestSuite("SQLSessionContextTest");

        /* Positive tests */
        if (!JDBC.vmSupportsJSR169()) {
            // JSR169 cannot run with tests with stored procedures
            // that do database access - for they require a
            // DriverManager connection to jdbc:default:connection;
            // DriverManager is not supported with JSR169.
            suite.addTest(
                positiveSuite("suite: positive, embedded"));

            suite.addTest(
                TestConfiguration.clientServerDecorator(
                    positiveSuite("suite: positive, client")));
        }

        return suite;
    }

    /**
     * Construct suite of positive tests
     *
     * @param framework Derby framework indication
     *
     * @return A suite containing the positive test cases incarnated only
     * for security level sqlAuthorization.
     */
    private static Test positiveSuite(String framework)
    {
        /* Tests running with sql authorization set.
         * First decorate with users, then with authentication +
         * sqlAuthorization.
         */

        // add decorator for different users authenticated
        BaseTestSuite usersSuite =
            new BaseTestSuite("suite: positiveSuite");

        // First decorate with users, then with authorization
        // decorator
        for (int userNo = 0; userNo < users.length; userNo++) {
            usersSuite.addTest
                (TestConfiguration.changeUserDecorator
                 (new SQLSessionContextTest("testPositive"),
                  users[userNo],
                  users[userNo].concat(pwSuffix)));
        }

        return TestConfiguration.sqlAuthorizationDecorator(
            DatabasePropertyTestSetup.builtinAuthentication(
                usersSuite, users, pwSuffix));
    }

    /**
     * Positive tests for SQL session state.
     *
     * @throws SQLException
     */
    public void testPositive() throws SQLException
    {
        PreparedStatement[]ps = new PreparedStatement[]{null, null};

        for (int i= 0; i < variableKeywords.length; i++) {
            String curr = currentPrefix[i] + variableKeywords[i];
            ps[i] = _conn.prepareStatement("values " + curr);
        }

        println("testPositive user="+getTestConfiguration().getUserName());

        /*
         * SET SESSION STATE variables
         */
        _stm.executeUpdate("set role outermost");
        _stm.executeUpdate("set schema outermost");

        /**
         * The SQL standard requires we have an SQL session context
         * see section 4.27.3, which is stacked. The stack is pushed
         * at entry to a stored procedure or function.  The current
         * SQL session state is popped at end of stored procedure.  We
         * test two levels deep.
         */
        _stm.execute("call test_dbo.p2()");

        // Dynamic result set: At what time should CURRENT_<state> be
        // evaluated?  Logically at the inside (inside the nested
        // SQL session context), so it should be "LEVEL2" also when
        // accessed on outside (outer SQL session context) I
        // think. Anyway, that's what's implemented: the
        // activation of the call is still live and holds (the
        // final state of) the nested SQL session context
        // even when the procedure call has
        // returned.
        ResultSet prs = _stm.getResultSet(); // role
        assertCurrent("role", prs, "LEVEL2");

        _stm.getMoreResults(Statement.CLOSE_CURRENT_RESULT);
        prs = _stm.getResultSet();
        assertCurrent("schema", prs, "LEVEL2");
        prs.close();

        // check that state didn't get impacted by change inside p2
        //
        for (int i= 0; i < variableKeywords.length; i++) {
            ResultSet rs = ps[i].executeQuery();
            assertCurrent(variableKeywords[i], rs, "OUTERMOST");
            rs.close();
        }

        ResultSet rs = _stm.executeQuery("values test_dbo.f2()");


        // Gotcha: we need to fetch first row for embedded driver
        // to actually call f2. The client driver prefetches, so
        // call to f2 will get performed even without the next():
        rs.next();
        rs.close();

        // check that state didn't get impacted by change inside f2
        //
        for (int i= 0; i < variableKeywords.length; i++) {
            rs = ps[i].executeQuery();
            assertCurrent(variableKeywords[i], rs, "OUTERMOST");
            rs.close();
        }

        // check that f2 doesn't impact f22
        rs = _stm.executeQuery("values test_dbo.f2() + test_dbo.f22()");
        rs.next();
        rs.close();

        // check that pushed SQL session context was popped also
        // when the callee gets an exception
        try {
            rs = _stm.executeQuery("values test_dbo.f3()");
            rs.next();
        } catch (SQLException e) {
            assertSQLState(userException, e);
        }

        for (int i= 0; i < 1; i++) {
            rs = ps[i].executeQuery();
            assertCurrent(variableKeywords[i], rs, "OUTERMOST");
            rs.close();
        }

        // Test that when a nested routine drops a role/schema the
        // caller's stacked value is correctly reset. See also javadoc
        // for dropper.
        _stm.execute("call test_dbo.dropper()");

        String[] expected = new String[]{null, "TEST_DBO"};
        for (int i= 0; i < 1; i++) {
            rs = ps[i].executeQuery();
            assertCurrent(variableKeywords[i], rs, expected[i]);
            rs.close();
        }

        for (int i= 0; i < variableKeywords.length; i++) {
            ps[i].close();
        }

        // DERBY-3897: See
        //
        // RolesConferredPrivilegesTest#testDefaultCurrentRole and
        // RolesConferredPrivilegesTest#testCurrentRoleInWeirdContexts
        //
        // which are also relevant tests for SQLSessionContext.
    }


    protected void setUp() throws Exception
    {
        super.setUp();

        _stm = createStatement();
        _conn = getConnection();

        _stm.executeUpdate("create role outermost");
        _stm.executeUpdate("create role level2");
        _stm.executeUpdate("create role innermost");
        _stm.executeUpdate("create schema outermost");
        _stm.executeUpdate("create schema level2");
        _stm.executeUpdate("create schema innermost");

        _stm.executeUpdate(
            "create procedure p2()" +
            "  dynamic result sets 2 language java parameter style java"+
            "  external name 'org.apache.derbyTesting." +
            "functionTests.tests.lang.SQLSessionContextTest.p2'" +
            "  modifies sql data");
        _stm.executeUpdate(
            "create function f2()" +
            "  returns int language java parameter style java" +
            "  external name 'org.apache.derbyTesting." +
            "functionTests.tests.lang.SQLSessionContextTest.f2'" +
            "  reads sql data");
        _stm.executeUpdate(
            "create function f22()" +
            "  returns int language java parameter style java" +
            "  external name 'org.apache.derbyTesting." +
            "functionTests.tests.lang.SQLSessionContextTest.f22'" +
            "  reads sql data");
        _stm.executeUpdate(
            "create function f3()" +
            "  returns int language java parameter style java" +
            "  external name 'org.apache.derbyTesting." +
            "functionTests.tests.lang.SQLSessionContextTest.f3'" +
            "  reads sql data");
        _stm.executeUpdate(
            "create procedure calledNestedFromP2(state VARCHAR(255))" +
            "  language java parameter style java" +
            "  external name 'org.apache.derbyTesting." +
            "functionTests.tests.lang.SQLSessionContextTest.calledNestedFromP2'"
            +
            "  modifies sql data");
        _stm.executeUpdate(
            "create procedure dropper()" +
            "  language java parameter style java" +
            "  external name 'org.apache.derbyTesting." +
            "functionTests.tests.lang.SQLSessionContextTest.dropper'" +
            "  modifies sql data");
    }


    protected void tearDown() throws Exception
    {
        try {
            _stm.executeUpdate("set schema test_dbo");
            // "OUTERMOST" role/schema is dropped as part of the test,
            // cf. stored procedure 'dropper'.
            _stm.executeUpdate("drop role level2");
            _stm.executeUpdate("drop role innermost");
            _stm.executeUpdate("drop schema level2 restrict");
            _stm.executeUpdate("drop schema innermost restrict");
            _stm.executeUpdate("drop procedure p2");
            _stm.executeUpdate("drop function f2");
            _stm.executeUpdate("drop function f22");
            _stm.executeUpdate("drop function f3");
            _stm.executeUpdate("drop procedure calledNestedFromP2");
            _stm.executeUpdate("drop procedure dropper");
        }
        finally {
            if (_stm != null) {
                _stm = null;
            }

            if (_conn != null) {
                _conn = null;
            }

            super.tearDown();
        }

    }


    private static void assertCurrent(String sessionVar,
                                      ResultSet rs,
                                      String expected)
            throws SQLException
    {
        assertTrue("result set empty", rs.next());
        String actualCurrent = rs.getString(1);

        if (sessionVar.equals("role") && expected != null) {
            // returned current_role is a delimited identifer, which is SQL
            // standard compliant. current_schema returns case normal form,
            // which is not.
            expected = "\"" + expected + "\"";
        }

        if (expected != null) {
            assertTrue(sessionVar + ": current is " + actualCurrent +
                       ", expected " + expected,
                       expected.equals(actualCurrent));
        } else {
            assertTrue(sessionVar + ": current is " + actualCurrent +
                       ", expected null",
                       actualCurrent == null);
        }



        // cardinality should be 1
        assertFalse("result set not empty", rs.next());
    }


    /**
     * Utility procedure used to test that current session state is
     * stacked correctly in a nested SQL session context.
     */
    public static void p2(ResultSet[] rs1, ResultSet[] rs2)
            throws Throwable
    {
        Connection conn1 = null;
        Connection conn2 = null;

        try {
            conn1 = DriverManager.getConnection("jdbc:default:connection");

            for (int i= 0; i < variableKeywords.length; i++) {

                String curr = currentPrefix[i] + variableKeywords[i];

                PreparedStatement ps =
                    conn1.prepareStatement("values " + curr);

                // check that we inherit context correctly
                // current role, cf. SQL 4.34.1.1 and 4.27.3
                // current default schema, cf. SQL 4.37.3 and 4.37.5
                ResultSet rs = ps.executeQuery();
                assertCurrent(variableKeywords[i], rs, "OUTERMOST");
                rs.close();

                // set the state to "LEVEL2"
                Statement stm = conn1.createStatement();
                stm.executeUpdate("set " + variableKeywords[i] + " level2");
                rs = ps.executeQuery();

                // check that state got set
                assertCurrent(variableKeywords[i], rs, "LEVEL2");

                // another nesting level to test session context stack
                // even more
                conn1.commit(); // need to be idle
                stm.executeUpdate("call test_dbo.calledNestedFromP2('"
                                  + variableKeywords[i] + "')");

                rs = ps.executeQuery();

                // check that state didn't get impacted by change inside
                // calledNestedFromP2 to 'INNERMOST':
                assertCurrent(variableKeywords[i], rs, "LEVEL2");
                rs.close();

                // Test that the state is shared by another nested
                // connection also.
                conn2 = DriverManager.getConnection("jdbc:default:connection");
                PreparedStatement ps2 =
                    conn2.prepareStatement("values " + curr);
                rs = ps2.executeQuery();
                assertCurrent(variableKeywords[i], rs, "LEVEL2");
                rs.close();
                ps2.close();
            }

            for (int i= 0; i < variableKeywords.length; i++) {
                // Pass out CURRENT <state> in a dynamic result set.
                String curr = currentPrefix[i] + variableKeywords[i];
                PreparedStatement ps =
                    conn1.prepareStatement("values " + curr);
                ResultSet rs = ps.executeQuery();

                if (variableKeywords[i].equals("role")) {
                    rs1[0] = rs;
                } else {
                    rs2[0] = rs;
                }
            }
        } catch (Throwable e) {
            // Print here if debug, since on outside we only see 38000
            // (user error)
            println("err: " + e);

            throw e;

        } finally {

            if (conn1 != null) {
                try {
                    conn1.close();
                } catch (Exception e) {
                }
            }

            if (conn2 != null) {
                try {
                    conn2.close();
                } catch (Exception e) {
                }
            }
        }

    }

    /**
     * Called from p2 so we get to test with a call stack 3 levels
     * deep.
     */
    public static void calledNestedFromP2(String stateString)
            throws SQLException
    {
        Connection conn1 = null;
        Connection conn2 = null;

        try {
            conn1 = DriverManager.getConnection("jdbc:default:connection");

            // CURRENT_ROLE  vs CURRENT SCHEMA syntax:
            String curr = stateString.equals("role")
                ? "current_role"
                : "current schema";

            PreparedStatement ps =
                conn1.prepareStatement("values " + curr);

            // check that we inherit state correctly
            ResultSet rs = ps.executeQuery();
            assertCurrent(stateString, rs, "LEVEL2");
            rs.close();

            // set the state to "INNERMOST"
            Statement stm = conn1.createStatement();
            stm.executeUpdate("set " + stateString + " innermost");
            rs = ps.executeQuery();

            // check that state got set
            assertCurrent(stateString, rs, "INNERMOST");
            rs.close();
            ps.close();

            // Test that the session context is shared by another
            // nested connection also.
            conn2 = DriverManager.getConnection("jdbc:default:connection");
            ps = conn2.prepareStatement("values " + curr);
            rs = ps.executeQuery();
            assertCurrent(stateString, rs, "INNERMOST");
            rs.close();
            ps.close();

        } finally {
            if (conn1 != null) {
                try {
                    conn1.close();
                } catch (Exception e) {
                }
            }
            if (conn2 != null) {
                try {
                    conn2.close();
                } catch (Exception e) {
                }
            }
        }
    }


    /**
     * Utility function used to test that state variables are stacked
     * correctly in a nested SQL session context.
     */
    public static int f2() throws SQLException
    {
        Connection conn1 = null;
        Connection conn2 = null;

        try {
            conn1 = DriverManager.getConnection("jdbc:default:connection");

            for (int i= 0; i < variableKeywords.length; i++) {
                String curr = currentPrefix[i] + variableKeywords[i];

                PreparedStatement ps =
                    conn1.prepareStatement("values " + curr);

                // check that we inherit context correctly
                ResultSet rs = ps.executeQuery();
                assertCurrent(variableKeywords[i], rs, "OUTERMOST");
                rs.close();

                // set the state to "LEVEL2"
                Statement stm = conn1.createStatement();
                stm.executeUpdate("set " + variableKeywords[i] + " level2");
                rs = ps.executeQuery();

                // check that state got set
                assertCurrent(variableKeywords[i], rs, "LEVEL2");

                ps.close();

                // Test that the state is shared by another nested
                // connection also.
                conn2 = DriverManager.getConnection("jdbc:default:connection");
                ps = conn2.prepareStatement("values " + curr);
                rs = ps.executeQuery();
                assertCurrent(variableKeywords[i], rs, "LEVEL2");
                rs.close();
                ps.close();
            }

        } finally {

            if (conn1 != null) {
                try {
                    conn1.close();
                } catch (Exception e) {
                }
            }
            if (conn2 != null) {
                try {
                    conn2.close();
                } catch (Exception e) {
                }
            }
        }

        return 1;
    }


    /**
     * Used to test that a parallel (subsequent) function call in the
     * same statement (called after f2 which changes state) is not
     * affected by the preceding function (f2) call's changes.
     *
     */
    public static int f22() throws SQLException
    {
        Connection conn1 = null;

        try {
            conn1 = DriverManager.getConnection("jdbc:default:connection");

            for (int i= 0; i < variableKeywords.length; i++) {
                String curr = currentPrefix[i] + variableKeywords[i];

                PreparedStatement ps =
                    conn1.prepareStatement("values " + curr);

                // check that we inherit context correctly
                ResultSet rs = ps.executeQuery();
                assertCurrent(variableKeywords[i], rs, "OUTERMOST");
                rs.close();
                ps.close();
            }

        } finally {

            if (conn1 != null) {
                try {
                    conn1.close();
                } catch (Exception e) {
                }
            }
        }

        return 1;
    }


    /**
     * Utility function used to test that current state is stacked
     * correctly in a nested SQL session context.  This particular
     * function will throw and exception. This is used to test that
     * the cleaning up pops the SQL session stack also.
     */
    public static int f3() throws SQLException
    {
        Connection conn1 = null;

        try {
            conn1 = DriverManager.getConnection("jdbc:default:connection");
            // set the state to something else
            Statement stm = conn1.createStatement();
            stm.executeUpdate("set role level2");
            stm.executeUpdate("set schema level2");

            PreparedStatement ps =
                conn1.prepareStatement("values 42");
            ResultSet rs = ps.executeQuery();
            rs.next();
            // force an exception, rs. is empty, next should throw now
            rs.next();
            String s = rs.getString(1);
        } finally {
            if (conn1 != null) {
                try {
                    conn1.close();
                } catch (Exception e) {
                }
            }
        }
        return 1;
    }


    /**
     * Test that when a nested routine drops a role/schema, the
     * current value is correctly reset. For roles, the current role
     * is unchanged, since it is lazily checked (and potentially reset
     * to NONE if it no longer exists or it is no longer granted to
     * session user) only when it is attempted used for anything. For
     * schema, the current schema should revert back to the session's
     * default schema. This holds for all frames on the session
     * context stack (see also caller's check).
     */
    public static void dropper() throws SQLException
    {
        Connection conn1 = null;

        try {
            conn1 = DriverManager.getConnection("jdbc:default:connection");

            // Drop current contexts
            Statement stm = conn1.createStatement();
            stm.executeUpdate("drop role outermost");
            stm.executeUpdate("drop schema outermost restrict");
            stm.close();

            String[] expected = new String[]{null, "TEST_DBO"};

            // check that we revert correctly
            for (int i= 0; i < variableKeywords.length; i++) {
                String curr = currentPrefix[i] + variableKeywords[i];

                PreparedStatement ps =
                    conn1.prepareStatement("values " + curr);

                ResultSet rs = ps.executeQuery();
                assertCurrent(variableKeywords[i], rs, expected[i]);
                rs.close();
                ps.close();
            }
        } finally {
            if (conn1 != null) {
                try {
                    conn1.close();
                } catch (Exception e) {
                }
            }
        }
    }
}