longchar.java
/*
** Module : longchar.java
** Abstract : Progress 4GL compatible longchar object
**
** Copyright (c) 2012-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
** 001 AIL 20121206 Created initial version to support for Progress LONGCHAR type.
** 002 GES 20130322 Added the BDT c'tor.
** 003 VIG 20131003 Overridden instantiateUnknown method to return longchar
** 004 MAG 20140602 Fixed the BDT c'tor and modified the assign(BDT,boolean) on _POLY morphing.
** Override compareTo() method for _POLY morphing.
** 005 GES 20141003 Added overridden method to disable assignments of values with embedded
** null characters.
** 006 CA 20151222 Added instantiateDefaultExtent.
** 007 GES 20171207 Removed forced version of assign().
** 008 ECF 20181214 Implemented LargeObject interface.
** CA 20181221 Added GET-CODEPAGE variants.
** 009 EVL 20190412 Added runtime support for GET-CODEPAGE, FIX-CODEPAGE, IS-CODEPAGE-FIXED.
** 010 ECF 20190628 Implemented COPY-LOB runtime.
** 011 HC 20190805 Added method instantiateDefault.
** 012 CA 20191119 Fixed write(...) - if the data is empty, then assign it.
** 013 CA 20191203 Fixed overlay and unknown COPY-LOB related bugs.
** 014 ME 20200401 Fixed codepage set on assign, fix codepage validation.
** 015 ME 20200810 Cleanup for toStringExport().
** IAS 20201007 Added Type enum
** ME 20201009 Allow codepage to be reset back to unknown in fix-codepage.
** OM 20210203 Added API to accept unknown parameter for fixCodePage() method.
** OM 20210312 FIX-CODE-PAGE statement is converted to a static method to accomodate the cases when
** the object is obtained by dereference. Improved COPY-LOB engine and validations.
** OM 20210404 Reworked codepage management for CLOB fields.
** CA 20210428 Fixed conversion when the lvalue for an assign-styme stmt is a OO property (chained or
** not). In this case, a setter must wrap the assign-style stmt, to change the property's
** value.
** ME 20210504 Added isIncompatibleTypesOnConversion override for invalid POLY conversion.
** CA 20210609 Reworked INPUT/INPUT-OUTPUT parameters to a new approach, where they are explicitly
** initialized at the method's execution, and not at the caller's arguments.
** CA 20210713 Fixed COPY-LOB when source is unknown (must set the longchar target to unknown).
** AL2 20220328 Added proxy checks for BDT.
** EVL 20220406 Fix for pverlay mode in write method when we need to replace the text considering offset
** in target object.
** EVL 20220411 User regular overlay method when using offset with overlay mode. Adding trim option
** support for writing to longchar. Reworked overlay trim because of different meaning
** the word 'trim' has here.
** CA 20221024 'asByteArray' must use the actual codepage set at the longchar instance, regardless if
** this was set via FIX-CODEPAGE or via an assignment from another longchar instance.
** 016 HC 20230118 Eliminated some of the uses of String.toUpperCase and/or String.toLowerCase
** for performance.
** 017 CA 20230215 'duplicate()' method returns the real type instead of BDT.
** 018 EVL 20230317 Adding supprt for longchar variable length override in some conditions. This value can
** differ from backend String value length.
** EVL 20230322 Changed approach for setting length override value. If was already set the new value
** accepted if it exceeds the current one.
** 019 CA 20230526 Added 'forceCharacterType', emitted for a 'ELSE' longchar expr in a ternary IF which is
** used for a builtin function call.
** 020 EVL 20240607 Fix for unwanted message for assignment to unknown value. If codepage was already fixed
** no need to do this again.
** 021 SP 20240805 Fix for unwanted 11683 error for assignment to unknown value. Moved the fixCodepage call
** after the assignment.
** 022 CA 20241030 Avoid 'Text.javaSpacifyNull' if the string is known to already have been processed.
** 023 AP 20250318 Improved toStringMessage method to take into account unknown values.
** 024 TG 20250519 Removed longchar.getcodePage(BaseDataType) because it is implemented in I18nOps
** 20250520 Replaced new character() with character.UNKNOWN in getCodePage() for better performance
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** 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 Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.util;
import com.goldencode.util.*;
import java.io.*;
/**
* A class that represents a Progress 4GL compatible longchar object whose data is mutable.
* <p>
* Although Progress documentation states that the default value of any <code>longchar</code>
* variable is the unknown value, the real behavior is that it gets initialized to the empty
* string, same as character variables get initialized.
*/
public class longchar
extends Text
implements LargeObject
{
/** Variable to store code page value set by FIX-CODEPAGE statement. */
private String codePage;
/**
* Variable to store if code page value was set by FIX-CODEPAGE statement.
* IS-CODEPAGE-FIXED will relay on this
* */
private boolean fixedCodepage;
/**
* The override value for variable length. Can be changed in copy-lob operration if target is longchar
* and source is memptr.
*/
private int overrideLength = -1;
/**
* Default constructor, creates an instance that represents the unknown value.
*/
public longchar()
{
super();
}
/**
* This is a special c'tor which should be used only when converting the
* value returned by a function or method with polymorphic return type into the
* expected type (i.e. DYNAMIC-FUNCTION()). In such cases, the 4GL does some
* automatic type conversion (this is delegated to the superclass' constructor).
* <p>
* Only Text (character or longchar) BDT's can be converted to longchar.
*
* @param value
* The value to be used for this instance.
*/
public longchar(BaseDataType value)
{
// the value may be a proxy; make sure to unwrap and work with the real value
value = value == null ? null : value.val();
if (value == null || value.isUnknown())
{
setUnknown();
}
else
{
if (value instanceof Text)
{
assign(value);
}
else
{
incompatibleTypesOnConversion();
}
}
}
/**
* Constructs an instance that has the <code>String</code> value passed
* in and which <b>does not</b> represent the <code>unknown value</code>,
* unless the <code>value</code> argument is <code>null</code>.
* If value is not "" then codepage is cpinternal
*
* @param value
* The character value of the resulting instance.
*/
public longchar(String value)
{
super(value);
if (!TextOps.isEmpty(value))
{
codePage = I18nOps._getCPInternal();
}
}
/**
* Constructs an instance that has the <code>String</code> value passed
* in and which <b>does not</b> represent the <code>unknown value</code>
* unless the <code>value</code> argument is <code>null</code>.
*
* @param value
* The character value of the resulting instance.
* @param caseSens
* Specifies whether this instance should use case sensitive
* comparisons.
*/
public longchar(String value, boolean caseSens)
{
super(value, caseSens);
if (!TextOps.isEmpty(value))
{
codePage = I18nOps._getCPInternal();
}
}
/**
* Constructs an instance that has a <code>char</code> value passed
* in and which <b>does not</b> represent the <code>unknown value</code>.
*
* @param ch
* The character value of the resulting instance.
*/
public longchar(char ch)
{
super(ch);
}
/**
* Create a new instance, by copying the state of the passed {@link Text}.
*
* @param value
* The value which needs to be copied.
*/
public longchar(Text value)
{
super(value);
}
/**
* Force the longchar value as a character type, without limit length enforcement.
*
* @param val
* The value to convert.
*
* @return The new character value, with {@link character#forceLengthLimit()} disabled.
*/
public static character forceCharacterType(longchar val)
{
return new character(val)
{
@Override
protected boolean forceLengthLimit()
{
return false;
}
};
}
/**
* Get the type
* @return type
*/
public Type getType()
{
return Type.LONGCHAR;
}
/**
* Report if existing instances that have embedded null characters are allowed to be
* assigned to this instance.
*
* @return Always <code>false</code>.
*/
public boolean isEmbeddedNullAllowed()
{
return false;
}
/**
* Compares this instance with the specified instance and returns a -1
* if this instance is less than the specified, 0 if the two instances
* are equal and 1 if this instance is greater than the specified
* instance. This is the implementation of the <code>Comparable</code>
* interface.
*
* @param obj
* The instance to compare against.
*
* @return -1, 0 or 1 depending on if this instance is less than,
* equal to or greater (respectively) than the specified
* instance <code>obj</code>.
*/
public int compareTo(Object obj)
{
if (obj instanceof BaseDataType)
{
return super.compareTo(new longchar((BaseDataType) obj));
}
return super.compareTo(obj);
}
/**
* Returns the code page of a the specified longchar variable. If the
* specified LONGCHAR is empty and the code page was not fixed using the
* FIX-CODEPAGE statement, must return the unknown value.
*
* @param value
* The value for which the codepage will be retrieved.
*
* @return See above
*/
public static character getCodePage(longchar value)
{
return value.getCodePage();
}
/**
* Returns the code page of a the current longchar variable. If the LONGCHAR is unknown or empty and the
* code page was not fixed using the FIX-CODEPAGE statement, the unknown value is returned.
*
* @return See above
*/
public character getCodePage()
{
String cp = _getCodePage();
return (cp == null) ? character.UNKNOWN : new character(cp.toUpperCase());
}
/**
* Returns the code page of a the current longchar variable. If the LONGCHAR is unknown or empty and the
* code page was not fixed using the FIX-CODEPAGE statement, the unknown value is returned.
* <p>
* This is the String returning value, the unknown value is represented by {@code null}.
*
* @return See above
*/
public String _getCodePage()
{
if (fixedCodepage)
{
return codePage;
}
if (isUnknown() || value.isEmpty())
{
return null;
}
// at this moment codePage must not be null
return codePage;
}
/**
* Creates a new instance of the same type that represents the {@code unknown value}.
*
* @return An instance that represents the {@code unknown value}.
*/
public BaseDataType instantiateUnknown()
{
return new longchar();
}
/**
* Return {@code true} if the codepage of the given longchar variable is fixed.
*
* @param value
* The value for which the codepage will be retrieved.
*
* @return See above.
*/
public static logical isCodePageFixed(longchar value)
{
return new logical(value != null && value.isCodePageFixed());
}
/**
* Implements Progress 4GL feature for FIX-CODEPAGE statement.
*
* @param longcharRef
* A reference to a {@code longchar} variable.
* @param cpToUse
* The new value for codepage to be fixed.
*
* @return The longchar reference.
*/
public static longchar fixCodePage(longchar longcharRef, String cpToUse)
{
return fixCodePage(longcharRef, cpToUse, false);
}
/**
* Implements Progress 4GL feature for FIX-CODEPAGE statement.
* <p>
* Note: actually this method should be as less visible as possible, preferably private. However, it must
* be accessed from {@link com.goldencode.p2j.persist.FieldReference}.
*
* @param longcharRef
* A reference to a {@code longchar} variable.
* @param cpToUse
* The new value for codepage to be fixed. If {@code prepareClob} is true, this parameter must NOT
* be {@code null}.
* @param prepareClob
* Allow to set a FIXED the CODEPAGE on target {@code longcharRef} only if it is a field (hence
* a {@code clob}) only when this parameter is {@code true}. Otherwise the procedure is finished.
* At least this is behaviour in 4GL: ERROR-STATUS:ERROR = YES ERROR-STATUS:GET-NUMBER(1) = 0.
* ERROR-STATUS:get-message(1) = "".
*
* @return The longchar reference.
*/
public static longchar fixCodePage(longchar longcharRef, String cpToUse, boolean prepareClob)
{
if (longcharRef instanceof clob)
{
if (!prepareClob || longcharRef.fixedCodepage)
{
// yes!, isn't it funny when procedure stops without any apparent reason?
ErrorManager.recordOrThrowError(0, "", false);
return longcharRef;
}
}
// allow to lazily set the CP on CLOB fields
if (!TextOps.isEmpty(longcharRef) && !prepareClob)
{
ErrorManager.recordOrThrowError(11683);
// FIX-CODEPAGE can only be run when the LONGCHAR variable is empty.
}
else
{
if (cpToUse == null)
{
longcharRef.codePage = null;
longcharRef.fixedCodepage = false;
}
else if (!I18nOps.isSupported(cpToUse))
{
ErrorManager.recordOrThrowError(912, cpToUse.toUpperCase(), I18nOps.CONVERSION_MAP_FILE);
// Code page attribute table for <code-page> was not found in <filename>.
}
else
{
if (I18nOps.CP_UNDEFINED.equalsIgnoreCase(cpToUse))
{
ErrorManager.recordOrThrowError(12125, cpToUse, "");
// The codepage "<codepage>" cannot be used for CLOB or LONGCHAR variables.
}
else
{
longcharRef.codePage = cpToUse;
longcharRef.fixedCodepage = true;
}
}
}
return longcharRef;
}
/**
* Implements Progress 4GL feature for FIX-CODEPAGE statement.
*
* @param longcharRef
* A reference to a {@code longchar} variable.
* @param cpToUse
* The new value for codepage to be fixed.
*/
public static void fixCodePage(longchar longcharRef, Text cpToUse)
{
fixCodePage(longcharRef, (cpToUse == null) ? null : cpToUse.toJavaType());
}
/**
* Implements Progress 4GL feature for FIX-CODEPAGE statement. This variant is used when the first
* argument is obtained by dereferenciation.
*
* @param value
* A reference to a BDT, obtained by dereferenciation.
* @param cpToUse
* The new value for codepage to be fixed.
*/
public static void fixCodePage(BaseDataType value, String cpToUse)
{
if (value instanceof longchar)
{
fixCodePage((longchar) value, cpToUse);
}
else
{
ErrorManager.recordOrThrowError(5729);
// Incompatible datatypes found during runtime conversion. (5729)
}
}
/**
* Implements Progress 4GL feature for FIX-CODEPAGE statement. This variant is used when either of the
* arguments or both are obtained by dereferenciation.
*
* @param value
* A reference to a BDT, obtained by dereferenciation.
* @param cpToUse
* The new value for codepage to be fixed.
*/
public static void fixCodePage(BaseDataType value, BaseDataType cpToUse)
{
if (cpToUse == null || cpToUse.isUnknown())
{
fixCodePage(value, (String) null);
}
else if (cpToUse instanceof Text && !(cpToUse instanceof clob))
{
fixCodePage(value, ((Text) cpToUse).toJavaType());
}
else if (cpToUse instanceof blob || cpToUse instanceof clob ||
cpToUse instanceof raw || cpToUse instanceof memptr)
{
ErrorManager.recordOrThrowError(5729);
// Incompatible datatypes found during runtime conversion. (5729)
}
else
{
ErrorManager.recordOrThrowError(912, cpToUse.toStringMessage(), I18nOps.CONVERSION_MAP_FILE);
// Code page attribute table for <code-page> was not found in <filename>. (912)
}
}
/**
* Implements Progress 4GL feature for FIX-CODEPAGE statement.
*
* @param cpToUse
* The new value for codepage to be fixed.
*/
public void fixCodePage(String cpToUse)
{
fixCodePage(this, cpToUse);
}
/**
* Implements Progress 4GL feature for FIX-CODEPAGE statement.
*
* @param cpToUse
* The new value for codepage to be fixed.
*/
public void fixCodePage(character cpToUse)
{
fixCodePage(this, (cpToUse != null) ? cpToUse.getValue() : null);
}
/**
* Return the value codepage fixed status.
*
* @return <code>TRUE</code> is codepage was fixed for this variable,
* <code>FALSE</code> otherwise.
*/
public boolean isCodePageFixed()
{
return fixedCodepage;
}
/**
* Return the default display format string for this type.
*
* @return The default format string.
*/
public String defaultFormatString()
{
return null;
}
/**
* Does the same as standard <code>clone()</code> method but returns an
* instance of <code>BaseDataType</code> and doesn't throw the
* <code>CloneNotSupportedException</code>.
*
* @return A clone of this instance.
*/
public longchar duplicate()
{
return new longchar(this);
}
/**
* Creates a string representation of the instance data in a form that is compatible with the
* {@code MESSAGE} language statement. If the instance represents the {@code unknown value}, a '?' will
* be returned.
*
* @return The 'message' formatted string.
*/
public String toStringMessage()
{
return toStringExport();
}
/**
* Creates a string representation of the instance data using the 'export'
* format. For the character data type the entire string is returned
* enclosed in a pair of double quotes. If the instance represents the
* <code>unknown value</code>, a '?' will be returned. Any instances of
* double quotes inside the string will be doubled up on output.
*
* @return The 'export' formatted string.
*/
public String toStringExport()
{
return isUnknown() ? "?" : getValue();
}
/**
* Creates a string representation of the instance data using the user- specified Progress 4GL format
* string. The algorithm to format a {@code longchar} is basically the same as for any {@code character}.
*
* @param fmt
* The Progress 4GL format string for a character data type.
*
* @return The formatted string.
*/
public String toString(String fmt)
{
if (isUnknown())
{
return "?";
}
String clean = null;
// implement 'default' behavior
if (fmt == null)
{
fmt = character.defaultFormat;
// default case doesn't specify
clean = value;
}
else
{
// for some reason, when there is an explicit format string, the value is specified
clean = javaSpacifyNull ? javaSpacifyNull(value) : value;
}
// make the format string easier to process
String format = character.preprocessFormatString(fmt);
// trim trailing whitespace off the value
String trimmed = StringHelper.safeTrimTrailing(clean);
// build the output string and return it
return character.processDataString(trimmed, format);
}
/**
* Indicate whether this object manages character data (as opposed to binary data).
*
* @return Always {@code true}.
*/
@Override
public boolean isCharacterData()
{
return true;
}
/**
* The length of the data managed by this object.
*
* @return The length, or 0 if uninitialized/unknown.
*/
@Override
public long lengthOf()
{
if (isUnknown())
{
return 0;
}
return value.length();
}
/**
* Return the entire contents of the current buffer as an array. This may be a copy of the data, depending
* on the subclass' implementation. The byte array is the binary representation of this LOB using the
* configured codepage. If none was configured the default CPInternal is used.
*
* @param pos
* Starting offset position.
* @param len
* Length of range to return.
*
* @return The contents of the instance. If the instance is uninitialized the returned
* value will be a 0 length array. If the instance is {@code unknown} or has an
* undefined size, then {@code null} will be returned.
*/
@Override
public byte[] asByteArray(long pos, long len)
{
if (isUnknown())
{
return null;
}
int offset = (int) Math.max(0, pos);
int length = (int) Math.min(len, value.length());
String s = (pos == 0 && len == length) ? value : value.substring(offset, length);
String codePage = this.codePage != null ? this.codePage : I18nOps._getCPInternal();
String charset = I18nOps.convmap2Java.get(codePage);
try
{
return s.getBytes(charset);
}
catch (UnsupportedEncodingException e)
{
ErrorManager.recordOrThrowError(912, codePage, I18nOps.CONVERSION_MAP_FILE);
// Code page attribute table for <code-page> was not found in <filename>.
return null;
}
}
/**
* Write the given character data into the data managed by this object, overwriting the data
* that are at the given location, if any.
* <p>
* This implementation:
* <ul>
* <li>ignores the {@code trim} option (i.e., any existing characters beyond the end of the
* write are left in place, regardless of the value of {@code trim});</li>
* <li>extends the target size if the write goes past the end of the existing value.</li>
* </ul>
*
* @param overlay
* Flag indicating if the OVERLAY option is used.
* @param data
* Data to be assigned to this object.
* @param offset
* Offset position (in characters) in the target large object.
* @param trim
* {@code true} to truncate any remaining data in the target large object; {@code
* false} to leave remaining data alone. Ignored.
*/
@Override
public void write(boolean overlay, String data, int offset, boolean trim)
{
// if we are in overlay mode, fill with 'offset - 1' spaces to the right
// TODO: if value is null and source is clob, then this remains unknown....
if (overlay && (value == null || offset >= value.length()))
{
int rightFill = offset - (value == null ? 0 : value.length());
assign(value + StringHelper.rightAlignText("", rightFill));
}
int dataLen;
if (data == null || (dataLen = data.length()) == 0 || (offset == 0 && data.equals(value)))
{
// nothing to write or data already is stored in this object (we don't do a deep equals
// check because it could be expensive and the common case is likely a full assignment
// anyway, so don't take the hit here, just quickly check for object reference equality)
if (overlay)
{
// do the trimming is requested
if (trim && value != null && offset >= 0 && offset < value.length())
{
// do not using regular trim function here
assign(value.substring(0, offset) + ((data != null) ? data : ""));
}
}
else
{
if (data != null)
{
assign(data);
}
else
{
setUnknown();
// TODO: CA - this was commented out because 'COPY-LOB tt1.clobField to lc' sets the target
// to unknown if tt1.clobField is unknown.
// assign("");
}
}
return;
}
int currentLen = (value != null) ? value.length() : 0;
if (offset > currentLen)
{
ErrorManager.recordOrThrowError(11316);
// Could not obtain LONGCHAR. (11316)
return;
}
// simple case: just replace existing value with data
if (!overlay || isUnknown() || (offset == 0 && (currentLen <= dataLen)))
{
assign(data);
return;
}
// complex case: overlay data over existing data, possibly extending the length
int endData = offset + dataLen;
int newLen = trim ? endData : Math.max(currentLen, endData);
char[] buf = new char[newLen];
if (offset > 0)
{
// copy first portion from existing value into new buffer
value.getChars(0, offset, buf, 0);
}
// copy new data to its target offset in new buffer
data.getChars(0, dataLen, buf, offset);
if (newLen > endData)
{
// copy last portion from existing value into new buffer
value.getChars(endData, currentLen, buf, endData);
}
assign(new String(buf));
}
/**
* Creates a new instance of the same type that represents the
* default initialized value.
*
* @return An instance that represents the default value.
*/
public BaseDataType instantiateDefault()
{
return new longchar("");
}
/**
* Get the default initialization for an extent variable of this type.
*
* @return See above.
*/
@Override
protected BaseDataType instantiateDefaultExtent()
{
return new longchar("");
}
/**
* Assigns the value represented by {@code value} to this object. If this {@code longchar} does not have a
* fixed codepage, the default codepage (SESSION:CPINTERNAL) is used. Otherwise a codepage conversion
* occurs.
*
* @param value
* The source {@code Text} to be assigned.
*/
@Override
protected boolean isIncompatibleTypesOnConversion(BaseDataType value)
{
// invalid conversion is being thrown even if unknown
if (value instanceof blob ||
// if not unknown only longchar/character allowed
(value != null && !value.isUnknown() && !(value instanceof longchar)
&& !(value instanceof character)))
{
incompatibleTypesOnConversion();
}
return super.isIncompatibleTypesOnConversion(value);
}
/**
* Sets new value for longchar overridden length. Can be more than backend String variable and sets up
* in copy-lob operation in some conditions.
*
* @param newOverrideLength
* The new value of the internal longchar length.
*/
protected void setOverrideLength(int newOverrideLength)
{
if(newOverrideLength == -1 || newOverrideLength > overrideLength)
{
overrideLength = newOverrideLength;
}
}
/**
* Returns the length of the current Text object instance in chars. Internal version.
*
* @return Current text variable char length.
*/
@Override
protected int lengthInt()
{
return overrideLength != -1 ? overrideLength : super.lengthInt();
}
@Override
public void assign(Text value)
{
// the value may be a proxy; make sure to unwrap and work with the real value
if (BaseDataType.isProxy(value))
{
assign(value.val());
return;
}
if (value instanceof longchar)
{
assign((longchar) value);
}
else
{
if (value.isUnknown())
{
// the fixed codepage is kept
setUnknown();
}
else
{
if (!isCodePageFixed() && !TextOps.isEmpty(value))
{
codePage = I18nOps._getCPInternal();
}
super.assign(value);
}
}
}
/**
* Assigns the value represented by {@code value} to this object. If this {@code longchar} does not have a
* fixed codepage, the codepage from the source is copied too. Otherwise a codepage conversion occurs.
*
* @param value
* The source {@code longchar} to be assigned.
*/
public void assign(longchar value)
{
// the value may be a proxy; make sure to unwrap and work with the real value
if (BaseDataType.isProxy(value))
{
assign(value.val());
return;
}
if (!value.isUnknown())
{
if (!isCodePageFixed())
{
codePage = value._getCodePage();
super.assign(value);
}
else
{
super.assign(TextOps.codePageConvert(value, codePage, value._getCodePage()));
}
}
else
{
super.assign(value);
// do not fix code page if already done
if (!isCodePageFixed())
{
fixCodePage(this, (String) null);
}
}
}
/**
* Obtain the length (in bytes) of this BDT will use when serialized.
*
* @return the length of this BDT will use when serialized.
*/
@Override
public int getSize()
{
return super.value.length();
}
}