Error: this expression has type unit but an expression was expected of type int - syntax-error

I am trying to do this simple while loop but it's not working. It is giving me the following error:
this expression has type unit but an expression was expected of type
int
let function () =
let current = ref 0 in
let square = ref !current in
while(((square := !current * !current) mod 1000000) != 269696) do
current := !current +1
done;
!square
;;

First of all, function is a keyword in OCaml, you cannot use it to name your functions.
Also, the condition in the while loop is buggy:
this square := !current * !current is an assignment, which type is unit. It is a type error to use it as an argument of mod which takes two integers as input.
You should probably do the assignment inside the loop and only test !square mod 1000000 <> 269696 in the loop's condition.
Notice that i used the <> structural inequality, instead of the physical one != which by luck does the same thing for integers, but you should not use it unless you know that.

Related

No function matches the given name and argument types. You might need to add explicit type casts psql loop

I keep getting the error and I cant seem to solve it
ERROR: function partialdistanceh(integer, integer) does not exist
LINE 1: partialDistanceH(rHops.PlanetOrigin, rHops.PlanetDestination...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: partialDistanceH(rHops.PlanetOrigin, rHops.PlanetDestination)
CONTEXT: PL/pgSQL function inline_code_block line 33 at EXECUTE
Code
FOR rHops IN SELECT PlanetOrigin, PlanetDestination FROM Hops
LOOP
PREPARE partialDistanceB (INT, INT) AS
SELECT AvgDistance FROM Distance
WHERE PlanetOrigin = $1
AND PlanetDestination = $2;
EXECUTE partialDistanceB(rHops.PlanetOrigin, rHops.PlanetDestination);
hopDistance = partialDistance;
routeDistance = routeDistance + hopDistance;
END LOOP;

How to execute function with parameter in PostgreSQL using anonymous code block in FireDAC?

My database (PostgreSQL 11) has a function that must be called to execute an action. The return is not important, as long as there's no error. This function has arguments that must be passed as parameters.
I cannot directly use TFDConnection.ExecSQL because I use parameters of type array that is not supported by the method (to my knowledge). So, I use TFDQuery.ExecSQL like this:
msql1: = 'DO $$ BEGIN PERFORM DoIt (:id,:items); END $$; ';
{... create FDQuery (fq), set connection, set SQL.Text to msql1}
fq.Params.ParamByName ('id'). AsInteger: = 1;
{$ REGION 'items'}
fq.ParamByName ('items'). DataType: = ftArray;
fq.ParamByName ('items'). ArrayType: = atTable; // Must be atTable, not atArray
if length (items)> 0 then
begin
fq.ParamByName ('items'). ArraySize: = length (items);
for it: = 0 to length (items) -1 do
fq.ParamByName ('items'). AsIntegers [it]: = items [it];
end;
fq.ExecSQL;
{$ ENDREGION}
When executing the above code, the error above message raises
"Parameter 'id' not found".
After some research that suggested using fq.Params.ParamByName I was also unsuccessful.
However, if you change the way the function is called to
select DoIt (:id,:items); and obviously replacing the execution with fq.Open works perfectly.
Is it possible to execute a PL / pgSQL block that contains parameters in the function called by this block using TFDConnection / TFDQuery?
PS: I'm using Delphi Rio 10.3.3
When you assign a value to TFDQuery.SQL, FireDAC does some pre-processing of the SQL based on various options. ResourceOptions.CreateParams option controls whether parameters should be processed. This is enabled by default.
The preprocessor recognizes string literals in your SQL and doesn't try to look for the parameters in them. You used dollar quoted string constant and that's why FireDAC doesn't recognize parameters in it. Even if you add parameter manually I think that FireDAC would not bind the value.
With that said, the proper way to execute stored procedures/function is to use TFDStoredProc. You just assign StoredProcName and call its Prepare method which will retrieve procedure's metadata (parameters) from database so you don't need to set ArrayType or DataType of the parameter.
In your code you set the DataType to ftArray which is wrong, because in case of array parameter it should be set to array's element type. Anyway, by setting fq.ParamByName ('items').AsIntegers you effectively set parameter's DataType to ftInteger. All you need to do is to set ArraySize
Here's what you should do instead:
procedure DoIt(Connection: TFDConnection; ID: Integer; const Items: TArray<Integer>);
var
StoredProc: TFDStoredProc;
ParamItems: TFDParam;
Index: Integer;
begin
StoredProc := TFDStoredProc.Create(nil);
try
StoredProc.Connection := Connection;
StoredProc.StoredProcName := 'DoIt';
StoredProc.Prepare;
StoredProc.Params.ParamByName('id').AsInteger := ID;
if Length(Items) > 0 then
begin
ParamItems := StoredProc.Params.ParamByName('items');
ParamItems.ArraySize := Length(Items);
for Index := Low(Items) to High(Items) do
ParamItems.AsIntegers[Index] := Items[Index];
end;
StoredProc.ExecProc;
finally
StoredProc.Free;
end;
end;
Alternatively you can use ExecFunc to get the result of stored function.

Delphi SQL.Add() throws incompatability error with custom function which returns a string

I have the following code which is constructs an SQL statement based on a number of variables:
SQL.Add('SELECT CDbl(Answer) as An FROM v_Outcomes_FirstLastOneYear ' +
'WHERE ' + GetTool(ReportGrid.Cells[col, 0]) + ' ' +
'AND (Collector = ' + QuotedStr('Patient') + ') ' +
'AND (Question=' + GetQuestion(ReportGrid.Cells[col, 0]) + ') ' +
'AND (Answer is not null) ' +
'AND (Answer <> ''null '') ');
if Copy(ReportGrid.Cells[col, 0], Length(ReportGrid.Cells[col, 0]), 1) = '1' then
SQL.Add('AND ('+GetTPoint(first)+') ')
else
SQL.Add('AND ('+GetTPoint(second)+') ');
SQL.Add('ORDER BY CDbl(Answer)');
The top row of ReportGrid (a TStringGrid) has already been populated with a series of strings such as 'Peds phys 1', or 'Peds phys 2'. The last number is either 1 or 2.
The variables 'first' and 'second' a strings defined further up.
col is an integer - this statement is constructed as part of a for loop which goes through each of the columns and populates each row with data corresponding to the header.
GetTool(), GetQuestion() and GetTPoint() are functions I have defined. The code for GetTPoint() is as follows:
function GetTPoint(timepoint: string): string;
begin
if (timepoint = '0') or (timepoint = 'discharge') then
begin
if timepoint = '0' then
Result := 'FirstAxData=''TRUE'' and DischargeData=''FALSE''';
if timepoint = 'discharge' then
Result := 'DischargeData=''TRUE'' and FirstAxData=''FALSE''';
end
else
begin
timepoint := FormatFloat('0', StrToInt(timepoint)*30.4368);
Result := '[Date] BETWEEN ([Date of First CPC]+' + timepoint +
')-61 AND ([Date of First CPC]+'+timepoint+')+61';
end;
end;
Each of the custom functions are similar and simply returns a string. GetTool() and GetQuestion() both work fine but GetTPoint() throws the following compiler error:
E2010 Incompatible types: 'string' and 'procedure, untyped pointer or
untyped parameter'
Does anyone know why this is being thrown?
The code you've shown appears inside a with statement for the query object you're operating on. Something like this:
with SomeQuery do begin
SQL.Add(...);
...
end;
You're able to refer to the SQL property alone like that because the with statement brings the query object's members into the current scope. That means all its members, including the First method (used for selecting the first query result). Anything introduced in the scope of the with statement will hide things of the same name introduced in earlier scopes. That includes the first variable you say was declared elsewhere.
When you have the expression GetTPoint(first), the compiler interprets the name first as referring to the query method, not the variable. The method is not a string, and calling it doesn't return a string, so the compiler rightfully complains.
The best solution is to stop using with. It just introduces brittleness to code. If you simply must continue using with, then rename your first variable so it doesn't interfere with names brought into scope later. There is no way to refer to local variables that have been hidden by another scope. (If first were global, you could qualify it with the name of the unit, but global variables should be avoided almost as much as with statements.)

ORACLE SQL Method Produces Warning

I'm having trouble getting the following member method to compile (count_single_buses). Would appreciate any advice on what might be wrong syntactically with my code.
CREATE OR REPLACE TYPE BodyModel2_Type AS OBJECT(
ModelID INTEGER,
ModelName VARCHAR2(45),
FloorType VARCHAR2(45),
Manufacturer VARCHAR2(45),
Length NUMBER(8,2),
Width NUMBER(8,2),
NoOfAxles INTEGER,
MEMBER FUNCTION count_single_buses(ModelID INTEGER) RETURN INTEGER);
/
CREATE OR REPLACE TYPE BODY BodyModel2_Type AS
MEMBER FUNCTION count_single_buses(ModelID INTEGER) RETURN INTEGER IS
N INTEGER;
BEGIN
N := (SELECT COUNT(BODYMODELREF) FROM SINGLEDECKBUS_TABLE S
WHERE S.BODYMODELREF = ModelID);
RETURN N;
END count_single_buses;
END;
--EDIT--
Thanks to #Ravi, I managed to solve the issue my correcting my SQL syntax and setting the resultset to a NUMBER, instead of INTEGER.
CREATE OR REPLACE TYPE BODY BodyModel_Type AS
MEMBER FUNCTION count_single_buses(thisModelID INTEGER) RETURN NUMBER IS
NUM NUMBER;
BEGIN
SELECT COUNT(S.BODYMODELREF) INTO NUM FROM SINGLEDECKBUS_TABLE S WHERE S.BODYMODELREF.MODELID = thisModelID;
RETURN NUM;
END count_single_buses;
END;
/
Still not sure why #Ravi's exact code still produced the warning, and thought that resultset when returning a count value could go into an integer. At any rate, the code works now. Thanks all.
Your BodyModel2_Type Type definition looks okay. However, the body definition is syntactically incorrect.
You cannot define a SQL statement directly to a variable, thus making this statement wrong.
N := (SELECT COUNT(BODYMODELREF) FROM SINGLEDECKBUS_TABLE S
WHERE S.BODYMODELREF = ModelID);
You will have to use Select... into statement in order to assign the result set of your SQL query into a variable. So, the right syntax should look like this
SELECT COUNT(BODYMODELREF) FROM SINGLEDECKBUS_TABLE S INTO N
WHERE S.BODYMODELREF = ModelID
AFAIK you don't have END the Type followed by the Type name like this END count_single_buses. It'll produce an error. So, overall your Type body specification should look like this:
CREATE OR REPLACE TYPE BODY BodyModel2_Type AS
MEMBER FUNCTION count_single_buses(ModelID INTEGER) RETURN NUMBER IS
N NUMBER;
BEGIN
SELECT COUNT(BODYMODELREF) FROM SINGLEDECKBUS_TABLE S INTO N
WHERE S.BODYMODELREF = ModelID;
RETURN (N);
END;
END;
/
I'm writing this off without any live environment available right now so please let me know if you come across any error in the above code.
Cheers.

Use variable as operator for calculation C

I'm looking for a way to evaluate arithmetic operation using variable instead of operators.
Here is an example:
char op1 = '+';
char op2 = '/';
int i = 0;
i = 4 op1 5 op2 3;
I've no idea if its possible in C. But, if its possible.. would be great.
Thanks..
No, this isn't possible. When the C compiler parses the line of code, it treats operators and variables completely differently. There is no mechanism for interpreting a variable as an operator.
You can of course emulate the process with a function:
if ( op == '+' )
return a+b;
else if ( op == '-' )
return a-b;
else if . . .
but good luck with this when you have more than two operands.
There is one way you can look at this problem, yes you can use "if(random_var == '+')" or something similar or you can use a const defined variable:
#include<stdio.h>
#define plus +
#define minus -
main(){
printf("%d",5 plus 6 minus 1);
}
The output will be as expected 10 (5 + 6 - 1 = 10)
-> the const defined variables must be separated form the numbers