Index: core/xwiki-core/src/main/java/com/xpn/xwiki/store/XWikiHibernateStore.java
===================================================================
--- core/xwiki-core/src/main/java/com/xpn/xwiki/store/XWikiHibernateStore.java	(revision 30669)
+++ core/xwiki-core/src/main/java/com/xpn/xwiki/store/XWikiHibernateStore.java	(working copy)
@@ -104,6 +104,9 @@
 @Component
 public class XWikiHibernateStore extends XWikiHibernateBaseStore implements XWikiStoreInterface
 {
+    /** Maximum number of characters a StringProperty can have. */
+    private static final int STRING_PROPERTY_MAXLENGTH = 255;
+
     private static final Log log = LogFactory.getLog(XWikiHibernateStore.class);
 
     private Map<String, String[]> validTypesMap = new HashMap<String, String[]>();
@@ -1342,64 +1345,102 @@
         }
     }
 
-    public void saveXWikiProperty(PropertyInterface property, XWikiContext context, boolean bTransaction)
+    /**
+     * Save a single property of an object.
+     *
+     * @param property the property to save.
+     * @param context the {@link com.xpn.xwiki.XWikiContext} to use if opening a new transation.
+     * @param runInNewTransaction if true then run this opperation in a new transaction and commit at the end,
+     *                            otherwise get the transaction from the context.
+     * @throws XWikiException if something fails in the Hibernate or the database. If an exception is thrown a rollback
+     *                        will be attempted.
+     */
+    public void saveXWikiProperty(final PropertyInterface property,
+                                  final XWikiContext context,
+                                  final boolean runInNewTransaction)
         throws XWikiException
     {
+        // Clone the paramerter runInNewTransaction so that it cannot be mutated.
+        boolean bTransaction = runInNewTransaction;
+
         try {
             if (bTransaction) {
-                checkHibernate(context);
-                bTransaction = beginTransaction(context);
+                this.checkHibernate(context);
+                bTransaction = this.beginTransaction(context);
             }
-            Session session = getSession(context);
-            Query query =
-                session
-                    .createQuery("select prop.name from BaseProperty as prop where prop.id.id = :id and prop.id.name= :name");
+            final Session session = this.getSession(context);
+            final Query query = session.createQuery("select prop from BaseProperty as prop "
+                                                    + "where prop.id.id = :id and prop.id.name= :name");
             query.setInteger("id", property.getId());
             query.setString("name", property.getName());
-            if (query.uniqueResult() == null) {
-                session.save(property);
-            } else {
-                session.update(property);
+
+            final List<PropertyInterface> oldProps = (List<PropertyInterface>) query.list();
+
+            // True if the property is already in the database and should be updated rather than saved.
+            boolean isInDatabase = false;
+
+            if (oldProps.size() == 1) {
+                isInDatabase = true;
             }
 
+            // If it's a StringProperty and is larger than the maximum length for StringProperties, silently save
+            // as a LargeStringProperty.
+            PropertyInterface propToSave = property;
+            if (property instanceof StringProperty 
+                && ((StringProperty) property).toText().length() > STRING_PROPERTY_MAXLENGTH) 
+            {
+                propToSave = new LargeStringProperty();
+                propToSave.setId(property.getId());
+                propToSave.setName(property.getName());
+                ((LargeStringProperty) propToSave).setValue(((StringProperty) property).getValue());
+            }
+
             /*
-             * // I'm using a local transaction // There might be implications to this for a wider transaction
-             * Transaction ltransaction = session.beginTransaction(); // Use to chose what to delete boolean isSave =
-             * false; try { Query query = session.createQuery("select prop.name from BaseProperty as prop where
-             * prop.id.id = :id and prop.id.name= :name"); query.setInteger("id", property.getId());
-             * query.setString("name", property.getName()); if (query.uniqueResult()==null) { isSave = true;
-             * session.save(property); } else { isSave = false; session.update(property); } session.flush();
-             * ltransaction.commit(); } catch (Exception e) { // We can't clean-up ListProperties if (property
-             * instanceof ListProperty) throw e; // This seems to have failed.. // This is an attempt to cleanup a
-             * potential mess // This code is only called if the tables are in an incoherent state // (Example: data in
-             * xwikiproperties and no data in xwikiintegers or vice-versa) // TODO: verify of the code works with longer
-             * transactions BaseProperty prop2; // Depending on save/update there is too much data either // in the
-             * BaseProperty table or in the inheritated property table // We need to delete this data if (isSave) prop2
-             * = (BaseProperty) property; else prop2 = new BaseProperty(); prop2.setName(property.getName());
-             * prop2.setObject(property.getObject()); ltransaction.rollback(); // We need to run the delete in a
-             * separate session // This is not a problem since this is cleaning up Session session2 =
-             * getSessionFactory().openSession(); Transaction transaction2 = session2.beginTransaction();
-             * session2.delete(prop2); session2.flush(); // I don't understand why I can't run this in the general
-             * session // This might make transactions fail if (!isSave) session2.save(property); transaction2.commit();
-             * session2.close(); }
+             * Three possibilities:
+             * 1. Property was StringProperty but overflowed and we plan to save LargeStringProperty
+             * 2. We had a overflowed StringProperty in a LargeStringProperty but it's not overflowed anymore
+             *    and we are being presented with a StringProperty to save.
+             * 3. Something went wrong somewhere and we are being asked to save a property of type x in a location
+             *    where the id was for property type y.
+             *
+             * No matter the case, clear the old property out and add the new one in without complaint.
              */
+            if (isInDatabase && !propToSave.getClass().getName().equals(oldProps.get(0).getClass().getName())) {
+                session.delete(oldProps.get(0));
+                isInDatabase = false;
+            }
+
+            // Update if already in database, otherwise save.
+            if (isInDatabase) {
+                session.evict(oldProps.get(0));
+                session.update(propToSave);
+            } else {
+                session.save(propToSave);
+            }
+
             if (bTransaction) {
-                endTransaction(context, true);
+                // Commit if this is supposed to run in it's own transation.
+                this.endTransaction(context, true);
             }
+
         } catch (Exception e) {
-            BaseCollection obj = property.getObject();
-            Object[] args = {(obj != null) ? obj.getName() : "unknown", property.getName()};
-            throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
-                XWikiException.ERROR_XWIKI_STORE_HIBERNATE_LOADING_OBJECT,
-                "Exception while saving property {1} of object {0}", e, args);
 
-        } finally {
+            // If something fails, attempt to rollback if we are in our own transaction.
             try {
                 if (bTransaction) {
-                    endTransaction(context, false);
+                    this.endTransaction(context, false);
                 }
-            } catch (Exception e) {
+            } catch (Exception ee) {
+                // Failed to rollback the transaction, not a lot we can do here.
             }
+
+            BaseCollection obj = property.getObject();
+            Object[] args = {(obj != null) ? obj.getName() : "unknown", property.getName()};
+            throw new XWikiException(XWikiException.MODULE_XWIKI_STORE,
+                                     XWikiException.ERROR_XWIKI_STORE_HIBERNATE_LOADING_OBJECT,
+                                     "Exception while saving property {1} of object {0}",
+                                     e,
+                                     args);
         }
     }
 
