I was trying to load data in to db on application startup.
With H2 I was using the below query and it worked perfectly. With Oracle it doesn't work. Can someone point me the right direction? I went through oracle documentation but didn't manage to find an equivalent.
INSERT INTO TEMPLATES(ID,NAME,BODY) VALUES('2b04469f31c445ca82c354322845b52b', 'Records', FILE_READ('/opt/bin/Records.txt'));
Oracle SQL has no equivalent of a file_read() function. However, it is possible to write your own.
However, before we start you need to known that Oracle is much more locked down when it comes to database interoperability with the OS. Many things are not enabled by default, and consequently you may require assistance from a friendly DBA to get this working.
For instance, we cannot use OS filepaths directly (at least in more recent versions) so we need to create a DIRECTORY object. Normally the privilege to do this is restricted to DBAs.
create directory opt_bin as '/opt/bin';
grant read on directory opt_bin to <<your_user>>;
Note that /opt/bin must be a directory to which the database has access. On a *nix environment that means the oracle OS user has at least read on the directory.
With that infrastructure in place we can create a function which loads an OS file into a blob. It uses the directory and file name to instantiate a BFILE then applies DBMS_LOB capability to load that BFILE into a BLOB.
create or replace file_to_blob
(p_dir in varchar2, p_file in varchar2)
return blob
is
bf bfile;
tmp_blob blob := empty_blob();
l_dest_offset pls_integer := 1;
l_src_offset pls_integer := 1;
begin
bf := bfilename(p_dir, b_file);
dbms_lob.createtemporary(tmp_blob, true);
dbms_open(bf, dbms_lob.file_readonly);
dbms_lob.loadblobfromfile(tmp_blob, bf, dbms_lob.lobmaxsize, l_dest_offset, l_src_offset);
dbms_lob.close(bf);
return tmp_blob;
end;
/
You can use this function in your insert statement like this:
INSERT INTO TEMPLATES(ID,NAME,BODY)
VALUES
('2b04469f31c445ca82c354322845b52b', 'Records', file_to_blob('opt_bin', 'Records.txt'));
Related
We have a function that turns sql query into xml and in shared components we have a xsl-fo stylesheet. With both combined we want to generate PDF's and save them into the Database.
Now we tried to use the Print API's (APEX_UTIL.GET_PRINT_DOCUMENT) but the PDF's are damaged and return a 401 Error (Unathorized).
We are using Apex 19.1 and as print option ORDS.Ive read somewhere that you cant use those tho because with ORDS the PDF is only returned to the client.
Since im pretty new to this whole PDF printing subject:
Is there a way to still save the PDF into the Database? Or is this a feature that only comes with the paid solutions? Are there any necessary settings we have to configure with REST?
You can save the PDF if you can convert it into BLOB, but APEX by itself cannot give you that functionality.
You are right about this "Ive read somewhere that you cant use those tho because with ORDS the PDF is only returned to the client."
For example I created a report in Jasper Server Community and save it into the database using PLSQL
declare
l_url VARCHAR2(3000) := '//apexdevtesting.com:8081/jasperserver/rest_v2/reports/reports/Blank_Letter.pdf?STATUS=';
l_request SYS.utl_http.req;
l_response SYS.utl_http.resp;
l_download RAW(32767);
l_file BLOB;
l_mimetype VARCHAR2(50) := 'application/pdf';
l_charset VARCHAR2(50) := 'UTF8';
l_filename varchar2(50) := 'archivo_'||ARCHIVOS_CARGADOS_SEQ.nextval||'.pdf';
begin
l_request := SYS.utl_http.begin_request(l_url ||'ASSIGNED&'||'j_username=jasperadmin'||'&'||'j_password=jasperadmin' );
SYS.utl_http.set_header(l_request, 'User-Agent', 'Mozilla/5.0 (Windows NT x.y; Win64; x64; rv:10.0) Gecko/20100101 Firefox/10.0');
l_response := SYS.utl_http.get_response(l_request);
dbms_lob.createtemporary(l_file, TRUE, dbms_lob.SESSION);
LOOP
BEGIN
SYS.utl_http.read_raw(l_response, l_download);
dbms_lob.writeappend(l_file, utl_raw.LENGTH(l_download), l_download);
INSERT INTO j_test2
VALUES (SYS_GUID(),
SYSTIMESTAMP,
l_file,
l_mimetype,
l_filename);
EXCEPTION WHEN SYS.utl_http.end_of_body THEN
EXIT;
END;
END LOOP;
SYS.utl_http.end_response(l_response);
commit;
end;
So I have this trigger procedure in my structure.sql:
CREATE FUNCTION dead_filter() RETURNS TRIGGER AS $dead_filter$
BEGIN
IF (NEW.all_votes > 6 AND NEW.non_skip_votes/NEW.all_votes::float < 0.56) THEN
NEW.dead := true;
RETURN NEW;
END IF;
RETURN NEW;
END;
$dead_filter$ LANGUAGE plpgsql;
CREATE TRIGGER dead_filter AFTER UPDATE ON statements
FOR EACH ROW
EXECUTE PROCEDURE dead_filter();
And it works locally just fine, but for some reason it is showing up in my staging and production servers!
Both live on a heroku app, and both have
config.active_record.schema_format = :sql
in their relevant config files. What am I missing here?
select * from pg_trigger;
doesn't include my trigger on staging/production, but DOES locally, on development.
Is there something I need to run to have the structure.sql file re-read? Backend is definitely my weak spot, so if there's something super obvious I should've known to do...odds are I didn't know to do it!
Thanks!
As in a comment, you need to create a migration that adds a trigger and run this migration on production as it is not automatic on Heroku. Also please note that structure.sql file will be regenerated after running migrations locally or task such as rake db:schema:dump. So you shouldn't edit this file manually.
I would like to write/read a simple text file using dwscript.
My code is here below... but I am non able to get it run, please someone might help...:
(I am using the Simple.exe in the Demos folder of DWS installation)
// uses Classes;
{$INCLUDE_ONCE 'c:/.../System.Classes.pas'}
var
s: TFileStream;
o: string; // out
i: integer;
f: word; // flag
f := fmOpenReadWrite;
if not FileExists('C:\Temp\Junkfile.txt') then
f := f or fmCreate;
s := TFileStream.Create('C:\Temp\Junkfile.txt', f);
try
s.Position := s.Size; // will be 0 if file created, end of text if not
for i := 1 to 10 do begin
o := Format('This is test line %d'#13#10, [i]);
s.Write(o[1], Length(o) * SizeOf(Char));
end;
finally
s.Free;
end;
By default the script engine keeps everything sand-boxed and nothing that gives access outside the sandbox is exposed. So if you want to give access to arbitrary files to script you need to expose functions & classes to achieve it (through TdwsUnit f.i.).
Also it won't compile the Delphi classes unit, DWScript is not meant to be an alternative to the Delphi compiler, but to offer scripting support, ie. allow end users to run code in a way over which you have full control over what they can do, and that can't crash or corrupt the host application (that last point being the key differentiation with the other notable Pascal scripting engines).
You can use dwsFileFunctions to get basic file I/O support, in which case an equivalent to the file creation portion of your code would be something like
var f := FileCreate('C:\Temp\Junkfile.txt');
for var i := 1 to 10 do
FileWrite(f, Format('This is test line %d'#13#10, [i]));
FileClose(f);
I have a Delphi 6 application that uses an ODBC DSN to connect to target databases. I want to include text that lists the name of the Database the DSN is connected to. I tried using the SQL command db_name() but only received a nil in response despite having it work when I log into the SQL server.
Is there a way within Delphi to identify which Database I'm connected to? I can pull up the sys.databases table, but am not certain how to identify which database is the one I'm connected to
As an Example:
if I am connecting to the dsn LocalDSN I want to be able to display to the user that they are connected to Database, where database is the name of the sql database they are communicating with.
The ODBC DSN is stored in the Windows Registry. Keep in mind that the Windows Registry, and therefore the ODBC DSN settings, are separated between 32 and 64 bit versions. You can access this information through HKEY_LOCAL_MACHINE\Software\ODBC\ODBC.INI\[YOUR_DSN_NAME] and then read the value Database or Server to know the database or server name.
You can read the server and database name with these functions:
uses
Registry;
function ServerOfDSN(const Name: String): String;
var
R: TRegistry;
K: String;
begin
K:= 'Software\ODBC\ODBC.INI\'+Name;
R:= TRegistry.Create(KEY_READ);
try
R.RootKey:= HKEY_LOCAL_MACHINE;
if R.KeyExists(K) then begin
if R.OpenKey(K, False) then begin
if R.ValueExists('Server') then
Result:= R.ReadString('Server');
R.CloseKey;
end;
end;
finally
R.Free;
end;
end;
function DatabaseOfDSN(const Name: String): String;
var
R: TRegistry;
K: String;
begin
K:= 'Software\ODBC\ODBC.INI\'+Name;
R:= TRegistry.Create(KEY_READ);
try
R.RootKey:= HKEY_LOCAL_MACHINE;
if R.KeyExists(K) then begin
if R.OpenKey(K, False) then begin
if R.ValueExists('Database') then
Result:= R.ReadString('Database');
R.CloseKey;
end;
end;
finally
R.Free;
end;
end;
Depending on what database engine and drivers you're using, the contents of this registry key may be different, and therefore there's a possibility that Server or Database might not be the registry value you need, but inspect it yourself and find your value names in the registry to know how to read it.
You can use SQLGetPrivateProfileString ODBC API to get the contents of DSN created.
int SQLGetPrivateProfileString(
LPCSTR lpszSection,
LPCSTR lpszEntry,
LPCSTR lpszDefault,
LPCSTR RetBuffer,
INT cbRetBuffer,
LPCSTR lpszFilename);
Here,
lpszSection = registry section you want details for. it will be DSN name in your case.
lpszEntry = key which you want to extract value from. you want to get database name information so you need to check registry entry HKEY_LOCAL_MACHINE\Software\ODBC\ODBC.INI[YOUR_DSN_NAME] to know what is the key name to store database name information. This is because different driver can have different key name to store database name.
lpszDefault = Default value for the key specified in last argument(lpszEntry) if key is not found.
RetBuffer = Pointer to Output buffer in which value for the specified key is received.
cbRetBuffer = size of buffer pointed to by RetBuffer in characters.
lpszFilename = File name where you search these entries in. It will be odbc.ini in your case.
Sample example
CHAR *dsn_name = "Your DSN name";
CHAR db_name[20];
char *odbcini = NULL;
odbcini = "odbc.ini";
SQLGetPrivateProfileString(dsn_name, (CHAR*)"DATABASE", (CHAR*)"", db_name,
sizeof(db_name), odbcini);
It will search registry entry HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE or both depending on the config mode set(It can be set using SQLSetConfigMode ODBC API). If mode is not explicitly set, it will search both HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE.
Please refer https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgetprivateprofilestring-function for more information.
I am new to dbexpress and I cannot figure out how to set the TSQLConnection parm for the SQL Host name at runtime. When I install my program on a client system the TSQLConnectionHost is still reading the Host from my development system that I entered during development.
TSQLConnection.Params is of type TStrings, which means it holds a set of String items. In case of TSQLConnection, Params holds a set of Name=Value pairs, where Name is a parameter name and Value is that parameters value. To read a value of specific parameter, use:
var
s: String;
...
s := SQLConnection1.Params.Values['ParamName'];
To assign a value to specific parameter, use:
SQLConnection1.Params.Values['ParamName'] := 'NewValue';
(Substitute 'ParamName' with actual parameter name and 'NewValue' with actual new value.)
I faced this problem a few years ago when I started developing with dbExpress. On my development machine, the databases were in location X whereas the production machines had the databases in location Y. The way I got around this was to store the physical location of the database in the registry (via a small utility program which I wrote) and then use the following code to load the correct value. The location could be stored in an INI file which would require a slight alteration to my code, but that part is less important.
procedure TDm.SQLConnection1BeforeConnect(Sender: TObject);
var
dir: string;
begin
with TRegIniFile.create (regpath) do // this is where I get the physical value
begin
dir:= ReadString ('firebird', progname, '');
free
end;
with sqlconnection1 do
begin
close;
params.values['database']:= dir;
end;
end;
The reason for your problem is that you have not disconnected the SQLConnection AND all datasets before distrbuting your app.
Things to do
a) make sure all components are NOT connected.
b) set the params of the SQLConnection to blanks.
c) when you app starts, read the required connection params from an ini file, and populate the SQLConnection with those.
d) THEN connect and you will be fine!
Regards
Chris