All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.foundationdb.sql.jdbc.core.Utils Maven / Gradle / Ivy

/*-------------------------------------------------------------------------
*
* Copyright (c) 2004-2011, PostgreSQL Global Development Group
* Copyright (c) 2004, Open Cloud Limited.
*
*
*-------------------------------------------------------------------------
*/

package com.foundationdb.sql.jdbc.core;

import java.sql.SQLException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;

import com.foundationdb.sql.jdbc.util.GT;
import com.foundationdb.sql.jdbc.util.PSQLException;
import com.foundationdb.sql.jdbc.util.PSQLState;

/**
 * Collection of utilities used by the protocol-level code.
 */
public class Utils {
    /**
     * Turn a bytearray into a printable form, representing
     * each byte in hex.
     *
     * @param data the bytearray to stringize
     * @return a hex-encoded printable representation of data
     */
    public static String toHexString(byte[] data) {
        StringBuffer sb = new StringBuffer(data.length * 2);
        for (int i = 0; i < data.length; ++i)
        {
            sb.append(Integer.toHexString((data[i] >> 4) & 15));
            sb.append(Integer.toHexString(data[i] & 15));
        }
        return sb.toString();
    }

    /**
     * Keep a local copy of the UTF-8 Charset so we can avoid
     * synchronization overhead from looking up the Charset by
     * name as String.getBytes(String) requires.
     */
    private final static Charset utf8Charset = Charset.forName("UTF-8");

    /**
     * Encode a string as UTF-8.
     *
     * @param str the string to encode
     * @return the UTF-8 representation of str
     */
    public static byte[] encodeUTF8(String str) {
        // Previously we just used str.getBytes("UTF-8"), but when
        // the JVM is using more than one encoding the lookup cost
        // makes that a loser to the below (even in the single thread case).
        // When multiple threads are doing Charset lookups, they all get
        // blocked and must wait, severely dropping throughput.
        //
        ByteBuffer buf = utf8Charset.encode(CharBuffer.wrap(str));
        byte b[] = new byte[buf.limit()];
        buf.get(b, 0, buf.limit());
        return b;
    }

    /**
     * Escape the given literal value and append it to the string buffer
     * sbuf. If sbuf is null, a new StringBuffer will be
     * returned. The argument standardConformingStrings defines whether the
     * backend expects standard-conforming string literals or allows backslash
     * escape sequences.
     * 
     * @param sbuf the string buffer to append to; or null
     * @param value the string value
     * @param standardConformingStrings
     * @return the sbuf argument; or a new string buffer for sbuf == null
     * @throws SQLException if the string contains a \0 character
     */
    public static StringBuffer appendEscapedLiteral(StringBuffer sbuf, String value,
                                                   boolean standardConformingStrings)
                                                   throws SQLException {
        if (sbuf == null)
            sbuf = new StringBuffer(value.length() * 11 / 10); // Add 10% for escaping.
        
        if (standardConformingStrings)
        {
            // With standard_conforming_strings on, escape only single-quotes.
            for (int i = 0; i < value.length(); ++i)
            {
                char ch = value.charAt(i);
                if (ch == '\0')
                    throw new PSQLException(GT.tr("Zero bytes may not occur in string parameters."), PSQLState.INVALID_PARAMETER_VALUE);
                if (ch == '\'')
                    sbuf.append('\'');
                sbuf.append(ch);
            }
        }
        else
        {
            // With standard_conforming_string off, escape backslashes and
            // single-quotes, but still escape single-quotes by doubling, to
            // avoid a security hazard if the reported value of
            // standard_conforming_strings is incorrect, or an error if
            // backslash_quote is off.
            for (int i = 0; i < value.length(); ++i)
            {
                char ch = value.charAt(i);
                if (ch == '\0')
                    throw new PSQLException(GT.tr("Zero bytes may not occur in string parameters."), PSQLState.INVALID_PARAMETER_VALUE);
                if (ch == '\\' || ch == '\'')
                    sbuf.append(ch);
                sbuf.append(ch);
            }
        }
        
        return sbuf;
    }

    /**
     * Escape the given identifier value and append it to the string
     * buffer * sbuf. If sbuf is null, a new
     * StringBuffer will be returned.  This method is different from
     * appendEscapedLiteral in that it includes the quoting required for the
     * identifier while appendEscapedLiteral does not.
     * 
     * @param sbuf the string buffer to append to; or null
     * @param value the string value
     * @return the sbuf argument; or a new string buffer for sbuf == null
     * @throws SQLException if the string contains a \0 character
     */
    public static StringBuffer appendEscapedIdentifier(StringBuffer sbuf, String value)
                                                   throws SQLException {
        if (sbuf == null)
            sbuf = new StringBuffer(2 + value.length() * 11 / 10); // Add 10% for escaping.

        sbuf.append('"');

        for (int i = 0; i < value.length(); ++i)
        {
            char ch = value.charAt(i);
            if (ch == '\0')
                throw new PSQLException(GT.tr("Zero bytes may not occur in identifiers."), PSQLState.INVALID_PARAMETER_VALUE);
            if (ch == '"')
                sbuf.append(ch);
            sbuf.append(ch);
        }

        sbuf.append('"');

        return sbuf;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy