1
votes

I am doing a database copy Using Oracle SQL Developer, Tools>Database Copy...

From: Oracle Database 11g Release 11.1.0.6.0 - 64bit Production To: Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production

Single quotes in the old database interpreted with the Oracle ASCII() function return 146. Single quotes in the new copy return 14844057 from the Oracle ASCII() function Single quotes also crash PL/SQL if I try and put them into a Varchar2(1) variable.

What is causing this character translation?

I'm at a loss wether the character translation is a SQL Developer problem, Oracle Version problem, or some setting in Oracle that I don't know about.

1
As I explain in the answer, it's an "Oracle setting" (the database characterset for the first question, and the length semantics for the second). I removed the SQL Developer tag, since SQL Developer has nothing to do with this. It's also not an Oracle version problem. - mathguy

1 Answers

1
votes

Let's clarify what you mean by "single quotes". First, there is the basic, "straight" single-quote character ' (which is used both as an opening and a closing quote), part of the standard ASCII set, at position 39. Then, there are "calligraphic" left and right single-quote characters - which are represented in Unicode and other character sets (but are NOT part of the basic ASCII character set).

The ASCII() function, contrary to its name, has very little to do with ASCII, except that in the case of characters actually included in the ASCII set, the function returns their ASCII code. In general, the function returns the decimal representation of the character in the database encoding. Note that the Oracle documentation itself is wrong: it says "the representation in the character set", but in fact it's the encoded value, not the code point of the character. This makes a huge difference in Unicode. (The fact that ASCII() returns the ASCII code of ASCII characters is only due to the fact that in most if not all character encodings, the ASCII characters are given an encoding equal to their ASCII code. This is very convenient for compatibility, but it is not a theoretical requirement - it's just a practical matter.)

The right single-quote character is encoded at position 146 in the character set CP1252, which in Oracle is called WE8MSWIN1252. This, very likely, was the database character set in your old database.

The same character has the encoding 14844057 in the UTF-8 encoding of Unicode. Your database "character set" (really, encoding) is very likely AL32UTF8.

You will be able to find the database "character set" in both databases, and confirm what I said, with

select value from v$nls_parameters where parameter = 'NLS_CHARACTERSET';

You can talk to your DBA to confirm that the new database uses a different character set from the old.

As for the single quote character (really: right single-quote character, the one we are talking about), in Unicode it is a multi-byte character. If it is rejected by varchar2(1), this means that your character length semantics is BYTE rather than CHAR. Try varchar2(1 char) (making explicit the meaning of 1) instead. You can see an illustration at the end of this answer.

The same assignment may have worked OK in the old database, regardless of its length semantics, because in CP1252 the right single-quote character is encoded as single-byte.

So, here's the example. The character I am assigning is the right single-quote character, my database character encoding is AL32UTF8, and my NLS_LENGTH_SEMANTICS is BYTE.

Fails:

declare
  x varchar2(1);
begin
  x := '’';
end;
/


Error starting at line : 1 in command -
declare
  x varchar2(1);
begin
  x := '’';
end;
Error report -
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 4
06502. 00000 -  "PL/SQL: numeric or value error%s"
*Cause:    An arithmetic, numeric, string, conversion, or constraint error
           occurred. For example, this error occurs if an attempt is made to
           assign the value NULL to a variable declared NOT NULL, or if an
           attempt is made to assign an integer larger than 99 to a variable
           declared NUMBER(2).
*Action:   Change the data, how it is manipulated, or how it is declared so
           that values do not violate constraints.
           

Works:

declare
  x varchar2(1 char);
begin
  x := '’';
end;
/

PL/SQL procedure successfully completed.