/** Compatibility with Tempfile#make_tmpname(basename, n) in MRI */ @JRubyMethod(visibility = PRIVATE) public IRubyObject make_tmpname( ThreadContext context, IRubyObject basename, IRubyObject n, Block block) { Ruby runtime = context.getRuntime(); IRubyObject[] newargs = new IRubyObject[5]; IRubyObject base, suffix; if (basename instanceof RubyArray) { RubyArray array = (RubyArray) basename; int length = array.getLength(); base = length > 0 ? array.eltInternal(0) : runtime.getNil(); suffix = length > 0 ? array.eltInternal(1) : runtime.getNil(); } else { base = basename; suffix = runtime.newString(""); } newargs[0] = runtime.newString("%s.%d.%d%s"); newargs[1] = base; newargs[2] = runtime.getGlobalVariables().get("$$"); // PID newargs[3] = n; newargs[4] = suffix; return callMethod(context, "sprintf", newargs); }
/** * Assist with setting the parameter values on a PreparedStatement * * @param ps the PreparedStatement for which parameters should be set * @param recv * @param args an array of parameter values */ private static void prepareStatementFromArgs( PreparedStatement ps, IRubyObject recv, IRubyObject[] args) { int index = 1; try { for (IRubyObject arg : args) { // Handle multiple valued arguments, i.e. arrays + ranges if (arg instanceof RubyArray) { // Handle a RubyArray passed into a query // // NOTE: This should not call ps.setArray(i,v) as this is // designed to work with the SQL Array type, and in most cases // is not what we want. // Instead, this functionality is for breaking down a Ruby // array of ["a","b","c"] into SQL "('a','b','c')": // // So, in this case, we actually want to augment the number of // ? params in the PreparedStatement query appropriately. RubyArray array_value = arg.convertToArray(); for (int j = 0; j < array_value.getLength(); j++) { setPreparedStatementParam(ps, recv, array_value.eltInternal(j), index++); } } else if (arg instanceof RubyRange) { // Handle a RubyRange passed into a query // // NOTE: see above - need to augment the number of ? params // in the PreparedStatement: (? AND ?) RubyRange range_value = (RubyRange) arg; setPreparedStatementParam(ps, recv, range_value.first(), index++); setPreparedStatementParam(ps, recv, range_value.last(), index++); } else { // Otherwise, handle each argument setPreparedStatementParam(ps, recv, arg, index++); } } } catch (SQLException sqle) { // TODO: log sqle.printStackTrace(); // TODO: possibly move this exception string parsing somewhere else Pattern pattern = Pattern.compile( "Parameter index out of bounds. (\\d+) is not between valid values of (\\d+) and (\\d+)"); Matcher matcher = pattern.matcher(sqle.getMessage()); if (matcher.matches()) { throw recv.getRuntime() .newArgumentError( String.format( "Binding mismatch: %1$d for %2$d", Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)))); } else { throw DataObjectsUtils.newDriverError(recv.getRuntime(), errorName, sqle); } } }
@Override public long[] toNative(IRubyObject value, ToNativeContext context) { RubyArray rbArray = value.convertToArray(); long[] arr = new long[rbArray.getLength()]; if (ArrayFlags.isIn(arrayFlags)) { for (int i = 0; i < arr.length; i++) { arr[i] = Util.longValue(rbArray.entry(i)); } } return arr; }
@Override public void assignArray( Ruby runtime, ThreadContext context, IRubyObject self, IRubyObject arg, Block block) { RubyArray values = (RubyArray) arg; int valueLength = values.getLength(); switch (valueLength) { case 0: assign(runtime, context, self, block); break; case 1: assign(runtime, context, self, values.eltInternal(0), block); break; case 2: assign(runtime, context, self, values.eltInternal(0), values.eltInternal(1), block); break; case 3: assign( runtime, context, self, values.eltInternal(0), values.eltInternal(1), values.eltInternal(2), block); break; } // Populate up to shorter of calling arguments or local parameters in the block for (int i = 0; i < preLength && i < valueLength; i++) { pre.get(i).assign(runtime, context, self, values.eltInternal(i), block, false); } // nil pad since we provided less values than block parms if (valueLength < preLength) { assignNilTo(runtime, context, self, block, valueLength); } else if (valueLength == preLength) { // no extra args for rest rest.assign( runtime, context, self, runtime.newArrayNoCopyLight(IRubyObject.NULL_ARRAY), block, true); } else { // extra args for rest rest.assign( runtime, context, self, values.subseqLight(preLength, valueLength - preLength), block, true); } }
@Override public void accept(ThreadContext context, SaveContextVisitor visitor) { visitor.enter((Element) node); XmlNodeSet xmlNodeSet = (XmlNodeSet) children(context); if (xmlNodeSet.length() > 0) { RubyArray array = (RubyArray) xmlNodeSet.to_a(context); for (int i = 0; i < array.getLength(); i++) { Object item = array.get(i); if (item instanceof XmlNode) { XmlNode cur = (XmlNode) item; cur.accept(context, visitor); } else if (item instanceof XmlNamespace) { XmlNamespace cur = (XmlNamespace) item; cur.accept(context, visitor); } } } visitor.leave((Element) node); }
@Override public Object interpret( ThreadContext context, IRubyObject self, IRubyObject[] args, Block block, Object exception, Object[] temp) { IRubyObject receiver = (IRubyObject) arg1.retrieve(context, self, temp); IRubyObject value = (IRubyObject) arg2.retrieve(context, self, temp); if (value == UndefinedValue.UNDEFINED) { result.store(context, self, temp, receiver); } else if (receiver instanceof RubyArray) { RubyArray testVals = (RubyArray) receiver; for (int i = 0, n = testVals.getLength(); i < n; i++) { IRubyObject excType = (IRubyObject) testVals.eltInternal(i); if (!(excType instanceof RubyModule)) { throw context .getRuntime() .newTypeError("class or module required for rescue clause. Found: " + excType); } IRubyObject eqqVal = excType.callMethod(context, "===", value); if (eqqVal.isTrue()) { result.store(context, self, temp, eqqVal); return null; } } result.store(context, self, temp, context.getRuntime().newBoolean(false)); } else { if (!(receiver instanceof RubyModule)) { throw context .getRuntime() .newTypeError("class or module required for rescue clause. Found: " + receiver); } result.store(context, self, temp, receiver.callMethod(context, "===", value)); } return null; }
/** * Assist with setting the parameter values on a PreparedStatement * * @param sqlText * @param ps the PreparedStatement for which parameters should be set * @param args an array of parameter values * @return true if there is return parameter, false if there is not */ private boolean prepareStatementFromArgs( String sqlText, PreparedStatement ps, IRubyObject[] args) { int index = 1; boolean hasReturnParam = false; try { int psCount = ps.getParameterMetaData().getParameterCount(); // fail fast if (args.length > psCount) { throw getRuntime().newArgumentError("Binding mismatch: " + args.length + " for " + psCount); } for (IRubyObject arg : args) { // Handle multiple valued arguments, i.e. arrays + ranges if (arg instanceof RubyArray) { // Handle a RubyArray passed into a query // // NOTE: This should not call ps.setArray(i,v) as this is // designed to work with the SQL Array type, and in most cases // is not what we want. // Instead, this functionality is for breaking down a Ruby // array of ["a","b","c"] into SQL "('a','b','c')": // // So, in this case, we actually want to augment the number of // ? params in the PreparedStatement query appropriately. RubyArray arrayValues = arg.convertToArray(); for (int j = 0; j < arrayValues.getLength(); j++) { driver.setPreparedStatementParam(ps, arrayValues.eltInternal(j), index++); } } else if (arg instanceof RubyRange) { // Handle a RubyRange passed into a query // // NOTE: see above - need to augment the number of ? params // in the PreparedStatement: (? AND ?) RubyRange range_value = (RubyRange) arg; driver.setPreparedStatementParam(ps, range_value.first(), index++); driver.setPreparedStatementParam(ps, range_value.last(), index++); } else { // Otherwise, handle each argument driver.setPreparedStatementParam(ps, arg, index++); } } // callback for binding RETURN ... INTO ... output parameter if (driver.registerPreparedStatementReturnParam(sqlText, ps, index)) { index++; hasReturnParam = true; } if ((index - 1) < psCount) { throw getRuntime().newArgumentError("Binding mismatch: " + (index - 1) + " for " + psCount); } return hasReturnParam; } catch (SQLException sqle) { // TODO: possibly move this exception string parsing somewhere else Pattern pattern = Pattern.compile( "Parameter index out of bounds. (\\d+) is not between valid values of (\\d+) and (\\d+)"); // POSTGRES: The column index is out of range: 2, number of columns: 1. // POSTGRES SQL STATE: 22023 (22023 "INVALID PARAMETER VALUE" invalid_parameter_value) // SQLITE3: Does not throw a SQLException! // H2: Invalid value 2 for parameter parameterIndex [90008-63] // HSQLDB: Invalid argument in JDBC call: parameter index out of range: 2 // DERBY: The parameter position '2' is out of range. The number of parameters for this // prepared statement is '1' // DERbY SQL CODE: XCL13 Matcher matcher = pattern.matcher(sqle.getMessage()); if (matcher.matches()) { throw getRuntime() .newArgumentError( String.format( "Binding mismatch: %1$d for %2$d", Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)))); } else { throw Errors.newSqlError(getRuntime(), driver, sqle); } } }