Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Runtime/XSharp.SQLRdd/Classes/Command.prg
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class SqlDbCommand inherit SqlDbHandleObject implements IDisposable
/// <summary>The DBMS Provider class.</summary>
property Provider as ISqlDbProvider get iif(Connection == null, null, Connection:Provider)
/// <summary>The text of the Command object.</summary>
property CommandText as string get DbCommand:CommandText set DbCommand:CommandText := value
property CommandText as string get iif(DbCommand == null, "", DbCommand:CommandText) set DbCommand:CommandText := value

#endregion

Expand Down
85 changes: 22 additions & 63 deletions src/Runtime/XSharp.SQLRdd/Classes/Connection.prg
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ class SqlDbConnection inherit SqlDbHandleObject implements IDisposable
internal const DefaultConnection := "DEFAULT" as string
internal static Connections as List<SqlDbConnection>
static internal property DefaultCached as logic auto
private static oExistingTables := List<string>{} as List<string>

static constructor()
Connections := List<SqlDbConnection>{}
DefaultCached := true
Expand Down Expand Up @@ -273,20 +275,15 @@ class SqlDbConnection inherit SqlDbHandleObject implements IDisposable
KeepOpen := DefaultCached
if @@Callback != null
self:CallBack += @@Callback
SELF:MetadataProvider := SqlMetadataProviderCallBack{SELF}
ELSE
SELF:MetadataProvider := SqlMetadataProviderIni{SELF}
endif
endif
Connections:Add(self)
_datasourceProperties := Dictionary<string, string>{StringComparer.OrdinalIgnoreCase}
_commands := List<SqlDbCommand>{}
_command := SqlDbCommand{"Worker", self}
self:ForceOpen()
SELF:_FillMetadataCollections()
SELF:_FillDataSourceProperties()
SELF:_CheckConnectionTable()
SELF:_CreateLockTable()
SELF:_Login()
SELF:InitializeLockTimer()
// Todo: Check for # of open users and close the connection when no users are left and then throw an exception
return
Expand All @@ -303,9 +300,11 @@ class SqlDbConnection inherit SqlDbHandleObject implements IDisposable
if self:RDDs:Count > 0
return false
endif
self:_Logout()
// Logout the workstation from the Open Connections table
_command:Dispose()
if _command != null
_command:Dispose()
endif

foreach var cmd in SELF:_commands:ToArray()
if cmd:Connection == self
cmd:Dispose()
Expand Down Expand Up @@ -480,7 +479,7 @@ class SqlDbConnection inherit SqlDbHandleObject implements IDisposable
/// <param name="cTable">Table name to display for Event Handler</param>
/// <returns>DbDataReader or NULL when an exception occurred</returns>
method ExecuteReader(cCommand as string, cTable := __FUNCTION__ as STRING) as DbDataReader
local result := null as DbDataReader
local result := null as DbDataReader
try
_command:CommandText := cCommand
result := _command:ExecuteReader(cTable)
Expand Down Expand Up @@ -627,19 +626,26 @@ class SqlDbConnection inherit SqlDbHandleObject implements IDisposable
/// <returns>TRUE when the table exists. </returns>
method DoesTableExist(cTableName as string) as logic
try
if oExistingTables:Contains(cTableName)
return true
endif
if !SELF:HasCollection(TABLECOLLECTION)
return false
endif
if self:_tableRestrictions != 0
local aTableRestrictions := string[]{4} as string[]
aTableRestrictions[2] := cTableName
var dt := self:DbConnection:GetSchema(TABLECOLLECTION, aTableRestrictions)
return dt:Rows:Count > 0
if dt:Rows:Count > 0
oExistingTables:Add(cTableName)
return true
endif
else
var dt := self:DbConnection:GetSchema(TABLECOLLECTION)
foreach row as DataRow in dt:Rows
var tbl := row["TABLE_NAME"]:ToString()
if String.Compare(tbl, cTableName, true) == 0
oExistingTables:Add(cTableName)
return true
endif
next
Expand Down Expand Up @@ -737,58 +743,6 @@ class SqlDbConnection inherit SqlDbHandleObject implements IDisposable
end method
#endregion



private method _CheckConnectionTable() as void
if SELF:DoesTableExist(CONNECTIONSTABLE)
return
endif
var sb := StringBuilder{}
sb:Append(SELF:Provider:CreateTableStatement)
using var cmd := SqlDbCommand{"ConnectionTable", self, false}

sb:Replace(SqlDbProvider.TableNameMacro,CONNECTIONSTABLE)
sb:Replace(SqlDbProvider.FieldDefinitionListMacro, "station varchar(50), username varchar(50), lastlogin varchar(10), refcount int")
cmd:CommandText := sb:ToString()
cmd:ExecuteNonQuery("License")


private method _Login() as void
SELF:_LoginWorker(true)
private method _Logout() as void
SELF:_LoginWorker(false)
private method _LoginWorker(lIn as LOGIC) as void
var user := Environment.UserName
var station := Environment.MachineName
var dDate := DateTime.Now
var today := dDate:Year:ToString()+"-"+dDate:Month:ToString("0#")+"-"+dDate:Day:ToString("0#")
SELF:BeginTrans()
// clear old logins
using var cmd := SqlDbCommand{"Licenses", self, false}
cmd:CommandText := "Delete from "+CONNECTIONSTABLE+" where lastlogin < @p3"
cmd:ClearParameters()
cmd:AddParameter("@p1",user)
cmd:AddParameter("@p2",station)
cmd:AddParameter("@p3",today)
cmd:ExecuteNonQuery("License")
var sWhere := "where username = @p1 and station = @p2 and lastlogin = @p3"
if lIn
cmd:CommandText := "select count(*) from "+CONNECTIONSTABLE+" "+sWhere
var result := Convert.ToInt64(cmd:ExecuteScalar())
if result == 0
cmd:CommandText := "Insert into "+CONNECTIONSTABLE+"(username, station, lastlogin, refcount) values(@p1, @p2, @p3, 0)"
cmd:ExecuteNonQuery("Login")
endif
cmd:CommandText := "Update "+CONNECTIONSTABLE+" set refcount = refcount + 1 "+sWhere
cmd:ExecuteNonQuery("Login")
else
cmd:CommandText := "Update "+CONNECTIONSTABLE+" set refcount = refcount - 1 "+sWhere
cmd:ExecuteNonQuery("Logout")
cmd:CommandText := "delete from "+CONNECTIONSTABLE+" "+sWhere+" and refcount <= 0"
cmd:ExecuteNonQuery("Logout")

endif
SELF:CommitTrans()
#region Implement IDisposable
/// <inheritdoc/>
public override method Dispose() as void
Expand All @@ -798,7 +752,6 @@ class SqlDbConnection inherit SqlDbHandleObject implements IDisposable

#endregion

INTERNAL CONST CONNECTIONSTABLE := "xs_connections" as string
INTERNAL CONST DEFAULT_ALLOWUPDATES := TRUE AS LOGIC
INTERNAL CONST DEFAULT_COMPAREMEMO := TRUE AS LOGIC
INTERNAL CONST DEFAULT_DELETEDCOLUMN := "" AS STRING
Expand Down Expand Up @@ -913,6 +866,9 @@ class SqlDbConnection inherit SqlDbHandleObject implements IDisposable

// Refresh my Locks
using var cmdRefresh := SqlDbCommand{"RefreshLockTable", SELF, false}
if !cmdRefresh:Connection:IsOpen
cmdRefresh:Connection:ForceOpen()
endif
var updateStatement := SELF:Provider:UpdateStatement:Replace(SqlDbProvider.TableNameMacro, LockTableName)
updateStatement := updateStatement:Replace(SqlDbProvider.ColumnsMacro, "lockdatetime = " + SELF:Provider:CurrentDateTime)
updateStatement := updateStatement:Replace(SqlDbProvider.WhereMacro, "connectionid = " + parameterName1)
Expand All @@ -923,6 +879,9 @@ class SqlDbConnection inherit SqlDbHandleObject implements IDisposable

// Clear all old locks
using var cmdClear := SqlDbCommand{"ClearLockTable", SELF, false}
if !cmdClear:Connection:IsOpen
cmdClear:Connection:ForceOpen()
endif
cmdClear:CommandText := SELF:Provider:DeleteStatement:Replace(SqlDbProvider.TableNameMacro, LockTableName):Replace(SqlDbProvider.WhereMacro, "LockDateTime < " + parameterName1)
cmdClear:Parameters := List<SqlDbParameter>{}
cmdClear:Parameters:Add(SqlDbParameter{parameterName1, DateTime.Now.AddSeconds(-120)})
Expand Down
2 changes: 1 addition & 1 deletion src/Runtime/XSharp.SQLRdd/RDD/SQLDbOrderBag.prg
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ internal class SqlDbOrderBag INHERIT BaseIndex
super(oRdd)
self:RDD := oRdd
SELF:LogicalName := cName
if File(cName)
if System.IO.File.Exists(cName)
cName := FPathName()
SELF:Path := System.IO.Path.GetDirectoryName(cName)
SELF:FileName := System.IO.Path.GetFileNameWithoutExtension(cName)
Expand Down
94 changes: 23 additions & 71 deletions src/Runtime/XSharp.SQLRdd/RDD/SQLRDD-Main.prg
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ partial class SQLRDD inherit Workarea
public property RowCount as INT => iif(Self:DataTable == null, 0, Self:DataTable:Rows:Count)

/// <summary>The current rownumber in the buffer (DataTable).</summary>
public property RowNumber as INT GET _rowNumber INTERNAL SET _rowNumber := value
public property RowNumber as INT GET _rowNumber private SET _rowNumber := value

/// <summary>The current row in the buffer (DataTable).
/// When the server is at EOF then the phantomrow is returned.</summary>
Expand Down Expand Up @@ -148,7 +148,7 @@ partial class SQLRDD inherit Workarea
throw Exception{}
endif
if !self:_oTd:HasRecnoColumn
throw Exception{"RecnoColumn is required"}
throw Exception{"RecnoColumn is required for table " + info:FileName}
endif
endif
local aUpdatableColumns := null as HashSet<string>
Expand Down Expand Up @@ -274,7 +274,7 @@ partial class SQLRDD inherit Workarea
next
self:_ExecuteInsertStatement(row)
row:AcceptChanges()
_updatedRowIds:Add((int)row[self:_recnoColumNo])
_updatedRecNos:Add((int)row[self:_recnoColumNo])
SELF:RowNumber := SELF:DataTable:Rows:Count
self:_serverReccount += 1
SELF:_SetBOF(FALSE)
Expand Down Expand Up @@ -368,8 +368,8 @@ partial class SQLRDD inherit Workarea
var col := self:_GetColumn(nFldPos)
if SELF:_updatableColumns:Contains(col)
var row := SELF:CurrentRow
if !_updatedRowIds:Contains((int)row[self:_recnoColumNo])
_updatedRowIds:Add((int)row[self:_recnoColumNo])
if !_updatedRecNos:Contains((int)row[self:_recnoColumNo])
_updatedRecNos:Add((int)row[self:_recnoColumNo])
endif

row[nFldPos-1] := SELF:_HandleNullDate(oValue,self:DataTable:Columns[nFldPos-1])
Expand All @@ -385,7 +385,6 @@ partial class SQLRDD inherit Workarea
/// <summary>Write the contents of a work area's memory to the data store (usually a disk).</summary>
/// <returns><include file="CoreComments.xml" path="Comments/TrueOrFalse/*" /></returns>
override method GoCold() as logic
local row as DataRow
var current := SELF:CurrentRow
if current == null
return false
Expand All @@ -404,64 +403,8 @@ partial class SQLRDD inherit Workarea
return false
endif

foreach var rowId in _updatedRowIds
try
foreach tableRow as DataRow in self:DataTable:Rows
if (int)tableRow[self:_recnoColumNo] = rowId
row := tableRow
endif
next

// Check row lock
dbLockInfo:RecId := row[_oTd:RecnoColumn]
SELF:CheckLock(dbLockInfo, StringBuilder{}, myLock, otherLock)
if otherLock
lOk := false
loop
endif

if !myLock
SELF:Lock(ref dbLockInfo)
endif

lOk := true
if super:Deleted
local wasNew := false as logic
// Append from may add deleted rows
if row:RowState.HasFlag(DataRowState.Added)
lOk := SELF:_ExecuteInsertStatement(row)
row:AcceptChanges()
wasNew := true
endif
if self:_deletedColumnNo > -1
if !wasNew
// already written with _deletedColumnNo with the correct value
lOk := SELF:_ExecuteUpdateStatement(row)
if lOk
row:AcceptChanges()
endif
endif
else
lOk := SELF:_ExecuteDeleteStatement(row)
// we do not clear the fields, but leave the row unchanged.
// the DBF has the deleted flag. This emulates what DBF files do

row:AcceptChanges()
endif

else
if row:RowState.HasFlag(DataRowState.Added)
lOk := SELF:_ExecuteInsertStatement(row)
row:AcceptChanges()
elseif row:RowState.HasFlag(DataRowState.Modified)
lOk := SELF:_ExecuteUpdateStatement(row)
row:AcceptChanges()
endif
endif
catch e as Exception
lOk := false
self:_dbfError(ERDD.WRITE, XSharp.Gencode.EG_WRITE, "SqlRDD:GoCold", e:Message )
end try
foreach var rowId in _updatedRecNos
lOk := self:_UpdateRow(rowId)
if !lOk
exit
endif
Expand All @@ -472,7 +415,7 @@ partial class SQLRDD inherit Workarea
else
self:DataTable:RejectChanges()
endif
_updatedRowIds:Clear()
_updatedRecNos:Clear()
self:_GetRecCount()
endif
return lOk
Expand All @@ -487,12 +430,12 @@ partial class SQLRDD inherit Workarea
override method Close() as logic
local lOk as logic
lOk := SELF:GoCold()
self:UnLock(0)
// This method deletes the temporary file after the file is closed
foreach var bag in self:OrderBagList
bag:Close()
next
self:UnLock(0)
_connection:UnregisterRdd(self)
_connection?:UnregisterRdd(self)

lOk := super:Close()
return lOk
Expand Down Expand Up @@ -653,7 +596,7 @@ partial class SQLRDD inherit Workarea
LOCAL result AS LOGIC
TRY
VAR nRec := Convert.ToUInt32( oRec )
if nRec != RowNumber
if oRec != self:CurrentRow[self:_recnoColumNo]
result := SELF:GoTo( (DWORD) nRec )
endif
CATCH ex AS Exception
Expand Down Expand Up @@ -780,7 +723,6 @@ partial class SQLRDD inherit Workarea
end try
endif
else
self:_rowNumber := self:RowNumber
return super:Deleted
endif
end get
Expand Down Expand Up @@ -901,6 +843,10 @@ partial class SQLRDD inherit Workarea
end method

public override method UnLock(oRecId as object) as logic
if Connection?:Provider is null .or. !self:Connection:IsOpen
return false
endif

try
var sb := StringBuilder{}
var sbWhere := StringBuilder{}
Expand All @@ -923,7 +869,7 @@ partial class SQLRDD inherit Workarea
cmd:AddParameter(self:Provider:ParameterPrefix+"p1", Environment.MachineName ?? String.Empty)
cmd:AddParameter(self:Provider:ParameterPrefix+"p2", Environment.UserName ?? String.Empty)
cmd:AddParameter(self:Provider:ParameterPrefix+"p3", self:Connection:ConnectionId:ToString())
cmd:AddParameter(self:Provider:ParameterPrefix+"p4", _oTd:RealName ?? String.Empty)
cmd:AddParameter(self:Provider:ParameterPrefix+"p4", _oTd?:RealName ?? super:Alias ?? String.Empty)
cmd:AddParameter(self:Provider:ParameterPrefix+"p5", (int)super:Area)
if oRecId != null .and. oRecId is int .and. ((int)oRecId) > 0
cmd:AddParameter(self:Provider:ParameterPrefix+"p6", (int)oRecId)
Expand All @@ -934,9 +880,15 @@ partial class SQLRDD inherit Workarea
end try

// In ADS this happens in here: ACE.AdsUnlockRecord(SELF:_Table, dwRecno)
if (self:Deleted)
if self:Deleted
self:_ExecuteDeleteStatement(CurrentRow)
endif
if self:_updatedRecNos.Count > 0
foreach var nRecNo in self:_updatedRecNos
self:_UpdateRow(nRecNo)
next
self:_updatedRecNos:Clear()
endif

return true
end method
Expand Down
Loading