/* Devin Server - DMS - november 00 - by François Chenebit */ /* GLOBAL CONSTANTS */ var SIZE_OF_PREDICTION_PACKET = 35;; var PACKED_PREDICTION_SIZE = 100;; /* GLOBALS VARIABLES */ /* handle to the DataBase */ typeof DBConnection = SqlDB;; /* Communication constructors */ defcom CReceivePredictions = ReceivePredictions S;; defcom CReceivePrecisePrediction = ReceivePrecisePrediction I S;; defcom CErrorDatabase = ErrorDatabase;; defcom CCorrectDatabaseOperation = CorrectDatabaseOperation;; defcom CCorrectDeleteDatabaseOperation = CorrectDeleteDatabaseOperation I S;; /* There are the parameters given by the editor : - The name of the ODBC alias to the base - Login and Password on that Base - name of the Login table - name of the password table - a Boolen that indicate wheter the last prediction is returned or not when less than 24 hours passed since the last prédiction. */ typeof SBaseName = S;; typeof SBaseLogin = S;; typeof SBasePassword = S;; typeof SLoginTableName = S;; typeof SPredictionTableName = S;; typeof IBehavior = I;; /* Number of prediction inside the table, also the IModulo of random */ typeof IModulo = I;; /* client currently editing the database */ typeof SClientEditing = S;; /* FUNCTIONS */ /* GENERAL FUNCTIONS */ /* ErrorMessage : this function write an error message into the memory log of DMS Parameters : SerrorMsg : the string to add in the error message Return value : unsignifiant */ fun ErrorMessage(SErrorMsg)= ( _addwarning SErrorMsg );; /* LastSQLErrorMessage : this function write the last SQL error into the log Parameters : none Return value : unsignifiant */ fun LastSQLErrorMessage()= ( let SqlDescErr DBConnection -> [ _ InativeError SerrorMessageSQL _ ] in ( let strcatn (_loc this "TxtErreurSQL" nil )::" "::SerrorMessageSQL::(_loc this "TxtErreurSQLNative" nil ):: (itoa InativeError )::nil -> SmsgToUser in ( ErrorMessage SmsgToUser ) ) );; /* this function is used to build a list of string, from a list of list of string. Its obvious usage is to build a list of prediction from the result of a request parameters : the list of list of string to concat result : a list of string of the form : hd::" "::tl because of this form, we can't use strbuild. NB : only the first 40 chars of the predictions are sent,to minimize traffics inside the network */ fun LineMake(LLSToConcat)= ( if LLSToConcat==nil then ( nil ) else ( let LLSToConcat -> [ hdL tlL ] in ( (strcat (strcat hd hdL " " ) (strcatn (substr (strcatn tl hdL) 0 PACKED_PREDICTION_SIZE ) ::"..."::nil))::LineMake(tlL) ) ) );; /* InsertPrediction : this function insert a new prediction inside the databse, and if the insert is a succes, add one to the IModulo Parameters : Prediction : this is a string to be the new prediction inserted inside the prediction table if nil, if its length is more than 256, SQL_ERROR is returned Return Value : I either SQL_SUCCESS or SQL_ERROR if no data has been inserted, or if the Prediction is nil or too long, SQL_ERROR is returned */ /* NB : such a function, and the following ones exist because we want to insert from an event, and from the client*/ fun InsertPrediction(SPrediction) = ( if ( SPrediction == nil || ((strlen SPrediction) > 255 )) then ( /* this prediction can not be inserted into the database */ ErrorMessage strcatn (_loc this "ErreurMauvaiseChaine" nil)::" "::SPrediction::nil ; SQL_ERROR ) else ( /* the prediction is insertable */ SqlRequest DBConnection (strcatn "INSERT INTO "::SPredictionTableName::" (NumPrediction,TxtPrediction) VALUES (":: (itoa (IModulo + 1))::",?)"::nil ) (SQL_CHAR SPrediction)::nil ; let SqlCod DBConnection -> IbaseReturn in ( let SqlDescErr DBConnection -> [ _ _ _ IinsertLineCount ] in ( if (IbaseReturn == SQL_SUCCESS) && (IinsertLineCount == 1) then ( set IModulo = IModulo + 1; SQL_SUCCESS ) else ( ErrorMessage(strcatn (_loc this "ErreurRequeteInsert" nil)::" ":: SPrediction::nil); LastSQLErrorMessage; SQL_ERROR; ) ) ) ) );; /* DeletePrediction : this function delete a prediction inside the databse. to be precise, the prediction which key number is id is changed with the last prediction in the table, and the last one is deleted. So, there is no gap in the prediction numbers. IModulo is then set accordingly. Parameters : an integer, that identifies the prediction number. Return Value : I either SQL_SUCCESS or SQL_ERROR NB: if the delete command deletes no line, SQL_ERROR is returned */ fun DeletePrediction(IIdPrediction)= ( let hd hd SqlRequest DBConnection strcatn "SELECT TxtPrediction FROM "::SPredictionTableName:: " WHERE NumPrediction = "::(itoa IModulo)::nil nil -> SlastPredictionText in ( SqlRequest DBConnection strcatn ("UPDATE "::SPredictionTableName::" Set TxtPrediction = ? WHERE NumPrediction = " ::(itoa IIdPrediction)::nil) (SQL_CHAR SlastPredictionText)::nil ); let SqlDescErr DBConnection -> [ _ _ _ IupdateLineCount ] in ( let SqlCod DBConnection -> IupdateErrorCode in ( if ( IupdateErrorCode == SQL_SUCCESS ) && ( IupdateLineCount == 1 ) then ( /* the update request is successfull */ SqlRequest DBConnection strcatn "DELETE * FROM "::SPredictionTableName::" WHERE NumPrediction = " ::(itoa IModulo)::nil nil; let SqlDescErr DBConnection -> [ _ _ _ IdeleteLineCount ] in ( let SqlCod DBConnection -> IdeleteErrorCode in ( if ( IdeleteErrorCode == SQL_SUCCESS ) && ( IdeleteLineCount == 1 ) then ( /* The request is successfull, so IModulo is set accordingly */ set IModulo = (IModulo - 1); SQL_SUCCESS ) else ( /* there is an error with the request, either with the line count or with the return code */ ErrorMessage(strcatn (_loc this "ErreurRequeteUpdate" nil)::" ":: (itoa IIdPrediction)::nil); LastSQLErrorMessage; SQL_ERROR ) ) ) ) else ( /* there is an error with the request, either with the line count or with the return code */ ErrorMessage(strcatn (_loc this "ErreurRequeteUpdate" nil)::" "::(itoa IIdPrediction)::nil); LastSQLErrorMessage; SQL_ERROR ) ) ) );; /* this function update the text of a given prediction parameters : IpredictionId : an integer, that identify the prediction to update SnewPredictionTxt : a string that is the value that will replace the prediction text Return Value : I either SQL_SUCCESS or SQL_ERROR if no data has been updated, or if the Prediction is nil or too long, SQL_ERROR is returned */ fun UpdatePrediction(IPredictionId,SNewPredictionTxt)= ( if ( SNewPredictionTxt == nil ) || ( (strlen SNewPredictionTxt) > 255 ) then ( /* The new prediction text is not a correct value */ ErrorMessage strcatn (_loc this "ErreurMauvaiseChaine" nil)::" "::SNewPredictionTxt::nil ; SQL_ERROR ) else ( SqlRequest DBConnection strcatn "UPDATE "::SPredictionTableName::" Set TxtPrediction = ? WHERE NumPrediction = " ::(itoa IPredictionId)::nil (SQL_CHAR SNewPredictionTxt)::nil; let SqlDescErr DBConnection -> [ _ _ _ IupdateLineCount ] in ( let SqlCod DBConnection -> IupdateErrorCode in ( if ( IupdateErrorCode == SQL_SUCCESS ) && ( IupdateLineCount == 1 ) then ( /* the update request is successfull */ SQL_SUCCESS; ) else ( /* there is an error with the update request */ ErrorMessage strcatn (_loc this "ErreurRequeteUpdate2" nil)::" "::(itoa IPredictionId):: (_loc this "ErreurRequeteUpdate3" nil)::" "::SNewPredictionTxt::nil ; LastSQLErrorMessage; SQL_ERROR; ) ) ) ) );; /* this function select the text of an identified prediction Parameters : IpredictionId : an integer that identify an unique prediction Return value : a tuple made of an integer corresponding to either SQL_SUCCESS or SQL_ERROR and a string containing the prediction text NB : SQL_NO_DATA is considered to be an error, so if there is no data corresponding to the number, the function returns SQL_ERROR */ fun SelectPrediction(IPredictionId)= ( let hd hd SqlRequest DBConnection strcatn "SELECT TxtPrediction FROM "::SPredictionTableName::" WHERE NumPrediction = ":: (itoa IPredictionId)::nil nil -> SrequestResult in ( if (SqlCod DBConnection) == SQL_SUCCESS then ( /* the select request is successfull, so we return its result */ [ SQL_SUCCESS SrequestResult ]; ) else ( /* there is an error whith the request */ ErrorMessage(strcatn(_loc this "ErreurRequeteSelection" nil)::" "::(itoa IPredictionId)::nil); LastSQLErrorMessage; [ SQL_ERROR nil ]; ) ) );; /* COMMUNICATION FUNCTIONS */ /* this function is called by the client to get a set of SIZE_OF_PREDICTION_PACKET predictions in the database. The prediction he gets are the prediction number IFirstPrediction, to the id IFirstPrediction + SIZE_OF_PREDICTION_PACKET He gets them trough a Server->Client Message : ReceivePredictions. Predictions are in the form : ["Num Text of the prediction" r1] parameters : the first prediction number return : unsignificant. In case of a select error, the client receive an error message */ fun __GiveNextPredictions(INextPredictionId)= ( let SqlRequest DBConnection strcatn "SELECT NumPrediction,TxtPrediction FROM "::SPredictionTableName::" WHERE NumPrediction >= ":: (itoa INextPredictionId)::" AND NumPrediction < "::( itoa (INextPredictionId + SIZE_OF_PREDICTION_PACKET))::nil nil -> LLSresult in ( if (SqlCod DBConnection) == SQL_SUCCESS || (SqlCod DBConnection) == SQL_NO_DATA then ( _DMSsend this DMSsender CReceivePredictions [ linebuild LineMake LLSresult ] ) else ( let strcatn (_loc this "ErreurSelectNext" nil)::" "::(itoa INextPredictionId)::nil -> SerrMsg in ( ErrorMessage SerrMsg; LastSQLErrorMessage; _DMSsend this DMSsender CReceivePredictions [ strcatn (itoa INextPredictionId)::" "::SerrMsg::nil ] ) ) ) );; /* this function is called by the client when it wants to receive an identified prediction the prediction is sent back, with the message ReceivePrecisePrediction. In case of error, an error msg is send through the message ErrorDatabase parameters : Asked prediction ID return value : unsignificant */ fun __GivePrecisePrediction(IAskedPrediction)= ( let SelectPrediction(IAskedPrediction) -> [ IrequestResult SpredictionTxt ] in ( if IrequestResult == SQL_SUCCESS then ( _DMSsend this DMSsender CReceivePrecisePrediction [ IAskedPrediction SpredictionTxt ] ) else ( _DMSsend this DMSsender CErrorDatabase [] ) ) );; /* this function is called by the client when it wants to update a prediction. The result of the operation is send with a message : either CorrectDatabaseOperation, or ErrorDatabase parameters : the Id of the prediction to update and the new text of the prediction result value : unsignificant */ fun __UpdatePrediction(IPredictionId,SPredictionTxt)= ( let UpdatePrediction IPredictionId SPredictionTxt -> IsqlResult in ( if IsqlResult == SQL_SUCCESS then ( _DMSsend this DMSsender CCorrectDatabaseOperation [] ) else ( _DMSsend this DMSsender CErrorDatabase [] ) ) );; /* this function is called by the client when it wants to create a prediction. The result of the operation is send with a message : either CorrectDatabaseOperation, or ErrorDatabase parameters : the text of the new prediction result value : unsignificant */ fun __CreatePrediction(SPredictionTxt)= ( let InsertPrediction SPredictionTxt -> IsqlResult in ( if IsqlResult == SQL_SUCCESS then ( _DMSsend this DMSsender CCorrectDatabaseOperation [] ) else ( _DMSsend this DMSsender CErrorDatabase [] ) ) );; /* this function is called by the client to delete a prediction. In case of error, the error message is given by the message ErrorDatabase. But if the deletion is correct, we use CCorrectDatabseDeleteOperation to send the last prediction to client, for it to update its data. If the deleted prediciton was the last one, we use the message CReceivePrecisePrediction, as the update of the client is different. parameter : the ID of the prediction to delete return value : unsignificant */ fun __DeletePrediction(IPredictionId)= ( let DeletePrediction IPredictionId -> IsqlResult in ( if IsqlResult == SQL_SUCCESS then ( if IPredictionId <= IModulo then ( let SelectPrediction(IPredictionId) -> [ IrequestResult SpredictionTxt ] in ( if IrequestResult == SQL_SUCCESS then ( _DMSsend this DMSsender CCorrectDeleteDatabaseOperation [ IPredictionId SpredictionTxt ] ) else ( _DMSsend this DMSsender CErrorDatabase [] ) ) ) else ( /* the deleted prediction was the last one. In fact, noone has been updated, but the operation is correct*/ _DMSsend this DMSsender CReceivePrecisePrediction [ 0 ""] ) ) else ( _DMSsend this DMSsender CErrorDatabase [] ) ) );; /* this function is called by the client when it closed itself. Its login is retired from the list of the client currently working parameters : noon, we just use DMSsender return value : unsignificant */ fun __ClosingClient()= ( let strcatn "\""::(_DMSgetLogin DMSsender)::"\""::nil -> SclientLogin in ( let strfindi SclientLogin SClientEditing 0 -> IclientPosition in ( if IclientPosition == nil then ( ErrorMessage strcatn (_loc this "ErreurClosingClient" nil)::" "::SclientLogin::nil; 0 ) else ( set SClientEditing = strcat (substr SClientEditing 0 (IclientPosition-1) ) (substr SClientEditing (IclientPosition + (strlen (SclientLogin)) + 1) ( (strlen(SClientEditing)) - IclientPosition + (strlen(SclientLogin)) + 1) ); 0 ) ) ) );; /* CALLBACK FUNCTIONS */ /* Server closing callback It is there just to close correctly the database. It is supposed to not be used, because server is supposed to never stop */ fun CloseServeur()= ( SqlDestroy DBConnection );; /* Action CreatePrediction callback This function insert a prediction in the database, and set IModulo, with the function InsertPrediction This function parameters are standards action function parameters. Only param is used, to get the prediction to insert. */ fun Devin_CreatePrediction(from,u,action,param,ulist,tag)= ( let InsertPrediction param -> IinsertResult in ( if IinsertResult != SQL_SUCCESS then ( LastSQLErrorMessage; 0 ) else ( 0 ); _DMSeventTag this u "sendModificationResult" (itoa IinsertResult) nil nil; ) );; /*Action DeletePrediction callback This function delete a prediction in the database, and set IModulo This function parameters are standards action function parameters. Only param is used, to get the prediction to insert. */ fun Devin_DeletePrediction(from,u,action,param,ulist,tag)= ( let DeletePrediction atoi(param) -> IdeleteResult in ( if IdeleteResult != SQL_SUCCESS then ( LastSQLErrorMessage; 0 ) else ( 0 ); _DMSeventTag this u "sendModificationResult" (itoa IdeleteResult) nil nil; ) );; /* Action UpdatePrediction callback this function update the text of a prediction This function parameters are standards action function parameters. Only param is used. It MUST be "NUMBERID NEWTEXT", else the function will not work */ fun Devin_UpdatePrediction(from,u,action,param,ulist,tag)= ( let (strfind " " param 0) -> IfirstSpacePosition in ( let [ (substr param 0 IfirstSpacePosition ) (substr param (IfirstSpacePosition + 1) ((strlen param) - (IfirstSpacePosition -1)))] -> [ SnumberPredictionId SpredictionText ] in ( let UpdatePrediction (atoi SnumberPredictionId) SpredictionText -> IupdateResult in ( if IupdateResult != SQL_SUCCESS then ( LastSQLErrorMessage; 0 ) else ( 0 ); _DMSeventTag this u "sendModificationResult" (itoa IupdateResult) nil nil ) ) ) );; /* Action AskPrecisePrediction callback this function select the prediction text of an identified prediction This function parameters are standards action function parameters. Only param is used. It must contain a number, corresponding to the ID of the searched prediction NB : the string returned in the event is "SQLRETURNINT PREDICTIONTEXT". If Sql return is SQL_ERROR, PREDICTIONTEXT is nil */ fun Devin_AskPrecisePrediction(from,u,action,param,ulist,tag)= ( let SelectPrediction atoi param -> [ IselectResult SpredictionTxt] in ( if IselectResult != SQL_SUCCESS then ( LastSQLErrorMessage; 0 ) else ( 0 ); _DMSeventTag this u "sendPrecisePrediction" (strcatn (itoa IselectResult)::" "::SpredictionTxt::nil) nil nil; ) );; /* Action AskRandomPrediction callback This function checks whether or not a new prediction is mandatory, according to the last prediction date. If yes, a random prediction is sent back, with the event SendRandomPrediction If no, according to the behavior defined inside the editor, the function sent the last prediction or nil. This function parameters are standards action function parameters. Only u is used, to get the client. */ fun Devin_AskRandomPrediction(from,u,action,param,ulist,tag)= ( /* First, we look into the Databse, for the last Time a prediction was ask. This time is in second, to make comparaison easier */ let atoi hd (hd SqlRequest DBConnection (strcatn "SELECT DernierePrediction FROM " ::SLoginTableName::" WHERE login = ?"::nil) (SQL_CHAR _DMSgetLogin UtoC u)::nil ) -> IlastPrediction in ( if (SqlCod DBConnection) == SQL_NO_DATA then ( /* that user has never asked a prediction, so we insert him in the login table */ SqlRequest DBConnection strcatn "INSERT INTO "::SLoginTableName:: " (Login,DernierePrediction,NumDernierePrediction) VALUES (?,0,0)"::nil (SQL_CHAR _DMSgetLogin UtoC u)::nil; let SqlCod DBConnection -> IbaseReturn in ( let SqlDescErr DBConnection -> [ _ _ _ IinsertLineCount ] in ( if (IbaseReturn == SQL_SUCCESS) && (IinsertLineCount == 1) then ( set IlastPrediction = 0; ) else ( ErrorMessage( _loc this "ErreurRequeteInsertNewUser" nil ); LastSQLErrorMessage; SQL_ERROR; ) ) ) ) else ( if (SqlCod DBConnection) == SQL_ERROR then ( /* There is a SQL Error */ let strcatn (_DMSgetName this)::" "::( _loc this "ErreurSQLDernierePrediction" nil)::(_DMSgetLogin UtoC u) ::nil -> SerrorMsg in ( ErrorMessage SerrorMsg; LastSQLErrorMessage; 0 ) ) else ( 0; ) ); /* there, IlastPrediction is correct */ if (time - IlastPrediction) > 86400 then /* NB : there are 86400 seconds in 24 hours */ ( /* Last prediction is outdated, we need a new one and we have to update the login table */ let rand -> IrandomNumber in let IrandomNumber - ((IrandomNumber / IModulo)*IModulo) + 1 -> IpredictionNumber in let strcatn ( hd SqlRequest (DBConnection) (strcatn "SELECT TxtPrediction FROM "::SPredictionTableName:: " WHERE NumPrediction =?"::nil) (SQL_INTEGER itoa IpredictionNumber)::nil ) -> SreadPrediction in ( if SreadPrediction == nil then ( /* error in new prediction request processing */ let strcatn (_DMSgetName this)::( _loc this "ErreurSQLTxtNouvellePrediction" nil) ::(_DMSgetLogin UtoC u)::nil -> SerrorMsg in ( ErrorMessage SerrorMsg; LastSQLErrorMessage; 0 ) ) else ( /* login table is updated */ SqlRequest DBConnection (strcatn "UPDATE "::SLoginTableName::" SET NumDernierePrediction = ":: (itoa IpredictionNumber)::", DernierePrediction = "::(itoa time):: " WHERE login = ?"::nil) (SQL_CHAR (_DMSgetLogin UtoC u))::nil ; let SqlDescErr DBConnection -> [ _ _ _ IlineCount ] in ( let SqlCod DBConnection -> IerrorCode in ( if ( IerrorCode == SQL_SUCCESS ) && (IlineCount == 1) then ( /* everything is correct, result is sent with an event */ _DMSeventTag this u "sendRandomPrediction" SreadPrediction nil nil ; 0 ; ) else ( let strcatn (_DMSgetName this)::( _loc this "ErreurSQLUpdateLogin" nil) ::(_DMSgetLogin UtoC u)::nil -> SerrorMsg in ( /* error in the login table update request */ ErrorMessage SerrorMsg; LastSQLErrorMessage; 0 ) ) ) ) ) ) ) else ( /* in that case, last request was sent, less than 24 hours ago. Behavior is tested */ if IBehavior then ( /* last prediction must be resent */ let strcatn( hd SqlRequest DBConnection (strcatn "SELECT "::SPredictionTableName::".TxtPrediction FROM "::SLoginTableName::" , ":: SPredictionTableName:: " WHERE "::SLoginTableName::".login =? AND ":: SPredictionTableName::".NumPrediction = ":: SLoginTableName::".NumDernierePrediction"::nil) (SQL_CHAR _DMSgetLogin UtoC u)::nil ) -> SreadPrediction in ( if SreadPrediction == nil then ( let strcatn (_DMSgetName this)::" "::( _loc this "ErreurSQLTxtDernierePrediction" nil):: (_DMSgetLogin UtoC u)::nil -> SerrorMsg in ( /* Error in the last prediction request */ ErrorMessage SerrorMsg; LastSQLErrorMessage; 0 ) ) else ( /* Prediction is sent with a message */ _DMSeventTag this u "sendRandomPrediction" SreadPrediction nil nil; 0 ) ) ) else ( /* Nothing is sent */ _DMSeventTag this u "sendRandomPrediction" nil nil nil ; 0 ) ) ) );; /* Devin_EditDatabase action function : this function just open the client and sent it the list of the current client login. */ fun Devin_EditDatabase(from,u,action,param,ulist,tag)= ( set SClientEditing = strcatn "\""::(_DMSgetLogin UtoC u)::"\" "::SClientEditing::nil; _DMScreateClientDMI this UtoC u SClientEditing );; /* module initialisation function - file : name of the file where the module is defined into */ fun IniDMI(file)= ( /* Module registry with the closing function */ _DMSregister this nil nil @CloseServeur; /* module action definition : AskRandomPrecision : look for a random precision, and send it with sendRandomPrecision to be used with the normal user. All other actions are destined to the site administrator EditDatabase : Client opening, with a window for editing the database AskPrecisePredictio : Ask an identified prediction CreatePrediction : insert a new prediction into the database UpdatePrediction : update an identified prediction DeletePrediction : delete an identified prediction. As there can be no hole inside the prediction number the last prediction take the place of the destroyed one */ _DMSdefineActions this ["askRandomPrediction" @Devin_AskRandomPrediction]:: ["askPrecisePrediction" @Devin_AskPrecisePrediction]:: ["editDatabase" @Devin_EditDatabase]:: ["createPrediction" @Devin_CreatePrediction]:: ["updatePrediction" @Devin_UpdatePrediction]:: ["deletePrediction" @Devin_DeletePrediction]:: nil; /* Parameter reading, form the file created by the editor. LSfile is the file in the shape of a list of string */ let strextr _getpack _checkpack file -> LSfile in ( set SBaseName = getInfo LSfile "BaseName"; set SBaseLogin = getInfo LSfile "BaseLogin"; set SBasePassword = getInfo LSfile "BasePassword"; set SLoginTableName = getInfo LSfile "LoginTableName"; set SPredictionTableName = getInfo LSfile "PredictionTableName"; set IBehavior = atoi getInfo LSfile "Behavior" ); /* random initialisation, with a true random event : start up time */ srand time; /* Database opening, with parameters given in the editor */ if SBasePassword == nil then ( set SBasePassword = "" ) else ( SBasePassword ); set DBConnection = SqlCreate _channel SBaseName SBaseLogin SBasePassword; if DBConnection==nil then let strcatn (_DMSgetName this)::" "::( _loc this "ErreurOuvertureDeBase" nil):: ( _loc this "TextParametres" nil)::" "::SBaseName::", "::SBaseLogin:: ", "::SBasePassword::nil -> SerrorMsg in ( ErrorMessage SerrorMsg; LastSQLErrorMessage; 0 ) else 0; /* IModulo evaluation. Take care, this evaluation must be done with each database update */ let (SqlRequest DBConnection strcatn("SELECT count(NumPrediction) FROM "::SPredictionTableName::nil) nil) -> [ [ Scount _ ] _ ] in set IModulo = atoi Scount; set SClientEditing = ""; if (SqlCod DBConnection) != SQL_SUCCESS then let strcatn (_DMSgetName this)::" "::( _loc this "ErreurRequeteModulo" nil)::nil -> SerrorMsg in ( ErrorMessage SerrorMsg; LastSQLErrorMessage; 0 ) else 0 );;