Skip to content

Commit b2bb3e2

Browse files
author
aafent
committed
SQL Data Adapter Library
1 parent 6ded544 commit b2bb3e2

21 files changed

+537
-28
lines changed

FAST.FBasic.InteractiveConsole/FAST.FBasicInteractiveConsole.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11+
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.1" />
1112
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.9" />
13+
<PackageReference Include="System.Data.Odbc" Version="9.0.9" />
1214
</ItemGroup>
1315

1416
<ItemGroup>

FAST.FBasic.InteractiveConsole/FBasicIC.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using FAST.FBasicInterpreter;
22
using Microsoft.Extensions.Configuration;
3+
using System.Data.Odbc;
34

45
namespace FAST.FBasic.InteractiveConsole
56
{
@@ -124,9 +125,14 @@ private void setupEnvironment()
124125
env.printHandler += Console.WriteLine;
125126
env.inputHandler += Console.ReadLine;
126127
env.callHandler += (name) => { var filepath = Path.Combine(programsFolder, name); return File.ReadAllText(filepath); };
127-
env.requestForObject += (context, group, name) =>
128+
env.requestForObjectHandler += (context, group, name) =>
128129
{
129-
//if ($"{context}.{group}.{name}" == "ADAPTER.CONNECTION.SQL") return connection;
130+
if ($"{context}.{group}.{name}" == "SQL.CONNECTION.DATA1")
131+
{
132+
string cs = "<replace with your CS hear>";
133+
var connection = new OdbcConnection(cs);
134+
return connection;
135+
}
130136
if ($"{context}.{group}.{name}" == "IN.TEST.NAME") return "THIS IS AN IN TEST!";
131137
return null;
132138
};
@@ -144,11 +150,12 @@ private void runFBasicProgram()
144150
var basProgramFile = Directory.GetFiles(programsFolder, startupName).FirstOrDefault();
145151
result = FBasicSource.Run(env, basProgramFile, (interp) =>
146152
{
147-
// interp.AddDataAdapter(new sqlFBasicDataProvider());
153+
148154
interp.SetVar("table.column", new Value("myColumn1"));
149155
interp.AddLibrary(new FBasicStringFunctions());
150156
interp.AddLibrary(new FBasicMathFunctions());
151157
interp.AddLibrary(new FBasicDateFunctions());
158+
interp.AddLibrary(new FBasicSQLDataAdapter()); // interp.AddDataAdapter(new sqlFBasicDataProvider());
152159
});
153160
if (result.hasError)
154161
{
@@ -172,7 +179,7 @@ static void spBuilder()
172179
env.printHandler += Console.WriteLine;
173180
env.inputHandler += Console.ReadLine;
174181
env.callHandler += (name) => { var filepath = Path.Combine(folder, name); return File.ReadAllText(filepath); };
175-
env.requestForObject += (context, group, name) =>
182+
env.requestForObjectHandler += (context, group, name) =>
176183
{
177184
// if ($"{context}.{group}.{name}" == "SQL.CONNECTION.ADAPTER") return connection;
178185
return null;

FAST.FBasicInterpreter/Core/ErrorReturnClass.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
public class ErrorReturnClass
44
{
55
public Value value { get=>Value.Error; }
6+
7+
public bool falseError { get=>false;}
68
}
79
}

FAST.FBasicInterpreter/Core/Errors.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ public static string E127_WrongArgumentReferredType(string expectedType, string
5656
return msg;
5757
}
5858

59+
public static string E128_RequestHandlerNullReturn(string context, string group, string name, string moreText=null)
60+
{
61+
return $"Request object error. An object expected but got null. Request:{context}.{group}.{name}. {moreText} [E128]";
62+
}
5963

6064
public static string X007_OnlyUnaryOperationsOnNumbers()
6165
{
@@ -82,7 +86,12 @@ public static string X011_CannotConvert(string fromType, string toType)
8286
return $"Cannot convert {fromType} to {toType}. [X011]";
8387
}
8488

85-
89+
public static string X012_GeneralException(string source, Exception ex)
90+
{
91+
string msg = $"FATAL Error ({source}) {ex.Message}. ";
92+
if (ex.InnerException !=null) msg+=$"{ex.InnerException.Message} [X012]";
93+
return msg;
94+
}
8695

8796
}
8897

FAST.FBasicInterpreter/Core/Interpreter.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ public partial class Interpreter : IFBasicError
3333
/// <param name="context">The Context</param>
3434
/// <param name="group">The group of names</param>
3535
/// <param name="name">The name</param>
36-
/// <param name="value">output the value</param>
37-
/// <returns>True if the request found</returns>
38-
public delegate object RequestForObject(string context, string group, string name );
36+
/// <returns>object</returns>
37+
public delegate object RequestForObjectAction(string context, string group, string name );
3938

4039
/// <summary>
4140
/// The delegation handler for the PRINT statement
@@ -62,7 +61,7 @@ public partial class Interpreter : IFBasicError
6261
/// <summary>
6362
/// The delegation handler for Request for Object
6463
/// </summary>
65-
public RequestForObject requestForObjectHandler = null;
64+
public RequestForObjectAction requestForObjectHandler = null;
6665

6766
#endregion (+) Handlers
6867

@@ -103,7 +102,7 @@ public partial class Interpreter : IFBasicError
103102
/// <summary>
104103
/// Collection objects
105104
/// </summary>
106-
public readonly Dictionary<string, IBAasicCollection> collections = new();
105+
public readonly Dictionary<string, IBasicCollection> collections = new();
107106
/// <summary>
108107
/// The result of the execution (statement: RESULT)
109108
/// </summary>

FAST.FBasicInterpreter/Core/Interpreter_Methods.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public T GetDataAdapter<T>(string name) where T: IfbasicDataAdapter
113113
/// </summary>
114114
/// <param name="name">The collection name</param>
115115
/// <param name="collection">The collection handler</param>
116-
public void AddCollection(string name, IBAasicCollection collection)
116+
public void AddCollection(string name, IBasicCollection collection)
117117
{
118118
if (!dataAdapters.ContainsKey(name))
119119
{
@@ -132,7 +132,7 @@ public void AddCollection(string name, IBAasicCollection collection)
132132
/// <param name="group">The group</param>
133133
/// <param name="name">The name</param>
134134
/// <returns>The requested object or null</returns>
135-
public object requestForObject(string context, string group, string name, bool errorIfNull = true)
135+
public object RequestForObject(string context, string group, string name, bool errorIfNull = true)
136136
{
137137
if (this.requestForObjectHandler == null)
138138
Error(context, $"The Request For Object Handler is not installed ({context},{group},{name}) [E100]");

FAST.FBasicInterpreter/Core/Interpreter_Statements.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ void RInputStatement()
456456

457457
GetNextToken();
458458

459-
var value=requestForObject(context: "IN", group: group, name: name);
459+
var value=RequestForObject(context: "IN", group: group, name: name);
460460

461461
SetVar(vname, new Value(value.ToString()) );
462462

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Data.Common;
2+
3+
namespace FAST.FBasicInterpreter
4+
{
5+
public class cursorCollection : dataReaderCollection<DbDataReader, sqlFBasicDataProvider>
6+
{
7+
public override string title => "CURSOR";
8+
9+
public cursorCollection(string cursorName, sqlFBasicDataProvider callback) : base(cursorName, callback)
10+
{
11+
}
12+
13+
public DbConnection channel = null;
14+
15+
protected override bool readerHasRows => reader.HasRows;
16+
17+
protected override void closeCollection(string name) => callback.closeCursor(name, this);
18+
19+
protected override bool openCollection(string name) => callback.openCursor(name, this);
20+
}
21+
22+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
using System.Data;
2+
3+
namespace FAST.FBasicInterpreter
4+
{
5+
/// <summary>
6+
/// Abstract class to implement any collection based on a data reader
7+
/// </summary>
8+
/// <typeparam name="TReader">The type of the reader</typeparam>
9+
/// <typeparam name="TCallback">The type of FBASIC data adapter callback</typeparam>
10+
public abstract class dataReaderCollection<TReader, TCallback> : IBasicCollection
11+
where TReader : IDataReader
12+
where TCallback : IfbasicDataAdapter
13+
{
14+
public bool _endOfData = false;
15+
public bool endOfData
16+
{
17+
get => _endOfData;
18+
set => _endOfData = value;
19+
}
20+
21+
public abstract string title { get; }
22+
23+
public TReader reader;
24+
25+
private bool isOpen = false;
26+
protected TCallback callback;
27+
private string cursorName = null;
28+
private Dictionary<string, Tuple<int, Type, bool>> columnsMap = null;
29+
30+
public dataReaderCollection(string cursorName, TCallback callback)
31+
{
32+
this.callback = callback;
33+
this.cursorName = cursorName;
34+
inner_reset();
35+
}
36+
37+
public object Current { get; set; } = null;
38+
39+
protected abstract bool openCollection(string name);
40+
protected abstract void closeCollection(string name);
41+
protected abstract bool readerHasRows { get; }
42+
43+
44+
public bool MoveNext()
45+
{
46+
if (!this.isOpen)
47+
{
48+
this.isOpen = openCollection(cursorName); //callback.openCursor(cursorName, this);
49+
if (!this.isOpen) return false; //moveToNext=false
50+
this.columnsMap = getColumnsMap(reader);
51+
}
52+
53+
// (v) code to MoveNext()
54+
if (!readerHasRows) return false; //moveToNext=false;
55+
this.Current = reader;
56+
57+
this.endOfData = !reader.Read();
58+
59+
return !this.endOfData;
60+
}
61+
62+
public void Reset()
63+
{
64+
if (this.isOpen)
65+
{
66+
closeCollection(cursorName); //callback.closeCursor(cursorName, this);
67+
this.isOpen = false;
68+
}
69+
70+
inner_reset();
71+
}
72+
73+
private void inner_reset()
74+
{
75+
this.endOfData = false;
76+
this.isOpen = false;
77+
}
78+
79+
public Value getValue(string name)
80+
{
81+
if (!this.columnsMap.ContainsKey(name)) callback.Error(title, $"Name: {name} is missing from {cursorName} [S003]");
82+
var value = reader[name];
83+
var isNumeric = columnsMap[name].Item3;
84+
if (isNumeric)
85+
{
86+
return new Value(Convert.ToDouble(value));
87+
}
88+
else
89+
{
90+
return new Value(value.ToString());
91+
}
92+
93+
}
94+
95+
96+
/// <summary>
97+
/// A map between column name and ordinary and type
98+
/// of each column, extracted from a reader
99+
/// MAP: Key=Column Name, Value=int:Ordinary Number, type:The Type, bool:true if type is Numeric
100+
/// </summary>
101+
/// <param name="reader">the reader</param>
102+
/// <returns>Dictionary with column names as key and Tuple as value</returns
103+
private static Dictionary<string, Tuple<int, Type, bool>> getColumnsMap(IDataReader reader)
104+
{
105+
if (reader == null) { throw new ArgumentNullException("Class isn't yet bind with a DbDataReader object"); }
106+
107+
Dictionary<string, Tuple<int, Type, bool>> map = new();
108+
109+
for (int field = 0; field < reader.FieldCount; field++)
110+
{
111+
var type = reader.GetFieldType(field);
112+
map.Add(reader.GetName(field), new Tuple<int, Type, bool>(field, type, isNumericType(type)));
113+
}
114+
return map;
115+
}
116+
117+
/// <summary>
118+
/// Check if a type is numeric type
119+
/// </summary>
120+
/// <param name="type">the type to check</param>
121+
/// <returns>True if it is numeric type</returns>
122+
private static bool isNumericType(Type type)
123+
{
124+
switch (Type.GetTypeCode(type))
125+
{
126+
case TypeCode.Byte:
127+
case TypeCode.SByte:
128+
case TypeCode.UInt16:
129+
case TypeCode.UInt32:
130+
case TypeCode.UInt64:
131+
case TypeCode.Int16:
132+
case TypeCode.Int32:
133+
case TypeCode.Int64:
134+
case TypeCode.Decimal:
135+
case TypeCode.Double:
136+
case TypeCode.Single:
137+
return true;
138+
default:
139+
return false;
140+
}
141+
}
142+
143+
}
144+
}

0 commit comments

Comments
 (0)