One major new feature of NexusDB V3 is the ability to run server side pascal scripts. These scripts have full access to the server infrastructure (like server engine, monitors, settings) as well as to all databases. The initial release will only include a simple access control to this feature on the basis of a security token which can be assigned to a user (same as the R, W and A tokens in NexusDB V2). Incremental updates will introduce finer access control to the server infra structure and databases.

Let's take a look at a small script that executes a query and dumps the data to the output.

Example

var
  aSession: TnxSession;
  adb: TnxDatabase;
  aQuery: TnxQuery;
  i: integer;
begin
  aSession:=TnxSession.Create(nil);
  adb:=TnxDatabase.Create(nil);
  aQuery:=TnxQuery.Create(nil);
  try
    aSession.ServerEngine:=ServerEngine;
    aSession.Active:=true;
    adb.AliasName:='Test';
    adb.Session:=aSession;
    adb.Open;
    aQuery.Database:=adb;
    aQuery.SQL.Text:='select * from test';
    aQuery.Open;
    while not aQuery.eof do
    begin
      for i:=0 to aQuery.FieldCount-1 do
        Output.Write(aQuery.Fields.Fields[i].AsString+',');
      Output.WriteLn('');
      aQuery.Next;
    end;
    Output.SaveToFile('c:\out.txt');
  finally
    aQuery.Free;
    adb.free;
    aSession.Free;
  end;
end.

As you can see, very straight forward, the only thing different to a standard Delphi function is the use of the global variable ServerEngine (which is a direct reference to the main server engine of the server where the script is executed) and the use of the global Output class instance (preliminary class members) to dump the data.

The script processing on the server side is implemented as a special handler of the also new nxRemoteRemoteCommands plugin. This plugin has an extensible Type parameter and one such type is cmdExecScript.

How to run a script?

Now that's the question is it. Simple to answer: All you need to do is call the plugins ExecCommand method. The server side implementation of the plugin creates an Alias 'ServerRemoteCommand' which will have the the output of the script buffered in a (per command unique) table.

One of the simplest ways start a script and get return the output is the following:

uses
  ...
  nxdb, nxtwWinsockTransport, nxreRemoteServerEngine,
  nxrcRemoteCommandsPluginClient, nxsdServerEngine, nxsdTypes
  ...

function ExecCommand(aserver: string; aport: integer;
  auser, apassword, ascript, aparams: string): string;
var
  Transport: TnxWinsockTransport;
  ServerEngine: TnxRemoteServerEngine;
  Session: TnxSession;
  rc: TnxRemoteRemoteCommandsPlugin;
  error: integer;
  errormessage: string;
  Taskinfo: TnxAbstractTaskInfo;
  Database: TnxDatabase;
  ProgressTable: TnxTable;
  Completed: Boolean;
  Status: TnxTaskStatus;
  ResultData: TStringlist;
begin
  Transport:=TnxWinsockTransport.Create(nil);
  ServerEngine:=TnxRemoteServerEngine.Create(nil);
  Session:=TnxSession.Create(nil);
  rc:=TnxRemoteRemoteCommandsPlugin.Create(nil);
  ResultData:=TStringlist.Create;
  try
    try
      Transport.ServerNameRuntime:=aserver;
      Transport.Port:=aport;
      ServerEngine.Transport:=Transport;
      Session.ServerEngine:=ServerEngine;
      Session.UserName:=auser;
      Session.Password:=apassword;
      rc.Session:=Session;
      rc.Active:=true;

      rc.ExecCommand('cmdExecScript', ascript, aparams, error, errormessage, Taskinfo);
      if (error<>0) or (Taskinfo=nil) then
        ResultData.Add(inttostr(error)+' - '+errormessage)
     else
     begin
        Database:=TnxDatabase.Create(nil);
        ProgressTable:=TnxTable.Create(nil);
        if Assigned(TaskInfo) then
        try
          Database.Session:=Session;
          Database.AliasName:='ServerRemoteCommand';
          Database.Open;
          ProgressTable.Database:=Database;
          ProgressTable.TableName:='ServerRemoteCommand_'+IntToStr(Taskinfo.RemoteID);
          repeat
            ProgressTable.Open;
            while not ProgressTable.Eof do
            begin
              ResultData.Add(ProgressTable.FindField('Lines').AsString);
              ProgressTable.Delete;
            end;
            ProgressTable.Close;
            TaskInfo.GetStatus(Completed, Status);
            if not Completed then begin
              Sleep(500);
            end;
          until Completed;
          ProgressTable.Open;
          while not ProgressTable.Eof do
          begin
            Write(ProgressTable.FindField('Lines').AsString);
            ProgressTable.Delete;
          end;
          ProgressTable.Close;
        finally
          ProgressTable.Free;
          Database.Free;
          TaskInfo.Free;
        end;
      end;
    except
      on E:Exception do
      begin
        ResultData.Add(E.Classname + ': ' + E.Message);
      end;
    end;
  finally
    result:=ResultData.Text;
    rc.Free;
    Session.Free;
    ServerEngine.Free;
    Transport.Free;
    ResultData.Free;
  end;
end;

Usage examples:

// exec script direct
procedure TformRemoteCommandTest.Button1Click(Sender: TObject);
var
  params:TStringlist;
begin
  params:=TStringlist.Create;
  try
    Params.Values['/direct']:='begin Output.Write(''abc'');end.';
    Memo1.Lines.Text:=ExecCommand(
      edServer.Text, strtointdef(edPort.Text, 16000),
      edUser.Text, edPassWord.Text,
      '', params.text);
  finally
    params.Free;
  end;
end;

// exec SQL
procedure TformRemoteCommandTest.Button2Click(Sender: TObject);
var
  params:TStringlist;
begin
  params:=TStringlist.Create;
  try
    Params.Values['/database']:='Test';
    Params.Values['/sql']:='select * from t1';
    Params.Values['/delimiter']:=',';
    Params.Values['/qualifier']:='"';
    Memo1.Lines.Text:=ExecCommand(
      edServer.Text, strtointdef(edPort.Text, 16000),
      edUser.Text, edPassWord.Text,
      'runsql.nxscript', params.text);
  finally
    params.Free;
  end;
end;

// exec Backup
procedure TformRemoteCommandTest.Button3Click(Sender: TObject);
var
  params:TStringlist;
begin
  params:=TStringlist.Create;
  try
    Params.Values['/Source']:='Test';
    Params.Values['/Destination']:='c:\testbackup';
    Memo1.Lines.Text:=ExecCommand(
      edServer.Text, strtointdef(edPort.Text, 16000),
      edUser.Text, edPassWord.Text,
      'Backup.nxscript', params.text);
  finally
    params.Free;
  end;
end;

Now say hello to a very small but in combination with server scripting very powerful tool:

nxCommand.exe

This nifty utility is an extended command line implementation of above code and can be used to call NexusDB server side scripts. The command line arguments are as following:

nxCommand /Type:cmdExecScript /Script:myscript.nxscript [/param1:asneededbythescript ...]

See a screen shot here.

You can also execute a script directly by replacing the last parameter with

/Direct:"begin Output.Write('abc');end."

in future (together with updated security) we will of course add support for server, username and password arguments, but for the time being this will only work on a local server.

Script Repository

We will provide at least 2 scripts at launch which will be shipped with NexusDB and at the same time will be available from our upcoming online script repository. Every registered user of our web site will be able to access and add scripts in that global repository.

The first script runSQL.nxscript will execute a SQL command and allow to format the output with delimeters, quoting etc. This can be used to very quickly export some data to a CSV (or similar) file. Please look at the preliminary source for the details. You can call it like this (for a local server with no user/password):

nxCommand /Type:cmdExecScript /Script:runsql.nxscript /database:dbname
  /sql:"select * from t1" /delimiter:%20 /qualifier:%22 > export.txt

This will create nice CSV formated file of the given query.

The second script is Backup.nxscript which can be used in the pre-backup event of your favourite backup solution to create a consistent backup of your database. Call it like that:

nxCommand /Type:cmdExecScript /Script:Backup.nxscript /Source:srcalias|srcpath
  /Destination:destalias|destpath

nxCommand returns, like a good command line utility, an error code<>0 if something didn't work as expected and dumps the error message to STDOUT/STDERR.

(We're also considering to ship an extra nxScript.exe command line utility that would remove the need for explicitly specifying the Type parameter.)

Home | Site Contents | Documentation | NexusDB Manual V4 | Overview of new Features in NexusDB V3