/** Initialize the SEQUENCE key generator. */ public SequenceKeyGenerator(PersistenceFactory factory, Properties params, int sqlType) throws MappingException { boolean returning; _factoryName = factory.getFactoryName(); returning = "true".equals(params.getProperty("returning")); _triggerPresent = "true".equals(params.getProperty("trigger", "false")); if (!_factoryName.equals(OracleFactory.FACTORY_NAME) && !_factoryName.equals(PostgreSQLFactory.FACTORY_NAME) && !_factoryName.equals(InterbaseFactory.FACTORY_NAME) && !_factoryName.equals("sapdb") && !_factoryName.equals(DB2Factory.FACTORY_NAME)) { throw new MappingException( Messages.format("mapping.keyGenNotCompatible", getClass().getName(), _factoryName)); } if (!_factoryName.equals(OracleFactory.FACTORY_NAME) && returning) { throw new MappingException( Messages.format( "mapping.keyGenParamNotCompat", "returning=\"true\"", getClass().getName(), _factoryName)); } _factory = factory; _seqName = params.getProperty("sequence", "{0}_seq"); _style = (_factoryName.equals(PostgreSQLFactory.FACTORY_NAME) || _factoryName.equals(InterbaseFactory.FACTORY_NAME) || _factoryName.equals(DB2Factory.FACTORY_NAME) ? BEFORE_INSERT : (returning ? DURING_INSERT : AFTER_INSERT)); if (_triggerPresent && !returning) { _style = AFTER_INSERT; } if (_triggerPresent && _style == BEFORE_INSERT) throw new MappingException( Messages.format( "mapping.keyGenParamNotCompat", "trigger=\"true\"", getClass().getName(), _factoryName)); _sqlType = sqlType; supportsSqlType(sqlType); try { _increment = Integer.parseInt(params.getProperty("increment", "1")); } catch (NumberFormatException nfe) { _increment = 1; } }
protected FieldDescriptorImpl createFieldDesc(final Class javaClass, final FieldMapping fieldMap) throws MappingException { // If not an SQL field, return a stock field descriptor. Sql sql = fieldMap.getSql(); if (sql == null) { return super.createFieldDesc(javaClass, fieldMap); } String fieldName = fieldMap.getName(); // If the field type is supplied, grab it and use it to locate the // field/accessor. Class fieldType = null; if (fieldMap.getType() != null) { fieldType = resolveType(fieldMap.getType()); } // If the field is declared as a collection, grab the collection type as // well and use it to locate the field/accessor. CollectionHandler colHandler = null; boolean isLazy = fieldMap.getLazy(); if (fieldMap.getCollection() != null) { Class colType = CollectionHandlers.getCollectionType(fieldMap.getCollection().toString()); colHandler = CollectionHandlers.getHandler(colType); if (colType.getName().equals("java.util.Iterator") && isLazy) { String err = "Lazy loading not supported for collection type 'iterator'"; throw new MappingException(err); } if (colType.getName().equals("java.util.Enumeration") && isLazy) { String err = "Lazy loading not supported for collection type 'enumerate'"; throw new MappingException(err); } } TypeInfo typeInfo = getTypeInfo(fieldType, colHandler, fieldMap); ExtendedFieldHandler exfHandler = null; FieldHandler handler = null; // -- check for user supplied FieldHandler if (fieldMap.getHandler() != null) { Class handlerClass = resolveType(fieldMap.getHandler()); if (!FieldHandler.class.isAssignableFrom(handlerClass)) { String err = "The class '" + fieldMap.getHandler() + "' must implement " + FieldHandler.class.getName(); throw new MappingException(err); } // -- get default constructor to invoke. We can't use the // -- newInstance method unfortunately becaue FieldHandler // -- overloads this method Constructor constructor = null; try { constructor = handlerClass.getConstructor(new Class[0]); handler = (FieldHandler) constructor.newInstance(new Object[0]); } catch (Exception except) { String err = "The class '" + handlerClass.getName() + "' must have a default public constructor."; throw new MappingException(err); } // -- ExtendedFieldHandler? if (handler instanceof ExtendedFieldHandler) { exfHandler = (ExtendedFieldHandler) handler; } // -- Fix for Castor JDO from Steve Vaughan, Castor JDO // -- requires FieldHandlerImpl or a ClassCastException // -- will be thrown... [KV 20030131 - also make sure this new handler // -- doesn't use it's own CollectionHandler otherwise // -- it'll cause unwanted calls to the getValue method during // -- unmarshalling] colHandler = typeInfo.getCollectionHandler(); typeInfo.setCollectionHandler(null); handler = new FieldHandlerImpl(handler, typeInfo); typeInfo.setCollectionHandler(colHandler); // -- End Castor JDO fix } boolean generalized = (exfHandler instanceof GeneralizedFieldHandler); // -- if generalized we need to change the fieldType to whatever // -- is specified in the GeneralizedFieldHandler so that the // -- correct getter/setter methods can be found FieldHandler custom = handler; if (generalized) { fieldType = ((GeneralizedFieldHandler) exfHandler).getFieldType(); } if (generalized || (handler == null)) { // -- create TypeInfoRef to get new TypeInfo from call // -- to createFieldHandler TypeInfoReference typeInfoRef = new TypeInfoReference(); typeInfoRef.typeInfo = typeInfo; handler = createFieldHandler(javaClass, fieldType, fieldMap, typeInfoRef); if (custom != null) { ((GeneralizedFieldHandler) exfHandler).setFieldHandler(handler); handler = custom; } else { typeInfo = typeInfoRef.typeInfo; } } String[] sqlName = sql.getName(); String[] sqlTypes = getSqlTypes(fieldMap); int[] sqlTypeNum; if (sqlTypes.length > 0) { sqlTypeNum = new int[sqlTypes.length]; for (int i = 0; i < sqlTypes.length; i++) { String sqlTypeString = definition2type(sqlTypes[i]); Class sqlType = SQLTypeInfos.sqlTypeName2javaType(sqlTypeString); if (_factory != null) { sqlType = _factory.adjustSqlType(sqlType); } sqlTypeNum[i] = SQLTypeInfos.javaType2sqlTypeNum(sqlType); } } else { Class sqlType = typeInfo.getFieldType(); if (_factory != null) { sqlType = _factory.adjustSqlType(sqlType); } sqlTypeNum = new int[] {SQLTypeInfos.javaType2sqlTypeNum(sqlType)}; } // create FieldDescriptor(Impl) instance, and apply JDO nature FieldDescriptorImpl fieldDescriptor = new FieldDescriptorImpl(fieldName, typeInfo, handler, fieldMap.getTransient()); fieldDescriptor.addNature(FieldDescriptorJDONature.class.getName()); fieldDescriptor.setRequired(fieldMap.getRequired()); // If we're using an ExtendedFieldHandler we need to set the FieldDescriptor if (exfHandler != null) { ((FieldHandlerFriend) exfHandler).setFieldDescriptor(fieldDescriptor); } // if SQL mapping declares transient // TODO: cross-check that this should be implemented like this if (sql.getTransient()) { fieldDescriptor.setTransient(true); } // set collection type as specified in mapping file fieldDescriptor.setCollection(fieldMap.getCollection()); fieldDescriptor.setComparator(fieldMap.getComparator()); fieldDescriptor.setCreateMethod(fieldMap.getCreateMethod()); fieldDescriptor.setGetMethod(fieldMap.getGetMethod()); fieldDescriptor.setSetMethod(fieldMap.getSetMethod()); fieldDescriptor.setDirect(fieldMap.getDirect()); // extract values for 'laziness' from field mapping fieldDescriptor.setLazy(isLazy); FieldDescriptorJDONature fieldJdoNature = new FieldDescriptorJDONature(fieldDescriptor); fieldJdoNature.setTypeConvertor(typeInfo.getConvertorFrom()); if (sqlName.length > 0) { fieldJdoNature.setSQLName(sqlName); } fieldJdoNature.setSQLType(sqlTypeNum); fieldJdoNature.setManyTable(sql.getManyTable()); if (sql.getManyKey().length > 0) { fieldJdoNature.setManyKey(sql.getManyKey()); } fieldJdoNature.setDirtyCheck(!SqlDirtyType.IGNORE.equals(sql.getDirty())); fieldJdoNature.setReadOnly(sql.getReadOnly()); fieldJdoNature.setCascading(sql.getCascading()); fieldJdoNature.setTransient(sql.getTransient()); return fieldDescriptor; }
protected TypeInfo getTypeInfo( final Class fieldType, final CollectionHandler colHandler, final FieldMapping fieldMap) throws MappingException { Class internalFieldType = Types.typeFromPrimitive(fieldType); String typeName = null; Class sqlType = null; String sqlParam = null; String[] sqlTypes = getSqlTypes(fieldMap); if ((fieldMap.getSql() != null) && (sqlTypes.length > 0)) { // --TO Check typeName = sqlTypes[0]; sqlType = SQLTypeInfos.sqlTypeName2javaType(definition2type(typeName)); sqlParam = definition2param(typeName); } else { sqlType = internalFieldType; } if (_factory != null) { sqlType = _factory.adjustSqlType(sqlType); } TypeConvertor convertorTo = null; TypeConvertor convertorFrom = null; if (internalFieldType != sqlType) { try { convertorTo = _typeConvertorRegistry.getConvertor(sqlType, internalFieldType, sqlParam); } catch (MappingException ex) { boolean isTypeSafeEnum = false; // -- check for type-safe enum style classes if ((internalFieldType != null) && (!isPrimitive(internalFieldType))) { // -- make sure no default constructor Constructor cons = null; try { cons = internalFieldType.getConstructor(EMPTY_ARGS); if (!Modifier.isPublic(cons.getModifiers())) { cons = null; } } catch (NoSuchMethodException nsmx) { // -- Do nothing } if (cons == null) { // -- make sure a valueOf factory method exists try { Method method = internalFieldType.getMethod(VALUE_OF, STRING_ARG); Class returnType = method.getReturnType(); if ((returnType != null) && internalFieldType.isAssignableFrom(returnType)) { int mods = method.getModifiers(); if (Modifier.isStatic(mods)) { // create individual SQLTypeConverter convertorTo = new String2EnumTypeConvertor(sqlType, internalFieldType, method); Types.addEnumType(internalFieldType); isTypeSafeEnum = true; } } } catch (NoSuchMethodException nsmx) { // -- Do nothing } } if (isTypeSafeEnum) { // -- check if name() method should be used instead of toString() try { Method method = internalFieldType.getMethod(NAME); if (String.class == method.getReturnType()) { convertorFrom = new Enum2StringTypeConvertor(internalFieldType, sqlType, method); } } catch (NoSuchMethodException nsmx) { // -- Do nothing } } } if (!isTypeSafeEnum) { throw new MappingException( "mapping.noConvertor", sqlType.getName(), internalFieldType.getName()); } } if (convertorFrom == null) { convertorFrom = _typeConvertorRegistry.getConvertor(internalFieldType, sqlType, sqlParam); } if ((convertorTo != null) && (convertorFrom != null)) { Types.addConvertibleType(internalFieldType); } } return new TypeInfo( internalFieldType, convertorTo, convertorFrom, fieldMap.getRequired(), null, colHandler); }
public QueryExpression getQueryExpression() { return _factory.getQueryExpression(); }
/** * Gives a possibility to patch the Castor-generated SQL statement for INSERT (makes sense for * DURING_INSERT key generators) */ public String patchSQL(String insert, String primKeyName) throws MappingException { StringTokenizer st; String tableName; String seqName; String nextval; StringBuffer sb; int lp1; // the first left parenthesis, which starts fields list int lp2; // the second left parenthesis, which starts values list if (_style == BEFORE_INSERT) { return insert; } // First find the table name st = new StringTokenizer(insert); if (!st.hasMoreTokens() || !st.nextToken().equalsIgnoreCase("INSERT")) { throw new MappingException(Messages.format("mapping.keyGenCannotParse", insert)); } if (!st.hasMoreTokens() || !st.nextToken().equalsIgnoreCase("INTO")) { throw new MappingException(Messages.format("mapping.keyGenCannotParse", insert)); } if (!st.hasMoreTokens()) { throw new MappingException(Messages.format("mapping.keyGenCannotParse", insert)); } tableName = st.nextToken(); // remove every double quote in the tablename int idxQuote = tableName.indexOf('"'); if (idxQuote >= 0) { StringBuffer buffer2 = new StringBuffer(); int pos = 0; do { buffer2.append(tableName.substring(pos, idxQuote)); pos = idxQuote + 1; } while ((idxQuote = tableName.indexOf('"', pos)) != -1); buffer2.append(tableName.substring(pos)); tableName = buffer2.toString(); } seqName = MessageFormat.format( _seqName, new String[] {tableName, primKeyName}); // due to varargs in 1.5, see CASTOR-1097 nextval = _factory.quoteName(seqName + ".nextval"); lp1 = insert.indexOf('('); lp2 = insert.indexOf('(', lp1 + 1); if (lp1 < 0) { throw new MappingException(Messages.format("mapping.keyGenCannotParse", insert)); } sb = new StringBuffer(insert); if (!_triggerPresent) { // if no onInsert triggers in the DB, we have to supply the Key values // manually if (lp2 < 0) { // Only one pk field in the table, the INSERT statement would be // INSERT INTO table VALUES () lp2 = lp1; lp1 = insert.indexOf(" VALUES "); // don't change the order of lines below, // otherwise index becomes invalid sb.insert(lp2 + 1, nextval); sb.insert(lp1 + 1, "(" + _factory.quoteName(primKeyName) + ") "); } else { // don't change the order of lines below, // otherwise index becomes invalid sb.insert(lp2 + 1, nextval + ","); sb.insert(lp1 + 1, _factory.quoteName(primKeyName) + ","); } } if (_style == DURING_INSERT) { // append 'RETURNING primKeyName INTO ?' sb.append(" RETURNING "); sb.append(_factory.quoteName(primKeyName)); sb.append(" INTO ?"); } return sb.toString(); }
/** * @param conn An open connection within the given transaction * @param tableName The table name * @param primKeyName The primary key name * @param props A temporary replacement for Principal object * @return A new key * @throws PersistenceException An error occured talking to persistent storage */ public Object generateKey(Connection conn, String tableName, String primKeyName, Properties props) throws PersistenceException { PreparedStatement stmt = null; ResultSet rs; String seqName; String table; seqName = MessageFormat.format( _seqName, new String[] {tableName, primKeyName}); // due to varargs in 1.5, see CASTOR-1097 table = _factory.quoteName(tableName); try { if (_factory.getFactoryName().equals(InterbaseFactory.FACTORY_NAME)) { // interbase only does before_insert, and does it its own way stmt = conn.prepareStatement( "SELECT gen_id(" + seqName + "," + _increment + ") FROM rdb$database"); rs = stmt.executeQuery(); } else if (_factory.getFactoryName().equals(DB2Factory.FACTORY_NAME)) { stmt = conn.prepareStatement("SELECT nextval FOR " + seqName + " FROM SYSIBM.SYSDUMMY1"); rs = stmt.executeQuery(); } else { if (_style == BEFORE_INSERT) { stmt = conn.prepareStatement("SELECT nextval('" + seqName + "')"); rs = stmt.executeQuery(); } else if (_triggerPresent && _factoryName.equals(PostgreSQLFactory.FACTORY_NAME)) { Object insStmt = props.get("insertStatement"); Class psqlStmtClass = Class.forName("org.postgresql.Statement"); Method getInsertedOID = psqlStmtClass.getMethod("getInsertedOID", (Class[]) null); int insertedOID = ((Integer) getInsertedOID.invoke(insStmt, (Object[]) null)).intValue(); stmt = conn.prepareStatement( "SELECT " + _factory.quoteName(primKeyName) + " FROM " + table + " WHERE OID=?"); stmt.setInt(1, insertedOID); rs = stmt.executeQuery(); } else { stmt = conn.prepareStatement( "SELECT " + _factory.quoteName(seqName + ".currval") + " FROM " + table); rs = stmt.executeQuery(); } } if (!rs.next()) { throw new PersistenceException( Messages.format("persist.keyGenFailed", getClass().getName())); } Object resultKey = null; int resultValue = rs.getInt(1); String resultColName = rs.getMetaData().getColumnName(1); int resultColType = rs.getMetaData().getColumnType(1); if (LOG.isDebugEnabled()) { LOG.debug( "JDBC query returned value " + resultValue + " from column " + resultColName + "/" + resultColType); } if (_sqlType == Types.INTEGER) { resultKey = new Integer(resultValue); } else if (_sqlType == Types.BIGINT) { resultKey = new Long(resultValue); } else if (_sqlType == Types.CHAR || _sqlType == Types.VARCHAR) { resultKey = String.valueOf(resultValue); } else { resultKey = new BigDecimal(resultValue); } if (LOG.isDebugEnabled()) { if (resultKey != null) { LOG.debug( "Returning value " + resultKey + " of type " + resultKey.getClass().getName() + " as key."); } } return resultKey; } catch (Exception ex) { throw new PersistenceException( Messages.format("persist.keyGenSQL", getClass().getName(), ex.toString())); } finally { JDOUtils.closeStatement(stmt); } }