/* * ==================================================================== * Copyright (c) 2004-2010 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.internal.db; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.tmatesoft.sqljet.core.SqlJetException; import org.tmatesoft.sqljet.core.SqlJetTransactionMode; import org.tmatesoft.sqljet.core.table.ISqlJetCursor; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNProperties; import org.tmatesoft.svn.core.internal.util.SVNDate; import org.tmatesoft.svn.core.internal.util.SVNSkel; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc17.db.Structure; import org.tmatesoft.svn.core.internal.wc17.db.StructureFields.InheritedProperties; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnChecksum; import org.tmatesoft.svn.util.SVNLogType; /** * @author TMate Software Ltd. */ public abstract class SVNSqlJetStatement { protected SVNSqlJetDb sDb; private ISqlJetCursor cursor; protected List<Object> binds = new ArrayList<Object>(); protected SqlJetTransactionMode transactionMode = SqlJetTransactionMode.READ_ONLY; protected ISqlJetCursor openCursor() throws SVNException { throw new UnsupportedOperationException(); } public long insert(Object... data) throws SVNException { throw new UnsupportedOperationException(); } public long exec() throws SVNException { throw new UnsupportedOperationException(); } public SVNSqlJetStatement(SVNSqlJetDb sDb) { this.sDb = sDb; setCursor(null); } public List<Object> getBinds() { return binds; } public boolean isNeedsReset() { return getCursor() != null; } public void reset() throws SVNException { binds.clear(); if (isNeedsReset()) { try { getCursor().close(); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); } finally { setCursor(null); sDb.commit(); } } } public boolean next() throws SVNException { try { if (getCursor() == null) { sDb.beginTransaction(transactionMode); try { setCursor(openCursor()); return !getCursor().eof(); } catch (SVNException e) { if (getCursor() == null) { sDb.commit(); } throw e; } } return getCursor().next(); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); return false; } } public boolean eof() throws SVNException { try { if (getCursor() == null) { sDb.beginTransaction(transactionMode); setCursor(openCursor()); } return getCursor().eof(); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); return false; } } public void bindf(String format, Object... data) throws SVNException { int n = 0; int length = data.length; for (int i = 0; i < format.length(); i++) { char fmt = format.charAt(i); switch (fmt) { case 's': case 't': if (n > length || data[n] == null) { bindNull(i + 1); } else if (data[n] instanceof File) { bindString(i + 1, SVNFileUtil.getFilePath((File) data[n])); } else { bindString(i + 1, data[n].toString()); } n++; break; case 'i': if (n > length || data[n] == null) { bindNull(i + 1); } else if (data[n] instanceof Number) { bindLong(i + 1, ((Number) data[n]).longValue()); } else if (data[n] instanceof SVNDate) { bindLong(i + 1, ((SVNDate) data[n]).getTimeInMicros()); } else { SVNErrorManager.assertionFailure(false, String.format("Number argument required in %d", i + 1), SVNLogType.WC); } n++; break; case 'r': if (n > length || data[n] == null) { bindNull(i + 1); } else if (data[n] instanceof Number) { bindRevision(i + 1, ((Number) data[n]).longValue()); } else { SVNErrorManager.assertionFailure(false, String.format("Number argument required in %d", i + 1), SVNLogType.WC); } n++; break; case 'b': if (n > length || data[n] == null) { bindNull(i + 1); } else if (data[n] instanceof byte[]) { bindBlob(i + 1, (byte[]) data[n]); } else { SVNErrorManager.assertionFailure(false, String.format("Byte array argument required in %d", i + 1), SVNLogType.WC); } n++; break; case 'n': bindNull(i + 1); break; default: SVNErrorManager.assertionFailure(false, String.format("Unknown format '%s' in %d", fmt, i + 1), SVNLogType.WC); } } } private void adjustBinds(int i) { int size = binds.size(); if (size < i) { for (int n = size; n < i; n++) { binds.add(null); } } } public void bindNull(int i) { adjustBinds(i); binds.set(i - 1, null); } public void bindLong(int i, long v) { adjustBinds(i); binds.set(i - 1, v); } public void bindString(int i, String string) { adjustBinds(i); binds.set(i - 1, string); } @SuppressWarnings("unchecked") public void bindProperties(int i, SVNProperties props) throws SVNException { adjustBinds(i); binds.set(i - 1, props != null ? SVNSkel.createPropList(props.asMap()).unparse() : null); } public void bindIProperties(int i, Map<String, SVNProperties> iprops) throws SVNException { adjustBinds(i); binds.set(i - 1, iprops != null ? SVNSkel.createInheritedProperties(iprops).unparse() : null); } public void bindChecksum(int i, SvnChecksum checksum) { adjustBinds(i); binds.set(i - 1, checksum != null ? checksum.toString() : null); } public void bindBlob(int i, byte[] serialized) { adjustBinds(i); binds.set(i - 1, serialized); } public void bindRevision(int i, long revision) { adjustBinds(i); if (SVNRevision.isValidRevisionNumber(revision)) { bindLong(i, revision); } else { bindNull(i); } } protected Object getBind(int i) { adjustBinds(i); return binds.get(i - 1); } public long count() throws SVNException { try { if (getCursor() == null || getCursor().eof()) return 0; return getCursor().getRowCount(); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); return 0; } } public Object getColumn(Enum<?> f) throws SVNException { return getColumn(f.toString()); } protected Object getColumn(String f) throws SVNException { try { if (getCursor() == null || getCursor().eof()) return null; return getCursor().getValue(f); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); return null; } } public long getColumnLong(Enum<?> f) throws SVNException { return getColumnLong(f.toString()); } protected long getColumnLong(String f) throws SVNException { try { if (getCursor() == null || getCursor().eof()) return 0; return getCursor().getInteger(f); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); return 0; } } public String getColumnString(Enum<?> f) throws SVNException { return getColumnString(f.toString()); } protected String getColumnString(String f) throws SVNException { try { if (getCursor() == null || getCursor().eof()) return null; return getCursor().getString(f); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); return null; } } public boolean isColumnNull(Enum<?> f) throws SVNException { return isColumnNull(f.toString()); } protected boolean isColumnNull(String f) throws SVNException { try { if (getCursor() == null || getCursor().eof()) return true; return getCursor().isNull(f); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); return false; } } public byte[] getColumnBlob(Enum<?> f) throws SVNException { return getColumnBlob(f.toString()); } protected byte[] getColumnBlob(String f) throws SVNException { try { if (getCursor() == null || getCursor().eof()) return null; return getCursor().getBlobAsArray(f); } catch (SqlJetException e) { SVNSqlJetDb.createSqlJetError(e); return null; } } public boolean getColumnBoolean(Enum<?> f) throws SVNException { return getColumnLong(f) != 0; } public SVNSqlJetStatement getJoinedStatement(String joinedTable) throws SVNException { SVNErrorManager.assertionFailure(false, "unsupported", SVNLogType.WC); return null; } public SVNSqlJetStatement getJoinedStatement(Enum<?> joinedTable) throws SVNException { return getJoinedStatement(joinedTable.toString()); } public SVNProperties getColumnProperties(Enum<?> f) throws SVNException { return getColumnProperties(f.name()); } public boolean hasColumnProperties(Enum<?> f) throws SVNException { return hasColumnProperties(f.name()); } public List<Structure<InheritedProperties>> getColumnInheritedProperties(Enum<?> f) throws SVNException { return getColumnInheritedProperties(f.name()); } public boolean hasColumnInheritedProperties(Enum<?> f) throws SVNException { return hasColumnInheritedProperties(f.name()); } protected SVNProperties getColumnProperties(String f) throws SVNException { if (isColumnNull(f)) { return null; } final byte[] val = getColumnBlob(f); return parseProperties(val); } protected boolean hasColumnProperties(String f) throws SVNException { if (isColumnNull(f)) { return false; } final byte[] val = getColumnBlob(f); return val.length > 2; } public List<Structure<InheritedProperties>> getColumnInheritedProperties(String f) throws SVNException { if (isColumnNull(f)) { return null; } final byte[] val = getColumnBlob(f); return parseInheritedProperties(val); } public boolean hasColumnInheritedProperties(String f) throws SVNException { if (isColumnNull(f)) { return false; } final byte[] val = getColumnBlob(f); return val.length > 2; } public static SVNProperties parseProperties(byte[] val) throws SVNException { if (val == null) return null; final SVNSkel skel = SVNSkel.parse(val); if (!skel.isValidPropList()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_MALFORMED_SKEL, "proplist"); SVNErrorManager.error(err, SVNLogType.FSFS); } return SVNProperties.wrap(skel.parsePropList()); } public static List<Structure<InheritedProperties>> parseInheritedProperties(byte[] val) throws SVNException { if (val == null) { return null; } final SVNSkel skel = SVNSkel.parse(val); if (!skel.isValidInheritedProperties()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_MALFORMED_SKEL, "inhertied-props"); SVNErrorManager.error(err, SVNLogType.FSFS); } return skel.parseInheritedProperties(); } public long done() throws SVNException { try { return exec(); } finally { reset(); } } public void nextRow() throws SVNException { if (!next()) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.SQLITE_ERROR, "Expected database row missing"); SVNErrorManager.error(err, SVNLogType.DEFAULT); } } public long getColumnRevnum(Enum<?> f) throws SVNException { if (isColumnNull(f)) { return -1; } return getColumnLong(f); } protected ISqlJetCursor getCursor() { return cursor; } protected void setCursor(ISqlJetCursor cursor) { this.cursor = cursor; } public Map<String, Object> getRowValues() throws SVNException { throw new UnsupportedOperationException(); } }