📄 tds.java
字号:
case TDS_ORDER:
{
int len = comm.getTdsShort();
comm.skip(len);
result = new PacketColumnOrderResult();
break;
}
case TDS_CONTROL:
{
int len = comm.getTdsShort();
comm.skip(len);
// FIXME - I'm just ignoring this
result = new PacketControlResult();
break;
}
case TDS_ROW:
{
result = getRow(context);
break;
}
case TDS_COLMETADATA:
{
result = processTds7Result();
break;
}
default:
{
throw new TdsUnknownPacketSubType(packetSubType);
}
}
return result;
}
private void setCharset(String charset)
{
if (charset == null || charset.length() > 30)
charset = "iso_1";
if( charset.startsWith("cp") )
charset = "Cp" + charset.substring(2);
if (!charset.equals(this.charset)) {
encoder = EncodingHelper.getHelper(charset);
this.charset = charset;
}
}
/**
* Try to figure out what client name we should identify ourselves as. Get
* the hostname of this machine,
*
*@return name we will use as the client.
*/
private String getClientName()
{
// This method is thread safe.
String tmp;
try {
tmp = java.net.InetAddress.getLocalHost().getHostName();
}
catch (java.net.UnknownHostException e) {
tmp = "";
}
StringTokenizer st = new StringTokenizer(tmp, ".");
if (!st.hasMoreTokens()) {
// This means hostname wasn't found for this machine.
return "JOHNDOE";
}
// Look at the first (and possibly only) word in the name.
tmp = st.nextToken();
if (tmp.length() == 0) {
// This means the hostname had no leading component.
// (This case would be strange.)
return "JANEDOE";
}
else if (Character.isDigit(tmp.charAt(0))) {
// This probably means that the name was a quad-decimal
// number. We don't want to send that as our name,
// so make one up.
return "BABYDOE";
}
else {
// Ah, Life is good. We have a name. All other
// applications I've seen have upper case client names,
// and so shall we.
return tmp.toUpperCase();
}
}
/**
* Get the length of the current subpacket. <p>
*
* This will eat two bytes from the input socket.
*
*@return length of the current
* subpacket.
*@exception java.io.IOException Description of
* Exception
*@exception net.sourceforge.jtds.jdbc.TdsException Description of
* Exception
*/
private int getSubPacketLength()
throws java.io.IOException, net.sourceforge.jtds.jdbc.TdsException
{
return comm.getTdsShort();
}
/**
* determine if a given datatype is a fixed size
*
*@param nativeColumnType The SQLServer datatype
* to check
*@return <code>true</code> if
* the datatype is a fixed size, <code>false</code> if the datatype is
* a variable size
*@exception net.sourceforge.jtds.jdbc.TdsException If the <code>
* nativeColumnType</code> is not a knowm datatype.
*/
private boolean isFixedSizeColumn(byte nativeColumnType)
throws net.sourceforge.jtds.jdbc.TdsException
{
switch (nativeColumnType) {
case SYBINT1:
case SYBINT2:
case SYBINT4:
case SYBFLT8:
case SYBDATETIME:
case SYBBIT:
case SYBMONEY:
case SYBMONEY4:
case SYBSMALLMONEY:
case SYBREAL:
case SYBDATETIME4:
{
return true;
}
case SYBINTN:
case SYBMONEYN:
case SYBVARCHAR:
case SYBNVARCHAR:
case SYBDATETIMN:
case SYBFLTN:
case SYBCHAR:
case SYBNCHAR:
case SYBNTEXT:
case SYBIMAGE:
case SYBVARBINARY:
case SYBBINARY:
case SYBDECIMAL:
case SYBNUMERIC:
case SYBBITN:
case SYBUNIQUEID:
{
return false;
}
default:
{
throw new TdsException("Unrecognized column type 0x"
+ Integer.toHexString(nativeColumnType));
}
}
}
private Object getMoneyValue(
int type)
throws java.io.IOException, TdsException
{
int len;
Object result;
switch( type )
{
case SYBSMALLMONEY:
case SYBMONEY4:
len = 4;
break;
case SYBMONEY:
len = 8;
break;
case SYBMONEYN:
len = comm.getByte();
break;
default:
throw new TdsException("Not a money value.");
}
if (len == 0) {
result = null;
}
else {
BigInteger x = null;
if (len == 4) {
x = BigInteger.valueOf(comm.getTdsInt());
}
else if (len == 8) {
byte b4 = comm.getByte();
byte b5 = comm.getByte();
byte b6 = comm.getByte();
byte b7 = comm.getByte();
byte b0 = comm.getByte();
byte b1 = comm.getByte();
byte b2 = comm.getByte();
byte b3 = comm.getByte();
long l =
(long) (b0 & 0xff) + ((long) (b1 & 0xff) << 8) +
((long) (b2 & 0xff) << 16) + ((long) (b3 & 0xff) << 24) +
((long) (b4 & 0xff) << 32) + ((long) (b5 & 0xff) << 40) +
((long) (b6 & 0xff) << 48) + ((long) (b7 & 0xff) << 56);
x = BigInteger.valueOf(l);
}
else {
throw new TdsConfused("Don't know what to do with len of "
+ len);
}
x = x.divide(BigInteger.valueOf(100));
result = new BigDecimal(x, 2);
}
return result;
}
// getMoneyValue
/**
* Extracts decimal value from the server's results packet. Takes advantage
* of Java's superb handling of large numbers, which does all the heavy
* lifting for us. Format is:
* <UL>
* <LI> Length byte <code>len</code> ; count includes sign byte.</LI>
*
* <LI> Sign byte (0=negative; 1=positive).</LI>
* <LI> Magnitude bytes (array of <code>len</code> - 1 bytes, in
* little-endian order.</LI>
* </UL>
*
*
*@param scale number of decimal digits after the
* decimal point.
*@return <code>BigDecimal</code> for extracted
* value (or ( <code>null</code> if appropriate).
*@exception TdsException Description of Exception
*@exception java.io.IOException Description of Exception
*@exception NumberFormatException Description of Exception
*/
private Object getDecimalValue(int scale)
throws TdsException, java.io.IOException, NumberFormatException
{
int len = comm.getByte() & 0xff;
if (--len < 1) {
return null;
}
// RMK 2000-06-10. Deduced from some testing/packet sniffing.
byte[] bytes = new byte[len];
int signum = comm.getByte() == 0 ? -1 : 1;
while (len > 0) {
bytes[--len] = comm.getByte();
}
BigInteger bigInt = new BigInteger(signum, bytes);
return new BigDecimal(bigInt, scale);
}
private Object getDatetimeValue(
int type)
throws java.io.IOException, TdsException
{
// Some useful constants
final long SECONDS_PER_DAY = 24L * 60L * 60L;
final long DAYS_BETWEEN_1900_AND_1970 = 25567L;
int len;
Object result;
if (type == SYBDATETIMN) {
len = comm.getByte();
}
else if (type == SYBDATETIME4) {
len = 4;
}
else {
len = 8;
// XXX shouldn't this be an error?
}
switch (len) {
case 0:
{
result = null;
break;
}
case 8:
{
// It appears that a datetime is made of of 2 32bit ints
// The first one is the number of days since 1900
// The second integer is the number of seconds*300
// The reason the calculations below are sliced up into
// such small baby steps is to avoid a bug in JDK1.2.2's
// runtime, which got confused by the original complexity.
long tdsDays = (long) comm.getTdsInt();
long tdsTime = (long) comm.getTdsInt();
long sqlDays = tdsDays - DAYS_BETWEEN_1900_AND_1970;
long seconds = sqlDays * SECONDS_PER_DAY + tdsTime / 300L;
long micros = ((tdsTime % 300L) * 1000000L) / 300L;
long millis = seconds * 1000L + micros / 1000L - zoneOffset;
// Round up if appropriate.
if (micros % 1000L >= 500L) {
millis++;
}
result = new Timestamp(millis - getDstOffset(millis));
break;
}
case 4:
{
// Accroding to Transact SQL Reference
// a smalldatetime is two small integers.
// The first is the number of days past January 1, 1900,
// the second smallint is the number of minutes past
// midnight.
long tdsDays = (long) comm.getTdsShort();
long minutes = (long) comm.getTdsShort();
long sqlDays = tdsDays - DAYS_BETWEEN_1900_AND_1970;
long seconds = sqlDays * SECONDS_PER_DAY + minutes * 60L;
long millis = seconds * 1000L - zoneOffset;
result = new Timestamp(millis - getDstOffset(millis));
break;
}
default:
{
result = null;
throw new TdsNotImplemented("Don't now how to handle "
+ "date with size of "
+ len);
}
}
return result;
}
// getDatetimeValue()
/**
* Determines the number of milliseconds needed to adjust for daylight
* savings time for a given date/time value. Note that there is a problem
* with the way SQL Server sends a DATETIME value, since it is constructed
* to represent the local time for the server. This means that each fall
* there is a window of approximately one hour during which a single value
* can represent two different times.
*
* @param time Description of Parameter
* @return The DstOffset value
* @todo SAfe Try to find a better way to do this, because it doubles the time it takes to process datetime values!!!
*/
private long getDstOffset(long time)
{
Calendar cal = Calendar.getInstance();
cal.setTime(new java.util.Date(time));
return cal.get(Calendar.DST_OFFSET);
}
private Object getIntValue(int type)
throws java.io.IOException, TdsException
{
Obje
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -