gt:     protected int getClobSizeFor(int i) {
context: /*
     Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License, version 2.0,
     as published by the Free Software Foundation.
  
     This program is also distributed with certain software (including
     but not limited to OpenSSL) that is licensed under separate terms,
     as designated in a particular file or component or in included license
     documentation.  The authors of MySQL hereby grant you an additional
     permission to link the program and your derivative works with the
     separately licensed software that they have included with MySQL.
  
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License, version 2.0, for more details.
  
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
  
  package com.mysql.clusterj.jpatest;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.nio.charset.Charset;
  import java.nio.charset.CharsetEncoder;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  
  import com.mysql.clusterj.jpatest.model.ClobTypes;
  
  /** Test clobs
   * Schema:
  drop table if exists charsetlatin1;
  create table charsetlatin1 (
   id int not null primary key,
   smallcolumn varchar(200),
   mediumcolumn varchar(500),
   largecolumn text(10000)
  
  ) ENGINE=ndbcluster DEFAULT CHARSET=latin1;
   
   */
  public class ClobTest extends AbstractJPABaseTest {
  
      /** The size of the clob column is 2 raised to the power i. */
      private static final int NUMBER_TO_INSERT = 16;
  
      /** The clob instances for testing. */
      protected List<ClobTypes> clobs = new ArrayList<ClobTypes>();
  
      /** Characters that can be encoded using latin1 character set */
      private char[] chars = getChars(Charset.forName("latin1"));
  
      /** Subclasses can override this method to get debugging info printed to System.out */
      protected boolean getDebug() {
          return false;
      }
  
      /** Create a char array with the first 128 encodable characters.
       * 
       * @return the char array
       */
      private char[] getChars(Charset charset) {
          CharsetEncoder encoder = charset.newEncoder();
          char[] result = new char[128];
          char current = (char)0;
          for (int i = 0; i < result.length; ++i) {
              current = nextChar(encoder, current);
              result[i] = current;
          }
          return result;
      }
  
      /** Get the next char greater than the current char that is encodable
       * by the encoder.
       * @param encoder 
       * 
       */
      char nextChar(CharsetEncoder encoder, char current) {
          current++;
          if (encoder.canEncode(current)) {
              return current;
          } else {
              return nextChar(encoder, current);
          }
      }
  
      public void test() {
          createClobInstances(NUMBER_TO_INSERT);
          remove();
          insert();
          update();
          failOnError();
      }
  
      protected void remove() {
          removeAll(ClobTypes.class);
      }
  
      protected void insert() {
          // insert instances
          tx = em.getTransaction();
          tx.begin();
          
          int count = 0;
  
          for (int i = 0; i < NUMBER_TO_INSERT; ++i) {
              // must be done with an active transaction
              em.persist(clobs.get(i));
              ++count;
          }
          tx.commit();
      }
  
      protected void update() {
  
          tx.begin();
  
          for (int i = 1; i < NUMBER_TO_INSERT; ++i) {
              // must be done with an active transaction
              ClobTypes e = em.find(ClobTypes.class, i);
              // see if it is the right one
              int actualId = e.getId();
              if (actualId != i) {
                  error("Expected ClobTypes.id " + i + " but got " + actualId);
              }
              String string = e.getLarge10000();
              // make sure all fields were fetched properly
              checkString("before update", string, i, false);
  
              int position = getClobSizeFor(i)/2;
              // only update if the length is correct
              if (string.length() == (position * 2)) {
                  StringBuilder sb = new StringBuilder(string);
                  // modify the byte in the middle of the blob
                  sb.replace(position, position + 1, "!");
                  string = sb.toString();
                  checkString("after update", string, i, true);
              }
              e.setLarge10000(string);
          }
          tx.commit();
          tx.begin();
  
          for (int i = 1; i < NUMBER_TO_INSERT; ++i) {
              // must be done with an active transaction
              ClobTypes e = em.find(ClobTypes.class, i);
              // see if it is the right one
              int actualId = e.getId();
              if (actualId != i) {
                  error("Expected ClobTypes.id " + i + " but got " + actualId);
              }
              String string = e.getLarge10000();
  
              // check to see that the blob field has the right data
              checkString("after commit", string, i, true);
          }
          tx.commit();
      }
  
      protected void createClobInstances(int number) {
          for (int i = 0; i < number; ++i) {
              ClobTypes instance = new ClobTypes();
              instance.setId(i);
              int length = getClobSizeFor(i);
              instance.setLarge10000(getString(length));
  //            blob streams are not yet supported
  //            instance.setBlobstream(getBlobStream(length));
              clobs.add(instance);
          }
      }
  
      /** Create a new String of the specified size containing a pattern
       * of characters in which each character is the value of encodable characters
       * at position modulo 128. This pattern is easy to test.
       * @param size the length of the returned string
       * @return the string filled with the pattern
       */
      protected String getString(int size) {
          char[] result = new char[size];
          for (int i = 0; i < size; ++i) {
              result[i] = chars [i%128];
          }
          return new String(result);
      }
  
      /** Check the string to be sure it matches the pattern in both size
       * and contents.
       * @see getString
       * @param string the string to check
       * @param number the expected length of the string
       * @param updated whether the string is original or updated
       */
      protected void checkString(String where, String string, int number, boolean updated) {
          if (getDebug()) dumpClob(where, string);
          int expectedSize = getClobSizeFor(number);
          int actualSize = string.length();
          if (expectedSize != actualSize) {
              error("In " + where
                      + " wrong size of string; "
                      + "expected: " + expectedSize
                      + " actual: " + actualSize);
          }
          for (int i = 0; i < actualSize; ++i) {
              char expected;
              int position = expectedSize/2;
              if (updated && (i == position)) {
                  expected = '!';
              } else {
                  expected = chars[i%128];
              }
                  char actual = string.charAt(i);
              if (expected != actual) {
                  error("In " + where + " for size: " + actualSize
                          + " mismatch in string at position " + i
                          + " expected: " + (int)expected
                          + " actual: " + (int)actual);
              }
          }
  
      }
  
      protected InputStream getClobStream(final int i) {
          return new InputStream() {
              int size = i;
              int counter = 0;
              @Override
              public int read() throws IOException {
                  if (counter >= i) {
                      return -1;
                  } else {
                      return counter++ %256;
                  }
              }
          };
      }
  
      protected void dumpClob(String where, String string) {
          System.out.println("In " + where + " dumpClob of size: " + string.length() + " " + Arrays.toString(string.getBytes()));
      }
  
  