| 1 | /* ============================================================= |
| 2 | * SmallSQL : a free Java DBMS library for the Java(tm) platform |
| 3 | * ============================================================= |
| 4 | * |
| 5 | * (C) Copyright 2004-2006, by Volker Berlin. |
| 6 | * |
| 7 | * Project Info: http://www.smallsql.de/ |
| 8 | * |
| 9 | * This library is free software; you can redistribute it and/or modify it |
| 10 | * under the terms of the GNU Lesser General Public License as published by |
| 11 | * the Free Software Foundation; either version 2.1 of the License, or |
| 12 | * (at your option) any later version. |
| 13 | * |
| 14 | * This library is distributed in the hope that it will be useful, but |
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| 17 | * License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU Lesser General Public |
| 20 | * License along with this library; if not, write to the Free Software |
| 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
| 22 | * USA. |
| 23 | * |
| 24 | * [Java is a trademark or registered trademark of Sun Microsystems, Inc. |
| 25 | * in the United States and other countries.] |
| 26 | * |
| 27 | * --------------- |
| 28 | * Utils.java |
| 29 | * --------------- |
| 30 | * Author: Volker Berlin |
| 31 | * |
| 32 | */ |
| 33 | package smallsql.database; |
| 34 | |
| 35 | import java.sql.*; |
| 36 | |
| 37 | |
| 38 | class Utils { |
| 39 | |
| 40 | static final String MASTER_FILENAME = "smallsql.master"; |
| 41 | static final String TABLE_VIEW_EXTENTION = ".sdb"; |
| 42 | private static final String LOB_EXTENTION = ".lob"; |
| 43 | static final String IDX_EXTENTION = ".idx"; |
| 44 | private static final Integer[] integerCache = new Integer[260]; |
| 45 | private static final Short[] shortCache = new Short[260]; |
| 46 | static{ |
| 47 | for(int i=-4; i<256; i++){ |
| 48 | integerCache[ i+4 ] = new Integer(i); |
| 49 | shortCache [ i+4 ] = new Short((short)i); |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | static SQLException createSQLException( String msg ){ |
| 54 | return new SmallSQLException( msg ); |
| 55 | } |
| 56 | |
| 57 | static SQLException createSQLException( Throwable e ){ |
| 58 | if(e instanceof SQLException) return (SQLException)e; |
| 59 | return new SmallSQLException( e ); |
| 60 | } |
| 61 | |
| 62 | static String createTableViewFileName(Database database, String name){ |
| 63 | return database.getName() + '/' + name + TABLE_VIEW_EXTENTION; |
| 64 | } |
| 65 | |
| 66 | static String createLobFileName(Database database, String name){ |
| 67 | return database.getName() + '/' + name + LOB_EXTENTION; |
| 68 | } |
| 69 | |
| 70 | static String createIdxFileName(Database database, String name){ |
| 71 | return database.getName() + '/' + name + IDX_EXTENTION; |
| 72 | } |
| 73 | |
| 74 | static boolean like(String value, String pattern){ |
| 75 | if(value == null || pattern == null) return false; |
| 76 | if(pattern.length() == 0) return true; |
| 77 | |
| 78 | int mIdx = 0;//index in mask Array |
| 79 | int sIdx = 0;//index in search Array |
| 80 | boolean range = false; |
| 81 | weiter: |
| 82 | while(pattern.length() > mIdx && value.length() > sIdx) { |
| 83 | char m = Character.toUpperCase(pattern.charAt(mIdx++)); |
| 84 | switch(m) { |
| 85 | case '%': |
| 86 | range = true; |
| 87 | break; |
| 88 | case '_': |
| 89 | sIdx++; |
| 90 | break; |
| 91 | default: |
| 92 | if(range) {//* wildcard ist aktiv |
| 93 | for(; sIdx < value.length(); sIdx++) { |
| 94 | if(Character.toUpperCase(value.charAt(sIdx)) == m) break;//Zähler darf nicht vor dem break erhöht werden |
| 95 | } |
| 96 | if(sIdx >= value.length()) return false; |
| 97 | int lastmIdx = mIdx - 1; |
| 98 | sIdx++; |
| 99 | while(pattern.length() > mIdx && value.length() > sIdx) { |
| 100 | m = Character.toUpperCase(pattern.charAt(mIdx++)); |
| 101 | if(Character.toUpperCase(value.charAt(sIdx)) != m) { |
| 102 | if(m == '%' || m == '_') { |
| 103 | mIdx--; |
| 104 | break; |
| 105 | } |
| 106 | mIdx = lastmIdx; |
| 107 | continue weiter; |
| 108 | } |
| 109 | sIdx++; |
| 110 | } |
| 111 | range = false; |
| 112 | }else{ |
| 113 | if(Character.toUpperCase(value.charAt(sIdx)) != m) return false; |
| 114 | sIdx++; |
| 115 | } |
| 116 | break; |
| 117 | } |
| 118 | } |
| 119 | while(pattern.length() > mIdx) { |
| 120 | //Suchmaske ist noch nicht zu ende es dürfen nur noch '*' enthalten sein |
| 121 | if(Character.toUpperCase(pattern.charAt(mIdx++)) != '*') return false; |
| 122 | } |
| 123 | while(value.length() > sIdx && !range) return false; |
| 124 | return true; |
| 125 | } |
| 126 | |
| 127 | |
| 128 | static int long2int(long value){ |
| 129 | if(value > Integer.MAX_VALUE) |
| 130 | return Integer.MAX_VALUE; |
| 131 | if(value < Integer.MIN_VALUE) |
| 132 | return Integer.MIN_VALUE; |
| 133 | return (int)value; |
| 134 | } |
| 135 | |
| 136 | static long double2long(double value){ |
| 137 | if(value > Long.MAX_VALUE) |
| 138 | return Long.MAX_VALUE; |
| 139 | if(value < Long.MIN_VALUE) |
| 140 | return Long.MIN_VALUE; |
| 141 | return (long)value; |
| 142 | } |
| 143 | |
| 144 | |
| 145 | |
| 146 | static float bytes2float( byte[] bytes ){ |
| 147 | return Float.intBitsToFloat( bytes2int( bytes ) ); |
| 148 | } |
| 149 | |
| 150 | static double bytes2double( byte[] bytes ){ |
| 151 | return Double.longBitsToDouble( bytes2long( bytes ) ); |
| 152 | } |
| 153 | |
| 154 | static long bytes2long( byte[] bytes ){ |
| 155 | long result = 0; |
| 156 | int length = Math.min( 8, bytes.length); |
| 157 | for(int i=0; i<length; i++){ |
| 158 | result = (result << 8) | (bytes[i] & 0xFF); |
| 159 | } |
| 160 | return result; |
| 161 | } |
| 162 | |
| 163 | static int bytes2int( byte[] bytes ){ |
| 164 | int result = 0; |
| 165 | int length = Math.min( 4, bytes.length); |
| 166 | for(int i=0; i<length; i++){ |
| 167 | result = (result << 8) | (bytes[i] & 0xFF); |
| 168 | } |
| 169 | return result; |
| 170 | } |
| 171 | |
| 172 | static byte[] int2bytes( int value ){ |
| 173 | byte[] result = new byte[4]; |
| 174 | result[0] = (byte)(value >> 24); |
| 175 | result[1] = (byte)(value >> 16); |
| 176 | result[2] = (byte)(value >> 8); |
| 177 | result[3] = (byte)(value); |
| 178 | return result; |
| 179 | } |
| 180 | |
| 181 | static String bytes2hex( byte[] bytes ){ |
| 182 | StringBuffer buf = new StringBuffer(bytes.length << 1); |
| 183 | for(int i=0; i<bytes.length; i++){ |
| 184 | buf.append( digits[ (bytes[i] >> 4) & 0x0F ] ); |
| 185 | buf.append( digits[ (bytes[i] ) & 0x0F ] ); |
| 186 | } |
| 187 | return buf.toString(); |
| 188 | } |
| 189 | |
| 190 | static byte[] hex2bytes( char[] hex, int offset, int length) throws SQLException{ |
| 191 | try{ |
| 192 | byte[] bytes = new byte[length / 2]; |
| 193 | for(int i=0; i<bytes.length; i++){ |
| 194 | bytes[i] = (byte)((hexDigit2int( hex[ offset++ ] ) << 4) |
| 195 | | hexDigit2int( hex[ offset++ ] )); |
| 196 | } |
| 197 | return bytes; |
| 198 | }catch(Exception e){ |
| 199 | throw new SQLException("Invalid hex sequense at " + offset/*, offset*/); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | private static int hexDigit2int(char digit){ |
| 204 | if(digit >= '0' && digit <= '9') return digit - '0'; |
| 205 | digit |= 0x20; |
| 206 | if(digit >= 'a' && digit <= 'f') return digit - 'W'; // -'W' == -'a' + 10 |
| 207 | throw new RuntimeException(); |
| 208 | } |
| 209 | |
| 210 | static byte[] unique2bytes( String unique ) throws SQLException{ |
| 211 | char[] chars = unique.toCharArray(); |
| 212 | byte[] daten = new byte[16]; |
| 213 | daten[3] = hex2byte( chars, 0 ); |
| 214 | daten[2] = hex2byte( chars, 2 ); |
| 215 | daten[1] = hex2byte( chars, 4 ); |
| 216 | daten[0] = hex2byte( chars, 6 ); |
| 217 | |
| 218 | daten[5] = hex2byte( chars, 9 ); |
| 219 | daten[4] = hex2byte( chars, 11 ); |
| 220 | |
| 221 | daten[7] = hex2byte( chars, 14 ); |
| 222 | daten[6] = hex2byte( chars, 16 ); |
| 223 | |
| 224 | daten[8] = hex2byte( chars, 19 ); |
| 225 | daten[9] = hex2byte( chars, 21 ); |
| 226 | |
| 227 | daten[10] = hex2byte( chars, 24 ); |
| 228 | daten[11] = hex2byte( chars, 26 ); |
| 229 | daten[12] = hex2byte( chars, 28 ); |
| 230 | daten[13] = hex2byte( chars, 30 ); |
| 231 | daten[14] = hex2byte( chars, 32 ); |
| 232 | daten[15] = hex2byte( chars, 34 ); |
| 233 | return daten; |
| 234 | } |
| 235 | |
| 236 | private static byte hex2byte( char[] hex, int offset) throws SQLException{ |
| 237 | try{ |
| 238 | return (byte)((hexDigit2int( hex[ offset++ ] ) << 4) |
| 239 | | hexDigit2int( hex[ offset++ ] )); |
| 240 | }catch(Exception e){ |
| 241 | throw new SQLException("Invalid hex sequense at position " + offset + " in '" + new String(hex) + '\''); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | static String bytes2unique( byte[] daten, int offset ){ |
| 246 | if(daten.length-offset < 16){ |
| 247 | byte[] temp = new byte[16]; |
| 248 | System.arraycopy(daten, offset, temp, 0, daten.length-offset); |
| 249 | daten = temp; |
| 250 | } |
| 251 | char[] chars = new char[36]; |
| 252 | chars[8] = chars[13] = chars[18] = chars[23] = '-'; |
| 253 | |
| 254 | chars[0] = digits[ (daten[offset+3] >> 4) & 0x0F ]; |
| 255 | chars[1] = digits[ (daten[offset+3] ) & 0x0F ]; |
| 256 | chars[2] = digits[ (daten[offset+2] >> 4) & 0x0F ]; |
| 257 | chars[3] = digits[ (daten[offset+2] ) & 0x0F ]; |
| 258 | chars[4] = digits[ (daten[offset+1] >> 4) & 0x0F ]; |
| 259 | chars[5] = digits[ (daten[offset+1] ) & 0x0F ]; |
| 260 | chars[6] = digits[ (daten[offset+0] >> 4) & 0x0F ]; |
| 261 | chars[7] = digits[ (daten[offset+0] ) & 0x0F ]; |
| 262 | |
| 263 | chars[ 9] = digits[ (daten[offset+5] >> 4) & 0x0F ]; |
| 264 | chars[10] = digits[ (daten[offset+5] ) & 0x0F ]; |
| 265 | chars[11] = digits[ (daten[offset+4] >> 4) & 0x0F ]; |
| 266 | chars[12] = digits[ (daten[offset+4] ) & 0x0F ]; |
| 267 | |
| 268 | chars[14] = digits[ (daten[offset+7] >> 4) & 0x0F ]; |
| 269 | chars[15] = digits[ (daten[offset+7] ) & 0x0F ]; |
| 270 | chars[16] = digits[ (daten[offset+6] >> 4) & 0x0F ]; |
| 271 | chars[17] = digits[ (daten[offset+6] ) & 0x0F ]; |
| 272 | |
| 273 | chars[19] = digits[ (daten[offset+8] >> 4) & 0x0F ]; |
| 274 | chars[20] = digits[ (daten[offset+8] ) & 0x0F ]; |
| 275 | chars[21] = digits[ (daten[offset+9] >> 4) & 0x0F ]; |
| 276 | chars[22] = digits[ (daten[offset+9] ) & 0x0F ]; |
| 277 | |
| 278 | chars[24] = digits[ (daten[offset+10] >> 4) & 0x0F ]; |
| 279 | chars[25] = digits[ (daten[offset+10] ) & 0x0F ]; |
| 280 | chars[26] = digits[ (daten[offset+11] >> 4) & 0x0F ]; |
| 281 | chars[27] = digits[ (daten[offset+11] ) & 0x0F ]; |
| 282 | chars[28] = digits[ (daten[offset+12] >> 4) & 0x0F ]; |
| 283 | chars[29] = digits[ (daten[offset+12] ) & 0x0F ]; |
| 284 | chars[30] = digits[ (daten[offset+13] >> 4) & 0x0F ]; |
| 285 | chars[31] = digits[ (daten[offset+13] ) & 0x0F ]; |
| 286 | chars[32] = digits[ (daten[offset+14] >> 4) & 0x0F ]; |
| 287 | chars[33] = digits[ (daten[offset+14] ) & 0x0F ]; |
| 288 | chars[34] = digits[ (daten[offset+15] >> 4) & 0x0F ]; |
| 289 | chars[35] = digits[ (daten[offset+15] ) & 0x0F ]; |
| 290 | return new String(chars); |
| 291 | } |
| 292 | |
| 293 | static boolean string2boolean( String val){ |
| 294 | try{ |
| 295 | return Double.parseDouble( val ) != 0; |
| 296 | }catch(NumberFormatException e){} |
| 297 | return "true".equalsIgnoreCase( val ) || "yes".equalsIgnoreCase( val ) || "t".equalsIgnoreCase( val ); |
| 298 | } |
| 299 | |
| 300 | |
| 301 | static long doubleToMoney(double value){ |
| 302 | if(value < 0) |
| 303 | return (long)(value * 10000 - 0.5); |
| 304 | return (long)(value * 10000 + 0.5); |
| 305 | } |
| 306 | |
| 307 | static int indexOf( char value, char[] str, int offset, int length ){ |
| 308 | value |= 0x20; |
| 309 | for(int end = offset+length;offset < end; offset++){ |
| 310 | if((str[offset] | 0x20) == value) return offset; |
| 311 | } |
| 312 | return -1; |
| 313 | } |
| 314 | |
| 315 | static int indexOf( int value, int[] list ){ |
| 316 | int offset = 0; |
| 317 | for(int end = list.length; offset < end; offset++){ |
| 318 | if((list[offset]) == value) return offset; |
| 319 | } |
| 320 | return -1; |
| 321 | } |
| 322 | |
| 323 | static int indexOf( byte[] value, byte[] list, int offset ){ |
| 324 | int length = value.length; |
| 325 | loop1: |
| 326 | for(int end = list.length-length; offset <= end; offset++){ |
| 327 | for(int i=0; i<length; i++ ){ |
| 328 | if(list[offset+i] != value[i]){ |
| 329 | continue loop1; |
| 330 | } |
| 331 | } |
| 332 | return offset; |
| 333 | } |
| 334 | return -1; |
| 335 | } |
| 336 | |
| 337 | static int compareBytes( byte[] leftBytes, byte[] rightBytes){ |
| 338 | int length = Math.min( leftBytes.length, rightBytes.length ); |
| 339 | int comp = 0; |
| 340 | for(int i=0; i<length; i++){ |
| 341 | if(leftBytes[i] != rightBytes[i]){ |
| 342 | comp = leftBytes[i] < rightBytes[i] ? -1 : 1; |
| 343 | break; |
| 344 | } |
| 345 | } |
| 346 | if(comp == 0 && leftBytes.length != rightBytes.length){ |
| 347 | comp = leftBytes.length < rightBytes.length ? -1 : 1; |
| 348 | } |
| 349 | return comp; |
| 350 | } |
| 351 | |
| 352 | |
| 353 | /** |
| 354 | * |
| 355 | * @param colNames |
| 356 | * @param data |
| 357 | * @return |
| 358 | * @throws SQLException |
| 359 | */ |
| 360 | static CommandSelect createMemoryCommandSelect( SSConnection con, String[] colNames, Object[][] data) throws SQLException{ |
| 361 | MemoryResult source = new MemoryResult(data, colNames.length); |
| 362 | CommandSelect cmd = new CommandSelect(con.log); |
| 363 | for(int i=0; i<colNames.length; i++){ |
| 364 | ExpressionName expr = new ExpressionName(colNames[i]); |
| 365 | cmd.addColumnExpression( expr ); |
| 366 | expr.setFrom( source, i, source.getColumn(i)); |
| 367 | } |
| 368 | cmd.setSource(source); |
| 369 | return cmd; |
| 370 | } |
| 371 | |
| 372 | |
| 373 | // receycle Integer objects, this is faster as to garbage the objects |
| 374 | static final Integer getInteger(int value){ |
| 375 | if(value >= -4 && value < 256){ |
| 376 | return integerCache[ value+4 ]; |
| 377 | }else |
| 378 | return new Integer(value); |
| 379 | } |
| 380 | |
| 381 | // receycle Integer objects, this is faster as to garbage the objects |
| 382 | static final Short getShort(int value){ |
| 383 | if(value >= -4 && value < 256){ |
| 384 | return shortCache[ value+4 ]; |
| 385 | }else |
| 386 | return new Short((short)value); |
| 387 | } |
| 388 | |
| 389 | final static char[] digits = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; |
| 390 | } |