001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.db;
020
021import java.io.ByteArrayInputStream;
022import java.util.Enumeration;
023import java.util.HashSet;
024import java.util.Set;
025import java.util.Vector;
026
027import lucee.runtime.sql.old.ParseException;
028import lucee.runtime.sql.old.ZExp;
029import lucee.runtime.sql.old.ZExpression;
030import lucee.runtime.sql.old.ZFromItem;
031import lucee.runtime.sql.old.ZQuery;
032import lucee.runtime.sql.old.ZStatement;
033import lucee.runtime.sql.old.ZqlParser;
034
035
036/**
037 * utilities for sql statements
038 */
039public final class HSQLUtil {
040        
041        private ZqlParser parser;
042        private String sql;
043        private boolean isUnion;
044
045        /**or of the class
046         * construct
047         * @param sql SQl Statement as String
048         */
049        public HSQLUtil(String sql) {
050                this.sql=SQLPrettyfier.prettyfie(sql,true);//sqlToZQL(sql,true);
051                parser = new ZqlParser(new ByteArrayInputStream(this.sql.getBytes()));
052        }
053        
054        /* *
055         * transalte SQL syntax to a ZQL combatible form
056         * @param sql sql to transalte
057         * @param changePlaceHolder
058         * @return translated sql
059         * /
060        private static String sqlToZQL(String sql,boolean changePlaceHolder) {
061                sql=sql.trim();
062                char c=' ';//,last=' ';
063                int len=sql.length();
064                boolean insideString=false;
065                StringBuilder sb=new StringBuilder(len);
066                
067                
068                
069                for(int i=0;i<len;i++) {
070                    c=sql.charAt(i);
071                    if(insideString) {
072                        if(c=='\'') {
073                            if(i+1>=len || sql.charAt(i+1)!='\'')insideString=false;
074                        }
075                    }
076                    else {
077                        if(c=='\'')insideString=true;
078                        else if(changePlaceHolder && c=='?') {
079                            sb.append("QUESTION_MARK_SIGN");
080                                    //last=c;
081                            continue;
082                        }
083                        else if(c=='a'|| c=='A') {
084                            if(
085                                    (i!=0 && isWhiteSpace(sql.charAt(i-1)))
086                                    &&
087                                    (i+1<len && (sql.charAt(i+1)=='s' || sql.charAt(i+1)=='S'))
088                                    &&
089                                    (i+2<len && isWhiteSpace(sql.charAt(i+2)))
090                            )   {
091                                i++;
092                                    //last=c;
093                                continue;
094                            }
095                        }
096                        else if(c=='*') {
097                                
098                        }
099                    }
100                    //last=c;
101                    sb.append(c);
102                }
103                
104                if(c!=';')sb.append(';');
105                
106                return sb.toString();
107                
108        }*/
109        
110        /*private static boolean isWhiteSpace(char c) {
111            return (c==' ' || c=='\t' || c=='\b' || c=='\r' || c=='\n');
112        }*/
113
114        /**
115         * @return return the sql state inside
116         */
117        public String getSQL() {
118                return sql;
119        }
120        
121        /**
122         * return all invoked tables by a sql statement
123         * @return invoked tables in a ArrayList
124         * @throws ParseException
125         */
126        public Set<String> getInvokedTables() throws ParseException {
127                
128                
129                // Read all SQL statements from input
130                ZStatement st;
131                Set<String> tables=new HashSet<String>();
132                
133                while((st = parser.readStatement()) != null) {
134                        this.sql=st.toString();
135                        if(st instanceof ZQuery) { // An SQL query: query the DB
136                      getInvokedTables((ZQuery)st,tables);                
137                    }
138                    break;
139                }
140                return tables;
141        }
142        
143        private void getInvokedTables(ZQuery query, Set<String> tablesNames) {
144                //print.out("qry:"+query.getSet());
145                Vector tables=query.getFrom();
146                Enumeration e = tables.elements();
147                
148                // from
149                        while(e.hasMoreElements()) {
150                                ZFromItem fromItem=(ZFromItem) e.nextElement();
151                                tablesNames.add(fromItem.getFullName());
152                        }
153                // where
154                        ZExp where = query.getWhere();
155                        if(where instanceof ZExpression) {
156                                parseZExpression((ZExpression) where, tablesNames);
157                        }
158                // set
159                        ZExpression set = query.getSet();
160                        if(set!=null){
161                                isUnion=true;
162                                ZExp op = set.getOperand(0);
163                                if(op instanceof ZQuery) getInvokedTables((ZQuery)op, tablesNames);
164                        }
165        }
166        
167
168
169        public boolean isUnion() {
170                return isUnion;
171        }
172        
173        private void parseZExpression(ZExpression expression, Set tablesNames) {
174                Vector operands = expression.getOperands();
175                Enumeration e = operands.elements();
176                while(e.hasMoreElements()) {
177                        Object el=e.nextElement();
178                        if(el instanceof ZExpression)parseZExpression((ZExpression)el,tablesNames);
179                        else if(el instanceof ZQuery)getInvokedTables((ZQuery)el,tablesNames);
180                }
181        }
182}