/*
* Copyright (c) 2002, 2019, 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.
*
* Without limiting anything contained in the foregoing, this file, which is
* part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
* version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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.cj.result;
import com.mysql.cj.
CharsetMapping;
import com.mysql.cj.
MysqlType;
import com.mysql.cj.
ServerVersion;
import com.mysql.cj.util.
LazyString;
/**
* Field is a class used to describe fields in a ResultSet
*/
public class
Field {
private int
collationIndex = 0;
private
String encoding = "US-ASCII";
private int
colDecimals;
private short
colFlag;
private
LazyString databaseName = null;
private
LazyString tableName = null;
private
LazyString originalTableName = null;
private
LazyString columnName = null;
private
LazyString originalColumnName = null;
private
String fullName = null;
private long
length; // Internal length of the field;
private int
mysqlTypeId = -1; // the MySQL type ID in legacy protocol
private
MysqlType mysqlType =
MysqlType.
UNKNOWN;
public
Field(
LazyString databaseName,
LazyString tableName,
LazyString originalTableName,
LazyString columnName,
LazyString originalColumnName, long
length,
int
mysqlTypeId, short
colFlag, int
colDecimals, int
collationIndex,
String encoding,
MysqlType mysqlType) {
this.
databaseName =
databaseName;
this.
tableName =
tableName;
this.
originalTableName =
originalTableName;
this.
columnName =
columnName;
this.
originalColumnName =
originalColumnName;
this.
length =
length;
this.
colFlag =
colFlag;
this.
colDecimals =
colDecimals;
this.
mysqlTypeId =
mysqlTypeId;
this.
collationIndex =
collationIndex;
// ucs2, utf16, and utf32 cannot be used as a client character set, but if it was received from server under some circumstances we can parse them as utf16
this.
encoding = "UnicodeBig".
equals(
encoding) ? "UTF-16" :
encoding;
// MySQL encodes JSON data with utf8mb4.
if (
mysqlType ==
MysqlType.
JSON) {
this.
encoding = "UTF-8";
}
this.
mysqlType =
mysqlType;
adjustFlagsByMysqlType();
}
private void
adjustFlagsByMysqlType() {
switch (this.
mysqlType) {
case
BIT:
if (this.
length > 1) {
this.
colFlag |=
MysqlType.
FIELD_FLAG_BINARY;
this.
colFlag |=
MysqlType.
FIELD_FLAG_BLOB;
}
break;
case
BINARY:
case
VARBINARY:
this.
colFlag |=
MysqlType.
FIELD_FLAG_BINARY;
this.
colFlag |=
MysqlType.
FIELD_FLAG_BLOB;
break;
case
DECIMAL_UNSIGNED:
case
TINYINT_UNSIGNED:
case
SMALLINT_UNSIGNED:
case
INT_UNSIGNED:
case
FLOAT_UNSIGNED:
case
DOUBLE_UNSIGNED:
case
BIGINT_UNSIGNED:
case
MEDIUMINT_UNSIGNED:
this.
colFlag |=
MysqlType.
FIELD_FLAG_UNSIGNED;
break;
default:
break;
}
}
/**
* Used by prepared statements to re-use result set data conversion methods
* when generating bound parameter retrieval instance for statement interceptors.
*
* @param tableName
* not used
* @param columnName
* not used
* @param collationIndex
* the MySQL collation/character set index
* @param encoding
* encoding of data in this field
* @param mysqlType
* {@link MysqlType}
* @param length
* length in characters or bytes (for BINARY data).
*/
public
Field(
String tableName,
String columnName, int
collationIndex,
String encoding,
MysqlType mysqlType, int
length) {
this.
databaseName = new
LazyString(null);
this.
tableName = new
LazyString(
tableName);
this.
originalTableName = new
LazyString(null);
this.
columnName = new
LazyString(
columnName);
this.
originalColumnName = new
LazyString(null);
this.
length =
length;
this.
mysqlType =
mysqlType;
this.
colFlag = 0;
this.
colDecimals = 0;
adjustFlagsByMysqlType();
switch (
mysqlType) {
case
CHAR:
case
VARCHAR:
case
TINYTEXT:
case
TEXT:
case
MEDIUMTEXT:
case
LONGTEXT:
case
JSON:
// TODO: this becomes moot when DBMD results aren't built from ByteArrayRow
// it possibly overrides correct encoding already existing in the Field instance
this.
collationIndex =
collationIndex;
// ucs2, utf16, and utf32 cannot be used as a client character set, but if it was received from server under some circumstances we can parse them as utf16
this.
encoding = "UnicodeBig".
equals(
encoding) ? "UTF-16" :
encoding;
break;
default:
// ignoring charsets for non-string types
}
}
/**
* Returns the Java encoding for this field.
*
* @return the Java encoding
*/
public
String getEncoding() {
return this.
encoding;
}
// TODO Remove this after DBMD isn't using ByteArrayRow results.
public void
setEncoding(
String javaEncodingName,
ServerVersion version) {
this.
encoding =
javaEncodingName;
this.
collationIndex =
CharsetMapping.
getCollationIndexForJavaEncoding(
javaEncodingName,
version);
}
public
String getColumnLabel() {
return
getName();
}
public
String getDatabaseName() {
return this.
databaseName.
toString();
}
public int
getDecimals() {
return this.
colDecimals;
}
public
String getFullName() {
if (this.
fullName == null) {
StringBuilder fullNameBuf = new
StringBuilder(this.
tableName.
length() + 1 + this.
columnName.
length());
fullNameBuf.
append(this.
tableName.
toString());
fullNameBuf.
append('.');
fullNameBuf.
append(this.
columnName.
toString());
this.
fullName =
fullNameBuf.
toString();
}
return this.
fullName;
}
public long
getLength() {
return this.
length;
}
public int
getMysqlTypeId() {
return this.
mysqlTypeId;
}
public void
setMysqlTypeId(int
id) {
this.
mysqlTypeId =
id;
}
public
String getName() {
return this.
columnName.
toString();
}
public
String getOriginalName() {
return this.
originalColumnName.
toString();
}
public
String getOriginalTableName() {
return this.
originalTableName.
toString();
}
public int
getJavaType() {
return this.
mysqlType.
getJdbcType();
}
public
String getTableName() {
return this.
tableName.
toString();
}
public boolean
isAutoIncrement() {
return ((this.
colFlag &
MysqlType.
FIELD_FLAG_AUTO_INCREMENT) > 0);
}
public boolean
isBinary() {
return ((this.
colFlag &
MysqlType.
FIELD_FLAG_BINARY) > 0);
}
public void
setBinary() {
this.
colFlag |=
MysqlType.
FIELD_FLAG_BINARY;
}
public boolean
isBlob() {
return ((this.
colFlag &
MysqlType.
FIELD_FLAG_BLOB) > 0);
}
public void
setBlob() {
this.
colFlag |=
MysqlType.
FIELD_FLAG_BLOB;
}
public boolean
isMultipleKey() {
return ((this.
colFlag &
MysqlType.
FIELD_FLAG_MULTIPLE_KEY) > 0);
}
public boolean
isNotNull() {
return ((this.
colFlag &
MysqlType.
FIELD_FLAG_NOT_NULL) > 0);
}
public boolean
isPrimaryKey() {
return ((this.
colFlag &
MysqlType.
FIELD_FLAG_PRIMARY_KEY) > 0);
}
public boolean
isFromFunction() {
return this.
originalTableName.
length() == 0;
}
/**
* Is this field _definitely_ not writable?
*
* @return true if this field can not be written to in an INSERT/UPDATE
* statement.
*/
public boolean
isReadOnly() {
return this.
originalColumnName.
length() == 0 && this.
originalTableName.
length() == 0;
}
public boolean
isUniqueKey() {
return ((this.
colFlag &
MysqlType.
FIELD_FLAG_UNIQUE_KEY) > 0);
}
public boolean
isUnsigned() {
return ((this.
colFlag &
MysqlType.
FIELD_FLAG_UNSIGNED) > 0);
}
public boolean
isZeroFill() {
return ((this.
colFlag &
MysqlType.
FIELD_FLAG_ZEROFILL) > 0);
}
@
Override
public
String toString() {
try {
StringBuilder asString = new
StringBuilder();
asString.
append(super.toString());
asString.
append("[");
asString.
append("dbName=");
asString.
append(this.
getDatabaseName());
asString.
append(",tableName=");
asString.
append(this.
getTableName());
asString.
append(",originalTableName=");
asString.
append(this.
getOriginalTableName());
asString.
append(",columnName=");
asString.
append(this.
getName());
asString.
append(",originalColumnName=");
asString.
append(this.
getOriginalName());
asString.
append(",mysqlType=");
asString.
append(
getMysqlTypeId());
asString.
append("(");
MysqlType ft =
getMysqlType();
if (
ft.
equals(
MysqlType.
UNKNOWN)) {
asString.
append(" Unknown MySQL Type # ");
asString.
append(
getMysqlTypeId());
} else {
asString.
append("FIELD_TYPE_");
asString.
append(
ft.
getName());
}
asString.
append(")");
asString.
append(",sqlType=");
asString.
append(
ft.
getJdbcType());
asString.
append(",flags=");
if (
isAutoIncrement()) {
asString.
append(" AUTO_INCREMENT");
}
if (
isPrimaryKey()) {
asString.
append(" PRIMARY_KEY");
}
if (
isUniqueKey()) {
asString.
append(" UNIQUE_KEY");
}
if (
isBinary()) {
asString.
append(" BINARY");
}
if (
isBlob()) {
asString.
append(" BLOB");
}
if (
isMultipleKey()) {
asString.
append(" MULTI_KEY");
}
if (
isUnsigned()) {
asString.
append(" UNSIGNED");
}
if (
isZeroFill()) {
asString.
append(" ZEROFILL");
}
asString.
append(", charsetIndex=");
asString.
append(this.
collationIndex);
asString.
append(", charsetName=");
asString.
append(this.
encoding);
asString.
append("]");
return
asString.
toString();
} catch (
Throwable t) {
return super.toString() + "[<unable to generate contents>]";
}
}
public boolean
isSingleBit() {
return (this.
length <= 1);
}
public boolean
getValueNeedsQuoting() {
switch (this.
mysqlType) {
case
BIGINT:
case
BIGINT_UNSIGNED:
case
BIT:
case
DECIMAL:
case
DECIMAL_UNSIGNED:
case
DOUBLE:
case
DOUBLE_UNSIGNED:
case
INT:
case
INT_UNSIGNED:
case
MEDIUMINT:
case
MEDIUMINT_UNSIGNED:
case
FLOAT:
case
FLOAT_UNSIGNED:
case
SMALLINT:
case
SMALLINT_UNSIGNED:
case
TINYINT:
case
TINYINT_UNSIGNED:
return false;
default:
return true;
}
}
public int
getCollationIndex() {
return this.
collationIndex;
}
public
MysqlType getMysqlType() {
return this.
mysqlType;
}
public void
setMysqlType(
MysqlType mysqlType) {
this.
mysqlType =
mysqlType;
}
public short
getFlags() {
return this.
colFlag;
}
public void
setFlags(short
colFlag) {
this.
colFlag =
colFlag;
}
}