9

I have a table with a column of data type LONG RAW. How do I determine the size (in bytes) of the data in this column?

If I call the LENGTH function on it, it raises ORA-00932: inconsistent datatypes: expected NUMBER got LONG BINARY.

Just in case you think it: UTL_RAW.LENGTH raises ORA-00997: illegal use of LONG datatype :)

(Yes, I know LONG RAW is deprecated - the question came up due to some old software that might require it)

OMG Ponies
  • 325,700
  • 82
  • 523
  • 502
Jeffrey Kemp
  • 59,135
  • 14
  • 106
  • 158

3 Answers3

6

I don't think it's possible to manipulate LONG RAWs longer than 32k in PLSQL. Here is a java procedure that returns the length of a LONG RAW.

First, the setup:

SQL> CREATE TABLE my_table (ID NUMBER, my_long_raw_column LONG RAW);

Table created

SQL> INSERT INTO my_table VALUES (1, utl_raw.cast_to_raw('123456789'));

1 row inserted

The java class (my java is a bit rusty):

SQL> CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "Raw" AS
  2  import java.io.*;
  3  import java.sql.*;
  4  import oracle.jdbc.driver.*;
  5  
  6  public class Raw {
  7  
  8     public static int getLength(int pk) throws SQLException,IOException {
  9  
 10        Connection conn = new OracleDriver().defaultConnection();
 11  
 12        PreparedStatement ps = conn.prepareStatement
 13           ( "SELECT my_long_raw_column FROM my_table WHERE id = ?" );
 14        ps.setInt( 1, pk);
 15        ResultSet rs = ps.executeQuery();
 16  
 17        int len = 0;
 18        if (rs.next()) {
 19           InputStream is = rs.getBinaryStream(1);
 20           int nb = is.read(new byte[1024]);
 21           while (nb>0) {
 22              len += nb;
 23              nb = is.read(new byte[1024]);
 24           }
 25        } else
 26           len = -1;
 27  
 28        rs.close();
 29        ps.close();
 30
 31        return len;
 32     }
 33  }
 34  /

Java created

Let's call it:

SQL> CREATE OR REPLACE
  2  FUNCTION get_lr_length(p_id NUMBER) RETURN NUMBER
  3  AS LANGUAGE JAVA
  4  NAME 'Raw.getLength(int) return int';
  5  /

Function created

SQL> select get_lr_length(id) from my_table;

GET_LR_LENGTH(ID)
-----------------
                9

I've tested the function with larger than 32k fields and it seems to work.

JohnGom
  • 91
  • 4
Vincent Malgrat
  • 66,725
  • 9
  • 119
  • 171
2

As long as the data in the column does not exceed 16,383 bytes, you can solve this with a PL/SQL function, e.g.

CREATE OR REPLACE FUNCTION get_lr_length (id IN NUMBER)
  RETURN NUMBER IS
  raw_data LONG RAW;
  hex_data VARCHAR2(32767);
  len      NUMBER;
BEGIN
  SELECT my_long_raw_column INTO raw_data
  FROM my_table
  WHERE my_table.id = get_lr_length.id;
  hex_data := RAWTOHEX(raw_data);
  len := LENGTH(hex_data) / 2;
  RETURN len;
END get_lr_length;

Unfortunately, a LONG RAW can hold up to 2GB...

Jeffrey Kemp
  • 59,135
  • 14
  • 106
  • 158
  • You can use utl_raw.length on a PLSQL LONG RAW variable directly (since LONG RAW is synonym with RAW (32767) in PLSQL if I remember correctly). Consequently, you can measure a RAW up to 32767 bytes :) – Vincent Malgrat Mar 31 '11 at 11:52
  • Also from [this thread on Asktom](http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:201012348073), it seems that manipulating LONG RAW longer than 32k in PLSQL is not possible. You may need to write a java function to get the length of your raw. – Vincent Malgrat Mar 31 '11 at 11:56
  • @Vincent: do you not get `ORA-00997: illegal use of LONG datatype`? That's what I get when I call utl_raw.length on a LONG RAW (Oracle 11.2.0.1.0) – Jeffrey Kemp Apr 01 '11 at 01:45
  • 2
    not in PLSQL (since LONG RAW gets translated to RAW(32767)): this is my function `CREATE OR REPLACE FUNCTION get_lr_length (p_id IN NUMBER) RETURN NUMBER IS raw_data LONG RAW; BEGIN SELECT my_long_raw_column INTO raw_data FROM my_table WHERE my_table.id = p_id; RETURN utl_raw.length(raw_data); END;` – Vincent Malgrat Apr 01 '11 at 10:11
  • +1 Vincent - if you supplied that as an answer I'd give it another +1 - it's better than my solution. – Jeffrey Kemp Apr 04 '11 at 02:28
0

One dirty trick, which might help if you're playing with a small test database: copy all data in a table with a BLOB instead of a LONG RAW.

create table START(ID int not null, VAL long raw);
... inserts
create table START_BLOB(ID int not null, VAL blob);
insert into START_BLOB(ID,VAL) select ID,to_lob(VAL) from STAR;
select ID,length(VAL) from START_BLOB;
pascal
  • 3,287
  • 1
  • 17
  • 35