Oracle Apex save pasted image into blob - oracle

I found the way here, how to copy a clipboard image to a region, ad it works well. But I didn't find how can I save this picture into my blob field. Which variable contains the image (maybe it is a javascript variable), and how can I refer to it in the SQL expression (e.g. in a dynamic action)?

create a process like this:
declare
doc_size integer;
Upload_blob blob;
begin
--Copy BLOB to Upload_blob variable
select blob_content into Upload_blob from APEX_APPLICATION_TEMP_FILES where name = :FILE_BROWSER;
--Get BLOB size
doc_size := dbms_lob.getlength(Upload_blob);
--Copy data to table MyIMAGES_TBL
if doc_size <= 1000000 then
insert into MyIMAGES_TBL ( IMAGE_NAME, FILENAME, MIME_TYPE, DOC_SIZE, CONTENT ) select :FILE_NAME, filename, mime_type, doc_size, blob_content from APEX_APPLICATION_TEMP_FILES where name = :FILE_BROWSER;
--Delete temp files delete from APEX_APPLICATION_TEMP_FILES where name = :FILE_BROWSER;
else delete from APEX_APPLICATION_TEMP_FILES where name = :FILE_BROWSER;
commit;
raise_application_error(-20001,'Cannot upload pictures bigger than 1MB!');
end if;
exception when others then raise_application_error(-20001,'Error when uploading image!');
end;

Related

Downloading files from the database server via APEX

I am trying to find a way to get files from the database server via APEX. I can't find any documentation about this issue.
Can I avoid using the plsql code?
PS: I'm launching APEX on tomcat on different server that db is.
As we talked on the comments, let me show you an example. I write you a lot of thing so take your time...
Upload file
You can have an object in Apex that allows the user to browse for a file to be uploaded. At the end, the user press a button that triggers the action . The button upload submits the page, and the action is after submit for the button itself. Any file upload is stored automatically in apex_application_temp_files ( keep in mind I removed a lot of controls I have regarding format of the file, size, etc ).
First create the directory
create or replace directory yourdirectory as '/your_path' ;
grant read, write on directory yourdirectory to your_user ;
The code in the button:
declare
v_error VARCHAR2(400);
v_filename VARCHAR2(400);
v_name VARCHAR2(400);
v_blob blob;
vodate number(8);
begin
SELECT filename,blob_content,name, to_number(regexp_replace(filename,'[0-9]{4}[0-9]{2}[0-9]{2}'))
INTO v_filename,v_blob,v_name,vodate
FROM apex_application_temp_files
WHERE name = :P2_FILE;
apex_debug.enable ( p_level => 5 );
apex_debug.message(p_message => 'v_filename is '||v_filename||' ', p_level => 5) ;
apex_debug.message(p_message => 'v_name is '||v_name||' ', p_level => 5) ;
apex_debug.message(p_message => 'vodate is '||to_number(substr(v_filename,14,8)) ||' ', p_level => 5) ;
-- insert into filesystem
p_write_blob_to_file(p_name=>v_name);
EXCEPTION
WHEN OTHERS THEN
raise;
end;
The important part here is the code p_write_blob_to_file. This is the code of that procedure, keeping in consideration that in my case p_dir takes a default value.
CREATE OR REPLACE procedure p_write_blob_to_file (p_name IN VARCHAR2, p_dir IN VARCHAR2 default 'your_directory' )
IS
l_blob BLOB;
l_blob_length INTEGER;
l_out_file UTL_FILE.file_type;
l_buffer RAW (32767);
l_chunk_size BINARY_INTEGER := 32767;
l_blob_position INTEGER := 1;
l_file_name varchar2(2000);
v_mime_type varchar2(2000);
BEGIN
-- Retrieve the BLOB for reading
SELECT blob_content, filename, mime_type
INTO l_blob, l_file_name, v_mime_type
FROM apex_application_temp_files
WHERE name = p_name;
-- Retrieve the SIZE of the BLOB
l_blob_length := DBMS_LOB.getlength (l_blob);
-- Open a handle to the location where you are going to write the BLOB
-- to file.
l_out_file :=
UTL_FILE.fopen (p_dir,
l_file_name,
'wb',
l_chunk_size);
-- Write the BLOB to file in chunks
WHILE l_blob_position <= l_blob_length
LOOP
IF l_blob_position + l_chunk_size - 1 > l_blob_length
THEN
l_chunk_size := l_blob_length - l_blob_position + 1;
END IF;
DBMS_LOB.read (l_blob,
l_chunk_size,
l_blob_position,
l_buffer);
UTL_FILE.put_raw (l_out_file, l_buffer, TRUE);
l_blob_position := l_blob_position + l_chunk_size;
END LOOP;
-- Close the file handle
UTL_FILE.fclose (l_out_file);
END p_write_blob_to_file;
/
Download File
In order to download the file, you need the opposite path.
The button or link download must be associated to a component PL/SQL
The button loads the file first from the directory in the server into a column
The button then download the file
I was going to write all the commands here , but you have a find very good example here of both actions:
Load file from directory into column
https://renaps.com/en/blog/how-to/how-to-load-file-content-to-a-blob-field-and-unload-blob-content-to-a-file-on-the-os
Download file
https://oracle-base.com/articles/misc/apex-tips-file-download-from-a-button-or-link#apex-button
Try to experiment with this and let me know any issues you might find. The only tricky thing here is that in Apex you need to pass the name of the file you want to download. So the user must know the name, exactly as it is in the server. What you can't do is provide a graphical interface to the server in order to select the file.

Oracle - Update BLOB with PL/SQL

I need to update a preexisting BLOB value in table using PL/SQL.
I'm dealing with poor table design, the column should be CLOB and that is not going to change.
The steps I want to perform:
1) select the BLOB
2) convert the BLOB to CLOB
3) modify the CLOB
3) convert the CLOB to BLOB
4) update the BLOB column with the new value
The 4th step I don't know how to do. I was hoping the BLOB could be updated directly but the only examples I find are reading a file into a blob column or using another programming language.
I understand your question, but i think there has to be another problem.
Solution
Just update it..
UPDATE myTable SET myBlobColumn = myBlob WHERE myCondition = 1;
Complete Example
DECLARE
myVarcharVar VARCHAR2(1000);
myClobVar CLOB;
myBlobVar BLOB;
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE TTEST'; -- ensure out testdata will be correct.
INSERT INTO TTEST (myBlob, myClob, myVarchar) VALUES(utl_raw.cast_to_raw('1111'), '2222', '3333'); -- insert our data
-- Attention: ONLY ONE ROW => NO WHERE-CONDITIONS to simplify the code!
SELECT myVarchar INTO myVarcharVar FROM TTEST;
UPDATE TTEST SET myClob = myVarcharVar;
SELECT myClob INTO myClobVar FROM TTEST;
UPDATE TTest SET myBlob = utl_raw.cast_to_raw(myClobVar);
SELECT myBlob, myClob, myVarchar INTO myBlobVar, myClobVar, myVarcharVar FROM TTest;
dbms_output.put_line('Blob: ' || utl_raw.cast_to_varchar2(myBlobVar));
dbms_output.put_line('Clob: ' || myClobVar);
dbms_output.put_line('Varchar:' || myVarcharVar);
END;
update table_name set column_name = utl_raw.cast_to_raw ('value') where id = 'your_id';

issue with apex_application_temp_files

I have a problem, in my ORACLE APEX app, I want to have file uploading mechanism that send uploaded .zip file as parameter to some function (that function works well, I tested it by manual feeding from DB). Problem is, when I try to select uploaded file from "apex_application_temp_files" in a process it throws exception "NO DATA FOUND", but when I add report to app where I select ID and FILENAMES I see that file...any idea why this is happen?
I am sorry if this is some trivial issue, but I am pretty new in APEX developing.
The process:
declare
l_blob blob;
begin
SELECT blob_content
INTO l_blob
FROM apex_application_temp_files
WHERE NAME = :P6_FILE;
--INSTANTLY SET :G_TEST_ID FOR REPORTS
:G_TEST_ID := file_management.unwrap_zip(ab_zipped_blob => l_blob);
end;
You need to select on column NAME instead of FILENAME. The former is the unique identifier (looks like series_of_numbers\the_filename) and is what the file browse item will contain, while the latter is without the prefix.
Look, you'll have to provide more information from your end. I've created a really simple page to try this (apex.oracle.com).
P2_FILE is a file-browse item.
Storage Type: Table APEX_APPLICATION_TEMP_FILES
Purge File at: End of Session
I've created an on-submit process which does nothing more than list some things in the debug output.
declare
l_blob blob;
begin
for r in (select * from apex_application_temp_files)
loop
apex_debug.message('name: %s - filename: %s', r.name, r.filename);
end loop;
apex_debug.message('P2_FILE: %s', :P2_FILE);
SELECT blob_content
INTO l_blob
FROM apex_application_temp_files
WHERE name = :P2_FILE;
apex_debug.message('blob length: %s', dbms_lob.getlength(l_blob));
end;
So I run the page, enable debug, select a file and hit submit. All works. Check the debug log (accept):
name: 39044609744029199463/README (2).md - filename: README (2).md
name: 39044529927808550681/README (1).md - filename: README (1).md
name: 39044569042020557797/README.md - filename: README.md
P2_FILE: 39044609744029199463/README (2).md
blob length: 1884
So: what's different at your end? Have you done as suggested by Jeffrey and run a debug of the page? What is your "purge" set as? Are you sure the no-data-found occurs on select of the blob and not in your procedure - have you commented out your procedure call yet?

Add images to Oracle Database

Hello I am trying to add images to table.
I made table:
CREATE TABLE program_images
(
image_id NUMBER,
image_filename VARCHAR2(50),
image BLOB
);
Then made directory where All images are:
Finaly made procedure, which insert images to table:
create or replace
PROCEDURE insert_image_file (p_id NUMBER, p_image_name IN VARCHAR2)
IS
src_file BFILE;
dst_file BLOB;
lgh_file BINARY_INTEGER;
BEGIN
src_file := BFILENAME ('image_DIR', p_image_name);
-- insert a NULL record to lock
INSERT INTO program_images
(image_id, image_filename, image
)
VALUES (p_id, p_image_name, EMPTY_BLOB ()
)
RETURNING image
INTO dst_file;
-- lock record
SELECT image
INTO dst_file
FROM program_images
WHERE image_id = p_id AND image_filename = p_image_name
FOR UPDATE;
-- open the file
DBMS_LOB.fileopen (src_file, DBMS_LOB.file_readonly);
-- determine length
lgh_file := DBMS_LOB.getlength (src_file);
-- read the file
DBMS_LOB.loadfromfile (dst_file, src_file, lgh_file);
-- update the blob field
UPDATE program_images
SET image = dst_file
WHERE image_id = p_id AND image_filename = p_image_name;
-- close file
DBMS_LOB.fileclose (src_file);
END insert_image_file;
Is that when I call procedure: EXECUTE insert_image_file(1,'audi_logo.png'); it says me that "non-existent directory or file for FILEOPEN operation" in procedure what is " DBMS_LOB.fileopen (src_file, DBMS_LOB.file_readonly);" this line.
It was first time I use directories, so maybe I forget something to do?
The image directory name should be all UPPER_CASE, i.e.
src_file := BFILENAME ('IMAGE_DIR', p_image_name);
Per the docs for BFILENAME:
The directory argument is case sensitive. You must ensure that you specify the
directory object name exactly as it exists in the data dictionary.

ROWTYPE AND FETCH COMMAND ERROR

Create or replace package body file as
procedure filehandler as
declare
V_PERSON PERSON%ROWTYPE;
FID UTL_FILE.FILE_TYPE;
FOLDER_NAME VARCHAR(50) := 'GID_FILE';
FILE_NAME VARCHAR(50) :='bhanu.txt';
cusor test_persondetails is
select personid, personnum,fullnm from person where rownum<=10;
begin
open test_persondetails;
FID := UTL_FILE.FOPEN (FOLDER_NAME, FILE_NAME, 'A');
fetch test_persondetails into V_person;
DBMS_OUTPUT.PUT_LINE(V_PERSON);
UTL_FILE.PUT_LINE (FID,V_PERSON);
UTL_FILE.FCLOSE (FID);
close test_persondetails;
end test_filehandler;
end test_file;
i am getting some errors related to the fetch statement , can you please suggest me the changes that can be done that code......
You need to tell us which errors you get, as looking at your source there are potentially many of them.
For instance your cursor will select up to ten rows. However you are not executing a loop, so your fetch will hurl TOO_MANY_ROWS if there is more than one row in the PERSON table.
Also, you need to explicitly reference the individual elements of the cursor not the %ROWTYPE variable.
Furthermore, the projection of the query must match the variable you fetch into (number of columns, datatype of columns, etc). It is easier to use the CURSOR FOR syntax, and let Oracle handle it for us. This also solves the TOO_MANY_ROWS problem.
So I would rewrite your code to look like this:
procedure filehandler as
FID UTL_FILE.FILE_TYPE;
FOLDER_NAME VARCHAR(50) := 'GID_FILE';
FILE_NAME VARCHAR(50) :='bhanu.txt';
begin
FID := UTL_FILE.FOPEN (FOLDER_NAME, FILE_NAME, 'A');
for V_PERSON in ( select personid, personnum,fullnm
from person where rownum<=10 )
loop
DBMS_OUTPUT.PUT_LINE(V_PERSON.personid);
UTL_FILE.PUT_LINE (FID,V_PERSON.personid
||' '||V_PERSON.personnum
||' '||V_PERSON.fullnm);
end loop;
UTL_FILE.FCLOSE (FID);
end test_filehandler;
Opening and closing the file for each line is not wrong, just slower than need be.
My guess is that the table contains more than the 3 columns you are selecting, and so trying to fetch those 3 columns into a record whose structure included all the columns of the table will fail. Change the record definition to:
V_PERSON test_persondetails%rowtype;
and move to to after the cursor definition.

Resources