com.ibm.as400.access.SQLVarcharBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400 Show documentation
Show all versions of jt400 Show documentation
The Open Source version of the IBM Toolbox for Java
The newest version!
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: SQLVarchar.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2014 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.sql.Blob;
import java.sql.Clob;
/* ifdef JDBC40 */
import java.sql.NClob;
import java.sql.RowId;
/* endif */
import java.sql.SQLException;
/* ifdef JDBC40 */
import java.sql.SQLXML;
/* endif */
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
/* ifdef JDBC40 */
import java.util.GregorianCalendar;
/* endif */
/* ifdef JDBC42
import java.time.LocalTime;
import java.time.LocalDate;
import java.time.LocalDateTime;
endif */
import java.net.URL;
abstract class SQLVarcharBase
extends SQLDataBase implements SQLVariableCompressible
{
static final String copyright = "Copyright (C) 1997-2013 International Business Machines Corporation and others.";
// Private data.
protected int length_;
protected int maxLength_;
protected String value_;
// We need the untruncated value for UTF-8 conversions @X4A
protected String untruncatedValue_;
protected int bytesPerCharacter_;
protected int sizeAfterTruncation_ = 0;
// Note: maxLength is in bytes not counting 2 for LL.
//
SQLVarcharBase(SQLConversionSettings settings, int length, int maxLength, String value)
{
super(settings);
length_ = length;
maxLength_ = maxLength;
value_ = value;
untruncatedValue_ = value;
bytesPerCharacter_ = 1;
}
SQLVarcharBase(SQLConversionSettings settings, int length, int maxLength, String value, int bytesPerCharacter)
{
super(settings);
length_ = length;
maxLength_ = maxLength;
value_ = value;
untruncatedValue_ = value;
bytesPerCharacter_ = bytesPerCharacter;
}
// @A2A
// Added method trim() to trim the string.
public void trim() // @A2A
{ // @A2A
value_ = value_.trim(); // @A2A
} // @A2A
//---------------------------------------------------------//
// //
// CONVERSION TO AND FROM RAW BYTES //
// //
//---------------------------------------------------------//
public void convertFromRawBytes(byte[] rawBytes, int offset, ConvTable ccsidConverter, boolean ignoreConversionErrors)
throws SQLException
{
length_ = BinaryConverter.byteArrayToUnsignedShort(rawBytes, offset);
int bidiStringType = settings_.getBidiStringType();
// if bidiStringType is not set by user, use ccsid to get value
if(bidiStringType == -1)
bidiStringType = ccsidConverter.bidiStringType_;
BidiConversionProperties bidiConversionProperties = new BidiConversionProperties(bidiStringType); //@KBA
bidiConversionProperties.setBidiImplicitReordering(settings_.getBidiImplicitReordering()); //@KBA
bidiConversionProperties.setBidiNumericOrderingRoundTrip(settings_.getBidiNumericOrdering()); //@KBA
try{
// If the field is VARGRAPHIC, length_ contains the number
// of characters in the string, while the converter is expecting
// the number of bytes. Thus, we need to multiply length_ by bytesPerCharacter.
sizeAfterTruncation_ = length_*bytesPerCharacter_;
value_ = ccsidConverter.byteArrayToString(rawBytes, offset+2, length_*bytesPerCharacter_, bidiConversionProperties); //@KBC changed to use bidiConversionProperties instead of bidiStringType
untruncatedValue_ = value_;
}catch(Exception e){
JDError.throwSQLException(JDError.EXC_CHAR_CONVERSION_INVALID, e);
}
}
public void convertToRawBytes(byte[] rawBytes, int offset, ConvTable ccsidConverter)
throws SQLException
{
try
{
int bidiStringType = settings_.getBidiStringType();
// if bidiStringType is not set by user, use ccsid to get value
if(bidiStringType == -1)
bidiStringType = ccsidConverter.bidiStringType_;
BidiConversionProperties bidiConversionProperties = new BidiConversionProperties(bidiStringType); //@KBA
bidiConversionProperties.setBidiImplicitReordering(settings_.getBidiImplicitReordering()); //@KBA
bidiConversionProperties.setBidiNumericOrderingRoundTrip(settings_.getBidiNumericOrdering()); //@KBA
truncated_ = 0; outOfBounds_ = false ;
String value = value_;
// For CCSID 1208 we must use the untruncated value to avoid having half a UTF-16 character
if (ccsidConverter.getCcsid() == 1208) {
value = untruncatedValue_;
}
// The length in the first 2 bytes is actually the length in characters.
byte[] temp = ccsidConverter.stringToByteArray(value, bidiConversionProperties); //@KBC changed to used bidiConversionProperties instead of bidiStringType
BinaryConverter.unsignedShortToByteArray(temp.length/bytesPerCharacter_, rawBytes, offset);
sizeAfterTruncation_ = temp.length;
if(temp.length > maxLength_)
{
// Normally truncation is detected before setting the string. In the case of UTF-8
// truncation may be detected here.
// Make sure the length sent to the server is the truncated length -- otherwise the string
// would include garbage. @V6A
BinaryConverter.unsignedShortToByteArray(maxLength_/bytesPerCharacter_, rawBytes, offset);
sizeAfterTruncation_ = maxLength_;
truncated_ = temp.length - maxLength_; /*@H2C*/
// Not sure why maxLength_ was changed.
// maxLength_ = temp.length;
// We now set the truncated information and let the truncated data through
// JDError.throwSQLException(this, JDError.EXC_INTERNAL, "Change Descriptor");
// the testDataTruncation method will be called to see if
// the truncation message should be thrown.
System.arraycopy(temp, 0, rawBytes, offset+2, maxLength_);
} else {
System.arraycopy(temp, 0, rawBytes, offset+2, temp.length);
}
// The buffer we are filling with data is big enough to hold the entire field.
// For varchar fields the actual data is often smaller than the field width.
// That means whatever is in the buffer from the previous send is sent to the
// system. The data stream includes actual data length so the old bytes are not
// written to the database, but the junk left over may decrease the effectiveness
// of compression. The following code will write hex 0s to the buffer when
// actual length is less that field length. Note the 0s are written only if
// the field length is pretty big. The data stream code (DBBaseRequestDS)
// does not compress anything smaller than 1K.
if( (maxLength_ - temp.length > 16)) //@rle
{
int stopHere = offset + 2 + maxLength_;
for(int i=offset + 2 + temp.length; i maxLength_) {
truncated_ = temp.length - maxLength_; /* @H2C */
// maxLength_ = temp.length;
// JDError.throwSQLException(this, JDError.EXC_INTERNAL,
// "Change Descriptor");
// @X6D.
// Complete @H2 fix and report truncation
System.arraycopy(temp, 0, rawBytes, offset + 2, maxLength_);
bytesWritten += maxLength_;
} else {
if (temp.length > 0) {
System.arraycopy(temp, 0, rawBytes, offset + 2, temp.length);
bytesWritten += temp.length;
}
}
} catch (Exception e) {
JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
}
return bytesWritten;
}
//---------------------------------------------------------//
// //
// SET METHODS //
// //
//---------------------------------------------------------//
public void set(Object object, Calendar calendar, int scale)
throws SQLException
{
String value = null; // @C1A
if(object instanceof String)
value = (String) object; // @C1C
else if(object instanceof Number)
value = object.toString(); // @C1C
else if(object instanceof Boolean)
{
// @PDC
// if "translate boolean" == false, then use "0" and "1" values to match native driver
if(settings_.getTranslateBoolean() == true)
value = object.toString(); //"true" or "false"
else
value = ((Boolean)object).booleanValue() == true ? "1" : "0";
}
else if(object instanceof Time)
value = SQLTime.timeToString((Time) object, settings_, calendar); // @C1C
else if(object instanceof Timestamp)
value = SQLTimestamp.timestampToStringTrimTrailingZeros((Timestamp) object, calendar, settings_); // @C1C
else if(object instanceof java.util.Date) // @F5M @F5C
value = SQLDate.dateToString((java.util.Date) object, settings_, calendar); // @C1C @F5C
else if(object instanceof URL)
value = object.toString();
else if( object instanceof Clob)
{ // @C1C
Clob clob = (Clob)object; // @C1C
value = clob.getSubString(1, (int)clob.length()); // @C1C @D1
} // @C1C
else if(object instanceof Reader)
{
value = getStringFromReader((Reader) object, ALL_READER_BYTES, this);
}
/* ifdef JDBC40 */
else if(object instanceof SQLXML) //@PDA jdbc40
{
SQLXML xml = (SQLXML)object;
value = xml.getString();
}
/* endif */
/* ifdef JDBC42
else if(object instanceof java.time.LocalDate)
{
value = SQLDate.localDateToString((java.time.LocalDate)object, settings_, calendar);
}
else if(object instanceof LocalTime)
value = SQLTime.localTimeToString((LocalTime) object, settings_, calendar);
else if(object instanceof LocalDateTime)
value = SQLTimestamp.localDateTimeToStringTrimTrailingZeros((LocalDateTime) object, calendar, settings_);
endif */
if(value == null) { // @C1C
if (JDTrace.isTraceOn()) {
if (object == null) {
JDTrace.logInformation(this, "Unable to assign null object");
} else {
JDTrace.logInformation(this, "Unable to assign object("+object+") of class("+object.getClass().toString()+")");
}
}
JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
}
value_ = value; // @C1A
untruncatedValue_ = value_;
// Truncate if necessary.
int valueLength = value_.length();
int truncLimit = maxLength_ / bytesPerCharacter_; // @F2a
if(valueLength > truncLimit) // @F2c
{
value_ = value_.substring(0, truncLimit); // @F2c
truncated_ = valueLength - truncLimit; // @F2c
outOfBounds_ = false;
}
else
truncated_ = 0; outOfBounds_ = false;
length_ = value_.length();
}
//---------------------------------------------------------//
// //
// DESCRIPTION OF SQL TYPE //
// //
//---------------------------------------------------------//
public int getSQLType()
{
return SQLData.VARCHAR;
}
public String getCreateParameters()
{
return AS400JDBCDriver.getResource("MAXLENGTH",null);
}
public int getDisplaySize()
{
return maxLength_;
}
//@F1A JDBC 3.0
public String getJavaClassName()
{
return "java.lang.String";
}
public String getLiteralPrefix()
{
return "\'";
}
public String getLiteralSuffix()
{
return "\'";
}
public String getLocalName()
{
return "VARCHAR";
}
public int getMaximumPrecision()
{
return 32739;
}
public int getMaximumScale()
{
return 0;
}
public int getMinimumScale()
{
return 0;
}
public int getNativeType()
{
return 448;
}
public int getPrecision()
{
return maxLength_ / bytesPerCharacter_;
}
public int getRadix()
{
return 0;
}
public int getScale()
{
return 0;
}
public int getType()
{
return java.sql.Types.VARCHAR;
}
public String getTypeName()
{
return "VARCHAR";
}
public boolean isSigned()
{
return false;
}
public boolean isText()
{
return true;
}
// Returns the size after truncation has occurred
public int getActualSize()
{
if (sizeAfterTruncation_ != 0) {
return sizeAfterTruncation_;
} else {
return value_.length();
}
}
public int getTruncated()
{
return truncated_;
}
public boolean getOutOfBounds() {
return outOfBounds_;
}
//---------------------------------------------------------//
// //
// CONVERSIONS TO JAVA TYPES //
// //
//---------------------------------------------------------//
public InputStream getBinaryStream()
throws SQLException
{
truncated_ = 0; outOfBounds_ = false;
return new HexReaderInputStream(new StringReader(getString()));
}
public Blob getBlob()
throws SQLException
{
truncated_ = 0; outOfBounds_ = false;
try
{
byte[] bytes = BinaryConverter.stringToBytes(getString());
return new AS400JDBCBlob(bytes, bytes.length);
}
catch(NumberFormatException nfe)
{
// this field contains non-hex characters
JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH, nfe);
return null;
}
}
public byte[] getBytes()
throws SQLException
{
truncated_ = 0; outOfBounds_ = false;
try
{
return BinaryConverter.stringToBytes(getString());
}
catch(NumberFormatException nfe)
{
// this field contains non-hex characters
JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH, nfe);
return null;
}
}
public Object getObject()
throws SQLException
{
truncated_ = 0; outOfBounds_ = false;
// This is written in terms of getString(), since it will
// handle truncating to the max field size if needed.
return getString();
}
public String getString() throws SQLException
{
truncated_ = 0; outOfBounds_ = false;
// Truncate to the max field size if needed.
// Do not signal a DataTruncation per the spec. @B1A
int maxFieldSize = settings_.getMaxFieldSize();
if((value_.length() > maxFieldSize) && (maxFieldSize > 0))
{
// @B1D truncated_ = value_.length() - maxFieldSize;
return value_.substring(0, maxFieldSize);
}
else
{
// @B1D truncated_ = 0; outOfBounds_ = false;
return value_;
}
}
//@pda jdbc40
public String getNString() throws SQLException
{
// Truncate to the max field size if needed.
// Do not signal a DataTruncation per the spec.
int maxFieldSize = settings_.getMaxFieldSize();
if((value_.length() > maxFieldSize) && (maxFieldSize > 0))
{
return value_.substring(0, maxFieldSize);
}
else
{
return value_;
}
}
/* ifdef JDBC40 */
//@pda jdbc40
public RowId getRowId() throws SQLException
{
JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
return null;
}
//@pda jdbc40
public SQLXML getSQLXML() throws SQLException
{
//This is written in terms of getString(), since it will
// handle truncating to the max field size if needed.
truncated_ = 0; outOfBounds_ = false;
return new AS400JDBCSQLXML(getString());
}
/* endif */
public void saveValue() {
savedValue_ = untruncatedValue_;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy