This is My Situation
I have a Service Named BaseDataService, in here I create a LocalDataAdapter that I'm gonna use to connect to a specific service called DataBaseLayer. The service I'm trying to connect contains the schemas that have all datatables needed to use.
Then I create a another service that descends from BaseDataService, so it contains the LocalDataAdapter mentioned earlier. The problem is that after configuring the local data adapter I can't open the datatables that are in the DataBaseLayer service. Posting the code:
Procedure TBaseDataService.ConnectDatabaseLayerToAdapter
begin
DataBaseLayerAdapter.ServiceInstance := DatabaseLayerService as IDataAbstractLocalServiceAccess
end
Procedure TBaseDataService.DataAbstractServiceCreate(Sender: TObject);
begin
DataBaseLayerAdapter.ServiceName := ' ';
end
function TBaseDataService.GetDataBaseLayerService: IDataBaseLayerService;
begin
if not Assigned(FDatabaseLayerService) then
FDataBaseLayerService := (CreateAndConnectService('DataBaseLayerService') as IDataBaseLayerService);
Result := FDataBaseLayerService;
end
ConnectDataBaseLayerToAdapter;
tbl_SA_Receipts.Open;
Note: The last part is where I try to connect to DataBaseLayerService.
At first I got this error:
"An exception was Raised on the server: Acces Violation ad Adress
014FD9C0 in Module .... Read of address 0000098"
I manage to get this part fixed after a lot working, but now the problem I have is when I assigned the server instance, it is assigned as null, can't figure out the reason why, since in the code above does that, been here for a while now but can't get past this part.
Manage to fix this:
in order to use local data adapter to connect to another service containing datatables, the service you are conecting to must be a descendant of TDataAbstractService,otherwise it will return a read of acces error.
the code making the connection is actually correct.
Related
I have a public website made using Apex 21.1.3
When a user shares a page of my website, let's say on facebook, Facebook adds "?fbclickId=something" to the URL.
My app then crashes saying : Unable to find item ID for item fbclickId in application.
Apex thinks the user is trying to set an element that does not exist on the application.
I have url processing layer using htaccess that formats the urls before sending them to Apex in a reverse proxy. I could say let's ignore all what comes after a question mark "?" but in this case I wont be able to set any application item value neither. So that's not possible.
Does anyone have an idea how to make Apex ignore setting a parameter if it doesn't exist ?
Using google for example :
This URL https://www.google.com/?anyparameter=anyvalue will always resolve to https://www.google.com
Thanks
Cheers
I'm not aware of any way to ignore invalid parameters, but you can make the error a bit nicer for the end user.
Create a custom apex error handling function. The only difference with standard error handling is that the error with code WWV_FLOW.FIND_ITEM_ID_ERR has a custom message and no additional info. Change the string "Invalid url arguments" to something more relevant for your business case.
create or replace function apex_error_custom
(
p_error IN apex_error.t_error
)
RETURN apex_error.t_error_result
IS
l_result apex_error.t_error_result := apex_error.t_error_result();
BEGIN
l_result := apex_error.init_error_result ( p_error => APEX_ERROR_CUSTOM.p_error );
IF p_error.apex_error_code = 'WWV_FLOW.FIND_ITEM_ID_ERR' THEN
l_result.message := 'Invalid url arguments';
l_result.additional_info := NULL;
END IF;
RETURN l_result;
END apex_error_custom;
Change the application definition to use the new error function:
Application Definitions > Error Handling > Custom Error Function. Note this affects all errors in the application.
An additional way to make the error nicer is to change the default error page to use a defined template (Shared Components > Themes > your theme > Component Defaults > Error page). Note this affects all errors in the application.
Here is the solution I came up with.
I couldn't find any way to ignore unavailable fields but found a trick to avoid sending them to Apex, hence escaping the error.
In the middle tier (nginx, apache, IIS) add the following logic :
Whenever there are two question marks, ignore the second one part:
For example : someApexAppUrl?Parameter=value?fbclickid=something
Should become : someApexAppUrl?Parameter=value
Whenever there is a parameter added to the url for example
someApexAppUrl?Parameter=value
Check the parameter name against
Application Items with a protection level of Unrestricted, Checksum Required - Application Level, Checksum Required - User Level, Checksum Required - Session Level
The hard coded list of the default Apex urls parameters which are : session, request, clear, debug, printerFriendly, trace, timezone, lang, territory, cs, dialogCs, x01 according to this article
Application page items with a name pattern P99_Someting
Whenever a parameter is not among these three categories, ignore it and don't send it to Apex. This way even if facebook adds something like ?fbclickid=xxx the Apex App will still work nicely.
You can add the item to your application to avoid getting this error message.
Create an Application Item (under Shared Components) called FBCLICKID. Set its Session State Protected to Unrestricted.
I am trying to develop some REST API and I am working with: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production, Oracle ORDS and SQL Developer 17.3.1.279.
I already develop and test a GET API in order to prove that the db is REST-Enabled.
I try to develop a POST API and I am reading this article
My POST handler is:
declare
lrow accounts%rowtype := null;
begin
lrow.id := :id;
lrow.account := :account;
/*added to inspect the current value*/
Raise_Application_Error(-20000, '*'||:account||'*');
lrow.category := :category;
lrow.address := :address;
lrow.zipcode := :zipcode;
lrow.city := :city;
lrow.county := :county;
ASADMIN.INSERTACCOUNT(lrow);
:error := null;
exception
when others then
:error := sqlerrm;
end;
For each bind variable I create a corresponding in/out parameter in the handler.
I test the API with POSTMAN passing this object:
{
"id" : "18092018"
,"account" : "Buster Keaton"
,"category" : "TEST CATEGORY"
,"address" : "TEST ADDRESS"
,"zipcode" : "12345"
,"city" : "TEST CITY"
,"county" : "TEST COUNTY"
,"error" : null
}
and the response was "Cannot insert NULL in ..." then I add the raise application error in order to check what is the value passed that results as null.
I would like to know which is the common (or best) practice to debug a REST API and the way to "monitor" bind variables.
I try to run the anon block attached to the handler inside of SQL Developer to make sure it's going to work there first. So, does that work, in SQL Developer where you are doing the restful service definition?
For others reading this question, when you want to 'debug' and don't have access to the ORDS server logs:
If you get a 500 response when calling it from ORDS, it can be helpful to run ORDS in 'debug' mode.
There are two properties you can enable, debug and print to screen. (docs)
This will show the stack dump from the back end in your browser - not something you ever want to do in 'prod' but since you're debugging, I'm assuming you're in a safe place.
Once that's on, make your call again -
Now you can see the ORA error code that's causing the 500 - and you can also probably see how ORDS is executing the anon plsql block - maybe you're not processing the inputs correctly...
I talk about this here.
For your case specifically, you either have a typo or you are neglecting a value when it comes to making your call to INSERTACCOUNT().
Without seeing the spec for INSERTACCOUNT(), we're left to guess what might be happening.
After commenting the response from thatjeffsmith I focus on service parameters and bind variables and I realize that my setup was completly wrong. I would like to share how I correct what was my mistake.
In the POST handler I use bind variable that I pass to the service in the body of the request but I define corresponding parameters as IN/OUT so the SOURCE can be only HEADER or URI and the bind variables result all null.
I found very useful theese articles: Parameters and binds and resultset.
I modify the handler deleting ALL the IN/OUT parameters because every variable (or JSON object) passed via request body are automatically "matched" with bind variables used in the handler.
Now I am working/studying on resultset in order to return the well formed json object with all the information needed to my app.
fphttpclient works fine with simple examples like
procedure ReadFromURL(theURL: string);
var
httpClient: TFPHTTPClient;
FileContents: String;
theStatusCode: integer;
begin
httpClient := TFPHTTPClient.Create(nil);
try
FileContents := httpClient.Get(theURL);
theStatusCode := httpClient.ResponseStatusCode;
if theStatusCode = 200 then
begin
; // do something
end
else
ShowMessage(IntToStr(theStatusCode));
finally
httpClient.Free;
end;
end;
but only, if the URL exists, so that the status code is 200. In other cases the code crashes at httpClient.Get with an exception of class EHTTPClient, ESocketError or EXC_BAD_ACCESS, although the procedure uses a try ... finally section (formulating it as try ... except doesn't change anything). Unfortunately, the exception is raised before the status code can be processed.
What is the recommended way to handle errors with fphttpclient? Is there any method to check for the existence of a resource (and, possibly, the correctness of an URL, too), before invoking the Get method?
Make sure the various events are assigned, so that the class knows what to do on password prompts, redirects etc.
Standard examples init the class like
With TFPHTTPClient.Create(Nil) do
try
AllowRedirect:=True;
OnRedirect:=#ShowRedirect;
OnPassword:=#DoPassword;
OnDataReceived:=#DoProgress;
OnHeaders:=#DoHeaders;
{ Set this if you want to try a proxy.
Proxy.Host:='ahostname.net.domain';
Proxy.Port:=80;
etc.
Please study examples and try to sort through your problems till you have reproducible cases. If then there is still a problem, please submit it to the bugtracker
In rare cases, checking the existences of headers with HEAD() can speed up e.g. sifting through lists of old urls
We are trying to execute an oracle function that requires parameters and we are getting the error ORA-01008- Not all variables are bound. We are pretty sure the problem is in how we are binding the variable that is supposed to received the result of the function. First we tried the following (a method without parameters):
$tSql:="select staging.FUNC_ORAOCI_TEST() from dual"
$iStatus:=OCIHandleAlloc (envhp;$stmthp;OCI_HTYPE_STMT)
$iStatus:=OCIHandleAlloc (envhp;$errhp;OCI_HTYPE_ERROR)
$iStatus:=OCIStmtPrepare ($stmthp;$errhp;$tSql;OCI_DEFAULT)
$iStatus:=OCIDefineByPos ($stmthp;$bindpp;$errhp;1;->atResults;SQLT_STR;$ORANullIndicator;$ORANullLenArray;$ORANullReturnCodeArray;OCI_DEFAULT)
$iStatus:=OCIStmtExecute (svchp;$stmthp;$errhp;1;0;0;0;OCI_DEFAULT)
And it worked perfectly...
Where we got stuck was when trying to pass parameters to the function (which we had modified on purpose to now accept parameters)
We thought it was because we now had to make the binding by name, but it just did not work. We have tried running a PL/SQL block and still we get the error. Here are our failed attempts:
Using a SQL Statement:
$tSql:="select staging.FUNC_ORAOCI_TEST(:tParamText,:iParamNum) from dual"
$iStatus:=OCIBindByName ($stmthp;$bindpp;$errhp;":tParamText";- >tParamText;SQLT_STR;$ORANullIndicator;$ORANullLenArray;$ORANullReturnCodeArray;1;OCI_DEFAULT;BIND_IN)
$iStatus:=OCIBindByName ($stmthp;$bindpp;$errhp;":iParamNum";->iParamNum;SQLT_INT;$ORANullIndicator;$ORANullLenArray;$ORANullReturnCodeArray;1;OCI_DEFAULT;BIND_IN)
$iStatus:=OCIDefineByPos ($stmthp;$bindpp;$errhp;1;->atResults;SQLT_STR;$ORANullIndicator;$ORANullLenArray;$ORANullReturnCodeArray;OCI_DEFAULT)
$iStatus:=OCIStmtExecute (svchp;$stmthp;$errhp;1;0;0;0;OCI_DEFAULT)
Using a PL/SQL Anonymous Block:
$tSql:="DECLARE vResult VARCHAR2:=''; BEGIN vResult := FUNC_ORAOCI_TEST(:tParamText,:iParamNum); End;"
$iStatus:=OCIBindByName ($stmthp;$bindpp;$errhp;":tParamText";->tParamText;SQLT_STR;$ORANullIndicator;$ORANullLenArray;$ORANullReturnCodeArray;1;OCI_DEFAULT;BIND_IN)
$iStatus:=OCIBindByName ($stmthp;$bindpp;$errhp;":iParamNum";->iParamNum;SQLT_INT;$ORANullIndicator;$ORANullLenArray;$ORANullReturnCodeArray;1;OCI_DEFAULT;BIND_IN)
$iStatus:=OCIBindByName ($stmthp;$bindpp;$errhp;":vResult";->tResult;SQLT_STR;$ORANullIndicator;$ORANullLenArray;$ORANullReturnCodeArray;1;OCI_DEFAULT;BIND_OUT)
$iStatus:=OCIStmtExecute (svchp;$stmthp;$errhp;1;0;0;0;OCI_DEFAULT)
We have looked at similar questions but no one was trying to use the OCI interface to execute the function the way we are doing it.
We are coding in 4D so ignore the weird syntax. We just need guidance as to how build the statement and what would be the proper OCI command to reach a successful binding.
We partially resolved this issue.
We have got it to work only for SQL statements not for PL/SQL. But we got rid of the ORA-01008 error.
The code in case 1 referenced above works as is. We did some clean up of comments and lines that were added for debugging, but they might have altered the sqlstmt somehow, thus affecting the binds.
The code in case 2 now gives an error "Invalid SQL Statement" which we will open a new inquiry for in separate thread.
One very useful information that we found to help us resolve the initial inquiry can be found here:
https://docs.oracle.com/database/121/LNOCI/oci05bnd.htm#LNOCI16368
Has anyone seen this error when trying to call an external C function from an Oracle query? I'm using Oracle 10g and get this error every time I try to call one of the two functions in the library. A call to the other function returns fine every time, though the function that works is all self-contained, no calls to any OCI* functions.
Here's the stored procedure that is used to call the failing C code:
CREATE OR REPLACE PROCEDURE index_procedure(text in clob, tokens in out nocopy clob, location_needed in boolean)
as language c
name "c_index_proc"
library lexer_lib
with context
parameters
(
context,
text,
tokens,
location_needed
);
Any help would be appreciated. Everything I've found on this error message says that the action to take is: Contact Oracle customer support.
Edit: I've narrowed it down to the point that I know that there is a segfault deep in libclntsh after I call OCILobTrim (to truncate it down to 0 length) on the tokens clob. Here is the code I've been using to call this procedure.
declare text CLOB; tokens CLOB;
begin
dbms_lob.createtemporary(tokens, TRUE);
dbms_lob.append(tokens, 'token');
dbms_lob.createtemporary(text, TRUE);
dbms_lob.append(text, '<BODY>Test Document</BODY>');
index_procedure(text, tokens, FALSE);
dbms_output.put_line(tokens);
end;
/
Is there something wrong with this setup that might be causing OCILobTrim problems?
It looks like this is one of those errors that essentially means any number of things could have gone wrong with the external procedure.
There is a known bug in 10.2.0.3, no idea if it's relevant:
ORA-28579 occurs when trying to select
data from a pipelined table function
implemented in "C" using the
ODCITable/ANYDATASET interface.
ODCITableDescribe works fine but
ODCITableFetch generates an ORA-28579
error.
I would suggest:
Look in the database server
trace directories, and the directory
where the external proc is located,
for any log or trace files generated
when the error occurs.
Instrument your external proc in
some way so that you can try to
trace its execution yourself.
Contact Oracle support
Well, an upgrade to 10.2.0.4 (was using 10.2.0.1) at least gave me an understandable error instead of a fairly useless core file and the ORA-28579.
It turns out that the code I was debugging was assuming that calling OCILobRead would return all of the data in one pass. This is the case for any client using a fixed width character set.
For clients using a variable width character set, this isn't the case, OCILobRead was actually reading part of the data and returning OCI_NEED_DATA and future calls to OCILobTrim and OCILobWrite were failing because of the still pending call to OCILobRead. The solution was to loop OCILobRead calls until OCI_NEED_DATA was no longer returned and we had all of the needed data in our buffer.
A call to OCIBreak also would have allowed the OCILobTrim and OCILobWrite functions to continue, though we wouldn't have had all of the needed input data.