Project

General

Profile

MariaDbErrorHandler.diff

Igor Skornyakov, 02/12/2023 11:02 AM

Download (275 KB)

View differences:

build.gradle 2023-02-08 15:41:34 +0000
848 848

  
849 849
task mergeMariaDBUDFs(dependsOn: 'makeManifests') {
850 850
    inputs.files('udf/mariadb/udfs.sql', 
851
                 'udf/mariadb/guarded.sql', 
851 852
                 'udf/mariadb/error_handler.sql', 
852 853
                 "${buildDir}/udf/mariadb/getFWDVersion.sql")
853 854
    outputs.file( "${buildDir}/udf/mariadb/udfs.sql" )
src/com/goldencode/p2j/persist/FQLPreprocessor.java 2023-02-12 14:08:04 +0000
3319 3319
            int idxPos = next.getIndexPos();
3320 3320
            parent = (HQLAst) next.getParent();
3321 3321
            
3322
            String checkErrorFn = "checkError";
3323
            String initErrorFn = "initError";
3324
            if (dialect instanceof P2JSQLServer2008Dialect)
3325
            {
3326
               checkErrorFn = "dbo.checkError_bb"; 
3327
               initErrorFn = "dbo.initError_b";
3328
            }
3329
            if (useSQLUdfs)
3330
            {
3331
               checkErrorFn = udfSchema + checkErrorFn;
3332
               initErrorFn = udfSchema + initErrorFn;
3333
            }
3322
            String checkErrorFn = (useSQLUdfs ? udfSchema : "") + dialect.checkErrorFn();
3323
            String initErrorFn = (useSQLUdfs ? udfSchema : "") + dialect.initErrorFn();
3334 3324
            
3335 3325
            HQLAst checkErrFunc = createAstNode(FUNCTION, checkErrorFn, null);
3336 3326
            HQLAst initErrFunc = createAstNode(FUNCTION, initErrorFn, checkErrFunc);
......
3365 3355
               // as operand of the logical operators:
3366 3356
               needSQLBooleanConversion.add(checkErrFunc);
3367 3357
            }
3368
            if (dialect instanceof P2JPostgreSQLDialect)
3358
            if (useSQLUdfs)
3369 3359
            {
3370 3360
               Iterator<Aast> it = next.iterator();
3371 3361
               while (it.hasNext())
......
6361 6351
      {
6362 6352
         fn = fn.substring(udfSchema.length());
6363 6353
      }
6354
      int pos = fn.lastIndexOf("_");
6355
      if (pos > 0)
6356
      {
6357
         fn = fn.substring(0, pos);
6358
      }
6359
               
6364 6360
      return UdfNamesHolder.UDF_NAMES.contains(fn); 
6365 6361
   }
6366 6362
   
src/com/goldencode/p2j/persist/dialect/Dialect.java 2023-02-12 15:00:42 +0000
95 95
**     SVL 20230110          P2JIndex.components() provides direct access to the components array in order to
96 96
**                           improve performance.
97 97
**     ECF 20230127          Added resolveBooleanConstant method.
98
**     IAS 20230208          Dialect-specific error handler support.
98 99
*/
99 100

  
100 101
/*
......
168 169
import com.goldencode.p2j.persist.sequence.SequenceHandler;
169 170
import com.goldencode.p2j.util.*;
170 171
import com.goldencode.p2j.util.ErrorManager.*;
172
import com.mchange.v2.c3p0.*;
171 173

  
172 174
/**
173 175
 * Extends the API defined by Hibernate's abstract <code>Dialect</code> class
......
403 405
    */
404 406
   public abstract boolean useWordTables();
405 407
   
408
   
406 409
   /**
407 410
    * Check if native UDFs are supported for the dialect
408 411
    * 
......
420 423
      return "";
421 424
   }
422 425
   
426
   /** 
427
    * Get name of the checkError UDF. 
428
    * @return the name of the checkError UDF.  
429
    */ 
430
   public String checkErrorFn()
431
   {
432
      return "checkError";
433
   }
434

  
435
   /** 
436
    * Get name of the initError UDF. 
437
    * @return the name of the initError UDF.  
438
    */ 
439
   public String initErrorFn()
440
   {
441
      return "initError";
442
   }
443

  
423 444
   /**
424 445
    * Check if the exception was caused by an error in UDF. 
425 446
    * @param e
......
493 514
   }
494 515

  
495 516
   /**
517
    * Get c3p0 ConnectionCustomizer class for the dialect.
518
    * 
519
    * @param cfg 
520
    *        Database configuration.
521
    * @return c3p0 ConnectionCustomizer class for the dialect.
522
    */
523
   public Class<? extends AbstractConnectionCustomizer> connectionCustomizer(DatabaseConfig cfg)
524
   {
525
      return null;
526
   }
527
   
528
   /**
529
    * Activate error handler at the database side.
530
    * @param  conn 
531
    *         Database connection
532
    * @throws SQLException
533
    *         on error.
534
    */
535
   public void activateErrorHandler(Connection conn)
536
   throws SQLException
537
   {
538
      
539
   }
540
   
541
   /**
542
    * Reset error handler at the database side.
543
    * @param  conn 
544
    *         Database connection
545
    * @throws SQLException
546
    *         on error.
547
    */
548
   public void resetErrorHandler(Connection conn)
549
   throws SQLException
550
   {
551
      
552
   }
553

  
554
   /**
496 555
    * Worker method for {@code generateTriggerDDLs()}. It generates the DDLs needed to create all
497 556
    * triggers in a database with a specific schema and using a certain dialect.
498 557
    *
src/com/goldencode/p2j/persist/dialect/FWDMariaDBConnectionCustomizer.java 2023-02-12 14:57:59 +0000
1
/*
2
** Module   : FWDMariaDBConnectionCustomizer
3
** Abstract : c3p0 connection customizer
4
**
5
** Copyright (c) 2023, Golden Code Development Corporation.
6
**
7
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
8
** 001 IAS 20230208 Created initial version.
9
*/
10

  
11
/*
12
** This program is free software: you can redistribute it and/or modify
13
** it under the terms of the GNU Affero General Public License as
14
** published by the Free Software Foundation, either version 3 of the
15
** License, or (at your option) any later version.
16
**
17
** This program is distributed in the hope that it will be useful,
18
** but WITHOUT ANY WARRANTY; without even the implied warranty of
19
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
** GNU Affero General Public License for more details.
21
**
22
** You may find a copy of the GNU Affero GPL version 3 at the following
23
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
24
**
25
** Additional terms under GNU Affero GPL version 3 section 7:
26
**
27
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
28
**   terms apply to the works covered under the License.  These additional terms
29
**   are non-permissive additional terms allowed under Section 7 of the GNU
30
**   Affero GPL version 3 and may not be removed by you.
31
**
32
**   0. Attribution Requirement.
33
**
34
**     You must preserve all legal notices or author attributions in the covered
35
**     work or Appropriate Legal Notices displayed by works containing the covered
36
**     work.  You may not remove from the covered work any author or developer
37
**     credit already included within the covered work.
38
**
39
**   1. No License To Use Trademarks.
40
**
41
**     This license does not grant any license or rights to use the trademarks
42
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
43
**     of Golden Code Development Corporation. You are not authorized to use the
44
**     name Golden Code, FWD, or the names of any author or contributor, for
45
**     publicity purposes without written authorization.
46
**
47
**   2. No Misrepresentation of Affiliation.
48
**
49
**     You may not represent yourself as Golden Code Development Corporation or FWD.
50
**
51
**     You may not represent yourself for publicity purposes as associated with
52
**     Golden Code Development Corporation, FWD, or any author or contributor to
53
**     the covered work, without written authorization.
54
**
55
**   3. No Misrepresentation of Source or Origin.
56
**
57
**     You may not represent the covered work as solely your work.  All modified
58
**     versions of the covered work must be marked in a reasonable way to make it
59
**     clear that the modified work is not originating from Golden Code Development
60
**     Corporation or FWD.  All modified versions must contain the notices of
61
**     attribution required in this license.
62
*/
63

  
64
package com.goldencode.p2j.persist.dialect;
65

  
66
import java.sql.*;
67
import org.slf4j.*;
68
import com.goldencode.p2j.*;
69
import com.mchange.v2.c3p0.*;
70

  
71
/**
72
 * Customizes the connection to database by setting up the {@code use.java.udfs} and {@code fwd.version}
73
 * SQL configuration variable. 
74
 */
75
public class FWDMariaDBConnectionCustomizer 
76
extends AbstractConnectionCustomizer
77
{
78
   /** Logger */
79
   private static final Logger LOG = LoggerFactory.getLogger(FWDPostgreSQLConnectionCustomizer.class);
80
   
81
   /**
82
    * Called immediately after a {@code Connection} is acquired from the underlying database for 
83
    * incorporation into the pool.
84
    *
85
    * @param   c
86
    *          Connection to be customized.
87
    * @param   parentDataSourceIdentityToken
88
    *          The parent data source identity token.
89
    */
90
   @Override
91
   public void onAcquire(Connection c, String parentDataSourceIdentityToken)
92
   throws java.lang.Exception 
93
   {
94
      // The database session user should be able to create temporary tables
95
      // This can be granted by GRANT CREATE TEMPORARY TABLES ON *.* TO 'fwd_user'@'%';
96
      try
97
      {
98
         c.prepareStatement(
99
            "create temporary table if not exists "
100
            + "temp_error_stack("
101
            + "id integer not null auto_increment, "
102
            + "state boolean not null, "
103
            + "fwd_error_ctx text default @fwd_error_ctx, "
104
            + "PRIMARY KEY (id)"
105
            + ")"
106
         ).executeUpdate();
107
      }
108
      catch(SQLException e)
109
      {
110
         LOG.warn("Failed to customize connection", e);
111
      }
112
   }
113
}
src/com/goldencode/p2j/persist/dialect/FWDPostgreSQLConnectionCustomizer.java 2023-02-08 16:19:49 +0000
1 1
/*
2
** Module   : FWDConnectionCustomizer.java
2
** Module   : FWDPostgreSQLConnectionCustomizer.java
3 3
** Abstract : c3p0 connection customizer
4 4
**
5
** Copyright (c) 2021-2022, Golden Code Development Corporation.
5
** Copyright (c) 2021-2023, Golden Code Development Corporation.
6 6
**
7 7
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
8 8
** 001 IAS 20210803 Created initial version.
9 9
**     OM  20220721 Added copyright statement, javadoc and updated formatting to GC standard.
10
*      IAS 20230202 Renamed
10 11
*/
11 12

  
12 13
/*
......
73 74
 * Customizes the connection to database by setting up the {@code use.java.udfs} and {@code fwd.version}
74 75
 * SQL configuration variable. 
75 76
 */
76
public class FWDConnectionCustomizer
77
public class FWDPostgreSQLConnectionCustomizer
77 78
extends AbstractConnectionCustomizer
78 79
{
79 80
   /** Logger */
80
   private static final Logger LOG = LoggerFactory.getLogger(FWDConnectionCustomizer.class);
81
   private static final Logger LOG = LoggerFactory.getLogger(FWDPostgreSQLConnectionCustomizer.class);
81 82
   
82 83
   /**
83 84
    * Called immediately after a {@code Connection} is acquired from the underlying database for 
src/com/goldencode/p2j/persist/dialect/MariaDbLenientDialect.java 2023-02-12 15:00:42 +0000
14 14
**     BS  20230126 Added support for SAVE CACHE.
15 15
**     ECF 20230127 Data type adjustment for SAVE CACHE.
16 16
**     OM  20230131 Code cleanup.
17
**     IAS 20230208 Added error handler support.
17 18
*/
18 19

  
19 20
/*
......
78 79
import com.goldencode.p2j.persist.sequence.*;
79 80
import com.goldencode.p2j.util.*;
80 81
import com.goldencode.p2j.util.ErrorManager.*;
82
import com.mchange.v2.c3p0.*;
83

  
81 84
import java.io.*;
82 85
import java.sql.*;
83 86
import java.sql.Date;
......
479 482
   }
480 483
   
481 484
   /**
485
    * Get c3p0 ConnectionCustomizer class for the dialect.
486
    * @param <T>
487
    *        Customizer class  
488
    * @param cfg 
489
    *        Database configuration.
490
    * @return c3p0 ConnectionCustomizer class for the dialect.
491
    */
492
   @Override
493
   public Class<? extends AbstractConnectionCustomizer> connectionCustomizer(DatabaseConfig cfg)
494
   {
495
      return FWDMariaDBConnectionCustomizer.class;
496
   }
497
   
498
   /**
499
    * Activate error handler at the database side.
500
    * @param  conn 
501
    *         Database connection
502
    * @throws SQLException
503
    *         on error.
504
    */
505
   @Override
506
   public void activateErrorHandler(Connection conn)
507
   throws SQLException
508
   {
509
      conn.prepareCall("{ call activateErrorHandler()}").executeUpdate();
510
   }
511
   
512
   /**
513
    * Reset error handler at the database side.
514
    * @param  conn 
515
    *         Database connection
516
    * @throws SQLException
517
    *         on error.
518
    */
519
   @Override
520
   public void resetErrorHandler(Connection conn)
521
   throws SQLException
522
   {
523
      conn.prepareCall("{ call resetErrorHandler()}").executeUpdate();
524
   }
525

  
526
   /**
482 527
    * Get a new instance of a splitter for DDL scripts. Reuses the splitter for PG dialect.
483 528
    * 
484 529
    * @return  A new instance of splitter for DDL scripts.
......
609 654
      return true;
610 655
   }
611 656
   
657
   /** 
658
    * Get name of the checkError UDF. 
659
    * @return the name of the checkError UDF.  
660
    */
661
   @Override
662
   public String checkErrorFn()
663
   {
664
      return "checkError_BB";
665
   }
666

  
667
   /** 
668
    * Get name of the initError UDF. 
669
    * @return the name of the initError UDF.  
670
    */ 
671
   @Override
672
   public String initErrorFn()
673
   {
674
      return "initError_B";
675
   }
676

  
612 677
   /**
613 678
    * Check if the exception was caused by an error in UDF.
614 679
    *
src/com/goldencode/p2j/persist/dialect/P2JPostgreSQLDialect.java 2023-02-12 15:00:56 +0000
123 123
**     OM  20221026          Excluded table name from index name by default. It will be added as needed by
124 124
**                           dialects.
125 125
**     RAA 20230109          Overrided method getSequenceSetValString().
126
**     IAS 20230208          Dialect-specific error handler support.
126 127
*/
127 128

  
128 129
/*
......
196 197
import com.goldencode.p2j.util.LogHelper;
197 198
import com.goldencode.p2j.util.ErrorManager.*;
198 199
import com.goldencode.util.*;
200
import com.mchange.v2.c3p0.*;
199 201
import com.goldencode.p2j.cfg.*;
200 202
import com.goldencode.p2j.convert.*;
201 203
import com.goldencode.p2j.directory.DirectoryService;
......
2032 2034
   }
2033 2035
   
2034 2036
   /**
2037
    * Get c3p0 ConnectionCustomizer class for the dialect.
2038
    * @param <T>
2039
    *        Customizer class  
2040
    * @param cfg 
2041
    *        Database configuration.
2042
    * @return c3p0 ConnectionCustomizer class for the dialect.
2043
    */
2044
   @Override
2045
   public Class<? extends AbstractConnectionCustomizer> connectionCustomizer(DatabaseConfig cfg)
2046
   {
2047
      return cfg.isUseJavaUDFs() ? null : FWDPostgreSQLConnectionCustomizer.class;
2048
   }
2049
   /**
2035 2050
    * Worker method for {@code generateTriggerDDLs()}. It generates the DDLs needed to create all
2036 2051
    * triggers in a database with a specific schema and using a certain dialect.
2037 2052
    *
src/com/goldencode/p2j/persist/dialect/P2JSQLServer2008Dialect.java 2023-02-12 15:01:53 +0000
43 43
**     RAA 20230109 Overrided method getSequenceSetValString().
44 44
**     SVL 20230110 P2JIndex.components() provides direct access to the components array in order to improve
45 45
**                  performance.
46
**     IAS 20230208 Dialect-specific error handler support.
46 47
*/
47 48

  
48 49
/*
......
1363 1364
      return false;
1364 1365
   }
1365 1366

  
1367
   /** 
1368
    * Get name of the checkError UDF. 
1369
    * @return the name of the checkError UDF.  
1370
    */
1371
   @Override
1372
   public String checkErrorFn()
1373
   {
1374
      return "dbo.checkError_bb";
1375
   }
1376

  
1377
   /** 
1378
    * Get name of the initError UDF. 
1379
    * @return the name of the initError UDF.  
1380
    */ 
1381
   @Override
1382
   public String initErrorFn()
1383
   {
1384
      return "dbo.initError_b";
1385
   }
1386

  
1366 1387
   /**
1367 1388
    * Check if the exception was caused by error in UDF. 
1368 1389
    * @param e
src/com/goldencode/p2j/persist/orm/FqlToSqlConverter.java 2023-02-12 15:02:55 +0000
47 47
**     SVL 20230108 Improved performance by replacing some "for-each" loops with indexed "for" loops.
48 48
**         20221031 Collected fields of "select" query.
49 49
**         20221101 Fixed possible NPE.
50
**     IAS 20230208 Dialect-specific error handler support.
50 51
*/
51 52

  
52 53
/*
......
271 272
    * Mutable session attributes' values used in the query 
272 273
    */
273 274
   private final List<SessionAttr> sessionAttrs = new ArrayList<>(); 
275

  
276
   /** The name of the checkError UDF with prepended dot */
277
   private final String _checkErrorFn;
278
   
279
   /** Flag indicating that the query contains error handling */
280
   private boolean containsErrorHandling = false;
281

  
274 282
   
275 283
   /**
276 284
    * The constructor is private. To create an instance of this class, use the {@code getInstance}
......
296 304
      this.generateUniqueSqlColumnNames = true;
297 305
      this.useWordTables = !SchemaDictionary.TEMP_TABLE_DB.equals(schema) && 
298 306
                           !db.isDirty() && !db.isMeta() && dialect.useWordTables();
307
      this._checkErrorFn = "." + dialect.checkErrorFn();
299 308
   }
300 309
   
301 310
   /**
......
347 356
   {
348 357
      return sessionAttrs;
349 358
   }
359

  
360
   /**
361
    * Checks if the query contains error handling.
362
    * 
363
    * @return  {@code true} if the query contains error handling.
364
    */
365
   public boolean containsErrorHandling()
366
   {
367
      return containsErrorHandling;
368
   }
350 369
   /**
351 370
    * Check if the query reads _UserTableStat VST. 
352 371
    * 
......
2481 2500
                  }
2482 2501
                  else 
2483 2502
                  {
2503
                     if (text.equals(dialect.checkErrorFn()) || text.endsWith(_checkErrorFn))
2504
                     {
2505
                        containsErrorHandling = true;
2506
                     }
2484 2507
                     sb.append(text);
2485 2508
                     sb.append("(");
2486 2509
                     if (next.getNumImmediateChildren() == 0)
src/com/goldencode/p2j/persist/orm/PooledDataSourceProvider.java 2023-02-12 15:04:54 +0000
2 2
** Module   : PooledDataSourceProvider.java
3 3
** Abstract : Implementation of DataSourceProvider that offers a pooled DataSource.
4 4
**
5
** Copyright (c) 2019-2021, Golden Code Development Corporation.
5
** Copyright (c) 2019-2023, Golden Code Development Corporation.
6 6
**
7 7
** -#- -I- --Date-- --------------------------------------Description----------------------------------------
8 8
** 001 ECF 20191001 Created initial version with basic runtime support.
......
11 11
**     ECF 20210910 Minor cleanup.
12 12
**     IAS 20220816 Do not use ConnectionCustomizer for non-PostgreSQL databases.
13 13
**     TW  20221024 Implement support for driver_properties.
14
**     IAS 20230208 Dialect-specific error handler support.
14 15
*/
15 16

  
16 17
/*
......
191 192
               }
192 193
            }
193 194
         }
194
         if (!cfg.isUseJavaUDFs() && 
195
                  (DatabaseManager.getDialect(database) instanceof P2JPostgreSQLDialect))
195
         Class<? extends AbstractConnectionCustomizer> customizer = 
196
                  DatabaseManager.getDialect(database).connectionCustomizer(cfg);
197
         if (ds.getConnectionCustomizerClassName() == null && customizer != null)
198
         {
199
            ds.setConnectionCustomizerClassName(customizer.getName());
200
         }
201
         if (!cfg.isUseJavaUDFs() )
196 202
         {
197 203
            extensions.putIfAbsent("useJavaUdfs", "n");
198
            if (ds.getConnectionCustomizerClassName() == null)
199
            {
200
               ds.setConnectionCustomizerClassName(FWDConnectionCustomizer.class.getName());
201
            }
202 204
         }
203 205
         if (!extensions.isEmpty())
204 206
         {
src/com/goldencode/p2j/persist/orm/Query.java 2023-02-12 15:04:48 +0000
2 2
** Module   : Query.java
3 3
** Abstract : Wrapper for FQL statements.
4 4
**
5
** Copyright (c) 2019-2022, Golden Code Development Corporation.
5
** Copyright (c) 2019-2023, Golden Code Development Corporation.
6 6
**
7 7
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
8 8
** 001 ECF 20191001 Created initial version with stubbed methods.
......
26 26
**     SBI 20221023 Added a usage of SQLQuery.uniqueResult(Session session, RowStructure rowStructure).
27 27
**     CA  20221031 Javadoc fixes.
28 28
**     IAS 20230209 Fixed ${TZ} placeholder value
29
**     IAS 20230208 Dialect-specific error handler support.
29 30
*/
30 31

  
31 32
/*
......
120 121
   /** Flag indicating that the query reads from _Lock VST */
121 122
   private boolean lockTableRead = false;
122 123

  
124
   /** Flag indicating that the query contains error handling */
125
   private boolean containsErrorHandling = false;
126
   
123 127
   /**
124 128
    * The maximum number of results accepted by the (SELECT) query. Used with {@code firstResult}
125 129
    * to configure result pagination.
......
353 357
            paramCount = fql2sql.getLastConversionParamCount();
354 358
            wasRewritten = fql2sql.isQueryWasRewritten();
355 359
            userTableStatRead = fql2sql.isUserTableStatRead();
360
            this.containsErrorHandling = fql2sql.containsErrorHandling();
356 361
            lockTableRead = fql2sql.isLockTableRead();
357 362
            if (!wasRewritten)
358 363
            {
359 364
               cache.accept(this);
360 365
            }
361
            sqlQuery = Session.createSQLQuery(sql, fql2sql.sessionAttrs(), fql2sql.getParameterPermutation());
366
            sqlQuery = Session.createSQLQuery(sql, fql2sql.sessionAttrs(), 
367
                     fql2sql.getParameterPermutation()).
368
                     containsErrorHandling(containsErrorHandling);
362 369
         };
363 370
         
364 371
         QUERY_PARSE.timer(op);
src/com/goldencode/p2j/persist/orm/SQLQuery.java 2023-02-12 15:04:05 +0000
51 51
**     CA  20230104 If a cached record is incomplete, get the full record from the database when a hydrate is
52 52
**                  is performed.
53 53
**     IAS 20230209 Fixed ${TZ} placeholder value
54
**     IAS 20230208 Dialect-specific error handler support.
54 55
*/
55 56

  
56 57
/*
......
172 173
   /** Mutable session attributes' values used in the query. */
173 174
   private final List<SessionAttr> sessionAttrs; 
174 175
   
176
   /** Flag indicating that the query contains error handling */
177
   private boolean containsErrorHandling = false;
178

  
175 179
   /** The {@code PreparedStatement}. */
176 180
   private PreparedStatement stmt;
177 181
   
......
214 218
   }
215 219
   
216 220
   /**
221
    * Set the value of the flag indicating that the query contains error handling.
222
    * @param value
223
    *        The new value of the flag;
224
    * @return <code>this</code>
225
    */
226
   public SQLQuery containsErrorHandling(boolean value)
227
   {
228
      this.containsErrorHandling = value;
229
      return this;
230
   }
231
   
232
   /**
217 233
    * Checks if the query can raise {@code SQLWarning}.
218 234
    * 
219 235
    * @return  {@code true} if the query can raise {@code SQLWarning}.
......
237 253
      return this;
238 254
   }
239 255
   
256

  
240 257
   /**
241 258
    * Expand placeholder.
242 259
    * @param dialect 
......
319 336
      
320 337
      try
321 338
      {
339
         activateErrorHandler(session);
322 340
         stmt = conn.prepareStatement(sql, scrollMode, readOnlyMode);
323 341
         setParameters(stmt, false);
324 342
         
......
332 350
         
333 351
         ResultSet resultSet = resultSetArray[0];
334 352
         reportSQLWarnings(session);
335
         return new ScrollableResults<>(stmt, resultSet, rowStructure, session);
353
         return new ScrollableResults<T>(stmt, resultSet, rowStructure, session).
354
                    onClose(() -> {resetErrorHandler(session); return null;});
336 355
      }
337 356
      catch (SQLException exc)
338 357
      {
......
344 363
         }
345 364
         throw new PersistenceException("Error scrolling", exc);
346 365
      }
366
//      finally
367
//      {
368
//         resetErrorHandler(session);
369
//      }
347 370
   }
348 371
   
349 372
   /**
......
372 395
      
373 396
      try
374 397
      {
398
         activateErrorHandler(session);
375 399
         stmt = conn.prepareStatement(sql);
376 400
         setParameters(stmt, false);
377 401
         
......
381 405
            log(session.getDatabase(), stmt, () -> resultSetArray[0] = stmt.executeQuery());
382 406
         
383 407
         ResultSet resultSet = resultSetArray[0];
384
         return new ScrollableResults<>(stmt, resultSet, rowStructure, session);
408
         return new ScrollableResults<T>(stmt, resultSet, rowStructure, session).
409
                  onClose(() -> {resetErrorHandler(session); return null;});
385 410
      }
386 411
      catch (SQLException exc)
387 412
      {
388 413
         close();
389 414
         throw new PersistenceException("Error scrolling", exc);
390 415
      }
416
//      finally 
417
//      {
418
//         resetErrorHandler(session);
419
//      }
391 420
   }
392 421
   
393 422
   /**
......
439 468
      
440 469
      try
441 470
      {
471
         activateErrorHandler(session);
442 472
         stmt = conn.prepareStatement(sql);
443 473
         setParameters(stmt, false);
444 474
         
......
489 519
      finally
490 520
      {
491 521
         close();
522
         resetErrorHandler(session);
492 523
      }
493 524
   }
494 525
   
......
511 542
      
512 543
      try
513 544
      {
545
         activateErrorHandler(session);
514 546
         stmt = conn.prepareStatement(sql);
515 547
         setParameters(stmt, true);
516 548
         
......
529 561
      finally
530 562
      {
531 563
         close();
564
         resetErrorHandler(session);
532 565
      }
533 566
   }
534 567
   
......
562 595
      
563 596
      try
564 597
      {
598
         activateErrorHandler(session);
565 599
         int rowSize = rowStructure.size();
566 600
         List<T> ret = new ArrayList<>();
567 601
         stmt = conn.prepareStatement(sql);
......
640 674
      }
641 675
      finally
642 676
      {
677
         resetErrorHandler(session);
643 678
         close();
644 679
      }
645 680
   }
......
1022 1057
   }
1023 1058
   
1024 1059
   /**
1060
    * Activate error handler at the database side.
1061
    * @param  session 
1062
    *         Database session
1063
    * @throws SQLException
1064
    *         on error.
1065
    * @throws PersistenceException 
1066
    *         on error.
1067
    */
1068
   private void activateErrorHandler(Session session)
1069
   throws SQLException, PersistenceException
1070
   {
1071
      if (!containsErrorHandling)
1072
      {
1073
         return;
1074
      }
1075
      Query.getDialect(session).activateErrorHandler(session.getConnection());  
1076
   }
1077
   
1078
   /**
1079
    * Reset error handler at the database side.
1080
    * @param  session 
1081
    *         Database session
1082
    * @throws SQLException
1083
    *         on error.
1084
    * @throws PersistenceException 
1085
    *         on error.
1086
    */
1087
   public void resetErrorHandler(Session session)
1088
   throws PersistenceException
1089
   {
1090
      if (!containsErrorHandling)
1091
      {
1092
         return;
1093
      }
1094
      try
1095
      {
1096
         Query.getDialect(session).activateErrorHandler(session.getConnection());
1097
      }
1098
      catch (SQLException e)
1099
      {
1100
         throw new PersistenceException("Failed to reset error handler", e);
1101
      }  
1102
   }
1103
   /**
1025 1104
    * Sets the value for a parameter at a specified position in a statement. The process is done in recursive
1026 1105
    * manner for arrays and {@code List}s. The {@code pos} is incremented automatically for each scalar
1027 1106
    * parameter configured.
src/com/goldencode/p2j/persist/orm/ScrollableResults.java 2023-02-12 15:04:30 +0000
2 2
** Module   : ScrollableResults.java
3 3
** Abstract : Allows scrollable access to result set.
4 4
**
5
** Copyright (c) 2019-2022, Golden Code Development Corporation.
5
** Copyright (c) 2019-2023, Golden Code Development Corporation.
6 6
**
7 7
** -#- -I- --Date-- ---------------------------------Description---------------------------------
8 8
** 001 ECF 20191001 Created initial version, with stubbed methods.
9 9
**     OM  20191111 Added method implementation.
10 10
** 002 SBI 20220811 Added new version of get method to retrieve selected columns from a row.
11 11
**         20221023 Added a usage of SQLQuery.hydrateRecord(ResultSet, RowStructure, int, Session).
12
**     IAS 20230208          Dialect-specific error handler support.
12 13
*/
13 14

  
14 15
/*
......
96 97
   /** The {@code Session} to be used.*/
97 98
   private final Session session;
98 99
   
100
   /** On close hook*/
101
   private SandboxRun<Void> onClose = () -> null;
102
   
99 103
   /**
100 104
    * Constructs a {@code ScrollableResults} object for further use.
101 105
    * 
......
129 133
   }
130 134
   
131 135
   /**
136
    * Set on close hook
137
    * @param hook
138
    *        new hook;
139
    * @return <code>this</code>
140
    */
141
   public ScrollableResults<T> onClose(SandboxRun<Void> hook)
142
   {
143
      this.onClose = hook;
144
      return this;
145
   }
146
   /**
132 147
    * Go to result row.
133 148
    *
134 149
    * @return  {@code true} if there is a result under the cursor and {@code false} otherwise
......
339 354

  
340 355
   /**
341 356
    * Obtain the value of a {@code i}-th column of the current row.
357
    * @param i 
358
    *        column number
359
    * @param tClass 
360
    *        column 
342 361
    *
343 362
    * @return  The value on {@code i}-th column of the current row if {@code i} and current row
344 363
    *          are valid and {@code null} otherwise.
345 364
    */
346
   public T get(int i, Class<T> tClass)
365
   public T get(int i, Class<T>tClass)
347 366
   {
348 367
      return execute(() -> rs.getObject(i + 1, tClass), null);
349 368
   }
......
409 428
   public void close()
410 429
   throws PersistenceException
411 430
   {
412
      execute(() -> { stmt.close(); return null; }, null);
431
      execute(() -> { stmt.close(); onClose.run(); return null; }, null);
413 432
   }
414 433
   
415 434
   /**
udf/mariadb/error_handler.sql 2023-02-12 14:29:52 +0000
1 1
/*
2 2
** Module   : error-handlers.sql
3
** Abstract : 'Native' versions of the ErrorHandler-based Java UDFs
3
** Abstract : 'Native' versions of the ErrorHandler-based Java UDFs (MariaDB version)
4 4
**
5
** Copyright (c) 2021, Golden Code Development Corporation.
5
** Copyright (c) 2023, Golden Code Development Corporation.
6 6
**
7 7
** -#- -I- --Date-- --------------------------------Description----------------------------------
8
** 001 IAS 20210803 Created initial version.
8
** 001 IAS 20230208 Created initial version.
9 9
*/
10 10
/*
11 11
** This program is free software: you can redistribute it and/or modify
......
62 62
/**
63 63
 * Check if the error stack is active
64 64
 */
65
##CREATE OR REPLACE FUNCTION udf.error_handler_active()
66
CREATE OR REPLACE FUNCTION error_handler_active() ##!! TODO
67
##RETURNS boolean 
65
CREATE OR REPLACE FUNCTION error_handler_active()
68 66
RETURNS BOOLEAN
69 67
DETERMINISTIC
70 68
BEGIN
71
  RETURN null;
69
  RETURN true; -- exists(select * from temp_error_stack where fwd_error_ctx = @fwd_error_ctx);
72 70
END;
73 71
$$
74 72

  
75
##AS $function$
76
##select exists (
77
##   select 1
78
##   from   information_schema.tables 
79
##   where  table_schema like 'pg_temp_%'
80
##   and table_name='temp_error_stack'
81
##)
82
##$function$
83 73

  
84 74
/**
85 75
 * A special wrapper function for a UDF called
......
118 108
 * @return  false if an error occurred in this scope;
119 109
 *          otherwise, the result of the boolean sub-expression.
120 110
 */
121
##CREATE OR REPLACE FUNCTION udf.initerror(state boolean) 
122
CREATE OR REPLACE FUNCTION initerror_B(state BOOLEAN) ##!! TODO
123
##RETURNS boolean 
111
CREATE OR REPLACE FUNCTION initError_B(state BOOLEAN)
124 112
RETURNS BOOLEAN
125 113
DETERMINISTIC
126 114
BEGIN
127
  RETURN null;
115
  call initError_P(state);
116
  return true;
128 117
END;
129 118
$$
130 119

  
131
##AS $function$
132
##begin
133
##   if not udf.error_handler_active() then  
134
##      create temporary table if not exists temp_error_stack(id serial, state boolean not null) on commit drop;
135
##   end if;
136
##   insert into temp_error_stack(state) values (state);
137
##   return true;
138
##end;
139
##$function$
120
CREATE OR REPLACE PROCEDURE initError_P(state BOOLEAN)
121
DETERMINISTIC
122
BEGIN
123
  insert into temp_error_stack(state,fwd_error_ctx) values (state, @fwd_error_ctx);
124
END;
125
$$
140 126

  
141 127
/**
142 128
 * Initialize the error flag stack for the current function scope by
......
147 133
 * 
148 134
 * @return  Boolean.TRUE.
149 135
 */
150
##CREATE OR REPLACE FUNCTION udf.checkerror(init boolean, result boolean)
151
CREATE OR REPLACE FUNCTION checkerror_BB(init BOOLEAN, result BOOLEAN) ##!! TODO
152
##RETURNS boolean 
136
CREATE OR REPLACE FUNCTION checkError_BB(init BOOLEAN, result BOOLEAN)
153 137
RETURNS BOOLEAN
154 138
DETERMINISTIC
155 139
BEGIN
156
  RETURN null;
157
END;
158
$$
159

  
160
##AS $function$
161
##declare top bigint;
162
##declare val boolean;
163
##begin
164
##   if not udf.error_handler_active() then  
165
##      create temporary table if not exists temp_error_stack(id serial, state boolean not null) on commit drop;
166
##   end if;
167
##   top := (select max(id) from temp_error_stack);
168
##   if top is null then
169
##      return null;
170
##--    raise exception 'Error stack is empty';
171
##   end if;
172
##   val := (select state from temp_error_stack where id = top);
173
##   delete from temp_error_stack where id = top;
174
##   return case when val then false else result end;
175
##end;
176
##$function$
140
   declare top integer;
141
   declare val boolean;
142
   set top = (select max(id) from temp_error_stack);
143
   if top is null then
144
      return null;
145
   end if;
146
   set val = (select state from temp_error_stack where id = top);
147
   delete from temp_error_stack where id = top;
148
   return if(val, false, result);
149
END;
150
$$
151

  
152
/**
153
 * Activate error handler
154
 */
155
CREATE OR REPLACE PROCEDURE activateErrorHandler()
156
DETERMINISTIC
157
begin
158
   truncate table temp_error_stack;
159
   set @fwd_error_ctx = uuid();  
160
END;
161
$$
162

  
163
/**
164
 * Reset error handler
165
 */
166
CREATE OR REPLACE PROCEDURE resetErrorHandler()
167
DETERMINISTIC
168
begin
169
   truncate table temp_error_stack;
170
   set @fwd_error_ctx = null;  
171
END;
172
$$
177 173

  
udf/mariadb/guard.awk 2023-02-12 13:38:24 +0000
1
# Module   : guard.awk
2
# Abstract : awk script for generating 'guarded' versions of the MariaDB UDFs
3
#
4
# Copyright (c) 2023, Golden Code Development Corporation.
5
#
6
# -#- -I- --Date-- --------------------------------Description----------------------------------
7
# 001 IAS 20230308 Created initial version.
8
#
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU Affero General Public License as
11
# published by the Free Software Foundation, either version 3 of the
12
# License, or (at your option) any later version.
13
#
14
# This program is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
# GNU Affero General Public License for more details.
18
#
19
# You may find a copy of the GNU Affero GPL version 3 at the following
20
# location: https://www.gnu.org/licenses/agpl-3.0.en.html
21
#
22
# Additional terms under GNU Affero GPL version 3 section 7:
23
#
24
#   Under Section 7 of the GNU Affero GPL version 3, the following additional
25
#   terms apply to the works covered under the License.  These additional terms
26
#   are non-permissive additional terms allowed under Section 7 of the GNU
27
#   Affero GPL version 3 and may not be removed by you.
28
#
29
#   0. Attribution Requirement.
30
#
31
#     You must preserve all legal notices or author attributions in the covered
32
#     work or Appropriate Legal Notices displayed by works containing the covered
33
#     work.  You may not remove from the covered work any author or developer
34
#     credit already included within the covered work.
35
#
36
#   1. No License To Use Trademarks.
37
#
38
#     This license does not grant any license or rights to use the trademarks
39
#     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
40
#     of Golden Code Development Corporation. You are not authorized to use the
41
#     name Golden Code, FWD, or the names of any author or contributor, for
42
#     publicity purposes without written authorization.
43
#
44
#   2. No Misrepresentation of Affiliation.
45
#
46
#     You may not represent yourself as Golden Code Development Corporation or FWD.
47
#
48
#     You may not represent yourself for publicity purposes as associated with
49
#     Golden Code Development Corporation, FWD, or any author or contributor to
50
#     the covered work, without written authorization.
51
#
52
#   3. No Misrepresentation of Source or Origin.
53
#
54
#     You may not represent the covered work as solely your work.  All modified
55
#     versions of the covered work must be marked in a reasonable way to make it
56
#     clear that the modified work is not originating from Golden Code Development
57
#     Corporation or FWD.  All modified versions must contain the notices of
58
#     attribution required in this license.
59

  
60
# Generates 'guarded' versions of the UDFs
61
# Usage: awk -f guard.awk <udfs.sql >guarded.sql
62

  
63
BEGIN {
64
print "-- The 'guarded' versions of SQL UDFs";
65
print "-- Generated automatically from udfs.sql with guard.awk script.";
66
print "-- DO NOT MODIFY!";
67
}
68

  
69
/\/\*/, /\*\// {
70
   print $0;
71
}
72

  
73
match($0, "^CREATE *OR *REPLACE *FUNCTION *(.*)$", m) {
74
   f = m[1];
75
   print "create or replace function guarded_" f; 
76
}
77
/^RETURNS/ {
78
   print tolower($0);
79
   s = f; 
80
   gsub(/\(50, 10\)/, "", s); 
81
   gsub(/\(3\)/, "", s); 
82
   gsub(/ JSON/, "", s);
83
   gsub(/ [a-zA-Z]*\)/, ")", s);
84
   gsub(/ [^,]*, */, ", ", s); 
85
   gsub(/##!! TODO/, "", s);
86
   print "deterministic";
87
   print "begin";
88
   print "declare tmp text;"
89
   print "declare exit handler for SQLEXCEPTION";
90
   print "  begin";
91
   print "    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;";
92
   print "    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);";
93
   print "    if error_handler_active() then";
94
   print "      call initError_P(true);";
95
   print "      signal sqlstate '01FWD' set message_text = tmp;";
96
   print "      return null;";
97
   print "    else";
98
   print "      signal sqlstate 'FWD00' set message_text = tmp;";
99
   print "    end if;";
100
   print "  end;";
101
   print "  return " s ";";
102
   print "end;";
103
   print "$$";
104
}
udf/mariadb/guarded.sql 2023-02-12 13:42:03 +0000
1
-- The 'guarded' versions of SQL UDFs
2
-- Generated automatically from udfs.sql with guard.awk script.
3
-- DO NOT MODIFY!
4
/*
5
** Module   : udfs.sql
6
** Abstract : 'native' versions of the Java UDFs for MariaDB
7
**
8
** Copyright (c) 2022, Golden Code Development Corporation.
9
**
10
** -#- -I- --Date-- --------------------------------Description----------------------------------
11
** 001 IAS 20220810 Created UDFs' templates.
12
*/
13
/*
14
** This program is free software: you can redistribute it and/or modify
15
** it under the terms of the GNU Affero General Public License as
16
** published by the Free Software Foundation, either version 3 of the
17
** License, or (at your option) any later version.
18
**
19
** This program is distributed in the hope that it will be useful,
20
** but WITHOUT ANY WARRANTY; without even the implied warranty of
21
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
** GNU Affero General Public License for more details.
23
**
24
** You may find a copy of the GNU Affero GPL version 3 at the following
25
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
26
**
27
** Additional terms under GNU Affero GPL version 3 section 7:
28
**
29
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
30
**   terms apply to the works covered under the License.  These additional terms
31
**   are non-permissive additional terms allowed under Section 7 of the GNU
32
**   Affero GPL version 3 and may not be removed by you.
33
**
34
**   0. Attribution Requirement.
35
**
36
**     You must preserve all legal notices or author attributions in the covered
37
**     work or Appropriate Legal Notices displayed by works containing the covered
38
**     work.  You may not remove from the covered work any author or developer
39
**     credit already included within the covered work.
40
**
41
**   1. No License To Use Trademarks.
42
**
43
**     This license does not grant any license or rights to use the trademarks
44
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
45
**     of Golden Code Development Corporation. You are not authorized to use the
46
**     name Golden Code, FWD, or the names of any author or contributor, for
47
**     publicity purposes without written authorization.
48
**
49
**   2. No Misrepresentation of Affiliation.
50
**
51
**     You may not represent yourself as Golden Code Development Corporation or FWD.
52
**
53
**     You may not represent yourself for publicity purposes as associated with
54
**     Golden Code Development Corporation, FWD, or any author or contributor to
55
**     the covered work, without written authorization.
56
**
57
**   3. No Misrepresentation of Source or Origin.
58
**
59
**     You may not represent the covered work as solely your work.  All modified
60
**     versions of the covered work must be marked in a reasonable way to make it
61
**     clear that the modified work is not originating from Golden Code Development
62
**     Corporation or FWD.  All modified versions must contain the notices of
63
**     attribution required in this license.
64
*/
65
/**
66
 * For debugging.
67
 * See the commented table definition above 
68
 */
69
/**
70
 * Convert 4GL 'matches' pattern to regex
71
 */
72
create or replace function guarded_regex_tb(s TEXT, windows BOOLEAN)
73
returns text
74
deterministic
75
begin
76
declare tmp text;
77
declare exit handler for SQLEXCEPTION
78
  begin
79
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
80
    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);
81
    if error_handler_active() then
82
      call initError_P(true);
83
      signal sqlstate '01FWD' set message_text = tmp;
84
      return null;
85
    else
86
      signal sqlstate 'FWD00' set message_text = tmp;
87
    end if;
88
  end;
89
  return regex_tb(s, windows);
90
end;
91
$$
92
/**
93
 * Convert 4GL 'CAN-DO' function pattern to regex
94
 */
95
create or replace function guarded_regex_t(s TEXT)
96
returns text
97
deterministic
98
begin
99
declare tmp text;
100
declare exit handler for SQLEXCEPTION
101
  begin
102
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
103
    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);
104
    if error_handler_active() then
105
      call initError_P(true);
106
      signal sqlstate '01FWD' set message_text = tmp;
107
      return null;
108
    else
109
      signal sqlstate 'FWD00' set message_text = tmp;
110
    end if;
111
  end;
112
  return regex_t(s);
113
end;
114
$$
115
/**
116
 * Transform the given integer into a string as the time value 
117
 */
118
create or replace function guarded_totimestring_lti(v BIGINT, fmt TEXT, tz INTEGER)
119
returns text
120
deterministic
121
begin
122
declare tmp text;
123
declare exit handler for SQLEXCEPTION
124
  begin
125
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
126
    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);
127
    if error_handler_active() then
128
      call initError_P(true);
129
      signal sqlstate '01FWD' set message_text = tmp;
130
      return null;
131
    else
132
      signal sqlstate 'FWD00' set message_text = tmp;
133
    end if;
134
  end;
135
  return totimestring_lti(v, fmt, tz);
136
end;
137
$$
138
/**
139
 * Computes a new date by adding respective number of time units.
140
 * Corresponds to the 4GL ADD-INTERVAL function.
141
 * 
142
 * @param   initial
143
 *          The first date.
144
 * @param   amount
145
 *          The count of units to be added.
146
 * @param   unit
147
 *          The unit to measure the interval.
148
 *          
149
 * @return  The date that is amount units further in time. 
150
 */
151
create or replace function guarded_addinterval_dit(initial DATE, amount INTEGER, unit TEXT)
152
returns date
153
deterministic
154
begin
155
declare tmp text;
156
declare exit handler for SQLEXCEPTION
157
  begin
158
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
159
    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);
160
    if error_handler_active() then
161
      call initError_P(true);
162
      signal sqlstate '01FWD' set message_text = tmp;
163
      return null;
164
    else
165
      signal sqlstate 'FWD00' set message_text = tmp;
166
    end if;
167
  end;
168
  return addinterval_dit(initial, amount, unit);
169
end;
170
$$
171
/**
172
 * Computes a new date by adding respective number of time units.
173
 * Corresponds to the 4GL ADD-INTERVAL function.
174
 * 
175
 * @param   initial
176
 *          The first date.
177
 * @param   amount
178
 *          The count of units to be added.
179
 * @param   unit
180
 *          The unit to measure the interval.
181
 *          
182
 * @return  The date that is amount units further in time. 
183
 */
184
create or replace function guarded_addinterval_dlt(initial DATE, amount BIGINT, unit TEXT)
185
returns date
186
deterministic
187
begin
188
declare tmp text;
189
declare exit handler for SQLEXCEPTION
190
  begin
191
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
192
    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);
193
    if error_handler_active() then
194
      call initError_P(true);
195
      signal sqlstate '01FWD' set message_text = tmp;
196
      return null;
197
    else
198
      signal sqlstate 'FWD00' set message_text = tmp;
199
    end if;
200
  end;
201
  return addinterval_dlt(initial, amount, unit);
202
end;
203
$$
204
/**
205
 * Computes a new date by adding respective number of time units.
206
 * Corresponds to the 4GL ADD-INTERVAL function.
207
 * 
208
 * @param   initial
209
 *          The first date.
210
 * @param   amount
211
 *          The count of units to be added.
212
 * @param   unit
213
 *          The unit to measure the interval.
214
 *          
215
 * @return  The date that is amount units further in time. 
216
 */
217
create or replace function guarded_addinterval_sit(initial TIMESTAMP(3), amount INTEGER, unit TEXT)
218
returns timestamp(3)
219
deterministic
220
begin
221
declare tmp text;
222
declare exit handler for SQLEXCEPTION
223
  begin
224
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
225
    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);
226
    if error_handler_active() then
227
      call initError_P(true);
228
      signal sqlstate '01FWD' set message_text = tmp;
229
      return null;
230
    else
231
      signal sqlstate 'FWD00' set message_text = tmp;
232
    end if;
233
  end;
234
  return addinterval_sit(initial, amount, unit);
235
end;
236
$$
237
/**
238
 * Computes a new date by adding respective number of time units.
239
 * Corresponds to the 4GL ADD-INTERVAL function.
240
 * 
241
 * @param   initial
242
 *          The first date.
243
 * @param   amount
244
 *          The count of units to be added.
245
 * @param   unit
246
 *          The unit to measure the interval.
247
 *          
248
 * @return  The date that is amount units further in time. 
249
 */
250
create or replace function guarded_addinterval_slt(initial TIMESTAMP(3), amount BIGINT, unit TEXT)
251
returns timestamp(3)
252
deterministic
253
begin
254
declare tmp text;
255
declare exit handler for SQLEXCEPTION
256
  begin
257
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
258
    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);
259
    if error_handler_active() then
260
      call initError_P(true);
261
      signal sqlstate '01FWD' set message_text = tmp;
262
      return null;
263
    else
264
      signal sqlstate 'FWD00' set message_text = tmp;
265
    end if;
266
  end;
267
  return addinterval_slt(initial, amount, unit);
268
end;
269
$$
270
/**
271
 * Test whether one string begins with another case insensitively.
272
 * Corresponds to the 4GL BEGINS operator
273
 */
274
create or replace function guarded_begins_tt(a TEXT, b TEXT)
275
returns boolean
276
deterministic
277
begin
278
declare tmp text;
279
declare exit handler for SQLEXCEPTION
280
  begin
281
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
282
    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);
283
    if error_handler_active() then
284
      call initError_P(true);
285
      signal sqlstate '01FWD' set message_text = tmp;
286
      return null;
287
    else
288
      signal sqlstate 'FWD00' set message_text = tmp;
289
    end if;
290
  end;
291
  return begins_tt(a, b);
292
end;
293
$$
294
/**
295
 * Test whether one string begins with another, optionally taking case into account.
296
 * Corresponds to the 4GL BEGINS operator
297
 */
298
create or replace function guarded_begins_ttb(a TEXT, b TEXT, cs BOOLEAN)
299
returns boolean
300
deterministic
301
begin
302
declare tmp text;
303
declare exit handler for SQLEXCEPTION
304
  begin
305
    GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,  @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
306
    set tmp = sformat('ERROR {} ({}): {}', @sqlstate, @errno, @text);
307
    if error_handler_active() then
308
      call initError_P(true);
309
      signal sqlstate '01FWD' set message_text = tmp;
310
      return null;
311
    else
312
      signal sqlstate 'FWD00' set message_text = tmp;
313
    end if;
314
  end;
315
  return begins_ttb(a, b, cs);
316
end;
317
$$
318
/**
319
 * Returns the uppercase representation of the string.
320
 * Corresponds to the 4GL CAPS function
321
 */
322
create or replace function guarded_caps_t(t TEXT)
323
returns text
324
deterministic
... This diff was truncated because it exceeds the maximum size that can be displayed.