001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.util.dao.orm;
016    
017    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
018    import com.liferay.portal.kernel.dao.orm.QueryDefinition;
019    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
020    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.util.ArrayUtil;
024    import com.liferay.portal.kernel.util.CharPool;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.OrderByComparator;
027    import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
028    import com.liferay.portal.kernel.util.PropsKeys;
029    import com.liferay.portal.kernel.util.PropsUtil;
030    import com.liferay.portal.kernel.util.StreamUtil;
031    import com.liferay.portal.kernel.util.StringBundler;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.StringUtil;
034    import com.liferay.portal.kernel.util.Validator;
035    import com.liferay.portal.kernel.workflow.WorkflowConstants;
036    import com.liferay.portal.kernel.xml.Document;
037    import com.liferay.portal.kernel.xml.Element;
038    import com.liferay.portal.kernel.xml.UnsecureSAXReaderUtil;
039    import com.liferay.portal.util.PortalUtil;
040    
041    import java.io.IOException;
042    import java.io.InputStream;
043    
044    import java.sql.Connection;
045    import java.sql.DatabaseMetaData;
046    import java.sql.SQLException;
047    
048    import java.util.ArrayList;
049    import java.util.HashMap;
050    import java.util.List;
051    import java.util.Map;
052    import java.util.Properties;
053    
054    /**
055     * @author Brian Wing Shun Chan
056     * @author Bruno Farache
057     * @author Raymond Aug??
058     */
059    public class CustomSQL {
060    
061            public static final String DB2_FUNCTION_IS_NOT_NULL =
062                    "CAST(? AS VARCHAR(32672)) IS NOT NULL";
063    
064            public static final String DB2_FUNCTION_IS_NULL =
065                    "CAST(? AS VARCHAR(32672)) IS NULL";
066    
067            public static final String INFORMIX_FUNCTION_IS_NOT_NULL =
068                    "NOT lportal.isnull(?)";
069    
070            public static final String INFORMIX_FUNCTION_IS_NULL = "lportal.isnull(?)";
071    
072            public static final String MYSQL_FUNCTION_IS_NOT_NULL =
073                    "IFNULL(?, '1') = '0'";
074    
075            public static final String MYSQL_FUNCTION_IS_NULL = "IFNULL(?, '1') = '1'";
076    
077            public static final String SYBASE_FUNCTION_IS_NOT_NULL =
078                    "CONVERT(VARCHAR,?) IS NOT NULL";
079    
080            public static final String SYBASE_FUNCTION_IS_NULL =
081                    "CONVERT(VARCHAR,?) IS NULL";
082    
083            public CustomSQL() throws SQLException {
084                    reloadCustomSQL();
085            }
086    
087            public String appendCriteria(String sql, String criteria) {
088                    if (Validator.isNull(criteria)) {
089                            return sql;
090                    }
091    
092                    if (!criteria.startsWith(StringPool.SPACE)) {
093                            criteria = StringPool.SPACE.concat(criteria);
094                    }
095    
096                    if (!criteria.endsWith(StringPool.SPACE)) {
097                            criteria = criteria.concat(StringPool.SPACE);
098                    }
099    
100                    int pos = sql.indexOf(_GROUP_BY_CLAUSE);
101    
102                    if (pos != -1) {
103                            return sql.substring(0, pos + 1).concat(criteria).concat(
104                                    sql.substring(pos + 1));
105                    }
106    
107                    pos = sql.indexOf(_ORDER_BY_CLAUSE);
108    
109                    if (pos != -1) {
110                            return sql.substring(0, pos + 1).concat(criteria).concat(
111                                    sql.substring(pos + 1));
112                    }
113    
114                    return sql.concat(criteria);
115            }
116    
117            public String get(String id) {
118                    return _sqlPool.get(id);
119            }
120    
121            public String get(String id, QueryDefinition queryDefinition) {
122                    return get(id, queryDefinition, StringPool.BLANK);
123            }
124    
125            public String get(
126                    String id, QueryDefinition queryDefinition, String tableName) {
127    
128                    String sql = get(id);
129    
130                    if (!Validator.isBlank(tableName) &&
131                            !tableName.endsWith(StringPool.PERIOD)) {
132    
133                            tableName = tableName.concat(StringPool.PERIOD);
134                    }
135    
136                    if (queryDefinition.getStatus() == WorkflowConstants.STATUS_ANY) {
137                            sql = sql.replace(_STATUS_KEYWORD, _STATUS_CONDITION_EMPTY);
138                    }
139                    else {
140                            if (queryDefinition.isExcludeStatus()) {
141                                    sql = sql.replace(
142                                            _STATUS_KEYWORD,
143                                            tableName.concat(_STATUS_CONDITION_INVERSE));
144                            }
145                            else {
146                                    sql = sql.replace(
147                                            _STATUS_KEYWORD,
148                                            tableName.concat(_STATUS_CONDITION_DEFAULT));
149                            }
150                    }
151    
152                    if (queryDefinition.getOwnerUserId() > 0) {
153                            if (queryDefinition.isIncludeOwner()) {
154                                    StringBundler sb = new StringBundler(7);
155    
156                                    sb.append(StringPool.OPEN_PARENTHESIS);
157                                    sb.append(tableName);
158                                    sb.append(_OWNER_USER_ID_CONDITION_DEFAULT);
159                                    sb.append(" AND ");
160                                    sb.append(tableName);
161                                    sb.append(_STATUS_CONDITION_INVERSE);
162                                    sb.append(StringPool.CLOSE_PARENTHESIS);
163    
164                                    sql = sql.replace(_OWNER_USER_ID_KEYWORD, sb.toString());
165    
166                                    sql = sql.replace(_OWNER_USER_ID_AND_OR_CONNECTOR, " OR ");
167                            }
168                            else {
169                                    sql = sql.replace(
170                                            _OWNER_USER_ID_KEYWORD,
171                                            tableName.concat(_OWNER_USER_ID_CONDITION_DEFAULT));
172    
173                                    sql = sql.replace(_OWNER_USER_ID_AND_OR_CONNECTOR, " AND ");
174                            }
175                    }
176                    else {
177                            sql = sql.replace(_OWNER_USER_ID_KEYWORD, StringPool.BLANK);
178    
179                            sql = sql.replace(
180                                    _OWNER_USER_ID_AND_OR_CONNECTOR, StringPool.BLANK);
181                    }
182    
183                    return sql;
184            }
185    
186            /**
187             * Returns <code>true</code> if Hibernate is connecting to a DB2 database.
188             *
189             * @return <code>true</code> if Hibernate is connecting to a DB2 database
190             */
191            public boolean isVendorDB2() {
192                    return _vendorDB2;
193            }
194    
195            /**
196             * Returns <code>true</code> if Hibernate is connecting to a Hypersonic
197             * database.
198             *
199             * @return <code>true</code> if Hibernate is connecting to a Hypersonic
200             *         database
201             */
202            public boolean isVendorHSQL() {
203                    return _vendorHSQL;
204            }
205    
206            /**
207             * Returns <code>true</code> if Hibernate is connecting to an Informix
208             * database.
209             *
210             * @return <code>true</code> if Hibernate is connecting to an Informix
211             *         database
212             */
213            public boolean isVendorInformix() {
214                    return _vendorInformix;
215            }
216    
217            /**
218             * Returns <code>true</code> if Hibernate is connecting to a MySQL database.
219             *
220             * @return <code>true</code> if Hibernate is connecting to a MySQL database
221             */
222            public boolean isVendorMySQL() {
223                    return _vendorMySQL;
224            }
225    
226            /**
227             * Returns <code>true</code> if Hibernate is connecting to an Oracle
228             * database. Oracle has a nasty bug where it treats '' as a
229             * <code>NULL</code> value. See
230             * http://thedailywtf.com/forums/thread/26879.aspx for more information on
231             * this nasty bug.
232             *
233             * @return <code>true</code> if Hibernate is connecting to an Oracle
234             *         database
235             */
236            public boolean isVendorOracle() {
237                    return _vendorOracle;
238            }
239    
240            /**
241             * Returns <code>true</code> if Hibernate is connecting to a PostgreSQL
242             * database.
243             *
244             * @return <code>true</code> if Hibernate is connecting to a PostgreSQL
245             *         database
246             */
247            public boolean isVendorPostgreSQL() {
248                    return _vendorPostgreSQL;
249            }
250    
251            /**
252             * Returns <code>true</code> if Hibernate is connecting to a Sybase
253             * database.
254             *
255             * @return <code>true</code> if Hibernate is connecting to a Sybase database
256             */
257            public boolean isVendorSybase() {
258                    return _vendorSybase;
259            }
260    
261            public String[] keywords(String keywords) {
262                    return keywords(keywords, true);
263            }
264    
265            public String[] keywords(String keywords, boolean lowerCase) {
266                    if (Validator.isNull(keywords)) {
267                            return new String[] {null};
268                    }
269    
270                    if (_CUSTOM_SQL_AUTO_ESCAPE_WILDCARDS_ENABLED) {
271                            keywords = escapeWildCards(keywords);
272                    }
273    
274                    if (lowerCase) {
275                            keywords = StringUtil.toLowerCase(keywords);
276                    }
277    
278                    keywords = keywords.trim();
279    
280                    List<String> keywordsList = new ArrayList<String>();
281    
282                    for (int i = 0; i < keywords.length(); i++) {
283                            char c = keywords.charAt(i);
284    
285                            if (c == CharPool.QUOTE) {
286                                    int pos = i + 1;
287    
288                                    i = keywords.indexOf(CharPool.QUOTE, pos);
289    
290                                    if (i == -1) {
291                                            i = keywords.length();
292                                    }
293    
294                                    if (i > pos) {
295                                            String keyword = keywords.substring(pos, i);
296    
297                                            keywordsList.add(
298                                                    StringUtil.quote(keyword, StringPool.PERCENT));
299                                    }
300                            }
301                            else {
302                                    while (Character.isWhitespace(c)) {
303                                            i++;
304    
305                                            c = keywords.charAt(i);
306                                    }
307    
308                                    int pos = i;
309    
310                                    while (!Character.isWhitespace(c)) {
311                                            i++;
312    
313                                            if (i == keywords.length()) {
314                                                    break;
315                                            }
316    
317                                            c = keywords.charAt(i);
318                                    }
319    
320                                    String keyword = keywords.substring(pos, i);
321    
322                                    keywordsList.add(StringUtil.quote(keyword, StringPool.PERCENT));
323                            }
324                    }
325    
326                    return keywordsList.toArray(new String[keywordsList.size()]);
327            }
328    
329            public String[] keywords(String[] keywordsArray) {
330                    return keywords(keywordsArray, true);
331            }
332    
333            public String[] keywords(String[] keywordsArray, boolean lowerCase) {
334                    if (ArrayUtil.isEmpty(keywordsArray)) {
335                            return new String[] {null};
336                    }
337    
338                    if (lowerCase) {
339                            for (int i = 0; i < keywordsArray.length; i++) {
340                                    keywordsArray[i] = StringUtil.lowerCase(keywordsArray[i]);
341                            }
342                    }
343    
344                    return keywordsArray;
345            }
346    
347            public void reloadCustomSQL() throws SQLException {
348                    PortalUtil.initCustomSQL();
349    
350                    Connection con = DataAccess.getConnection();
351    
352                    String functionIsNull = PortalUtil.getCustomSQLFunctionIsNull();
353                    String functionIsNotNull = PortalUtil.getCustomSQLFunctionIsNotNull();
354    
355                    try {
356                            if (Validator.isNotNull(functionIsNull) &&
357                                    Validator.isNotNull(functionIsNotNull)) {
358    
359                                    _functionIsNull = functionIsNull;
360                                    _functionIsNotNull = functionIsNotNull;
361    
362                                    if (_log.isDebugEnabled()) {
363                                            _log.debug(
364                                                    "functionIsNull is manually set to " + functionIsNull);
365                                            _log.debug(
366                                                    "functionIsNotNull is manually set to " +
367                                                            functionIsNotNull);
368                                    }
369                            }
370                            else if (con != null) {
371                                    DatabaseMetaData metaData = con.getMetaData();
372    
373                                    String dbName = GetterUtil.getString(
374                                            metaData.getDatabaseProductName());
375    
376                                    if (_log.isInfoEnabled()) {
377                                            _log.info("Database name " + dbName);
378                                    }
379    
380                                    if (dbName.startsWith("DB2")) {
381                                            _vendorDB2 = true;
382                                            _functionIsNull = DB2_FUNCTION_IS_NULL;
383                                            _functionIsNotNull = DB2_FUNCTION_IS_NOT_NULL;
384    
385                                            if (_log.isInfoEnabled()) {
386                                                    _log.info("Detected DB2 with database name " + dbName);
387                                            }
388                                    }
389                                    else if (dbName.startsWith("HSQL")) {
390                                            _vendorHSQL = true;
391    
392                                            if (_log.isInfoEnabled()) {
393                                                    _log.info("Detected HSQL with database name " + dbName);
394                                            }
395                                    }
396                                    else if (dbName.startsWith("Informix")) {
397                                            _vendorInformix = true;
398                                            _functionIsNull = INFORMIX_FUNCTION_IS_NULL;
399                                            _functionIsNotNull = INFORMIX_FUNCTION_IS_NOT_NULL;
400    
401                                            if (_log.isInfoEnabled()) {
402                                                    _log.info(
403                                                            "Detected Informix with database name " + dbName);
404                                            }
405                                    }
406                                    else if (dbName.startsWith("MySQL")) {
407                                            _vendorMySQL = true;
408                                            //_functionIsNull = MYSQL_FUNCTION_IS_NULL;
409                                            //_functionIsNotNull = MYSQL_FUNCTION_IS_NOT_NULL;
410    
411                                            if (_log.isInfoEnabled()) {
412                                                    _log.info(
413                                                            "Detected MySQL with database name " + dbName);
414                                            }
415                                    }
416                                    else if (dbName.startsWith("Sybase") || dbName.equals("ASE")) {
417                                            _vendorSybase = true;
418                                            _functionIsNull = SYBASE_FUNCTION_IS_NULL;
419                                            _functionIsNotNull = SYBASE_FUNCTION_IS_NOT_NULL;
420    
421                                            if (_log.isInfoEnabled()) {
422                                                    _log.info(
423                                                            "Detected Sybase with database name " + dbName);
424                                            }
425                                    }
426                                    else if (dbName.startsWith("Oracle")) {
427                                            _vendorOracle = true;
428    
429                                            if (_log.isInfoEnabled()) {
430                                                    _log.info(
431                                                            "Detected Oracle with database name " + dbName);
432                                            }
433                                    }
434                                    else if (dbName.startsWith("PostgreSQL")) {
435                                            _vendorPostgreSQL = true;
436    
437                                            if (_log.isInfoEnabled()) {
438                                                    _log.info(
439                                                            "Detected PostgreSQL with database name " + dbName);
440                                            }
441                                    }
442                                    else {
443                                            if (_log.isDebugEnabled()) {
444                                                    _log.debug(
445                                                            "Unable to detect database with name " + dbName);
446                                            }
447                                    }
448                            }
449                    }
450                    catch (Exception e) {
451                            _log.error(e, e);
452                    }
453                    finally {
454                            DataAccess.cleanUp(con);
455                    }
456    
457                    if (_sqlPool == null) {
458                            _sqlPool = new HashMap<String, String>();
459                    }
460                    else {
461                            _sqlPool.clear();
462                    }
463    
464                    try {
465                            Class<?> clazz = getClass();
466    
467                            ClassLoader classLoader = clazz.getClassLoader();
468    
469                            String[] configs = getConfigs();
470    
471                            for (String _config : configs) {
472                                    read(classLoader, _config);
473                            }
474                    }
475                    catch (Exception e) {
476                            _log.error(e, e);
477                    }
478            }
479    
480            public String removeGroupBy(String sql) {
481                    int x = sql.indexOf(_GROUP_BY_CLAUSE);
482    
483                    if (x != -1) {
484                            int y = sql.indexOf(_ORDER_BY_CLAUSE);
485    
486                            if (y == -1) {
487                                    sql = sql.substring(0, x);
488                            }
489                            else {
490                                    sql = sql.substring(0, x) + sql.substring(y);
491                            }
492                    }
493    
494                    return sql;
495            }
496    
497            public String removeOrderBy(String sql) {
498                    int pos = sql.indexOf(_ORDER_BY_CLAUSE);
499    
500                    if (pos != -1) {
501                            sql = sql.substring(0, pos);
502                    }
503    
504                    return sql;
505            }
506    
507            public String replaceAndOperator(String sql, boolean andOperator) {
508                    String andOrConnector = "OR";
509                    String andOrNullCheck = "AND ? IS NOT NULL";
510    
511                    if (andOperator) {
512                            andOrConnector = "AND";
513                            andOrNullCheck = "OR ? IS NULL";
514                    }
515    
516                    sql = StringUtil.replace(
517                            sql,
518                            new String[] {
519                                    "[$AND_OR_CONNECTOR$]", "[$AND_OR_NULL_CHECK$]"
520                            },
521                            new String[] {
522                                    andOrConnector, andOrNullCheck
523                            });
524    
525                    if (_vendorPostgreSQL) {
526                            sql = StringUtil.replace(
527                                    sql,
528                                    new String[] {
529                                            "Date >= ? AND ? IS NOT NULL",
530                                            "Date <= ? AND ? IS NOT NULL", "Date >= ? OR ? IS NULL",
531                                            "Date <= ? OR ? IS NULL"
532                                    },
533                                    new String[] {
534                                            "Date >= ? AND CAST(? AS TIMESTAMP) IS NOT NULL",
535                                            "Date <= ? AND CAST(? AS TIMESTAMP) IS NOT NULL",
536                                            "Date >= ? OR CAST(? AS TIMESTAMP) IS NULL",
537                                            "Date <= ? OR CAST(? AS TIMESTAMP) IS NULL"
538                                    });
539                    }
540    
541                    sql = replaceIsNull(sql);
542    
543                    return sql;
544            }
545    
546            public String replaceGroupBy(String sql, String groupBy) {
547                    if (groupBy == null) {
548                            return sql;
549                    }
550    
551                    int x = sql.indexOf(_GROUP_BY_CLAUSE);
552    
553                    if (x != -1) {
554                            int y = sql.indexOf(_ORDER_BY_CLAUSE);
555    
556                            if (y == -1) {
557                                    sql = sql.substring(0, x + _GROUP_BY_CLAUSE.length()).concat(
558                                            groupBy);
559                            }
560                            else {
561                                    sql = sql.substring(0, x + _GROUP_BY_CLAUSE.length()).concat(
562                                            groupBy).concat(sql.substring(y));
563                            }
564                    }
565                    else {
566                            int y = sql.indexOf(_ORDER_BY_CLAUSE);
567    
568                            if (y == -1) {
569                                    sql = sql.concat(_GROUP_BY_CLAUSE).concat(groupBy);
570                            }
571                            else {
572                                    StringBundler sb = new StringBundler();
573    
574                                    sb.append(sql.substring(0, y));
575                                    sb.append(_GROUP_BY_CLAUSE);
576                                    sb.append(groupBy);
577                                    sb.append(sql.substring(y));
578    
579                                    sql = sb.toString();
580                            }
581                    }
582    
583                    return sql;
584            }
585    
586            public String replaceIsNull(String sql) {
587                    if (Validator.isNotNull(_functionIsNull)) {
588                            sql = StringUtil.replace(
589                                    sql,
590                                    new String[] {
591                                            "? IS NULL", "? IS NOT NULL"
592                                    },
593                                    new String[] {
594                                            _functionIsNull, _functionIsNotNull
595                                    });
596                    }
597    
598                    return sql;
599            }
600    
601            public String replaceKeywords(
602                    String sql, String field, boolean last, int[] values) {
603    
604                    if ((values != null) && (values.length == 1)) {
605                            return sql;
606                    }
607    
608                    StringBundler oldSql = new StringBundler(4);
609    
610                    oldSql.append(StringPool.OPEN_PARENTHESIS);
611                    oldSql.append(field);
612                    oldSql.append(" = ?)");
613    
614                    if (!last) {
615                            oldSql.append(" [$AND_OR_CONNECTOR$]");
616                    }
617    
618                    if (ArrayUtil.isEmpty(values)) {
619                            return StringUtil.replace(sql, oldSql.toString(), StringPool.BLANK);
620                    }
621    
622                    StringBundler newSql = new StringBundler(values.length * 4 + 3);
623    
624                    newSql.append(StringPool.OPEN_PARENTHESIS);
625    
626                    for (int i = 0; i < values.length; i++) {
627                            if (i > 0) {
628                                    newSql.append(" OR ");
629                            }
630    
631                            newSql.append(StringPool.OPEN_PARENTHESIS);
632                            newSql.append(field);
633                            newSql.append(" = ?)");
634                    }
635    
636                    newSql.append(StringPool.CLOSE_PARENTHESIS);
637    
638                    if (!last) {
639                            newSql.append(" [$AND_OR_CONNECTOR$]");
640                    }
641    
642                    return StringUtil.replace(sql, oldSql.toString(), newSql.toString());
643            }
644    
645            public String replaceKeywords(
646                    String sql, String field, boolean last, long[] values) {
647    
648                    if ((values != null) && (values.length == 1)) {
649                            return sql;
650                    }
651    
652                    StringBundler oldSql = new StringBundler(4);
653    
654                    oldSql.append(StringPool.OPEN_PARENTHESIS);
655                    oldSql.append(field);
656                    oldSql.append(" = ?)");
657    
658                    if (!last) {
659                            oldSql.append(" [$AND_OR_CONNECTOR$]");
660                    }
661    
662                    if (ArrayUtil.isEmpty(values)) {
663                            return StringUtil.replace(sql, oldSql.toString(), StringPool.BLANK);
664                    }
665    
666                    StringBundler newSql = new StringBundler(values.length * 4 + 3);
667    
668                    newSql.append(StringPool.OPEN_PARENTHESIS);
669    
670                    for (int i = 0; i < values.length; i++) {
671                            if (i > 0) {
672                                    newSql.append(" OR ");
673                            }
674    
675                            newSql.append(StringPool.OPEN_PARENTHESIS);
676                            newSql.append(field);
677                            newSql.append(" = ?)");
678                    }
679    
680                    newSql.append(StringPool.CLOSE_PARENTHESIS);
681    
682                    if (!last) {
683                            newSql.append(" [$AND_OR_CONNECTOR$]");
684                    }
685    
686                    return StringUtil.replace(sql, oldSql.toString(), newSql.toString());
687            }
688    
689            public String replaceKeywords(
690                    String sql, String field, String operator, boolean last,
691                    String[] values) {
692    
693                    if ((values != null) && (values.length <= 1)) {
694                            return sql;
695                    }
696    
697                    StringBundler oldSql = new StringBundler(6);
698    
699                    oldSql.append(StringPool.OPEN_PARENTHESIS);
700                    oldSql.append(field);
701                    oldSql.append(" ");
702                    oldSql.append(operator);
703                    oldSql.append(" ? [$AND_OR_NULL_CHECK$])");
704    
705                    if (!last) {
706                            oldSql.append(" [$AND_OR_CONNECTOR$]");
707                    }
708    
709                    StringBundler newSql = new StringBundler(values.length * 6 + 3);
710    
711                    newSql.append(StringPool.OPEN_PARENTHESIS);
712    
713                    for (int i = 0; i < values.length; i++) {
714                            if (i > 0) {
715                                    newSql.append(" OR ");
716                            }
717    
718                            newSql.append(StringPool.OPEN_PARENTHESIS);
719                            newSql.append(field);
720                            newSql.append(" ");
721                            newSql.append(operator);
722                            newSql.append(" ? [$AND_OR_NULL_CHECK$])");
723                    }
724    
725                    newSql.append(StringPool.CLOSE_PARENTHESIS);
726    
727                    if (!last) {
728                            newSql.append(" [$AND_OR_CONNECTOR$]");
729                    }
730    
731                    return StringUtil.replace(sql, oldSql.toString(), newSql.toString());
732            }
733    
734            public String replaceOrderBy(String sql, OrderByComparator obc) {
735                    if (obc == null) {
736                            return sql;
737                    }
738    
739                    String orderBy = obc.getOrderBy();
740    
741                    int pos = sql.indexOf(_ORDER_BY_CLAUSE);
742    
743                    if ((pos != -1) && (pos < sql.length())) {
744                            sql = sql.substring(0, pos + _ORDER_BY_CLAUSE.length()).concat(
745                                    orderBy);
746                    }
747                    else {
748                            sql = sql.concat(_ORDER_BY_CLAUSE).concat(orderBy);
749                    }
750    
751                    return sql;
752            }
753    
754            protected String[] getConfigs() {
755                    if (PortalClassLoaderUtil.getClassLoader() ==
756                                    CustomSQL.class.getClassLoader()) {
757    
758                            Properties propsUtil = PortalUtil.getPortalProperties();
759    
760                            return StringUtil.split(
761                                    propsUtil.getProperty("custom.sql.configs"));
762                    }
763                    else {
764                            return new String[] {"custom-sql/default.xml"};
765                    }
766            }
767    
768            protected void read(ClassLoader classLoader, String source)
769                    throws Exception {
770    
771                    InputStream is = classLoader.getResourceAsStream(source);
772    
773                    if (is == null) {
774                            return;
775                    }
776    
777                    try {
778                            if (_log.isDebugEnabled()) {
779                                    _log.debug("Loading " + source);
780                            }
781    
782                            Document document = UnsecureSAXReaderUtil.read(is);
783    
784                            Element rootElement = document.getRootElement();
785    
786                            for (Element sqlElement : rootElement.elements("sql")) {
787                                    String file = sqlElement.attributeValue("file");
788    
789                                    if (Validator.isNotNull(file)) {
790                                            read(classLoader, file);
791                                    }
792                                    else {
793                                            String id = sqlElement.attributeValue("id");
794                                            String content = transform(sqlElement.getText());
795    
796                                            content = replaceIsNull(content);
797    
798                                            _sqlPool.put(id, content);
799                                    }
800                            }
801                    }
802                    finally {
803                            StreamUtil.cleanUp(is);
804                    }
805            }
806    
807            protected String transform(String sql) {
808                    sql = PortalUtil.transformCustomSQL(sql);
809    
810                    StringBundler sb = new StringBundler();
811    
812                    try {
813                            UnsyncBufferedReader unsyncBufferedReader =
814                                    new UnsyncBufferedReader(new UnsyncStringReader(sql));
815    
816                            String line = null;
817    
818                            while ((line = unsyncBufferedReader.readLine()) != null) {
819                                    sb.append(line.trim());
820                                    sb.append(StringPool.SPACE);
821                            }
822    
823                            unsyncBufferedReader.close();
824                    }
825                    catch (IOException ioe) {
826                            return sql;
827                    }
828    
829                    return sb.toString();
830            }
831    
832            private String escapeWildCards(String keywords) {
833                    if (!isVendorMySQL() && !isVendorOracle()) {
834                            return keywords;
835                    }
836    
837                    StringBuilder sb = new StringBuilder(keywords);
838    
839                    for (int i = 0; i < sb.length(); ++i) {
840                            char c = sb.charAt(i);
841    
842                            if (c == CharPool.BACK_SLASH) {
843                                    i++;
844    
845                                    continue;
846                            }
847    
848                            if ((c == CharPool.UNDERLINE) || (c == CharPool.PERCENT)) {
849                                    sb.insert(i, CharPool.BACK_SLASH);
850    
851                                    i++;
852    
853                                    continue;
854                            }
855                    }
856    
857                    return sb.toString();
858            }
859    
860            private static final boolean _CUSTOM_SQL_AUTO_ESCAPE_WILDCARDS_ENABLED =
861                    GetterUtil.getBoolean(
862                            PropsUtil.get(PropsKeys.CUSTOM_SQL_AUTO_ESCAPE_WILDCARDS_ENABLED));
863    
864            private static final String _GROUP_BY_CLAUSE = " GROUP BY ";
865    
866            private static final String _ORDER_BY_CLAUSE = " ORDER BY ";
867    
868            private static final String _OWNER_USER_ID_AND_OR_CONNECTOR =
869                    "[$OWNER_USER_ID_AND_OR_CONNECTOR$]";
870    
871            private static final String _OWNER_USER_ID_CONDITION_DEFAULT = "userId = ?";
872    
873            private static final String _OWNER_USER_ID_KEYWORD = "[$OWNER_USER_ID$]";
874    
875            private static final String _STATUS_CONDITION_DEFAULT = "status = ?";
876    
877            private static final String _STATUS_CONDITION_EMPTY =
878                    WorkflowConstants.STATUS_ANY + " = ?";
879    
880            private static final String _STATUS_CONDITION_INVERSE = "status != ?";
881    
882            private static final String _STATUS_KEYWORD = "[$STATUS$]";
883    
884            private static Log _log = LogFactoryUtil.getLog(CustomSQL.class);
885    
886            private String _functionIsNotNull;
887            private String _functionIsNull;
888            private Map<String, String> _sqlPool;
889            private boolean _vendorDB2;
890            private boolean _vendorHSQL;
891            private boolean _vendorInformix;
892            private boolean _vendorMySQL;
893            private boolean _vendorOracle;
894            private boolean _vendorPostgreSQL;
895            private boolean _vendorSybase;
896    
897    }