Procedure to open, write and append in Ada - file-io

This question is a follow-up of the post at
Ada file operation: instantiation and exception
about writing to files in Ada.
I chose to place this question in a separate post so that it'll become visible to more people as I already accepted an answer on a slightly different issue (which was on exceptions in file handling) in that aforementioned post.
WITH Ada.Sequential_IO;
WITH Ada.Float_Text_IO;
PROCEDURE TEST is
package Seq_Float_IO is new Ada.Sequential_IO (Element_Type => Float);
X_File : Seq_Float_IO.File_Type;
File_Name : String;
procedure Open_Data(File : in out Seq_Float_IO.File_Type;
Name : in String) is
BEGIN
begin
Seq_Float_IO.Open (
File => File,
Mode => Seq_Float_IO.Append_File,
Name => File_Name );
exception
when Seq_Float_IO.Name_Error =>
Seq_Float_IO.Create (
File => File,
Mode => Seq_Float_IO.Out_File,
Name => File_Name);
end;
END Open_Data;
x : CONSTANT Float := 2.0;
BEGIN --main program
Open_Data(X_File, "xvalues.dat");
Seq_Float_IO.Write(File => X_File,Item => x);
Seq_Float_IO.Close(File => X_File);
END TEST;
On compiling the above I get an error as follows:
X_File : Seq_Float_IO.File_Type;
File_Name : String;
|
unconstrained subtype not allowed (need initialization)
provide initial value or explicit array bounds
I don't know 2 things:
I have File_Name : String; as I want to be able to write to different files. So I want a general string and not something like:
File_Name : CONSTANT String := "one_File_Only.dat"
Would it be better to save the procedure Open_Data in separate ads and adb (for the body) files?
Thanks a lot...
NEW...
I've modified the code as follows:
WITH Ada.Sequential_IO;
PROCEDURE TEST1 is
package Seq_Float_IO is new Ada.Sequential_IO (Element_Type => Float);
X_File, Y_File : Seq_Float_IO.File_Type;
Name_X : CONSTANT String := "domainvalues.dat";
Name_Y : CONSTANT String := "ordinatevalues.dat";
procedure Open_Data(File : in out Seq_Float_IO.File_Type; Name : in String) is
BEGIN
begin
Seq_Float_IO.Open (
File => File,
Mode => Seq_Float_IO.Append_File,
Name => Name_X );
exception
when Seq_Float_IO.Name_Error =>
Seq_Float_IO.Create (
File => File,
Mode => Seq_Float_IO.Out_File,
Name => Name_X);
end;
END Open_Data;
x : CONSTANT Float := 2.0;
BEGIN --main program
Open_Data(File => X_File, Name => Name_X);
Seq_Float_IO.Write(File => X_File, Item => x);
Seq_Float_IO.Close(File => X_File);
Open_Data(File => Y_File, Name => Name_Y);
Seq_Float_IO.Write(File => Y_File, Item => x);
Seq_Float_IO.Close(File => Y_File);
END TEST1;
As you see I have
Seq_Float_IO.Open (
File => File,
Mode => Seq_Float_IO.Append_File,
Name => Name_X );
I have put Name_X as the parameter that Name is taking but this is not right as I should be able to pass in a general name which can be either Name_X or Name_Y. Sorry guys, I can't figure out what to put here.
I would much appreciate your help. Thanks

The thing about plain String in Ada is that a particular string, like your File_Name, has to be fixed-length; but different Strings can be of different length.
You can write
S1 : String := "1234";
S2 : String := "12345";
in which case S1 is of length 4, and assignments to it have to be of length 4. You can write
S1 := "abcd";
but if you try to write
S1 := "pqrst";
or
S1 := S2;
you will get a Constraint_Error.
In the case of String parameters to subprograms, like your Open_Data, the String parameter Name takes on the length -- and of course the value! of the actual parameter in the call. So you can say
Open_Data (X_File, "x.dat");
Open_Data (Y_File, "a_very_long_name.dat");
You were having problems earlier with
procedure Open_Data(File : in out Seq_Float_IO.File_Type;
Name : in String) is
begin
Seq_Float_IO.Open (File => File,
Mode => Seq_Float_IO.Append_File,
Name => ????);
I'm reluctant to just tell you the answer, so -- consider the File => File part. The first File is the name of the formal parameter of Seq_Float_IO.Open and the second File is what is to be passed, in this case Open_Data's File parameter.
It might help if I point out that I could have written the calls above as
Open_Data (File => X_File, Name => "x.dat");
Open_Data (File => Y_File, Name => "a_very_long_name.dat");

#Simon Wright's answer is correct, and you may find it helpful to compare his answer to the second one I wrote earlier. Note that if you had
Name_X : constant String := "domainvalues.dat";
Name_Y : constant String := "ordinatevalues.dat";
Either string, Name_X or Name_Y, could be used as the actual Name parameter to Open_Data. The formal parameter, Name, is of type String. String is unconstrained, and it may be any (implementation-defined) maximum length. In contrast, Name_X and Name_Y each have a fixed length determined by their initial assignment.
Addendum: You wrote a subprogram with a formal parameter (Name) of type String, having this signature
procedure Open_Data(
File : in out Seq_Float_IO.File_Type;
Name : in String) is ...
In the implementation, you want to forward to Open the String you received as the actual parameter (Name), not the name of a global constant (Name_X).
Seq_Float_IO.Open (
File => File,
Mode => Seq_Float_IO.Append_File,
Name => Name );

Related

Why is my script not building in HelpNDoc? Error: Unknown name

I am trying to write a script:
const
// Define the output file
OUTPUT_FILE = 'd:\topics.txt';
var
// Current topic ID
aTopicId: string;
// List of output
aList: TStringList;
begin
// Init list
aList := TStringList.Create;
aList.Add('Topic Caption | Help ID | Help Context | Meta Description');
try
// Get first topic
aTopicId := HndTopics.GetTopicFirst();
// Loop through all topics
while aTopicId <> '' do
begin
// Add the topic to the list
aList.Add(Format('%s | %s | %d | %s', [
HndTopics.GetTopicCaption(aTopicId),
HndTopics.GetTopicHelpId(aTopicId),
HndTopics.GetTopicHelpContext(aTopicId),
HndTopics.GetTopicDescription(aTopicId)
]));
// Get next topic
aTopicId := HndTopics.GetTopicNext(aTopicId);
end;
// Create the file
aList.SaveToFile(OUTPUT_FILE);
finally
aList.Free;
end;
end.
When I build it in HelpNDoc:
Why is it saying:
[Error] script(9, 3): Unknown name "aList"
The authors of HelpNDoc provided some clarification about this issue. Starting with HelpNDoc 7, you need to add the var keyword each time you change the type: Migrating scripts from V6 to V7.
So my variable declaration section needed to be changed to something like:
var
// Current topic ID
aTopicId: string;
var
// List of output
aList: TStringList;
This is a limitation of HelpNDoc's scripting engine.

Snowflake error in JavaScript procedure column index/name does not exists in resultSet getColumnValue

I am having a procedure on snowflake which executing the following query:
select
array_size(split($1, ',')) as NO_OF_COL,
split($1, ',') as COLUMNS_ARRAY
from
#mystage/myfile.csv(file_format => 'ONE_COLUMN_FILE_FORMAT')
limit 1;
And the result would be like:
Why I run this query in a procedure:
CREATE OR REPLACE PROCEDURE ADD_TEMPORARY_TABLE(TEMP_TABLE_NAME STRING, FILE_FULL_PATH STRING, ONE_COLUMN_FORMAT_FILE STRING, FILE_FORMAT_NAME STRING)
RETURNS variant
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
try{
var final_result = [];
var nested_obj = {};
var nbr_rows = 0;
var NO_OF_COL = 0;
var COLUMNS_ARRAY = [];
var get_length_and_columns_array = "select array_size(split($1,',')) as NO_OF_COL, "+
"split($1,',') as COLUMNS_ARRAY from "+FILE_FULL_PATH+" "+
"(file_format=>"+ONE_COLUMN_FORMAT_FILE+") limit 1";
var stmt = snowflake.createStatement({sqlText: get_length_and_columns_array});
var array_result = stmt.execute();
array_result.next();
//return array_result.getColumnValue('COLUMNS_ARRAY');
NO_OF_COL = array_result.getColumnValue('NO_OF_COL');
COLUMNS_ARRAY = array_result.getColumnValue('COLUMNS_ARRAY');
return COLUMNS_ARRAY;
}
...
$$;
It will return an error as the following:
{
"code": 100183,
"message": "Given column name/index does not exist: NO_OF_COL",
"stackTraceTxt": "At ResultSet.getColumnValue, line 16 position 29",
"state": "P0000",
"toString": {}
}
The other issue is if I keep trying, it will return the desired array, but most of the times is returning this error.
The other issue is if I keep trying, it will return the desired array
If it works one time and not another time, my educated guess is that the stored procedure is called from different schemas.
Querying stage
( FILE_FORMAT => '<namespace>.<named_file_format>' )
If referencing a file format in the current namespace for your user session, you can omit the single quotes around the format identifier.
In the standalone query we can see:
select
array_size(split($1, ',')) as NO_OF_COL,
split($1, ',') as COLUMNS_ARRAY
from
#mystage/myfile.csv(file_format => 'ONE_COLUMN_FILE_FORMAT')
>-< >-<
But in the stored procedure body:
"(file_format=>"+ONE_COLUMN_FORMAT_FILE+") limit 1";
--here the text is appended, but without wrapping with ''
=>
"(file_format=>'"+ONE_COLUMN_FORMAT_FILE+"') limit 1";
Suggestion: always provide file format as as string wrapped with ', preferably prefixed with namespace '<schema_name>.<format_name>'.

ErrorException [ Notice ]: Undefined variable on an existing variable dynamically built

First of all thanks for your time on my issue.
Second sorry if this is a duplicate, I legit searched for 3 days on and off and didn't find answer to my particular situation.
Visual on the error obtained
This first line transforms an array's values into a string of index(es)
$path = self::extract_path($path);
After extraction $path becomes a string with a format similar to['key1']['key2']
Here I test if one valuable element (ondemand) is found within that Keys string, so far so good.
if( $path !== FALSE && strpos($path, $element) !== FALSE){
$var_dim_str = 'coupon' . $path . '[recurrence]';
As a self-proofing, I hard-coded one of my specific scenario element and it does exist so my issue is not really non-initialization of my variable as most other topic were suggesting.
var_dump($coupon['item']['ondemand']['recurrence']);
My issue lies here, I get "ErrorException [ Notice ]: Undefined variable: coupon[item][ondemand][recurrence]"
$recurrence = $$var_dim_str;
[...]
Here are my var_dump output:
These are my indexes as an array they get extracted to reconstruct the variable's string', I have some variable-dimension arrays that gets called so the dimension depth might not always be of fixed value, hence why I have to dynamically test this.
1- $path, before being extracted
[...]\modules\payment\classes\Helper\Payment.php:290:
array (size=2)
0 => string 'item' (length=4)
1 => string 'ondemand' (length=8)
2- We see here that (['item']['ondemand']['recurrence'] => 3) exists
[...]\modules\payment\classes\Payment\Cart.php:266:
array (size=1)
'item' =>
array (size=3)
'ondemand' =>
array (size=14)
[...]
'recurrence' => string '3' (length=1)
[...]
3- My var_dump above is outputting it properly.
[...]\modules\payment\classes\Payment\Cart.php:270:string '3' (length=1)
**So, my conclusion is that PHP doesn't really appreciate my 'built' variable but there has to be some way to make this logic work... any pointers on this would be really appreciated. **
The issue does lie with $$var_dim_str. What the $$ does is resolve $$variableName to be the variable name contained in $variableName. It basically holds a reference to another variable based on the variable's name. From the PHP site:
A variable variable takes the value of a variable and treats that as the name of a variable. In the above example, hello, can be used as the name of a variable by using two dollar signs. i.e.
So ...
// some variables
$name = 'Ellan' ;
$site = 'Stack Exchange' ;
$tags = 'PHP-7, Variables' ;
// we want $site
$variableName = 'site' ;
echo $$variableName ;
// we want $tags
$variableName = 'tags' ;
echo $$variableName ;
The code above will produce:
Stack Exchange
PHP-7, Variables
When you assign a value to $var_dim_str:
$var_dim_str = 'coupon' . $path . '[recurrence]';
$var_dim_str does not hold the name of a variable. It contains the a string.
Are you sure you want to use $$ in this instance? Maybe you really want to use:
$recurrence = $var_dim_str;

Build a query on the selected record , position of the dataset pointer

to display the content of a geometry/spatial field I made a small component. This component does it's job when I provide all the information to query the table correctly.
tablename
fieldname of the gemoetry field
fieldname of a field to select the correct element by a query
a connection to connect the query to the correct database on my server
a datasource to display other elements of my table for reference
as my component should be similliar to all the other dbmemo, dbedit ... VCL components, I do not want to share
a) fieldname of a field to select the correct element by a query
and if possible also remove from parameter transfer to my component
b) the connection
here come my current working solution and need help on a) and b)
unit Unit_DBmemoSpatial;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB ;
type
TDBmemoSpatial = class(TMemo)
private
{ Private-Deklarationen }
Fdatasource : Tdatasource ;
FConnection : TADOConnection;
FdataField : String;
procedure Setdatasource(const Value: Tdatasource);
procedure SetdataField(const Value: String);
procedure AfterSCROLL(DataSet: TDataSet);
protected
{ Protected-Deklarationen }
public
{ Public-Deklarationen }
published
{ Published-Deklarationen }
property Connection : TADOConnection read FConnection write FConnection ;
property datasoure : Tdatasource read Fdatasource write Setdatasource ;
property dataField : String read FdataField write SetdataField ;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('TOOLS', [ TDBmemoSpatial]);
end;
{ TDBmemoSpatial }
procedure TDBmemoSpatial.AfterSCROLL(DataSet: TDataSet);
var aQuery : TADOQuery ;
SQLSTR : String ;
RIndex : Integer ;
begin
/// this will only work on my table , not for others !!!!!
RIndex := Fdatasource.DataSet.FieldByName('MyrecordIndex').AsInteger;
self.Lines.Clear;
self.Lines.Add( 'DBCOMP' + TimetoStr(now) );
aQuery := TADOQuery.Create(nil);
try
aQuery.Connection := FConnection;
SQLSTR := 'SELECT ' + FdataField+'.STAsText() FROM ' + 'MyTable' + ' where MyrecordIndex=' + IntToStr(RIndex);
aQuery.SQL.Add(SQLSTR);
aQuery.Open;
self.Lines.Add( 'record affected ' + IntToStr(aQuery.RecordCount) );
self.Lines.Add( 'Text ' + (aQuery.Fields[0].asString) );
finally
aQuery.Free;
end;
end;
procedure TDBmemoSpatial.SetdataField(const Value: String);
begin
FdataField := Value;
end;
procedure TDBmemoSpatial.Setdatasource(const Value: Tdatasource);
begin
Fdatasource := Value;
Fdatasource.DataSet.AfterScroll := AfterSCROLL;
end;
end.
the calling code for my component goes like this
dbmsptl1.Connection := FCon;
dbmsptl1.datasoure := Fdatasource;
dbmsptl1.dataField :='geometry_by_Fieldname';

How do I use Rhino.Mocks.RhinoMocksExtensions.VoidType with lambda Expect?

I get the following error on this line:
session.Expect(s => s.Add("string", null)).IgnoreArguments().Return(SaveMockUser());
cannot convert from 'void' to 'Rhino.Mocks.RhinoMocksExtensions.VoidType'
SaveMockUser is defined as follows
private void SaveMockUser()
{
}
What am I doing wrong?
It's not possible to return a void type. Probably what you want to do is have another expectation that expects that SaveMockUser() is actually called or actually perform the action via a callback - i.e., when you see this function called, then do this.
session.Expect( s => s.Add("string", null) )
.IgnoreArguments()
.WhenCalled( x => SaveMockUser() );
or even better - use the new inline constraints
session.Expect( s => s.Add( Arg<string>.Is.Equal( "string" ), Arg<string>.Is.Anything ) )
.WhenCalled( x => SaveMockUser() );