/** * Generates a unique and non-repeating primary key for specified dbEntity. * * <p>This implementation is naive since it does not lock the database rows when executing select * and subsequent update. Adapter-specific implementations are more robust. * * @since 3.0 */ public Object generatePk(DataNode node, DbAttribute pk) throws Exception { DbEntity entity = (DbEntity) pk.getEntity(); switch (pk.getType()) { case Types.BINARY: case Types.VARBINARY: return IDUtil.pseudoUniqueSecureByteSequence(pk.getMaxLength()); } DbKeyGenerator pkGenerator = entity.getPrimaryKeyGenerator(); long cacheSize; if (pkGenerator != null && pkGenerator.getKeyCacheSize() != null) cacheSize = pkGenerator.getKeyCacheSize().intValue(); else cacheSize = pkCacheSize; long value; // if no caching, always generate fresh if (cacheSize <= 1) { value = longPkFromDatabase(node, entity); } else { synchronized (pkCache) { LongPkRange r = pkCache.get(entity.getName()); if (r == null) { // created exhausted LongPkRange r = new LongPkRange(1l, 0l); pkCache.put(entity.getName(), r); } if (r.isExhausted()) { long val = longPkFromDatabase(node, entity); r.reset(val, val + cacheSize - 1); } value = r.getNextPrimaryKey(); } } if (pk.getType() == Types.BIGINT) { return Long.valueOf(value); } else { // leaving it up to the user to ensure that PK does not exceed max int... return Integer.valueOf((int) value); } }
@Override protected ParameterBinding[] createBindings() { List<DbAttribute> dbAttributes = query.getDbAttributes(); int len = dbAttributes.size(); ParameterBinding[] bindings = new ParameterBinding[len]; for (int i = 0; i < len; i++) { DbAttribute attribute = dbAttributes.get(i); String typeName = TypesMapping.getJavaBySqlType(attribute.getType()); ExtendedType extendedType = adapter.getExtendedTypes().getRegisteredType(typeName); bindings[i] = new ParameterBinding(attribute, extendedType); } return bindings; }
/** * Appends parameter placeholder for the value of the column being updated. If requested, performs * special handling on LOB columns. */ protected void appendUpdatedParameter(StringBuffer buf, DbAttribute dbAttribute, Object value) { int type = dbAttribute.getType(); if (isUpdateableColumn(value, type)) { buf.append('?'); } else { if (type == Types.CLOB) { buf.append(newClobFunction); } else if (type == Types.BLOB) { buf.append(newBlobFunction); } else { throw new CayenneRuntimeException( "Unknown LOB column type: " + type + "(" + TypesMapping.getSqlNameByType(type) + "). Query buffer: " + buf); } } }
/** Binds BatchQuery parameters to the PreparedStatement. */ @Override public void bindParameters(PreparedStatement statement, BatchQuery query) throws SQLException, Exception { List<DbAttribute> dbAttributes = query.getDbAttributes(); int attributeCount = dbAttributes.size(); // i - attribute position in the query // j - PreparedStatement parameter position (starts with "1") for (int i = 0, j = 1; i < attributeCount; i++) { Object value = query.getValue(i); DbAttribute attribute = dbAttributes.get(i); int type = attribute.getType(); // TODO: (Andrus) This works as long as there is no LOBs in qualifier if (isUpdateableColumn(value, type)) { adapter.bindParameter(statement, value, j, type, attribute.getScale()); j++; } } }
@Override protected ParameterBinding[] doUpdateBindings(BatchQueryRow row) { int len = bindings.length; for (int i = 0, j = 1; i < len; i++) { ParameterBinding b = bindings[i]; Object value = row.getValue(i); DbAttribute attribute = b.getAttribute(); int type = attribute.getType(); // TODO: (Andrus) This works as long as there is no LOBs in // qualifier if (isUpdateableColumn(value, type)) { b.include(j++, value); } else { b.exclude(); } } return bindings; }
/** * Customizes table creating procedure for PostgreSQL. One difference with generic implementation * is that "bytea" type has no explicit length unlike similar binary types in other databases. * * @since 1.0.2 */ @Override public String createTable(DbEntity ent) { boolean status; if (ent.getDataMap() != null && ent.getDataMap().isQuotingSQLIdentifiers()) { status = true; } else { status = false; } QuotingStrategy context = getQuotingStrategy(status); StringBuilder buf = new StringBuilder(); buf.append("CREATE TABLE "); buf.append(context.quoteFullyQualifiedName(ent)); buf.append(" ("); // columns Iterator<DbAttribute> it = ent.getAttributes().iterator(); boolean first = true; while (it.hasNext()) { if (first) first = false; else buf.append(", "); DbAttribute at = it.next(); // attribute may not be fully valid, do a simple check if (at.getType() == TypesMapping.NOT_DEFINED) { throw new CayenneRuntimeException( "Undefined type for attribute '" + ent.getFullyQualifiedName() + "." + at.getName() + "'."); } String[] types = externalTypesForJdbcType(at.getType()); if (types == null || types.length == 0) { throw new CayenneRuntimeException( "Undefined type for attribute '" + ent.getFullyQualifiedName() + "." + at.getName() + "': " + at.getType()); } String type = types[0]; buf.append(context.quoteString(at.getName())).append(' ').append(type); // append size and precision (if applicable) if (typeSupportsLength(at.getType())) { int len = at.getMaxLength(); int scale = (TypesMapping.isDecimal(at.getType()) && at.getType() != Types.FLOAT) // Postgress // don't // support // notations // float(a, // b) ? at.getScale() : -1; // sanity check if (scale > len) { scale = -1; } if (len > 0) { buf.append('(').append(len); if (scale >= 0) { buf.append(", ").append(scale); } buf.append(')'); } } if (at.isMandatory()) { buf.append(" NOT NULL"); } else { buf.append(" NULL"); } } // primary key clause Iterator<DbAttribute> pkit = ent.getPrimaryKeys().iterator(); if (pkit.hasNext()) { if (first) first = false; else buf.append(", "); buf.append("PRIMARY KEY ("); boolean firstPk = true; while (pkit.hasNext()) { if (firstPk) firstPk = false; else buf.append(", "); DbAttribute at = pkit.next(); buf.append(context.quoteString(at.getName())); } buf.append(')'); } buf.append(')'); return buf.toString(); }