Hi, everybody.
I am new to PL/SQL and Oracle Databases.
I need to read/write file that exists on server so i'm using utl_file.fopen('/home/tmp/','text.txt','R') but Oracle shows error 'invalid directory path'.
Main problem is that i have only user privileges, so i cant use commands like create directory user_dir as '/home/temp/' or view utl_file_dir with just show parameter utl_file_dir;
I used this code to view utl_file_dir:
SQL> set serveroutput on;
SQL> Declare
2 Intval number;
3 Strval varchar2 (500);
4 Begin
5 If (dbms_utility.get_parameter_value('utl_file_dir', intval,strval)=0)
6 Then dbms_output.put_line('value ='||intval);
7 Else dbms_output.put_line('value = '||strval);
8 End if;
9 End;
10 /
and output was 'value = 0'.
I google'd much but didnt find any solution of this problem, so i'm asking help here.
To read file i used this code:
declare
f utl_file.file_type;
s varchar2(200);
begin
f := utl_file.fopen('/home/tmp/','text.txt','R');
loop
utl_file.get_line(f,s);
dbms_output.put_line(s);
end loop;
exception
when NO_DATA_FOUND then
utl_file.fclose(f);
end;
If you do not have permission to create the directory object (and assuming that the directory object does not already exist), you'll need to send a request to your DBA (or someone else that has the appropriate privileges) in order to create a directory for you and to grant you access to that directory.
utl_file_dir is an obsolete parameter that is much less flexible than directory objects and requires a reboot of the database to change-- unless you're using Oracle 8.1.x or you are dealing with a legacy process that was written back in the 8.1.x days and hasn't been updated to use directories, you ought to ignore it.
Related
I have a db function that populates data from active directory into a table in the database. It works fine without giving any errors.
Next step is to schedule a job in db so that it is run everyday automatically. When I do that, I get this error: ORA-01008: not all variables are mapped
The code I am using in the PL/SQL block is this:
DECLARE
v_Return VARCHAR2(200);
BEGIN
v_Return := PRE_JOB_FUNCTION();
:v_Return := v_Return;
END;
I think that the issue is that v_Return needs to be Null to begin the execution of this function but I am confused how to do that. Can someone please help?
I have executed a block of code which generates a simple text file using utl_file package
with a word 'test' and outputs the file to the location in server.
When i run the procedure it compiles successfully but the file is not
generated in the path.
set serveroutput on
declare
l_file utl_file.file_type;
l_dir varchar2(500):='WMS_IFILEOUT';
l_file_name varchar2(500):='test.txt';
begin
l_file :=utl_file.fopen(l_dir,l_file_name,'w',32767);
utl_file.put_line(l_file,'test123');
utl_file.fclose(l_file);
end;
The path and directory are available in the dba_directories
and read and write privileges are available on it.
I noticed that when i print
show parameter utl_file
then no values are displayed alongside to it.
Do I have to set this parameter in order to generate the files in the server path.
If so, can you please tell how to set it.
Thanks
I tried code you posted; the only modification was to rename directory).
SQL> DECLARE
2 l_file UTL_FILE.file_type;
3 l_dir VARCHAR2 (500) := 'DPDIR';
4 l_file_name VARCHAR2 (500) := 'test.txt';
5 BEGIN
6 l_file :=
7 UTL_FILE.fopen (l_dir,
8 l_file_name,
9 'w',
10 32767);
11 UTL_FILE.put_line (l_file, 'test123');
12 UTL_FILE.fclose (l_file);
13 END;
14 /
PL/SQL procedure successfully completed.
SQL>
Result: file is here:
So ... no, there's nothing else you should do. Everything you wrote seems to be just fine (from my point of view).
You said something about "show parameter utl_file" - what is that, exactly? UTL_FILE is a package, and you have to have EXECUTE privilege on it. You already have it, otherwise procedure wouldn't work at all.
I created a new superuser just so that this user can run COPY command.
Note that a non-superuser cannot run a copy command.
I need this user due to a backup application, and that application requires to run COPY command
But all the restrictions that I specified does not take effect (see below).
What is the difference between user postgres and a superuser?
And is there a better way to achieve what I want? I looked into a function with security definer as postgres ... that seems a lot of work for multiple tables.
DROP ROLE IF EXISTS mynewuser;
CREATE ROLE mynewuser PASSWORD 'somepassword' SUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT LOGIN;
-- ISSUE: the user can still CREATEDB, CREATEROLE
REVOKE UPDATE,DELETE,TRUNCATE ON ALL TABLES IN SCHEMA public, schema1, schema2, schema3 FROM mynewuser;
-- ISSUE: the user can still UPDATE, DELETE, TRUNCATE
REVOKE CREATE ON DATABASE ip2_sync_master FROM mynewuser;
-- ISSUE: the user can still create table;
You are describing a situation where a user can write files to the server where the database runs but is not a superuser. While not impossible, it's definitely abnormal. I would be very selective about who I allow to access my DB server.
That said, if this is the situation, I'd create a function to load the table (using copy), owned by the postgres user and grant the user rights to execute the function. You can pass the filename as a parameter.
If you want to get fancy, you can create a table of users and tables to define what users can upload to what tables and have the table name as a parameter also.
It's pretty outside of the norm, but it's an idea.
Here's a basic example:
CREATE OR REPLACE FUNCTION load_table(TABLENAME text, FILENAME text)
RETURNS character varying AS
$BODY$
DECLARE
can_upload integer;
BEGIN
select count (*)
into can_upload
from upload_permissions p
where p.user_name = current_user and p.table_name = TABLENAME;
if can_upload = 0 then
return 'Permission denied';
end if;
execute 'copy ' || TABLENAME ||
' from ''' || FILENAME || '''' ||
' csv';
return '';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
COPY with option other than writing to STDOUT and reading from STDIN is only allowed for database superusers role since it allows reading or writing any file that the server has privileges to access.
\copy is a psql client command which serves the same functionality as COPY but is not server-sided, so only local files can be processed - meaning it invokes COPY but ... FROM STDIN / ... TO STDOUT, so that files on a server are not "touched".
You can not revoke specific rights from a superuser. I'm quoting docs on this one:
Docs: Access DB
Being a superuser means that you are not subject to access controls.
Docs: CREATE ROLE
"superuser", who can override all access restrictions within the database. Superuser status is dangerous and should be used only when really needed.
I have used the following code to copy the text from a file to a CLOB. However it is giving me a PL/SQL numeric or value error at the position where writeappend is performed.
declare
l_fhandle utl_file.file_type;
l_clob CLOB;
l_buffer VARCHAR2(4096);
BEGIN
l_fhandle := utl_file.fopen('/data',
'FILE.TXT',
'R');
dbms_lob.createtemporary(l_clob, TRUE, DBMS_LOB.CALL);
LOOP
BEGIN
utl_file.get_line(L_FHANDLE, l_buffer);
dbms_output.put_line(l_buffer);
dbms_lob.writeappend(l_clob, length(l_buffer), l_buffer);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('Inside No data found');
INSERT INTO TAB_CLOB_FILE
(FILENAME, BODYCONT)
VALUES
('FILE', l_clob);
dbms_output.put_line('Inserted data into table');
EXIT;
END;
END LOOP;
END;
Please help me figure out what is wrong
Your problem is most likely here:
utl_file.fopen('/data', 'FILE.TXT','R');
The fist parameter is the name of an oracle directory OBJECT, not a physical path to a directory. From the Oracle docs, "Directory location of file. This string is a directory object name and is case sensitive. The default is uppercase. Read privileges must be granted on this directory object for the UTL_FILE user to run FOPEN." The incorrect call should have thrown an exception though.
You need to first create a directory object such as:
create directory MY_DIR as '/data';
Then change the fopen call to: utl_file.fopen('MY_DIR', 'FILE.TXT','R');
You can read about directory objects here.
Okay so basically I've been working on my computing project for a while now and I've got 90% of it working however I'm having a problem with Delphi where is says that my database is not connected/ there is a problem connecting however I've already tried writing the information to the screen and this showed me that the items I was looking to pick up where in fact being picked up so the failure is when the items are being input in to the database. This however shouldn't be happening as the System already has database information displayed from that table and the user can physically select things from the database tables within the program however when trying to store the information back into the database it just breaks. Me and my computing teacher can not work it out, any help would be appreciated.
The problem appears on the new orders page. If you'd rather look at the system then you can download it from here https://drive.google.com/folderview?id=0B_iRfwwM9QpHVXJnSkx4U1FjMlk&usp=sharing
procedure Tform1.btnSaveClick(Sender: TObject);
var orderID:integer;
count:integer;
begin
try
//save into the order table first
tblOrder.Open;
tblOrder.Insert;
tblOrder.FieldByName('CustomerID').value:= strtoint(cboCustomer.Text);
tblOrder.Close;
tblOrder.Open;
tblOrder.Last;
orderID:=tblOrder.FieldByName('OrderID').Value;
showmessage(inttostr(orderID));
for count := 1 to nextFree-1 do
begin
if itemOrdered[count,1]<>0 then
begin
tblOrderLine.Open;
tblOrderLine.AppendRecord([orderID, itemOrdered[count,1],itemOrdered[count,2]]);
end;
end;
showmessage('The order has been saved');
except
showmessage('There was a problem connecting to the database');
end;
end;
You're doing far too much open, do something, close, open. Don't do that, because it's almost certain that is the cause of your problem. If the data is already being displayed, the database is open already. If you want it to keep being displayed, the database has to remain open.
I also removed your try..except. You can put it back in if you'd like; I personally like to allow the exception to occur so that I can find out why the database operation failed from the exception message, rather than hide it and have no clue what caused it not to work.
procedure Tform1.btnSaveClick(Sender: TObject);
var
orderID: integer;
count: integer;
begin
//save into the order table first
tblOrder.Insert;
tblOrder.FieldByName('CustomerID').value:= strtoint(cboCustomer.Text);
tblOrder.Post;
orderID:=tblOrder.FieldByName('OrderID').Value;
showmessage(inttostr(orderID));
for count := 1 to nextFree-1 do
begin
if itemOrdered[count, 1] <> 0 then
begin
tblOrderLine.AppendRecord([orderID, itemOrdered[count,1],itemOrdered[count,2]]);
tblOrderLine.Post;
end;
end;
showmessage('The order has been saved');
end;