1.1 --- a/java/sql-vyuka/src/java/cz/frantovo/sql/vyuka/dao/PiskovisteDAO.java Wed Feb 08 12:44:51 2012 +0100
1.2 +++ b/java/sql-vyuka/src/java/cz/frantovo/sql/vyuka/dao/PiskovisteDAO.java Wed Feb 08 13:15:23 2012 +0100
1.3 @@ -14,118 +14,149 @@
1.4
1.5 /**
1.6 * Pro spouštění uživatelových příkazů.
1.7 + *
1.8 * @author fiki
1.9 */
1.10 public class PiskovisteDAO extends VyukaSuperDAO {
1.11
1.12 - private enum VLASTNOSTI {
1.13 + /** maximální doba trvání SQL dotazu – vteřiny */
1.14 + private static final int LIMIT_ČASU = 3;
1.15 + /** maximální počet řádků */
1.16 + private static final int LIMIT_POČTU = 10000;
1.17
1.18 - VYCHOZI_CESTA
1.19 - }
1.20 - TipyDAO tipy = new TipyDAO();
1.21 - HistorieDAO historie = new HistorieDAO();
1.22 + private enum VLASTNOSTI {
1.23
1.24 - public VysledekSQL vykonejSQL(String sql, Uzivatel uzivatel) {
1.25 - VysledekSQL v = new VysledekSQL();
1.26 - if (historie.ulozPrikaz(sql, uzivatel)) {
1.27 + VYCHOZI_CESTA,
1.28 + LIMIT_ČASU
1.29 + }
1.30 + TipyDAO tipy = new TipyDAO();
1.31 + HistorieDAO historie = new HistorieDAO();
1.32
1.33 - Connection db = getSpojeni(DATABAZE.PISKOVISTE);
1.34 - if (db == null) {
1.35 - v.getHlasky().add(new Hlaska("Došlo k chybě spojení.", Typ.Chyba));
1.36 - } else {
1.37 - PreparedStatement ps = null;
1.38 - ResultSet rs = null;
1.39 - try {
1.40 - /**
1.41 - * Uživatelskému SQL příkazu předřadíme výchozí cestu (search_path).
1.42 - * Protože uživatelé si ji mohou měnit a kvůli recyklaci databázových zdrojů
1.43 - * by jeden uživatel mohl ovlivnit jiného.
1.44 - */
1.45 - if (getVlastnost(VLASTNOSTI.VYCHOZI_CESTA) != null) {
1.46 - sql = orizni(getVlastnost(VLASTNOSTI.VYCHOZI_CESTA)) + sql;
1.47 - }
1.48 + public VysledekSQL vykonejSQL(String sql, Uzivatel uzivatel) {
1.49 + VysledekSQL v = new VysledekSQL();
1.50 + if (historie.ulozPrikaz(sql, uzivatel)) {
1.51
1.52 - long casPred = System.currentTimeMillis();
1.53 - ps = db.prepareStatement(sql);
1.54 - boolean isRS = ps.execute();
1.55 + Connection db = getSpojeni(DATABAZE.PISKOVISTE);
1.56 + if (db == null) {
1.57 + v.getHlasky().add(new Hlaska("Došlo k chybě spojení.", Typ.Chyba));
1.58 + } else {
1.59 + PreparedStatement ps = null;
1.60 + ResultSet rs = null;
1.61 + try {
1.62 + /**
1.63 + * Uživatelskému SQL příkazu předřadíme výchozí cestu (search_path).
1.64 + * Protože uživatelé si ji mohou měnit a kvůli recyklaci databázových zdrojů
1.65 + * by jeden uživatel mohl ovlivnit jiného.
1.66 + */
1.67 + if (getVlastnost(VLASTNOSTI.VYCHOZI_CESTA) != null) {
1.68 + sql = orizni(getVlastnost(VLASTNOSTI.VYCHOZI_CESTA)) + sql;
1.69 + }
1.70 +
1.71 + /**
1.72 + * TODO:
1.73 + * použít ps.setQueryTimeout(LIMIT_ČASU);
1.74 + * až ho bude podporovat JDBC ovladač,
1.75 + * viz níže.
1.76 + * Uživatel ale stejně může zadat:
1.77 + * SET statement_timeout 0;
1.78 + * do svého SQL dotazu.
1.79 + */
1.80 + if (getVlastnost(VLASTNOSTI.LIMIT_ČASU) != null) {
1.81 + sql = orizni(getVlastnost(VLASTNOSTI.LIMIT_ČASU)) + sql;
1.82 + }
1.83
1.84 - if (isRS) {
1.85 - rs = ps.getResultSet();
1.86 - v.getTabulky().add(zpracujVysledek(rs));
1.87 - }
1.88 + long casPred = System.currentTimeMillis();
1.89 + ps = db.prepareStatement(sql);
1.90 + /**
1.91 + * Limit času bohužel není podporován JDBC ovladačem.
1.92 + * Alespoň ne v postgresql-9.1-901.jdbc4.jar
1.93 + * http://jdbc.postgresql.org/todo.html
1.94 + *
1.95 + * TODO:
1.96 + * ps.setQueryTimeout(LIMIT_ČASU);
1.97 + */
1.98 + ps.setMaxRows(LIMIT_POČTU);
1.99 + boolean isRS = ps.execute();
1.100
1.101 - /**
1.102 - * Ošetříme případ, kdy uživatel zadá SQL příkaz, který nevrací výsledkovou sadu.
1.103 - * Typicky nastavení výchozího schématu: SET search_path = '…';
1.104 - * Poznámka: jeden „SET search_path TO "…"“ se obvykle předřazuje uživatelskému SQL (viz PiskovisteDAO.xml).
1.105 - */
1.106 - while (ps.getMoreResults() || ps.getUpdateCount() > -1) {
1.107 - rs = ps.getResultSet();
1.108 - if (rs == null) {
1.109 - /** Jedná se o „update count“. */
1.110 - } else {
1.111 - v.getTabulky().add(zpracujVysledek(rs));
1.112 - }
1.113 - }
1.114 - long dobaProvadeni = System.currentTimeMillis() - casPred;
1.115 + if (isRS) {
1.116 + rs = ps.getResultSet();
1.117 + v.getTabulky().add(zpracujVysledek(rs));
1.118 + }
1.119
1.120 - /** Varování */
1.121 - if (v.getHlasky().size() < 1 && v.getTabulky().size() < 1) {
1.122 - v.getHlasky().add(new Hlaska("SQL příkaz proběhl, ale nevrátil žádná data.", Typ.Varovani));
1.123 - }
1.124 + /**
1.125 + * Ošetříme případ, kdy uživatel zadá SQL příkaz, který nevrací výsledkovou
1.126 + * sadu.
1.127 + * Typicky nastavení výchozího schématu: SET search_path = '…';
1.128 + * Poznámka: jeden „SET search_path TO "…"“ se obvykle předřazuje uživatelskému
1.129 + * SQL (viz PiskovisteDAO.xml).
1.130 + */
1.131 + while (ps.getMoreResults() || ps.getUpdateCount() > -1) {
1.132 + rs = ps.getResultSet();
1.133 + if (rs == null) {
1.134 + /** Jedná se o „update count“. */
1.135 + } else {
1.136 + v.getTabulky().add(zpracujVysledek(rs));
1.137 + }
1.138 + }
1.139 + long dobaProvadeni = System.currentTimeMillis() - casPred;
1.140
1.141 - /** Varování */
1.142 - int pocitadloTabulek = 1;
1.143 - for (Tabulka t : v.getTabulky()) {
1.144 - if (t.getHodnoty().size() < 1) {
1.145 - v.getHlasky().add(new Hlaska("Tabulka " + pocitadloTabulek + " je prázdná.", Typ.Varovani));
1.146 - }
1.147 - pocitadloTabulek++;
1.148 - }
1.149 + /** Varování */
1.150 + if (v.getHlasky().size() < 1 && v.getTabulky().size() < 1) {
1.151 + v.getHlasky().add(new Hlaska("SQL příkaz proběhl, ale nevrátil žádná data.", Typ.Varovani));
1.152 + }
1.153
1.154 - v.getHlasky().add(new Hlaska("SQL příkaz byl proveden úspěšně, během " + dobaProvadeni + " ms.", Typ.OK));
1.155 + /** Varování */
1.156 + int pocitadloTabulek = 1;
1.157 + for (Tabulka t : v.getTabulky()) {
1.158 + if (t.getHodnoty().size() < 1) {
1.159 + v.getHlasky().add(new Hlaska("Tabulka " + pocitadloTabulek + " je prázdná.", Typ.Varovani));
1.160 + }
1.161 + pocitadloTabulek++;
1.162 + }
1.163
1.164 - } catch (SQLException e) {
1.165 - log.log(Level.SEVERE, "SQL chyba při vykonávání uživatelského dotazu.", e);
1.166 - v.getHlasky().add(new Hlaska("Chybné SQL: " + e.getMessage(), Typ.Chyba));
1.167 - } catch (Exception e) {
1.168 - log.log(Level.SEVERE, "Chyba při vykonávání uživatelského dotazu.", e);
1.169 - v.getHlasky().add(new Hlaska("Došlo k chybě dotazu.", Typ.Chyba));
1.170 - } finally {
1.171 - zavri(db, ps, rs);
1.172 - }
1.173 - }
1.174 + v.getHlasky().add(new Hlaska("SQL příkaz byl proveden úspěšně, během " + dobaProvadeni + " ms.", Typ.OK));
1.175
1.176 - /** Tip pro uživatele */
1.177 - String tip = tipy.getTip();
1.178 - if (tip != null) {
1.179 - v.getHlasky().add(new Hlaska(tip, Typ.Tip, false));
1.180 - }
1.181 + } catch (SQLException e) {
1.182 + log.log(Level.SEVERE, "SQL chyba při vykonávání uživatelského dotazu.", e);
1.183 + v.getHlasky().add(new Hlaska("Chybné SQL: " + e.getMessage(), Typ.Chyba));
1.184 + } catch (Exception e) {
1.185 + log.log(Level.SEVERE, "Chyba při vykonávání uživatelského dotazu.", e);
1.186 + v.getHlasky().add(new Hlaska("Došlo k chybě dotazu.", Typ.Chyba));
1.187 + } finally {
1.188 + zavri(db, ps, rs);
1.189 + }
1.190 + }
1.191
1.192 - } else {
1.193 - v.getHlasky().add(new Hlaska("Došlo k chybě historie.", Typ.Chyba));
1.194 - }
1.195 - return v;
1.196 - }
1.197 + /** Tip pro uživatele */
1.198 + String tip = tipy.getTip();
1.199 + if (tip != null) {
1.200 + v.getHlasky().add(new Hlaska(tip, Typ.Tip, false));
1.201 + }
1.202
1.203 - private Tabulka zpracujVysledek(ResultSet rs) throws SQLException {
1.204 - Tabulka t = new Tabulka();
1.205 + } else {
1.206 + v.getHlasky().add(new Hlaska("Došlo k chybě historie.", Typ.Chyba));
1.207 + }
1.208 + return v;
1.209 + }
1.210
1.211 - int pocetSloupecku = rs.getMetaData().getColumnCount();
1.212 - String[] zahlavi = new String[pocetSloupecku];
1.213 - t.setZahlavi(zahlavi);
1.214 - for (int i = 0; i < pocetSloupecku; i++) {
1.215 - zahlavi[i] = rs.getMetaData().getColumnName(i + 1);
1.216 - }
1.217 + private Tabulka zpracujVysledek(ResultSet rs) throws SQLException {
1.218 + Tabulka t = new Tabulka();
1.219
1.220 - while (rs.next()) {
1.221 - Object[] hodnoty = new Object[pocetSloupecku];
1.222 - for (int i = 0; i < pocetSloupecku; i++) {
1.223 - hodnoty[i] = rs.getObject(i + 1);
1.224 - }
1.225 - t.getHodnoty().add(hodnoty);
1.226 - }
1.227 + int pocetSloupecku = rs.getMetaData().getColumnCount();
1.228 + String[] zahlavi = new String[pocetSloupecku];
1.229 + t.setZahlavi(zahlavi);
1.230 + for (int i = 0; i < pocetSloupecku; i++) {
1.231 + zahlavi[i] = rs.getMetaData().getColumnName(i + 1);
1.232 + }
1.233
1.234 - return t;
1.235 - }
1.236 + while (rs.next()) {
1.237 + Object[] hodnoty = new Object[pocetSloupecku];
1.238 + for (int i = 0; i < pocetSloupecku; i++) {
1.239 + hodnoty[i] = rs.getObject(i + 1);
1.240 + }
1.241 + t.getHodnoty().add(hodnoty);
1.242 + }
1.243 +
1.244 + return t;
1.245 + }
1.246 }
2.1 --- a/java/sql-vyuka/src/java/cz/frantovo/sql/vyuka/dao/PiskovisteDAO.xml Wed Feb 08 12:44:51 2012 +0100
2.2 +++ b/java/sql-vyuka/src/java/cz/frantovo/sql/vyuka/dao/PiskovisteDAO.xml Wed Feb 08 13:15:23 2012 +0100
2.3 @@ -2,12 +2,23 @@
2.4 <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
2.5 <properties>
2.6 <!--
2.7 - PostgreSQL proměnná „search_path“ – nastavíme ji před každým uživatelským SQL dotazem,
2.8 - aby se uživatelé vzájemně neovlivňovali.
2.9 + PostgreSQL proměnná „search_path“ – nastavíme ji před každým uživatelským SQL dotazem,
2.10 + aby se uživatelé vzájemně neovlivňovali.
2.11 -->
2.12 - <entry key="VYCHOZI_CESTA">
2.13 + <entry key="VYCHOZI_CESTA">
2.14 <![CDATA[
2.15 SET search_path TO "$user",public;
2.16 ]]>
2.17 - </entry>
2.18 + </entry>
2.19 + <!--
2.20 + Limit (vteřiny) pro vykonání jednoho SQL příkazu.
2.21 + TODO:
2.22 + použít ps.setQueryTimeout(LIMIT_ČASU);
2.23 + až ho bude podporovat JDBC ovladač.
2.24 + -->
2.25 + <entry key="LIMIT_ČASU">
2.26 + <![CDATA[
2.27 + SET statement_timeout TO 3;
2.28 + ]]>
2.29 + </entry>
2.30 </properties>
2.31 \ No newline at end of file