class StringClob implements Clob {

    private String inner;

    public StringClob(String inner) {
        this.inner = requireNonNull(inner);
    }

    @Override
    public long length() throws SQLException {
        assertNotFreeNotCalled();
        return inner.length();
    }

    @Override
    public String getSubString(final long ordinalPosition, final int len) throws SQLException {
        assertNotFreeNotCalled();
        if (inner.isEmpty()) {
            return inner;
        }
        assertInRange(ordinalPosition);
        final int effectiveLen;
        if (len > inner.length() - ordinalPosition + 1) {
            // Truncate length
            effectiveLen = (int) (inner.length() - ordinalPosition + 1);
        } else {
            effectiveLen = len;
        }
        return inner.substring((int) ordinalPosition - 1, effectiveLen);
    }

    @Override
    public Reader getCharacterStream() throws SQLException {
        assertNotFreeNotCalled();
        return new StringReader(inner);
    }

    @Override
    public InputStream getAsciiStream() throws SQLException {
        assertNotFreeNotCalled();
        return new ByteArrayInputStream(inner.getBytes(StandardCharsets.US_ASCII));
    }

    @Override
    public long position(final String str, final long startOrdinalPosition) throws SQLException {<FILL_FUNCTION_BODY>}

    @Override
    public long position(final Clob clob, final long start) throws SQLException {
        requireNonNull(clob);
        assertNotFreeNotCalled();
        return position(clob.getSubString(1, (int) clob.length()), start);
    }

    @Override
    public int setString(final long pos, final String str) throws SQLException {
        assertNotFreeNotCalled();
        throw newSQLFeatureNotSupportedException();
    }

    @Override
    public int setString(long pos, String str, int offset, int len) throws SQLException {
        assertNotFreeNotCalled();
        throw newSQLFeatureNotSupportedException();
    }

    @Override
    public OutputStream setAsciiStream(long pos) throws SQLException {
        assertNotFreeNotCalled();
        throw newSQLFeatureNotSupportedException();
    }

    @Override
    public Writer setCharacterStream(long ordinalPosition) throws SQLException {
        assertNotFreeNotCalled();
        assertInRange(ordinalPosition);
        throw newSQLFeatureNotSupportedException();
    }

    @Override
    public void truncate(long len) throws SQLException {
        assertNotFreeNotCalled();
        throw newSQLFeatureNotSupportedException();
    }

    private SQLFeatureNotSupportedException newSQLFeatureNotSupportedException() {
        return new SQLFeatureNotSupportedException("Not supported for an unmodifiable Clob.");
    }

    @Override
    public void free() throws SQLException {
        inner = null;
    }

    @Override
    public Reader getCharacterStream(long pos, long length) throws SQLException {
        assertNotFreeNotCalled();
        if (length > Integer.MAX_VALUE) {
            throw new SQLException("Length cannot be >" + Integer.MAX_VALUE);
        }
        return new StringReader(getSubString(pos, (int) length));
    }

    private void assertNotFreeNotCalled() throws SQLException {
        if (inner == null) {
            throw new SQLException("The method free() was already called on this Clob");
        }
    }

    private void assertInRange(long ordinalPosition) throws SQLException {
        if (ordinalPosition > inner.length() || ordinalPosition < 1) {
            throw new SQLException("Starting position cannot be < 1 or >" + inner.length());
        }
    }

}

        assertNotFreeNotCalled();
        assertInRange(startOrdinalPosition);
        final int index = inner.indexOf(str, (int) startOrdinalPosition - 1);
        return (index == -1) ? (-1) : (index + 1);
    
<no_super_class>