1 29 30 package com.caucho.quercus.lib.db; 31 32 import com.caucho.quercus.UnimplementedException; 33 import com.caucho.quercus.annotation.Optional; 34 import com.caucho.quercus.annotation.ReadOnly; 35 import com.caucho.quercus.annotation.Reference; 36 import com.caucho.quercus.env.*; 37 import com.caucho.quercus.lib.file.FileReadValue; 38 import com.caucho.util.IntMap; 39 import com.caucho.util.L10N; 40 import com.caucho.vfs.ReadStream; 41 import com.caucho.vfs.TempBuffer; 42 import com.caucho.vfs.TempReadStream; 43 44 import java.io.IOException ; 45 import java.io.InputStream ; 46 import java.sql.*; 47 import java.util.ArrayList ; 48 import java.util.Collections ; 49 import java.util.Iterator ; 50 import java.util.Map ; 51 import java.util.Set ; 52 import java.util.logging.Level ; 53 import java.util.logging.Logger ; 54 55 58 public class PDOStatement 59 implements Iterable <Value>, java.io.Closeable  60 { 61 private static final Logger log = Logger.getLogger(PDOStatement.class.getName()); 62 private static final L10N L = new L10N(PDOStatement.class); 63 64 private static final Value[] NULL_VALUES = new Value[0]; 65 66 private static final Value FETCH_FAILURE = new BooleanValue(false) {}; 67 private static final Value FETCH_EXHAUSTED = new BooleanValue(false) {}; 68 private static final Value FETCH_CONTINUE = new BooleanValue(false) {}; 69 private static final Value FETCH_SUCCESS = new BooleanValue(true) {}; 70 71 private final Env _env; 72 private final PDOError _error; 73 74 private final String _query; 75 76 private Statement _statement; 77 private PreparedStatement _preparedStatement; 78 79 private ResultSet _resultSet; 80 private ResultSetMetaData _resultSetMetaData; 81 private boolean _resultSetExhausted = true; 82 private String _lastInsertId; 83 84 private int _fetchMode = PDO.FETCH_BOTH; 85 private Value[] _fetchModeArgs = NULL_VALUES; 86 private ArrayList <BindColumn> _bindColumns; 87 private ArrayList <BindParam> _bindParams; 88 private IntMap _parameterNameMap; 89 90 PDOStatement(Env env, Connection conn, String query, boolean isPrepared, ArrayValue options) 91 throws SQLException 92 93 { 94 _env = env; 95 _error = new PDOError(_env); 96 97 _query = query; 98 99 env.addClose(this); 100 101 if (options != null && options.getSize() > 0) { 102 _env.notice(L.l("PDOStatement options unsupported")); 103 } 104 105 query = parseQueryString(query); 106 107 if (isPrepared) { 108 _statement = null; 109 _preparedStatement = conn.prepareStatement(query); 110 _preparedStatement.setEscapeProcessing(false); 111 } 112 else { 113 _preparedStatement = null; 114 115 Statement statement = null; 116 117 try { 118 statement = conn.createStatement(); 119 statement.setEscapeProcessing(false); 120 121 if (statement.execute(query)) { 122 _resultSet = statement.getResultSet(); 123 _resultSetExhausted = false; 124 } 125 126 _statement = statement; 127 128 statement = null; 129 130 } finally { 131 try { 132 if (statement != null) 133 statement.close(); 134 } catch (SQLException e) { 135 log.log(Level.FINE, e.toString(), e); 136 } 137 } 138 } 139 } 140 141 private String parseQueryString(String query) 143 { 144 final int queryLength = query.length(); 145 StringBuilder parsedQuery = new StringBuilder (queryLength); 146 147 int parameterCount = 0; 148 StringBuilder name = null; 149 150 int quote = 0; 151 152 for (int i = 0; i < queryLength + 1; i++) { 153 int ch = -1; 154 155 if (i < queryLength) 156 ch = query.charAt(i); 157 158 if (ch == '\'' || ch == '"') { 159 if (quote == 0) 160 quote = ch; 161 else if (quote == ch) 162 quote = 0; 163 } 164 else if (quote == 0 && ch == '?') { 165 parameterCount++; 166 } 167 else if (quote == 0 && ch == ':') { 168 parameterCount++; 169 name = new StringBuilder (); 170 continue; 171 } 172 else if (name != null && (ch == -1 || !Character.isJavaIdentifierStart(ch))) { 173 if (_parameterNameMap == null) 174 _parameterNameMap = new IntMap(); 175 176 _parameterNameMap.put(name.toString(), parameterCount); 177 178 parsedQuery.append('?'); 179 180 name = null; 181 } 182 183 if (ch != -1) { 184 if (name != null) 185 name.append((char) ch); 186 else 187 parsedQuery.append((char) ch); 188 } 189 } 190 191 return parsedQuery.toString(); 192 } 193 194 private boolean advanceResultSet() 195 { 196 if (_resultSet == null || _resultSetExhausted) 197 return false; 198 199 try { 200 boolean isNext = _resultSet.next(); 201 202 if (!isNext) 203 _resultSetExhausted = true; 204 205 if (!isNext) 206 return false; 207 208 if (_bindColumns != null) { 209 for (BindColumn bindColumn : _bindColumns) 210 if (!bindColumn.bind()) 211 return false; 212 } 213 214 return isNext; 215 } 216 catch (SQLException ex) { 217 _error.error(ex); 218 return false; 219 } 220 } 221 222 public boolean bindColumn(Value column, @Reference Value var, @Optional("-1") int type) 223 { 224 if (_bindColumns == null) 225 _bindColumns = new ArrayList <BindColumn>(); 226 227 try { 228 _bindColumns.add(new BindColumn(column, var, type)); 229 } 230 catch (SQLException ex) { 231 _error.error(ex); 232 return false; 233 } 234 235 return true; 236 } 237 238 public boolean bindParam(Value parameter, 239 @Reference Value variable, 240 @Optional("-1") int dataType, 241 @Optional("-1") int length, 242 @Optional Value driverOptions) 243 { 244 if (length != -1) 245 throw new UnimplementedException("length"); 246 247 if (!(driverOptions == null || driverOptions.isNull())) 248 throw new UnimplementedException("driverOptions"); 249 250 if (dataType == -1) 251 dataType = PDO.PARAM_STR; 252 253 boolean isInputOutput = (dataType & PDO.PARAM_INPUT_OUTPUT) != 0; 254 255 if (isInputOutput) { 256 dataType = dataType & (~PDO.PARAM_INPUT_OUTPUT); 257 if (true) throw new UnimplementedException("PARAM_INPUT_OUTPUT"); 258 } 259 260 switch (dataType) { 261 case PDO.PARAM_BOOL: 262 case PDO.PARAM_INT: 263 case PDO.PARAM_LOB: 264 case PDO.PARAM_NULL: 265 case PDO.PARAM_STMT: 266 case PDO.PARAM_STR: 267 break; 268 269 default: 270 _error.warning(L.l("unknown dataType `{0}'", dataType)); 271 return false; 272 } 273 274 if (_bindParams == null) 275 _bindParams = new ArrayList <BindParam>(); 276 277 BindParam bindParam = new BindParam(parameter, variable, dataType, length, driverOptions); 278 279 _bindParams.add(bindParam); 280 281 return true; 282 } 283 284 public boolean bindValue(Value parameter, 285 Value value, 286 @Optional("-1") int dataType) 287 { 288 return bindParam(parameter, value.toValue(), dataType, -1, null); 289 } 290 291 294 public boolean closeCursor() 295 { 296 if (_resultSet == null) 297 return false; 298 299 ResultSet resultSet = _resultSet; 300 301 _resultSet = null; 302 _resultSetMetaData = null; 303 _resultSetExhausted = true; 304 _lastInsertId = null; 305 306 try { 307 resultSet.close(); 308 } 309 catch (SQLException e) { 310 _error.error(e); 311 312 return false; 313 } 314 315 return true; 316 } 317 318 321 public int columnCount() 322 { 323 if (_resultSet == null) 324 return 0; 325 326 try { 327 return getResultSetMetaData().getColumnCount(); 328 } 329 catch (SQLException e) { 330 _error.error(e); 331 332 return 0; 333 } 334 } 335 336 public BindParam createBindParam(Value parameter, Value value, int dataType, int length, Value driverOptions) 337 { 338 return new BindParam(parameter, value, dataType, length, driverOptions); 339 } 340 341 public void close() 342 { 343 ResultSet resultSet = _resultSet; 344 Statement statement = _statement; 345 PreparedStatement preparedStatement = _preparedStatement; 346 347 _resultSet = null; 348 _resultSetMetaData = null; 349 _resultSetExhausted = true; 350 _lastInsertId = null; 351 _statement = null; 352 _preparedStatement = null; 353 354 if (resultSet != null) { 355 try { 356 resultSet.close(); 357 } 358 catch (SQLException e) { 359 log.log(Level.WARNING, e.toString(), e); 360 } 361 } 362 363 if (statement != null) { 364 try { 365 statement.close(); 366 } 367 catch (SQLException e) { 368 log.log(Level.WARNING, e.toString(), e); 369 } 370 } 371 372 if (preparedStatement != null) { 373 try { 374 preparedStatement.close(); 375 } 376 catch (SQLException e) { 377 log.log(Level.WARNING, e.toString(), e); 378 } 379 } 380 } 381 382 public String errorCode() 383 { 384 return _error.errorCode(); 385 } 386 387 public ArrayValue errorInfo() 388 { 389 return _error.errorInfo(); 390 } 391 392 400 public boolean execute(@Optional @ReadOnly Value inputParameters) 401 { 402 ArrayValue parameters; 405 406 if (inputParameters instanceof ArrayValue) 407 parameters = (ArrayValue) inputParameters; 408 else if (inputParameters instanceof DefaultValue) 409 parameters = null; 410 else { 411 _env.warning(L.l("'{0}' is an unexpected argument, expected ArrayValue", inputParameters)); 412 return false; 413 } 414 415 closeCursor(); 416 417 try { 418 _preparedStatement.clearParameters(); 419 _preparedStatement.clearWarnings(); 420 421 if (parameters != null) { 422 for (Map.Entry<Value, Value> entry : parameters.entrySet()) { 423 Value key = entry.getKey(); 424 425 if (key.isNumberConvertible()) { 426 if (! setParameter(key.toInt() + 1, entry.getValue(), -1)) 427 return false; 428 } 429 else { 430 if (! setParameter(resolveParameter(key), entry.getValue(), -1)) 431 return false; 432 } 433 } 434 } 435 else if (_bindParams != null) { 436 for (BindParam bindParam : _bindParams) { 437 if (!bindParam.apply()) 438 return false; 439 } 440 } 441 442 if (_preparedStatement.execute()) { 443 _resultSet = _preparedStatement.getResultSet(); 444 _resultSetExhausted = false; 445 } 446 447 SQLWarning sqlWarning = _preparedStatement.getWarnings(); 448 449 if (sqlWarning != null) { 450 _error.error(sqlWarning); 451 return false; 452 } 453 454 return true; 455 } catch (SQLException e) { 456 _error.error(e); 457 458 return false; 459 } 460 } 461 462 468 public Value fetch(@Optional int fetchMode, 469 @Optional("-1") int cursorOrientation, 470 @Optional("-1") int cursorOffset) 471 { 472 if (cursorOrientation != -1) 473 throw new UnimplementedException("fetch with cursorOrientation"); 474 475 if (cursorOffset != -1) 476 throw new UnimplementedException("fetch with cursorOffset"); 477 478 return fetchImpl(fetchMode, -1); 479 } 480 481 486 public Value fetchAll(@Optional("0") int fetchMode, @Optional("-1") int columnIndex) 487 { 488 int effectiveFetchMode; 489 490 if (fetchMode == 0) { 491 effectiveFetchMode = _fetchMode; 492 } 493 else { 494 effectiveFetchMode = fetchMode; 495 } 496 497 boolean isGroup = (fetchMode & PDO.FETCH_GROUP) != 0; 498 boolean isUnique = (fetchMode & PDO.FETCH_UNIQUE) != 0; 499 500 if (isGroup) 501 throw new UnimplementedException("PDO.FETCH_GROUP"); 502 503 if (isUnique) 504 throw new UnimplementedException("PDO.FETCH_UNIQUE"); 505 506 effectiveFetchMode = effectiveFetchMode & (~(PDO.FETCH_GROUP | PDO.FETCH_UNIQUE)); 507 508 switch (effectiveFetchMode) { 509 case PDO.FETCH_COLUMN: 510 break; 511 512 case PDO.FETCH_LAZY: 513 _error.warning(L.l("PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()")); 514 return BooleanValue.FALSE; 515 516 default: 517 if (columnIndex != -1) { 518 _error.warning(L.l("unexpected arguments")); 519 return BooleanValue.FALSE; 520 } 521 } 522 523 ArrayValueImpl rows = new ArrayValueImpl(); 524 525 while (true) { 526 Value value = fetchImpl(effectiveFetchMode, columnIndex); 527 528 if (value == FETCH_FAILURE) { 529 rows.clear(); 530 return rows; 531 } 532 533 if (value == FETCH_EXHAUSTED) 534 break; 535 536 if (value == FETCH_CONTINUE) 537 continue; 538 539 rows.put(value); 540 } 541 542 return rows; 543 } 544 545 private Value fetchAssoc() 546 { 547 try { 548 if (!advanceResultSet()) 549 return FETCH_EXHAUSTED; 550 551 if (_fetchModeArgs.length != 0) { 552 _error.notice(L.l("unexpected arguments")); 553 return FETCH_FAILURE; 554 } 555 556 ArrayValueImpl array = new ArrayValueImpl(); 557 558 int columnCount = getResultSetMetaData().getColumnCount(); 559 560 for (int i = 1; i <= columnCount; i++) { 561 String name = getResultSetMetaData().getColumnName(i); 562 Value value = getColumnValue(i); 563 564 array.put(new StringValueImpl(name), value); 565 } 566 567 return array; 568 } 569 catch (SQLException ex) { 570 _error.error(ex); 571 return FETCH_FAILURE; 572 } 573 } 574 575 private Value fetchBoth() 576 { 577 try { 578 if (!advanceResultSet()) 579 return FETCH_EXHAUSTED; 580 581 if (_fetchModeArgs.length != 0) { 582 _error.notice(L.l("unexpected arguments")); 583 return FETCH_FAILURE; 584 } 585 586 587 ArrayValueImpl array = new ArrayValueImpl(); 588 589 int columnCount = getResultSetMetaData().getColumnCount(); 590 591 for (int i = 1; i <= columnCount; i++) { 592 String name = getResultSetMetaData().getColumnName(i); 593 Value value = getColumnValue(i); 594 595 array.put(new StringValueImpl(name), value); 596 array.put(new LongValue(i - 1), value); 597 } 598 599 return array; 600 } 601 catch (SQLException ex) { 602 _error.error(ex); 603 return FETCH_FAILURE; 604 } 605 } 606 607 private Value fetchBound() 608 { 609 if (!advanceResultSet()) 610 return FETCH_EXHAUSTED; 611 612 return FETCH_SUCCESS; 613 } 614 615 private Value fetchClass() 616 { 617 String className; 618 Value[] ctorArgs; 619 620 if (_fetchModeArgs.length == 0 || _fetchModeArgs.length > 2) 621 return fetchBoth(); 622 623 className = _fetchModeArgs[0].toString(); 624 625 if (_fetchModeArgs.length == 2) { 626 if (_fetchModeArgs[1].isArray()) { 627 ArrayValue argsArray = (ArrayValue) _fetchModeArgs[1]; 629 630 ctorArgs = new Value[argsArray.getSize()]; 631 632 int i = 0; 633 634 for (Value key : argsArray.keySet()) 635 ctorArgs[i++] = argsArray.getRef(key); 636 } 637 else 638 return fetchBoth(); 639 } 640 else 641 ctorArgs = NULL_VALUES; 642 643 return fetchObject(className, ctorArgs); 644 } 645 646 649 public Value fetchColumn(@Optional int column) 650 { 651 if (!advanceResultSet()) 652 return FETCH_EXHAUSTED; 653 654 if (column < 0 && _fetchModeArgs.length > 0) 655 column = _fetchModeArgs[0].toInt(); 656 657 try { 658 if (column < 0 || column >= getResultSetMetaData().getColumnCount()) 659 return FETCH_CONTINUE; 660 661 return getColumnValue(column + 1); 662 } 663 catch (SQLException ex) { 664 _error.error(ex); 665 return FETCH_FAILURE; 666 } 667 } 668 669 private Value fetchFunc() 670 { 671 throw new UnimplementedException(); 672 } 673 674 680 private Value fetchImpl(int fetchMode, int columnIndex) 681 { 682 if (fetchMode == 0) { 683 fetchMode = _fetchMode; 684 685 fetchMode = fetchMode & (~(PDO.FETCH_GROUP | PDO.FETCH_UNIQUE)); 686 } 687 else { 688 if ((fetchMode & PDO.FETCH_GROUP) != 0) { 689 _error.warning(L.l("FETCH_GROUP is not allowed")); 690 return BooleanValue.FALSE; 691 } 692 else if ((fetchMode & PDO.FETCH_UNIQUE) != 0) { 693 _error.warning(L.l("FETCH_UNIQUE is not allowed")); 694 return BooleanValue.FALSE; 695 } 696 } 697 698 boolean isClasstype = (fetchMode & PDO.FETCH_CLASSTYPE) != 0; 699 boolean isSerialize = (fetchMode & PDO.FETCH_SERIALIZE) != 0; 700 701 fetchMode = fetchMode & (~(PDO.FETCH_CLASSTYPE | PDO.FETCH_SERIALIZE)); 702 703 switch (fetchMode) { 704 case PDO.FETCH_ASSOC: 705 return fetchAssoc(); 706 707 case PDO.FETCH_BOTH: 708 return fetchBoth(); 709 710 case PDO.FETCH_BOUND: 711 return fetchBound(); 712 713 case PDO.FETCH_COLUMN: 714 return fetchColumn(columnIndex); 715 716 case PDO.FETCH_CLASS: 717 return fetchClass(); 718 719 case PDO.FETCH_FUNC: 720 return fetchFunc(); 721 722 case PDO.FETCH_INTO: 723 return fetchInto(); 724 725 case PDO.FETCH_LAZY: 726 return fetchLazy(); 727 728 case PDO.FETCH_NAMED: 729 return fetchNamed(); 730 731 case PDO.FETCH_NUM: 732 return fetchNum(); 733 734 case PDO.FETCH_OBJ: 735 return fetchObject(); 736 737 default: 738 _error.warning(L.l("invalid fetch mode {0}", fetchMode)); 739 closeCursor(); 740 return BooleanValue.FALSE; 741 } 742 } 743 744 private Value fetchInto() 745 { 746 assert _fetchModeArgs.length > 0; 747 assert _fetchModeArgs[0].isObject(); 748 749 Value var = _fetchModeArgs[0]; 750 751 if (!advanceResultSet()) 752 return FETCH_EXHAUSTED; 753 754 try { 755 int columnCount = getResultSetMetaData().getColumnCount(); 756 757 for (int i = 1; i <= columnCount; i++) { 758 String name = getResultSetMetaData().getColumnName(i); 759 Value value = getColumnValue(i); 760 761 var.putField(_env, name, value); 762 } 763 } 764 catch (SQLException ex) { 765 _error.error(ex); 766 return FETCH_FAILURE; 767 } 768 769 return var; 770 } 771 772 private Value fetchLazy() 773 { 774 return fetchObject(null, NULL_VALUES); 776 } 777 778 private Value fetchNamed() 779 { 780 try { 781 if (!advanceResultSet()) 782 return FETCH_EXHAUSTED; 783 784 ArrayValue array = new ArrayValueImpl(); 785 786 int columnCount = getResultSetMetaData().getColumnCount(); 787 788 for (int i = 1; i <= columnCount; i++) { 789 Value name = new StringValueImpl(getResultSetMetaData().getColumnName(i)); 790 Value value = getColumnValue(i); 791 792 Value existingValue = array.get(name); 793 794 if (! (existingValue instanceof UnsetValue)) { 795 796 if (! existingValue.isArray()) { 797 ArrayValue arrayValue = new ArrayValueImpl(); 798 arrayValue.put(existingValue); 799 array.put(name, arrayValue); 800 existingValue = arrayValue; 801 } 802 803 existingValue.put(value); 804 } 805 else 806 array.put(name, value); 807 } 808 809 return array; 810 } 811 catch (SQLException ex) { 812 _error.error(ex); 813 return FETCH_FAILURE; 814 } 815 } 816 817 private Value fetchNum() 818 { 819 try { 820 if (!advanceResultSet()) 821 return FETCH_EXHAUSTED; 822 823 if (_fetchModeArgs.length != 0) { 824 _error.notice(L.l("unexpected arguments")); 825 return FETCH_FAILURE; 826 } 827 828 ArrayValueImpl array = new ArrayValueImpl(); 829 830 int columnCount = getResultSetMetaData().getColumnCount(); 831 832 for (int i = 1; i <= columnCount; i++) { 833 Value value = getColumnValue(i); 834 835 array.put(value); 836 } 837 838 return array; 839 } 840 catch (SQLException ex) { 841 _error.error(ex); 842 return FETCH_FAILURE; 843 } 844 } 845 846 private Value fetchObject() 847 { 848 return fetchObject(null, NULL_VALUES); 849 } 850 851 public Value fetchObject(@Optional String className, @Optional Value[] args) 852 { 853 QuercusClass cl; 854 855 if (className != null) { 856 cl = _env.findAbstractClass(className); 857 858 if (cl == null) 859 return fetchBoth(); 860 } 861 else { 862 cl = null; 863 864 if (args.length != 0) { 865 advanceResultSet(); 866 _error.warning(L.l("unexpected arguments")); 867 return BooleanValue.FALSE; 868 } 869 } 870 871 if (!advanceResultSet()) 872 return FETCH_EXHAUSTED; 873 874 try { 875 Value object; 876 877 if (cl != null) 878 object = cl.callNew(_env, args); 879 else 880 object = _env.createObject(); 881 882 int columnCount = getResultSetMetaData().getColumnCount(); 883 884 for (int i = 1; i <= columnCount; i++) { 885 String name = getResultSetMetaData().getColumnName(i); 886 Value value = getColumnValue(i); 887 888 object.putField(_env, name, value); 889 } 890 891 return object; 892 } 893 catch (Throwable ex) { 894 _error.error(ex); 895 return FETCH_FAILURE; 896 } 897 898 } 899 900 public Value getAttribute(int attribute) 901 { 902 _error.unsupportedAttribute(attribute); 903 904 return BooleanValue.FALSE; 905 } 906 907 910 public Value getColumnMeta(int column) 911 { 912 throw new UnimplementedException(); 913 } 914 915 918 private Value getColumnValue(int column) 919 throws SQLException 920 { 921 return getColumnValue(column, -1, -1); 922 } 923 924 929 private Value getColumnValue(int column, int jdbcType, int returnType) 930 throws SQLException 931 { 932 if (returnType != -1) 933 throw new UnimplementedException("parm type " + returnType); 934 935 if (jdbcType == -1) 936 jdbcType = getResultSetMetaData().getColumnType(column); 937 938 940 switch (jdbcType) { 941 case Types.NULL: 942 return NullValue.NULL; 943 944 case Types.BIT: 945 case Types.TINYINT: 946 case Types.SMALLINT: 947 case Types.INTEGER: 948 case Types.BIGINT: 949 { 950 String value = _resultSet.getString(column); 951 952 if (value == null || _resultSet.wasNull()) 953 return NullValue.NULL; 954 else 955 return new StringValueImpl(value); 956 } 957 958 case Types.DOUBLE: 959 { 960 double value = _resultSet.getDouble(column); 961 962 if (_resultSet.wasNull()) 963 return NullValue.NULL; 964 else 965 return (new DoubleValue(value)).toStringValue(); 966 } 967 968 970 default: 971 { 972 String value = _resultSet.getString(column); 973 974 if (value == null || _resultSet.wasNull()) 975 return NullValue.NULL; 976 else 977 return new StringValueImpl(value); 978 } 979 } 980 981 } 982 983 private ResultSetMetaData getResultSetMetaData() 984 throws SQLException 985 { 986 if (_resultSetMetaData == null) 987 _resultSetMetaData = _resultSet.getMetaData(); 988 989 return _resultSetMetaData; 990 } 991 992 995 public Iterator <Value> iterator() 996 { 997 Value value = fetchAll(0, -1); 998 999 if (value instanceof ArrayValue) 1000 return ((ArrayValue) value).values().iterator(); 1001 else { 1002 Set <Value> emptySet = Collections.emptySet(); 1003 return emptySet.iterator(); 1004 } 1005 } 1006 1007 String lastInsertId(String name) 1008 { 1009 if (!(name == null || name.length() == 0)) 1010 throw new UnimplementedException("lastInsertId with name "); 1011 1012 if (_lastInsertId != null) 1013 return _lastInsertId; 1014 1015 String lastInsertId = null; 1016 1017 Statement stmt; 1018 1019 if (_preparedStatement != null) 1020 stmt = _preparedStatement; 1021 else 1022 stmt = _statement; 1023 1024 ResultSet resultSet = null; 1025 1026 try { 1027 resultSet = stmt.getGeneratedKeys(); 1028 1029 if (resultSet.next()) 1030 lastInsertId = resultSet.getString(1); 1031 } 1032 catch (SQLException ex) { 1033 _error.error(ex); 1034 } 1035 finally { 1036 try { 1037 if (resultSet != null) 1038 resultSet.close(); 1039 } 1040 catch (SQLException ex) { 1041 log.log(Level.WARNING, ex.toString(), ex); 1042 } 1043 } 1044 1045 _lastInsertId = lastInsertId == null ? "0" : lastInsertId; 1046 1047 return _lastInsertId; 1048 } 1049 1050 public boolean nextRowset() 1051 { 1052 throw new UnimplementedException(); 1053 } 1054 1055 private int resolveParameter(Value parameter) 1056 { 1057 int index = -1; 1058 1059 if (parameter instanceof LongValue) { 1060 index = parameter.toInt(); 1062 } 1063 else { 1064 String name = parameter.toString(); 1065 1066 if (name.length() > 1 && name.charAt(0) == ':') { 1067 name = name.substring(1); 1068 if (_parameterNameMap != null) 1069 index = _parameterNameMap.get(name); 1070 } 1071 else 1072 index = parameter.toInt(); 1073 } 1074 1075 return index; 1076 } 1077 1078 public int rowCount() 1079 { 1080 if (_resultSet == null) 1081 return 0; 1082 1083 try { 1084 int row = _resultSet.getRow(); 1085 1086 try { 1087 _resultSet.last(); 1088 1089 return _resultSet.getRow(); 1090 } 1091 finally { 1092 if (row == 0) 1093 _resultSet.beforeFirst(); 1094 else 1095 _resultSet.absolute(row); 1096 } 1097 } 1098 catch (SQLException ex) { 1099 _error.error(ex); 1100 return 0; 1101 } 1102 } 1103 1104 public boolean setAttribute(int attribute, Value value) 1105 { 1106 return setAttribute(attribute, value, false); 1107 } 1108 1109 public boolean setAttribute(int attribute, Value value, boolean isFromConstructor) 1110 { 1111 if (isFromConstructor) { 1112 switch (attribute) { 1113 case PDO.CURSOR_FWDONLY: 1114 case PDO.CURSOR_SCROLL: 1115 return setCursor(attribute); 1116 } 1117 } 1118 1119 _error.unsupportedAttribute(attribute); 1120 1121 return false; 1122 } 1123 1124 private boolean setCursor(int attribute) 1125 { 1126 switch (attribute) { 1127 case PDO.CURSOR_FWDONLY: 1128 throw new UnimplementedException(); 1129 case PDO.CURSOR_SCROLL: 1130 throw new UnimplementedException(); 1131 1132 default: 1133 _error.unsupportedAttribute(attribute); 1134 return false; 1135 } 1136 } 1137 1138 1139 1142 public boolean setFetchMode(int fetchMode, Value[] args) 1143 { 1144 _fetchMode = PDO.FETCH_BOTH; 1145 _fetchModeArgs = NULL_VALUES; 1146 1147 int fetchStyle = fetchMode; 1148 1149 boolean isGroup = (fetchMode & PDO.FETCH_GROUP) != 0; 1150 boolean isUnique = (fetchMode & PDO.FETCH_UNIQUE) != 0; 1151 1152 if (isGroup) 1153 throw new UnimplementedException("PDO.FETCH_GROUP"); 1154 1155 if (isUnique) 1156 throw new UnimplementedException("PDO.FETCH_UNIQUE"); 1157 1158 fetchStyle = fetchStyle & (~(PDO.FETCH_GROUP | PDO.FETCH_UNIQUE)); 1159 1160 boolean isClasstype = (fetchMode & PDO.FETCH_CLASSTYPE) != 0; 1161 boolean isSerialize = (fetchMode & PDO.FETCH_SERIALIZE) != 0; 1162 1163 fetchStyle = fetchStyle & (~(PDO.FETCH_CLASSTYPE | PDO.FETCH_SERIALIZE)); 1164 1165 switch (fetchStyle) { 1166 case PDO.FETCH_ASSOC: 1167 case PDO.FETCH_BOTH: 1168 case PDO.FETCH_BOUND: 1169 case PDO.FETCH_LAZY: 1170 case PDO.FETCH_NAMED: 1171 case PDO.FETCH_NUM: 1172 case PDO.FETCH_OBJ: 1173 break; 1174 1175 case PDO.FETCH_CLASS: 1176 if (args.length < 1 || args.length > 2) 1177 return false; 1178 1179 if (_env.findAbstractClass(args[0].toString()) == null) 1180 return false; 1181 1182 if (args.length == 2 && !(args[1].isNull() || args[1].isArray())) { 1183 _env.warning(L.l("constructor args must be an array")); 1184 1185 return false; 1186 } 1187 1188 break; 1189 1190 case PDO.FETCH_COLUMN: 1191 if (args.length != 1) 1192 return false; 1193 1194 break; 1195 1196 case PDO.FETCH_FUNC: 1197 _error.warning(L.l("PDO::FETCH_FUNC can only be used with PDOStatement::fetchAll()")); 1198 return false; 1199 1200 case PDO.FETCH_INTO: 1201 if (args.length != 1 || !args[0].isObject()) 1202 return false; 1203 1204 break; 1205 1206 default: 1207 _error.warning(L.l("invalid fetch mode")); 1208 break; 1209 } 1210 1211 _fetchModeArgs = args; 1212 _fetchMode = fetchMode; 1213 1214 return true; 1215 } 1216 1217 1223 private boolean setLobParameter(int index, Value value, long length) 1224 { 1225 try { 1226 if (value == null || value.isNull()) { 1227 _preparedStatement.setObject(index, null); 1228 } 1229 else if (value instanceof StringValue) { 1230 if (length < 0) { 1231 _preparedStatement.setBinaryStream(index, value.toInputStream(), value.toString().length()); 1232 } 1233 else 1234 _preparedStatement.setBinaryStream(index, value.toInputStream(), (int) length); 1235 } 1236 else { 1237 InputStream inputStream = value.toInputStream(); 1238 1239 if (inputStream == null) { 1240 _error.warning(L.l("type {0} ({1}) for parameter index {2} cannot be used for lob", value.getType(), value.getClass(), index)); 1241 return false; 1242 } 1243 1244 if (length < 0 && (value instanceof FileReadValue)) { 1245 length = ((FileReadValue) value).getLength(); 1246 1247 if (length <= 0) 1248 length = -1; 1249 } 1250 1251 if (length < 0) { 1252 TempBuffer tempBuffer = TempBuffer.allocate(); 1253 1254 try { 1255 byte[] bytes = new byte[1024]; 1256 1257 int len; 1258 1259 while ((len = inputStream.read(bytes, 0, 1024)) != -1) 1260 tempBuffer.write(bytes, 0, len); 1261 } 1262 catch (IOException ex) { 1263 _error.error(ex); 1264 return false; 1265 } 1266 1267 TempReadStream tempReadStream = new TempReadStream(tempBuffer); 1268 tempReadStream.setFreeWhenDone(true); 1269 1270 _preparedStatement.setBinaryStream(index, new ReadStream(tempReadStream), tempBuffer.getLength()); 1271 } 1272 else 1273 _preparedStatement.setBinaryStream(index, inputStream, (int) length); 1274 } 1275 } 1276 catch (SQLException ex) { 1277 _error.error(ex); 1278 return false; 1279 } 1280 1281 return true; 1282 } 1283 1284 1290 private boolean setParameter(int index, Value value, long length) 1291 { 1292 try { 1293 if (value instanceof DoubleValue) { 1294 _preparedStatement.setDouble(index, value.toDouble()); 1295 } 1296 else if (value instanceof LongValue) { 1297 _preparedStatement.setLong(index, value.toLong()); 1298 } 1299 else if (value instanceof StringValue) { 1300 String string = value.toString(); 1301 1302 if (length >= 0) 1303 string = string.substring(0, (int) length); 1304 1305 _preparedStatement.setString(index, string); 1306 } 1307 else if (value instanceof NullValue) { 1308 _preparedStatement.setObject(index, null); 1309 } 1310 else { 1311 _error.warning(L.l("unknown type {0} ({1}) for parameter index {2}", value.getType(), value.getClass(), index)); 1312 return false; 1313 } 1314 } 1315 catch (SQLException ex) { 1316 _error.error(ex); 1317 return false; 1318 } 1319 1320 return true; 1321 } 1322 1323 public String toString() 1324 { 1325 return "PDOStatement[" + _query + "]"; 1326 } 1327 1328 1331 private class BindColumn { 1332 private final String _columnAsName; 1333 private final Value _var; 1334 private final int _type; 1335 1336 private int _column; 1337 private int _jdbcType; 1338 1339 private boolean _isInit; 1340 private boolean _isValid; 1341 1342 1347 private BindColumn(Value column, Value var, int type) 1348 throws SQLException 1349 { 1350 assert column != null; 1351 assert var != null; 1352 1353 if (column.isNumberConvertible()) { 1354 _column = column.toInt(); 1355 _columnAsName = null; 1356 } 1357 else { 1358 _columnAsName = column.toString(); 1359 } 1360 1361 _var = var; 1362 _type = type; 1363 1364 if (_resultSet != null) 1365 init(); 1366 } 1367 1368 private boolean init() 1369 throws SQLException 1370 { 1371 if (_isInit) 1372 return true; 1373 1374 ResultSetMetaData resultSetMetaData = getResultSetMetaData(); 1375 1376 int columnCount = resultSetMetaData.getColumnCount(); 1377 1378 if (_columnAsName != null) { 1379 1380 for (int i = 1; i <= columnCount; i++) { 1381 String name = resultSetMetaData.getColumnName(i); 1382 if (name.equals(_columnAsName)) { 1383 _column = i; 1384 break; 1385 } 1386 } 1387 } 1388 1389 _isValid = _column > 0 && _column <= columnCount; 1390 1391 if (_isValid) { 1392 _jdbcType = resultSetMetaData.getColumnType(_column); 1393 } 1394 1395 _isInit = true; 1396 1397 return true; 1398 } 1399 1400 public boolean bind() 1401 throws SQLException 1402 { 1403 if (!init()) 1404 return false; 1405 1406 if (!_isValid) { 1407 _var.set(StringValueImpl.EMPTY); 1409 } 1410 else { 1411 Value value = getColumnValue(_column, _jdbcType, _type); 1412 1413 _var.set(value); 1414 } 1415 1416 return true; 1417 } 1418 } 1419 1420 1423 private class BindParam { 1424 private final int _index; 1425 private final Value _value; 1426 private final int _dataType; 1427 private final int _length; 1428 private final Value _driverOptions; 1429 1430 public BindParam(Value parameter, Value value, int dataType, int length, Value driverOptions) 1431 { 1432 int index = resolveParameter(parameter); 1433 1434 _index = index; 1435 _value = value; 1436 _dataType = dataType; 1437 _length = length; 1438 _driverOptions = driverOptions; 1439 } 1440 1441 public boolean apply() 1442 throws SQLException 1443 { 1444 switch (_dataType) { 1445 case PDO.PARAM_BOOL: 1446 case PDO.PARAM_INT: 1447 case PDO.PARAM_STR: 1448 return setParameter(_index, _value.toValue(), _length); 1449 case PDO.PARAM_LOB: 1450 return setLobParameter(_index, _value.toValue(), _length); 1451 case PDO.PARAM_NULL: 1452 return setParameter(_index, NullValue.NULL, _length); 1453 case PDO.PARAM_STMT: 1454 throw new UnimplementedException("PDO.PARAM_STMT"); 1455 default: 1456 throw new AssertionError (); 1457 } 1458 } 1459 } 1460} 1461 | Popular Tags |